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