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    {
1331        use MirScalarExpr::*;
1332        match self {
1333            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1334            CallUnary { expr, .. } => {
1335                f(expr)?;
1336            }
1337            CallBinary { expr1, expr2, .. } => {
1338                f(expr1)?;
1339                f(expr2)?;
1340            }
1341            CallVariadic { exprs, .. } => {
1342                for expr in exprs {
1343                    f(expr)?;
1344                }
1345            }
1346            If { cond, then, els } => {
1347                f(cond)?;
1348                f(then)?;
1349                f(els)?;
1350            }
1351        }
1352        Ok(())
1353    }
1354
1355    fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
1356    where
1357        F: FnMut(&mut Self) -> Result<(), E>,
1358    {
1359        use MirScalarExpr::*;
1360        match self {
1361            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1362            CallUnary { expr, .. } => {
1363                f(expr)?;
1364            }
1365            CallBinary { expr1, expr2, .. } => {
1366                f(expr1)?;
1367                f(expr2)?;
1368            }
1369            CallVariadic { exprs, .. } => {
1370                for expr in exprs {
1371                    f(expr)?;
1372                }
1373            }
1374            If { cond, then, els } => {
1375                f(cond)?;
1376                f(then)?;
1377                f(els)?;
1378            }
1379        }
1380        Ok(())
1381    }
1382
1383    fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a Self>
1384    where
1385        Self: 'a,
1386    {
1387        self.children()
1388    }
1389
1390    fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut Self>
1391    where
1392        Self: 'a,
1393    {
1394        self.children_mut()
1395    }
1396}
1397
1398impl MirScalarExpr {
1399    /// Iterates through references to child expressions.
1400    pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self> {
1401        let mut first = None;
1402        let mut second = None;
1403        let mut third = None;
1404        let mut variadic = None;
1405
1406        use MirScalarExpr::*;
1407        match self {
1408            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1409            CallUnary { expr, .. } => {
1410                first = Some(&**expr);
1411            }
1412            CallBinary { expr1, expr2, .. } => {
1413                first = Some(&**expr1);
1414                second = Some(&**expr2);
1415            }
1416            CallVariadic { exprs, .. } => {
1417                variadic = Some(exprs);
1418            }
1419            If { cond, then, els } => {
1420                first = Some(&**cond);
1421                second = Some(&**then);
1422                third = Some(&**els);
1423            }
1424        }
1425
1426        first
1427            .into_iter()
1428            .chain(second)
1429            .chain(third)
1430            .chain(variadic.into_iter().flatten())
1431    }
1432
1433    /// Iterates through mutable references to child expressions.
1434    pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self> {
1435        let mut first = None;
1436        let mut second = None;
1437        let mut third = None;
1438        let mut variadic = None;
1439
1440        use MirScalarExpr::*;
1441        match self {
1442            Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1443            CallUnary { expr, .. } => {
1444                first = Some(&mut **expr);
1445            }
1446            CallBinary { expr1, expr2, .. } => {
1447                first = Some(&mut **expr1);
1448                second = Some(&mut **expr2);
1449            }
1450            CallVariadic { exprs, .. } => {
1451                variadic = Some(exprs);
1452            }
1453            If { cond, then, els } => {
1454                first = Some(&mut **cond);
1455                second = Some(&mut **then);
1456                third = Some(&mut **els);
1457            }
1458        }
1459
1460        first
1461            .into_iter()
1462            .chain(second)
1463            .chain(third)
1464            .chain(variadic.into_iter().flatten())
1465    }
1466
1467    /// Visits all subexpressions in DFS preorder.
1468    pub fn visit_pre<F>(&self, mut f: F)
1469    where
1470        F: FnMut(&Self),
1471    {
1472        let mut worklist = vec![self];
1473        while let Some(e) = worklist.pop() {
1474            f(e);
1475            worklist.extend(e.children().rev());
1476        }
1477    }
1478
1479    /// Iterative pre-order visitor.
1480    pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, mut f: F) {
1481        let mut worklist = vec![self];
1482        while let Some(expr) = worklist.pop() {
1483            f(expr);
1484            worklist.extend(expr.children_mut().rev());
1485        }
1486    }
1487}
1488
1489/// Filter characteristics that are used for ordering join inputs.
1490/// This can be created for a `Vec<MirScalarExpr>`, which represents an AND of predicates.
1491///
1492/// The fields are ordered based on heuristic assumptions about their typical selectivity, so that
1493/// Ord gives the right ordering for join inputs. Bigger is better, i.e., will tend to come earlier
1494/// than other inputs.
1495#[derive(
1496    Eq,
1497    PartialEq,
1498    Ord,
1499    PartialOrd,
1500    Debug,
1501    Clone,
1502    Serialize,
1503    Deserialize,
1504    Hash,
1505    MzReflect
1506)]
1507pub struct FilterCharacteristics {
1508    // `<expr> = <literal>` appears in the filter.
1509    // Excludes cases where NOT appears anywhere above the literal equality.
1510    literal_equality: bool,
1511    // (Assuming a random string of lower-case characters, `LIKE 'a%'` has a selectivity of 1/26.)
1512    like: bool,
1513    is_null: bool,
1514    // Number of Vec elements that involve inequality predicates. (A BETWEEN is represented as two
1515    // inequality predicates.)
1516    // Excludes cases where NOT appears around the literal inequality.
1517    // Note that for inequality predicates, some databases assume 1/3 selectivity in the absence of
1518    // concrete statistics.
1519    literal_inequality: usize,
1520    /// Any filter, except ones involving `IS NOT NULL`, because those are too common.
1521    /// Can be true by itself, or any other field being true can also make this true.
1522    /// `NOT LIKE` is only in this category.
1523    /// `!=` is only in this category.
1524    /// `NOT (a = b)` is turned into `!=` by `reduce` before us!
1525    any_filter: bool,
1526}
1527
1528impl BitOrAssign for FilterCharacteristics {
1529    fn bitor_assign(&mut self, rhs: Self) {
1530        self.literal_equality |= rhs.literal_equality;
1531        self.like |= rhs.like;
1532        self.is_null |= rhs.is_null;
1533        self.literal_inequality += rhs.literal_inequality;
1534        self.any_filter |= rhs.any_filter;
1535    }
1536}
1537
1538impl FilterCharacteristics {
1539    pub fn none() -> FilterCharacteristics {
1540        FilterCharacteristics {
1541            literal_equality: false,
1542            like: false,
1543            is_null: false,
1544            literal_inequality: 0,
1545            any_filter: false,
1546        }
1547    }
1548
1549    pub fn explain(&self) -> String {
1550        let mut e = "".to_owned();
1551        if self.literal_equality {
1552            e.push_str("e");
1553        }
1554        if self.like {
1555            e.push_str("l");
1556        }
1557        if self.is_null {
1558            e.push_str("n");
1559        }
1560        for _ in 0..self.literal_inequality {
1561            e.push_str("i");
1562        }
1563        if self.any_filter {
1564            e.push_str("f");
1565        }
1566        e
1567    }
1568
1569    pub fn filter_characteristics(
1570        filters: &Vec<MirScalarExpr>,
1571    ) -> Result<FilterCharacteristics, RecursionLimitError> {
1572        let mut literal_equality = false;
1573        let mut like = false;
1574        let mut is_null = false;
1575        let mut literal_inequality = 0;
1576        let mut any_filter = false;
1577        filters.iter().try_for_each(|f| {
1578            let mut literal_inequality_in_current_filter = false;
1579            let mut is_not_null_in_current_filter = false;
1580            f.visit_pre_with_context(
1581                false,
1582                &mut |not_in_parent_chain, expr| {
1583                    not_in_parent_chain
1584                        || matches!(
1585                            expr,
1586                            MirScalarExpr::CallUnary {
1587                                func: UnaryFunc::Not(func::Not),
1588                                ..
1589                            }
1590                        )
1591                },
1592                &mut |not_in_parent_chain, expr| {
1593                    if !not_in_parent_chain {
1594                        if expr.any_expr_eq_literal().is_some() {
1595                            literal_equality = true;
1596                        }
1597                        if expr.any_expr_ineq_literal() {
1598                            literal_inequality_in_current_filter = true;
1599                        }
1600                        if matches!(
1601                            expr,
1602                            MirScalarExpr::CallUnary {
1603                                func: UnaryFunc::IsLikeMatch(_),
1604                                ..
1605                            }
1606                        ) {
1607                            like = true;
1608                        }
1609                    };
1610                    if matches!(
1611                        expr,
1612                        MirScalarExpr::CallUnary {
1613                            func: UnaryFunc::IsNull(crate::func::IsNull),
1614                            ..
1615                        }
1616                    ) {
1617                        if *not_in_parent_chain {
1618                            is_not_null_in_current_filter = true;
1619                        } else {
1620                            is_null = true;
1621                        }
1622                    }
1623                },
1624            );
1625            if literal_inequality_in_current_filter {
1626                literal_inequality += 1;
1627            }
1628            if !is_not_null_in_current_filter {
1629                // We want to ignore `IS NOT NULL` for `any_filter`.
1630                any_filter = true;
1631            }
1632            Ok(())
1633        })?;
1634        Ok(FilterCharacteristics {
1635            literal_equality,
1636            like,
1637            is_null,
1638            literal_inequality,
1639            any_filter,
1640        })
1641    }
1642
1643    pub fn add_literal_equality(&mut self) {
1644        self.literal_equality = true;
1645    }
1646
1647    pub fn worst_case_scaling_factor(&self) -> f64 {
1648        let mut factor = 1.0;
1649
1650        if self.literal_equality {
1651            factor *= 0.1;
1652        }
1653
1654        if self.is_null {
1655            factor *= 0.1;
1656        }
1657
1658        if self.literal_inequality >= 2 {
1659            factor *= 0.25;
1660        } else if self.literal_inequality == 1 {
1661            factor *= 0.33;
1662        }
1663
1664        // catch various negated filters, treat them pessimistically
1665        if !(self.literal_equality || self.is_null || self.literal_inequality > 0)
1666            && self.any_filter
1667        {
1668            factor *= 0.9;
1669        }
1670
1671        factor
1672    }
1673}
1674
1675#[derive(
1676    Ord,
1677    PartialOrd,
1678    Copy,
1679    Clone,
1680    Debug,
1681    Eq,
1682    PartialEq,
1683    Serialize,
1684    Deserialize,
1685    Hash,
1686    MzReflect
1687)]
1688#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1689pub enum DomainLimit {
1690    None,
1691    Inclusive(i64),
1692    Exclusive(i64),
1693}
1694
1695impl RustType<ProtoDomainLimit> for DomainLimit {
1696    fn into_proto(&self) -> ProtoDomainLimit {
1697        use proto_domain_limit::Kind::*;
1698        let kind = match self {
1699            DomainLimit::None => None(()),
1700            DomainLimit::Inclusive(v) => Inclusive(*v),
1701            DomainLimit::Exclusive(v) => Exclusive(*v),
1702        };
1703        ProtoDomainLimit { kind: Some(kind) }
1704    }
1705
1706    fn from_proto(proto: ProtoDomainLimit) -> Result<Self, TryFromProtoError> {
1707        use proto_domain_limit::Kind::*;
1708        if let Some(kind) = proto.kind {
1709            match kind {
1710                None(()) => Ok(DomainLimit::None),
1711                Inclusive(v) => Ok(DomainLimit::Inclusive(v)),
1712                Exclusive(v) => Ok(DomainLimit::Exclusive(v)),
1713            }
1714        } else {
1715            Err(TryFromProtoError::missing_field("ProtoDomainLimit::kind"))
1716        }
1717    }
1718}
1719
1720#[derive(
1721    Ord,
1722    PartialOrd,
1723    Clone,
1724    Debug,
1725    Eq,
1726    PartialEq,
1727    Serialize,
1728    Deserialize,
1729    Hash,
1730    MzReflect
1731)]
1732#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1733pub enum EvalError {
1734    CharacterNotValidForEncoding(i32),
1735    CharacterTooLargeForEncoding(i32),
1736    DateBinOutOfRange(Box<str>),
1737    DivisionByZero,
1738    Unsupported {
1739        feature: Box<str>,
1740        discussion_no: Option<usize>,
1741    },
1742    FloatOverflow,
1743    FloatUnderflow,
1744    NumericFieldOverflow,
1745    Float32OutOfRange(Box<str>),
1746    Float64OutOfRange(Box<str>),
1747    Int16OutOfRange(Box<str>),
1748    Int32OutOfRange(Box<str>),
1749    Int64OutOfRange(Box<str>),
1750    UInt16OutOfRange(Box<str>),
1751    UInt32OutOfRange(Box<str>),
1752    UInt64OutOfRange(Box<str>),
1753    MzTimestampOutOfRange(Box<str>),
1754    MzTimestampStepOverflow,
1755    OidOutOfRange(Box<str>),
1756    IntervalOutOfRange(Box<str>),
1757    TimestampCannotBeNan,
1758    TimestampOutOfRange,
1759    DateOutOfRange,
1760    CharOutOfRange,
1761    IndexOutOfRange {
1762        provided: i32,
1763        // The last valid index position, i.e. `v.len() - 1`
1764        valid_end: i32,
1765    },
1766    InvalidBase64Equals,
1767    InvalidBase64Symbol(char),
1768    InvalidBase64EndSequence,
1769    InvalidTimezone(Box<str>),
1770    InvalidTimezoneInterval,
1771    InvalidTimezoneConversion,
1772    InvalidIanaTimezoneId(Box<str>),
1773    InvalidLayer {
1774        max_layer: usize,
1775        val: i64,
1776    },
1777    InvalidArray(InvalidArrayError),
1778    InvalidEncodingName(Box<str>),
1779    InvalidHashAlgorithm(Box<str>),
1780    InvalidByteSequence {
1781        byte_sequence: Box<str>,
1782        encoding_name: Box<str>,
1783    },
1784    InvalidJsonbCast {
1785        from: Box<str>,
1786        to: Box<str>,
1787    },
1788    InvalidRegex(Box<str>),
1789    InvalidRegexFlag(char),
1790    InvalidParameterValue(Box<str>),
1791    InvalidDatePart(Box<str>),
1792    KeyCannotBeNull,
1793    NegSqrt,
1794    NegLimit,
1795    NullCharacterNotPermitted,
1796    UnknownUnits(Box<str>),
1797    UnsupportedUnits(Box<str>, Box<str>),
1798    UnterminatedLikeEscapeSequence,
1799    Parse(ParseError),
1800    ParseHex(ParseHexError),
1801    Internal(Box<str>),
1802    InfinityOutOfDomain(Box<str>),
1803    NegativeOutOfDomain(Box<str>),
1804    ZeroOutOfDomain(Box<str>),
1805    OutOfDomain(DomainLimit, DomainLimit, Box<str>),
1806    ComplexOutOfRange(Box<str>),
1807    MultipleRowsFromSubquery,
1808    NegativeRowsFromSubquery,
1809    Undefined(Box<str>),
1810    LikePatternTooLong,
1811    LikeEscapeTooLong,
1812    StringValueTooLong {
1813        target_type: Box<str>,
1814        length: usize,
1815    },
1816    MultidimensionalArrayRemovalNotSupported,
1817    IncompatibleArrayDimensions {
1818        dims: Option<(usize, usize)>,
1819    },
1820    TypeFromOid(Box<str>),
1821    InvalidRange(InvalidRangeError),
1822    InvalidRoleId(Box<str>),
1823    InvalidPrivileges(Box<str>),
1824    InvalidCatalogJson(Box<str>),
1825    LetRecLimitExceeded(Box<str>),
1826    MultiDimensionalArraySearch,
1827    MustNotBeNull(Box<str>),
1828    InvalidIdentifier {
1829        ident: Box<str>,
1830        detail: Option<Box<str>>,
1831    },
1832    ArrayFillWrongArraySubscripts,
1833    // TODO: propagate this check more widely throughout the expr crate
1834    MaxArraySizeExceeded(usize),
1835    DateDiffOverflow {
1836        unit: Box<str>,
1837        a: Box<str>,
1838        b: Box<str>,
1839    },
1840    // The error for ErrorIfNull; this should not be used in other contexts as a generic error
1841    // printer.
1842    IfNullError(Box<str>),
1843    LengthTooLarge,
1844    AclArrayNullElement,
1845    MzAclArrayNullElement,
1846    PrettyError(Box<str>),
1847    RedactError(Box<str>),
1848}
1849
1850impl fmt::Display for EvalError {
1851    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1852        match self {
1853            EvalError::CharacterNotValidForEncoding(v) => {
1854                write!(f, "requested character not valid for encoding: {v}")
1855            }
1856            EvalError::CharacterTooLargeForEncoding(v) => {
1857                write!(f, "requested character too large for encoding: {v}")
1858            }
1859            EvalError::DateBinOutOfRange(message) => f.write_str(message),
1860            EvalError::DivisionByZero => f.write_str("division by zero"),
1861            EvalError::Unsupported {
1862                feature,
1863                discussion_no,
1864            } => {
1865                write!(f, "{} not yet supported", feature)?;
1866                if let Some(discussion_no) = discussion_no {
1867                    write!(
1868                        f,
1869                        ", see https://github.com/MaterializeInc/materialize/discussions/{} for more details",
1870                        discussion_no
1871                    )?;
1872                }
1873                Ok(())
1874            }
1875            EvalError::FloatOverflow => f.write_str("value out of range: overflow"),
1876            EvalError::FloatUnderflow => f.write_str("value out of range: underflow"),
1877            EvalError::NumericFieldOverflow => f.write_str("numeric field overflow"),
1878            EvalError::Float32OutOfRange(val) => write!(f, "{} real out of range", val.quoted()),
1879            EvalError::Float64OutOfRange(val) => {
1880                write!(f, "{} double precision out of range", val.quoted())
1881            }
1882            EvalError::Int16OutOfRange(val) => write!(f, "{} smallint out of range", val.quoted()),
1883            EvalError::Int32OutOfRange(val) => write!(f, "{} integer out of range", val.quoted()),
1884            EvalError::Int64OutOfRange(val) => write!(f, "{} bigint out of range", val.quoted()),
1885            EvalError::UInt16OutOfRange(val) => write!(f, "{} uint2 out of range", val.quoted()),
1886            EvalError::UInt32OutOfRange(val) => write!(f, "{} uint4 out of range", val.quoted()),
1887            EvalError::UInt64OutOfRange(val) => write!(f, "{} uint8 out of range", val.quoted()),
1888            EvalError::MzTimestampOutOfRange(val) => {
1889                write!(f, "{} mz_timestamp out of range", val.quoted())
1890            }
1891            EvalError::MzTimestampStepOverflow => f.write_str("step mz_timestamp overflow"),
1892            EvalError::OidOutOfRange(val) => write!(f, "{} OID out of range", val.quoted()),
1893            EvalError::IntervalOutOfRange(val) => {
1894                write!(f, "{} interval out of range", val.quoted())
1895            }
1896            EvalError::TimestampCannotBeNan => f.write_str("timestamp cannot be NaN"),
1897            EvalError::TimestampOutOfRange => f.write_str("timestamp out of range"),
1898            EvalError::DateOutOfRange => f.write_str("date out of range"),
1899            EvalError::CharOutOfRange => f.write_str("\"char\" out of range"),
1900            EvalError::IndexOutOfRange {
1901                provided,
1902                valid_end,
1903            } => write!(f, "index {provided} out of valid range, 0..{valid_end}",),
1904            EvalError::InvalidBase64Equals => {
1905                f.write_str("unexpected \"=\" while decoding base64 sequence")
1906            }
1907            EvalError::InvalidBase64Symbol(c) => write!(
1908                f,
1909                "invalid symbol \"{}\" found while decoding base64 sequence",
1910                c.escape_default()
1911            ),
1912            EvalError::InvalidBase64EndSequence => f.write_str("invalid base64 end sequence"),
1913            EvalError::InvalidJsonbCast { from, to } => {
1914                write!(f, "cannot cast jsonb {} to type {}", from, to)
1915            }
1916            EvalError::InvalidTimezone(tz) => write!(f, "invalid time zone '{}'", tz),
1917            EvalError::InvalidTimezoneInterval => {
1918                f.write_str("timezone interval must not contain months or years")
1919            }
1920            EvalError::InvalidTimezoneConversion => f.write_str("invalid timezone conversion"),
1921            EvalError::InvalidIanaTimezoneId(tz) => {
1922                write!(f, "invalid IANA Time Zone Database identifier: '{}'", tz)
1923            }
1924            EvalError::InvalidLayer { max_layer, val } => write!(
1925                f,
1926                "invalid layer: {}; must use value within [1, {}]",
1927                val, max_layer
1928            ),
1929            EvalError::InvalidArray(e) => e.fmt(f),
1930            EvalError::InvalidEncodingName(name) => write!(f, "invalid encoding name '{}'", name),
1931            EvalError::InvalidHashAlgorithm(alg) => write!(f, "invalid hash algorithm '{}'", alg),
1932            EvalError::InvalidByteSequence {
1933                byte_sequence,
1934                encoding_name,
1935            } => write!(
1936                f,
1937                "invalid byte sequence '{}' for encoding '{}'",
1938                byte_sequence, encoding_name
1939            ),
1940            EvalError::InvalidDatePart(part) => write!(f, "invalid datepart {}", part.quoted()),
1941            EvalError::KeyCannotBeNull => f.write_str("key cannot be null"),
1942            EvalError::NegSqrt => f.write_str("cannot take square root of a negative number"),
1943            EvalError::NegLimit => f.write_str("LIMIT must not be negative"),
1944            EvalError::NullCharacterNotPermitted => f.write_str("null character not permitted"),
1945            EvalError::InvalidRegex(e) => write!(f, "invalid regular expression: {}", e),
1946            EvalError::InvalidRegexFlag(c) => write!(f, "invalid regular expression flag: {}", c),
1947            EvalError::InvalidParameterValue(s) => f.write_str(s),
1948            EvalError::UnknownUnits(units) => write!(f, "unit '{}' not recognized", units),
1949            EvalError::UnsupportedUnits(units, typ) => {
1950                write!(f, "unit '{}' not supported for type {}", units, typ)
1951            }
1952            EvalError::UnterminatedLikeEscapeSequence => {
1953                f.write_str("unterminated escape sequence in LIKE")
1954            }
1955            EvalError::Parse(e) => e.fmt(f),
1956            EvalError::PrettyError(e) => e.fmt(f),
1957            EvalError::RedactError(e) => e.fmt(f),
1958            EvalError::ParseHex(e) => e.fmt(f),
1959            EvalError::Internal(s) => write!(f, "internal error: {}", s),
1960            EvalError::InfinityOutOfDomain(s) => {
1961                write!(f, "function {} is only defined for finite arguments", s)
1962            }
1963            EvalError::NegativeOutOfDomain(s) => {
1964                write!(f, "function {} is not defined for negative numbers", s)
1965            }
1966            EvalError::ZeroOutOfDomain(s) => {
1967                write!(f, "function {} is not defined for zero", s)
1968            }
1969            EvalError::OutOfDomain(lower, upper, s) => {
1970                use DomainLimit::*;
1971                write!(f, "function {s} is defined for numbers ")?;
1972                match (lower, upper) {
1973                    (Inclusive(n), None) => write!(f, "greater than or equal to {n}"),
1974                    (Exclusive(n), None) => write!(f, "greater than {n}"),
1975                    (None, Inclusive(n)) => write!(f, "less than or equal to {n}"),
1976                    (None, Exclusive(n)) => write!(f, "less than {n}"),
1977                    (Inclusive(lo), Inclusive(hi)) => write!(f, "between {lo} and {hi} inclusive"),
1978                    (Exclusive(lo), Exclusive(hi)) => write!(f, "between {lo} and {hi} exclusive"),
1979                    (Inclusive(lo), Exclusive(hi)) => {
1980                        write!(f, "between {lo} inclusive and {hi} exclusive")
1981                    }
1982                    (Exclusive(lo), Inclusive(hi)) => {
1983                        write!(f, "between {lo} exclusive and {hi} inclusive")
1984                    }
1985                    (None, None) => panic!("invalid domain error"),
1986                }
1987            }
1988            EvalError::ComplexOutOfRange(s) => {
1989                write!(f, "function {} cannot return complex numbers", s)
1990            }
1991            EvalError::MultipleRowsFromSubquery => {
1992                write!(f, "more than one record produced in subquery")
1993            }
1994            EvalError::NegativeRowsFromSubquery => {
1995                write!(f, "negative number of rows produced in subquery")
1996            }
1997            EvalError::Undefined(s) => {
1998                write!(f, "{} is undefined", s)
1999            }
2000            EvalError::LikePatternTooLong => {
2001                write!(f, "LIKE pattern exceeds maximum length")
2002            }
2003            EvalError::LikeEscapeTooLong => {
2004                write!(f, "invalid escape string")
2005            }
2006            EvalError::StringValueTooLong {
2007                target_type,
2008                length,
2009            } => {
2010                write!(f, "value too long for type {}({})", target_type, length)
2011            }
2012            EvalError::MultidimensionalArrayRemovalNotSupported => {
2013                write!(
2014                    f,
2015                    "removing elements from multidimensional arrays is not supported"
2016                )
2017            }
2018            EvalError::IncompatibleArrayDimensions { dims: _ } => {
2019                write!(f, "cannot concatenate incompatible arrays")
2020            }
2021            EvalError::TypeFromOid(msg) => write!(f, "{msg}"),
2022            EvalError::InvalidRange(e) => e.fmt(f),
2023            EvalError::InvalidRoleId(msg) => write!(f, "{msg}"),
2024            EvalError::InvalidPrivileges(privilege) => {
2025                write!(f, "unrecognized privilege type: {privilege}")
2026            }
2027            EvalError::InvalidCatalogJson(msg) => {
2028                write!(f, "invalid catalog JSON: {msg}")
2029            }
2030            EvalError::LetRecLimitExceeded(max_iters) => {
2031                write!(
2032                    f,
2033                    "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.)",
2034                    max_iters
2035                )
2036            }
2037            EvalError::MultiDimensionalArraySearch => write!(
2038                f,
2039                "searching for elements in multidimensional arrays is not supported"
2040            ),
2041            EvalError::MustNotBeNull(v) => write!(f, "{v} must not be null"),
2042            EvalError::InvalidIdentifier { ident, .. } => {
2043                write!(f, "string is not a valid identifier: {}", ident.quoted())
2044            }
2045            EvalError::ArrayFillWrongArraySubscripts => {
2046                f.write_str("wrong number of array subscripts")
2047            }
2048            EvalError::MaxArraySizeExceeded(max_size) => {
2049                write!(
2050                    f,
2051                    "array size exceeds the maximum allowed ({max_size} bytes)"
2052                )
2053            }
2054            EvalError::DateDiffOverflow { unit, a, b } => {
2055                write!(f, "datediff overflow, {unit} of {a}, {b}")
2056            }
2057            EvalError::IfNullError(s) => f.write_str(s),
2058            EvalError::LengthTooLarge => write!(f, "requested length too large"),
2059            EvalError::AclArrayNullElement => write!(f, "ACL arrays must not contain null values"),
2060            EvalError::MzAclArrayNullElement => {
2061                write!(f, "MZ_ACL arrays must not contain null values")
2062            }
2063        }
2064    }
2065}
2066
2067impl EvalError {
2068    pub fn detail(&self) -> Option<String> {
2069        match self {
2070            EvalError::IncompatibleArrayDimensions { dims: None } => Some(
2071                "Arrays with differing dimensions are not compatible for concatenation.".into(),
2072            ),
2073            EvalError::IncompatibleArrayDimensions {
2074                dims: Some((a_dims, b_dims)),
2075            } => Some(format!(
2076                "Arrays of {} and {} dimensions are not compatible for concatenation.",
2077                a_dims, b_dims
2078            )),
2079            EvalError::InvalidIdentifier { detail, .. } => detail.as_deref().map(Into::into),
2080            EvalError::ArrayFillWrongArraySubscripts => {
2081                Some("Low bound array has different size than dimensions array.".into())
2082            }
2083            _ => None,
2084        }
2085    }
2086
2087    pub fn hint(&self) -> Option<String> {
2088        match self {
2089            EvalError::InvalidBase64EndSequence => Some(
2090                "Input data is missing padding, is truncated, or is otherwise corrupted.".into(),
2091            ),
2092            EvalError::LikeEscapeTooLong => {
2093                Some("Escape string must be empty or one character.".into())
2094            }
2095            EvalError::MzTimestampOutOfRange(_) => Some(
2096                "Integer, numeric, and text casts to mz_timestamp must be in the form of whole \
2097                milliseconds since the Unix epoch. Values with fractional parts cannot be \
2098                converted to mz_timestamp."
2099                    .into(),
2100            ),
2101            _ => None,
2102        }
2103    }
2104}
2105
2106impl std::error::Error for EvalError {}
2107
2108impl From<ParseError> for EvalError {
2109    fn from(e: ParseError) -> EvalError {
2110        EvalError::Parse(e)
2111    }
2112}
2113
2114impl From<ParseHexError> for EvalError {
2115    fn from(e: ParseHexError) -> EvalError {
2116        EvalError::ParseHex(e)
2117    }
2118}
2119
2120impl From<InvalidArrayError> for EvalError {
2121    fn from(e: InvalidArrayError) -> EvalError {
2122        EvalError::InvalidArray(e)
2123    }
2124}
2125
2126impl From<RegexCompilationError> for EvalError {
2127    fn from(e: RegexCompilationError) -> EvalError {
2128        EvalError::InvalidRegex(e.to_string().into())
2129    }
2130}
2131
2132impl From<TypeFromOidError> for EvalError {
2133    fn from(e: TypeFromOidError) -> EvalError {
2134        EvalError::TypeFromOid(e.to_string().into())
2135    }
2136}
2137
2138impl From<DateError> for EvalError {
2139    fn from(e: DateError) -> EvalError {
2140        match e {
2141            DateError::OutOfRange => EvalError::DateOutOfRange,
2142        }
2143    }
2144}
2145
2146impl From<TimestampError> for EvalError {
2147    fn from(e: TimestampError) -> EvalError {
2148        match e {
2149            TimestampError::OutOfRange => EvalError::TimestampOutOfRange,
2150        }
2151    }
2152}
2153
2154impl From<InvalidRangeError> for EvalError {
2155    fn from(e: InvalidRangeError) -> EvalError {
2156        EvalError::InvalidRange(e)
2157    }
2158}
2159
2160impl RustType<ProtoEvalError> for EvalError {
2161    fn into_proto(&self) -> ProtoEvalError {
2162        use proto_eval_error::Kind::*;
2163        use proto_eval_error::*;
2164        let kind = match self {
2165            EvalError::CharacterNotValidForEncoding(v) => CharacterNotValidForEncoding(*v),
2166            EvalError::CharacterTooLargeForEncoding(v) => CharacterTooLargeForEncoding(*v),
2167            EvalError::DateBinOutOfRange(v) => DateBinOutOfRange(v.into_proto()),
2168            EvalError::DivisionByZero => DivisionByZero(()),
2169            EvalError::Unsupported {
2170                feature,
2171                discussion_no,
2172            } => Unsupported(ProtoUnsupported {
2173                feature: feature.into_proto(),
2174                discussion_no: discussion_no.into_proto(),
2175            }),
2176            EvalError::FloatOverflow => FloatOverflow(()),
2177            EvalError::FloatUnderflow => FloatUnderflow(()),
2178            EvalError::NumericFieldOverflow => NumericFieldOverflow(()),
2179            EvalError::Float32OutOfRange(val) => Float32OutOfRange(ProtoValueOutOfRange {
2180                value: val.to_string(),
2181            }),
2182            EvalError::Float64OutOfRange(val) => Float64OutOfRange(ProtoValueOutOfRange {
2183                value: val.to_string(),
2184            }),
2185            EvalError::Int16OutOfRange(val) => Int16OutOfRange(ProtoValueOutOfRange {
2186                value: val.to_string(),
2187            }),
2188            EvalError::Int32OutOfRange(val) => Int32OutOfRange(ProtoValueOutOfRange {
2189                value: val.to_string(),
2190            }),
2191            EvalError::Int64OutOfRange(val) => Int64OutOfRange(ProtoValueOutOfRange {
2192                value: val.to_string(),
2193            }),
2194            EvalError::UInt16OutOfRange(val) => Uint16OutOfRange(ProtoValueOutOfRange {
2195                value: val.to_string(),
2196            }),
2197            EvalError::UInt32OutOfRange(val) => Uint32OutOfRange(ProtoValueOutOfRange {
2198                value: val.to_string(),
2199            }),
2200            EvalError::UInt64OutOfRange(val) => Uint64OutOfRange(ProtoValueOutOfRange {
2201                value: val.to_string(),
2202            }),
2203            EvalError::MzTimestampOutOfRange(val) => MzTimestampOutOfRange(ProtoValueOutOfRange {
2204                value: val.to_string(),
2205            }),
2206            EvalError::MzTimestampStepOverflow => MzTimestampStepOverflow(()),
2207            EvalError::OidOutOfRange(val) => OidOutOfRange(ProtoValueOutOfRange {
2208                value: val.to_string(),
2209            }),
2210            EvalError::IntervalOutOfRange(val) => IntervalOutOfRange(ProtoValueOutOfRange {
2211                value: val.to_string(),
2212            }),
2213            EvalError::TimestampCannotBeNan => TimestampCannotBeNan(()),
2214            EvalError::TimestampOutOfRange => TimestampOutOfRange(()),
2215            EvalError::DateOutOfRange => DateOutOfRange(()),
2216            EvalError::CharOutOfRange => CharOutOfRange(()),
2217            EvalError::IndexOutOfRange {
2218                provided,
2219                valid_end,
2220            } => IndexOutOfRange(ProtoIndexOutOfRange {
2221                provided: *provided,
2222                valid_end: *valid_end,
2223            }),
2224            EvalError::InvalidBase64Equals => InvalidBase64Equals(()),
2225            EvalError::InvalidBase64Symbol(sym) => InvalidBase64Symbol(sym.into_proto()),
2226            EvalError::InvalidBase64EndSequence => InvalidBase64EndSequence(()),
2227            EvalError::InvalidTimezone(tz) => InvalidTimezone(tz.into_proto()),
2228            EvalError::InvalidTimezoneInterval => InvalidTimezoneInterval(()),
2229            EvalError::InvalidTimezoneConversion => InvalidTimezoneConversion(()),
2230            EvalError::InvalidLayer { max_layer, val } => InvalidLayer(ProtoInvalidLayer {
2231                max_layer: max_layer.into_proto(),
2232                val: *val,
2233            }),
2234            EvalError::InvalidArray(error) => InvalidArray(error.into_proto()),
2235            EvalError::InvalidEncodingName(v) => InvalidEncodingName(v.into_proto()),
2236            EvalError::InvalidHashAlgorithm(v) => InvalidHashAlgorithm(v.into_proto()),
2237            EvalError::InvalidByteSequence {
2238                byte_sequence,
2239                encoding_name,
2240            } => InvalidByteSequence(ProtoInvalidByteSequence {
2241                byte_sequence: byte_sequence.into_proto(),
2242                encoding_name: encoding_name.into_proto(),
2243            }),
2244            EvalError::InvalidJsonbCast { from, to } => InvalidJsonbCast(ProtoInvalidJsonbCast {
2245                from: from.into_proto(),
2246                to: to.into_proto(),
2247            }),
2248            EvalError::InvalidRegex(v) => InvalidRegex(v.into_proto()),
2249            EvalError::InvalidRegexFlag(v) => InvalidRegexFlag(v.into_proto()),
2250            EvalError::InvalidParameterValue(v) => InvalidParameterValue(v.into_proto()),
2251            EvalError::InvalidDatePart(part) => InvalidDatePart(part.into_proto()),
2252            EvalError::KeyCannotBeNull => KeyCannotBeNull(()),
2253            EvalError::NegSqrt => NegSqrt(()),
2254            EvalError::NegLimit => NegLimit(()),
2255            EvalError::NullCharacterNotPermitted => NullCharacterNotPermitted(()),
2256            EvalError::UnknownUnits(v) => UnknownUnits(v.into_proto()),
2257            EvalError::UnsupportedUnits(units, typ) => UnsupportedUnits(ProtoUnsupportedUnits {
2258                units: units.into_proto(),
2259                typ: typ.into_proto(),
2260            }),
2261            EvalError::UnterminatedLikeEscapeSequence => UnterminatedLikeEscapeSequence(()),
2262            EvalError::Parse(error) => Parse(error.into_proto()),
2263            EvalError::PrettyError(error) => PrettyError(error.into_proto()),
2264            EvalError::RedactError(error) => RedactError(error.into_proto()),
2265            EvalError::ParseHex(error) => ParseHex(error.into_proto()),
2266            EvalError::Internal(v) => Internal(v.into_proto()),
2267            EvalError::InfinityOutOfDomain(v) => InfinityOutOfDomain(v.into_proto()),
2268            EvalError::NegativeOutOfDomain(v) => NegativeOutOfDomain(v.into_proto()),
2269            EvalError::ZeroOutOfDomain(v) => ZeroOutOfDomain(v.into_proto()),
2270            EvalError::OutOfDomain(lower, upper, id) => OutOfDomain(ProtoOutOfDomain {
2271                lower: Some(lower.into_proto()),
2272                upper: Some(upper.into_proto()),
2273                id: id.into_proto(),
2274            }),
2275            EvalError::ComplexOutOfRange(v) => ComplexOutOfRange(v.into_proto()),
2276            EvalError::MultipleRowsFromSubquery => MultipleRowsFromSubquery(()),
2277            EvalError::NegativeRowsFromSubquery => NegativeRowsFromSubquery(()),
2278            EvalError::Undefined(v) => Undefined(v.into_proto()),
2279            EvalError::LikePatternTooLong => LikePatternTooLong(()),
2280            EvalError::LikeEscapeTooLong => LikeEscapeTooLong(()),
2281            EvalError::StringValueTooLong {
2282                target_type,
2283                length,
2284            } => StringValueTooLong(ProtoStringValueTooLong {
2285                target_type: target_type.into_proto(),
2286                length: length.into_proto(),
2287            }),
2288            EvalError::MultidimensionalArrayRemovalNotSupported => {
2289                MultidimensionalArrayRemovalNotSupported(())
2290            }
2291            EvalError::IncompatibleArrayDimensions { dims } => {
2292                IncompatibleArrayDimensions(ProtoIncompatibleArrayDimensions {
2293                    dims: dims.into_proto(),
2294                })
2295            }
2296            EvalError::TypeFromOid(v) => TypeFromOid(v.into_proto()),
2297            EvalError::InvalidRange(error) => InvalidRange(error.into_proto()),
2298            EvalError::InvalidRoleId(v) => InvalidRoleId(v.into_proto()),
2299            EvalError::InvalidPrivileges(v) => InvalidPrivileges(v.into_proto()),
2300            EvalError::InvalidCatalogJson(v) => InvalidCatalogJson(v.into_proto()),
2301            EvalError::LetRecLimitExceeded(v) => WmrRecursionLimitExceeded(v.into_proto()),
2302            EvalError::MultiDimensionalArraySearch => MultiDimensionalArraySearch(()),
2303            EvalError::MustNotBeNull(v) => MustNotBeNull(v.into_proto()),
2304            EvalError::InvalidIdentifier { ident, detail } => {
2305                InvalidIdentifier(ProtoInvalidIdentifier {
2306                    ident: ident.into_proto(),
2307                    detail: detail.into_proto(),
2308                })
2309            }
2310            EvalError::ArrayFillWrongArraySubscripts => ArrayFillWrongArraySubscripts(()),
2311            EvalError::MaxArraySizeExceeded(max_size) => {
2312                MaxArraySizeExceeded(u64::cast_from(*max_size))
2313            }
2314            EvalError::DateDiffOverflow { unit, a, b } => DateDiffOverflow(ProtoDateDiffOverflow {
2315                unit: unit.into_proto(),
2316                a: a.into_proto(),
2317                b: b.into_proto(),
2318            }),
2319            EvalError::IfNullError(s) => IfNullError(s.into_proto()),
2320            EvalError::LengthTooLarge => LengthTooLarge(()),
2321            EvalError::AclArrayNullElement => AclArrayNullElement(()),
2322            EvalError::MzAclArrayNullElement => MzAclArrayNullElement(()),
2323            EvalError::InvalidIanaTimezoneId(s) => InvalidIanaTimezoneId(s.into_proto()),
2324        };
2325        ProtoEvalError { kind: Some(kind) }
2326    }
2327
2328    fn from_proto(proto: ProtoEvalError) -> Result<Self, TryFromProtoError> {
2329        use proto_eval_error::Kind::*;
2330        match proto.kind {
2331            Some(kind) => match kind {
2332                CharacterNotValidForEncoding(v) => Ok(EvalError::CharacterNotValidForEncoding(v)),
2333                CharacterTooLargeForEncoding(v) => Ok(EvalError::CharacterTooLargeForEncoding(v)),
2334                DateBinOutOfRange(v) => Ok(EvalError::DateBinOutOfRange(v.into())),
2335                DivisionByZero(()) => Ok(EvalError::DivisionByZero),
2336                Unsupported(v) => Ok(EvalError::Unsupported {
2337                    feature: v.feature.into(),
2338                    discussion_no: v.discussion_no.into_rust()?,
2339                }),
2340                FloatOverflow(()) => Ok(EvalError::FloatOverflow),
2341                FloatUnderflow(()) => Ok(EvalError::FloatUnderflow),
2342                NumericFieldOverflow(()) => Ok(EvalError::NumericFieldOverflow),
2343                Float32OutOfRange(val) => Ok(EvalError::Float32OutOfRange(val.value.into())),
2344                Float64OutOfRange(val) => Ok(EvalError::Float64OutOfRange(val.value.into())),
2345                Int16OutOfRange(val) => Ok(EvalError::Int16OutOfRange(val.value.into())),
2346                Int32OutOfRange(val) => Ok(EvalError::Int32OutOfRange(val.value.into())),
2347                Int64OutOfRange(val) => Ok(EvalError::Int64OutOfRange(val.value.into())),
2348                Uint16OutOfRange(val) => Ok(EvalError::UInt16OutOfRange(val.value.into())),
2349                Uint32OutOfRange(val) => Ok(EvalError::UInt32OutOfRange(val.value.into())),
2350                Uint64OutOfRange(val) => Ok(EvalError::UInt64OutOfRange(val.value.into())),
2351                MzTimestampOutOfRange(val) => {
2352                    Ok(EvalError::MzTimestampOutOfRange(val.value.into()))
2353                }
2354                MzTimestampStepOverflow(()) => Ok(EvalError::MzTimestampStepOverflow),
2355                OidOutOfRange(val) => Ok(EvalError::OidOutOfRange(val.value.into())),
2356                IntervalOutOfRange(val) => Ok(EvalError::IntervalOutOfRange(val.value.into())),
2357                TimestampCannotBeNan(()) => Ok(EvalError::TimestampCannotBeNan),
2358                TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange),
2359                DateOutOfRange(()) => Ok(EvalError::DateOutOfRange),
2360                CharOutOfRange(()) => Ok(EvalError::CharOutOfRange),
2361                IndexOutOfRange(v) => Ok(EvalError::IndexOutOfRange {
2362                    provided: v.provided,
2363                    valid_end: v.valid_end,
2364                }),
2365                InvalidBase64Equals(()) => Ok(EvalError::InvalidBase64Equals),
2366                InvalidBase64Symbol(v) => char::from_proto(v).map(EvalError::InvalidBase64Symbol),
2367                InvalidBase64EndSequence(()) => Ok(EvalError::InvalidBase64EndSequence),
2368                InvalidTimezone(v) => Ok(EvalError::InvalidTimezone(v.into())),
2369                InvalidTimezoneInterval(()) => Ok(EvalError::InvalidTimezoneInterval),
2370                InvalidTimezoneConversion(()) => Ok(EvalError::InvalidTimezoneConversion),
2371                InvalidLayer(v) => Ok(EvalError::InvalidLayer {
2372                    max_layer: usize::from_proto(v.max_layer)?,
2373                    val: v.val,
2374                }),
2375                InvalidArray(error) => Ok(EvalError::InvalidArray(error.into_rust()?)),
2376                InvalidEncodingName(v) => Ok(EvalError::InvalidEncodingName(v.into())),
2377                InvalidHashAlgorithm(v) => Ok(EvalError::InvalidHashAlgorithm(v.into())),
2378                InvalidByteSequence(v) => Ok(EvalError::InvalidByteSequence {
2379                    byte_sequence: v.byte_sequence.into(),
2380                    encoding_name: v.encoding_name.into(),
2381                }),
2382                InvalidJsonbCast(v) => Ok(EvalError::InvalidJsonbCast {
2383                    from: v.from.into(),
2384                    to: v.to.into(),
2385                }),
2386                InvalidRegex(v) => Ok(EvalError::InvalidRegex(v.into())),
2387                InvalidRegexFlag(v) => Ok(EvalError::InvalidRegexFlag(char::from_proto(v)?)),
2388                InvalidParameterValue(v) => Ok(EvalError::InvalidParameterValue(v.into())),
2389                InvalidDatePart(part) => Ok(EvalError::InvalidDatePart(part.into())),
2390                KeyCannotBeNull(()) => Ok(EvalError::KeyCannotBeNull),
2391                NegSqrt(()) => Ok(EvalError::NegSqrt),
2392                NegLimit(()) => Ok(EvalError::NegLimit),
2393                NullCharacterNotPermitted(()) => Ok(EvalError::NullCharacterNotPermitted),
2394                UnknownUnits(v) => Ok(EvalError::UnknownUnits(v.into())),
2395                UnsupportedUnits(v) => {
2396                    Ok(EvalError::UnsupportedUnits(v.units.into(), v.typ.into()))
2397                }
2398                UnterminatedLikeEscapeSequence(()) => Ok(EvalError::UnterminatedLikeEscapeSequence),
2399                Parse(error) => Ok(EvalError::Parse(error.into_rust()?)),
2400                ParseHex(error) => Ok(EvalError::ParseHex(error.into_rust()?)),
2401                Internal(v) => Ok(EvalError::Internal(v.into())),
2402                InfinityOutOfDomain(v) => Ok(EvalError::InfinityOutOfDomain(v.into())),
2403                NegativeOutOfDomain(v) => Ok(EvalError::NegativeOutOfDomain(v.into())),
2404                ZeroOutOfDomain(v) => Ok(EvalError::ZeroOutOfDomain(v.into())),
2405                OutOfDomain(v) => Ok(EvalError::OutOfDomain(
2406                    v.lower.into_rust_if_some("ProtoDomainLimit::lower")?,
2407                    v.upper.into_rust_if_some("ProtoDomainLimit::upper")?,
2408                    v.id.into(),
2409                )),
2410                ComplexOutOfRange(v) => Ok(EvalError::ComplexOutOfRange(v.into())),
2411                MultipleRowsFromSubquery(()) => Ok(EvalError::MultipleRowsFromSubquery),
2412                NegativeRowsFromSubquery(()) => Ok(EvalError::NegativeRowsFromSubquery),
2413                Undefined(v) => Ok(EvalError::Undefined(v.into())),
2414                LikePatternTooLong(()) => Ok(EvalError::LikePatternTooLong),
2415                LikeEscapeTooLong(()) => Ok(EvalError::LikeEscapeTooLong),
2416                StringValueTooLong(v) => Ok(EvalError::StringValueTooLong {
2417                    target_type: v.target_type.into(),
2418                    length: usize::from_proto(v.length)?,
2419                }),
2420                MultidimensionalArrayRemovalNotSupported(()) => {
2421                    Ok(EvalError::MultidimensionalArrayRemovalNotSupported)
2422                }
2423                IncompatibleArrayDimensions(v) => Ok(EvalError::IncompatibleArrayDimensions {
2424                    dims: v.dims.into_rust()?,
2425                }),
2426                TypeFromOid(v) => Ok(EvalError::TypeFromOid(v.into())),
2427                InvalidRange(e) => Ok(EvalError::InvalidRange(e.into_rust()?)),
2428                InvalidRoleId(v) => Ok(EvalError::InvalidRoleId(v.into())),
2429                InvalidPrivileges(v) => Ok(EvalError::InvalidPrivileges(v.into())),
2430                InvalidCatalogJson(v) => Ok(EvalError::InvalidCatalogJson(v.into())),
2431                WmrRecursionLimitExceeded(v) => Ok(EvalError::LetRecLimitExceeded(v.into())),
2432                MultiDimensionalArraySearch(()) => Ok(EvalError::MultiDimensionalArraySearch),
2433                MustNotBeNull(v) => Ok(EvalError::MustNotBeNull(v.into())),
2434                InvalidIdentifier(v) => Ok(EvalError::InvalidIdentifier {
2435                    ident: v.ident.into(),
2436                    detail: v.detail.into_rust()?,
2437                }),
2438                ArrayFillWrongArraySubscripts(()) => Ok(EvalError::ArrayFillWrongArraySubscripts),
2439                MaxArraySizeExceeded(max_size) => {
2440                    Ok(EvalError::MaxArraySizeExceeded(usize::cast_from(max_size)))
2441                }
2442                DateDiffOverflow(v) => Ok(EvalError::DateDiffOverflow {
2443                    unit: v.unit.into(),
2444                    a: v.a.into(),
2445                    b: v.b.into(),
2446                }),
2447                IfNullError(v) => Ok(EvalError::IfNullError(v.into())),
2448                LengthTooLarge(()) => Ok(EvalError::LengthTooLarge),
2449                AclArrayNullElement(()) => Ok(EvalError::AclArrayNullElement),
2450                MzAclArrayNullElement(()) => Ok(EvalError::MzAclArrayNullElement),
2451                InvalidIanaTimezoneId(s) => Ok(EvalError::InvalidIanaTimezoneId(s.into())),
2452                PrettyError(s) => Ok(EvalError::PrettyError(s.into())),
2453                RedactError(s) => Ok(EvalError::RedactError(s.into())),
2454            },
2455            None => Err(TryFromProtoError::missing_field("ProtoEvalError::kind")),
2456        }
2457    }
2458}
2459
2460impl RustType<ProtoDims> for (usize, usize) {
2461    fn into_proto(&self) -> ProtoDims {
2462        ProtoDims {
2463            f0: self.0.into_proto(),
2464            f1: self.1.into_proto(),
2465        }
2466    }
2467
2468    fn from_proto(proto: ProtoDims) -> Result<Self, TryFromProtoError> {
2469        Ok((proto.f0.into_rust()?, proto.f1.into_rust()?))
2470    }
2471}
2472
2473#[cfg(test)]
2474mod tests {
2475    use super::*;
2476    use crate::scalar::func::variadic::Coalesce;
2477
2478    #[mz_ore::test]
2479    #[cfg_attr(miri, ignore)] // error: unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
2480    fn test_reduce() {
2481        let relation_type: Vec<ReprColumnType> = vec![
2482            ReprScalarType::Int64.nullable(true),
2483            ReprScalarType::Int64.nullable(true),
2484            ReprScalarType::Int64.nullable(false),
2485        ]
2486        .into_iter()
2487        .collect();
2488        let col = MirScalarExpr::column;
2489        let int64_typ = ReprScalarType::Int64;
2490        let err = |e| MirScalarExpr::literal(Err(e), int64_typ.clone());
2491        let lit = |i| MirScalarExpr::literal_ok(Datum::Int64(i), int64_typ.clone());
2492        let null = || MirScalarExpr::literal_null(int64_typ.clone());
2493
2494        struct TestCase {
2495            input: MirScalarExpr,
2496            output: MirScalarExpr,
2497        }
2498
2499        let test_cases = vec![
2500            TestCase {
2501                input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1)]),
2502                output: lit(1),
2503            },
2504            TestCase {
2505                input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1), lit(2)]),
2506                output: lit(1),
2507            },
2508            TestCase {
2509                input: MirScalarExpr::call_variadic(Coalesce, vec![null(), lit(2), null()]),
2510                output: lit(2),
2511            },
2512            TestCase {
2513                input: MirScalarExpr::call_variadic(
2514                    Coalesce,
2515                    vec![null(), col(0), null(), col(1), lit(2), lit(3)],
2516                ),
2517                output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(1), lit(2)]),
2518            },
2519            TestCase {
2520                input: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2), col(1)]),
2521                output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2)]),
2522            },
2523            TestCase {
2524                input: MirScalarExpr::call_variadic(
2525                    Coalesce,
2526                    vec![lit(1), err(EvalError::DivisionByZero)],
2527                ),
2528                output: lit(1),
2529            },
2530            TestCase {
2531                input: MirScalarExpr::call_variadic(
2532                    Coalesce,
2533                    vec![
2534                        null(),
2535                        err(EvalError::DivisionByZero),
2536                        err(EvalError::NumericFieldOverflow),
2537                    ],
2538                ),
2539                output: err(EvalError::DivisionByZero),
2540            },
2541        ];
2542
2543        for tc in test_cases {
2544            let mut actual = tc.input.clone();
2545            actual.reduce(&relation_type);
2546            assert!(
2547                actual == tc.output,
2548                "input: {}\nactual: {}\nexpected: {}",
2549                tc.input,
2550                actual,
2551                tc.output
2552            );
2553        }
2554    }
2555
2556    /// Exercises the `unsafe` pointer stack in [`Visit::visit_mut_post`] with a
2557    /// closure that *replaces subtrees* (`*expr = ...`). Miri's aliasing model
2558    /// should shout if the "stack mirrors the call stack" becomes untrue.
2559    #[mz_ore::test]
2560    fn test_visit_mut_post_replace_subtrees() {
2561        let col = MirScalarExpr::column;
2562        let mut expr = col(0).if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
2563
2564        expr.visit_mut_post(&mut |expr: &mut MirScalarExpr| match expr {
2565            MirScalarExpr::Column(n, _) => *n += 1,
2566            MirScalarExpr::If { then, .. } => {
2567                let then = then.take();
2568                *expr = then;
2569            }
2570            _ => {}
2571        });
2572
2573        // collapses to then-most branch
2574        assert_eq!(expr, col(3));
2575    }
2576
2577    /// Exercises the `unsafe` pointer stack in [`Visit::visit_mut_pre_post`] with
2578    /// a `pre` that both *replaces the visited node wholesale* (`*expr = ...`)
2579    /// and *returns an explicit child set* borrowed from the freshly written
2580    /// value. Miri's aliasing model should shout if the "stack mirrors the call
2581    /// stack" becomes untrue.
2582    #[mz_ore::test]
2583    fn test_visit_mut_pre_post_explicit_children() {
2584        let col = MirScalarExpr::column;
2585        let mut expr = col(5)
2586            .if_then_else(col(6), col(7))
2587            .if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
2588
2589        // turns conditions into column 0 in pre
2590        // doesn't traverse conditions of ifs
2591        // adds 10 to all column refs in post (but not in conditions!)
2592        expr.visit_mut_pre_post(
2593            &mut |expr: &mut MirScalarExpr| -> Option<Vec<&mut MirScalarExpr>> {
2594                if let MirScalarExpr::If { .. } = expr {
2595                    let MirScalarExpr::If { then, els, .. } = expr else {
2596                        unreachable!()
2597                    };
2598                    let then = then.take();
2599                    let els = els.take();
2600                    *expr = MirScalarExpr::column(0).if_then_else(then, els);
2601
2602                    let MirScalarExpr::If { then, els, .. } = expr else {
2603                        unreachable!()
2604                    };
2605                    Some(vec![then.as_mut(), els.as_mut()])
2606                } else {
2607                    // Leaves recurse with their default (empty) child set.
2608                    None
2609                }
2610            },
2611            &mut |expr: &mut MirScalarExpr| {
2612                if let MirScalarExpr::Column(n, _) = expr {
2613                    *n += 10;
2614                }
2615            },
2616        );
2617
2618        // conditions become 0; everyone else += 10
2619        let expected = col(0).if_then_else(col(0).if_then_else(col(12), col(13)), col(14));
2620        assert_eq!(expr, expected);
2621    }
2622}