1use std::collections::BTreeSet;
11use std::ops::BitOrAssign;
12use std::sync::Arc;
13use std::{fmt, mem};
14
15use itertools::Itertools;
16use mz_ore::cast::CastFrom;
17use mz_ore::iter::IteratorExt;
18use mz_ore::soft_assert_or_log;
19use mz_ore::stack::RecursionLimitError;
20use mz_ore::str::StrExt;
21use mz_ore::treat_as_equal::TreatAsEqual;
22use mz_ore::vec::swap_remove_multiple;
23use mz_pgrepr::TypeFromOidError;
24use mz_proto::{IntoRustIfSome, ProtoType, RustType, TryFromProtoError};
25use mz_repr::adt::array::InvalidArrayError;
26use mz_repr::adt::date::DateError;
27use mz_repr::adt::range::InvalidRangeError;
28use mz_repr::adt::regex::RegexCompilationError;
29use mz_repr::adt::timestamp::TimestampError;
30use mz_repr::strconv::{ParseError, ParseHexError};
31use mz_repr::{Datum, ReprColumnType, ReprScalarType, Row, RowArena, SqlColumnType};
32
33#[cfg(any(test, feature = "proptest"))]
34use proptest::prelude::*;
35#[cfg(any(test, feature = "proptest"))]
36use proptest_derive::Arbitrary;
37use serde::{Deserialize, Serialize};
38
39use crate::explain::{HumanizedExplain, HumanizerMode};
40pub use crate::scalar::columns::Columns;
41pub use crate::scalar::eval::Eval;
42use crate::scalar::func::variadic::{And, Or};
43use crate::scalar::func::{BinaryFunc, UnaryFunc, UnmaterializableFunc, VariadicFunc};
44pub use crate::scalar::optimizable::OptimizableExpr;
45use crate::scalar::proto_eval_error::proto_incompatible_array_dimensions::ProtoDims;
46use crate::visit::{Visit, VisitChildren};
47
48pub mod columns;
49pub mod eval;
50pub mod func;
51pub mod like_pattern;
52pub mod optimizable;
53mod reduce;
54
55include!(concat!(env!("OUT_DIR"), "/mz_expr.scalar.rs"));
56
57#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
58pub enum MirScalarExpr {
59 Column(usize, TreatAsEqual<Option<Arc<str>>>),
61 Literal(Result<Row, EvalError>, ReprColumnType),
64 CallUnmaterializable(UnmaterializableFunc),
69 CallUnary {
71 func: UnaryFunc,
72 expr: Box<MirScalarExpr>,
73 },
74 CallBinary {
76 func: BinaryFunc,
77 expr1: Box<MirScalarExpr>,
78 expr2: Box<MirScalarExpr>,
79 },
80 CallVariadic {
82 func: VariadicFunc,
83 exprs: Vec<MirScalarExpr>,
84 },
85 If {
92 cond: Box<MirScalarExpr>,
93 then: Box<MirScalarExpr>,
94 els: Box<MirScalarExpr>,
95 },
96}
97
98impl std::fmt::Debug for MirScalarExpr {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 match self {
103 MirScalarExpr::Column(i, TreatAsEqual(Some(name))) => {
104 write!(f, "Column({i}, {name:?})")
105 }
106 MirScalarExpr::Column(i, TreatAsEqual(None)) => write!(f, "Column({i})"),
107 MirScalarExpr::Literal(lit, typ) => write!(f, "Literal({lit:?}, {typ:?})"),
108 MirScalarExpr::CallUnmaterializable(func) => {
109 write!(f, "CallUnmaterializable({func:?})")
110 }
111 MirScalarExpr::CallUnary { func, expr } => {
112 write!(f, "CallUnary({func:?}, {expr:?})")
113 }
114 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
115 write!(f, "CallBinary({func:?}, {expr1:?}, {expr2:?})")
116 }
117 MirScalarExpr::CallVariadic { func, exprs } => {
118 write!(f, "CallVariadic({func:?}, {exprs:?})")
119 }
120 MirScalarExpr::If { cond, then, els } => {
121 write!(f, "If({cond:?}, {then:?}, {els:?})")
122 }
123 }
124 }
125}
126
127impl MirScalarExpr {
128 pub fn columns(is: &[usize]) -> Vec<MirScalarExpr> {
129 is.iter().map(|i| MirScalarExpr::column(*i)).collect()
130 }
131
132 pub fn column(column: usize) -> Self {
133 MirScalarExpr::Column(column, TreatAsEqual(None))
134 }
135
136 pub fn named_column(column: usize, name: Arc<str>) -> Self {
137 MirScalarExpr::Column(column, TreatAsEqual(Some(name)))
138 }
139
140 pub fn literal(res: Result<Datum, EvalError>, typ: ReprScalarType) -> Self {
141 let typ = ReprColumnType {
142 scalar_type: typ,
143 nullable: matches!(res, Ok(Datum::Null)),
144 };
145 let row = res.map(|datum| Row::pack_slice(&[datum]));
146 MirScalarExpr::Literal(row, typ)
147 }
148
149 pub fn literal_ok(datum: Datum, typ: ReprScalarType) -> Self {
150 MirScalarExpr::literal(Ok(datum), typ)
151 }
152
153 pub fn literal_from_single_element_row(row: Row, typ: ReprScalarType) -> Self {
157 soft_assert_or_log!(
158 row.iter().count() == 1,
159 "literal_from_row called with a Row containing {} datums",
160 row.iter().count()
161 );
162 let nullable = row.unpack_first() == Datum::Null;
163 let typ = ReprColumnType {
164 scalar_type: typ,
165 nullable,
166 };
167 MirScalarExpr::Literal(Ok(row), typ)
168 }
169
170 pub fn literal_null(typ: ReprScalarType) -> Self {
171 MirScalarExpr::literal_ok(Datum::Null, typ)
172 }
173
174 pub fn literal_false() -> Self {
175 MirScalarExpr::literal_ok(Datum::False, ReprScalarType::Bool)
176 }
177
178 pub fn literal_true() -> Self {
179 MirScalarExpr::literal_ok(Datum::True, ReprScalarType::Bool)
180 }
181
182 pub fn call_unary<U: Into<UnaryFunc>>(self, func: U) -> Self {
183 MirScalarExpr::CallUnary {
184 func: func.into(),
185 expr: Box::new(self),
186 }
187 }
188
189 pub fn call_binary<B: Into<BinaryFunc>>(self, other: Self, func: B) -> Self {
190 MirScalarExpr::CallBinary {
191 func: func.into(),
192 expr1: Box::new(self),
193 expr2: Box::new(other),
194 }
195 }
196
197 pub fn call_variadic<V: Into<VariadicFunc>>(func: V, exprs: Vec<Self>) -> Self {
199 MirScalarExpr::CallVariadic {
200 func: func.into(),
201 exprs,
202 }
203 }
204
205 pub fn if_then_else(self, t: Self, f: Self) -> Self {
206 MirScalarExpr::If {
207 cond: Box::new(self),
208 then: Box::new(t),
209 els: Box::new(f),
210 }
211 }
212
213 pub fn or(self, other: Self) -> Self {
214 MirScalarExpr::call_variadic(Or, vec![self, other])
215 }
216
217 pub fn and(self, other: Self) -> Self {
218 MirScalarExpr::call_variadic(And, vec![self, other])
219 }
220
221 pub fn not(self) -> Self {
222 self.call_unary(UnaryFunc::Not(func::Not))
223 }
224
225 pub fn call_is_null(self) -> Self {
226 self.call_unary(UnaryFunc::IsNull(func::IsNull))
227 }
228
229 pub fn and_or_args(&self, func_to_match: VariadicFunc) -> Vec<MirScalarExpr> {
232 assert!(func_to_match == Or.into() || func_to_match == And.into());
233 match self {
234 MirScalarExpr::CallVariadic { func, exprs } if *func == func_to_match => exprs.clone(),
235 _ => vec![self.clone()],
236 }
237 }
238
239 pub fn expr_eq_literal(&self, expr: &MirScalarExpr) -> Option<(Row, bool)> {
250 if let MirScalarExpr::CallBinary {
251 func: BinaryFunc::Eq(_),
252 expr1,
253 expr2,
254 } = self
255 {
256 if expr1.is_literal_null() || expr2.is_literal_null() {
257 return None;
258 }
259 if let Some(Ok(lit)) = expr1.as_literal_owned() {
260 return Self::expr_eq_literal_inner(expr, lit, expr1, expr2);
261 }
262 if let Some(Ok(lit)) = expr2.as_literal_owned() {
263 return Self::expr_eq_literal_inner(expr, lit, expr2, expr1);
264 }
265 }
266 None
267 }
268
269 fn expr_eq_literal_inner(
270 expr_to_match: &MirScalarExpr,
271 literal: Row,
272 literal_expr: &MirScalarExpr,
273 other_side: &MirScalarExpr,
274 ) -> Option<(Row, bool)> {
275 if other_side == expr_to_match {
276 return Some((literal, false));
277 } else {
278 let (cast_removed, inv_cast_lit) =
280 Self::invert_casts_on_expr_eq_literal_inner(other_side, literal_expr);
281 if &cast_removed == expr_to_match {
282 if let Some(Ok(inv_cast_lit_row)) = inv_cast_lit.as_literal_owned() {
283 return Some((inv_cast_lit_row, true));
284 }
285 }
286 }
287 None
288 }
289
290 pub fn any_expr_eq_literal(&self) -> Option<MirScalarExpr> {
294 if let MirScalarExpr::CallBinary {
295 func: BinaryFunc::Eq(_),
296 expr1,
297 expr2,
298 } = self
299 {
300 if expr1.is_literal() {
301 let (expr, _literal) = Self::invert_casts_on_expr_eq_literal_inner(expr2, expr1);
302 return Some(expr);
303 }
304 if expr2.is_literal() {
305 let (expr, _literal) = Self::invert_casts_on_expr_eq_literal_inner(expr1, expr2);
306 return Some(expr);
307 }
308 }
309 None
310 }
311
312 pub fn invert_casts_on_expr_eq_literal(&self) -> MirScalarExpr {
317 if let MirScalarExpr::CallBinary {
318 func: BinaryFunc::Eq(_),
319 expr1,
320 expr2,
321 } = self
322 {
323 if expr1.is_literal() {
324 let (expr, literal) = Self::invert_casts_on_expr_eq_literal_inner(expr2, expr1);
325 return literal.call_binary(expr, func::Eq);
326 }
327 if expr2.is_literal() {
328 let (expr, literal) = Self::invert_casts_on_expr_eq_literal_inner(expr1, expr2);
329 return literal.call_binary(expr, func::Eq);
330 }
331 }
334 self.clone()
335 }
336
337 fn invert_casts_on_expr_eq_literal_inner(
349 expr: &MirScalarExpr,
350 literal: &MirScalarExpr,
351 ) -> (MirScalarExpr, MirScalarExpr) {
352 assert!(matches!(literal, MirScalarExpr::Literal(..)));
353
354 let temp_storage = &RowArena::new();
355 let eval = |e: &MirScalarExpr| {
356 MirScalarExpr::literal(e.eval(&[], temp_storage), e.typ(&[]).scalar_type)
357 };
358
359 if let MirScalarExpr::CallUnary {
360 func,
361 expr: inner_expr,
362 } = expr
363 {
364 if let Some(inverse_func) = func.inverse() {
365 if func.preserves_uniqueness() && inverse_func.preserves_uniqueness() {
372 let lit_inv = eval(&MirScalarExpr::CallUnary {
373 func: inverse_func,
374 expr: Box::new(literal.clone()),
375 });
376 if !lit_inv.is_literal_err() {
379 return (*inner_expr.clone(), lit_inv);
380 }
381 }
382 }
383 }
384 (expr.clone(), literal.clone())
385 }
386
387 pub fn impossible_literal_equality_because_types(&self) -> bool {
393 if let MirScalarExpr::CallBinary {
394 func: BinaryFunc::Eq(_),
395 expr1,
396 expr2,
397 } = self
398 {
399 if expr1.is_literal() {
400 return Self::impossible_literal_equality_because_types_inner(expr1, expr2);
401 }
402 if expr2.is_literal() {
403 return Self::impossible_literal_equality_because_types_inner(expr2, expr1);
404 }
405 }
406 false
407 }
408
409 fn impossible_literal_equality_because_types_inner(
410 literal: &MirScalarExpr,
411 other_side: &MirScalarExpr,
412 ) -> bool {
413 assert!(matches!(literal, MirScalarExpr::Literal(..)));
414
415 let temp_storage = &RowArena::new();
416 let eval = |e: &MirScalarExpr| {
417 MirScalarExpr::literal(e.eval(&[], temp_storage), e.typ(&[]).scalar_type)
418 };
419
420 if let MirScalarExpr::CallUnary { func, .. } = other_side {
421 if let Some(inverse_func) = func.inverse() {
422 if inverse_func.preserves_uniqueness()
423 && eval(&MirScalarExpr::CallUnary {
424 func: inverse_func,
425 expr: Box::new(literal.clone()),
426 })
427 .is_literal_err()
428 {
429 return true;
430 }
431 }
432 }
433
434 false
435 }
436
437 pub fn any_expr_ineq_literal(&self) -> bool {
447 match self {
448 MirScalarExpr::CallBinary {
449 func:
450 BinaryFunc::Lt(_) | BinaryFunc::Lte(_) | BinaryFunc::Gt(_) | BinaryFunc::Gte(_),
451 expr1,
452 expr2,
453 } => expr1.is_literal() || expr2.is_literal(),
454 _ => false,
455 }
456 }
457
458 pub fn take(&mut self) -> Self {
459 mem::replace(self, MirScalarExpr::literal_null(ReprScalarType::String))
460 }
461
462 pub fn as_literal(&self) -> Option<Result<Datum<'_>, &EvalError>> {
465 if let MirScalarExpr::Literal(lit, _column_type) = self {
466 Some(lit.as_ref().map(|row| row.unpack_first()))
467 } else {
468 None
469 }
470 }
471
472 pub fn as_literal_non_error(&self) -> Option<Datum<'_>> {
475 self.as_literal().map(|eval_err| eval_err.ok()).flatten()
476 }
477
478 pub fn as_literal_owned(&self) -> Option<Result<Row, EvalError>> {
479 if let MirScalarExpr::Literal(lit, _column_type) = self {
480 Some(lit.clone())
481 } else {
482 None
483 }
484 }
485
486 pub fn as_literal_non_null_row(&self) -> Option<&Row> {
488 if let MirScalarExpr::Literal(Ok(row), _) = self {
489 if !row.unpack_first().is_null() {
490 return Some(row);
491 }
492 }
493 None
494 }
495
496 pub fn as_literal_str(&self) -> Option<&str> {
497 match self.as_literal() {
498 Some(Ok(Datum::String(s))) => Some(s),
499 _ => None,
500 }
501 }
502
503 pub fn as_literal_int64(&self) -> Option<i64> {
504 match self.as_literal() {
505 Some(Ok(Datum::Int64(i))) => Some(i),
506 _ => None,
507 }
508 }
509
510 pub fn as_literal_err(&self) -> Option<&EvalError> {
511 self.as_literal().and_then(|lit| lit.err())
512 }
513
514 pub fn is_literal(&self) -> bool {
515 matches!(self, MirScalarExpr::Literal(_, _))
516 }
517
518 pub fn is_literal_true(&self) -> bool {
519 Some(Ok(Datum::True)) == self.as_literal()
520 }
521
522 pub fn is_literal_false(&self) -> bool {
523 Some(Ok(Datum::False)) == self.as_literal()
524 }
525
526 pub fn is_literal_null(&self) -> bool {
527 Some(Ok(Datum::Null)) == self.as_literal()
528 }
529
530 pub fn is_literal_ok(&self) -> bool {
531 matches!(self, MirScalarExpr::Literal(Ok(_), _typ))
532 }
533
534 pub fn is_literal_err(&self) -> bool {
535 matches!(self, MirScalarExpr::Literal(Err(_), _typ))
536 }
537
538 pub fn is_error_if_null(&self) -> bool {
539 matches!(
540 self,
541 Self::CallVariadic {
542 func: VariadicFunc::ErrorIfNull(_),
543 ..
544 }
545 )
546 }
547
548 pub fn as_mut_temporal_filter(&mut self) -> Result<(&BinaryFunc, &mut MirScalarExpr), String> {
558 if !self.contains_temporal() {
559 return Err("Does not involve mz_now()".to_string());
560 }
561 if let MirScalarExpr::CallBinary { func, expr1, expr2 } = self {
563 if !expr1.contains_temporal()
565 && **expr2 == MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow)
566 {
567 let new_func = match func {
568 BinaryFunc::Eq(_) => func::Eq.into(),
569 BinaryFunc::Lt(_) => func::Gt.into(),
570 BinaryFunc::Lte(_) => func::Gte.into(),
571 BinaryFunc::Gt(_) => func::Lt.into(),
572 BinaryFunc::Gte(_) => func::Lte.into(),
573 x => {
574 return Err(format!("Unsupported binary temporal operation: {:?}", x));
575 }
576 };
577 std::mem::swap(expr1, expr2);
578 *func = new_func;
579 }
580
581 if expr2.contains_temporal()
583 || **expr1 != MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow)
584 {
585 let mode = HumanizedExplain::new(false); let bad_expr = MirScalarExpr::CallBinary {
587 func: func.clone(),
588 expr1: expr1.clone(),
589 expr2: expr2.clone(),
590 };
591 return Err(format!(
592 "Unsupported temporal predicate. Note: `mz_now()` must be directly compared to a mz_timestamp-castable expression. Expression found: {}",
593 mode.expr(&bad_expr, None),
594 ));
595 }
596
597 Ok((&*func, expr2))
598 } else {
599 let mode = HumanizedExplain::new(false); Err(format!(
601 "Unsupported temporal predicate. Note: `mz_now()` must be directly compared to a non-temporal expression of mz_timestamp-castable type. Expression found: {}",
602 mode.expr(self, None),
603 ))
604 }
605 }
606
607 #[deprecated = "Use `might_error` instead"]
608 pub fn contains_error_if_null(&self) -> bool {
609 let mut worklist = vec![self];
610 while let Some(expr) = worklist.pop() {
611 if expr.is_error_if_null() {
612 return true;
613 }
614 worklist.extend(expr.children());
615 }
616 false
617 }
618
619 pub fn contains_err(&self) -> bool {
620 let mut worklist = vec![self];
621 while let Some(expr) = worklist.pop() {
622 if expr.is_literal_err() {
623 return true;
624 }
625 worklist.extend(expr.children());
626 }
627 false
628 }
629
630 pub fn might_error(&self) -> bool {
636 let mut worklist = vec![self];
637 while let Some(expr) = worklist.pop() {
638 if expr.is_literal_err() || expr.is_error_if_null() {
639 return true;
640 }
641 worklist.extend(expr.children());
642 }
643 false
644 }
645
646 pub fn reduce(&mut self, column_types: &[ReprColumnType]) {
679 reduce::reduce(self, column_types);
680 }
681
682 fn decompose_is_null(&mut self) -> Option<MirScalarExpr> {
690 match self {
693 MirScalarExpr::CallUnary {
694 func,
695 expr: inner_expr,
696 } => {
697 if !func.introduces_nulls() {
698 if func.propagates_nulls() {
699 *self = inner_expr.take();
700 return self.decompose_is_null();
701 } else {
702 return Some(MirScalarExpr::literal_false());
721 }
722 }
723 }
724 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
725 if func.propagates_nulls() && !func.introduces_nulls() {
728 let expr1 = expr1.take().call_is_null();
729 let expr2 = expr2.take().call_is_null();
730 return Some(expr1.or(expr2));
731 }
732 }
733 MirScalarExpr::CallVariadic { func, exprs } => {
734 if func.propagates_nulls() && !func.introduces_nulls() {
735 let exprs = exprs.into_iter().map(|e| e.take().call_is_null()).collect();
736 return Some(MirScalarExpr::call_variadic(Or, exprs));
737 }
738 }
739 _ => {}
740 }
741
742 None
743 }
744
745 pub fn flatten_associative(&mut self) {
748 match self {
749 MirScalarExpr::CallVariadic {
750 exprs: outer_operands,
751 func: outer_func,
752 } if outer_func.is_associative() => {
753 *outer_operands = outer_operands
754 .into_iter()
755 .flat_map(|o| {
756 if let MirScalarExpr::CallVariadic {
757 exprs: inner_operands,
758 func: inner_func,
759 } = o
760 {
761 if *inner_func == *outer_func {
762 mem::take(inner_operands)
763 } else {
764 vec![o.take()]
765 }
766 } else {
767 vec![o.take()]
768 }
769 })
770 .collect();
771 }
772 _ => {}
773 }
774 }
775
776 fn reduce_and_canonicalize_and_or(&mut self) {
780 let mut old_self = MirScalarExpr::column(0);
784 while old_self != *self {
785 old_self = self.clone();
786 match self {
787 MirScalarExpr::CallVariadic {
788 func: func @ (VariadicFunc::And(_) | VariadicFunc::Or(_)),
789 exprs,
790 } => {
791 exprs.sort();
795
796 exprs.dedup(); if exprs.len() == 1 {
800 *self = exprs.swap_remove(0);
802 } else if exprs.len() == 0 {
803 *self = func.unit_of_and_or();
805 } else if exprs.iter().any(|e| *e == func.zero_of_and_or()) {
806 *self = func.zero_of_and_or();
808 } else {
809 exprs.retain(|e| *e != func.unit_of_and_or());
812 }
813 }
814 _ => {}
815 }
816 }
817 }
818
819 fn demorgans(&mut self) {
821 if let MirScalarExpr::CallUnary {
822 expr: inner,
823 func: UnaryFunc::Not(func::Not),
824 } = self
825 {
826 inner.flatten_associative();
827 match &mut **inner {
828 MirScalarExpr::CallVariadic {
829 func: inner_func @ (VariadicFunc::And(_) | VariadicFunc::Or(_)),
830 exprs,
831 } => {
832 *inner_func = inner_func.switch_and_or();
833 *exprs = exprs.into_iter().map(|e| e.take().not()).collect();
834 *self = (*inner).take(); }
836 _ => {}
837 }
838 }
839 }
840
841 fn undistribute_and_or(&mut self) {
906 let mut old_self = MirScalarExpr::column(0);
911 while old_self != *self {
912 old_self = self.clone();
913 self.reduce_and_canonicalize_and_or(); if let MirScalarExpr::CallVariadic {
915 exprs: outer_operands,
916 func: outer_func @ (VariadicFunc::Or(_) | VariadicFunc::And(_)),
917 } = self
918 {
919 let inner_func = outer_func.switch_and_or();
920
921 outer_operands.iter_mut().for_each(|o| {
924 if !matches!(o, MirScalarExpr::CallVariadic {func: f, ..} if *f == inner_func) {
925 *o = MirScalarExpr::CallVariadic {
926 func: inner_func.clone(),
927 exprs: vec![o.take()],
928 };
929 }
930 });
931
932 let mut inner_operands_refs: Vec<&mut Vec<MirScalarExpr>> = outer_operands
933 .iter_mut()
934 .map(|o| match o {
935 MirScalarExpr::CallVariadic { func: f, exprs } if *f == inner_func => exprs,
936 _ => unreachable!(), })
938 .collect();
939
940 let mut intersection = inner_operands_refs
942 .iter()
943 .map(|v| (*v).clone())
944 .reduce(|ops1, ops2| ops1.into_iter().filter(|e| ops2.contains(e)).collect())
945 .unwrap();
946 intersection.sort();
947 intersection.dedup();
948
949 if !intersection.is_empty() {
950 inner_operands_refs
954 .iter_mut()
955 .for_each(|ops| (**ops).retain(|o| !intersection.contains(o)));
956
957 outer_operands
959 .iter_mut()
960 .for_each(|o| o.reduce_and_canonicalize_and_or());
961
962 *self = MirScalarExpr::CallVariadic {
964 func: inner_func,
965 exprs: intersection.into_iter().chain_one(self.clone()).collect(),
966 };
967 } else {
968 let all_inner_operands = inner_operands_refs
979 .iter()
980 .enumerate()
981 .flat_map(|(i, inner_vec)| inner_vec.iter().map(move |a| ((*a).clone(), i)))
982 .sorted()
983 .collect_vec();
984
985 let undistribution_opportunities = all_inner_operands
990 .iter()
991 .chunk_by(|(a, _i)| a)
992 .into_iter()
993 .map(|(_a, g)| g.map(|(_a, i)| *i).sorted().dedup().collect_vec())
994 .filter(|g| g.len() > 1)
995 .collect_vec();
996
997 let indexes_to_undistribute = undistribution_opportunities
999 .iter()
1000 .find(|index_set| {
1002 index_set
1003 .iter()
1004 .any(|i| inner_operands_refs.get(*i).unwrap().len() == 1)
1005 })
1006 .or_else(|| undistribution_opportunities.first())
1008 .cloned();
1009
1010 outer_operands
1012 .iter_mut()
1013 .for_each(|o| o.reduce_and_canonicalize_and_or());
1014
1015 if let Some(indexes_to_undistribute) = indexes_to_undistribute {
1016 let mut undistribute_from = MirScalarExpr::CallVariadic {
1020 func: outer_func.clone(),
1021 exprs: swap_remove_multiple(outer_operands, indexes_to_undistribute),
1022 };
1023 undistribute_from.undistribute_and_or();
1026 outer_operands.push(undistribute_from);
1029 }
1030 }
1031 }
1032 }
1033 }
1034
1035 pub fn non_null_requirements(&self, columns: &mut BTreeSet<usize>) {
1039 match self {
1040 MirScalarExpr::Column(col, _name) => {
1041 columns.insert(*col);
1042 }
1043 MirScalarExpr::Literal(..) => {}
1044 MirScalarExpr::CallUnmaterializable(_) => (),
1045 MirScalarExpr::CallUnary { func, expr } => {
1046 if func.propagates_nulls() {
1047 expr.non_null_requirements(columns);
1048 }
1049 }
1050 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1051 if func.propagates_nulls() {
1052 expr1.non_null_requirements(columns);
1053 expr2.non_null_requirements(columns);
1054 }
1055 }
1056 MirScalarExpr::CallVariadic { func, exprs } => {
1057 if func.propagates_nulls() {
1058 for expr in exprs {
1059 expr.non_null_requirements(columns);
1060 }
1061 }
1062 }
1063 MirScalarExpr::If { .. } => (),
1064 }
1065 }
1066
1067 pub fn sql_typ(&self, column_types: &[SqlColumnType]) -> SqlColumnType {
1068 let repr_column_types = column_types.iter().map(ReprColumnType::from).collect_vec();
1069 SqlColumnType::from_repr(&self.typ(&repr_column_types))
1070 }
1071
1072 pub fn typ(&self, column_types: &[ReprColumnType]) -> ReprColumnType {
1073 match self {
1074 MirScalarExpr::Column(i, _name) => column_types[*i].clone(),
1075 MirScalarExpr::Literal(_, typ) => typ.clone(),
1076 MirScalarExpr::CallUnmaterializable(func) => func.output_type(),
1077 MirScalarExpr::CallUnary { expr, func } => func.output_type(expr.typ(column_types)),
1078 MirScalarExpr::CallBinary { expr1, expr2, func } => {
1079 func.output_type(&[expr1.typ(column_types), expr2.typ(column_types)])
1080 }
1081 MirScalarExpr::CallVariadic { exprs, func } => {
1082 func.output_type(exprs.iter().map(|e| e.typ(column_types)).collect())
1083 }
1084 MirScalarExpr::If { cond: _, then, els } => {
1085 let then_type = then.typ(column_types);
1086 let else_type = els.typ(column_types);
1087 then_type.union(&else_type).unwrap()
1088 }
1089 }
1090 }
1091
1092 pub fn contains_temporal(&self) -> bool {
1095 let mut contains = false;
1096 self.visit_pre(|e| {
1097 if let MirScalarExpr::CallUnmaterializable(UnmaterializableFunc::MzNow) = e {
1098 contains = true;
1099 }
1100 });
1101 contains
1102 }
1103
1104 pub fn contains_unmaterializable(&self) -> bool {
1106 let mut contains = false;
1107 self.visit_pre(|e| {
1108 if let MirScalarExpr::CallUnmaterializable(_) = e {
1109 contains = true;
1110 }
1111 });
1112 contains
1113 }
1114
1115 pub fn contains_unmaterializable_except(&self, exceptions: &[UnmaterializableFunc]) -> bool {
1118 let mut contains = false;
1119 self.visit_pre(|e| match e {
1120 MirScalarExpr::CallUnmaterializable(f) if !exceptions.contains(f) => contains = true,
1121 _ => (),
1122 });
1123 contains
1124 }
1125
1126 pub fn contains_column(&self) -> bool {
1128 let mut contains = false;
1129 self.visit_pre(|e| {
1130 if let MirScalarExpr::Column(_col, _name) = e {
1131 contains = true;
1132 }
1133 });
1134 contains
1135 }
1136
1137 pub fn contains_dummy(&self) -> bool {
1139 let mut contains = false;
1140 self.visit_pre(|e| {
1141 if let MirScalarExpr::Literal(row, _) = e {
1142 if let Ok(row) = row {
1143 contains |= row.iter().any(|d| d.contains_dummy());
1144 }
1145 }
1146 });
1147 contains
1148 }
1149
1150 pub fn size(&self) -> usize {
1152 let mut size = 0;
1153 self.visit_pre(&mut |_: &MirScalarExpr| {
1154 size += 1;
1155 });
1156 size
1157 }
1158}
1159
1160fn check_temp_storage_budget(temp_storage: &RowArena) -> Result<(), EvalError> {
1170 if temp_storage.over_budget() {
1171 return Err(EvalError::TempStorageBudgetExceeded);
1172 }
1173 Ok(())
1174}
1175
1176impl Eval for MirScalarExpr {
1177 fn eval<'a>(
1178 &'a self,
1179 datums: &[Datum<'a>],
1180 temp_storage: &'a RowArena,
1181 ) -> Result<Datum<'a>, EvalError> {
1182 match self {
1183 MirScalarExpr::Column(index, _name) => Ok(datums[*index]),
1184 MirScalarExpr::Literal(res, _column_type) => match res {
1185 Ok(row) => Ok(row.unpack_first()),
1186 Err(e) => Err(e.clone()),
1187 },
1188 MirScalarExpr::CallUnmaterializable(x) => Err(EvalError::Internal(
1192 format!("cannot evaluate unmaterializable function: {:?}", x).into(),
1193 )),
1194 MirScalarExpr::CallUnary { func, expr } => {
1195 let datum = func.eval(datums, temp_storage, expr.as_ref())?;
1196 check_temp_storage_budget(temp_storage)?;
1197 Ok(datum)
1198 }
1199 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1200 let datum = func.eval(datums, temp_storage, &[expr1.as_ref(), expr2.as_ref()])?;
1201 check_temp_storage_budget(temp_storage)?;
1202 Ok(datum)
1203 }
1204 MirScalarExpr::CallVariadic { func, exprs } => {
1205 let datum = func.eval(datums, temp_storage, exprs.as_slice())?;
1206 check_temp_storage_budget(temp_storage)?;
1207 Ok(datum)
1208 }
1209 MirScalarExpr::If { cond, then, els } => match cond.eval(datums, temp_storage)? {
1210 Datum::True => then.eval(datums, temp_storage),
1211 Datum::False | Datum::Null => els.eval(datums, temp_storage),
1212 d => Err(EvalError::Internal(
1213 format!("if condition evaluated to non-boolean datum: {:?}", d).into(),
1214 )),
1215 },
1216 }
1217 }
1218
1219 fn could_error(&self) -> bool {
1220 match self {
1221 MirScalarExpr::Column(_col, _name) => false,
1222 MirScalarExpr::Literal(row, ..) => row.is_err(),
1223 MirScalarExpr::CallUnmaterializable(_) => true,
1224 MirScalarExpr::CallUnary { func, expr } => func.could_error() || expr.could_error(),
1225 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1226 func.could_error() || expr1.could_error() || expr2.could_error()
1227 }
1228 MirScalarExpr::CallVariadic { func, exprs } => {
1229 func.could_error() || exprs.iter().any(|e| e.could_error())
1230 }
1231 MirScalarExpr::If { cond, then, els } => {
1232 cond.could_error() || then.could_error() || els.could_error()
1233 }
1234 }
1235 }
1236}
1237
1238impl Columns for MirScalarExpr {
1239 fn column(c: usize) -> Self {
1240 MirScalarExpr::column(c)
1241 }
1242
1243 fn is_column(&self) -> bool {
1244 matches!(self, MirScalarExpr::Column(_col, _name))
1245 }
1246
1247 fn as_column(&self) -> Option<usize> {
1248 if let MirScalarExpr::Column(c, _) = self {
1249 Some(*c)
1250 } else {
1251 None
1252 }
1253 }
1254
1255 fn as_column_mut(&mut self) -> Option<&mut usize> {
1256 if let MirScalarExpr::Column(c, _) = self {
1257 Some(c)
1258 } else {
1259 None
1260 }
1261 }
1262
1263 fn support_into(&self, support: &mut BTreeSet<usize>) {
1264 self.visit_pre(|e| {
1265 if let MirScalarExpr::Column(i, _) = e {
1266 support.insert(*i);
1267 }
1268 });
1269 }
1270
1271 fn visit_columns<F>(&mut self, mut action: F)
1272 where
1273 F: FnMut(&mut usize),
1274 {
1275 self.visit_pre_mut(|e| {
1276 if let MirScalarExpr::Column(col, _) = e {
1277 action(col);
1278 }
1279 });
1280 }
1281}
1282
1283impl VisitChildren<Self> for MirScalarExpr {
1284 fn visit_children<F>(&self, mut f: F)
1285 where
1286 F: FnMut(&Self),
1287 {
1288 use MirScalarExpr::*;
1289 match self {
1290 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1291 CallUnary { expr, .. } => {
1292 f(expr);
1293 }
1294 CallBinary { expr1, expr2, .. } => {
1295 f(expr1);
1296 f(expr2);
1297 }
1298 CallVariadic { exprs, .. } => {
1299 for expr in exprs {
1300 f(expr);
1301 }
1302 }
1303 If { cond, then, els } => {
1304 f(cond);
1305 f(then);
1306 f(els);
1307 }
1308 }
1309 }
1310
1311 fn visit_mut_children<F>(&mut self, mut f: F)
1312 where
1313 F: FnMut(&mut Self),
1314 {
1315 use MirScalarExpr::*;
1316 match self {
1317 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1318 CallUnary { expr, .. } => {
1319 f(expr);
1320 }
1321 CallBinary { expr1, expr2, .. } => {
1322 f(expr1);
1323 f(expr2);
1324 }
1325 CallVariadic { exprs, .. } => {
1326 for expr in exprs {
1327 f(expr);
1328 }
1329 }
1330 If { cond, then, els } => {
1331 f(cond);
1332 f(then);
1333 f(els);
1334 }
1335 }
1336 }
1337
1338 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
1339 where
1340 F: FnMut(&Self) -> Result<(), E>,
1341 {
1342 use MirScalarExpr::*;
1343 match self {
1344 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1345 CallUnary { expr, .. } => {
1346 f(expr)?;
1347 }
1348 CallBinary { expr1, expr2, .. } => {
1349 f(expr1)?;
1350 f(expr2)?;
1351 }
1352 CallVariadic { exprs, .. } => {
1353 for expr in exprs {
1354 f(expr)?;
1355 }
1356 }
1357 If { cond, then, els } => {
1358 f(cond)?;
1359 f(then)?;
1360 f(els)?;
1361 }
1362 }
1363 Ok(())
1364 }
1365
1366 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
1367 where
1368 F: FnMut(&mut Self) -> Result<(), E>,
1369 {
1370 use MirScalarExpr::*;
1371 match self {
1372 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1373 CallUnary { expr, .. } => {
1374 f(expr)?;
1375 }
1376 CallBinary { expr1, expr2, .. } => {
1377 f(expr1)?;
1378 f(expr2)?;
1379 }
1380 CallVariadic { exprs, .. } => {
1381 for expr in exprs {
1382 f(expr)?;
1383 }
1384 }
1385 If { cond, then, els } => {
1386 f(cond)?;
1387 f(then)?;
1388 f(els)?;
1389 }
1390 }
1391 Ok(())
1392 }
1393
1394 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a Self>
1395 where
1396 Self: 'a,
1397 {
1398 self.children()
1399 }
1400
1401 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut Self>
1402 where
1403 Self: 'a,
1404 {
1405 self.children_mut()
1406 }
1407}
1408
1409impl MirScalarExpr {
1410 pub fn could_hit_nonstrict_error_fold(&self) -> bool {
1433 let mut hit = false;
1434 self.visit_pre(|e| {
1435 if let MirScalarExpr::CallVariadic { func, exprs } = e {
1436 let non_strict = matches!(
1437 func,
1438 VariadicFunc::And(_) | VariadicFunc::Or(_) | VariadicFunc::ErrorIfNull(_)
1439 );
1440 if non_strict && exprs.iter().any(|operand| operand.could_error()) {
1441 hit = true;
1442 }
1443 }
1444 });
1445 hit
1446 }
1447
1448 pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self> {
1450 let mut first = None;
1451 let mut second = None;
1452 let mut third = None;
1453 let mut variadic = None;
1454
1455 use MirScalarExpr::*;
1456 match self {
1457 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1458 CallUnary { expr, .. } => {
1459 first = Some(&**expr);
1460 }
1461 CallBinary { expr1, expr2, .. } => {
1462 first = Some(&**expr1);
1463 second = Some(&**expr2);
1464 }
1465 CallVariadic { exprs, .. } => {
1466 variadic = Some(exprs);
1467 }
1468 If { cond, then, els } => {
1469 first = Some(&**cond);
1470 second = Some(&**then);
1471 third = Some(&**els);
1472 }
1473 }
1474
1475 first
1476 .into_iter()
1477 .chain(second)
1478 .chain(third)
1479 .chain(variadic.into_iter().flatten())
1480 }
1481
1482 pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self> {
1484 let mut first = None;
1485 let mut second = None;
1486 let mut third = None;
1487 let mut variadic = None;
1488
1489 use MirScalarExpr::*;
1490 match self {
1491 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1492 CallUnary { expr, .. } => {
1493 first = Some(&mut **expr);
1494 }
1495 CallBinary { expr1, expr2, .. } => {
1496 first = Some(&mut **expr1);
1497 second = Some(&mut **expr2);
1498 }
1499 CallVariadic { exprs, .. } => {
1500 variadic = Some(exprs);
1501 }
1502 If { cond, then, els } => {
1503 first = Some(&mut **cond);
1504 second = Some(&mut **then);
1505 third = Some(&mut **els);
1506 }
1507 }
1508
1509 first
1510 .into_iter()
1511 .chain(second)
1512 .chain(third)
1513 .chain(variadic.into_iter().flatten())
1514 }
1515
1516 pub fn visit_pre<F>(&self, mut f: F)
1518 where
1519 F: FnMut(&Self),
1520 {
1521 let mut worklist = vec![self];
1522 while let Some(e) = worklist.pop() {
1523 f(e);
1524 worklist.extend(e.children().rev());
1525 }
1526 }
1527
1528 pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, mut f: F) {
1530 let mut worklist = vec![self];
1531 while let Some(expr) = worklist.pop() {
1532 f(expr);
1533 worklist.extend(expr.children_mut().rev());
1534 }
1535 }
1536}
1537
1538#[derive(
1545 Eq,
1546 PartialEq,
1547 Ord,
1548 PartialOrd,
1549 Debug,
1550 Clone,
1551 Serialize,
1552 Deserialize,
1553 Hash
1554)]
1555pub struct FilterCharacteristics {
1556 literal_equality: bool,
1559 like: bool,
1561 is_null: bool,
1562 literal_inequality: usize,
1568 any_filter: bool,
1574}
1575
1576impl BitOrAssign for FilterCharacteristics {
1577 fn bitor_assign(&mut self, rhs: Self) {
1578 self.literal_equality |= rhs.literal_equality;
1579 self.like |= rhs.like;
1580 self.is_null |= rhs.is_null;
1581 self.literal_inequality += rhs.literal_inequality;
1582 self.any_filter |= rhs.any_filter;
1583 }
1584}
1585
1586impl FilterCharacteristics {
1587 pub fn none() -> FilterCharacteristics {
1588 FilterCharacteristics {
1589 literal_equality: false,
1590 like: false,
1591 is_null: false,
1592 literal_inequality: 0,
1593 any_filter: false,
1594 }
1595 }
1596
1597 pub fn explain(&self) -> String {
1598 let mut e = "".to_owned();
1599 if self.literal_equality {
1600 e.push_str("e");
1601 }
1602 if self.like {
1603 e.push_str("l");
1604 }
1605 if self.is_null {
1606 e.push_str("n");
1607 }
1608 for _ in 0..self.literal_inequality {
1609 e.push_str("i");
1610 }
1611 if self.any_filter {
1612 e.push_str("f");
1613 }
1614 e
1615 }
1616
1617 pub fn filter_characteristics(
1618 filters: &Vec<MirScalarExpr>,
1619 ) -> Result<FilterCharacteristics, RecursionLimitError> {
1620 let mut literal_equality = false;
1621 let mut like = false;
1622 let mut is_null = false;
1623 let mut literal_inequality = 0;
1624 let mut any_filter = false;
1625 filters.iter().try_for_each(|f| {
1626 let mut literal_inequality_in_current_filter = false;
1627 let mut is_not_null_in_current_filter = false;
1628 f.visit_pre_with_context(
1629 false,
1630 &mut |not_in_parent_chain, expr| {
1631 not_in_parent_chain
1632 || matches!(
1633 expr,
1634 MirScalarExpr::CallUnary {
1635 func: UnaryFunc::Not(func::Not),
1636 ..
1637 }
1638 )
1639 },
1640 &mut |not_in_parent_chain, expr| {
1641 if !not_in_parent_chain {
1642 if expr.any_expr_eq_literal().is_some() {
1643 literal_equality = true;
1644 }
1645 if expr.any_expr_ineq_literal() {
1646 literal_inequality_in_current_filter = true;
1647 }
1648 if matches!(
1649 expr,
1650 MirScalarExpr::CallUnary {
1651 func: UnaryFunc::IsLikeMatch(_),
1652 ..
1653 }
1654 ) {
1655 like = true;
1656 }
1657 };
1658 if matches!(
1659 expr,
1660 MirScalarExpr::CallUnary {
1661 func: UnaryFunc::IsNull(crate::func::IsNull),
1662 ..
1663 }
1664 ) {
1665 if *not_in_parent_chain {
1666 is_not_null_in_current_filter = true;
1667 } else {
1668 is_null = true;
1669 }
1670 }
1671 },
1672 );
1673 if literal_inequality_in_current_filter {
1674 literal_inequality += 1;
1675 }
1676 if !is_not_null_in_current_filter {
1677 any_filter = true;
1679 }
1680 Ok(())
1681 })?;
1682 Ok(FilterCharacteristics {
1683 literal_equality,
1684 like,
1685 is_null,
1686 literal_inequality,
1687 any_filter,
1688 })
1689 }
1690
1691 pub fn add_literal_equality(&mut self) {
1692 self.literal_equality = true;
1693 }
1694
1695 pub fn worst_case_scaling_factor(&self) -> f64 {
1696 let mut factor = 1.0;
1697
1698 if self.literal_equality {
1699 factor *= 0.1;
1700 }
1701
1702 if self.is_null {
1703 factor *= 0.1;
1704 }
1705
1706 if self.literal_inequality >= 2 {
1707 factor *= 0.25;
1708 } else if self.literal_inequality == 1 {
1709 factor *= 0.33;
1710 }
1711
1712 if !(self.literal_equality || self.is_null || self.literal_inequality > 0)
1714 && self.any_filter
1715 {
1716 factor *= 0.9;
1717 }
1718
1719 factor
1720 }
1721}
1722
1723#[derive(
1724 Ord,
1725 PartialOrd,
1726 Copy,
1727 Clone,
1728 Debug,
1729 Eq,
1730 PartialEq,
1731 Serialize,
1732 Deserialize,
1733 Hash
1734)]
1735#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1736pub enum DomainLimit {
1737 None,
1738 Inclusive(i64),
1739 Exclusive(i64),
1740}
1741
1742impl RustType<ProtoDomainLimit> for DomainLimit {
1743 fn into_proto(&self) -> ProtoDomainLimit {
1744 use proto_domain_limit::Kind::*;
1745 let kind = match self {
1746 DomainLimit::None => None(()),
1747 DomainLimit::Inclusive(v) => Inclusive(*v),
1748 DomainLimit::Exclusive(v) => Exclusive(*v),
1749 };
1750 ProtoDomainLimit { kind: Some(kind) }
1751 }
1752
1753 fn from_proto(proto: ProtoDomainLimit) -> Result<Self, TryFromProtoError> {
1754 use proto_domain_limit::Kind::*;
1755 if let Some(kind) = proto.kind {
1756 match kind {
1757 None(()) => Ok(DomainLimit::None),
1758 Inclusive(v) => Ok(DomainLimit::Inclusive(v)),
1759 Exclusive(v) => Ok(DomainLimit::Exclusive(v)),
1760 }
1761 } else {
1762 Err(TryFromProtoError::missing_field("ProtoDomainLimit::kind"))
1763 }
1764 }
1765}
1766
1767#[derive(
1768 Ord,
1769 PartialOrd,
1770 Clone,
1771 Debug,
1772 Eq,
1773 PartialEq,
1774 Serialize,
1775 Deserialize,
1776 Hash
1777)]
1778#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1779pub enum EvalError {
1780 CharacterNotValidForEncoding(i32),
1781 CharacterTooLargeForEncoding(i32),
1782 DateBinOutOfRange(Box<str>),
1783 DivisionByZero,
1784 Unsupported {
1785 feature: Box<str>,
1786 discussion_no: Option<usize>,
1787 },
1788 FloatOverflow,
1789 FloatUnderflow,
1790 NumericFieldOverflow,
1791 Float32OutOfRange(Box<str>),
1792 Float64OutOfRange(Box<str>),
1793 Int16OutOfRange(Box<str>),
1794 Int32OutOfRange(Box<str>),
1795 Int64OutOfRange(Box<str>),
1796 UInt16OutOfRange(Box<str>),
1797 UInt32OutOfRange(Box<str>),
1798 UInt64OutOfRange(Box<str>),
1799 MzTimestampOutOfRange(Box<str>),
1800 MzTimestampStepOverflow,
1801 OidOutOfRange(Box<str>),
1802 IntervalOutOfRange(Box<str>),
1803 TimestampCannotBeNan,
1804 TimestampOutOfRange,
1805 DateOutOfRange,
1806 CharOutOfRange,
1807 IndexOutOfRange {
1808 provided: i32,
1809 valid_end: i32,
1811 },
1812 InvalidBase64Equals,
1813 InvalidBase64Symbol(char),
1814 InvalidBase64EndSequence,
1815 InvalidTimezone(Box<str>),
1816 InvalidTimezoneInterval,
1817 InvalidTimezoneConversion,
1818 InvalidIanaTimezoneId(Box<str>),
1819 InvalidLayer {
1820 max_layer: usize,
1821 val: i64,
1822 },
1823 InvalidArray(InvalidArrayError),
1824 InvalidEncodingName(Box<str>),
1825 InvalidHashAlgorithm(Box<str>),
1826 InvalidByteSequence {
1827 byte_sequence: Box<str>,
1828 encoding_name: Box<str>,
1829 },
1830 InvalidJsonbCast {
1831 from: Box<str>,
1832 to: Box<str>,
1833 },
1834 InvalidRegex(Box<str>),
1835 InvalidRegexFlag(char),
1836 InvalidParameterValue(Box<str>),
1837 InvalidDatePart(Box<str>),
1838 KeyCannotBeNull,
1839 NegSqrt,
1840 NegLimit,
1841 NullCharacterNotPermitted,
1842 UnknownUnits(Box<str>),
1843 UnsupportedUnits(Box<str>, Box<str>),
1844 UnterminatedLikeEscapeSequence,
1845 Parse(ParseError),
1846 ParseHex(ParseHexError),
1847 Internal(Box<str>),
1848 InfinityOutOfDomain(Box<str>),
1849 NegativeOutOfDomain(Box<str>),
1850 ZeroOutOfDomain(Box<str>),
1851 OutOfDomain(DomainLimit, DomainLimit, Box<str>),
1852 ComplexOutOfRange(Box<str>),
1853 MultipleRowsFromSubquery,
1854 NegativeRowsFromSubquery,
1855 Undefined(Box<str>),
1856 LikePatternTooLong,
1857 LikeEscapeTooLong,
1858 StringValueTooLong {
1859 target_type: Box<str>,
1860 length: usize,
1861 },
1862 MultidimensionalArrayRemovalNotSupported,
1863 IncompatibleArrayDimensions {
1864 dims: Option<(usize, usize)>,
1865 },
1866 TypeFromOid(Box<str>),
1867 InvalidRange(InvalidRangeError),
1868 InvalidRoleId(Box<str>),
1869 InvalidPrivileges(Box<str>),
1870 InvalidCatalogJson(Box<str>),
1871 LetRecLimitExceeded(Box<str>),
1872 MultiDimensionalArraySearch,
1873 MustNotBeNull(Box<str>),
1874 InvalidIdentifier {
1875 ident: Box<str>,
1876 detail: Option<Box<str>>,
1877 },
1878 ArrayFillWrongArraySubscripts,
1879 MaxArraySizeExceeded(usize),
1881 DateDiffOverflow {
1882 unit: Box<str>,
1883 a: Box<str>,
1884 b: Box<str>,
1885 },
1886 IfNullError(Box<str>),
1889 LengthTooLarge,
1890 TempStorageBudgetExceeded,
1894 AclArrayNullElement,
1895 MzAclArrayNullElement,
1896 PrettyError(Box<str>),
1897 RedactError(Box<str>),
1898}
1899
1900impl fmt::Display for EvalError {
1901 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1902 match self {
1903 EvalError::CharacterNotValidForEncoding(v) => {
1904 write!(f, "requested character not valid for encoding: {v}")
1905 }
1906 EvalError::CharacterTooLargeForEncoding(v) => {
1907 write!(f, "requested character too large for encoding: {v}")
1908 }
1909 EvalError::DateBinOutOfRange(message) => f.write_str(message),
1910 EvalError::DivisionByZero => f.write_str("division by zero"),
1911 EvalError::Unsupported {
1912 feature,
1913 discussion_no,
1914 } => {
1915 write!(f, "{} not yet supported", feature)?;
1916 if let Some(discussion_no) = discussion_no {
1917 write!(
1918 f,
1919 ", see https://github.com/MaterializeInc/materialize/discussions/{} for more details",
1920 discussion_no
1921 )?;
1922 }
1923 Ok(())
1924 }
1925 EvalError::FloatOverflow => f.write_str("value out of range: overflow"),
1926 EvalError::FloatUnderflow => f.write_str("value out of range: underflow"),
1927 EvalError::NumericFieldOverflow => f.write_str("numeric field overflow"),
1928 EvalError::Float32OutOfRange(val) => write!(f, "{} real out of range", val.quoted()),
1929 EvalError::Float64OutOfRange(val) => {
1930 write!(f, "{} double precision out of range", val.quoted())
1931 }
1932 EvalError::Int16OutOfRange(val) => write!(f, "{} smallint out of range", val.quoted()),
1933 EvalError::Int32OutOfRange(val) => write!(f, "{} integer out of range", val.quoted()),
1934 EvalError::Int64OutOfRange(val) => write!(f, "{} bigint out of range", val.quoted()),
1935 EvalError::UInt16OutOfRange(val) => write!(f, "{} uint2 out of range", val.quoted()),
1936 EvalError::UInt32OutOfRange(val) => write!(f, "{} uint4 out of range", val.quoted()),
1937 EvalError::UInt64OutOfRange(val) => write!(f, "{} uint8 out of range", val.quoted()),
1938 EvalError::MzTimestampOutOfRange(val) => {
1939 write!(f, "{} mz_timestamp out of range", val.quoted())
1940 }
1941 EvalError::MzTimestampStepOverflow => f.write_str("step mz_timestamp overflow"),
1942 EvalError::OidOutOfRange(val) => write!(f, "{} OID out of range", val.quoted()),
1943 EvalError::IntervalOutOfRange(val) => {
1944 write!(f, "{} interval out of range", val.quoted())
1945 }
1946 EvalError::TimestampCannotBeNan => f.write_str("timestamp cannot be NaN"),
1947 EvalError::TimestampOutOfRange => f.write_str("timestamp out of range"),
1948 EvalError::DateOutOfRange => f.write_str("date out of range"),
1949 EvalError::CharOutOfRange => f.write_str("\"char\" out of range"),
1950 EvalError::IndexOutOfRange {
1951 provided,
1952 valid_end,
1953 } => write!(f, "index {provided} out of valid range, 0..{valid_end}",),
1954 EvalError::InvalidBase64Equals => {
1955 f.write_str("unexpected \"=\" while decoding base64 sequence")
1956 }
1957 EvalError::InvalidBase64Symbol(c) => write!(
1958 f,
1959 "invalid symbol \"{}\" found while decoding base64 sequence",
1960 c.escape_default()
1961 ),
1962 EvalError::InvalidBase64EndSequence => f.write_str("invalid base64 end sequence"),
1963 EvalError::InvalidJsonbCast { from, to } => {
1964 write!(f, "cannot cast jsonb {} to type {}", from, to)
1965 }
1966 EvalError::InvalidTimezone(tz) => write!(f, "invalid time zone '{}'", tz),
1967 EvalError::InvalidTimezoneInterval => {
1968 f.write_str("timezone interval must not contain months or years")
1969 }
1970 EvalError::InvalidTimezoneConversion => f.write_str("invalid timezone conversion"),
1971 EvalError::InvalidIanaTimezoneId(tz) => {
1972 write!(f, "invalid IANA Time Zone Database identifier: '{}'", tz)
1973 }
1974 EvalError::InvalidLayer { max_layer, val } => write!(
1975 f,
1976 "invalid layer: {}; must use value within [1, {}]",
1977 val, max_layer
1978 ),
1979 EvalError::InvalidArray(e) => e.fmt(f),
1980 EvalError::InvalidEncodingName(name) => write!(f, "invalid encoding name '{}'", name),
1981 EvalError::InvalidHashAlgorithm(alg) => write!(f, "invalid hash algorithm '{}'", alg),
1982 EvalError::InvalidByteSequence {
1983 byte_sequence,
1984 encoding_name,
1985 } => write!(
1986 f,
1987 "invalid byte sequence '{}' for encoding '{}'",
1988 byte_sequence, encoding_name
1989 ),
1990 EvalError::InvalidDatePart(part) => write!(f, "invalid datepart {}", part.quoted()),
1991 EvalError::KeyCannotBeNull => f.write_str("key cannot be null"),
1992 EvalError::NegSqrt => f.write_str("cannot take square root of a negative number"),
1993 EvalError::NegLimit => f.write_str("LIMIT must not be negative"),
1994 EvalError::NullCharacterNotPermitted => f.write_str("null character not permitted"),
1995 EvalError::InvalidRegex(e) => write!(f, "invalid regular expression: {}", e),
1996 EvalError::InvalidRegexFlag(c) => write!(f, "invalid regular expression flag: {}", c),
1997 EvalError::InvalidParameterValue(s) => f.write_str(s),
1998 EvalError::UnknownUnits(units) => write!(f, "unit '{}' not recognized", units),
1999 EvalError::UnsupportedUnits(units, typ) => {
2000 write!(f, "unit '{}' not supported for type {}", units, typ)
2001 }
2002 EvalError::UnterminatedLikeEscapeSequence => {
2003 f.write_str("unterminated escape sequence in LIKE")
2004 }
2005 EvalError::Parse(e) => e.fmt(f),
2006 EvalError::PrettyError(e) => e.fmt(f),
2007 EvalError::RedactError(e) => e.fmt(f),
2008 EvalError::ParseHex(e) => e.fmt(f),
2009 EvalError::Internal(s) => write!(f, "internal error: {}", s),
2010 EvalError::InfinityOutOfDomain(s) => {
2011 write!(f, "function {} is only defined for finite arguments", s)
2012 }
2013 EvalError::NegativeOutOfDomain(s) => {
2014 write!(f, "function {} is not defined for negative numbers", s)
2015 }
2016 EvalError::ZeroOutOfDomain(s) => {
2017 write!(f, "function {} is not defined for zero", s)
2018 }
2019 EvalError::OutOfDomain(lower, upper, s) => {
2020 use DomainLimit::*;
2021 write!(f, "function {s} is defined for numbers ")?;
2022 match (lower, upper) {
2023 (Inclusive(n), None) => write!(f, "greater than or equal to {n}"),
2024 (Exclusive(n), None) => write!(f, "greater than {n}"),
2025 (None, Inclusive(n)) => write!(f, "less than or equal to {n}"),
2026 (None, Exclusive(n)) => write!(f, "less than {n}"),
2027 (Inclusive(lo), Inclusive(hi)) => write!(f, "between {lo} and {hi} inclusive"),
2028 (Exclusive(lo), Exclusive(hi)) => write!(f, "between {lo} and {hi} exclusive"),
2029 (Inclusive(lo), Exclusive(hi)) => {
2030 write!(f, "between {lo} inclusive and {hi} exclusive")
2031 }
2032 (Exclusive(lo), Inclusive(hi)) => {
2033 write!(f, "between {lo} exclusive and {hi} inclusive")
2034 }
2035 (None, None) => write!(f, "in an unspecified range"),
2042 }
2043 }
2044 EvalError::ComplexOutOfRange(s) => {
2045 write!(f, "function {} cannot return complex numbers", s)
2046 }
2047 EvalError::MultipleRowsFromSubquery => {
2048 write!(f, "more than one record produced in subquery")
2049 }
2050 EvalError::NegativeRowsFromSubquery => {
2051 write!(f, "negative number of rows produced in subquery")
2052 }
2053 EvalError::Undefined(s) => {
2054 write!(f, "{} is undefined", s)
2055 }
2056 EvalError::LikePatternTooLong => {
2057 write!(f, "LIKE pattern exceeds maximum length")
2058 }
2059 EvalError::LikeEscapeTooLong => {
2060 write!(f, "invalid escape string")
2061 }
2062 EvalError::StringValueTooLong {
2063 target_type,
2064 length,
2065 } => {
2066 write!(f, "value too long for type {}({})", target_type, length)
2067 }
2068 EvalError::MultidimensionalArrayRemovalNotSupported => {
2069 write!(
2070 f,
2071 "removing elements from multidimensional arrays is not supported"
2072 )
2073 }
2074 EvalError::IncompatibleArrayDimensions { dims: _ } => {
2075 write!(f, "cannot concatenate incompatible arrays")
2076 }
2077 EvalError::TypeFromOid(msg) => write!(f, "{msg}"),
2078 EvalError::InvalidRange(e) => e.fmt(f),
2079 EvalError::InvalidRoleId(msg) => write!(f, "{msg}"),
2080 EvalError::InvalidPrivileges(privilege) => {
2081 write!(f, "unrecognized privilege type: {privilege}")
2082 }
2083 EvalError::InvalidCatalogJson(msg) => {
2084 write!(f, "invalid catalog JSON: {msg}")
2085 }
2086 EvalError::LetRecLimitExceeded(max_iters) => {
2087 write!(
2088 f,
2089 "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.)",
2090 max_iters
2091 )
2092 }
2093 EvalError::MultiDimensionalArraySearch => write!(
2094 f,
2095 "searching for elements in multidimensional arrays is not supported"
2096 ),
2097 EvalError::MustNotBeNull(v) => write!(f, "{v} must not be null"),
2098 EvalError::InvalidIdentifier { ident, .. } => {
2099 write!(f, "string is not a valid identifier: {}", ident.quoted())
2100 }
2101 EvalError::ArrayFillWrongArraySubscripts => {
2102 f.write_str("wrong number of array subscripts")
2103 }
2104 EvalError::MaxArraySizeExceeded(max_size) => {
2105 write!(
2106 f,
2107 "array size exceeds the maximum allowed ({max_size} bytes)"
2108 )
2109 }
2110 EvalError::DateDiffOverflow { unit, a, b } => {
2111 write!(f, "datediff overflow, {unit} of {a}, {b}")
2112 }
2113 EvalError::IfNullError(s) => f.write_str(s),
2114 EvalError::LengthTooLarge => write!(f, "requested length too large"),
2115 EvalError::TempStorageBudgetExceeded => {
2116 write!(f, "expression exceeded its temporary storage limit")
2117 }
2118 EvalError::AclArrayNullElement => write!(f, "ACL arrays must not contain null values"),
2119 EvalError::MzAclArrayNullElement => {
2120 write!(f, "MZ_ACL arrays must not contain null values")
2121 }
2122 }
2123 }
2124}
2125
2126impl EvalError {
2127 pub fn detail(&self) -> Option<String> {
2128 match self {
2129 EvalError::IncompatibleArrayDimensions { dims: None } => Some(
2130 "Arrays with differing dimensions are not compatible for concatenation.".into(),
2131 ),
2132 EvalError::IncompatibleArrayDimensions {
2133 dims: Some((a_dims, b_dims)),
2134 } => Some(format!(
2135 "Arrays of {} and {} dimensions are not compatible for concatenation.",
2136 a_dims, b_dims
2137 )),
2138 EvalError::InvalidIdentifier { detail, .. } => detail.as_deref().map(Into::into),
2139 EvalError::ArrayFillWrongArraySubscripts => {
2140 Some("Low bound array has different size than dimensions array.".into())
2141 }
2142 _ => None,
2143 }
2144 }
2145
2146 pub fn hint(&self) -> Option<String> {
2147 match self {
2148 EvalError::InvalidBase64EndSequence => Some(
2149 "Input data is missing padding, is truncated, or is otherwise corrupted.".into(),
2150 ),
2151 EvalError::LikeEscapeTooLong => {
2152 Some("Escape string must be empty or one character.".into())
2153 }
2154 EvalError::MzTimestampOutOfRange(_) => Some(
2155 "Integer, numeric, and text casts to mz_timestamp must be in the form of whole \
2156 milliseconds since the Unix epoch. Values with fractional parts cannot be \
2157 converted to mz_timestamp."
2158 .into(),
2159 ),
2160 _ => None,
2161 }
2162 }
2163}
2164
2165impl std::error::Error for EvalError {}
2166
2167impl From<ParseError> for EvalError {
2168 fn from(e: ParseError) -> EvalError {
2169 EvalError::Parse(e)
2170 }
2171}
2172
2173impl From<ParseHexError> for EvalError {
2174 fn from(e: ParseHexError) -> EvalError {
2175 EvalError::ParseHex(e)
2176 }
2177}
2178
2179impl From<InvalidArrayError> for EvalError {
2180 fn from(e: InvalidArrayError) -> EvalError {
2181 EvalError::InvalidArray(e)
2182 }
2183}
2184
2185impl From<RegexCompilationError> for EvalError {
2186 fn from(e: RegexCompilationError) -> EvalError {
2187 EvalError::InvalidRegex(e.to_string().into())
2188 }
2189}
2190
2191impl From<TypeFromOidError> for EvalError {
2192 fn from(e: TypeFromOidError) -> EvalError {
2193 EvalError::TypeFromOid(e.to_string().into())
2194 }
2195}
2196
2197impl From<DateError> for EvalError {
2198 fn from(e: DateError) -> EvalError {
2199 match e {
2200 DateError::OutOfRange => EvalError::DateOutOfRange,
2201 }
2202 }
2203}
2204
2205impl From<TimestampError> for EvalError {
2206 fn from(e: TimestampError) -> EvalError {
2207 match e {
2208 TimestampError::OutOfRange => EvalError::TimestampOutOfRange,
2209 }
2210 }
2211}
2212
2213impl From<InvalidRangeError> for EvalError {
2214 fn from(e: InvalidRangeError) -> EvalError {
2215 EvalError::InvalidRange(e)
2216 }
2217}
2218
2219impl RustType<ProtoEvalError> for EvalError {
2220 fn into_proto(&self) -> ProtoEvalError {
2221 use proto_eval_error::Kind::*;
2222 use proto_eval_error::*;
2223 let kind = match self {
2224 EvalError::CharacterNotValidForEncoding(v) => CharacterNotValidForEncoding(*v),
2225 EvalError::CharacterTooLargeForEncoding(v) => CharacterTooLargeForEncoding(*v),
2226 EvalError::DateBinOutOfRange(v) => DateBinOutOfRange(v.into_proto()),
2227 EvalError::DivisionByZero => DivisionByZero(()),
2228 EvalError::Unsupported {
2229 feature,
2230 discussion_no,
2231 } => Unsupported(ProtoUnsupported {
2232 feature: feature.into_proto(),
2233 discussion_no: discussion_no.into_proto(),
2234 }),
2235 EvalError::FloatOverflow => FloatOverflow(()),
2236 EvalError::FloatUnderflow => FloatUnderflow(()),
2237 EvalError::NumericFieldOverflow => NumericFieldOverflow(()),
2238 EvalError::Float32OutOfRange(val) => Float32OutOfRange(ProtoValueOutOfRange {
2239 value: val.to_string(),
2240 }),
2241 EvalError::Float64OutOfRange(val) => Float64OutOfRange(ProtoValueOutOfRange {
2242 value: val.to_string(),
2243 }),
2244 EvalError::Int16OutOfRange(val) => Int16OutOfRange(ProtoValueOutOfRange {
2245 value: val.to_string(),
2246 }),
2247 EvalError::Int32OutOfRange(val) => Int32OutOfRange(ProtoValueOutOfRange {
2248 value: val.to_string(),
2249 }),
2250 EvalError::Int64OutOfRange(val) => Int64OutOfRange(ProtoValueOutOfRange {
2251 value: val.to_string(),
2252 }),
2253 EvalError::UInt16OutOfRange(val) => Uint16OutOfRange(ProtoValueOutOfRange {
2254 value: val.to_string(),
2255 }),
2256 EvalError::UInt32OutOfRange(val) => Uint32OutOfRange(ProtoValueOutOfRange {
2257 value: val.to_string(),
2258 }),
2259 EvalError::UInt64OutOfRange(val) => Uint64OutOfRange(ProtoValueOutOfRange {
2260 value: val.to_string(),
2261 }),
2262 EvalError::MzTimestampOutOfRange(val) => MzTimestampOutOfRange(ProtoValueOutOfRange {
2263 value: val.to_string(),
2264 }),
2265 EvalError::MzTimestampStepOverflow => MzTimestampStepOverflow(()),
2266 EvalError::OidOutOfRange(val) => OidOutOfRange(ProtoValueOutOfRange {
2267 value: val.to_string(),
2268 }),
2269 EvalError::IntervalOutOfRange(val) => IntervalOutOfRange(ProtoValueOutOfRange {
2270 value: val.to_string(),
2271 }),
2272 EvalError::TimestampCannotBeNan => TimestampCannotBeNan(()),
2273 EvalError::TimestampOutOfRange => TimestampOutOfRange(()),
2274 EvalError::DateOutOfRange => DateOutOfRange(()),
2275 EvalError::CharOutOfRange => CharOutOfRange(()),
2276 EvalError::IndexOutOfRange {
2277 provided,
2278 valid_end,
2279 } => IndexOutOfRange(ProtoIndexOutOfRange {
2280 provided: *provided,
2281 valid_end: *valid_end,
2282 }),
2283 EvalError::InvalidBase64Equals => InvalidBase64Equals(()),
2284 EvalError::InvalidBase64Symbol(sym) => InvalidBase64Symbol(sym.into_proto()),
2285 EvalError::InvalidBase64EndSequence => InvalidBase64EndSequence(()),
2286 EvalError::InvalidTimezone(tz) => InvalidTimezone(tz.into_proto()),
2287 EvalError::InvalidTimezoneInterval => InvalidTimezoneInterval(()),
2288 EvalError::InvalidTimezoneConversion => InvalidTimezoneConversion(()),
2289 EvalError::InvalidLayer { max_layer, val } => InvalidLayer(ProtoInvalidLayer {
2290 max_layer: max_layer.into_proto(),
2291 val: *val,
2292 }),
2293 EvalError::InvalidArray(error) => InvalidArray(error.into_proto()),
2294 EvalError::InvalidEncodingName(v) => InvalidEncodingName(v.into_proto()),
2295 EvalError::InvalidHashAlgorithm(v) => InvalidHashAlgorithm(v.into_proto()),
2296 EvalError::InvalidByteSequence {
2297 byte_sequence,
2298 encoding_name,
2299 } => InvalidByteSequence(ProtoInvalidByteSequence {
2300 byte_sequence: byte_sequence.into_proto(),
2301 encoding_name: encoding_name.into_proto(),
2302 }),
2303 EvalError::InvalidJsonbCast { from, to } => InvalidJsonbCast(ProtoInvalidJsonbCast {
2304 from: from.into_proto(),
2305 to: to.into_proto(),
2306 }),
2307 EvalError::InvalidRegex(v) => InvalidRegex(v.into_proto()),
2308 EvalError::InvalidRegexFlag(v) => InvalidRegexFlag(v.into_proto()),
2309 EvalError::InvalidParameterValue(v) => InvalidParameterValue(v.into_proto()),
2310 EvalError::InvalidDatePart(part) => InvalidDatePart(part.into_proto()),
2311 EvalError::KeyCannotBeNull => KeyCannotBeNull(()),
2312 EvalError::NegSqrt => NegSqrt(()),
2313 EvalError::NegLimit => NegLimit(()),
2314 EvalError::NullCharacterNotPermitted => NullCharacterNotPermitted(()),
2315 EvalError::UnknownUnits(v) => UnknownUnits(v.into_proto()),
2316 EvalError::UnsupportedUnits(units, typ) => UnsupportedUnits(ProtoUnsupportedUnits {
2317 units: units.into_proto(),
2318 typ: typ.into_proto(),
2319 }),
2320 EvalError::UnterminatedLikeEscapeSequence => UnterminatedLikeEscapeSequence(()),
2321 EvalError::Parse(error) => Parse(error.into_proto()),
2322 EvalError::PrettyError(error) => PrettyError(error.into_proto()),
2323 EvalError::RedactError(error) => RedactError(error.into_proto()),
2324 EvalError::ParseHex(error) => ParseHex(error.into_proto()),
2325 EvalError::Internal(v) => Internal(v.into_proto()),
2326 EvalError::InfinityOutOfDomain(v) => InfinityOutOfDomain(v.into_proto()),
2327 EvalError::NegativeOutOfDomain(v) => NegativeOutOfDomain(v.into_proto()),
2328 EvalError::ZeroOutOfDomain(v) => ZeroOutOfDomain(v.into_proto()),
2329 EvalError::OutOfDomain(lower, upper, id) => OutOfDomain(ProtoOutOfDomain {
2330 lower: Some(lower.into_proto()),
2331 upper: Some(upper.into_proto()),
2332 id: id.into_proto(),
2333 }),
2334 EvalError::ComplexOutOfRange(v) => ComplexOutOfRange(v.into_proto()),
2335 EvalError::MultipleRowsFromSubquery => MultipleRowsFromSubquery(()),
2336 EvalError::NegativeRowsFromSubquery => NegativeRowsFromSubquery(()),
2337 EvalError::Undefined(v) => Undefined(v.into_proto()),
2338 EvalError::LikePatternTooLong => LikePatternTooLong(()),
2339 EvalError::LikeEscapeTooLong => LikeEscapeTooLong(()),
2340 EvalError::StringValueTooLong {
2341 target_type,
2342 length,
2343 } => StringValueTooLong(ProtoStringValueTooLong {
2344 target_type: target_type.into_proto(),
2345 length: length.into_proto(),
2346 }),
2347 EvalError::MultidimensionalArrayRemovalNotSupported => {
2348 MultidimensionalArrayRemovalNotSupported(())
2349 }
2350 EvalError::IncompatibleArrayDimensions { dims } => {
2351 IncompatibleArrayDimensions(ProtoIncompatibleArrayDimensions {
2352 dims: dims.into_proto(),
2353 })
2354 }
2355 EvalError::TypeFromOid(v) => TypeFromOid(v.into_proto()),
2356 EvalError::InvalidRange(error) => InvalidRange(error.into_proto()),
2357 EvalError::InvalidRoleId(v) => InvalidRoleId(v.into_proto()),
2358 EvalError::InvalidPrivileges(v) => InvalidPrivileges(v.into_proto()),
2359 EvalError::InvalidCatalogJson(v) => InvalidCatalogJson(v.into_proto()),
2360 EvalError::LetRecLimitExceeded(v) => WmrRecursionLimitExceeded(v.into_proto()),
2361 EvalError::MultiDimensionalArraySearch => MultiDimensionalArraySearch(()),
2362 EvalError::MustNotBeNull(v) => MustNotBeNull(v.into_proto()),
2363 EvalError::InvalidIdentifier { ident, detail } => {
2364 InvalidIdentifier(ProtoInvalidIdentifier {
2365 ident: ident.into_proto(),
2366 detail: detail.into_proto(),
2367 })
2368 }
2369 EvalError::ArrayFillWrongArraySubscripts => ArrayFillWrongArraySubscripts(()),
2370 EvalError::MaxArraySizeExceeded(max_size) => {
2371 MaxArraySizeExceeded(u64::cast_from(*max_size))
2372 }
2373 EvalError::DateDiffOverflow { unit, a, b } => DateDiffOverflow(ProtoDateDiffOverflow {
2374 unit: unit.into_proto(),
2375 a: a.into_proto(),
2376 b: b.into_proto(),
2377 }),
2378 EvalError::IfNullError(s) => IfNullError(s.into_proto()),
2379 EvalError::LengthTooLarge => LengthTooLarge(()),
2380 EvalError::TempStorageBudgetExceeded => TempStorageBudgetExceeded(()),
2381 EvalError::AclArrayNullElement => AclArrayNullElement(()),
2382 EvalError::MzAclArrayNullElement => MzAclArrayNullElement(()),
2383 EvalError::InvalidIanaTimezoneId(s) => InvalidIanaTimezoneId(s.into_proto()),
2384 };
2385 ProtoEvalError { kind: Some(kind) }
2386 }
2387
2388 fn from_proto(proto: ProtoEvalError) -> Result<Self, TryFromProtoError> {
2389 use proto_eval_error::Kind::*;
2390 match proto.kind {
2391 Some(kind) => match kind {
2392 CharacterNotValidForEncoding(v) => Ok(EvalError::CharacterNotValidForEncoding(v)),
2393 CharacterTooLargeForEncoding(v) => Ok(EvalError::CharacterTooLargeForEncoding(v)),
2394 DateBinOutOfRange(v) => Ok(EvalError::DateBinOutOfRange(v.into())),
2395 DivisionByZero(()) => Ok(EvalError::DivisionByZero),
2396 Unsupported(v) => Ok(EvalError::Unsupported {
2397 feature: v.feature.into(),
2398 discussion_no: v.discussion_no.into_rust()?,
2399 }),
2400 FloatOverflow(()) => Ok(EvalError::FloatOverflow),
2401 FloatUnderflow(()) => Ok(EvalError::FloatUnderflow),
2402 NumericFieldOverflow(()) => Ok(EvalError::NumericFieldOverflow),
2403 Float32OutOfRange(val) => Ok(EvalError::Float32OutOfRange(val.value.into())),
2404 Float64OutOfRange(val) => Ok(EvalError::Float64OutOfRange(val.value.into())),
2405 Int16OutOfRange(val) => Ok(EvalError::Int16OutOfRange(val.value.into())),
2406 Int32OutOfRange(val) => Ok(EvalError::Int32OutOfRange(val.value.into())),
2407 Int64OutOfRange(val) => Ok(EvalError::Int64OutOfRange(val.value.into())),
2408 Uint16OutOfRange(val) => Ok(EvalError::UInt16OutOfRange(val.value.into())),
2409 Uint32OutOfRange(val) => Ok(EvalError::UInt32OutOfRange(val.value.into())),
2410 Uint64OutOfRange(val) => Ok(EvalError::UInt64OutOfRange(val.value.into())),
2411 MzTimestampOutOfRange(val) => {
2412 Ok(EvalError::MzTimestampOutOfRange(val.value.into()))
2413 }
2414 MzTimestampStepOverflow(()) => Ok(EvalError::MzTimestampStepOverflow),
2415 OidOutOfRange(val) => Ok(EvalError::OidOutOfRange(val.value.into())),
2416 IntervalOutOfRange(val) => Ok(EvalError::IntervalOutOfRange(val.value.into())),
2417 TimestampCannotBeNan(()) => Ok(EvalError::TimestampCannotBeNan),
2418 TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange),
2419 DateOutOfRange(()) => Ok(EvalError::DateOutOfRange),
2420 CharOutOfRange(()) => Ok(EvalError::CharOutOfRange),
2421 IndexOutOfRange(v) => Ok(EvalError::IndexOutOfRange {
2422 provided: v.provided,
2423 valid_end: v.valid_end,
2424 }),
2425 InvalidBase64Equals(()) => Ok(EvalError::InvalidBase64Equals),
2426 InvalidBase64Symbol(v) => char::from_proto(v).map(EvalError::InvalidBase64Symbol),
2427 InvalidBase64EndSequence(()) => Ok(EvalError::InvalidBase64EndSequence),
2428 InvalidTimezone(v) => Ok(EvalError::InvalidTimezone(v.into())),
2429 InvalidTimezoneInterval(()) => Ok(EvalError::InvalidTimezoneInterval),
2430 InvalidTimezoneConversion(()) => Ok(EvalError::InvalidTimezoneConversion),
2431 InvalidLayer(v) => Ok(EvalError::InvalidLayer {
2432 max_layer: usize::from_proto(v.max_layer)?,
2433 val: v.val,
2434 }),
2435 InvalidArray(error) => Ok(EvalError::InvalidArray(error.into_rust()?)),
2436 InvalidEncodingName(v) => Ok(EvalError::InvalidEncodingName(v.into())),
2437 InvalidHashAlgorithm(v) => Ok(EvalError::InvalidHashAlgorithm(v.into())),
2438 InvalidByteSequence(v) => Ok(EvalError::InvalidByteSequence {
2439 byte_sequence: v.byte_sequence.into(),
2440 encoding_name: v.encoding_name.into(),
2441 }),
2442 InvalidJsonbCast(v) => Ok(EvalError::InvalidJsonbCast {
2443 from: v.from.into(),
2444 to: v.to.into(),
2445 }),
2446 InvalidRegex(v) => Ok(EvalError::InvalidRegex(v.into())),
2447 InvalidRegexFlag(v) => Ok(EvalError::InvalidRegexFlag(char::from_proto(v)?)),
2448 InvalidParameterValue(v) => Ok(EvalError::InvalidParameterValue(v.into())),
2449 InvalidDatePart(part) => Ok(EvalError::InvalidDatePart(part.into())),
2450 KeyCannotBeNull(()) => Ok(EvalError::KeyCannotBeNull),
2451 NegSqrt(()) => Ok(EvalError::NegSqrt),
2452 NegLimit(()) => Ok(EvalError::NegLimit),
2453 NullCharacterNotPermitted(()) => Ok(EvalError::NullCharacterNotPermitted),
2454 UnknownUnits(v) => Ok(EvalError::UnknownUnits(v.into())),
2455 UnsupportedUnits(v) => {
2456 Ok(EvalError::UnsupportedUnits(v.units.into(), v.typ.into()))
2457 }
2458 UnterminatedLikeEscapeSequence(()) => Ok(EvalError::UnterminatedLikeEscapeSequence),
2459 Parse(error) => Ok(EvalError::Parse(error.into_rust()?)),
2460 ParseHex(error) => Ok(EvalError::ParseHex(error.into_rust()?)),
2461 Internal(v) => Ok(EvalError::Internal(v.into())),
2462 InfinityOutOfDomain(v) => Ok(EvalError::InfinityOutOfDomain(v.into())),
2463 NegativeOutOfDomain(v) => Ok(EvalError::NegativeOutOfDomain(v.into())),
2464 ZeroOutOfDomain(v) => Ok(EvalError::ZeroOutOfDomain(v.into())),
2465 OutOfDomain(v) => Ok(EvalError::OutOfDomain(
2466 v.lower.into_rust_if_some("ProtoDomainLimit::lower")?,
2467 v.upper.into_rust_if_some("ProtoDomainLimit::upper")?,
2468 v.id.into(),
2469 )),
2470 ComplexOutOfRange(v) => Ok(EvalError::ComplexOutOfRange(v.into())),
2471 MultipleRowsFromSubquery(()) => Ok(EvalError::MultipleRowsFromSubquery),
2472 NegativeRowsFromSubquery(()) => Ok(EvalError::NegativeRowsFromSubquery),
2473 Undefined(v) => Ok(EvalError::Undefined(v.into())),
2474 LikePatternTooLong(()) => Ok(EvalError::LikePatternTooLong),
2475 LikeEscapeTooLong(()) => Ok(EvalError::LikeEscapeTooLong),
2476 StringValueTooLong(v) => Ok(EvalError::StringValueTooLong {
2477 target_type: v.target_type.into(),
2478 length: usize::from_proto(v.length)?,
2479 }),
2480 MultidimensionalArrayRemovalNotSupported(()) => {
2481 Ok(EvalError::MultidimensionalArrayRemovalNotSupported)
2482 }
2483 IncompatibleArrayDimensions(v) => Ok(EvalError::IncompatibleArrayDimensions {
2484 dims: v.dims.into_rust()?,
2485 }),
2486 TypeFromOid(v) => Ok(EvalError::TypeFromOid(v.into())),
2487 InvalidRange(e) => Ok(EvalError::InvalidRange(e.into_rust()?)),
2488 InvalidRoleId(v) => Ok(EvalError::InvalidRoleId(v.into())),
2489 InvalidPrivileges(v) => Ok(EvalError::InvalidPrivileges(v.into())),
2490 InvalidCatalogJson(v) => Ok(EvalError::InvalidCatalogJson(v.into())),
2491 WmrRecursionLimitExceeded(v) => Ok(EvalError::LetRecLimitExceeded(v.into())),
2492 MultiDimensionalArraySearch(()) => Ok(EvalError::MultiDimensionalArraySearch),
2493 MustNotBeNull(v) => Ok(EvalError::MustNotBeNull(v.into())),
2494 InvalidIdentifier(v) => Ok(EvalError::InvalidIdentifier {
2495 ident: v.ident.into(),
2496 detail: v.detail.into_rust()?,
2497 }),
2498 ArrayFillWrongArraySubscripts(()) => Ok(EvalError::ArrayFillWrongArraySubscripts),
2499 MaxArraySizeExceeded(max_size) => {
2500 Ok(EvalError::MaxArraySizeExceeded(usize::cast_from(max_size)))
2501 }
2502 DateDiffOverflow(v) => Ok(EvalError::DateDiffOverflow {
2503 unit: v.unit.into(),
2504 a: v.a.into(),
2505 b: v.b.into(),
2506 }),
2507 IfNullError(v) => Ok(EvalError::IfNullError(v.into())),
2508 LengthTooLarge(()) => Ok(EvalError::LengthTooLarge),
2509 TempStorageBudgetExceeded(()) => Ok(EvalError::TempStorageBudgetExceeded),
2510 AclArrayNullElement(()) => Ok(EvalError::AclArrayNullElement),
2511 MzAclArrayNullElement(()) => Ok(EvalError::MzAclArrayNullElement),
2512 InvalidIanaTimezoneId(s) => Ok(EvalError::InvalidIanaTimezoneId(s.into())),
2513 PrettyError(s) => Ok(EvalError::PrettyError(s.into())),
2514 RedactError(s) => Ok(EvalError::RedactError(s.into())),
2515 },
2516 None => Err(TryFromProtoError::missing_field("ProtoEvalError::kind")),
2517 }
2518 }
2519}
2520
2521impl RustType<ProtoDims> for (usize, usize) {
2522 fn into_proto(&self) -> ProtoDims {
2523 ProtoDims {
2524 f0: self.0.into_proto(),
2525 f1: self.1.into_proto(),
2526 }
2527 }
2528
2529 fn from_proto(proto: ProtoDims) -> Result<Self, TryFromProtoError> {
2530 Ok((proto.f0.into_rust()?, proto.f1.into_rust()?))
2531 }
2532}
2533
2534#[derive(
2548 Clone,
2549 Debug,
2550 Eq,
2551 PartialEq,
2552 Ord,
2553 PartialOrd,
2554 Hash,
2555 Serialize,
2556 Deserialize
2557)]
2558pub struct StableEvalError(#[serde(with = "stable_eval_error_proto")] pub EvalError);
2559
2560#[derive(Debug, Serialize)]
2563#[serde(rename = "StableEvalError")]
2564pub struct StableEvalErrorRef<'a>(#[serde(with = "stable_eval_error_proto")] pub &'a EvalError);
2565
2566impl From<EvalError> for StableEvalError {
2567 fn from(err: EvalError) -> Self {
2568 StableEvalError(err)
2569 }
2570}
2571
2572impl std::ops::Deref for StableEvalError {
2573 type Target = EvalError;
2574
2575 fn deref(&self) -> &EvalError {
2576 &self.0
2577 }
2578}
2579
2580mod stable_eval_error_proto {
2581 use mz_proto::RustType;
2582 use prost::Message;
2583 use serde::de::Error;
2584 use serde::{Deserialize, Deserializer, Serializer};
2585
2586 use crate::scalar::{EvalError, ProtoEvalError};
2587
2588 pub fn serialize<S: Serializer, E: std::borrow::Borrow<EvalError>>(
2589 err: &E,
2590 serializer: S,
2591 ) -> Result<S::Ok, S::Error> {
2592 serializer.serialize_bytes(&err.borrow().into_proto().encode_to_vec())
2593 }
2594
2595 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<EvalError, D::Error> {
2596 let bytes = serde_bytes::ByteBuf::deserialize(deserializer)?;
2597 let proto = ProtoEvalError::decode(bytes.as_slice()).map_err(D::Error::custom)?;
2598 EvalError::from_proto(proto).map_err(D::Error::custom)
2599 }
2600}
2601
2602#[cfg(test)]
2603mod tests {
2604 use super::*;
2605 use crate::scalar::func::variadic::Coalesce;
2606
2607 proptest! {
2613 #![proptest_config(ProptestConfig::with_cases(1000))]
2614
2615 #[mz_ore::test]
2616 #[cfg_attr(miri, ignore)] fn stable_eval_error_serde_roundtrip(err in any::<EvalError>()) {
2618 let stable = StableEvalError(err);
2619
2620 let json = serde_json::to_string(&stable).expect("serializes to JSON");
2621 let from_json: StableEvalError =
2622 serde_json::from_str(&json).expect("deserializes from JSON");
2623 prop_assert_eq!(&stable, &from_json);
2624
2625 let bytes = bincode::serialize(&stable).expect("serializes to bincode");
2626 let from_bincode: StableEvalError =
2627 bincode::deserialize(&bytes).expect("deserializes from bincode");
2628 prop_assert_eq!(&stable, &from_bincode);
2629 }
2630 }
2631
2632 #[mz_ore::test]
2637 fn test_unbounded_out_of_domain_renders() {
2638 let err = EvalError::OutOfDomain(DomainLimit::None, DomainLimit::None, "f".into());
2639 assert_eq!(
2640 err.to_string(),
2641 "function f is defined for numbers in an unspecified range"
2642 );
2643 }
2644
2645 #[mz_ore::test]
2650 #[cfg_attr(miri, ignore)] fn test_repeat_respects_arena_budget() {
2652 use crate::scalar::func::RepeatString;
2653
2654 let body = "a".repeat(1024 * 1024);
2655 let expr = MirScalarExpr::column(0).call_binary(
2656 MirScalarExpr::literal_ok(Datum::Int32(20), ReprScalarType::Int32),
2657 RepeatString,
2658 );
2659 let datums = [Datum::String(&body)];
2660
2661 let arena = RowArena::new();
2663 let datum = expr
2664 .eval(&datums, &arena)
2665 .expect("under the 100 MiB ceiling");
2666 assert_eq!(datum.unwrap_str().len(), 20 * 1024 * 1024);
2667 assert!(arena.allocated_bytes() >= 20 * 1024 * 1024);
2668
2669 let arena = RowArena::with_budget(4 * 1024 * 1024);
2672 assert_eq!(
2673 expr.eval(&datums, &arena),
2674 Err(EvalError::LengthTooLarge),
2675 "an over-budget result must be refused"
2676 );
2677 assert_eq!(arena.allocated_bytes(), 0);
2678
2679 let arena = RowArena::with_budget(64 * 1024 * 1024);
2681 let datum = expr.eval(&datums, &arena).expect("within budget");
2682 assert_eq!(datum.unwrap_str().len(), 20 * 1024 * 1024);
2683 }
2684
2685 #[mz_ore::test]
2689 #[cfg_attr(miri, ignore)] fn test_arena_built_result_respects_budget() {
2691 use crate::scalar::func::variadic::{RegexpSplitToArray, StringToArray};
2692
2693 let body = "a".repeat(256 * 1024);
2694 let expr = MirScalarExpr::call_variadic(
2695 StringToArray,
2696 vec![
2697 MirScalarExpr::column(0),
2698 MirScalarExpr::literal_ok(Datum::String("a"), ReprScalarType::String),
2699 ],
2700 );
2701 let datums = [Datum::String(&body)];
2702
2703 let arena = RowArena::new();
2704 expr.eval(&datums, &arena).expect("no ceiling applies");
2705 let unbudgeted = arena.allocated_bytes();
2706 assert!(unbudgeted > 0);
2707
2708 let arena = RowArena::with_budget(unbudgeted / 2);
2709 assert_eq!(
2710 expr.eval(&datums, &arena),
2711 Err(EvalError::TempStorageBudgetExceeded),
2712 "an over-budget arena-built result must be refused"
2713 );
2714
2715 let intermediate = (body.len() + 1) * std::mem::size_of::<&str>();
2718 let budget = 4 * unbudgeted;
2719 assert!(
2720 unbudgeted < budget && budget < intermediate,
2721 "budget sits between"
2722 );
2723 let arena = RowArena::with_budget(budget);
2724 assert!(
2725 expr.eval(&datums, &arena).is_err(),
2726 "a split costing {intermediate} bytes to build must be refused by a {budget} byte budget"
2727 );
2728 assert_eq!(
2729 arena.allocated_bytes(),
2730 0,
2731 "refused before the transient was built"
2732 );
2733
2734 let regexp_expr = MirScalarExpr::call_variadic(
2736 RegexpSplitToArray,
2737 vec![
2738 MirScalarExpr::column(0),
2739 MirScalarExpr::literal_ok(Datum::String("a"), ReprScalarType::String),
2740 ],
2741 );
2742 let arena = RowArena::with_budget(budget);
2743 assert!(
2744 regexp_expr.eval(&datums, &arena).is_err(),
2745 "a regexp split costing {intermediate} bytes to build must be refused too"
2746 );
2747 assert_eq!(arena.allocated_bytes(), 0);
2748 }
2749
2750 #[mz_ore::test]
2755 #[cfg_attr(miri, ignore)] fn test_array_fill_respects_arena_budget() {
2757 use crate::scalar::func::variadic::ArrayFill;
2758 use mz_repr::adt::array::ArrayDimension;
2759
2760 let fill_count: usize = 512 * 1024;
2762 let dims_storage = RowArena::new();
2763 let dims = dims_storage
2764 .try_make_datum(|packer| {
2765 packer.try_push_array(
2766 &[ArrayDimension {
2767 lower_bound: 1,
2768 length: 1,
2769 }],
2770 [Datum::Int32(i32::try_from(fill_count).unwrap())],
2771 )
2772 })
2773 .unwrap();
2774 let expr = MirScalarExpr::call_variadic(
2775 ArrayFill {
2776 elem_type: mz_repr::SqlScalarType::Int32,
2777 },
2778 vec![MirScalarExpr::column(0), MirScalarExpr::column(1)],
2779 );
2780 let datums = [Datum::Int32(1), dims];
2781
2782 let arena = RowArena::new();
2784 expr.eval(&datums, &arena)
2785 .expect("under the array-size ceiling");
2786 assert!(arena.allocated_bytes() > 0);
2787
2788 let arena = RowArena::with_budget(1024 * 1024);
2791 assert_eq!(
2792 expr.eval(&datums, &arena),
2793 Err(EvalError::TempStorageBudgetExceeded),
2794 "an over-budget array_fill must be refused before it allocates"
2795 );
2796 assert_eq!(arena.allocated_bytes(), 0);
2797
2798 let arena = RowArena::with_budget(256 * 1024 * 1024);
2800 expr.eval(&datums, &arena).expect("within budget");
2801 }
2802
2803 #[mz_ore::test]
2807 #[cfg_attr(miri, ignore)] fn test_array_remove_respects_arena_budget() {
2809 use crate::scalar::func::ArrayRemove;
2810 use mz_repr::adt::array::ArrayDimension;
2811
2812 const ELEMS: usize = 256 * 1024;
2813 let input_storage = RowArena::new();
2814 let array = input_storage
2815 .try_make_datum(|packer| {
2816 packer.try_push_array(
2817 &[ArrayDimension {
2818 lower_bound: 1,
2819 length: ELEMS,
2820 }],
2821 (0..ELEMS).map(|i| Datum::Int32(i32::try_from(i).unwrap())),
2822 )
2823 })
2824 .unwrap();
2825 let expr = MirScalarExpr::column(0).call_binary(MirScalarExpr::column(1), ArrayRemove);
2826 let datums = [array, Datum::Int32(0)];
2827
2828 let arena = RowArena::new();
2830 expr.eval(&datums, &arena).expect("no ceiling applies");
2831 let unbudgeted = arena.allocated_bytes();
2832 assert!(unbudgeted > 0);
2833
2834 let transient = ELEMS * std::mem::size_of::<Datum<'_>>();
2837 let budget = 2 * unbudgeted;
2838 assert!(budget < transient, "budget sits between");
2839 let arena = RowArena::with_budget(budget);
2840 assert_eq!(
2841 expr.eval(&datums, &arena),
2842 Err(EvalError::TempStorageBudgetExceeded),
2843 "an over-budget transient must be refused"
2844 );
2845 assert_eq!(arena.allocated_bytes(), 0);
2846
2847 let arena = RowArena::with_budget(64 * 1024 * 1024);
2849 expr.eval(&datums, &arena).expect("within budget");
2850 }
2851
2852 #[mz_ore::test]
2861 #[cfg_attr(miri, ignore)] fn test_single_call_respects_arena_budget() {
2863 use mz_ore::cast::CastLossy;
2864
2865 use crate::scalar::func::variadic::{ArrayCreate, PadLeading, Translate};
2866
2867 const BODY_BYTES: usize = 1024 * 1024;
2870 const BUDGET: usize = 2 * 1024 * 1024;
2871 const WIDE: &str = "\u{1F4A5}"; let str_lit = |s| MirScalarExpr::literal_ok(Datum::String(s), ReprScalarType::String);
2874 let array_of = |n| {
2877 let elem_type = mz_repr::SqlScalarType::String;
2878 let refs = vec![MirScalarExpr::column(0); n];
2879 MirScalarExpr::call_variadic(ArrayCreate { elem_type }, refs)
2880 };
2881 let cases = [
2882 ("ARRAY[body x4]", array_of(4)),
2883 ("ARRAY[body x16]", array_of(16)),
2884 (
2887 "lpad(body, BUDGET, wide)",
2888 MirScalarExpr::call_variadic(
2889 PadLeading,
2890 vec![
2891 MirScalarExpr::column(0),
2892 MirScalarExpr::literal_ok(
2893 Datum::Int32(i32::try_from(BUDGET).unwrap()),
2894 ReprScalarType::Int32,
2895 ),
2896 str_lit(WIDE),
2897 ],
2898 ),
2899 ),
2900 (
2903 "translate(body, 'a', wide)",
2904 MirScalarExpr::call_variadic(
2905 Translate,
2906 vec![MirScalarExpr::column(0), str_lit("a"), str_lit(WIDE)],
2907 ),
2908 ),
2909 ];
2910
2911 let body = "a".repeat(BODY_BYTES);
2912 let datums = [Datum::String(&body)];
2913 let mut over = Vec::new();
2914 for (name, expr) in cases {
2915 let arena = RowArena::with_budget(BUDGET);
2916 let _ = expr.eval(&datums, &arena); let held = arena.allocated_bytes();
2918 if held > BUDGET {
2919 let ratio = f64::cast_lossy(held) / f64::cast_lossy(BUDGET);
2920 over.push(format!(" {name}: held {held} bytes, {ratio:.1}x"));
2921 }
2922 }
2923 assert!(
2924 over.is_empty(),
2925 "a single call left a {BUDGET} byte arena holding more:\n{}",
2926 over.join("\n"),
2927 );
2928 }
2929
2930 #[mz_ore::test]
2931 #[cfg_attr(miri, ignore)] fn test_reduce() {
2933 let relation_type: Vec<ReprColumnType> = vec![
2934 ReprScalarType::Int64.nullable(true),
2935 ReprScalarType::Int64.nullable(true),
2936 ReprScalarType::Int64.nullable(false),
2937 ]
2938 .into_iter()
2939 .collect();
2940 let col = MirScalarExpr::column;
2941 let int64_typ = ReprScalarType::Int64;
2942 let err = |e| MirScalarExpr::literal(Err(e), int64_typ.clone());
2943 let lit = |i| MirScalarExpr::literal_ok(Datum::Int64(i), int64_typ.clone());
2944 let null = || MirScalarExpr::literal_null(int64_typ.clone());
2945
2946 struct TestCase {
2947 input: MirScalarExpr,
2948 output: MirScalarExpr,
2949 }
2950
2951 let test_cases = vec![
2952 TestCase {
2953 input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1)]),
2954 output: lit(1),
2955 },
2956 TestCase {
2957 input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1), lit(2)]),
2958 output: lit(1),
2959 },
2960 TestCase {
2961 input: MirScalarExpr::call_variadic(Coalesce, vec![null(), lit(2), null()]),
2962 output: lit(2),
2963 },
2964 TestCase {
2965 input: MirScalarExpr::call_variadic(
2966 Coalesce,
2967 vec![null(), col(0), null(), col(1), lit(2), lit(3)],
2968 ),
2969 output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(1), lit(2)]),
2970 },
2971 TestCase {
2972 input: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2), col(1)]),
2973 output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2)]),
2974 },
2975 TestCase {
2976 input: MirScalarExpr::call_variadic(
2977 Coalesce,
2978 vec![lit(1), err(EvalError::DivisionByZero)],
2979 ),
2980 output: lit(1),
2981 },
2982 TestCase {
2983 input: MirScalarExpr::call_variadic(
2984 Coalesce,
2985 vec![
2986 null(),
2987 err(EvalError::DivisionByZero),
2988 err(EvalError::NumericFieldOverflow),
2989 ],
2990 ),
2991 output: err(EvalError::DivisionByZero),
2992 },
2993 ];
2994
2995 for tc in test_cases {
2996 let mut actual = tc.input.clone();
2997 actual.reduce(&relation_type);
2998 assert!(
2999 actual == tc.output,
3000 "input: {}\nactual: {}\nexpected: {}",
3001 tc.input,
3002 actual,
3003 tc.output
3004 );
3005 }
3006 }
3007
3008 #[mz_ore::test]
3012 fn test_visit_mut_post_replace_subtrees() {
3013 let col = MirScalarExpr::column;
3014 let mut expr = col(0).if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
3015
3016 expr.visit_mut_post(&mut |expr: &mut MirScalarExpr| match expr {
3017 MirScalarExpr::Column(n, _) => *n += 1,
3018 MirScalarExpr::If { then, .. } => {
3019 let then = then.take();
3020 *expr = then;
3021 }
3022 _ => {}
3023 });
3024
3025 assert_eq!(expr, col(3));
3027 }
3028
3029 #[mz_ore::test]
3035 fn test_visit_mut_pre_post_explicit_children() {
3036 let col = MirScalarExpr::column;
3037 let mut expr = col(5)
3038 .if_then_else(col(6), col(7))
3039 .if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
3040
3041 expr.visit_mut_pre_post(
3045 &mut |expr: &mut MirScalarExpr| -> Option<Vec<&mut MirScalarExpr>> {
3046 if let MirScalarExpr::If { .. } = expr {
3047 let MirScalarExpr::If { then, els, .. } = expr else {
3048 unreachable!()
3049 };
3050 let then = then.take();
3051 let els = els.take();
3052 *expr = MirScalarExpr::column(0).if_then_else(then, els);
3053
3054 let MirScalarExpr::If { then, els, .. } = expr else {
3055 unreachable!()
3056 };
3057 Some(vec![then.as_mut(), els.as_mut()])
3058 } else {
3059 None
3061 }
3062 },
3063 &mut |expr: &mut MirScalarExpr| {
3064 if let MirScalarExpr::Column(n, _) = expr {
3065 *n += 10;
3066 }
3067 },
3068 );
3069
3070 let expected = col(0).if_then_else(col(0).if_then_else(col(12), col(13)), col(14));
3072 assert_eq!(expr, expected);
3073 }
3074}