mz_expr/scalar/
optimizable.rs1use std::fmt::Debug;
16use std::hash::Hash;
17
18use serde::Serialize;
19
20use crate::scalar::columns::Columns;
21use crate::scalar::func::{BinaryFunc, UnaryFunc, VariadicFunc};
22use crate::visit::VisitChildren;
23use crate::{MirScalarExpr, func};
24
25pub trait OptimizableExpr:
29 Columns + VisitChildren<Self> + Clone + Eq + Ord + Hash + Debug + Sized + Serialize
30{
31 fn is_literal(&self) -> bool;
33
34 fn is_literal_err(&self) -> bool;
36
37 fn contains_temporal(&self) -> bool;
39
40 fn size(&self) -> usize;
42
43 fn eager_children(&mut self) -> Option<Vec<&mut Self>>;
49
50 fn equality_column_alias(predicate: &Self, expr: &Self, threshold: usize) -> Option<Self>;
55
56 fn extract_temporal_bounds(temporal: Vec<Self>) -> Result<(Vec<Self>, Vec<Self>), String>;
60}
61
62impl OptimizableExpr for MirScalarExpr {
63 fn is_literal(&self) -> bool {
64 self.is_literal()
65 }
66
67 fn is_literal_err(&self) -> bool {
68 self.is_literal_err()
69 }
70
71 fn contains_temporal(&self) -> bool {
72 self.contains_temporal()
73 }
74
75 fn size(&self) -> usize {
76 self.size()
77 }
78
79 fn eager_children(&mut self) -> Option<Vec<&mut Self>> {
80 if let MirScalarExpr::If { cond, .. } = self {
82 return Some(vec![cond]);
83 }
84
85 if let MirScalarExpr::CallVariadic {
89 func: VariadicFunc::Coalesce(_),
90 exprs,
91 } = self
92 {
93 return Some(exprs.iter_mut().take(1).collect());
94 }
95
96 if let Ok((_func, other_side)) = self.as_mut_temporal_filter() {
100 return Some(vec![other_side]);
101 }
102
103 None
104 }
105
106 fn equality_column_alias(predicate: &Self, expr: &Self, threshold: usize) -> Option<Self> {
107 if let MirScalarExpr::CallBinary {
108 func: BinaryFunc::Eq(_),
109 expr1,
110 expr2,
111 } = predicate
112 {
113 if let MirScalarExpr::Column(c, name) = &**expr1 {
114 if *c < threshold && &**expr2 == expr {
115 return Some(MirScalarExpr::Column(*c, name.clone()));
116 }
117 }
118 if let MirScalarExpr::Column(c, name) = &**expr2 {
119 if *c < threshold && &**expr1 == expr {
120 return Some(MirScalarExpr::Column(*c, name.clone()));
121 }
122 }
123 }
124 None
125 }
126
127 fn extract_temporal_bounds(temporal: Vec<Self>) -> Result<(Vec<Self>, Vec<Self>), String> {
128 let mut lower_bounds = Vec::new();
129 let mut upper_bounds = Vec::new();
130
131 for mut predicate in temporal.into_iter() {
132 let (func, expr2) = predicate.as_mut_temporal_filter()?;
133 let expr2 = expr2.clone();
134
135 match func {
136 BinaryFunc::Eq(_) => {
137 lower_bounds.push(expr2.clone());
138 upper_bounds
139 .push(expr2.call_unary(UnaryFunc::StepMzTimestamp(func::StepMzTimestamp)));
140 }
141 BinaryFunc::Lt(_) => {
142 upper_bounds.push(expr2.clone());
143 }
144 BinaryFunc::Lte(_) => {
145 upper_bounds
146 .push(expr2.call_unary(UnaryFunc::StepMzTimestamp(func::StepMzTimestamp)));
147 }
148 BinaryFunc::Gt(_) => {
149 lower_bounds
150 .push(expr2.call_unary(UnaryFunc::StepMzTimestamp(func::StepMzTimestamp)));
151 }
152 BinaryFunc::Gte(_) => {
153 lower_bounds.push(expr2.clone());
154 }
155 _ => {
156 return Err(format!("Unsupported binary temporal operation: {:?}", func));
157 }
158 }
159 }
160
161 Ok((lower_bounds, upper_bounds))
162 }
163}