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_unfoldable(&self) -> bool {
1119 let mut contains = false;
1120 self.visit_pre(|e| match e {
1121 MirScalarExpr::CallUnmaterializable(_)
1122 | MirScalarExpr::CallUnary {
1123 func: UnaryFunc::Jq(_),
1124 ..
1125 } => contains = true,
1126 _ => {}
1127 });
1128 contains
1129 }
1130
1131 pub fn contains_unmaterializable_except(&self, exceptions: &[UnmaterializableFunc]) -> bool {
1134 let mut contains = false;
1135 self.visit_pre(|e| match e {
1136 MirScalarExpr::CallUnmaterializable(f) if !exceptions.contains(f) => contains = true,
1137 _ => (),
1138 });
1139 contains
1140 }
1141
1142 pub fn contains_column(&self) -> bool {
1144 let mut contains = false;
1145 self.visit_pre(|e| {
1146 if let MirScalarExpr::Column(_col, _name) = e {
1147 contains = true;
1148 }
1149 });
1150 contains
1151 }
1152
1153 pub fn contains_dummy(&self) -> bool {
1155 let mut contains = false;
1156 self.visit_pre(|e| {
1157 if let MirScalarExpr::Literal(row, _) = e {
1158 if let Ok(row) = row {
1159 contains |= row.iter().any(|d| d.contains_dummy());
1160 }
1161 }
1162 });
1163 contains
1164 }
1165
1166 pub fn size(&self) -> usize {
1168 let mut size = 0;
1169 self.visit_pre(&mut |_: &MirScalarExpr| {
1170 size += 1;
1171 });
1172 size
1173 }
1174}
1175
1176fn check_temp_storage_budget(temp_storage: &RowArena) -> Result<(), EvalError> {
1186 if temp_storage.over_budget() {
1187 return Err(EvalError::TempStorageBudgetExceeded);
1188 }
1189 Ok(())
1190}
1191
1192impl Eval for MirScalarExpr {
1193 fn eval<'a>(
1194 &'a self,
1195 datums: &[Datum<'a>],
1196 temp_storage: &'a RowArena,
1197 ) -> Result<Datum<'a>, EvalError> {
1198 match self {
1199 MirScalarExpr::Column(index, _name) => Ok(datums[*index]),
1200 MirScalarExpr::Literal(res, _column_type) => match res {
1201 Ok(row) => Ok(row.unpack_first()),
1202 Err(e) => Err(e.clone()),
1203 },
1204 MirScalarExpr::CallUnmaterializable(x) => Err(EvalError::Internal(
1208 format!("cannot evaluate unmaterializable function: {:?}", x).into(),
1209 )),
1210 MirScalarExpr::CallUnary { func, expr } => {
1211 let datum = func.eval(datums, temp_storage, expr.as_ref())?;
1212 check_temp_storage_budget(temp_storage)?;
1213 Ok(datum)
1214 }
1215 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1216 let datum = func.eval(datums, temp_storage, &[expr1.as_ref(), expr2.as_ref()])?;
1217 check_temp_storage_budget(temp_storage)?;
1218 Ok(datum)
1219 }
1220 MirScalarExpr::CallVariadic { func, exprs } => {
1221 let datum = func.eval(datums, temp_storage, exprs.as_slice())?;
1222 check_temp_storage_budget(temp_storage)?;
1223 Ok(datum)
1224 }
1225 MirScalarExpr::If { cond, then, els } => match cond.eval(datums, temp_storage)? {
1226 Datum::True => then.eval(datums, temp_storage),
1227 Datum::False | Datum::Null => els.eval(datums, temp_storage),
1228 d => Err(EvalError::Internal(
1229 format!("if condition evaluated to non-boolean datum: {:?}", d).into(),
1230 )),
1231 },
1232 }
1233 }
1234
1235 fn could_error(&self) -> bool {
1236 match self {
1237 MirScalarExpr::Column(_col, _name) => false,
1238 MirScalarExpr::Literal(row, ..) => row.is_err(),
1239 MirScalarExpr::CallUnmaterializable(_) => true,
1240 MirScalarExpr::CallUnary { func, expr } => func.could_error() || expr.could_error(),
1241 MirScalarExpr::CallBinary { func, expr1, expr2 } => {
1242 func.could_error() || expr1.could_error() || expr2.could_error()
1243 }
1244 MirScalarExpr::CallVariadic { func, exprs } => {
1245 func.could_error() || exprs.iter().any(|e| e.could_error())
1246 }
1247 MirScalarExpr::If { cond, then, els } => {
1248 cond.could_error() || then.could_error() || els.could_error()
1249 }
1250 }
1251 }
1252}
1253
1254impl Columns for MirScalarExpr {
1255 fn column(c: usize) -> Self {
1256 MirScalarExpr::column(c)
1257 }
1258
1259 fn is_column(&self) -> bool {
1260 matches!(self, MirScalarExpr::Column(_col, _name))
1261 }
1262
1263 fn as_column(&self) -> Option<usize> {
1264 if let MirScalarExpr::Column(c, _) = self {
1265 Some(*c)
1266 } else {
1267 None
1268 }
1269 }
1270
1271 fn as_column_mut(&mut self) -> Option<&mut usize> {
1272 if let MirScalarExpr::Column(c, _) = self {
1273 Some(c)
1274 } else {
1275 None
1276 }
1277 }
1278
1279 fn support_into(&self, support: &mut BTreeSet<usize>) {
1280 self.visit_pre(|e| {
1281 if let MirScalarExpr::Column(i, _) = e {
1282 support.insert(*i);
1283 }
1284 });
1285 }
1286
1287 fn visit_columns<F>(&mut self, mut action: F)
1288 where
1289 F: FnMut(&mut usize),
1290 {
1291 self.visit_pre_mut(|e| {
1292 if let MirScalarExpr::Column(col, _) = e {
1293 action(col);
1294 }
1295 });
1296 }
1297}
1298
1299impl VisitChildren<Self> for MirScalarExpr {
1300 fn visit_children<F>(&self, mut f: F)
1301 where
1302 F: FnMut(&Self),
1303 {
1304 use MirScalarExpr::*;
1305 match self {
1306 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1307 CallUnary { expr, .. } => {
1308 f(expr);
1309 }
1310 CallBinary { expr1, expr2, .. } => {
1311 f(expr1);
1312 f(expr2);
1313 }
1314 CallVariadic { exprs, .. } => {
1315 for expr in exprs {
1316 f(expr);
1317 }
1318 }
1319 If { cond, then, els } => {
1320 f(cond);
1321 f(then);
1322 f(els);
1323 }
1324 }
1325 }
1326
1327 fn visit_mut_children<F>(&mut self, mut f: F)
1328 where
1329 F: FnMut(&mut Self),
1330 {
1331 use MirScalarExpr::*;
1332 match self {
1333 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1334 CallUnary { expr, .. } => {
1335 f(expr);
1336 }
1337 CallBinary { expr1, expr2, .. } => {
1338 f(expr1);
1339 f(expr2);
1340 }
1341 CallVariadic { exprs, .. } => {
1342 for expr in exprs {
1343 f(expr);
1344 }
1345 }
1346 If { cond, then, els } => {
1347 f(cond);
1348 f(then);
1349 f(els);
1350 }
1351 }
1352 }
1353
1354 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
1355 where
1356 F: FnMut(&Self) -> Result<(), E>,
1357 {
1358 use MirScalarExpr::*;
1359 match self {
1360 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1361 CallUnary { expr, .. } => {
1362 f(expr)?;
1363 }
1364 CallBinary { expr1, expr2, .. } => {
1365 f(expr1)?;
1366 f(expr2)?;
1367 }
1368 CallVariadic { exprs, .. } => {
1369 for expr in exprs {
1370 f(expr)?;
1371 }
1372 }
1373 If { cond, then, els } => {
1374 f(cond)?;
1375 f(then)?;
1376 f(els)?;
1377 }
1378 }
1379 Ok(())
1380 }
1381
1382 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
1383 where
1384 F: FnMut(&mut Self) -> Result<(), E>,
1385 {
1386 use MirScalarExpr::*;
1387 match self {
1388 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1389 CallUnary { expr, .. } => {
1390 f(expr)?;
1391 }
1392 CallBinary { expr1, expr2, .. } => {
1393 f(expr1)?;
1394 f(expr2)?;
1395 }
1396 CallVariadic { exprs, .. } => {
1397 for expr in exprs {
1398 f(expr)?;
1399 }
1400 }
1401 If { cond, then, els } => {
1402 f(cond)?;
1403 f(then)?;
1404 f(els)?;
1405 }
1406 }
1407 Ok(())
1408 }
1409
1410 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a Self>
1411 where
1412 Self: 'a,
1413 {
1414 self.children()
1415 }
1416
1417 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut Self>
1418 where
1419 Self: 'a,
1420 {
1421 self.children_mut()
1422 }
1423}
1424
1425impl MirScalarExpr {
1426 pub fn could_hit_nonstrict_error_fold(&self) -> bool {
1449 let mut hit = false;
1450 self.visit_pre(|e| {
1451 if let MirScalarExpr::CallVariadic { func, exprs } = e {
1452 let non_strict = matches!(
1453 func,
1454 VariadicFunc::And(_) | VariadicFunc::Or(_) | VariadicFunc::ErrorIfNull(_)
1455 );
1456 if non_strict && exprs.iter().any(|operand| operand.could_error()) {
1457 hit = true;
1458 }
1459 }
1460 });
1461 hit
1462 }
1463
1464 pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self> {
1466 let mut first = None;
1467 let mut second = None;
1468 let mut third = None;
1469 let mut variadic = None;
1470
1471 use MirScalarExpr::*;
1472 match self {
1473 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1474 CallUnary { expr, .. } => {
1475 first = Some(&**expr);
1476 }
1477 CallBinary { expr1, expr2, .. } => {
1478 first = Some(&**expr1);
1479 second = Some(&**expr2);
1480 }
1481 CallVariadic { exprs, .. } => {
1482 variadic = Some(exprs);
1483 }
1484 If { cond, then, els } => {
1485 first = Some(&**cond);
1486 second = Some(&**then);
1487 third = Some(&**els);
1488 }
1489 }
1490
1491 first
1492 .into_iter()
1493 .chain(second)
1494 .chain(third)
1495 .chain(variadic.into_iter().flatten())
1496 }
1497
1498 pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self> {
1500 let mut first = None;
1501 let mut second = None;
1502 let mut third = None;
1503 let mut variadic = None;
1504
1505 use MirScalarExpr::*;
1506 match self {
1507 Column(_, _) | Literal(_, _) | CallUnmaterializable(_) => (),
1508 CallUnary { expr, .. } => {
1509 first = Some(&mut **expr);
1510 }
1511 CallBinary { expr1, expr2, .. } => {
1512 first = Some(&mut **expr1);
1513 second = Some(&mut **expr2);
1514 }
1515 CallVariadic { exprs, .. } => {
1516 variadic = Some(exprs);
1517 }
1518 If { cond, then, els } => {
1519 first = Some(&mut **cond);
1520 second = Some(&mut **then);
1521 third = Some(&mut **els);
1522 }
1523 }
1524
1525 first
1526 .into_iter()
1527 .chain(second)
1528 .chain(third)
1529 .chain(variadic.into_iter().flatten())
1530 }
1531
1532 pub fn visit_pre<F>(&self, mut f: F)
1534 where
1535 F: FnMut(&Self),
1536 {
1537 let mut worklist = vec![self];
1538 while let Some(e) = worklist.pop() {
1539 f(e);
1540 worklist.extend(e.children().rev());
1541 }
1542 }
1543
1544 pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, mut f: F) {
1546 let mut worklist = vec![self];
1547 while let Some(expr) = worklist.pop() {
1548 f(expr);
1549 worklist.extend(expr.children_mut().rev());
1550 }
1551 }
1552}
1553
1554#[derive(
1561 Eq,
1562 PartialEq,
1563 Ord,
1564 PartialOrd,
1565 Debug,
1566 Clone,
1567 Serialize,
1568 Deserialize,
1569 Hash
1570)]
1571pub struct FilterCharacteristics {
1572 literal_equality: bool,
1575 like: bool,
1577 is_null: bool,
1578 literal_inequality: usize,
1584 any_filter: bool,
1590}
1591
1592impl BitOrAssign for FilterCharacteristics {
1593 fn bitor_assign(&mut self, rhs: Self) {
1594 self.literal_equality |= rhs.literal_equality;
1595 self.like |= rhs.like;
1596 self.is_null |= rhs.is_null;
1597 self.literal_inequality += rhs.literal_inequality;
1598 self.any_filter |= rhs.any_filter;
1599 }
1600}
1601
1602impl FilterCharacteristics {
1603 pub fn none() -> FilterCharacteristics {
1604 FilterCharacteristics {
1605 literal_equality: false,
1606 like: false,
1607 is_null: false,
1608 literal_inequality: 0,
1609 any_filter: false,
1610 }
1611 }
1612
1613 pub fn explain(&self) -> String {
1614 let mut e = "".to_owned();
1615 if self.literal_equality {
1616 e.push_str("e");
1617 }
1618 if self.like {
1619 e.push_str("l");
1620 }
1621 if self.is_null {
1622 e.push_str("n");
1623 }
1624 for _ in 0..self.literal_inequality {
1625 e.push_str("i");
1626 }
1627 if self.any_filter {
1628 e.push_str("f");
1629 }
1630 e
1631 }
1632
1633 pub fn filter_characteristics(
1634 filters: &Vec<MirScalarExpr>,
1635 ) -> Result<FilterCharacteristics, RecursionLimitError> {
1636 let mut literal_equality = false;
1637 let mut like = false;
1638 let mut is_null = false;
1639 let mut literal_inequality = 0;
1640 let mut any_filter = false;
1641 filters.iter().try_for_each(|f| {
1642 let mut literal_inequality_in_current_filter = false;
1643 let mut is_not_null_in_current_filter = false;
1644 f.visit_pre_with_context(
1645 false,
1646 &mut |not_in_parent_chain, expr| {
1647 not_in_parent_chain
1648 || matches!(
1649 expr,
1650 MirScalarExpr::CallUnary {
1651 func: UnaryFunc::Not(func::Not),
1652 ..
1653 }
1654 )
1655 },
1656 &mut |not_in_parent_chain, expr| {
1657 if !not_in_parent_chain {
1658 if expr.any_expr_eq_literal().is_some() {
1659 literal_equality = true;
1660 }
1661 if expr.any_expr_ineq_literal() {
1662 literal_inequality_in_current_filter = true;
1663 }
1664 if matches!(
1665 expr,
1666 MirScalarExpr::CallUnary {
1667 func: UnaryFunc::IsLikeMatch(_),
1668 ..
1669 }
1670 ) {
1671 like = true;
1672 }
1673 };
1674 if matches!(
1675 expr,
1676 MirScalarExpr::CallUnary {
1677 func: UnaryFunc::IsNull(crate::func::IsNull),
1678 ..
1679 }
1680 ) {
1681 if *not_in_parent_chain {
1682 is_not_null_in_current_filter = true;
1683 } else {
1684 is_null = true;
1685 }
1686 }
1687 },
1688 );
1689 if literal_inequality_in_current_filter {
1690 literal_inequality += 1;
1691 }
1692 if !is_not_null_in_current_filter {
1693 any_filter = true;
1695 }
1696 Ok(())
1697 })?;
1698 Ok(FilterCharacteristics {
1699 literal_equality,
1700 like,
1701 is_null,
1702 literal_inequality,
1703 any_filter,
1704 })
1705 }
1706
1707 pub fn add_literal_equality(&mut self) {
1708 self.literal_equality = true;
1709 }
1710
1711 pub fn worst_case_scaling_factor(&self) -> f64 {
1712 let mut factor = 1.0;
1713
1714 if self.literal_equality {
1715 factor *= 0.1;
1716 }
1717
1718 if self.is_null {
1719 factor *= 0.1;
1720 }
1721
1722 if self.literal_inequality >= 2 {
1723 factor *= 0.25;
1724 } else if self.literal_inequality == 1 {
1725 factor *= 0.33;
1726 }
1727
1728 if !(self.literal_equality || self.is_null || self.literal_inequality > 0)
1730 && self.any_filter
1731 {
1732 factor *= 0.9;
1733 }
1734
1735 factor
1736 }
1737}
1738
1739#[derive(
1740 Ord,
1741 PartialOrd,
1742 Copy,
1743 Clone,
1744 Debug,
1745 Eq,
1746 PartialEq,
1747 Serialize,
1748 Deserialize,
1749 Hash
1750)]
1751#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1752pub enum DomainLimit {
1753 None,
1754 Inclusive(i64),
1755 Exclusive(i64),
1756}
1757
1758impl RustType<ProtoDomainLimit> for DomainLimit {
1759 fn into_proto(&self) -> ProtoDomainLimit {
1760 use proto_domain_limit::Kind::*;
1761 let kind = match self {
1762 DomainLimit::None => None(()),
1763 DomainLimit::Inclusive(v) => Inclusive(*v),
1764 DomainLimit::Exclusive(v) => Exclusive(*v),
1765 };
1766 ProtoDomainLimit { kind: Some(kind) }
1767 }
1768
1769 fn from_proto(proto: ProtoDomainLimit) -> Result<Self, TryFromProtoError> {
1770 use proto_domain_limit::Kind::*;
1771 if let Some(kind) = proto.kind {
1772 match kind {
1773 None(()) => Ok(DomainLimit::None),
1774 Inclusive(v) => Ok(DomainLimit::Inclusive(v)),
1775 Exclusive(v) => Ok(DomainLimit::Exclusive(v)),
1776 }
1777 } else {
1778 Err(TryFromProtoError::missing_field("ProtoDomainLimit::kind"))
1779 }
1780 }
1781}
1782
1783#[derive(
1784 Ord,
1785 PartialOrd,
1786 Clone,
1787 Debug,
1788 Eq,
1789 PartialEq,
1790 Serialize,
1791 Deserialize,
1792 Hash
1793)]
1794#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1795pub enum EvalError {
1796 CharacterNotValidForEncoding(i32),
1797 CharacterTooLargeForEncoding(i32),
1798 DateBinOutOfRange(Box<str>),
1799 DivisionByZero,
1800 Unsupported {
1801 feature: Box<str>,
1802 discussion_no: Option<usize>,
1803 },
1804 FloatOverflow,
1805 FloatUnderflow,
1806 NumericFieldOverflow,
1807 Float32OutOfRange(Box<str>),
1808 Float64OutOfRange(Box<str>),
1809 Int16OutOfRange(Box<str>),
1810 Int32OutOfRange(Box<str>),
1811 Int64OutOfRange(Box<str>),
1812 UInt16OutOfRange(Box<str>),
1813 UInt32OutOfRange(Box<str>),
1814 UInt64OutOfRange(Box<str>),
1815 MzTimestampOutOfRange(Box<str>),
1816 MzTimestampStepOverflow,
1817 OidOutOfRange(Box<str>),
1818 IntervalOutOfRange(Box<str>),
1819 TimestampCannotBeNan,
1820 TimestampOutOfRange,
1821 DateOutOfRange,
1822 CharOutOfRange,
1823 IndexOutOfRange {
1824 provided: i32,
1825 valid_end: i32,
1827 },
1828 InvalidBase64Equals,
1829 InvalidBase64Symbol(char),
1830 InvalidBase64EndSequence,
1831 InvalidTimezone(Box<str>),
1832 InvalidTimezoneInterval,
1833 InvalidTimezoneConversion,
1834 InvalidIanaTimezoneId(Box<str>),
1835 InvalidLayer {
1836 max_layer: usize,
1837 val: i64,
1838 },
1839 InvalidArray(InvalidArrayError),
1840 InvalidEncodingName(Box<str>),
1841 InvalidHashAlgorithm(Box<str>),
1842 InvalidByteSequence {
1843 byte_sequence: Box<str>,
1844 encoding_name: Box<str>,
1845 },
1846 InvalidJsonbCast {
1847 from: Box<str>,
1848 to: Box<str>,
1849 },
1850 InvalidRegex(Box<str>),
1851 InvalidRegexFlag(char),
1852 InvalidParameterValue(Box<str>),
1853 InvalidDatePart(Box<str>),
1854 KeyCannotBeNull,
1855 NegSqrt,
1856 NegLimit,
1857 NullCharacterNotPermitted,
1858 UnknownUnits(Box<str>),
1859 UnsupportedUnits(Box<str>, Box<str>),
1860 UnterminatedLikeEscapeSequence,
1861 Parse(ParseError),
1862 ParseHex(ParseHexError),
1863 Internal(Box<str>),
1864 InfinityOutOfDomain(Box<str>),
1865 NegativeOutOfDomain(Box<str>),
1866 ZeroOutOfDomain(Box<str>),
1867 OutOfDomain(DomainLimit, DomainLimit, Box<str>),
1868 ComplexOutOfRange(Box<str>),
1869 MultipleRowsFromSubquery,
1870 NegativeRowsFromSubquery,
1871 Undefined(Box<str>),
1872 LikePatternTooLong,
1873 LikeEscapeTooLong,
1874 StringValueTooLong {
1875 target_type: Box<str>,
1876 length: usize,
1877 },
1878 MultidimensionalArrayRemovalNotSupported,
1879 IncompatibleArrayDimensions {
1880 dims: Option<(usize, usize)>,
1881 },
1882 TypeFromOid(Box<str>),
1883 InvalidRange(InvalidRangeError),
1884 InvalidRoleId(Box<str>),
1885 InvalidPrivileges(Box<str>),
1886 InvalidCatalogJson(Box<str>),
1887 LetRecLimitExceeded(Box<str>),
1888 MultiDimensionalArraySearch,
1889 MustNotBeNull(Box<str>),
1890 InvalidIdentifier {
1891 ident: Box<str>,
1892 detail: Option<Box<str>>,
1893 },
1894 ArrayFillWrongArraySubscripts,
1895 MaxArraySizeExceeded(usize),
1897 DateDiffOverflow {
1898 unit: Box<str>,
1899 a: Box<str>,
1900 b: Box<str>,
1901 },
1902 IfNullError(Box<str>),
1905 LengthTooLarge,
1906 TempStorageBudgetExceeded,
1910 AclArrayNullElement,
1911 MzAclArrayNullElement,
1912 PrettyError(Box<str>),
1913 RedactError(Box<str>),
1914}
1915
1916impl fmt::Display for EvalError {
1917 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1918 match self {
1919 EvalError::CharacterNotValidForEncoding(v) => {
1920 write!(f, "requested character not valid for encoding: {v}")
1921 }
1922 EvalError::CharacterTooLargeForEncoding(v) => {
1923 write!(f, "requested character too large for encoding: {v}")
1924 }
1925 EvalError::DateBinOutOfRange(message) => f.write_str(message),
1926 EvalError::DivisionByZero => f.write_str("division by zero"),
1927 EvalError::Unsupported {
1928 feature,
1929 discussion_no,
1930 } => {
1931 write!(f, "{} not yet supported", feature)?;
1932 if let Some(discussion_no) = discussion_no {
1933 write!(
1934 f,
1935 ", see https://github.com/MaterializeInc/materialize/discussions/{} for more details",
1936 discussion_no
1937 )?;
1938 }
1939 Ok(())
1940 }
1941 EvalError::FloatOverflow => f.write_str("value out of range: overflow"),
1942 EvalError::FloatUnderflow => f.write_str("value out of range: underflow"),
1943 EvalError::NumericFieldOverflow => f.write_str("numeric field overflow"),
1944 EvalError::Float32OutOfRange(val) => write!(f, "{} real out of range", val.quoted()),
1945 EvalError::Float64OutOfRange(val) => {
1946 write!(f, "{} double precision out of range", val.quoted())
1947 }
1948 EvalError::Int16OutOfRange(val) => write!(f, "{} smallint out of range", val.quoted()),
1949 EvalError::Int32OutOfRange(val) => write!(f, "{} integer out of range", val.quoted()),
1950 EvalError::Int64OutOfRange(val) => write!(f, "{} bigint out of range", val.quoted()),
1951 EvalError::UInt16OutOfRange(val) => write!(f, "{} uint2 out of range", val.quoted()),
1952 EvalError::UInt32OutOfRange(val) => write!(f, "{} uint4 out of range", val.quoted()),
1953 EvalError::UInt64OutOfRange(val) => write!(f, "{} uint8 out of range", val.quoted()),
1954 EvalError::MzTimestampOutOfRange(val) => {
1955 write!(f, "{} mz_timestamp out of range", val.quoted())
1956 }
1957 EvalError::MzTimestampStepOverflow => f.write_str("step mz_timestamp overflow"),
1958 EvalError::OidOutOfRange(val) => write!(f, "{} OID out of range", val.quoted()),
1959 EvalError::IntervalOutOfRange(val) => {
1960 write!(f, "{} interval out of range", val.quoted())
1961 }
1962 EvalError::TimestampCannotBeNan => f.write_str("timestamp cannot be NaN"),
1963 EvalError::TimestampOutOfRange => f.write_str("timestamp out of range"),
1964 EvalError::DateOutOfRange => f.write_str("date out of range"),
1965 EvalError::CharOutOfRange => f.write_str("\"char\" out of range"),
1966 EvalError::IndexOutOfRange {
1967 provided,
1968 valid_end,
1969 } => write!(f, "index {provided} out of valid range, 0..{valid_end}",),
1970 EvalError::InvalidBase64Equals => {
1971 f.write_str("unexpected \"=\" while decoding base64 sequence")
1972 }
1973 EvalError::InvalidBase64Symbol(c) => write!(
1974 f,
1975 "invalid symbol \"{}\" found while decoding base64 sequence",
1976 c.escape_default()
1977 ),
1978 EvalError::InvalidBase64EndSequence => f.write_str("invalid base64 end sequence"),
1979 EvalError::InvalidJsonbCast { from, to } => {
1980 write!(f, "cannot cast jsonb {} to type {}", from, to)
1981 }
1982 EvalError::InvalidTimezone(tz) => write!(f, "invalid time zone '{}'", tz),
1983 EvalError::InvalidTimezoneInterval => {
1984 f.write_str("timezone interval must not contain months or years")
1985 }
1986 EvalError::InvalidTimezoneConversion => f.write_str("invalid timezone conversion"),
1987 EvalError::InvalidIanaTimezoneId(tz) => {
1988 write!(f, "invalid IANA Time Zone Database identifier: '{}'", tz)
1989 }
1990 EvalError::InvalidLayer { max_layer, val } => write!(
1991 f,
1992 "invalid layer: {}; must use value within [1, {}]",
1993 val, max_layer
1994 ),
1995 EvalError::InvalidArray(e) => e.fmt(f),
1996 EvalError::InvalidEncodingName(name) => write!(f, "invalid encoding name '{}'", name),
1997 EvalError::InvalidHashAlgorithm(alg) => write!(f, "invalid hash algorithm '{}'", alg),
1998 EvalError::InvalidByteSequence {
1999 byte_sequence,
2000 encoding_name,
2001 } => write!(
2002 f,
2003 "invalid byte sequence '{}' for encoding '{}'",
2004 byte_sequence, encoding_name
2005 ),
2006 EvalError::InvalidDatePart(part) => write!(f, "invalid datepart {}", part.quoted()),
2007 EvalError::KeyCannotBeNull => f.write_str("key cannot be null"),
2008 EvalError::NegSqrt => f.write_str("cannot take square root of a negative number"),
2009 EvalError::NegLimit => f.write_str("LIMIT must not be negative"),
2010 EvalError::NullCharacterNotPermitted => f.write_str("null character not permitted"),
2011 EvalError::InvalidRegex(e) => write!(f, "invalid regular expression: {}", e),
2012 EvalError::InvalidRegexFlag(c) => write!(f, "invalid regular expression flag: {}", c),
2013 EvalError::InvalidParameterValue(s) => f.write_str(s),
2014 EvalError::UnknownUnits(units) => write!(f, "unit '{}' not recognized", units),
2015 EvalError::UnsupportedUnits(units, typ) => {
2016 write!(f, "unit '{}' not supported for type {}", units, typ)
2017 }
2018 EvalError::UnterminatedLikeEscapeSequence => {
2019 f.write_str("unterminated escape sequence in LIKE")
2020 }
2021 EvalError::Parse(e) => e.fmt(f),
2022 EvalError::PrettyError(e) => e.fmt(f),
2023 EvalError::RedactError(e) => e.fmt(f),
2024 EvalError::ParseHex(e) => e.fmt(f),
2025 EvalError::Internal(s) => write!(f, "internal error: {}", s),
2026 EvalError::InfinityOutOfDomain(s) => {
2027 write!(f, "function {} is only defined for finite arguments", s)
2028 }
2029 EvalError::NegativeOutOfDomain(s) => {
2030 write!(f, "function {} is not defined for negative numbers", s)
2031 }
2032 EvalError::ZeroOutOfDomain(s) => {
2033 write!(f, "function {} is not defined for zero", s)
2034 }
2035 EvalError::OutOfDomain(lower, upper, s) => {
2036 use DomainLimit::*;
2037 write!(f, "function {s} is defined for numbers ")?;
2038 match (lower, upper) {
2039 (Inclusive(n), None) => write!(f, "greater than or equal to {n}"),
2040 (Exclusive(n), None) => write!(f, "greater than {n}"),
2041 (None, Inclusive(n)) => write!(f, "less than or equal to {n}"),
2042 (None, Exclusive(n)) => write!(f, "less than {n}"),
2043 (Inclusive(lo), Inclusive(hi)) => write!(f, "between {lo} and {hi} inclusive"),
2044 (Exclusive(lo), Exclusive(hi)) => write!(f, "between {lo} and {hi} exclusive"),
2045 (Inclusive(lo), Exclusive(hi)) => {
2046 write!(f, "between {lo} inclusive and {hi} exclusive")
2047 }
2048 (Exclusive(lo), Inclusive(hi)) => {
2049 write!(f, "between {lo} exclusive and {hi} inclusive")
2050 }
2051 (None, None) => write!(f, "in an unspecified range"),
2058 }
2059 }
2060 EvalError::ComplexOutOfRange(s) => {
2061 write!(f, "function {} cannot return complex numbers", s)
2062 }
2063 EvalError::MultipleRowsFromSubquery => {
2064 write!(f, "more than one record produced in subquery")
2065 }
2066 EvalError::NegativeRowsFromSubquery => {
2067 write!(f, "negative number of rows produced in subquery")
2068 }
2069 EvalError::Undefined(s) => {
2070 write!(f, "{} is undefined", s)
2071 }
2072 EvalError::LikePatternTooLong => {
2073 write!(f, "LIKE pattern exceeds maximum length")
2074 }
2075 EvalError::LikeEscapeTooLong => {
2076 write!(f, "invalid escape string")
2077 }
2078 EvalError::StringValueTooLong {
2079 target_type,
2080 length,
2081 } => {
2082 write!(f, "value too long for type {}({})", target_type, length)
2083 }
2084 EvalError::MultidimensionalArrayRemovalNotSupported => {
2085 write!(
2086 f,
2087 "removing elements from multidimensional arrays is not supported"
2088 )
2089 }
2090 EvalError::IncompatibleArrayDimensions { dims: _ } => {
2091 write!(f, "cannot concatenate incompatible arrays")
2092 }
2093 EvalError::TypeFromOid(msg) => write!(f, "{msg}"),
2094 EvalError::InvalidRange(e) => e.fmt(f),
2095 EvalError::InvalidRoleId(msg) => write!(f, "{msg}"),
2096 EvalError::InvalidPrivileges(privilege) => {
2097 write!(f, "unrecognized privilege type: {privilege}")
2098 }
2099 EvalError::InvalidCatalogJson(msg) => {
2100 write!(f, "invalid catalog JSON: {msg}")
2101 }
2102 EvalError::LetRecLimitExceeded(max_iters) => {
2103 write!(
2104 f,
2105 "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.)",
2106 max_iters
2107 )
2108 }
2109 EvalError::MultiDimensionalArraySearch => write!(
2110 f,
2111 "searching for elements in multidimensional arrays is not supported"
2112 ),
2113 EvalError::MustNotBeNull(v) => write!(f, "{v} must not be null"),
2114 EvalError::InvalidIdentifier { ident, .. } => {
2115 write!(f, "string is not a valid identifier: {}", ident.quoted())
2116 }
2117 EvalError::ArrayFillWrongArraySubscripts => {
2118 f.write_str("wrong number of array subscripts")
2119 }
2120 EvalError::MaxArraySizeExceeded(max_size) => {
2121 write!(
2122 f,
2123 "array size exceeds the maximum allowed ({max_size} bytes)"
2124 )
2125 }
2126 EvalError::DateDiffOverflow { unit, a, b } => {
2127 write!(f, "datediff overflow, {unit} of {a}, {b}")
2128 }
2129 EvalError::IfNullError(s) => f.write_str(s),
2130 EvalError::LengthTooLarge => write!(f, "requested length too large"),
2131 EvalError::TempStorageBudgetExceeded => {
2132 write!(f, "expression exceeded its temporary storage limit")
2133 }
2134 EvalError::AclArrayNullElement => write!(f, "ACL arrays must not contain null values"),
2135 EvalError::MzAclArrayNullElement => {
2136 write!(f, "MZ_ACL arrays must not contain null values")
2137 }
2138 }
2139 }
2140}
2141
2142impl EvalError {
2143 pub fn detail(&self) -> Option<String> {
2144 match self {
2145 EvalError::IncompatibleArrayDimensions { dims: None } => Some(
2146 "Arrays with differing dimensions are not compatible for concatenation.".into(),
2147 ),
2148 EvalError::IncompatibleArrayDimensions {
2149 dims: Some((a_dims, b_dims)),
2150 } => Some(format!(
2151 "Arrays of {} and {} dimensions are not compatible for concatenation.",
2152 a_dims, b_dims
2153 )),
2154 EvalError::InvalidIdentifier { detail, .. } => detail.as_deref().map(Into::into),
2155 EvalError::ArrayFillWrongArraySubscripts => {
2156 Some("Low bound array has different size than dimensions array.".into())
2157 }
2158 _ => None,
2159 }
2160 }
2161
2162 pub fn hint(&self) -> Option<String> {
2163 match self {
2164 EvalError::InvalidBase64EndSequence => Some(
2165 "Input data is missing padding, is truncated, or is otherwise corrupted.".into(),
2166 ),
2167 EvalError::LikeEscapeTooLong => {
2168 Some("Escape string must be empty or one character.".into())
2169 }
2170 EvalError::MzTimestampOutOfRange(_) => Some(
2171 "Integer, numeric, and text casts to mz_timestamp must be in the form of whole \
2172 milliseconds since the Unix epoch. Values with fractional parts cannot be \
2173 converted to mz_timestamp."
2174 .into(),
2175 ),
2176 _ => None,
2177 }
2178 }
2179}
2180
2181impl std::error::Error for EvalError {}
2182
2183impl From<ParseError> for EvalError {
2184 fn from(e: ParseError) -> EvalError {
2185 EvalError::Parse(e)
2186 }
2187}
2188
2189impl From<ParseHexError> for EvalError {
2190 fn from(e: ParseHexError) -> EvalError {
2191 EvalError::ParseHex(e)
2192 }
2193}
2194
2195impl From<InvalidArrayError> for EvalError {
2196 fn from(e: InvalidArrayError) -> EvalError {
2197 EvalError::InvalidArray(e)
2198 }
2199}
2200
2201impl From<RegexCompilationError> for EvalError {
2202 fn from(e: RegexCompilationError) -> EvalError {
2203 EvalError::InvalidRegex(e.to_string().into())
2204 }
2205}
2206
2207impl From<TypeFromOidError> for EvalError {
2208 fn from(e: TypeFromOidError) -> EvalError {
2209 EvalError::TypeFromOid(e.to_string().into())
2210 }
2211}
2212
2213impl From<DateError> for EvalError {
2214 fn from(e: DateError) -> EvalError {
2215 match e {
2216 DateError::OutOfRange => EvalError::DateOutOfRange,
2217 }
2218 }
2219}
2220
2221impl From<TimestampError> for EvalError {
2222 fn from(e: TimestampError) -> EvalError {
2223 match e {
2224 TimestampError::OutOfRange => EvalError::TimestampOutOfRange,
2225 }
2226 }
2227}
2228
2229impl From<InvalidRangeError> for EvalError {
2230 fn from(e: InvalidRangeError) -> EvalError {
2231 EvalError::InvalidRange(e)
2232 }
2233}
2234
2235impl RustType<ProtoEvalError> for EvalError {
2236 fn into_proto(&self) -> ProtoEvalError {
2237 use proto_eval_error::Kind::*;
2238 use proto_eval_error::*;
2239 let kind = match self {
2240 EvalError::CharacterNotValidForEncoding(v) => CharacterNotValidForEncoding(*v),
2241 EvalError::CharacterTooLargeForEncoding(v) => CharacterTooLargeForEncoding(*v),
2242 EvalError::DateBinOutOfRange(v) => DateBinOutOfRange(v.into_proto()),
2243 EvalError::DivisionByZero => DivisionByZero(()),
2244 EvalError::Unsupported {
2245 feature,
2246 discussion_no,
2247 } => Unsupported(ProtoUnsupported {
2248 feature: feature.into_proto(),
2249 discussion_no: discussion_no.into_proto(),
2250 }),
2251 EvalError::FloatOverflow => FloatOverflow(()),
2252 EvalError::FloatUnderflow => FloatUnderflow(()),
2253 EvalError::NumericFieldOverflow => NumericFieldOverflow(()),
2254 EvalError::Float32OutOfRange(val) => Float32OutOfRange(ProtoValueOutOfRange {
2255 value: val.to_string(),
2256 }),
2257 EvalError::Float64OutOfRange(val) => Float64OutOfRange(ProtoValueOutOfRange {
2258 value: val.to_string(),
2259 }),
2260 EvalError::Int16OutOfRange(val) => Int16OutOfRange(ProtoValueOutOfRange {
2261 value: val.to_string(),
2262 }),
2263 EvalError::Int32OutOfRange(val) => Int32OutOfRange(ProtoValueOutOfRange {
2264 value: val.to_string(),
2265 }),
2266 EvalError::Int64OutOfRange(val) => Int64OutOfRange(ProtoValueOutOfRange {
2267 value: val.to_string(),
2268 }),
2269 EvalError::UInt16OutOfRange(val) => Uint16OutOfRange(ProtoValueOutOfRange {
2270 value: val.to_string(),
2271 }),
2272 EvalError::UInt32OutOfRange(val) => Uint32OutOfRange(ProtoValueOutOfRange {
2273 value: val.to_string(),
2274 }),
2275 EvalError::UInt64OutOfRange(val) => Uint64OutOfRange(ProtoValueOutOfRange {
2276 value: val.to_string(),
2277 }),
2278 EvalError::MzTimestampOutOfRange(val) => MzTimestampOutOfRange(ProtoValueOutOfRange {
2279 value: val.to_string(),
2280 }),
2281 EvalError::MzTimestampStepOverflow => MzTimestampStepOverflow(()),
2282 EvalError::OidOutOfRange(val) => OidOutOfRange(ProtoValueOutOfRange {
2283 value: val.to_string(),
2284 }),
2285 EvalError::IntervalOutOfRange(val) => IntervalOutOfRange(ProtoValueOutOfRange {
2286 value: val.to_string(),
2287 }),
2288 EvalError::TimestampCannotBeNan => TimestampCannotBeNan(()),
2289 EvalError::TimestampOutOfRange => TimestampOutOfRange(()),
2290 EvalError::DateOutOfRange => DateOutOfRange(()),
2291 EvalError::CharOutOfRange => CharOutOfRange(()),
2292 EvalError::IndexOutOfRange {
2293 provided,
2294 valid_end,
2295 } => IndexOutOfRange(ProtoIndexOutOfRange {
2296 provided: *provided,
2297 valid_end: *valid_end,
2298 }),
2299 EvalError::InvalidBase64Equals => InvalidBase64Equals(()),
2300 EvalError::InvalidBase64Symbol(sym) => InvalidBase64Symbol(sym.into_proto()),
2301 EvalError::InvalidBase64EndSequence => InvalidBase64EndSequence(()),
2302 EvalError::InvalidTimezone(tz) => InvalidTimezone(tz.into_proto()),
2303 EvalError::InvalidTimezoneInterval => InvalidTimezoneInterval(()),
2304 EvalError::InvalidTimezoneConversion => InvalidTimezoneConversion(()),
2305 EvalError::InvalidLayer { max_layer, val } => InvalidLayer(ProtoInvalidLayer {
2306 max_layer: max_layer.into_proto(),
2307 val: *val,
2308 }),
2309 EvalError::InvalidArray(error) => InvalidArray(error.into_proto()),
2310 EvalError::InvalidEncodingName(v) => InvalidEncodingName(v.into_proto()),
2311 EvalError::InvalidHashAlgorithm(v) => InvalidHashAlgorithm(v.into_proto()),
2312 EvalError::InvalidByteSequence {
2313 byte_sequence,
2314 encoding_name,
2315 } => InvalidByteSequence(ProtoInvalidByteSequence {
2316 byte_sequence: byte_sequence.into_proto(),
2317 encoding_name: encoding_name.into_proto(),
2318 }),
2319 EvalError::InvalidJsonbCast { from, to } => InvalidJsonbCast(ProtoInvalidJsonbCast {
2320 from: from.into_proto(),
2321 to: to.into_proto(),
2322 }),
2323 EvalError::InvalidRegex(v) => InvalidRegex(v.into_proto()),
2324 EvalError::InvalidRegexFlag(v) => InvalidRegexFlag(v.into_proto()),
2325 EvalError::InvalidParameterValue(v) => InvalidParameterValue(v.into_proto()),
2326 EvalError::InvalidDatePart(part) => InvalidDatePart(part.into_proto()),
2327 EvalError::KeyCannotBeNull => KeyCannotBeNull(()),
2328 EvalError::NegSqrt => NegSqrt(()),
2329 EvalError::NegLimit => NegLimit(()),
2330 EvalError::NullCharacterNotPermitted => NullCharacterNotPermitted(()),
2331 EvalError::UnknownUnits(v) => UnknownUnits(v.into_proto()),
2332 EvalError::UnsupportedUnits(units, typ) => UnsupportedUnits(ProtoUnsupportedUnits {
2333 units: units.into_proto(),
2334 typ: typ.into_proto(),
2335 }),
2336 EvalError::UnterminatedLikeEscapeSequence => UnterminatedLikeEscapeSequence(()),
2337 EvalError::Parse(error) => Parse(error.into_proto()),
2338 EvalError::PrettyError(error) => PrettyError(error.into_proto()),
2339 EvalError::RedactError(error) => RedactError(error.into_proto()),
2340 EvalError::ParseHex(error) => ParseHex(error.into_proto()),
2341 EvalError::Internal(v) => Internal(v.into_proto()),
2342 EvalError::InfinityOutOfDomain(v) => InfinityOutOfDomain(v.into_proto()),
2343 EvalError::NegativeOutOfDomain(v) => NegativeOutOfDomain(v.into_proto()),
2344 EvalError::ZeroOutOfDomain(v) => ZeroOutOfDomain(v.into_proto()),
2345 EvalError::OutOfDomain(lower, upper, id) => OutOfDomain(ProtoOutOfDomain {
2346 lower: Some(lower.into_proto()),
2347 upper: Some(upper.into_proto()),
2348 id: id.into_proto(),
2349 }),
2350 EvalError::ComplexOutOfRange(v) => ComplexOutOfRange(v.into_proto()),
2351 EvalError::MultipleRowsFromSubquery => MultipleRowsFromSubquery(()),
2352 EvalError::NegativeRowsFromSubquery => NegativeRowsFromSubquery(()),
2353 EvalError::Undefined(v) => Undefined(v.into_proto()),
2354 EvalError::LikePatternTooLong => LikePatternTooLong(()),
2355 EvalError::LikeEscapeTooLong => LikeEscapeTooLong(()),
2356 EvalError::StringValueTooLong {
2357 target_type,
2358 length,
2359 } => StringValueTooLong(ProtoStringValueTooLong {
2360 target_type: target_type.into_proto(),
2361 length: length.into_proto(),
2362 }),
2363 EvalError::MultidimensionalArrayRemovalNotSupported => {
2364 MultidimensionalArrayRemovalNotSupported(())
2365 }
2366 EvalError::IncompatibleArrayDimensions { dims } => {
2367 IncompatibleArrayDimensions(ProtoIncompatibleArrayDimensions {
2368 dims: dims.into_proto(),
2369 })
2370 }
2371 EvalError::TypeFromOid(v) => TypeFromOid(v.into_proto()),
2372 EvalError::InvalidRange(error) => InvalidRange(error.into_proto()),
2373 EvalError::InvalidRoleId(v) => InvalidRoleId(v.into_proto()),
2374 EvalError::InvalidPrivileges(v) => InvalidPrivileges(v.into_proto()),
2375 EvalError::InvalidCatalogJson(v) => InvalidCatalogJson(v.into_proto()),
2376 EvalError::LetRecLimitExceeded(v) => WmrRecursionLimitExceeded(v.into_proto()),
2377 EvalError::MultiDimensionalArraySearch => MultiDimensionalArraySearch(()),
2378 EvalError::MustNotBeNull(v) => MustNotBeNull(v.into_proto()),
2379 EvalError::InvalidIdentifier { ident, detail } => {
2380 InvalidIdentifier(ProtoInvalidIdentifier {
2381 ident: ident.into_proto(),
2382 detail: detail.into_proto(),
2383 })
2384 }
2385 EvalError::ArrayFillWrongArraySubscripts => ArrayFillWrongArraySubscripts(()),
2386 EvalError::MaxArraySizeExceeded(max_size) => {
2387 MaxArraySizeExceeded(u64::cast_from(*max_size))
2388 }
2389 EvalError::DateDiffOverflow { unit, a, b } => DateDiffOverflow(ProtoDateDiffOverflow {
2390 unit: unit.into_proto(),
2391 a: a.into_proto(),
2392 b: b.into_proto(),
2393 }),
2394 EvalError::IfNullError(s) => IfNullError(s.into_proto()),
2395 EvalError::LengthTooLarge => LengthTooLarge(()),
2396 EvalError::TempStorageBudgetExceeded => TempStorageBudgetExceeded(()),
2397 EvalError::AclArrayNullElement => AclArrayNullElement(()),
2398 EvalError::MzAclArrayNullElement => MzAclArrayNullElement(()),
2399 EvalError::InvalidIanaTimezoneId(s) => InvalidIanaTimezoneId(s.into_proto()),
2400 };
2401 ProtoEvalError { kind: Some(kind) }
2402 }
2403
2404 fn from_proto(proto: ProtoEvalError) -> Result<Self, TryFromProtoError> {
2405 use proto_eval_error::Kind::*;
2406 match proto.kind {
2407 Some(kind) => match kind {
2408 CharacterNotValidForEncoding(v) => Ok(EvalError::CharacterNotValidForEncoding(v)),
2409 CharacterTooLargeForEncoding(v) => Ok(EvalError::CharacterTooLargeForEncoding(v)),
2410 DateBinOutOfRange(v) => Ok(EvalError::DateBinOutOfRange(v.into())),
2411 DivisionByZero(()) => Ok(EvalError::DivisionByZero),
2412 Unsupported(v) => Ok(EvalError::Unsupported {
2413 feature: v.feature.into(),
2414 discussion_no: v.discussion_no.into_rust()?,
2415 }),
2416 FloatOverflow(()) => Ok(EvalError::FloatOverflow),
2417 FloatUnderflow(()) => Ok(EvalError::FloatUnderflow),
2418 NumericFieldOverflow(()) => Ok(EvalError::NumericFieldOverflow),
2419 Float32OutOfRange(val) => Ok(EvalError::Float32OutOfRange(val.value.into())),
2420 Float64OutOfRange(val) => Ok(EvalError::Float64OutOfRange(val.value.into())),
2421 Int16OutOfRange(val) => Ok(EvalError::Int16OutOfRange(val.value.into())),
2422 Int32OutOfRange(val) => Ok(EvalError::Int32OutOfRange(val.value.into())),
2423 Int64OutOfRange(val) => Ok(EvalError::Int64OutOfRange(val.value.into())),
2424 Uint16OutOfRange(val) => Ok(EvalError::UInt16OutOfRange(val.value.into())),
2425 Uint32OutOfRange(val) => Ok(EvalError::UInt32OutOfRange(val.value.into())),
2426 Uint64OutOfRange(val) => Ok(EvalError::UInt64OutOfRange(val.value.into())),
2427 MzTimestampOutOfRange(val) => {
2428 Ok(EvalError::MzTimestampOutOfRange(val.value.into()))
2429 }
2430 MzTimestampStepOverflow(()) => Ok(EvalError::MzTimestampStepOverflow),
2431 OidOutOfRange(val) => Ok(EvalError::OidOutOfRange(val.value.into())),
2432 IntervalOutOfRange(val) => Ok(EvalError::IntervalOutOfRange(val.value.into())),
2433 TimestampCannotBeNan(()) => Ok(EvalError::TimestampCannotBeNan),
2434 TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange),
2435 DateOutOfRange(()) => Ok(EvalError::DateOutOfRange),
2436 CharOutOfRange(()) => Ok(EvalError::CharOutOfRange),
2437 IndexOutOfRange(v) => Ok(EvalError::IndexOutOfRange {
2438 provided: v.provided,
2439 valid_end: v.valid_end,
2440 }),
2441 InvalidBase64Equals(()) => Ok(EvalError::InvalidBase64Equals),
2442 InvalidBase64Symbol(v) => char::from_proto(v).map(EvalError::InvalidBase64Symbol),
2443 InvalidBase64EndSequence(()) => Ok(EvalError::InvalidBase64EndSequence),
2444 InvalidTimezone(v) => Ok(EvalError::InvalidTimezone(v.into())),
2445 InvalidTimezoneInterval(()) => Ok(EvalError::InvalidTimezoneInterval),
2446 InvalidTimezoneConversion(()) => Ok(EvalError::InvalidTimezoneConversion),
2447 InvalidLayer(v) => Ok(EvalError::InvalidLayer {
2448 max_layer: usize::from_proto(v.max_layer)?,
2449 val: v.val,
2450 }),
2451 InvalidArray(error) => Ok(EvalError::InvalidArray(error.into_rust()?)),
2452 InvalidEncodingName(v) => Ok(EvalError::InvalidEncodingName(v.into())),
2453 InvalidHashAlgorithm(v) => Ok(EvalError::InvalidHashAlgorithm(v.into())),
2454 InvalidByteSequence(v) => Ok(EvalError::InvalidByteSequence {
2455 byte_sequence: v.byte_sequence.into(),
2456 encoding_name: v.encoding_name.into(),
2457 }),
2458 InvalidJsonbCast(v) => Ok(EvalError::InvalidJsonbCast {
2459 from: v.from.into(),
2460 to: v.to.into(),
2461 }),
2462 InvalidRegex(v) => Ok(EvalError::InvalidRegex(v.into())),
2463 InvalidRegexFlag(v) => Ok(EvalError::InvalidRegexFlag(char::from_proto(v)?)),
2464 InvalidParameterValue(v) => Ok(EvalError::InvalidParameterValue(v.into())),
2465 InvalidDatePart(part) => Ok(EvalError::InvalidDatePart(part.into())),
2466 KeyCannotBeNull(()) => Ok(EvalError::KeyCannotBeNull),
2467 NegSqrt(()) => Ok(EvalError::NegSqrt),
2468 NegLimit(()) => Ok(EvalError::NegLimit),
2469 NullCharacterNotPermitted(()) => Ok(EvalError::NullCharacterNotPermitted),
2470 UnknownUnits(v) => Ok(EvalError::UnknownUnits(v.into())),
2471 UnsupportedUnits(v) => {
2472 Ok(EvalError::UnsupportedUnits(v.units.into(), v.typ.into()))
2473 }
2474 UnterminatedLikeEscapeSequence(()) => Ok(EvalError::UnterminatedLikeEscapeSequence),
2475 Parse(error) => Ok(EvalError::Parse(error.into_rust()?)),
2476 ParseHex(error) => Ok(EvalError::ParseHex(error.into_rust()?)),
2477 Internal(v) => Ok(EvalError::Internal(v.into())),
2478 InfinityOutOfDomain(v) => Ok(EvalError::InfinityOutOfDomain(v.into())),
2479 NegativeOutOfDomain(v) => Ok(EvalError::NegativeOutOfDomain(v.into())),
2480 ZeroOutOfDomain(v) => Ok(EvalError::ZeroOutOfDomain(v.into())),
2481 OutOfDomain(v) => Ok(EvalError::OutOfDomain(
2482 v.lower.into_rust_if_some("ProtoDomainLimit::lower")?,
2483 v.upper.into_rust_if_some("ProtoDomainLimit::upper")?,
2484 v.id.into(),
2485 )),
2486 ComplexOutOfRange(v) => Ok(EvalError::ComplexOutOfRange(v.into())),
2487 MultipleRowsFromSubquery(()) => Ok(EvalError::MultipleRowsFromSubquery),
2488 NegativeRowsFromSubquery(()) => Ok(EvalError::NegativeRowsFromSubquery),
2489 Undefined(v) => Ok(EvalError::Undefined(v.into())),
2490 LikePatternTooLong(()) => Ok(EvalError::LikePatternTooLong),
2491 LikeEscapeTooLong(()) => Ok(EvalError::LikeEscapeTooLong),
2492 StringValueTooLong(v) => Ok(EvalError::StringValueTooLong {
2493 target_type: v.target_type.into(),
2494 length: usize::from_proto(v.length)?,
2495 }),
2496 MultidimensionalArrayRemovalNotSupported(()) => {
2497 Ok(EvalError::MultidimensionalArrayRemovalNotSupported)
2498 }
2499 IncompatibleArrayDimensions(v) => Ok(EvalError::IncompatibleArrayDimensions {
2500 dims: v.dims.into_rust()?,
2501 }),
2502 TypeFromOid(v) => Ok(EvalError::TypeFromOid(v.into())),
2503 InvalidRange(e) => Ok(EvalError::InvalidRange(e.into_rust()?)),
2504 InvalidRoleId(v) => Ok(EvalError::InvalidRoleId(v.into())),
2505 InvalidPrivileges(v) => Ok(EvalError::InvalidPrivileges(v.into())),
2506 InvalidCatalogJson(v) => Ok(EvalError::InvalidCatalogJson(v.into())),
2507 WmrRecursionLimitExceeded(v) => Ok(EvalError::LetRecLimitExceeded(v.into())),
2508 MultiDimensionalArraySearch(()) => Ok(EvalError::MultiDimensionalArraySearch),
2509 MustNotBeNull(v) => Ok(EvalError::MustNotBeNull(v.into())),
2510 InvalidIdentifier(v) => Ok(EvalError::InvalidIdentifier {
2511 ident: v.ident.into(),
2512 detail: v.detail.into_rust()?,
2513 }),
2514 ArrayFillWrongArraySubscripts(()) => Ok(EvalError::ArrayFillWrongArraySubscripts),
2515 MaxArraySizeExceeded(max_size) => {
2516 Ok(EvalError::MaxArraySizeExceeded(usize::cast_from(max_size)))
2517 }
2518 DateDiffOverflow(v) => Ok(EvalError::DateDiffOverflow {
2519 unit: v.unit.into(),
2520 a: v.a.into(),
2521 b: v.b.into(),
2522 }),
2523 IfNullError(v) => Ok(EvalError::IfNullError(v.into())),
2524 LengthTooLarge(()) => Ok(EvalError::LengthTooLarge),
2525 TempStorageBudgetExceeded(()) => Ok(EvalError::TempStorageBudgetExceeded),
2526 AclArrayNullElement(()) => Ok(EvalError::AclArrayNullElement),
2527 MzAclArrayNullElement(()) => Ok(EvalError::MzAclArrayNullElement),
2528 InvalidIanaTimezoneId(s) => Ok(EvalError::InvalidIanaTimezoneId(s.into())),
2529 PrettyError(s) => Ok(EvalError::PrettyError(s.into())),
2530 RedactError(s) => Ok(EvalError::RedactError(s.into())),
2531 },
2532 None => Err(TryFromProtoError::missing_field("ProtoEvalError::kind")),
2533 }
2534 }
2535}
2536
2537impl RustType<ProtoDims> for (usize, usize) {
2538 fn into_proto(&self) -> ProtoDims {
2539 ProtoDims {
2540 f0: self.0.into_proto(),
2541 f1: self.1.into_proto(),
2542 }
2543 }
2544
2545 fn from_proto(proto: ProtoDims) -> Result<Self, TryFromProtoError> {
2546 Ok((proto.f0.into_rust()?, proto.f1.into_rust()?))
2547 }
2548}
2549
2550#[derive(
2564 Clone,
2565 Debug,
2566 Eq,
2567 PartialEq,
2568 Ord,
2569 PartialOrd,
2570 Hash,
2571 Serialize,
2572 Deserialize
2573)]
2574pub struct StableEvalError(#[serde(with = "stable_eval_error_proto")] pub EvalError);
2575
2576#[derive(Debug, Serialize)]
2579#[serde(rename = "StableEvalError")]
2580pub struct StableEvalErrorRef<'a>(#[serde(with = "stable_eval_error_proto")] pub &'a EvalError);
2581
2582impl From<EvalError> for StableEvalError {
2583 fn from(err: EvalError) -> Self {
2584 StableEvalError(err)
2585 }
2586}
2587
2588impl std::ops::Deref for StableEvalError {
2589 type Target = EvalError;
2590
2591 fn deref(&self) -> &EvalError {
2592 &self.0
2593 }
2594}
2595
2596mod stable_eval_error_proto {
2597 use mz_proto::RustType;
2598 use prost::Message;
2599 use serde::de::Error;
2600 use serde::{Deserialize, Deserializer, Serializer};
2601
2602 use crate::scalar::{EvalError, ProtoEvalError};
2603
2604 pub fn serialize<S: Serializer, E: std::borrow::Borrow<EvalError>>(
2605 err: &E,
2606 serializer: S,
2607 ) -> Result<S::Ok, S::Error> {
2608 serializer.serialize_bytes(&err.borrow().into_proto().encode_to_vec())
2609 }
2610
2611 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<EvalError, D::Error> {
2612 let bytes = serde_bytes::ByteBuf::deserialize(deserializer)?;
2613 let proto = ProtoEvalError::decode(bytes.as_slice()).map_err(D::Error::custom)?;
2614 EvalError::from_proto(proto).map_err(D::Error::custom)
2615 }
2616}
2617
2618#[cfg(test)]
2619mod tests {
2620 use super::*;
2621 use crate::scalar::func::variadic::Coalesce;
2622
2623 proptest! {
2629 #![proptest_config(ProptestConfig::with_cases(1000))]
2630
2631 #[mz_ore::test]
2632 #[cfg_attr(miri, ignore)] fn stable_eval_error_serde_roundtrip(err in any::<EvalError>()) {
2634 let stable = StableEvalError(err);
2635
2636 let json = serde_json::to_string(&stable).expect("serializes to JSON");
2637 let from_json: StableEvalError =
2638 serde_json::from_str(&json).expect("deserializes from JSON");
2639 prop_assert_eq!(&stable, &from_json);
2640
2641 let bytes = bincode::serialize(&stable).expect("serializes to bincode");
2642 let from_bincode: StableEvalError =
2643 bincode::deserialize(&bytes).expect("deserializes from bincode");
2644 prop_assert_eq!(&stable, &from_bincode);
2645 }
2646 }
2647
2648 #[mz_ore::test]
2653 fn test_unbounded_out_of_domain_renders() {
2654 let err = EvalError::OutOfDomain(DomainLimit::None, DomainLimit::None, "f".into());
2655 assert_eq!(
2656 err.to_string(),
2657 "function f is defined for numbers in an unspecified range"
2658 );
2659 }
2660
2661 #[mz_ore::test]
2666 #[cfg_attr(miri, ignore)] fn test_repeat_respects_arena_budget() {
2668 use crate::scalar::func::RepeatString;
2669
2670 let body = "a".repeat(1024 * 1024);
2671 let expr = MirScalarExpr::column(0).call_binary(
2672 MirScalarExpr::literal_ok(Datum::Int32(20), ReprScalarType::Int32),
2673 RepeatString,
2674 );
2675 let datums = [Datum::String(&body)];
2676
2677 let arena = RowArena::new();
2679 let datum = expr
2680 .eval(&datums, &arena)
2681 .expect("under the 100 MiB ceiling");
2682 assert_eq!(datum.unwrap_str().len(), 20 * 1024 * 1024);
2683 assert!(arena.allocated_bytes() >= 20 * 1024 * 1024);
2684
2685 let arena = RowArena::with_budget(4 * 1024 * 1024);
2688 assert_eq!(
2689 expr.eval(&datums, &arena),
2690 Err(EvalError::LengthTooLarge),
2691 "an over-budget result must be refused"
2692 );
2693 assert_eq!(arena.allocated_bytes(), 0);
2694
2695 let arena = RowArena::with_budget(64 * 1024 * 1024);
2697 let datum = expr.eval(&datums, &arena).expect("within budget");
2698 assert_eq!(datum.unwrap_str().len(), 20 * 1024 * 1024);
2699 }
2700
2701 #[mz_ore::test]
2705 #[cfg_attr(miri, ignore)] fn test_arena_built_result_respects_budget() {
2707 use crate::scalar::func::variadic::{RegexpSplitToArray, StringToArray};
2708
2709 let body = "a".repeat(256 * 1024);
2710 let expr = MirScalarExpr::call_variadic(
2711 StringToArray,
2712 vec![
2713 MirScalarExpr::column(0),
2714 MirScalarExpr::literal_ok(Datum::String("a"), ReprScalarType::String),
2715 ],
2716 );
2717 let datums = [Datum::String(&body)];
2718
2719 let arena = RowArena::new();
2720 expr.eval(&datums, &arena).expect("no ceiling applies");
2721 let unbudgeted = arena.allocated_bytes();
2722 assert!(unbudgeted > 0);
2723
2724 let arena = RowArena::with_budget(unbudgeted / 2);
2725 assert_eq!(
2726 expr.eval(&datums, &arena),
2727 Err(EvalError::TempStorageBudgetExceeded),
2728 "an over-budget arena-built result must be refused"
2729 );
2730
2731 let intermediate = (body.len() + 1) * std::mem::size_of::<&str>();
2734 let budget = 4 * unbudgeted;
2735 assert!(
2736 unbudgeted < budget && budget < intermediate,
2737 "budget sits between"
2738 );
2739 let arena = RowArena::with_budget(budget);
2740 assert!(
2741 expr.eval(&datums, &arena).is_err(),
2742 "a split costing {intermediate} bytes to build must be refused by a {budget} byte budget"
2743 );
2744 assert_eq!(
2745 arena.allocated_bytes(),
2746 0,
2747 "refused before the transient was built"
2748 );
2749
2750 let regexp_expr = MirScalarExpr::call_variadic(
2752 RegexpSplitToArray,
2753 vec![
2754 MirScalarExpr::column(0),
2755 MirScalarExpr::literal_ok(Datum::String("a"), ReprScalarType::String),
2756 ],
2757 );
2758 let arena = RowArena::with_budget(budget);
2759 assert!(
2760 regexp_expr.eval(&datums, &arena).is_err(),
2761 "a regexp split costing {intermediate} bytes to build must be refused too"
2762 );
2763 assert_eq!(arena.allocated_bytes(), 0);
2764 }
2765
2766 #[mz_ore::test]
2771 #[cfg_attr(miri, ignore)] fn test_array_fill_respects_arena_budget() {
2773 use crate::scalar::func::variadic::ArrayFill;
2774 use mz_repr::adt::array::ArrayDimension;
2775
2776 let fill_count: usize = 512 * 1024;
2778 let dims_storage = RowArena::new();
2779 let dims = dims_storage
2780 .try_make_datum(|packer| {
2781 packer.try_push_array(
2782 &[ArrayDimension {
2783 lower_bound: 1,
2784 length: 1,
2785 }],
2786 [Datum::Int32(i32::try_from(fill_count).unwrap())],
2787 )
2788 })
2789 .unwrap();
2790 let expr = MirScalarExpr::call_variadic(
2791 ArrayFill {
2792 elem_type: mz_repr::SqlScalarType::Int32,
2793 },
2794 vec![MirScalarExpr::column(0), MirScalarExpr::column(1)],
2795 );
2796 let datums = [Datum::Int32(1), dims];
2797
2798 let arena = RowArena::new();
2800 expr.eval(&datums, &arena)
2801 .expect("under the array-size ceiling");
2802 assert!(arena.allocated_bytes() > 0);
2803
2804 let arena = RowArena::with_budget(1024 * 1024);
2807 assert_eq!(
2808 expr.eval(&datums, &arena),
2809 Err(EvalError::TempStorageBudgetExceeded),
2810 "an over-budget array_fill must be refused before it allocates"
2811 );
2812 assert_eq!(arena.allocated_bytes(), 0);
2813
2814 let arena = RowArena::with_budget(256 * 1024 * 1024);
2816 expr.eval(&datums, &arena).expect("within budget");
2817 }
2818
2819 #[mz_ore::test]
2823 #[cfg_attr(miri, ignore)] fn test_array_remove_respects_arena_budget() {
2825 use crate::scalar::func::ArrayRemove;
2826 use mz_repr::adt::array::ArrayDimension;
2827
2828 const ELEMS: usize = 256 * 1024;
2829 let input_storage = RowArena::new();
2830 let array = input_storage
2831 .try_make_datum(|packer| {
2832 packer.try_push_array(
2833 &[ArrayDimension {
2834 lower_bound: 1,
2835 length: ELEMS,
2836 }],
2837 (0..ELEMS).map(|i| Datum::Int32(i32::try_from(i).unwrap())),
2838 )
2839 })
2840 .unwrap();
2841 let expr = MirScalarExpr::column(0).call_binary(MirScalarExpr::column(1), ArrayRemove);
2842 let datums = [array, Datum::Int32(0)];
2843
2844 let arena = RowArena::new();
2846 expr.eval(&datums, &arena).expect("no ceiling applies");
2847 let unbudgeted = arena.allocated_bytes();
2848 assert!(unbudgeted > 0);
2849
2850 let transient = ELEMS * std::mem::size_of::<Datum<'_>>();
2853 let budget = 2 * unbudgeted;
2854 assert!(budget < transient, "budget sits between");
2855 let arena = RowArena::with_budget(budget);
2856 assert_eq!(
2857 expr.eval(&datums, &arena),
2858 Err(EvalError::TempStorageBudgetExceeded),
2859 "an over-budget transient must be refused"
2860 );
2861 assert_eq!(arena.allocated_bytes(), 0);
2862
2863 let arena = RowArena::with_budget(64 * 1024 * 1024);
2865 expr.eval(&datums, &arena).expect("within budget");
2866 }
2867
2868 #[mz_ore::test]
2877 #[cfg_attr(miri, ignore)] fn test_single_call_respects_arena_budget() {
2879 use mz_ore::cast::CastLossy;
2880
2881 use crate::scalar::func::variadic::{ArrayCreate, PadLeading, Translate};
2882
2883 const BODY_BYTES: usize = 1024 * 1024;
2886 const BUDGET: usize = 2 * 1024 * 1024;
2887 const WIDE: &str = "\u{1F4A5}"; let str_lit = |s| MirScalarExpr::literal_ok(Datum::String(s), ReprScalarType::String);
2890 let array_of = |n| {
2893 let elem_type = mz_repr::SqlScalarType::String;
2894 let refs = vec![MirScalarExpr::column(0); n];
2895 MirScalarExpr::call_variadic(ArrayCreate { elem_type }, refs)
2896 };
2897 let cases = [
2898 ("ARRAY[body x4]", array_of(4)),
2899 ("ARRAY[body x16]", array_of(16)),
2900 (
2903 "lpad(body, BUDGET, wide)",
2904 MirScalarExpr::call_variadic(
2905 PadLeading,
2906 vec![
2907 MirScalarExpr::column(0),
2908 MirScalarExpr::literal_ok(
2909 Datum::Int32(i32::try_from(BUDGET).unwrap()),
2910 ReprScalarType::Int32,
2911 ),
2912 str_lit(WIDE),
2913 ],
2914 ),
2915 ),
2916 (
2919 "translate(body, 'a', wide)",
2920 MirScalarExpr::call_variadic(
2921 Translate,
2922 vec![MirScalarExpr::column(0), str_lit("a"), str_lit(WIDE)],
2923 ),
2924 ),
2925 ];
2926
2927 let body = "a".repeat(BODY_BYTES);
2928 let datums = [Datum::String(&body)];
2929 let mut over = Vec::new();
2930 for (name, expr) in cases {
2931 let arena = RowArena::with_budget(BUDGET);
2932 let _ = expr.eval(&datums, &arena); let held = arena.allocated_bytes();
2934 if held > BUDGET {
2935 let ratio = f64::cast_lossy(held) / f64::cast_lossy(BUDGET);
2936 over.push(format!(" {name}: held {held} bytes, {ratio:.1}x"));
2937 }
2938 }
2939 assert!(
2940 over.is_empty(),
2941 "a single call left a {BUDGET} byte arena holding more:\n{}",
2942 over.join("\n"),
2943 );
2944 }
2945
2946 #[mz_ore::test]
2947 #[cfg_attr(miri, ignore)] fn test_reduce() {
2949 let relation_type: Vec<ReprColumnType> = vec![
2950 ReprScalarType::Int64.nullable(true),
2951 ReprScalarType::Int64.nullable(true),
2952 ReprScalarType::Int64.nullable(false),
2953 ]
2954 .into_iter()
2955 .collect();
2956 let col = MirScalarExpr::column;
2957 let int64_typ = ReprScalarType::Int64;
2958 let err = |e| MirScalarExpr::literal(Err(e), int64_typ.clone());
2959 let lit = |i| MirScalarExpr::literal_ok(Datum::Int64(i), int64_typ.clone());
2960 let null = || MirScalarExpr::literal_null(int64_typ.clone());
2961
2962 struct TestCase {
2963 input: MirScalarExpr,
2964 output: MirScalarExpr,
2965 }
2966
2967 let test_cases = vec![
2968 TestCase {
2969 input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1)]),
2970 output: lit(1),
2971 },
2972 TestCase {
2973 input: MirScalarExpr::call_variadic(Coalesce, vec![lit(1), lit(2)]),
2974 output: lit(1),
2975 },
2976 TestCase {
2977 input: MirScalarExpr::call_variadic(Coalesce, vec![null(), lit(2), null()]),
2978 output: lit(2),
2979 },
2980 TestCase {
2981 input: MirScalarExpr::call_variadic(
2982 Coalesce,
2983 vec![null(), col(0), null(), col(1), lit(2), lit(3)],
2984 ),
2985 output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(1), lit(2)]),
2986 },
2987 TestCase {
2988 input: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2), col(1)]),
2989 output: MirScalarExpr::call_variadic(Coalesce, vec![col(0), col(2)]),
2990 },
2991 TestCase {
2992 input: MirScalarExpr::call_variadic(
2993 Coalesce,
2994 vec![lit(1), err(EvalError::DivisionByZero)],
2995 ),
2996 output: lit(1),
2997 },
2998 TestCase {
2999 input: MirScalarExpr::call_variadic(
3000 Coalesce,
3001 vec![
3002 null(),
3003 err(EvalError::DivisionByZero),
3004 err(EvalError::NumericFieldOverflow),
3005 ],
3006 ),
3007 output: err(EvalError::DivisionByZero),
3008 },
3009 ];
3010
3011 for tc in test_cases {
3012 let mut actual = tc.input.clone();
3013 actual.reduce(&relation_type);
3014 assert!(
3015 actual == tc.output,
3016 "input: {}\nactual: {}\nexpected: {}",
3017 tc.input,
3018 actual,
3019 tc.output
3020 );
3021 }
3022 }
3023
3024 #[mz_ore::test]
3028 fn test_visit_mut_post_replace_subtrees() {
3029 let col = MirScalarExpr::column;
3030 let mut expr = col(0).if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
3031
3032 expr.visit_mut_post(&mut |expr: &mut MirScalarExpr| match expr {
3033 MirScalarExpr::Column(n, _) => *n += 1,
3034 MirScalarExpr::If { then, .. } => {
3035 let then = then.take();
3036 *expr = then;
3037 }
3038 _ => {}
3039 });
3040
3041 assert_eq!(expr, col(3));
3043 }
3044
3045 #[mz_ore::test]
3051 fn test_visit_mut_pre_post_explicit_children() {
3052 let col = MirScalarExpr::column;
3053 let mut expr = col(5)
3054 .if_then_else(col(6), col(7))
3055 .if_then_else(col(1).if_then_else(col(2), col(3)), col(4));
3056
3057 expr.visit_mut_pre_post(
3061 &mut |expr: &mut MirScalarExpr| -> Option<Vec<&mut MirScalarExpr>> {
3062 if let MirScalarExpr::If { .. } = expr {
3063 let MirScalarExpr::If { then, els, .. } = expr else {
3064 unreachable!()
3065 };
3066 let then = then.take();
3067 let els = els.take();
3068 *expr = MirScalarExpr::column(0).if_then_else(then, els);
3069
3070 let MirScalarExpr::If { then, els, .. } = expr else {
3071 unreachable!()
3072 };
3073 Some(vec![then.as_mut(), els.as_mut()])
3074 } else {
3075 None
3077 }
3078 },
3079 &mut |expr: &mut MirScalarExpr| {
3080 if let MirScalarExpr::Column(n, _) = expr {
3081 *n += 10;
3082 }
3083 },
3084 );
3085
3086 let expected = col(0).if_then_else(col(0).if_then_else(col(12), col(13)), col(14));
3088 assert_eq!(expr, expected);
3089 }
3090}