Skip to main content

mz_expr/
scalar.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::collections::BTreeSet;
11use std::ops::BitOrAssign;
12use std::sync::Arc;
13use std::{fmt, mem};
14
15use itertools::Itertools;
16use mz_lowertest::MzReflect;
17use mz_ore::cast::CastFrom;
18use mz_ore::iter::IteratorExt;
19use mz_ore::soft_assert_or_log;
20use mz_ore::stack::RecursionLimitError;
21use mz_ore::str::StrExt;
22use mz_ore::treat_as_equal::TreatAsEqual;
23use mz_ore::vec::swap_remove_multiple;
24use mz_pgrepr::TypeFromOidError;
25use mz_proto::{IntoRustIfSome, ProtoType, RustType, TryFromProtoError};
26use mz_repr::adt::array::InvalidArrayError;
27use mz_repr::adt::date::DateError;
28use mz_repr::adt::range::InvalidRangeError;
29use mz_repr::adt::regex::RegexCompilationError;
30use mz_repr::adt::timestamp::TimestampError;
31use mz_repr::strconv::{ParseError, ParseHexError};
32use mz_repr::{Datum, ReprColumnType, ReprScalarType, Row, RowArena, SqlColumnType};
33
34#[cfg(any(test, feature = "proptest"))]
35use proptest::prelude::*;
36#[cfg(any(test, feature = "proptest"))]
37use proptest_derive::Arbitrary;
38use serde::{Deserialize, Serialize};
39
40use crate::explain::{HumanizedExplain, HumanizerMode};
41pub use crate::scalar::columns::Columns;
42pub use crate::scalar::eval::Eval;
43use crate::scalar::func::variadic::{And, Or};
44use crate::scalar::func::{BinaryFunc, UnaryFunc, UnmaterializableFunc, VariadicFunc};
45pub use crate::scalar::optimizable::OptimizableExpr;
46use crate::scalar::proto_eval_error::proto_incompatible_array_dimensions::ProtoDims;
47use crate::visit::{Visit, VisitChildren};
48
49pub mod columns;
50pub mod eval;
51pub mod func;
52pub mod like_pattern;
53pub mod optimizable;
54mod reduce;
55
56include!(concat!(env!("OUT_DIR"), "/mz_expr.scalar.rs"));
57
58#[derive(
59    Clone,
60    PartialEq,
61    Eq,
62    PartialOrd,
63    Ord,
64    Hash,
65    Serialize,
66    Deserialize,
67    MzReflect
68)]
69pub enum MirScalarExpr {
70    /// A column of the input row
71    Column(usize, TreatAsEqual<Option<Arc<str>>>),
72    /// A literal value.
73    /// (Stored as a row, because we can't own a Datum)
74    Literal(Result<Row, EvalError>, ReprColumnType),
75    /// A call to an unmaterializable function.
76    ///
77    /// These functions cannot be evaluated by `MirScalarExpr::eval`. They must
78    /// be transformed away by a higher layer.
79    CallUnmaterializable(UnmaterializableFunc),
80    /// A function call that takes one expression as an argument.
81    CallUnary {
82        func: UnaryFunc,
83        expr: Box<MirScalarExpr>,
84    },
85    /// A function call that takes two expressions as arguments.
86    CallBinary {
87        func: BinaryFunc,
88        expr1: Box<MirScalarExpr>,
89        expr2: Box<MirScalarExpr>,
90    },
91    /// A function call that takes an arbitrary number of arguments.
92    CallVariadic {
93        func: VariadicFunc,
94        exprs: Vec<MirScalarExpr>,
95    },
96    /// Conditionally evaluated expressions.
97    ///
98    /// It is important that `then` and `els` only be evaluated if
99    /// `cond` is true or not, respectively. This is the only way
100    /// users can guard execution (other logical operator do not
101    /// short-circuit) and we need to preserve that.
102    If {
103        cond: Box<MirScalarExpr>,
104        then: Box<MirScalarExpr>,
105        els: Box<MirScalarExpr>,
106    },
107}
108
109// We need a custom Debug because we don't want to show `None` for name information.
110// Sadly, the `derivative` crate doesn't support this use case.
111impl std::fmt::Debug for MirScalarExpr {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            MirScalarExpr::Column(i, TreatAsEqual(Some(name))) => {
115                write!(f, "Column({i}, {name:?})")
116            }
117            MirScalarExpr::Column(i, TreatAsEqual(None)) => write!(f, "Column({i})"),
118            MirScalarExpr::Literal(lit, typ) => write!(f, "Literal({lit:?}, {typ:?})"),
119            MirScalarExpr::CallUnmaterializable(func) => {
120                write!(f, "CallUnmaterializable({func:?})")
121            }
122            MirScalarExpr::CallUnary { func, expr } => {
123                write!(f, "CallUnary({func:?}, {expr:?})")
124            }
125            MirScalarExpr::CallBinary { func, expr1, expr2 } => {
126                write!(f, "CallBinary({func:?}, {expr1:?}, {expr2:?})")
127            }
128            MirScalarExpr::CallVariadic { func, exprs } => {
129                write!(f, "CallVariadic({func:?}, {exprs:?})")
130            }
131            MirScalarExpr::If { cond, then, els } => {
132                write!(f, "If({cond:?}, {then:?}, {els:?})")
133            }
134        }
135    }
136}
137
138impl MirScalarExpr {
139    pub fn columns(is: &[usize]) -> Vec<MirScalarExpr> {
140        is.iter().map(|i| MirScalarExpr::column(*i)).collect()
141    }
142
143    pub fn column(column: usize) -> Self {
144        MirScalarExpr::Column(column, TreatAsEqual(None))
145    }
146
147    pub fn named_column(column: usize, name: Arc<str>) -> Self {
148        MirScalarExpr::Column(column, TreatAsEqual(Some(name)))
149    }
150
151    pub fn literal(res: Result<Datum, EvalError>, typ: ReprScalarType) -> Self {
152        let typ = ReprColumnType {
153            scalar_type: typ,
154            nullable: matches!(res, Ok(Datum::Null)),
155        };
156        let row = res.map(|datum| Row::pack_slice(&[datum]));
157        MirScalarExpr::Literal(row, typ)
158    }
159
160    pub fn literal_ok(datum: Datum, typ: ReprScalarType) -> Self {
161        MirScalarExpr::literal(Ok(datum), typ)
162    }
163
164    /// Constructs a `MirScalarExpr::Literal` from a pre-packed `Row`
165    /// containing a single datum and a `ReprScalarType`. Nullability is
166    /// derived by inspecting the first datum in the row.
167    pub fn literal_from_single_element_row(row: Row, typ: ReprScalarType) -> Self {
168        soft_assert_or_log!(
169            row.iter().count() == 1,
170            "literal_from_row called with a Row containing {} datums",
171            row.iter().count()
172        );
173        let nullable = row.unpack_first() == Datum::Null;
174        let typ = ReprColumnType {
175            scalar_type: typ,
176            nullable,
177        };
178        MirScalarExpr::Literal(Ok(row), typ)
179    }
180
181    pub fn literal_null(typ: ReprScalarType) -> Self {
182        MirScalarExpr::literal_ok(Datum::Null, typ)
183    }
184
185    pub fn literal_false() -> Self {
186        MirScalarExpr::literal_ok(Datum::False, ReprScalarType::Bool)
187    }
188
189    pub fn literal_true() -> Self {
190        MirScalarExpr::literal_ok(Datum::True, ReprScalarType::Bool)
191    }
192
193    pub fn call_unary<U: Into<UnaryFunc>>(self, func: U) -> Self {
194        MirScalarExpr::CallUnary {
195            func: func.into(),
196            expr: Box::new(self),
197        }
198    }
199
200    pub fn call_binary<B: Into<BinaryFunc>>(self, other: Self, func: B) -> Self {
201        MirScalarExpr::CallBinary {
202            func: func.into(),
203            expr1: Box::new(self),
204            expr2: Box::new(other),
205        }
206    }
207
208    /// Call function `func` on `exprs`.
209    pub fn call_variadic<V: Into<VariadicFunc>>(func: V, exprs: Vec<Self>) -> Self {
210        MirScalarExpr::CallVariadic {
211            func: func.into(),
212            exprs,
213        }
214    }
215
216    pub fn if_then_else(self, t: Self, f: Self) -> Self {
217        MirScalarExpr::If {
218            cond: Box::new(self),
219            then: Box::new(t),
220            els: Box::new(f),
221        }
222    }
223
224    pub fn or(self, other: Self) -> Self {
225        MirScalarExpr::call_variadic(Or, vec![self, other])
226    }
227
228    pub fn and(self, other: Self) -> Self {
229        MirScalarExpr::call_variadic(And, vec![self, other])
230    }
231
232    pub fn not(self) -> Self {
233        self.call_unary(UnaryFunc::Not(func::Not))
234    }
235
236    pub fn call_is_null(self) -> Self {
237        self.call_unary(UnaryFunc::IsNull(func::IsNull))
238    }
239
240    /// Match AND or OR on self and get the args. If no match, then interpret self as if it were
241    /// wrapped in a 1-arg AND/OR.
242    pub fn and_or_args(&self, func_to_match: VariadicFunc) -> Vec<MirScalarExpr> {
243        assert!(func_to_match == Or.into() || func_to_match == And.into());
244        match self {
245            MirScalarExpr::CallVariadic { func, exprs } if *func == func_to_match => exprs.clone(),
246            _ => vec![self.clone()],
247        }
248    }
249
250    /// Try to match a literal equality involving the given expression on one side.
251    /// Return the (non-null) literal and a bool that indicates whether an inversion was needed.
252    ///
253    /// More specifically:
254    /// If `self` is an equality with a `null` literal on any side, then the match fails!
255    /// Otherwise: for a given `expr`, if `self` is `<expr> = <literal>` or `<literal> = <expr>`
256    /// then return `Some((<literal>, false))`. In addition to just trying to match `<expr>` as it
257    /// is, we also try to remove an invertible function call (such as a cast). If the match
258    /// succeeds with the inversion, then return `Some((<inverted-literal>, true))`. For more
259    /// details on the inversion, see `invert_casts_on_expr_eq_literal_inner`.
260    pub fn expr_eq_literal(&self, expr: &MirScalarExpr) -> Option<(Row, bool)> {
261        if let MirScalarExpr::CallBinary {
262            func: BinaryFunc::Eq(_),
263            expr1,
264            expr2,
265        } = self
266        {
267            if expr1.is_literal_null() || expr2.is_literal_null() {
268                return None;
269            }
270            if let Some(Ok(lit)) = expr1.as_literal_owned() {
271                return Self::expr_eq_literal_inner(expr, lit, expr1, expr2);
272            }
273            if let Some(Ok(lit)) = expr2.as_literal_owned() {
274                return Self::expr_eq_literal_inner(expr, lit, expr2, expr1);
275            }
276        }
277        None
278    }
279
280    fn expr_eq_literal_inner(
281        expr_to_match: &MirScalarExpr,
282        literal: Row,
283        literal_expr: &MirScalarExpr,
284        other_side: &MirScalarExpr,
285    ) -> Option<(Row, bool)> {
286        if other_side == expr_to_match {
287            return Some((literal, false));
288        } else {
289            // expr didn't exactly match. See if we can match it by inverse-casting.
290            let (cast_removed, inv_cast_lit) =
291                Self::invert_casts_on_expr_eq_literal_inner(other_side, literal_expr);
292            if &cast_removed == expr_to_match {
293                if let Some(Ok(inv_cast_lit_row)) = inv_cast_lit.as_literal_owned() {
294                    return Some((inv_cast_lit_row, true));
295                }
296            }
297        }
298        None
299    }
300
301    /// If `self` is `<expr> = <literal>` or `<literal> = <expr>` then
302    /// return `<expr>`. It also tries to remove a cast (or other invertible function call) from
303    /// `<expr>` before returning it, see `invert_casts_on_expr_eq_literal_inner`.
304    pub fn any_expr_eq_literal(&self) -> Option<MirScalarExpr> {
305        if let MirScalarExpr::CallBinary {
306            func: BinaryFunc::Eq(_),
307            expr1,
308            expr2,
309        } = self
310        {
311            if expr1.is_literal() {
312                let (expr, _literal) = Self::invert_casts_on_expr_eq_literal_inner(expr2, expr1);
313                return Some(expr);
314            }
315            if expr2.is_literal() {
316                let (expr, _literal) = Self::invert_casts_on_expr_eq_literal_inner(expr1, expr2);
317                return Some(expr);
318            }
319        }
320        None
321    }
322
323    /// If the given `MirScalarExpr` is a literal equality where one side is an invertible function
324    /// call, then calls the inverse function on both sides of the equality and returns the modified
325    /// version of the given `MirScalarExpr`. Otherwise, it returns the original expression.
326    /// For more details, see `invert_casts_on_expr_eq_literal_inner`.
327    pub fn invert_casts_on_expr_eq_literal(&self) -> MirScalarExpr {
328        if let MirScalarExpr::CallBinary {
329            func: BinaryFunc::Eq(_),
330            expr1,
331            expr2,
332        } = self
333        {
334            if expr1.is_literal() {
335                let (expr, literal) = Self::invert_casts_on_expr_eq_literal_inner(expr2, expr1);
336                return literal.call_binary(expr, func::Eq);
337            }
338            if expr2.is_literal() {
339                let (expr, literal) = Self::invert_casts_on_expr_eq_literal_inner(expr1, expr2);
340                return literal.call_binary(expr, func::Eq);
341            }
342            // Note: The above return statements should be consistent in whether they put the
343            // literal in expr1 or expr2, for the deduplication in CanonicalizeMfp to work.
344        }
345        self.clone()
346    }
347
348    /// Given an `<expr>` and a `<literal>` that were taken out from `<expr> = <literal>` or
349    /// `<literal> = <expr>`, it tries to simplify the equality by applying the inverse function of
350    /// the outermost function call of `<expr>` (if exists):
351    ///
352    /// `<literal> = func(<inner_expr>)`, where `func` is invertible
353    ///  -->
354    /// `<func^-1(literal)> = <inner_expr>`
355    /// if `func^-1(literal)` doesn't error out, and both `func` and `func^-1` preserve uniqueness.
356    ///
357    /// The return value is the `<inner_expr>` and the literal value that we get by applying the
358    /// inverse function.
359    fn invert_casts_on_expr_eq_literal_inner(
360        expr: &MirScalarExpr,
361        literal: &MirScalarExpr,
362    ) -> (MirScalarExpr, MirScalarExpr) {
363        assert!(matches!(literal, MirScalarExpr::Literal(..)));
364
365        let temp_storage = &RowArena::new();
366        let eval = |e: &MirScalarExpr| {
367            MirScalarExpr::literal(e.eval(&[], temp_storage), e.typ(&[]).scalar_type)
368        };
369
370        if let MirScalarExpr::CallUnary {
371            func,
372            expr: inner_expr,
373        } = expr
374        {
375            if let Some(inverse_func) = func.inverse() {
376                // We don't want to remove a function call that doesn't preserve uniqueness, e.g.,
377                // if `f` is a float, we don't want to inverse-cast `f::INT = 0`, because the
378                // inserted int-to-float cast wouldn't be able to invert the rounding.
379                // Also, we don't want to insert a function call that doesn't preserve
380                // uniqueness. E.g., if `a` has an integer type, we don't want to do
381                // a surprise rounding for `WHERE a = 3.14`.
382                if func.preserves_uniqueness() && inverse_func.preserves_uniqueness() {
383                    let lit_inv = eval(&MirScalarExpr::CallUnary {
384                        func: inverse_func,
385                        expr: Box::new(literal.clone()),
386                    });
387                    // The evaluation can error out, e.g., when casting a too large int32 to int16.
388                    // This case is handled by `impossible_literal_equality_because_types`.
389                    if !lit_inv.is_literal_err() {
390                        return (*inner_expr.clone(), lit_inv);
391                    }
392                }
393            }
394        }
395        (expr.clone(), literal.clone())
396    }
397
398    /// Tries to remove a cast (or other invertible function) in the same way as
399    /// `invert_casts_on_expr_eq_literal`, but if calling the inverse function fails on the literal,
400    /// then it deems the equality to be impossible. For example if `a` is a smallint column, then
401    /// it catches `a::integer = 1000000` to be an always false predicate (where the `::integer`
402    /// could have been inserted implicitly).
403    pub fn impossible_literal_equality_because_types(&self) -> bool {
404        if let MirScalarExpr::CallBinary {
405            func: BinaryFunc::Eq(_),
406            expr1,
407            expr2,
408        } = self
409        {
410            if expr1.is_literal() {
411                return Self::impossible_literal_equality_because_types_inner(expr1, expr2);
412            }
413            if expr2.is_literal() {
414                return Self::impossible_literal_equality_because_types_inner(expr2, expr1);
415            }
416        }
417        false
418    }
419
420    fn impossible_literal_equality_because_types_inner(
421        literal: &MirScalarExpr,
422        other_side: &MirScalarExpr,
423    ) -> bool {
424        assert!(matches!(literal, MirScalarExpr::Literal(..)));
425
426        let temp_storage = &RowArena::new();
427        let eval = |e: &MirScalarExpr| {
428            MirScalarExpr::literal(e.eval(&[], temp_storage), e.typ(&[]).scalar_type)
429        };
430
431        if let MirScalarExpr::CallUnary { func, .. } = other_side {
432            if let Some(inverse_func) = func.inverse() {
433                if inverse_func.preserves_uniqueness()
434                    && eval(&MirScalarExpr::CallUnary {
435                        func: inverse_func,
436                        expr: Box::new(literal.clone()),
437                    })
438                    .is_literal_err()
439                {
440                    return true;
441                }
442            }
443        }
444
445        false
446    }
447
448    /// Determines if `self` is
449    /// `<expr> < <literal>` or
450    /// `<expr> > <literal>` or
451    /// `<literal> < <expr>` or
452    /// `<literal> > <expr>` or
453    /// `<expr> <= <literal>` or
454    /// `<expr> >= <literal>` or
455    /// `<literal> <= <expr>` or
456    /// `<literal> >= <expr>`.
457    pub fn any_expr_ineq_literal(&self) -> bool {
458        match self {
459            MirScalarExpr::CallBinary {
460                func:
461                    BinaryFunc::Lt(_) | BinaryFunc::Lte(_) | BinaryFunc::Gt(_) | BinaryFunc::Gte(_),
462                expr1,
463                expr2,
464            } => expr1.is_literal() || expr2.is_literal(),
465            _ => false,
466        }
467    }
468
469    pub fn take(&mut self) -> Self {
470        mem::replace(self, MirScalarExpr::literal_null(ReprScalarType::String))
471    }
472
473    /// If the expression is a literal, this returns the literal's Datum or the literal's EvalError.
474    /// Otherwise, it returns None.
475    pub fn as_literal(&self) -> Option<Result<Datum<'_>, &EvalError>> {
476        if let MirScalarExpr::Literal(lit, _column_type) = self {
477            Some(lit.as_ref().map(|row| row.unpack_first()))
478        } else {
479            None
480        }
481    }
482
483    /// Flattens the two failure modes of `as_literal` into one layer of Option: returns the
484    /// literal's Datum only if the expression is a literal, and it's not a literal error.
485    pub fn as_literal_non_error(&self) -> Option<Datum<'_>> {
486        self.as_literal().map(|eval_err| eval_err.ok()).flatten()
487    }
488
489    pub fn as_literal_owned(&self) -> Option<Result<Row, EvalError>> {
490        if let MirScalarExpr::Literal(lit, _column_type) = self {
491            Some(lit.clone())
492        } else {
493            None
494        }
495    }
496
497    /// Returns a reference to the `Row` if the expression is a non-NULL `Ok` literal.
498    pub fn as_literal_non_null_row(&self) -> Option<&Row> {
499        if let MirScalarExpr::Literal(Ok(row), _) = self {
500            if !row.unpack_first().is_null() {
501                return Some(row);
502            }
503        }
504        None
505    }
506
507    pub fn as_literal_str(&self) -> Option<&str> {
508        match self.as_literal() {
509            Some(Ok(Datum::String(s))) => Some(s),
510            _ => None,
511        }
512    }
513
514    pub fn as_literal_int64(&self) -> Option<i64> {
515        match self.as_literal() {
516            Some(Ok(Datum::Int64(i))) => Some(i),
517            _ => None,
518        }
519    }
520
521    pub fn as_literal_err(&self) -> Option<&EvalError> {
522        self.as_literal().and_then(|lit| lit.err())
523    }
524
525    pub fn is_literal(&self) -> bool {
526        matches!(self, MirScalarExpr::Literal(_, _))
527    }
528
529    pub fn is_literal_true(&self) -> bool {
530        Some(Ok(Datum::True)) == self.as_literal()
531    }
532
533    pub fn is_literal_false(&self) -> bool {
534        Some(Ok(Datum::False)) == self.as_literal()
535    }
536
537    pub fn is_literal_null(&self) -> bool {
538        Some(Ok(Datum::Null)) == self.as_literal()
539    }
540
541    pub fn is_literal_ok(&self) -> bool {
542        matches!(self, MirScalarExpr::Literal(Ok(_), _typ))
543    }
544
545    pub fn is_literal_err(&self) -> bool {
546        matches!(self, MirScalarExpr::Literal(Err(_), _typ))
547    }
548
549    pub fn is_error_if_null(&self) -> bool {
550        matches!(
551            self,
552            Self::CallVariadic {
553                func: VariadicFunc::ErrorIfNull(_),
554                ..
555            }
556        )
557    }
558
559    /// If `self` expresses a temporal filter, normalize it to start with `mz_now()` and return
560    /// references.
561    ///
562    /// A temporal filter is an expression of the form `mz_now() <BINOP> <EXPR>`,
563    /// for a restricted set of `BINOP` and `EXPR` that do not themselves contain `mz_now()`.
564    /// Expressions may conform to this once their expressions are swapped.
565    ///
566    /// If the expression is not a temporal filter, it will be unchanged, and the reason for why
567    /// it's not a temporal filter is returned as a string.
568    pub fn as_mut_temporal_filter(&mut self) -> Result<(&BinaryFunc, &mut MirScalarExpr), String> {
569        if !self.contains_temporal() {
570            return Err("Does not involve mz_now()".to_string());
571        }
572        // Supported temporal predicates are exclusively binary operators.
573        if let MirScalarExpr::CallBinary { func, expr1, expr2 } = self {
574            // Attempt to put `LogicalTimestamp` in the first argument position.
575            if !expr1.contains_temporal()
576                && **expr2 == MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow)
577            {
578                let new_func = match func {
579                    BinaryFunc::Eq(_) => func::Eq.into(),
580                    BinaryFunc::Lt(_) => func::Gt.into(),
581                    BinaryFunc::Lte(_) => func::Gte.into(),
582                    BinaryFunc::Gt(_) => func::Lt.into(),
583                    BinaryFunc::Gte(_) => func::Lte.into(),
584                    x => {
585                        return Err(format!("Unsupported binary temporal operation: {:?}", x));
586                    }
587                };
588                std::mem::swap(expr1, expr2);
589                *func = new_func;
590            }
591
592            // Error if MLT is referenced in an unsupported position.
593            if expr2.contains_temporal()
594                || **expr1 != MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow)
595            {
596                let mode = HumanizedExplain::new(false); // no redaction
597                let bad_expr = MirScalarExpr::CallBinary {
598                    func: func.clone(),
599                    expr1: expr1.clone(),
600                    expr2: expr2.clone(),
601                };
602                return Err(format!(
603                    "Unsupported temporal predicate. Note: `mz_now()` must be directly compared to a mz_timestamp-castable expression. Expression found: {}",
604                    mode.expr(&bad_expr, None),
605                ));
606            }
607
608            Ok((&*func, expr2))
609        } else {
610            let mode = HumanizedExplain::new(false); // no redaction
611            Err(format!(
612                "Unsupported temporal predicate. Note: `mz_now()` must be directly compared to a non-temporal expression of mz_timestamp-castable type. Expression found: {}",
613                mode.expr(self, None),
614            ))
615        }
616    }
617
618    #[deprecated = "Use `might_error` instead"]
619    pub fn contains_error_if_null(&self) -> bool {
620        let mut worklist = vec![self];
621        while let Some(expr) = worklist.pop() {
622            if expr.is_error_if_null() {
623                return true;
624            }
625            worklist.extend(expr.children());
626        }
627        false
628    }
629
630    pub fn contains_err(&self) -> bool {
631        let mut worklist = vec![self];
632        while let Some(expr) = worklist.pop() {
633            if expr.is_literal_err() {
634                return true;
635            }
636            worklist.extend(expr.children());
637        }
638        false
639    }
640
641    /// A very crude approximation for scalar expressions that might produce an
642    /// error.
643    ///
644    /// Currently, this is restricted only to expressions that either contain a
645    /// literal error or a [`VariadicFunc::ErrorIfNull`] call.
646    pub fn might_error(&self) -> bool {
647        let mut worklist = vec![self];
648        while let Some(expr) = worklist.pop() {
649            if expr.is_literal_err() || expr.is_error_if_null() {
650                return true;
651            }
652            worklist.extend(expr.children());
653        }
654        false
655    }
656
657    /// Reduces a complex expression where possible.
658    ///
659    /// This function uses nullability information present in `column_types`,
660    /// and the result may only continue to be a correct transformation as
661    /// long as this information continues to hold (nullability may not hold
662    /// as expressions migrate around).
663    ///
664    /// (If you'd like to not use nullability information here, then you can
665    /// tweak the nullabilities in `column_types` before passing it to this
666    /// function, see e.g. in `EquivalenceClasses::minimize`.)
667    ///
668    /// Also performs partial canonicalization on the expression.
669    ///
670    /// ```rust
671    /// use mz_expr::MirScalarExpr;
672    /// use mz_repr::{ReprColumnType, Datum, SqlScalarType};
673    ///
674    /// let expr_0 = MirScalarExpr::column(0);
675    /// let expr_t = MirScalarExpr::literal_true();
676    /// let expr_f = MirScalarExpr::literal_false();
677    ///
678    /// let mut test =
679    /// expr_t
680    ///     .clone()
681    ///     .and(expr_f.clone())
682    ///     .if_then_else(expr_0, expr_t.clone());
683    ///
684    /// let input_type = vec![ReprColumnType::from(&SqlScalarType::Int32.nullable(false))];
685    /// test.reduce(&input_type);
686    /// assert_eq!(test, expr_t);
687    /// ```
688    /// Reduce the expression to a simpler form.
689    pub fn reduce(&mut self, column_types: &[ReprColumnType]) {
690        reduce::reduce(self, column_types);
691    }
692
693    /// Decompose an IsNull expression into a disjunction of
694    /// simpler expressions.
695    ///
696    /// Assumes that `self` is the expression inside of an IsNull.
697    /// Returns `Some(expressions)` if the outer IsNull is to be
698    /// replaced by some other expression. Note: if it returns
699    /// None, it might still have mutated *self.
700    fn decompose_is_null(&mut self) -> Option<MirScalarExpr> {
701        // TODO: allow simplification of unmaterializable functions
702
703        match self {
704            MirScalarExpr::CallUnary {
705                func,
706                expr: inner_expr,
707            } => {
708                if !func.introduces_nulls() {
709                    if func.propagates_nulls() {
710                        *self = inner_expr.take();
711                        return self.decompose_is_null();
712                    } else {
713                        // We can simplify to `false`, because the function simply can't produce
714                        // nulls at all. This is because
715                        // - !propagates_nulls means that the input type of the Rust function is not
716                        //   nullable, so the automatic null propagation won't kick in;
717                        // - !introduces_nulls means that the output type of the Rust function is
718                        //   not nullable, so the Rust function can't produce a null manually either.
719                        //
720                        // Note that we can't do this same optimization for binary and variadic
721                        // functions. This is because for binary and variadic functions the value of
722                        // propagates_nulls and introduces_nulls is not derived solely from the
723                        // input/output type nullabilities, but instead depends on what the Rust
724                        // function does. For example, list concatenation neither introduces nor
725                        // propagates nulls, but it can produce a null:
726                        // - It does not introduce nulls, because if both input lists are not null,
727                        //   then it will produce a list.
728                        // - It does not propagate nulls, because giving a null as just one of the
729                        //   arguments returns the other argument instead of null.
730                        // - It does produce a null if both arguments are null.
731                        return Some(MirScalarExpr::literal_false());
732                    }
733                }
734            }
735            MirScalarExpr::CallBinary { func, expr1, expr2 } => {
736                // (<expr1> <op> <expr2>) IS NULL can often be simplified to
737                // (<expr1> IS NULL) OR (<expr2> IS NULL).
738                if func.propagates_nulls() && !func.introduces_nulls() {
739                    let expr1 = expr1.take().call_is_null();
740                    let expr2 = expr2.take().call_is_null();
741                    return Some(expr1.or(expr2));
742                }
743            }
744            MirScalarExpr::CallVariadic { func, exprs } => {
745                if func.propagates_nulls() && !func.introduces_nulls() {
746                    let exprs = exprs.into_iter().map(|e| e.take().call_is_null()).collect();
747                    return Some(MirScalarExpr::call_variadic(Or, exprs));
748                }
749            }
750            _ => {}
751        }
752
753        None
754    }
755
756    /// Flattens a chain of calls to associative variadic functions
757    /// (For example: ORs or ANDs)
758    pub fn flatten_associative(&mut self) {
759        match self {
760            MirScalarExpr::CallVariadic {
761                exprs: outer_operands,
762                func: outer_func,
763            } if outer_func.is_associative() => {
764                *outer_operands = outer_operands
765                    .into_iter()
766                    .flat_map(|o| {
767                        if let MirScalarExpr::CallVariadic {
768                            exprs: inner_operands,
769                            func: inner_func,
770                        } = o
771                        {
772                            if *inner_func == *outer_func {
773                                mem::take(inner_operands)
774                            } else {
775                                vec![o.take()]
776                            }
777                        } else {
778                            vec![o.take()]
779                        }
780                    })
781                    .collect();
782            }
783            _ => {}
784        }
785    }
786
787    /* #region AND/OR canonicalization and transformations  */
788
789    /// Canonicalizes AND/OR, and does some straightforward simplifications
790    fn reduce_and_canonicalize_and_or(&mut self) {
791        // We do this until fixed point, because after undistribute_and_or calls us, it relies on
792        // the property that self is not an 1-arg AND/OR. Just one application of our loop body
793        // can't ensure this, because the application itself might create a 1-arg AND/OR.
794        let mut old_self = MirScalarExpr::column(0);
795        while old_self != *self {
796            old_self = self.clone();
797            match self {
798                MirScalarExpr::CallVariadic {
799                    func: func @ (VariadicFunc::And(_) | VariadicFunc::Or(_)),
800                    exprs,
801                } => {
802                    // Canonically order elements so that various deduplications work better,
803                    // e.g., in undistribute_and_or.
804                    // Also, extract_equal_or_both_null_inner depends on the args being sorted.
805                    exprs.sort();
806
807                    // x AND/OR x --> x
808                    exprs.dedup(); // this also needs the above sorting
809
810                    if exprs.len() == 1 {
811                        // AND/OR of 1 argument evaluates to that argument
812                        *self = exprs.swap_remove(0);
813                    } else if exprs.len() == 0 {
814                        // AND/OR of 0 arguments evaluates to true/false
815                        *self = func.unit_of_and_or();
816                    } else if exprs.iter().any(|e| *e == func.zero_of_and_or()) {
817                        // short-circuiting
818                        *self = func.zero_of_and_or();
819                    } else {
820                        // a AND true --> a
821                        // a OR false --> a
822                        exprs.retain(|e| *e != func.unit_of_and_or());
823                    }
824                }
825                _ => {}
826            }
827        }
828    }
829
830    /// Transforms !(a && b) into !a || !b, and !(a || b) into !a && !b
831    fn demorgans(&mut self) {
832        if let MirScalarExpr::CallUnary {
833            expr: inner,
834            func: UnaryFunc::Not(func::Not),
835        } = self
836        {
837            inner.flatten_associative();
838            match &mut **inner {
839                MirScalarExpr::CallVariadic {
840                    func: inner_func @ (VariadicFunc::And(_) | VariadicFunc::Or(_)),
841                    exprs,
842                } => {
843                    *inner_func = inner_func.switch_and_or();
844                    *exprs = exprs.into_iter().map(|e| e.take().not()).collect();
845                    *self = (*inner).take(); // Removes the outer not
846                }
847                _ => {}
848            }
849        }
850    }
851
852    /// AND/OR undistribution (factoring out) to apply at each `MirScalarExpr`.
853    ///
854    /// This method attempts to apply one of the [distribution laws][distributivity]
855    /// (in a direction opposite to the their name):
856    /// ```text
857    /// (a && b) || (a && c) --> a && (b || c)  // Undistribute-OR
858    /// (a || b) && (a || c) --> a || (b && c)  // Undistribute-AND
859    /// ```
860    /// or one of their corresponding two [absorption law][absorption] special
861    /// cases:
862    /// ```text
863    /// a || (a && c)  -->  a  // Absorb-OR
864    /// a && (a || c)  -->  a  // Absorb-AND
865    /// ```
866    ///
867    /// The method also works with more than 2 arguments at the top, e.g.
868    /// ```text
869    /// (a && b) || (a && c) || (a && d)  -->  a && (b || c || d)
870    /// ```
871    /// It can also factor out only a subset of the top arguments, e.g.
872    /// ```text
873    /// (a && b) || (a && c) || (d && e)  -->  (a && (b || c)) || (d && e)
874    /// ```
875    ///
876    /// Note that sometimes there are two overlapping possibilities to factor
877    /// out from, e.g.
878    /// ```text
879    /// (a && b) || (a && c) || (d && c)
880    /// ```
881    /// Here we can factor out `a` from from the 1. and 2. terms, or we can
882    /// factor out `c` from the 2. and 3. terms. One of these might lead to
883    /// more/better undistribution opportunities later, but we just pick one
884    /// locally, because recursively trying out all of them would lead to
885    /// exponential run time.
886    ///
887    /// The local heuristic is that we prefer a candidate that leads to an
888    /// absorption, or if there is no such one then we simply pick the first. In
889    /// case of multiple absorption candidates, it doesn't matter which one we
890    /// pick, because applying an absorption cannot adversely effect the
891    /// possibility of applying other absorptions.
892    ///
893    /// # Assumption
894    ///
895    /// Assumes that nested chains of AND/OR applications are flattened (this
896    /// can be enforced with [`Self::flatten_associative`]).
897    ///
898    /// # Examples
899    ///
900    /// Absorb-OR:
901    /// ```text
902    /// a || (a && c) || (a && d)
903    /// -->
904    /// a && (true || c || d)
905    /// -->
906    /// a && true
907    /// -->
908    /// a
909    /// ```
910    /// Here only the first step is performed by this method. The rest is done
911    /// by [`Self::reduce_and_canonicalize_and_or`] called after us in
912    /// `reduce()`.
913    ///
914    /// [distributivity]: https://en.wikipedia.org/wiki/Distributive_property
915    /// [absorption]: https://en.wikipedia.org/wiki/Absorption_law
916    fn undistribute_and_or(&mut self) {
917        // It wouldn't be strictly necessary to wrap this fn in this loop, because `reduce()` calls
918        // us in a loop anyway. However, `reduce()` tries to do many other things, so the loop here
919        // improves performance when there are several undistributions to apply in sequence, which
920        // can occur in `CanonicalizeMfp` when undoing the DNF.
921        let mut old_self = MirScalarExpr::column(0);
922        while old_self != *self {
923            old_self = self.clone();
924            self.reduce_and_canonicalize_and_or(); // We don't want to deal with 1-arg AND/OR at the top
925            if let MirScalarExpr::CallVariadic {
926                exprs: outer_operands,
927                func: outer_func @ (VariadicFunc::Or(_) | VariadicFunc::And(_)),
928            } = self
929            {
930                let inner_func = outer_func.switch_and_or();
931
932                // Make sure that each outer operand is a call to inner_func, by wrapping in a 1-arg
933                // call if necessary.
934                outer_operands.iter_mut().for_each(|o| {
935                    if !matches!(o, MirScalarExpr::CallVariadic {func: f, ..} if *f == inner_func) {
936                        *o = MirScalarExpr::CallVariadic {
937                            func: inner_func.clone(),
938                            exprs: vec![o.take()],
939                        };
940                    }
941                });
942
943                let mut inner_operands_refs: Vec<&mut Vec<MirScalarExpr>> = outer_operands
944                    .iter_mut()
945                    .map(|o| match o {
946                        MirScalarExpr::CallVariadic { func: f, exprs } if *f == inner_func => exprs,
947                        _ => unreachable!(), // the wrapping made sure that we'll get a match
948                    })
949                    .collect();
950
951                // Find inner operands to undistribute, i.e., which are in _all_ of the outer operands.
952                let mut intersection = inner_operands_refs
953                    .iter()
954                    .map(|v| (*v).clone())
955                    .reduce(|ops1, ops2| ops1.into_iter().filter(|e| ops2.contains(e)).collect())
956                    .unwrap();
957                intersection.sort();
958                intersection.dedup();
959
960                if !intersection.is_empty() {
961                    // Factor out the intersection from all the top-level args.
962
963                    // Remove the intersection from each inner operand vector.
964                    inner_operands_refs
965                        .iter_mut()
966                        .for_each(|ops| (**ops).retain(|o| !intersection.contains(o)));
967
968                    // Simplify terms that now have only 0 or 1 args due to removing the intersection.
969                    outer_operands
970                        .iter_mut()
971                        .for_each(|o| o.reduce_and_canonicalize_and_or());
972
973                    // Add the intersection at the beginning
974                    *self = MirScalarExpr::CallVariadic {
975                        func: inner_func,
976                        exprs: intersection.into_iter().chain_one(self.clone()).collect(),
977                    };
978                } else {
979                    // If the intersection was empty, that means that there is nothing we can factor out
980                    // from _all_ the top-level args. However, we might still find something to factor
981                    // out from a subset of the top-level args. To find such an opportunity, we look for
982                    // duplicates across all inner args, e.g. if we have
983                    // `(...) OR (... AND `a` AND ...) OR (...) OR (... AND `a` AND ...)`
984                    // then we'll find that `a` occurs in more than one top-level arg, so
985                    // `indexes_to_undistribute` will point us to the 2. and 4. top-level args.
986
987                    // Create (inner_operand, index) pairs, where the index is the position in
988                    // outer_operands
989                    let all_inner_operands = inner_operands_refs
990                        .iter()
991                        .enumerate()
992                        .flat_map(|(i, inner_vec)| inner_vec.iter().map(move |a| ((*a).clone(), i)))
993                        .sorted()
994                        .collect_vec();
995
996                    // Find inner operand expressions that occur in more than one top-level arg.
997                    // Each inner vector in `undistribution_opportunities` will belong to one such inner
998                    // operand expression, and it is a set of indexes pointing to top-level args where
999                    // that inner operand occurs.
1000                    let undistribution_opportunities = all_inner_operands
1001                        .iter()
1002                        .chunk_by(|(a, _i)| a)
1003                        .into_iter()
1004                        .map(|(_a, g)| g.map(|(_a, i)| *i).sorted().dedup().collect_vec())
1005                        .filter(|g| g.len() > 1)
1006                        .collect_vec();
1007
1008                    // Choose one of the inner vectors from `undistribution_opportunities`.
1009                    let indexes_to_undistribute = undistribution_opportunities
1010                        .iter()
1011                        // Let's prefer index sets that directly lead to an absorption.
1012                        .find(|index_set| {
1013                            index_set
1014                                .iter()
1015                                .any(|i| inner_operands_refs.get(*i).unwrap().len() == 1)
1016                        })
1017                        // If we didn't find any absorption, then any index set will do.
1018                        .or_else(|| undistribution_opportunities.first())
1019                        .cloned();
1020
1021                    // In any case, undo the 1-arg wrapping that we did at the beginning.
1022                    outer_operands
1023                        .iter_mut()
1024                        .for_each(|o| o.reduce_and_canonicalize_and_or());
1025
1026                    if let Some(indexes_to_undistribute) = indexes_to_undistribute {
1027                        // Found something to undistribute from a subset of the outer operands.
1028                        // We temporarily remove these from outer_operands, call ourselves on it, and
1029                        // then push back the result.
1030                        let mut undistribute_from = MirScalarExpr::CallVariadic {
1031                            func: outer_func.clone(),
1032                            exprs: swap_remove_multiple(outer_operands, indexes_to_undistribute),
1033                        };
1034                        // By construction, the recursive call is guaranteed to hit
1035                        // the `!intersection.is_empty()` branch.
1036                        undistribute_from.undistribute_and_or();
1037                        // Append the undistributed result to outer operands that were not included in
1038                        // indexes_to_undistribute.
1039                        outer_operands.push(undistribute_from);
1040                    }
1041                }
1042            }
1043        }
1044    }
1045
1046    /* #endregion */
1047
1048    /// Adds any columns that *must* be non-Null for `self` to be non-Null.
1049    pub fn non_null_requirements(&self, columns: &mut BTreeSet<usize>) {
1050        match self {
1051            MirScalarExpr::Column(col, _name) => {
1052                columns.insert(*col);
1053            }
1054            MirScalarExpr::Literal(..) => {}
1055            MirScalarExpr::CallUnmaterializable(_) => (),
1056            MirScalarExpr::CallUnary { func, expr } => {
1057                if func.propagates_nulls() {
1058                    expr.non_null_requirements(columns);
1059                }
1060            }
1061            MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1062                if func.propagates_nulls() {
1063                    expr1.non_null_requirements(columns);
1064                    expr2.non_null_requirements(columns);
1065                }
1066            }
1067            MirScalarExpr::CallVariadic { func, exprs } => {
1068                if func.propagates_nulls() {
1069                    for expr in exprs {
1070                        expr.non_null_requirements(columns);
1071                    }
1072                }
1073            }
1074            MirScalarExpr::If { .. } => (),
1075        }
1076    }
1077
1078    pub fn sql_typ(&self, column_types: &[SqlColumnType]) -> SqlColumnType {
1079        let repr_column_types = column_types.iter().map(ReprColumnType::from).collect_vec();
1080        SqlColumnType::from_repr(&self.typ(&repr_column_types))
1081    }
1082
1083    pub fn typ(&self, column_types: &[ReprColumnType]) -> ReprColumnType {
1084        match self {
1085            MirScalarExpr::Column(i, _name) => column_types[*i].clone(),
1086            MirScalarExpr::Literal(_, typ) => typ.clone(),
1087            MirScalarExpr::CallUnmaterializable(func) => func.output_type(),
1088            MirScalarExpr::CallUnary { expr, func } => func.output_type(expr.typ(column_types)),
1089            MirScalarExpr::CallBinary { expr1, expr2, func } => {
1090                func.output_type(&[expr1.typ(column_types), expr2.typ(column_types)])
1091            }
1092            MirScalarExpr::CallVariadic { exprs, func } => {
1093                func.output_type(exprs.iter().map(|e| e.typ(column_types)).collect())
1094            }
1095            MirScalarExpr::If { cond: _, then, els } => {
1096                let then_type = then.typ(column_types);
1097                let else_type = els.typ(column_types);
1098                then_type.union(&else_type).unwrap()
1099            }
1100        }
1101    }
1102
1103    /// True iff the expression contains
1104    /// `UnmaterializableFunc::MzNow`.
1105    pub fn contains_temporal(&self) -> bool {
1106        let mut contains = false;
1107        self.visit_pre(|e| {
1108            if let MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow) = e {
1109                contains = true;
1110            }
1111        });
1112        contains
1113    }
1114
1115    /// True iff the expression contains an `UnmaterializableFunc`.
1116    pub fn contains_unmaterializable(&self) -> bool {
1117        let mut contains = false;
1118        self.visit_pre(|e| {
1119            if let MirScalarExpr::CallUnmaterializable(_) = e {
1120                contains = true;
1121            }
1122        });
1123        contains
1124    }
1125
1126    /// True iff the expression contains an `UnmaterializableFunc` that is not in the `exceptions`
1127    /// list.
1128    pub fn contains_unmaterializable_except(&self, exceptions: &[UnmaterializableFunc]) -> bool {
1129        let mut contains = false;
1130        self.visit_pre(|e| match e {
1131            MirScalarExpr::CallUnmaterializable(f) if !exceptions.contains(f) => contains = true,
1132            _ => (),
1133        });
1134        contains
1135    }
1136
1137    /// True iff the expression contains a `Column`.
1138    pub fn contains_column(&self) -> bool {
1139        let mut contains = false;
1140        self.visit_pre(|e| {
1141            if let MirScalarExpr::Column(_col, _name) = e {
1142                contains = true;
1143            }
1144        });
1145        contains
1146    }
1147
1148    /// True iff the expression contains a `Dummy`.
1149    pub fn contains_dummy(&self) -> bool {
1150        let mut contains = false;
1151        self.visit_pre(|e| {
1152            if let MirScalarExpr::Literal(row, _) = e {
1153                if let Ok(row) = row {
1154                    contains |= row.iter().any(|d| d.contains_dummy());
1155                }
1156            }
1157        });
1158        contains
1159    }
1160
1161    /// The size of the expression as a tree.
1162    pub fn size(&self) -> usize {
1163        let mut size = 0;
1164        self.visit_pre(&mut |_: &MirScalarExpr| {
1165            size += 1;
1166        });
1167        size
1168    }
1169}
1170
1171impl Eval for MirScalarExpr {
1172    fn eval<'a>(
1173        &'a self,
1174        datums: &[Datum<'a>],
1175        temp_storage: &'a RowArena,
1176    ) -> Result<Datum<'a>, EvalError> {
1177        match self {
1178            MirScalarExpr::Column(index, _name) => Ok(datums[*index]),
1179            MirScalarExpr::Literal(res, _column_type) => match res {
1180                Ok(row) => Ok(row.unpack_first()),
1181                Err(e) => Err(e.clone()),
1182            },
1183            // Unmaterializable functions must be transformed away before
1184            // evaluation. Their purpose is as a placeholder for data that is
1185            // not known at plan time but can be inlined before runtime.
1186            MirScalarExpr::CallUnmaterializable(x) => Err(EvalError::Internal(
1187                format!("cannot evaluate unmaterializable function: {:?}", x).into(),
1188            )),
1189            MirScalarExpr::CallUnary { func, expr } => {
1190                func.eval(datums, temp_storage, expr.as_ref())
1191            }
1192            MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1193                func.eval(datums, temp_storage, &[expr1.as_ref(), expr2.as_ref()])
1194            }
1195            MirScalarExpr::CallVariadic { func, exprs } => {
1196                func.eval(datums, temp_storage, exprs.as_slice())
1197            }
1198            MirScalarExpr::If { cond, then, els } => match cond.eval(datums, temp_storage)? {
1199                Datum::True => then.eval(datums, temp_storage),
1200                Datum::False | Datum::Null => els.eval(datums, temp_storage),
1201                d => Err(EvalError::Internal(
1202                    format!("if condition evaluated to non-boolean datum: {:?}", d).into(),
1203                )),
1204            },
1205        }
1206    }
1207
1208    fn could_error(&self) -> bool {
1209        match self {
1210            MirScalarExpr::Column(_col, _name) => false,
1211            MirScalarExpr::Literal(row, ..) => row.is_err(),
1212            MirScalarExpr::CallUnmaterializable(_) => true,
1213            MirScalarExpr::CallUnary { func, expr } => func.could_error() || expr.could_error(),
1214            MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1215                func.could_error() || expr1.could_error() || expr2.could_error()
1216            }
1217            MirScalarExpr::CallVariadic { func, exprs } => {
1218                func.could_error() || exprs.iter().any(|e| e.could_error())
1219            }
1220            MirScalarExpr::If { cond, then, els } => {
1221                cond.could_error() || then.could_error() || els.could_error()
1222            }
1223        }
1224    }
1225}
1226
1227impl Columns for MirScalarExpr {
1228    fn column(c: usize) -> Self {
1229        MirScalarExpr::column(c)
1230    }
1231
1232    fn is_column(&self) -> bool {
1233        matches!(self, MirScalarExpr::Column(_col, _name))
1234    }
1235
1236    fn as_column(&self) -> Option<usize> {
1237        if let MirScalarExpr::Column(c, _) = self {
1238            Some(*c)
1239        } else {
1240            None
1241        }
1242    }
1243
1244    fn as_column_mut(&mut self) -> Option<&mut usize> {
1245        if let MirScalarExpr::Column(c, _) = self {
1246            Some(c)
1247        } else {
1248            None
1249        }
1250    }
1251
1252    fn support_into(&self, support: &mut BTreeSet<usize>) {
1253        self.visit_pre(|e| {
1254            if let MirScalarExpr::Column(i, _) = e {
1255                support.insert(*i);
1256            }
1257        });
1258    }
1259
1260    fn visit_columns<F>(&mut self, mut action: F)
1261    where
1262        F: FnMut(&mut usize),
1263    {
1264        self.visit_pre_mut(|e| {
1265            if let MirScalarExpr::Column(col, _) = e {
1266                action(col);
1267            }
1268        });
1269    }
1270}
1271
1272impl VisitChildren<Self> for MirScalarExpr {
1273    fn visit_children<F>(&self, mut f: F)
1274    where
1275        F: FnMut(&Self),
1276    {
1277        use MirScalarExpr::*;
1278        match self {
1279            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1280            CallUnary { expr, .. } => {
1281                f(expr);
1282            }
1283            CallBinary { expr1, expr2, .. } => {
1284                f(expr1);
1285                f(expr2);
1286            }
1287            CallVariadic { exprs, .. } => {
1288                for expr in exprs {
1289                    f(expr);
1290                }
1291            }
1292            If { cond, then, els } => {
1293                f(cond);
1294                f(then);
1295                f(els);
1296            }
1297        }
1298    }
1299
1300    fn visit_mut_children<F>(&mut self, mut f: F)
1301    where
1302        F: FnMut(&mut Self),
1303    {
1304        use MirScalarExpr::*;
1305        match self {
1306            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1307            CallUnary { expr, .. } => {
1308                f(expr);
1309            }
1310            CallBinary { expr1, expr2, .. } => {
1311                f(expr1);
1312                f(expr2);
1313            }
1314            CallVariadic { exprs, .. } => {
1315                for expr in exprs {
1316                    f(expr);
1317                }
1318            }
1319            If { cond, then, els } => {
1320                f(cond);
1321                f(then);
1322                f(els);
1323            }
1324        }
1325    }
1326
1327    fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
1328    where
1329        F: FnMut(&Self) -> Result<(), E>,
1330        E: From<RecursionLimitError>,
1331    {
1332        use MirScalarExpr::*;
1333        match self {
1334            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1335            CallUnary { expr, .. } => {
1336                f(expr)?;
1337            }
1338            CallBinary { expr1, expr2, .. } => {
1339                f(expr1)?;
1340                f(expr2)?;
1341            }
1342            CallVariadic { exprs, .. } => {
1343                for expr in exprs {
1344                    f(expr)?;
1345                }
1346            }
1347            If { cond, then, els } => {
1348                f(cond)?;
1349                f(then)?;
1350                f(els)?;
1351            }
1352        }
1353        Ok(())
1354    }
1355
1356    fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
1357    where
1358        F: FnMut(&mut Self) -> Result<(), E>,
1359        E: From<RecursionLimitError>,
1360    {
1361        use MirScalarExpr::*;
1362        match self {
1363            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1364            CallUnary { expr, .. } => {
1365                f(expr)?;
1366            }
1367            CallBinary { expr1, expr2, .. } => {
1368                f(expr1)?;
1369                f(expr2)?;
1370            }
1371            CallVariadic { exprs, .. } => {
1372                for expr in exprs {
1373                    f(expr)?;
1374                }
1375            }
1376            If { cond, then, els } => {
1377                f(cond)?;
1378                f(then)?;
1379                f(els)?;
1380            }
1381        }
1382        Ok(())
1383    }
1384}
1385
1386impl MirScalarExpr {
1387    /// Iterates through references to child expressions.
1388    pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self> {
1389        let mut first = None;
1390        let mut second = None;
1391        let mut third = None;
1392        let mut variadic = None;
1393
1394        use MirScalarExpr::*;
1395        match self {
1396            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1397            CallUnary { expr, .. } => {
1398                first = Some(&**expr);
1399            }
1400            CallBinary { expr1, expr2, .. } => {
1401                first = Some(&**expr1);
1402                second = Some(&**expr2);
1403            }
1404            CallVariadic { exprs, .. } => {
1405                variadic = Some(exprs);
1406            }
1407            If { cond, then, els } => {
1408                first = Some(&**cond);
1409                second = Some(&**then);
1410                third = Some(&**els);
1411            }
1412        }
1413
1414        first
1415            .into_iter()
1416            .chain(second)
1417            .chain(third)
1418            .chain(variadic.into_iter().flatten())
1419    }
1420
1421    /// Iterates through mutable references to child expressions.
1422    pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self> {
1423        let mut first = None;
1424        let mut second = None;
1425        let mut third = None;
1426        let mut variadic = None;
1427
1428        use MirScalarExpr::*;
1429        match self {
1430            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1431            CallUnary { expr, .. } => {
1432                first = Some(&mut **expr);
1433            }
1434            CallBinary { expr1, expr2, .. } => {
1435                first = Some(&mut **expr1);
1436                second = Some(&mut **expr2);
1437            }
1438            CallVariadic { exprs, .. } => {
1439                variadic = Some(exprs);
1440            }
1441            If { cond, then, els } => {
1442                first = Some(&mut **cond);
1443                second = Some(&mut **then);
1444                third = Some(&mut **els);
1445            }
1446        }
1447
1448        first
1449            .into_iter()
1450            .chain(second)
1451            .chain(third)
1452            .chain(variadic.into_iter().flatten())
1453    }
1454
1455    /// Visits all subexpressions in DFS preorder.
1456    pub fn visit_pre<F>(&self, mut f: F)
1457    where
1458        F: FnMut(&Self),
1459    {
1460        let mut worklist = vec![self];
1461        while let Some(e) = worklist.pop() {
1462            f(e);
1463            worklist.extend(e.children().rev());
1464        }
1465    }
1466
1467    /// Iterative pre-order visitor.
1468    pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, mut f: F) {
1469        let mut worklist = vec![self];
1470        while let Some(expr) = worklist.pop() {
1471            f(expr);
1472            worklist.extend(expr.children_mut().rev());
1473        }
1474    }
1475}
1476
1477/// Filter characteristics that are used for ordering join inputs.
1478/// This can be created for a `Vec<MirScalarExpr>`, which represents an AND of predicates.
1479///
1480/// The fields are ordered based on heuristic assumptions about their typical selectivity, so that
1481/// Ord gives the right ordering for join inputs. Bigger is better, i.e., will tend to come earlier
1482/// than other inputs.
1483#[derive(
1484    Eq,
1485    PartialEq,
1486    Ord,
1487    PartialOrd,
1488    Debug,
1489    Clone,
1490    Serialize,
1491    Deserialize,
1492    Hash,
1493    MzReflect
1494)]
1495pub struct FilterCharacteristics {
1496    // `<expr> = <literal>` appears in the filter.
1497    // Excludes cases where NOT appears anywhere above the literal equality.
1498    literal_equality: bool,
1499    // (Assuming a random string of lower-case characters, `LIKE 'a%'` has a selectivity of 1/26.)
1500    like: bool,
1501    is_null: bool,
1502    // Number of Vec elements that involve inequality predicates. (A BETWEEN is represented as two
1503    // inequality predicates.)
1504    // Excludes cases where NOT appears around the literal inequality.
1505    // Note that for inequality predicates, some databases assume 1/3 selectivity in the absence of
1506    // concrete statistics.
1507    literal_inequality: usize,
1508    /// Any filter, except ones involving `IS NOT NULL`, because those are too common.
1509    /// Can be true by itself, or any other field being true can also make this true.
1510    /// `NOT LIKE` is only in this category.
1511    /// `!=` is only in this category.
1512    /// `NOT (a = b)` is turned into `!=` by `reduce` before us!
1513    any_filter: bool,
1514}
1515
1516impl BitOrAssign for FilterCharacteristics {
1517    fn bitor_assign(&mut self, rhs: Self) {
1518        self.literal_equality |= rhs.literal_equality;
1519        self.like |= rhs.like;
1520        self.is_null |= rhs.is_null;
1521        self.literal_inequality += rhs.literal_inequality;
1522        self.any_filter |= rhs.any_filter;
1523    }
1524}
1525
1526impl FilterCharacteristics {
1527    pub fn none() -> FilterCharacteristics {
1528        FilterCharacteristics {
1529            literal_equality: false,
1530            like: false,
1531            is_null: false,
1532            literal_inequality: 0,
1533            any_filter: false,
1534        }
1535    }
1536
1537    pub fn explain(&self) -> String {
1538        let mut e = "".to_owned();
1539        if self.literal_equality {
1540            e.push_str("e");
1541        }
1542        if self.like {
1543            e.push_str("l");
1544        }
1545        if self.is_null {
1546            e.push_str("n");
1547        }
1548        for _ in 0..self.literal_inequality {
1549            e.push_str("i");
1550        }
1551        if self.any_filter {
1552            e.push_str("f");
1553        }
1554        e
1555    }
1556
1557    pub fn filter_characteristics(
1558        filters: &Vec<MirScalarExpr>,
1559    ) -> Result<FilterCharacteristics, RecursionLimitError> {
1560        let mut literal_equality = false;
1561        let mut like = false;
1562        let mut is_null = false;
1563        let mut literal_inequality = 0;
1564        let mut any_filter = false;
1565        filters.iter().try_for_each(|f| {
1566            let mut literal_inequality_in_current_filter = false;
1567            let mut is_not_null_in_current_filter = false;
1568            f.visit_pre_with_context(
1569                false,
1570                &mut |not_in_parent_chain, expr| {
1571                    not_in_parent_chain
1572                        || matches!(
1573                            expr,
1574                            MirScalarExpr::CallUnary {
1575                                func: UnaryFunc::Not(func::Not),
1576                                ..
1577                            }
1578                        )
1579                },
1580                &mut |not_in_parent_chain, expr| {
1581                    if !not_in_parent_chain {
1582                        if expr.any_expr_eq_literal().is_some() {
1583                            literal_equality = true;
1584                        }
1585                        if expr.any_expr_ineq_literal() {
1586                            literal_inequality_in_current_filter = true;
1587                        }
1588                        if matches!(
1589                            expr,
1590                            MirScalarExpr::CallUnary {
1591                                func: UnaryFunc::IsLikeMatch(_),
1592                                ..
1593                            }
1594                        ) {
1595                            like = true;
1596                        }
1597                    };
1598                    if matches!(
1599                        expr,
1600                        MirScalarExpr::CallUnary {
1601                            func: UnaryFunc::IsNull(crate::func::IsNull),
1602                            ..
1603                        }
1604                    ) {
1605                        if *not_in_parent_chain {
1606                            is_not_null_in_current_filter = true;
1607                        } else {
1608                            is_null = true;
1609                        }
1610                    }
1611                },
1612            )?;
1613            if literal_inequality_in_current_filter {
1614                literal_inequality += 1;
1615            }
1616            if !is_not_null_in_current_filter {
1617                // We want to ignore `IS NOT NULL` for `any_filter`.
1618                any_filter = true;
1619            }
1620            Ok(())
1621        })?;
1622        Ok(FilterCharacteristics {
1623            literal_equality,
1624            like,
1625            is_null,
1626            literal_inequality,
1627            any_filter,
1628        })
1629    }
1630
1631    pub fn add_literal_equality(&mut self) {
1632        self.literal_equality = true;
1633    }
1634
1635    pub fn worst_case_scaling_factor(&self) -> f64 {
1636        let mut factor = 1.0;
1637
1638        if self.literal_equality {
1639            factor *= 0.1;
1640        }
1641
1642        if self.is_null {
1643            factor *= 0.1;
1644        }
1645
1646        if self.literal_inequality >= 2 {
1647            factor *= 0.25;
1648        } else if self.literal_inequality == 1 {
1649            factor *= 0.33;
1650        }
1651
1652        // catch various negated filters, treat them pessimistically
1653        if !(self.literal_equality || self.is_null || self.literal_inequality > 0)
1654            && self.any_filter
1655        {
1656            factor *= 0.9;
1657        }
1658
1659        factor
1660    }
1661}
1662
1663#[derive(
1664    Ord,
1665    PartialOrd,
1666    Copy,
1667    Clone,
1668    Debug,
1669    Eq,
1670    PartialEq,
1671    Serialize,
1672    Deserialize,
1673    Hash,
1674    MzReflect
1675)]
1676#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1677pub enum DomainLimit {
1678    None,
1679    Inclusive(i64),
1680    Exclusive(i64),
1681}
1682
1683impl RustType<ProtoDomainLimit> for DomainLimit {
1684    fn into_proto(&self) -> ProtoDomainLimit {
1685        use proto_domain_limit::Kind::*;
1686        let kind = match self {
1687            DomainLimit::None => None(()),
1688            DomainLimit::Inclusive(v) => Inclusive(*v),
1689            DomainLimit::Exclusive(v) => Exclusive(*v),
1690        };
1691        ProtoDomainLimit { kind: Some(kind) }
1692    }
1693
1694    fn from_proto(proto: ProtoDomainLimit) -> Result<Self, TryFromProtoError> {
1695        use proto_domain_limit::Kind::*;
1696        if let Some(kind) = proto.kind {
1697            match kind {
1698                None(()) => Ok(DomainLimit::None),
1699                Inclusive(v) => Ok(DomainLimit::Inclusive(v)),
1700                Exclusive(v) => Ok(DomainLimit::Exclusive(v)),
1701            }
1702        } else {
1703            Err(TryFromProtoError::missing_field("ProtoDomainLimit::kind"))
1704        }
1705    }
1706}
1707
1708#[derive(
1709    Ord,
1710    PartialOrd,
1711    Clone,
1712    Debug,
1713    Eq,
1714    PartialEq,
1715    Serialize,
1716    Deserialize,
1717    Hash,
1718    MzReflect
1719)]
1720#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1721pub enum EvalError {
1722    CharacterNotValidForEncoding(i32),
1723    CharacterTooLargeForEncoding(i32),
1724    DateBinOutOfRange(Box<str>),
1725    DivisionByZero,
1726    Unsupported {
1727        feature: Box<str>,
1728        discussion_no: Option<usize>,
1729    },
1730    FloatOverflow,
1731    FloatUnderflow,
1732    NumericFieldOverflow,
1733    Float32OutOfRange(Box<str>),
1734    Float64OutOfRange(Box<str>),
1735    Int16OutOfRange(Box<str>),
1736    Int32OutOfRange(Box<str>),
1737    Int64OutOfRange(Box<str>),
1738    UInt16OutOfRange(Box<str>),
1739    UInt32OutOfRange(Box<str>),
1740    UInt64OutOfRange(Box<str>),
1741    MzTimestampOutOfRange(Box<str>),
1742    MzTimestampStepOverflow,
1743    OidOutOfRange(Box<str>),
1744    IntervalOutOfRange(Box<str>),
1745    TimestampCannotBeNan,
1746    TimestampOutOfRange,
1747    DateOutOfRange,
1748    CharOutOfRange,
1749    IndexOutOfRange {
1750        provided: i32,
1751        // The last valid index position, i.e. `v.len() - 1`
1752        valid_end: i32,
1753    },
1754    InvalidBase64Equals,
1755    InvalidBase64Symbol(char),
1756    InvalidBase64EndSequence,
1757    InvalidTimezone(Box<str>),
1758    InvalidTimezoneInterval,
1759    InvalidTimezoneConversion,
1760    InvalidIanaTimezoneId(Box<str>),
1761    InvalidLayer {
1762        max_layer: usize,
1763        val: i64,
1764    },
1765    InvalidArray(InvalidArrayError),
1766    InvalidEncodingName(Box<str>),
1767    InvalidHashAlgorithm(Box<str>),
1768    InvalidByteSequence {
1769        byte_sequence: Box<str>,
1770        encoding_name: Box<str>,
1771    },
1772    InvalidJsonbCast {
1773        from: Box<str>,
1774        to: Box<str>,
1775    },
1776    InvalidRegex(Box<str>),
1777    InvalidRegexFlag(char),
1778    InvalidParameterValue(Box<str>),
1779    InvalidDatePart(Box<str>),
1780    KeyCannotBeNull,
1781    NegSqrt,
1782    NegLimit,
1783    NullCharacterNotPermitted,
1784    UnknownUnits(Box<str>),
1785    UnsupportedUnits(Box<str>, Box<str>),
1786    UnterminatedLikeEscapeSequence,
1787    Parse(ParseError),
1788    ParseHex(ParseHexError),
1789    Internal(Box<str>),
1790    InfinityOutOfDomain(Box<str>),
1791    NegativeOutOfDomain(Box<str>),
1792    ZeroOutOfDomain(Box<str>),
1793    OutOfDomain(DomainLimit, DomainLimit, Box<str>),
1794    ComplexOutOfRange(Box<str>),
1795    MultipleRowsFromSubquery,
1796    NegativeRowsFromSubquery,
1797    Undefined(Box<str>),
1798    LikePatternTooLong,
1799    LikeEscapeTooLong,
1800    StringValueTooLong {
1801        target_type: Box<str>,
1802        length: usize,
1803    },
1804    MultidimensionalArrayRemovalNotSupported,
1805    IncompatibleArrayDimensions {
1806        dims: Option<(usize, usize)>,
1807    },
1808    TypeFromOid(Box<str>),
1809    InvalidRange(InvalidRangeError),
1810    InvalidRoleId(Box<str>),
1811    InvalidPrivileges(Box<str>),
1812    InvalidCatalogJson(Box<str>),
1813    LetRecLimitExceeded(Box<str>),
1814    MultiDimensionalArraySearch,
1815    MustNotBeNull(Box<str>),
1816    InvalidIdentifier {
1817        ident: Box<str>,
1818        detail: Option<Box<str>>,
1819    },
1820    ArrayFillWrongArraySubscripts,
1821    // TODO: propagate this check more widely throughout the expr crate
1822    MaxArraySizeExceeded(usize),
1823    DateDiffOverflow {
1824        unit: Box<str>,
1825        a: Box<str>,
1826        b: Box<str>,
1827    },
1828    // The error for ErrorIfNull; this should not be used in other contexts as a generic error
1829    // printer.
1830    IfNullError(Box<str>),
1831    LengthTooLarge,
1832    AclArrayNullElement,
1833    MzAclArrayNullElement,
1834    PrettyError(Box<str>),
1835    RedactError(Box<str>),
1836}
1837
1838impl fmt::Display for EvalError {
1839    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1840        match self {
1841            EvalError::CharacterNotValidForEncoding(v) => {
1842                write!(f, "requested character not valid for encoding: {v}")
1843            }
1844            EvalError::CharacterTooLargeForEncoding(v) => {
1845                write!(f, "requested character too large for encoding: {v}")
1846            }
1847            EvalError::DateBinOutOfRange(message) => f.write_str(message),
1848            EvalError::DivisionByZero => f.write_str("division by zero"),
1849            EvalError::Unsupported {
1850                feature,
1851                discussion_no,
1852            } => {
1853                write!(f, "{} not yet supported", feature)?;
1854                if let Some(discussion_no) = discussion_no {
1855                    write!(
1856                        f,
1857                        ", see https://github.com/MaterializeInc/materialize/discussions/{} for more details",
1858                        discussion_no
1859                    )?;
1860                }
1861                Ok(())
1862            }
1863            EvalError::FloatOverflow => f.write_str("value out of range: overflow"),
1864            EvalError::FloatUnderflow => f.write_str("value out of range: underflow"),
1865            EvalError::NumericFieldOverflow => f.write_str("numeric field overflow"),
1866            EvalError::Float32OutOfRange(val) => write!(f, "{} real out of range", val.quoted()),
1867            EvalError::Float64OutOfRange(val) => {
1868                write!(f, "{} double precision out of range", val.quoted())
1869            }
1870            EvalError::Int16OutOfRange(val) => write!(f, "{} smallint out of range", val.quoted()),
1871            EvalError::Int32OutOfRange(val) => write!(f, "{} integer out of range", val.quoted()),
1872            EvalError::Int64OutOfRange(val) => write!(f, "{} bigint out of range", val.quoted()),
1873            EvalError::UInt16OutOfRange(val) => write!(f, "{} uint2 out of range", val.quoted()),
1874            EvalError::UInt32OutOfRange(val) => write!(f, "{} uint4 out of range", val.quoted()),
1875            EvalError::UInt64OutOfRange(val) => write!(f, "{} uint8 out of range", val.quoted()),
1876            EvalError::MzTimestampOutOfRange(val) => {
1877                write!(f, "{} mz_timestamp out of range", val.quoted())
1878            }
1879            EvalError::MzTimestampStepOverflow => f.write_str("step mz_timestamp overflow"),
1880            EvalError::OidOutOfRange(val) => write!(f, "{} OID out of range", val.quoted()),
1881            EvalError::IntervalOutOfRange(val) => {
1882                write!(f, "{} interval out of range", val.quoted())
1883            }
1884            EvalError::TimestampCannotBeNan => f.write_str("timestamp cannot be NaN"),
1885            EvalError::TimestampOutOfRange => f.write_str("timestamp out of range"),
1886            EvalError::DateOutOfRange => f.write_str("date out of range"),
1887            EvalError::CharOutOfRange => f.write_str("\"char\" out of range"),
1888            EvalError::IndexOutOfRange {
1889                provided,
1890                valid_end,
1891            } => write!(f, "index {provided} out of valid range, 0..{valid_end}",),
1892            EvalError::InvalidBase64Equals => {
1893                f.write_str("unexpected \"=\" while decoding base64 sequence")
1894            }
1895            EvalError::InvalidBase64Symbol(c) => write!(
1896                f,
1897                "invalid symbol \"{}\" found while decoding base64 sequence",
1898                c.escape_default()
1899            ),
1900            EvalError::InvalidBase64EndSequence => f.write_str("invalid base64 end sequence"),
1901            EvalError::InvalidJsonbCast { from, to } => {
1902                write!(f, "cannot cast jsonb {} to type {}", from, to)
1903            }
1904            EvalError::InvalidTimezone(tz) => write!(f, "invalid time zone '{}'", tz),
1905            EvalError::InvalidTimezoneInterval => {
1906                f.write_str("timezone interval must not contain months or years")
1907            }
1908            EvalError::InvalidTimezoneConversion => f.write_str("invalid timezone conversion"),
1909            EvalError::InvalidIanaTimezoneId(tz) => {
1910                write!(f, "invalid IANA Time Zone Database identifier: '{}'", tz)
1911            }
1912            EvalError::InvalidLayer { max_layer, val } => write!(
1913                f,
1914                "invalid layer: {}; must use value within [1, {}]",
1915                val, max_layer
1916            ),
1917            EvalError::InvalidArray(e) => e.fmt(f),
1918            EvalError::InvalidEncodingName(name) => write!(f, "invalid encoding name '{}'", name),
1919            EvalError::InvalidHashAlgorithm(alg) => write!(f, "invalid hash algorithm '{}'", alg),
1920            EvalError::InvalidByteSequence {
1921                byte_sequence,
1922                encoding_name,
1923            } => write!(
1924                f,
1925                "invalid byte sequence '{}' for encoding '{}'",
1926                byte_sequence, encoding_name
1927            ),
1928            EvalError::InvalidDatePart(part) => write!(f, "invalid datepart {}", part.quoted()),
1929            EvalError::KeyCannotBeNull => f.write_str("key cannot be null"),
1930            EvalError::NegSqrt => f.write_str("cannot take square root of a negative number"),
1931            EvalError::NegLimit => f.write_str("LIMIT must not be negative"),
1932            EvalError::NullCharacterNotPermitted => f.write_str("null character not permitted"),
1933            EvalError::InvalidRegex(e) => write!(f, "invalid regular expression: {}", e),
1934            EvalError::InvalidRegexFlag(c) => write!(f, "invalid regular expression flag: {}", c),
1935            EvalError::InvalidParameterValue(s) => f.write_str(s),
1936            EvalError::UnknownUnits(units) => write!(f, "unit '{}' not recognized", units),
1937            EvalError::UnsupportedUnits(units, typ) => {
1938                write!(f, "unit '{}' not supported for type {}", units, typ)
1939            }
1940            EvalError::UnterminatedLikeEscapeSequence => {
1941                f.write_str("unterminated escape sequence in LIKE")
1942            }
1943            EvalError::Parse(e) => e.fmt(f),
1944            EvalError::PrettyError(e) => e.fmt(f),
1945            EvalError::RedactError(e) => e.fmt(f),
1946            EvalError::ParseHex(e) => e.fmt(f),
1947            EvalError::Internal(s) => write!(f, "internal error: {}", s),
1948            EvalError::InfinityOutOfDomain(s) => {
1949                write!(f, "function {} is only defined for finite arguments", s)
1950            }
1951            EvalError::NegativeOutOfDomain(s) => {
1952                write!(f, "function {} is not defined for negative numbers", s)
1953            }
1954            EvalError::ZeroOutOfDomain(s) => {
1955                write!(f, "function {} is not defined for zero", s)
1956            }
1957            EvalError::OutOfDomain(lower, upper, s) => {
1958                use DomainLimit::*;
1959                write!(f, "function {s} is defined for numbers ")?;
1960                match (lower, upper) {
1961                    (Inclusive(n), None) => write!(f, "greater than or equal to {n}"),
1962                    (Exclusive(n), None) => write!(f, "greater than {n}"),
1963                    (None, Inclusive(n)) => write!(f, "less than or equal to {n}"),
1964                    (None, Exclusive(n)) => write!(f, "less than {n}"),
1965                    (Inclusive(lo), Inclusive(hi)) => write!(f, "between {lo} and {hi} inclusive"),
1966                    (Exclusive(lo), Exclusive(hi)) => write!(f, "between {lo} and {hi} exclusive"),
1967                    (Inclusive(lo), Exclusive(hi)) => {
1968                        write!(f, "between {lo} inclusive and {hi} exclusive")
1969                    }
1970                    (Exclusive(lo), Inclusive(hi)) => {
1971                        write!(f, "between {lo} exclusive and {hi} inclusive")
1972                    }
1973                    (None, None) => panic!("invalid domain error"),
1974                }
1975            }
1976            EvalError::ComplexOutOfRange(s) => {
1977                write!(f, "function {} cannot return complex numbers", s)
1978            }
1979            EvalError::MultipleRowsFromSubquery => {
1980                write!(f, "more than one record produced in subquery")
1981            }
1982            EvalError::NegativeRowsFromSubquery => {
1983                write!(f, "negative number of rows produced in subquery")
1984            }
1985            EvalError::Undefined(s) => {
1986                write!(f, "{} is undefined", s)
1987            }
1988            EvalError::LikePatternTooLong => {
1989                write!(f, "LIKE pattern exceeds maximum length")
1990            }
1991            EvalError::LikeEscapeTooLong => {
1992                write!(f, "invalid escape string")
1993            }
1994            EvalError::StringValueTooLong {
1995                target_type,
1996                length,
1997            } => {
1998                write!(f, "value too long for type {}({})", target_type, length)
1999            }
2000            EvalError::MultidimensionalArrayRemovalNotSupported => {
2001                write!(
2002                    f,
2003                    "removing elements from multidimensional arrays is not supported"
2004                )
2005            }
2006            EvalError::IncompatibleArrayDimensions { dims: _ } => {
2007                write!(f, "cannot concatenate incompatible arrays")
2008            }
2009            EvalError::TypeFromOid(msg) => write!(f, "{msg}"),
2010            EvalError::InvalidRange(e) => e.fmt(f),
2011            EvalError::InvalidRoleId(msg) => write!(f, "{msg}"),
2012            EvalError::InvalidPrivileges(privilege) => {
2013                write!(f, "unrecognized privilege type: {privilege}")
2014            }
2015            EvalError::InvalidCatalogJson(msg) => {
2016                write!(f, "invalid catalog JSON: {msg}")
2017            }
2018            EvalError::LetRecLimitExceeded(max_iters) => {
2019                write!(
2020                    f,
2021                    "Recursive query exceeded the recursion limit {}. (Use RETURN AT RECURSION LIMIT to not error, but return the current state as the final result when reaching the limit.)",
2022                    max_iters
2023                )
2024            }
2025            EvalError::MultiDimensionalArraySearch => write!(
2026                f,
2027                "searching for elements in multidimensional arrays is not supported"
2028            ),
2029            EvalError::MustNotBeNull(v) => write!(f, "{v} must not be null"),
2030            EvalError::InvalidIdentifier { ident, .. } => {
2031                write!(f, "string is not a valid identifier: {}", ident.quoted())
2032            }
2033            EvalError::ArrayFillWrongArraySubscripts => {
2034                f.write_str("wrong number of array subscripts")
2035            }
2036            EvalError::MaxArraySizeExceeded(max_size) => {
2037                write!(
2038                    f,
2039                    "array size exceeds the maximum allowed ({max_size} bytes)"
2040                )
2041            }
2042            EvalError::DateDiffOverflow { unit, a, b } => {
2043                write!(f, "datediff overflow, {unit} of {a}, {b}")
2044            }
2045            EvalError::IfNullError(s) => f.write_str(s),
2046            EvalError::LengthTooLarge => write!(f, "requested length too large"),
2047            EvalError::AclArrayNullElement => write!(f, "ACL arrays must not contain null values"),
2048            EvalError::MzAclArrayNullElement => {
2049                write!(f, "MZ_ACL arrays must not contain null values")
2050            }
2051        }
2052    }
2053}
2054
2055impl EvalError {
2056    pub fn detail(&self) -> Option<String> {
2057        match self {
2058            EvalError::IncompatibleArrayDimensions { dims: None } => Some(
2059                "Arrays with differing dimensions are not compatible for concatenation.".into(),
2060            ),
2061            EvalError::IncompatibleArrayDimensions {
2062                dims: Some((a_dims, b_dims)),
2063            } => Some(format!(
2064                "Arrays of {} and {} dimensions are not compatible for concatenation.",
2065                a_dims, b_dims
2066            )),
2067            EvalError::InvalidIdentifier { detail, .. } => detail.as_deref().map(Into::into),
2068            EvalError::ArrayFillWrongArraySubscripts => {
2069                Some("Low bound array has different size than dimensions array.".into())
2070            }
2071            _ => None,
2072        }
2073    }
2074
2075    pub fn hint(&self) -> Option<String> {
2076        match self {
2077            EvalError::InvalidBase64EndSequence => Some(
2078                "Input data is missing padding, is truncated, or is otherwise corrupted.".into(),
2079            ),
2080            EvalError::LikeEscapeTooLong => {
2081                Some("Escape string must be empty or one character.".into())
2082            }
2083            EvalError::MzTimestampOutOfRange(_) => Some(
2084                "Integer, numeric, and text casts to mz_timestamp must be in the form of whole \
2085                milliseconds since the Unix epoch. Values with fractional parts cannot be \
2086                converted to mz_timestamp."
2087                    .into(),
2088            ),
2089            _ => None,
2090        }
2091    }
2092}
2093
2094impl std::error::Error for EvalError {}
2095
2096impl From<ParseError> for EvalError {
2097    fn from(e: ParseError) -> EvalError {
2098        EvalError::Parse(e)
2099    }
2100}
2101
2102impl From<ParseHexError> for EvalError {
2103    fn from(e: ParseHexError) -> EvalError {
2104        EvalError::ParseHex(e)
2105    }
2106}
2107
2108impl From<InvalidArrayError> for EvalError {
2109    fn from(e: InvalidArrayError) -> EvalError {
2110        EvalError::InvalidArray(e)
2111    }
2112}
2113
2114impl From<RegexCompilationError> for EvalError {
2115    fn from(e: RegexCompilationError) -> EvalError {
2116        EvalError::InvalidRegex(e.to_string().into())
2117    }
2118}
2119
2120impl From<TypeFromOidError> for EvalError {
2121    fn from(e: TypeFromOidError) -> EvalError {
2122        EvalError::TypeFromOid(e.to_string().into())
2123    }
2124}
2125
2126impl From<DateError> for EvalError {
2127    fn from(e: DateError) -> EvalError {
2128        match e {
2129            DateError::OutOfRange => EvalError::DateOutOfRange,
2130        }
2131    }
2132}
2133
2134impl From<TimestampError> for EvalError {
2135    fn from(e: TimestampError) -> EvalError {
2136        match e {
2137            TimestampError::OutOfRange => EvalError::TimestampOutOfRange,
2138        }
2139    }
2140}
2141
2142impl From<InvalidRangeError> for EvalError {
2143    fn from(e: InvalidRangeError) -> EvalError {
2144        EvalError::InvalidRange(e)
2145    }
2146}
2147
2148impl RustType<ProtoEvalError> for EvalError {
2149    fn into_proto(&self) -> ProtoEvalError {
2150        use proto_eval_error::Kind::*;
2151        use proto_eval_error::*;
2152        let kind = match self {
2153            EvalError::CharacterNotValidForEncoding(v) => CharacterNotValidForEncoding(*v),
2154            EvalError::CharacterTooLargeForEncoding(v) => CharacterTooLargeForEncoding(*v),
2155            EvalError::DateBinOutOfRange(v) => DateBinOutOfRange(v.into_proto()),
2156            EvalError::DivisionByZero => DivisionByZero(()),
2157            EvalError::Unsupported {
2158                feature,
2159                discussion_no,
2160            } => Unsupported(ProtoUnsupported {
2161                feature: feature.into_proto(),
2162                discussion_no: discussion_no.into_proto(),
2163            }),
2164            EvalError::FloatOverflow => FloatOverflow(()),
2165            EvalError::FloatUnderflow => FloatUnderflow(()),
2166            EvalError::NumericFieldOverflow => NumericFieldOverflow(()),
2167            EvalError::Float32OutOfRange(val) => Float32OutOfRange(ProtoValueOutOfRange {
2168                value: val.to_string(),
2169            }),
2170            EvalError::Float64OutOfRange(val) => Float64OutOfRange(ProtoValueOutOfRange {
2171                value: val.to_string(),
2172            }),
2173            EvalError::Int16OutOfRange(val) => Int16OutOfRange(ProtoValueOutOfRange {
2174                value: val.to_string(),
2175            }),
2176            EvalError::Int32OutOfRange(val) => Int32OutOfRange(ProtoValueOutOfRange {
2177                value: val.to_string(),
2178            }),
2179            EvalError::Int64OutOfRange(val) => Int64OutOfRange(ProtoValueOutOfRange {
2180                value: val.to_string(),
2181            }),
2182            EvalError::UInt16OutOfRange(val) => Uint16OutOfRange(ProtoValueOutOfRange {
2183                value: val.to_string(),
2184            }),
2185            EvalError::UInt32OutOfRange(val) => Uint32OutOfRange(ProtoValueOutOfRange {
2186                value: val.to_string(),
2187            }),
2188            EvalError::UInt64OutOfRange(val) => Uint64OutOfRange(ProtoValueOutOfRange {
2189                value: val.to_string(),
2190            }),
2191            EvalError::MzTimestampOutOfRange(val) => MzTimestampOutOfRange(ProtoValueOutOfRange {
2192                value: val.to_string(),
2193            }),
2194            EvalError::MzTimestampStepOverflow => MzTimestampStepOverflow(()),
2195            EvalError::OidOutOfRange(val) => OidOutOfRange(ProtoValueOutOfRange {
2196                value: val.to_string(),
2197            }),
2198            EvalError::IntervalOutOfRange(val) => IntervalOutOfRange(ProtoValueOutOfRange {
2199                value: val.to_string(),
2200            }),
2201            EvalError::TimestampCannotBeNan => TimestampCannotBeNan(()),
2202            EvalError::TimestampOutOfRange => TimestampOutOfRange(()),
2203            EvalError::DateOutOfRange => DateOutOfRange(()),
2204            EvalError::CharOutOfRange => CharOutOfRange(()),
2205            EvalError::IndexOutOfRange {
2206                provided,
2207                valid_end,
2208            } => IndexOutOfRange(ProtoIndexOutOfRange {
2209                provided: *provided,
2210                valid_end: *valid_end,
2211            }),
2212            EvalError::InvalidBase64Equals => InvalidBase64Equals(()),
2213            EvalError::InvalidBase64Symbol(sym) => InvalidBase64Symbol(sym.into_proto()),
2214            EvalError::InvalidBase64EndSequence => InvalidBase64EndSequence(()),
2215            EvalError::InvalidTimezone(tz) => InvalidTimezone(tz.into_proto()),
2216            EvalError::InvalidTimezoneInterval => InvalidTimezoneInterval(()),
2217            EvalError::InvalidTimezoneConversion => InvalidTimezoneConversion(()),
2218            EvalError::InvalidLayer { max_layer, val } => InvalidLayer(ProtoInvalidLayer {
2219                max_layer: max_layer.into_proto(),
2220                val: *val,
2221            }),
2222            EvalError::InvalidArray(error) => InvalidArray(error.into_proto()),
2223            EvalError::InvalidEncodingName(v) => InvalidEncodingName(v.into_proto()),
2224            EvalError::InvalidHashAlgorithm(v) => InvalidHashAlgorithm(v.into_proto()),
2225            EvalError::InvalidByteSequence {
2226                byte_sequence,
2227                encoding_name,
2228            } => InvalidByteSequence(ProtoInvalidByteSequence {
2229                byte_sequence: byte_sequence.into_proto(),
2230                encoding_name: encoding_name.into_proto(),
2231            }),
2232            EvalError::InvalidJsonbCast { from, to } => InvalidJsonbCast(ProtoInvalidJsonbCast {
2233                from: from.into_proto(),
2234                to: to.into_proto(),
2235            }),
2236            EvalError::InvalidRegex(v) => InvalidRegex(v.into_proto()),
2237            EvalError::InvalidRegexFlag(v) => InvalidRegexFlag(v.into_proto()),
2238            EvalError::InvalidParameterValue(v) => InvalidParameterValue(v.into_proto()),
2239            EvalError::InvalidDatePart(part) => InvalidDatePart(part.into_proto()),
2240            EvalError::KeyCannotBeNull => KeyCannotBeNull(()),
2241            EvalError::NegSqrt => NegSqrt(()),
2242            EvalError::NegLimit => NegLimit(()),
2243            EvalError::NullCharacterNotPermitted => NullCharacterNotPermitted(()),
2244            EvalError::UnknownUnits(v) => UnknownUnits(v.into_proto()),
2245            EvalError::UnsupportedUnits(units, typ) => UnsupportedUnits(ProtoUnsupportedUnits {
2246                units: units.into_proto(),
2247                typ: typ.into_proto(),
2248            }),
2249            EvalError::UnterminatedLikeEscapeSequence => UnterminatedLikeEscapeSequence(()),
2250            EvalError::Parse(error) => Parse(error.into_proto()),
2251            EvalError::PrettyError(error) => PrettyError(error.into_proto()),
2252            EvalError::RedactError(error) => RedactError(error.into_proto()),
2253            EvalError::ParseHex(error) => ParseHex(error.into_proto()),
2254            EvalError::Internal(v) => Internal(v.into_proto()),
2255            EvalError::InfinityOutOfDomain(v) => InfinityOutOfDomain(v.into_proto()),
2256            EvalError::NegativeOutOfDomain(v) => NegativeOutOfDomain(v.into_proto()),
2257            EvalError::ZeroOutOfDomain(v) => ZeroOutOfDomain(v.into_proto()),
2258            EvalError::OutOfDomain(lower, upper, id) => OutOfDomain(ProtoOutOfDomain {
2259                lower: Some(lower.into_proto()),
2260                upper: Some(upper.into_proto()),
2261                id: id.into_proto(),
2262            }),
2263            EvalError::ComplexOutOfRange(v) => ComplexOutOfRange(v.into_proto()),
2264            EvalError::MultipleRowsFromSubquery => MultipleRowsFromSubquery(()),
2265            EvalError::NegativeRowsFromSubquery => NegativeRowsFromSubquery(()),
2266            EvalError::Undefined(v) => Undefined(v.into_proto()),
2267            EvalError::LikePatternTooLong => LikePatternTooLong(()),
2268            EvalError::LikeEscapeTooLong => LikeEscapeTooLong(()),
2269            EvalError::StringValueTooLong {
2270                target_type,
2271                length,
2272            } => StringValueTooLong(ProtoStringValueTooLong {
2273                target_type: target_type.into_proto(),
2274                length: length.into_proto(),
2275            }),
2276            EvalError::MultidimensionalArrayRemovalNotSupported => {
2277                MultidimensionalArrayRemovalNotSupported(())
2278            }
2279            EvalError::IncompatibleArrayDimensions { dims } => {
2280                IncompatibleArrayDimensions(ProtoIncompatibleArrayDimensions {
2281                    dims: dims.into_proto(),
2282                })
2283            }
2284            EvalError::TypeFromOid(v) => TypeFromOid(v.into_proto()),
2285            EvalError::InvalidRange(error) => InvalidRange(error.into_proto()),
2286            EvalError::InvalidRoleId(v) => InvalidRoleId(v.into_proto()),
2287            EvalError::InvalidPrivileges(v) => InvalidPrivileges(v.into_proto()),
2288            EvalError::InvalidCatalogJson(v) => InvalidCatalogJson(v.into_proto()),
2289            EvalError::LetRecLimitExceeded(v) => WmrRecursionLimitExceeded(v.into_proto()),
2290            EvalError::MultiDimensionalArraySearch => MultiDimensionalArraySearch(()),
2291            EvalError::MustNotBeNull(v) => MustNotBeNull(v.into_proto()),
2292            EvalError::InvalidIdentifier { ident, detail } => {
2293                InvalidIdentifier(ProtoInvalidIdentifier {
2294                    ident: ident.into_proto(),
2295                    detail: detail.into_proto(),
2296                })
2297            }
2298            EvalError::ArrayFillWrongArraySubscripts => ArrayFillWrongArraySubscripts(()),
2299            EvalError::MaxArraySizeExceeded(max_size) => {
2300                MaxArraySizeExceeded(u64::cast_from(*max_size))
2301            }
2302            EvalError::DateDiffOverflow { unit, a, b } => DateDiffOverflow(ProtoDateDiffOverflow {
2303                unit: unit.into_proto(),
2304                a: a.into_proto(),
2305                b: b.into_proto(),
2306            }),
2307            EvalError::IfNullError(s) => IfNullError(s.into_proto()),
2308            EvalError::LengthTooLarge => LengthTooLarge(()),
2309            EvalError::AclArrayNullElement => AclArrayNullElement(()),
2310            EvalError::MzAclArrayNullElement => MzAclArrayNullElement(()),
2311            EvalError::InvalidIanaTimezoneId(s) => InvalidIanaTimezoneId(s.into_proto()),
2312        };
2313        ProtoEvalError { kind: Some(kind) }
2314    }
2315
2316    fn from_proto(proto: ProtoEvalError) -> Result<Self, TryFromProtoError> {
2317        use proto_eval_error::Kind::*;
2318        match proto.kind {
2319            Some(kind) => match kind {
2320                CharacterNotValidForEncoding(v) => Ok(EvalError::CharacterNotValidForEncoding(v)),
2321                CharacterTooLargeForEncoding(v) => Ok(EvalError::CharacterTooLargeForEncoding(v)),
2322                DateBinOutOfRange(v) => Ok(EvalError::DateBinOutOfRange(v.into())),
2323                DivisionByZero(()) => Ok(EvalError::DivisionByZero),
2324                Unsupported(v) => Ok(EvalError::Unsupported {
2325                    feature: v.feature.into(),
2326                    discussion_no: v.discussion_no.into_rust()?,
2327                }),
2328                FloatOverflow(()) => Ok(EvalError::FloatOverflow),
2329                FloatUnderflow(()) => Ok(EvalError::FloatUnderflow),
2330                NumericFieldOverflow(()) => Ok(EvalError::NumericFieldOverflow),
2331                Float32OutOfRange(val) => Ok(EvalError::Float32OutOfRange(val.value.into())),
2332                Float64OutOfRange(val) => Ok(EvalError::Float64OutOfRange(val.value.into())),
2333                Int16OutOfRange(val) => Ok(EvalError::Int16OutOfRange(val.value.into())),
2334                Int32OutOfRange(val) => Ok(EvalError::Int32OutOfRange(val.value.into())),
2335                Int64OutOfRange(val) => Ok(EvalError::Int64OutOfRange(val.value.into())),
2336                Uint16OutOfRange(val) => Ok(EvalError::UInt16OutOfRange(val.value.into())),
2337                Uint32OutOfRange(val) => Ok(EvalError::UInt32OutOfRange(val.value.into())),
2338                Uint64OutOfRange(val) => Ok(EvalError::UInt64OutOfRange(val.value.into())),
2339                MzTimestampOutOfRange(val) => {
2340                    Ok(EvalError::MzTimestampOutOfRange(val.value.into()))
2341                }
2342                MzTimestampStepOverflow(()) => Ok(EvalError::MzTimestampStepOverflow),
2343                OidOutOfRange(val) => Ok(EvalError::OidOutOfRange(val.value.into())),
2344                IntervalOutOfRange(val) => Ok(EvalError::IntervalOutOfRange(val.value.into())),
2345                TimestampCannotBeNan(()) => Ok(EvalError::TimestampCannotBeNan),
2346                TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange),
2347                DateOutOfRange(()) => Ok(EvalError::DateOutOfRange),
2348                CharOutOfRange(()) => Ok(EvalError::CharOutOfRange),
2349                IndexOutOfRange(v) => Ok(EvalError::IndexOutOfRange {
2350                    provided: v.provided,
2351                    valid_end: v.valid_end,
2352                }),
2353                InvalidBase64Equals(()) => Ok(EvalError::InvalidBase64Equals),
2354                InvalidBase64Symbol(v) => char::from_proto(v).map(EvalError::InvalidBase64Symbol),
2355                InvalidBase64EndSequence(()) => Ok(EvalError::InvalidBase64EndSequence),
2356                InvalidTimezone(v) => Ok(EvalError::InvalidTimezone(v.into())),
2357                InvalidTimezoneInterval(()) => Ok(EvalError::InvalidTimezoneInterval),
2358                InvalidTimezoneConversion(()) => Ok(EvalError::InvalidTimezoneConversion),
2359                InvalidLayer(v) => Ok(EvalError::InvalidLayer {
2360                    max_layer: usize::from_proto(v.max_layer)?,
2361                    val: v.val,
2362                }),
2363                InvalidArray(error) => Ok(EvalError::InvalidArray(error.into_rust()?)),
2364                InvalidEncodingName(v) => Ok(EvalError::InvalidEncodingName(v.into())),
2365                InvalidHashAlgorithm(v) => Ok(EvalError::InvalidHashAlgorithm(v.into())),
2366                InvalidByteSequence(v) => Ok(EvalError::InvalidByteSequence {
2367                    byte_sequence: v.byte_sequence.into(),
2368                    encoding_name: v.encoding_name.into(),
2369                }),
2370                InvalidJsonbCast(v) => Ok(EvalError::InvalidJsonbCast {
2371                    from: v.from.into(),
2372                    to: v.to.into(),
2373                }),
2374                InvalidRegex(v) => Ok(EvalError::InvalidRegex(v.into())),
2375                InvalidRegexFlag(v) => Ok(EvalError::InvalidRegexFlag(char::from_proto(v)?)),
2376                InvalidParameterValue(v) => Ok(EvalError::InvalidParameterValue(v.into())),
2377                InvalidDatePart(part) => Ok(EvalError::InvalidDatePart(part.into())),
2378                KeyCannotBeNull(()) => Ok(EvalError::KeyCannotBeNull),
2379                NegSqrt(()) => Ok(EvalError::NegSqrt),
2380                NegLimit(()) => Ok(EvalError::NegLimit),
2381                NullCharacterNotPermitted(()) => Ok(EvalError::NullCharacterNotPermitted),
2382                UnknownUnits(v) => Ok(EvalError::UnknownUnits(v.into())),
2383                UnsupportedUnits(v) => {
2384                    Ok(EvalError::UnsupportedUnits(v.units.into(), v.typ.into()))
2385                }
2386                UnterminatedLikeEscapeSequence(()) => Ok(EvalError::UnterminatedLikeEscapeSequence),
2387                Parse(error) => Ok(EvalError::Parse(error.into_rust()?)),
2388                ParseHex(error) => Ok(EvalError::ParseHex(error.into_rust()?)),
2389                Internal(v) => Ok(EvalError::Internal(v.into())),
2390                InfinityOutOfDomain(v) => Ok(EvalError::InfinityOutOfDomain(v.into())),
2391                NegativeOutOfDomain(v) => Ok(EvalError::NegativeOutOfDomain(v.into())),
2392                ZeroOutOfDomain(v) => Ok(EvalError::ZeroOutOfDomain(v.into())),
2393                OutOfDomain(v) => Ok(EvalError::OutOfDomain(
2394                    v.lower.into_rust_if_some("ProtoDomainLimit::lower")?,
2395                    v.upper.into_rust_if_some("ProtoDomainLimit::upper")?,
2396                    v.id.into(),
2397                )),
2398                ComplexOutOfRange(v) => Ok(EvalError::ComplexOutOfRange(v.into())),
2399                MultipleRowsFromSubquery(()) => Ok(EvalError::MultipleRowsFromSubquery),
2400                NegativeRowsFromSubquery(()) => Ok(EvalError::NegativeRowsFromSubquery),
2401                Undefined(v) => Ok(EvalError::Undefined(v.into())),
2402                LikePatternTooLong(()) => Ok(EvalError::LikePatternTooLong),
2403                LikeEscapeTooLong(()) => Ok(EvalError::LikeEscapeTooLong),
2404                StringValueTooLong(v) => Ok(EvalError::StringValueTooLong {
2405                    target_type: v.target_type.into(),
2406                    length: usize::from_proto(v.length)?,
2407                }),
2408                MultidimensionalArrayRemovalNotSupported(()) => {
2409                    Ok(EvalError::MultidimensionalArrayRemovalNotSupported)
2410                }
2411                IncompatibleArrayDimensions(v) => Ok(EvalError::IncompatibleArrayDimensions {
2412                    dims: v.dims.into_rust()?,
2413                }),
2414                TypeFromOid(v) => Ok(EvalError::TypeFromOid(v.into())),
2415                InvalidRange(e) => Ok(EvalError::InvalidRange(e.into_rust()?)),
2416                InvalidRoleId(v) => Ok(EvalError::InvalidRoleId(v.into())),
2417                InvalidPrivileges(v) => Ok(EvalError::InvalidPrivileges(v.into())),
2418                InvalidCatalogJson(v) => Ok(EvalError::InvalidCatalogJson(v.into())),
2419                WmrRecursionLimitExceeded(v) => Ok(EvalError::LetRecLimitExceeded(v.into())),
2420                MultiDimensionalArraySearch(()) => Ok(EvalError::MultiDimensionalArraySearch),
2421                MustNotBeNull(v) => Ok(EvalError::MustNotBeNull(v.into())),
2422                InvalidIdentifier(v) => Ok(EvalError::InvalidIdentifier {
2423                    ident: v.ident.into(),
2424                    detail: v.detail.into_rust()?,
2425                }),
2426                ArrayFillWrongArraySubscripts(()) => Ok(EvalError::ArrayFillWrongArraySubscripts),
2427                MaxArraySizeExceeded(max_size) => {
2428                    Ok(EvalError::MaxArraySizeExceeded(usize::cast_from(max_size)))
2429                }
2430                DateDiffOverflow(v) => Ok(EvalError::DateDiffOverflow {
2431                    unit: v.unit.into(),
2432                    a: v.a.into(),
2433                    b: v.b.into(),
2434                }),
2435                IfNullError(v) => Ok(EvalError::IfNullError(v.into())),
2436                LengthTooLarge(()) => Ok(EvalError::LengthTooLarge),
2437                AclArrayNullElement(()) => Ok(EvalError::AclArrayNullElement),
2438                MzAclArrayNullElement(()) => Ok(EvalError::MzAclArrayNullElement),
2439                InvalidIanaTimezoneId(s) => Ok(EvalError::InvalidIanaTimezoneId(s.into())),
2440                PrettyError(s) => Ok(EvalError::PrettyError(s.into())),
2441                RedactError(s) => Ok(EvalError::RedactError(s.into())),
2442            },
2443            None => Err(TryFromProtoError::missing_field("ProtoEvalError::kind")),
2444        }
2445    }
2446}
2447
2448impl RustType<ProtoDims> for (usize, usize) {
2449    fn into_proto(&self) -> ProtoDims {
2450        ProtoDims {
2451            f0: self.0.into_proto(),
2452            f1: self.1.into_proto(),
2453        }
2454    }
2455
2456    fn from_proto(proto: ProtoDims) -> Result<Self, TryFromProtoError> {
2457        Ok((proto.f0.into_rust()?, proto.f1.into_rust()?))
2458    }
2459}
2460
2461#[cfg(test)]
2462mod tests {
2463    use super::*;
2464    use crate::scalar::func::variadic::Coalesce;
2465
2466    #[mz_ore::test]
2467    #[cfg_attr(miri, ignore)] // error: unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
2468    fn test_reduce() {
2469        let relation_type: Vec<ReprColumnType> = vec![
2470            ReprScalarType::Int64.nullable(true),
2471            ReprScalarType::Int64.nullable(true),
2472            ReprScalarType::Int64.nullable(false),
2473        ]
2474        .into_iter()
2475        .collect();
2476        let col = MirScalarExpr::column;
2477        let int64_typ = ReprScalarType::Int64;
2478        let err = |e| MirScalarExpr::literal(Err(e), int64_typ.clone());
2479        let lit = |i| MirScalarExpr::literal_ok(Datum::Int64(i), int64_typ.clone());
2480        let null = || MirScalarExpr::literal_null(int64_typ.clone());
2481
2482        struct TestCase {
2483            input: MirScalarExpr,
2484            output: MirScalarExpr,
2485        }
2486
2487        let test_cases = vec![
2488            TestCase {
2489                input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1)]),
2490                output: lit(1),
2491            },
2492            TestCase {
2493                input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1), lit(2)]),
2494                output: lit(1),
2495            },
2496            TestCase {
2497                input: MirScalarExpr::call_variadic(Coalesce, vec![null(), lit(2), null()]),
2498                output: lit(2),
2499            },
2500            TestCase {
2501                input: MirScalarExpr::call_variadic(
2502                    Coalesce,
2503                    vec![null(), col(0), null(), col(1), lit(2), lit(3)],
2504                ),
2505                output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(1), lit(2)]),
2506            },
2507            TestCase {
2508                input: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2), col(1)]),
2509                output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2)]),
2510            },
2511            TestCase {
2512                input: MirScalarExpr::call_variadic(
2513                    Coalesce,
2514                    vec![lit(1), err(EvalError::DivisionByZero)],
2515                ),
2516                output: lit(1),
2517            },
2518            TestCase {
2519                input: MirScalarExpr::call_variadic(
2520                    Coalesce,
2521                    vec![
2522                        null(),
2523                        err(EvalError::DivisionByZero),
2524                        err(EvalError::NumericFieldOverflow),
2525                    ],
2526                ),
2527                output: err(EvalError::DivisionByZero),
2528            },
2529        ];
2530
2531        for tc in test_cases {
2532            let mut actual = tc.input.clone();
2533            actual.reduce(&relation_type);
2534            assert!(
2535                actual == tc.output,
2536                "input: {}\nactual: {}\nexpected: {}",
2537                tc.input,
2538                actual,
2539                tc.output
2540            );
2541        }
2542    }
2543}