Skip to main content

mz_expr/
scalar.rs

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