1use std::fmt::Display as _;
16use std::sync::Arc;
17
18use itertools::Itertools;
19use mz_expr::explain::{HumanizedExplain, HumanizedExpr, HumanizerMode};
20use mz_expr::{
21 BinaryFunc, Columns, Eval, EvalError, MapFilterProject, MfpPlan, MirScalarExpr,
22 OptimizableExpr, SafeMfpPlan, UnaryFunc, UnmaterializableFunc, VariadicFunc,
23};
24use mz_ore::str::separated;
25use mz_ore::treat_as_equal::TreatAsEqual;
26use mz_repr::explain::ScalarOps;
27use mz_repr::{Datum, ReprColumnType, ReprScalarType, Row, RowArena, StableRow};
28use serde::{Deserialize, Serialize};
29
30#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
33pub enum LirScalarExpr {
34 Column(usize, TreatAsEqual<Option<Arc<str>>>),
36 Literal(
39 #[serde(with = "literal_value_serde")] Result<StableRow, EvalError>,
40 ReprColumnType,
41 ),
42 CallUnary {
44 func: UnaryFunc<LirScalarExpr>,
46 expr: Box<LirScalarExpr>,
48 },
49 CallBinary {
51 func: BinaryFunc,
53 expr1: Box<LirScalarExpr>,
55 expr2: Box<LirScalarExpr>,
57 },
58 CallVariadic {
60 func: VariadicFunc,
62 exprs: Vec<LirScalarExpr>,
64 },
65 If {
72 cond: Box<LirScalarExpr>,
74 then: Box<LirScalarExpr>,
76 els: Box<LirScalarExpr>,
78 },
79}
80
81pub use literal_value_serde::LiteralValue;
82
83mod literal_value_serde {
91 use mz_expr::{EvalError, StableEvalError, StableEvalErrorRef};
92 use mz_repr::StableRow;
93 use serde::{Deserialize, Deserializer, Serialize, Serializer};
94
95 #[derive(Debug, Serialize, Deserialize)]
97 pub enum LiteralValue {
98 Ok(StableRow),
100 Err(StableEvalError),
102 }
103
104 #[derive(Serialize)]
106 #[serde(rename = "LiteralValue")]
107 enum LiteralValueRef<'a> {
108 Ok(&'a StableRow),
109 Err(StableEvalErrorRef<'a>),
110 }
111
112 pub fn serialize<S: Serializer>(
113 value: &Result<StableRow, EvalError>,
114 serializer: S,
115 ) -> Result<S::Ok, S::Error> {
116 let mirror = match value {
117 Ok(row) => LiteralValueRef::Ok(row),
118 Err(err) => LiteralValueRef::Err(StableEvalErrorRef(err)),
119 };
120 mirror.serialize(serializer)
121 }
122
123 pub fn deserialize<'de, D: Deserializer<'de>>(
124 deserializer: D,
125 ) -> Result<Result<StableRow, EvalError>, D::Error> {
126 Ok(match LiteralValue::deserialize(deserializer)? {
127 LiteralValue::Ok(row) => Ok(row),
128 LiteralValue::Err(err) => Err(err.0),
129 })
130 }
131}
132
133impl LirScalarExpr {
134 pub fn column(c: usize) -> Self {
136 LirScalarExpr::Column(c, TreatAsEqual(None))
137 }
138
139 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| StableRow(Row::pack_slice(&[datum])));
146 LirScalarExpr::Literal(row, typ)
147 }
148
149 pub fn literal_ok(datum: Datum, typ: ReprScalarType) -> Self {
151 LirScalarExpr::literal(Ok(datum), typ)
152 }
153
154 pub fn as_literal(&self) -> Option<Result<Datum<'_>, &EvalError>> {
157 if let LirScalarExpr::Literal(lit, _column_type) = self {
158 Some(lit.as_ref().map(|row| row.unpack_first()))
159 } else {
160 None
161 }
162 }
163
164 pub fn is_literal_true(&self) -> bool {
166 Some(Ok(Datum::True)) == self.as_literal()
167 }
168
169 pub fn as_literal_int64(&self) -> Option<i64> {
171 match self.as_literal() {
172 Some(Ok(Datum::Int64(i))) => Some(i),
173 _ => None,
174 }
175 }
176
177 pub fn call_unary<U: Into<UnaryFunc<LirScalarExpr>>>(self, func: U) -> Self {
179 LirScalarExpr::CallUnary {
180 func: func.into(),
181 expr: Box::new(self),
182 }
183 }
184
185 pub fn call_binary<B: Into<BinaryFunc>>(self, other: Self, func: B) -> Self {
187 LirScalarExpr::CallBinary {
188 func: func.into(),
189 expr1: Box::new(self),
190 expr2: Box::new(other),
191 }
192 }
193
194 pub fn visit_pre<F>(&self, mut f: F)
196 where
197 F: FnMut(&Self),
198 {
199 let mut worklist = vec![self];
200 while let Some(e) = worklist.pop() {
201 f(e);
202 worklist.extend(e.children().rev());
203 }
204 }
205
206 pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, mut f: F) {
208 let mut worklist = vec![self];
209 while let Some(expr) = worklist.pop() {
210 f(expr);
211 worklist.extend(expr.children_mut().rev());
212 }
213 }
214
215 pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self> {
217 let mut first = None;
218 let mut second = None;
219 let mut third = None;
220 let mut variadic = None;
221
222 use LirScalarExpr::*;
223 match self {
224 Column(_, _) | Literal(_, _) => (),
225 CallUnary { expr, .. } => {
226 first = Some(&**expr);
227 }
228 CallBinary { expr1, expr2, .. } => {
229 first = Some(&**expr1);
230 second = Some(&**expr2);
231 }
232 CallVariadic { exprs, .. } => {
233 variadic = Some(exprs);
234 }
235 If { cond, then, els } => {
236 first = Some(&**cond);
237 second = Some(&**then);
238 third = Some(&**els);
239 }
240 }
241
242 first
243 .into_iter()
244 .chain(second)
245 .chain(third)
246 .chain(variadic.into_iter().flatten())
247 }
248
249 pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self> {
251 let mut first = None;
252 let mut second = None;
253 let mut third = None;
254 let mut variadic = None;
255
256 use LirScalarExpr::*;
257 match self {
258 Column(_, _) | Literal(_, _) => (),
259 CallUnary { expr, .. } => {
260 first = Some(&mut **expr);
261 }
262 CallBinary { expr1, expr2, .. } => {
263 first = Some(&mut **expr1);
264 second = Some(&mut **expr2);
265 }
266 CallVariadic { exprs, .. } => {
267 variadic = Some(exprs);
268 }
269 If { cond, then, els } => {
270 first = Some(&mut **cond);
271 second = Some(&mut **then);
272 third = Some(&mut **els);
273 }
274 }
275
276 first
277 .into_iter()
278 .chain(second)
279 .chain(third)
280 .chain(variadic.into_iter().flatten())
281 }
282}
283
284impl mz_expr::visit::VisitChildren<LirScalarExpr> for LirScalarExpr {
285 fn visit_children<F>(&self, f: F)
286 where
287 F: FnMut(&Self),
288 {
289 self.children().for_each(f);
290 }
291
292 fn visit_mut_children<F>(&mut self, f: F)
293 where
294 F: FnMut(&mut Self),
295 {
296 self.children_mut().for_each(f);
297 }
298
299 fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
300 where
301 F: FnMut(&Self) -> Result<(), E>,
302 {
303 for child in self.children() {
304 f(child)?;
305 }
306 Ok(())
307 }
308
309 fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
310 where
311 F: FnMut(&mut Self) -> Result<(), E>,
312 {
313 use LirScalarExpr::*;
314 match self {
315 Column(_, _) | Literal(_, _) => (),
316 CallUnary { expr, .. } => f(expr)?,
317 CallBinary { expr1, expr2, .. } => {
318 f(expr1)?;
319 f(expr2)?;
320 }
321 CallVariadic { exprs, .. } => {
322 for expr in exprs {
323 f(expr)?;
324 }
325 }
326 If { cond, then, els } => {
327 f(cond)?;
328 f(then)?;
329 f(els)?;
330 }
331 }
332 Ok(())
333 }
334
335 fn children<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a LirScalarExpr>
336 where
337 LirScalarExpr: 'a,
338 {
339 LirScalarExpr::children(self)
340 }
341
342 fn children_mut<'a>(&'a mut self) -> impl DoubleEndedIterator<Item = &'a mut LirScalarExpr>
343 where
344 LirScalarExpr: 'a,
345 {
346 LirScalarExpr::children_mut(self)
347 }
348}
349
350impl Columns for LirScalarExpr {
351 fn column(c: usize) -> Self {
352 LirScalarExpr::Column(c, TreatAsEqual(None))
353 }
354
355 fn visit_columns<F>(&mut self, mut action: F)
359 where
360 F: FnMut(&mut usize),
361 {
362 self.visit_pre_mut(|e| {
363 if let LirScalarExpr::Column(col, _) = e {
364 action(col);
365 }
366 });
367 }
368
369 fn is_column(&self) -> bool {
370 matches!(self, LirScalarExpr::Column(_, _))
371 }
372
373 fn as_column(&self) -> Option<usize> {
374 if let LirScalarExpr::Column(i, _) = self {
375 Some(*i)
376 } else {
377 None
378 }
379 }
380
381 fn as_column_mut(&mut self) -> Option<&mut usize> {
382 if let LirScalarExpr::Column(i, _) = self {
383 Some(i)
384 } else {
385 None
386 }
387 }
388
389 fn support_into(&self, support: &mut std::collections::BTreeSet<usize>) {
390 self.visit_pre(|e| {
391 if let LirScalarExpr::Column(i, _) = e {
392 support.insert(*i);
393 }
394 });
395 }
396}
397
398impl Eval for LirScalarExpr {
399 fn eval<'a>(
400 &'a self,
401 datums: &[Datum<'a>],
402 temp_storage: &'a RowArena,
403 ) -> Result<Datum<'a>, EvalError> {
404 use LirScalarExpr::*;
405 match self {
406 Column(index, _name) => Ok(datums[*index]),
407 Literal(res, _column_type) => match res {
408 Ok(row) => Ok(row.unpack_first()),
409 Err(e) => Err(e.clone()),
410 },
411 CallUnary { func, expr } => func.eval(datums, temp_storage, expr.as_ref()),
412 CallBinary { func, expr1, expr2 } => {
413 func.eval(datums, temp_storage, &[expr1.as_ref(), expr2.as_ref()])
414 }
415 CallVariadic { func, exprs } => func.eval(datums, temp_storage, exprs.as_slice()),
416 If { cond, then, els } => match cond.eval(datums, temp_storage)? {
417 Datum::True => then.eval(datums, temp_storage),
418 Datum::False | Datum::Null => els.eval(datums, temp_storage),
419 d => Err(EvalError::Internal(
420 format!("if condition evaluated to non-boolean datum: {:?}", d).into(),
421 )),
422 },
423 }
424 }
425
426 fn could_error(&self) -> bool {
428 use LirScalarExpr::*;
429 match self {
430 Column(_col, _name) => false,
431 Literal(row, ..) => row.is_err(),
432 CallUnary { func, expr } => func.could_error() || expr.could_error(),
433 CallBinary { func, expr1, expr2 } => {
434 func.could_error() || expr1.could_error() || expr2.could_error()
435 }
436 CallVariadic { func, exprs } => {
437 func.could_error() || exprs.iter().any(|e| e.could_error())
438 }
439 If { cond, then, els } => cond.could_error() || then.could_error() || els.could_error(),
440 }
441 }
442}
443
444impl OptimizableExpr for LirScalarExpr {
445 fn is_literal(&self) -> bool {
446 matches!(self, LirScalarExpr::Literal(_, _))
447 }
448
449 fn is_literal_err(&self) -> bool {
450 matches!(self, LirScalarExpr::Literal(Err(_), _))
451 }
452
453 fn contains_temporal(&self) -> bool {
454 false }
456
457 fn size(&self) -> usize {
458 let mut size = 0;
459 self.visit_pre(|_| size += 1);
460 size
461 }
462
463 fn eager_children(&mut self) -> Option<Vec<&mut Self>> {
464 if let LirScalarExpr::If { cond, .. } = self {
466 return Some(vec![cond]);
467 }
468
469 if let LirScalarExpr::CallVariadic {
471 func: VariadicFunc::Coalesce(_),
472 exprs,
473 } = self
474 {
475 return Some(exprs.iter_mut().take(1).collect());
476 }
477
478 None
480 }
481
482 fn equality_column_alias(predicate: &Self, expr: &Self, threshold: usize) -> Option<Self> {
483 if let LirScalarExpr::CallBinary {
484 func: BinaryFunc::Eq(_),
485 expr1,
486 expr2,
487 } = predicate
488 {
489 if let LirScalarExpr::Column(c, name) = &**expr1 {
490 if *c < threshold && &**expr2 == expr {
491 return Some(LirScalarExpr::Column(*c, name.clone()));
492 }
493 }
494 if let LirScalarExpr::Column(c, name) = &**expr2 {
495 if *c < threshold && &**expr1 == expr {
496 return Some(LirScalarExpr::Column(*c, name.clone()));
497 }
498 }
499 }
500 None
501 }
502
503 fn extract_temporal_bounds(temporal: Vec<Self>) -> Result<(Vec<Self>, Vec<Self>), String> {
504 if temporal.is_empty() {
505 Ok((Vec::new(), Vec::new()))
506 } else {
507 Err("LIR expressions do not support temporal predicates".into())
508 }
509 }
510}
511
512impl std::fmt::Debug for LirScalarExpr {
515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516 match self {
517 LirScalarExpr::Column(i, TreatAsEqual(Some(name))) => {
518 write!(f, "Column({i}, {name:?})")
519 }
520 LirScalarExpr::Column(i, TreatAsEqual(None)) => write!(f, "Column({i})"),
521 LirScalarExpr::Literal(lit, typ) => write!(f, "Literal({lit:?}, {typ:?})"),
522 LirScalarExpr::CallUnary { func, expr } => {
523 write!(f, "CallUnary({func:?}, {expr:?})")
524 }
525 LirScalarExpr::CallBinary { func, expr1, expr2 } => {
526 write!(f, "CallBinary({func:?}, {expr1:?}, {expr2:?})")
527 }
528 LirScalarExpr::CallVariadic { func, exprs } => {
529 write!(f, "CallVariadic({func:?}, {exprs:?})")
530 }
531 LirScalarExpr::If { cond, then, els } => {
532 write!(f, "If({cond:?}, {then:?}, {els:?})")
533 }
534 }
535 }
536}
537
538impl ScalarOps for LirScalarExpr {
539 fn match_col_ref(&self) -> Option<usize> {
540 match self {
541 LirScalarExpr::Column(c, _name) => Some(*c),
542 _ => None,
543 }
544 }
545
546 fn references(&self, column: usize) -> bool {
547 match self {
548 LirScalarExpr::Column(c, _name) => *c == column,
549 _ => false,
550 }
551 }
552}
553
554impl mz_expr::explain::HumanizeDisplay for LirScalarExpr {
555 fn humanize<'a, M: HumanizerMode>(
556 e: &HumanizedExpr<'a, Self, M>,
557 f: &mut std::fmt::Formatter<'_>,
558 ) -> std::fmt::Result {
559 use LirScalarExpr::*;
560
561 match e.expr {
562 Column(i, TreatAsEqual(None)) => {
563 e.child(i).fmt(f)
565 }
566 Column(i, TreatAsEqual(Some(name))) => {
567 e.child(&(i, name)).fmt(f)
569 }
570 Literal(row, _) => {
571 e.child(row).fmt(f)
573 }
574 CallUnary { func, expr } => {
575 if let UnaryFunc::Not(_) = *func {
576 if let CallUnary { func, expr } = expr.as_ref() {
577 if let Some(is) = func.is() {
578 let expr = e.child::<LirScalarExpr>(&*expr);
579 return write!(f, "({}) IS NOT {}", expr, is);
580 }
581 }
582 }
583 if let Some(is) = func.is() {
584 let expr = e.child::<LirScalarExpr>(&*expr);
585 write!(f, "({}) IS {}", expr, is)
586 } else {
587 let expr = e.child::<LirScalarExpr>(&*expr);
588 write!(f, "{}({})", func, expr)
589 }
590 }
591 CallBinary { func, expr1, expr2 } => {
592 let expr1 = e.child::<LirScalarExpr>(&*expr1);
593 let expr2 = e.child::<LirScalarExpr>(&*expr2);
594 if func.is_infix_op() {
595 write!(f, "({} {} {})", expr1, func, expr2)
596 } else {
597 write!(f, "{}({}, {})", func, expr1, expr2)
598 }
599 }
600 CallVariadic { func, exprs } => {
601 use VariadicFunc::*;
602 match func {
603 CaseLiteral(cl) => {
604 let input = e.child::<LirScalarExpr>(&exprs[0]);
605 write!(f, "case_lookup {}", input)?;
606 for entry in &cl.lookup {
607 let result = e.child::<LirScalarExpr>(&exprs[entry.expr_index]);
608 write!(f, " when ")?;
609 e.mode.humanize_datum(entry.literal.unpack_first(), f)?;
610 write!(f, " then {}", result)?;
611 }
612 let els = e.child::<LirScalarExpr>(exprs.last().unwrap());
613 write!(f, " else {} end", els)
614 }
615 ArrayCreate(..) => {
616 let exprs = exprs.iter().map(|expr| e.child(expr));
617 let exprs = separated(", ", exprs);
618 write!(f, "array[{}]", exprs)
619 }
620 ListCreate(..) => {
621 let exprs = exprs.iter().map(|expr| e.child(expr));
622 let exprs = separated(", ", exprs);
623 write!(f, "list[{}]", exprs)
624 }
625 RecordCreate(..) => {
626 let exprs = exprs.iter().map(|expr| e.child(expr));
627 let exprs = separated(", ", exprs);
628 write!(f, "row({})", exprs)
629 }
630 func if func.is_infix_op() && exprs.len() > 1 => {
631 let exprs = exprs.iter().map(|expr| e.child(expr));
632 let func = format!(" {} ", func);
633 let exprs = separated(&func, exprs);
634 write!(f, "({})", exprs)
635 }
636 func => {
637 let exprs = exprs.iter().map(|expr| e.child(expr));
638 let exprs = separated(", ", exprs);
639 write!(f, "{}({})", func, exprs)
640 }
641 }
642 }
643 If { cond, then, els } => {
644 let cond = e.child::<LirScalarExpr>(&*cond);
645 let then = e.child::<LirScalarExpr>(&*then);
646 let els = e.child::<LirScalarExpr>(&*els);
647 write!(f, "case when {} then {} else {} end", cond, then, els)
648 }
649 }
650 }
651}
652
653impl std::fmt::Display for LirScalarExpr {
654 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
655 let mode = HumanizedExplain::default();
656 std::fmt::Display::fmt(&mode.expr(self, None), f)
657 }
658}
659
660impl From<&LirScalarExpr> for MirScalarExpr {
661 fn from(value: &LirScalarExpr) -> Self {
662 use LirScalarExpr::*;
663 match value {
664 Column(c, treat_as_equal) => MirScalarExpr::Column(c.clone(), treat_as_equal.clone()),
665 Literal(row, repr_column_type) => {
666 MirScalarExpr::Literal(row.clone().map(|row| row.0), repr_column_type.clone())
667 }
668 CallUnary { func, expr } => MirScalarExpr::CallUnary {
669 func: func.map_expr(),
670 expr: Box::new(MirScalarExpr::from(expr.as_ref())),
671 },
672 CallBinary { func, expr1, expr2 } => MirScalarExpr::CallBinary {
673 func: func.clone(),
674 expr1: Box::new(MirScalarExpr::from(expr1.as_ref())),
675 expr2: Box::new(MirScalarExpr::from(expr2.as_ref())),
676 },
677 CallVariadic { func, exprs } => MirScalarExpr::CallVariadic {
678 func: func.clone(),
679 exprs: exprs.iter().map(MirScalarExpr::from).collect(),
680 },
681 If { cond, then, els } => MirScalarExpr::If {
682 cond: Box::new(MirScalarExpr::from(cond.as_ref())),
683 then: Box::new(MirScalarExpr::from(then.as_ref())),
684 els: Box::new(MirScalarExpr::from(els.as_ref())),
685 },
686 }
687 }
688}
689
690impl TryFrom<&MirScalarExpr> for LirScalarExpr {
691 type Error = Vec<UnmaterializableFunc>;
693
694 fn try_from(value: &MirScalarExpr) -> Result<Self, Self::Error> {
695 use MirScalarExpr::*;
696 match value {
697 Column(c, treat_as_equal) => Ok(LirScalarExpr::Column(*c, treat_as_equal.clone())),
698 Literal(row, repr_column_type) => Ok(LirScalarExpr::Literal(
699 row.clone().map(StableRow),
700 repr_column_type.clone(),
701 )),
702 CallUnary { func, expr } => Ok(LirScalarExpr::CallUnary {
703 func: func.try_map_expr()?,
704 expr: Box::new(LirScalarExpr::try_from(expr.as_ref())?),
705 }),
706 CallBinary { func, expr1, expr2 } => {
707 match (
708 LirScalarExpr::try_from(expr1.as_ref()),
709 LirScalarExpr::try_from(expr2.as_ref()),
710 ) {
711 (Ok(expr1), Ok(expr2)) => Ok(LirScalarExpr::CallBinary {
712 func: func.clone(),
713 expr1: Box::new(expr1),
714 expr2: Box::new(expr2),
715 }),
716 (Ok(_), Err(e)) | (Err(e), Ok(_)) => Err(e),
717 (Err(mut e1), Err(mut e2)) => {
718 e1.append(&mut e2);
719 Err(e1)
720 }
721 }
722 }
723 CallVariadic { func, exprs } => {
724 let (exprs, errors): (Vec<LirScalarExpr>, Vec<Vec<UnmaterializableFunc>>) = exprs
725 .into_iter()
726 .map(LirScalarExpr::try_from)
727 .partition_result();
728
729 if errors.is_empty() {
730 Ok(LirScalarExpr::CallVariadic {
731 func: func.clone(),
732 exprs,
733 })
734 } else {
735 Err(errors.concat())
736 }
737 }
738 If { cond, then, els } => {
739 let cond = LirScalarExpr::try_from(cond.as_ref());
740 let then = LirScalarExpr::try_from(then.as_ref());
741 let els = LirScalarExpr::try_from(els.as_ref());
742
743 match (cond, then, els) {
744 (Ok(cond), Ok(then), Ok(els)) => Ok(LirScalarExpr::If {
745 cond: Box::new(cond),
746 then: Box::new(then),
747 els: Box::new(els),
748 }),
749 (Err(e), Ok(_), Ok(_)) | (Ok(_), Err(e), Ok(_)) | (Ok(_), Ok(_), Err(e)) => {
750 Err(e)
751 }
752 (Err(mut e1), Err(mut e2), Ok(_))
753 | (Err(mut e1), Ok(_), Err(mut e2))
754 | (Ok(_), Err(mut e1), Err(mut e2)) => {
755 e1.append(&mut e2);
756 Err(e1)
757 }
758 (Err(mut e1), Err(mut e2), Err(mut e3)) => {
759 e1.append(&mut e2);
760 e1.append(&mut e3);
761 Err(e1)
762 }
763 }
764 }
765 CallUnmaterializable(f) => Err(vec![f.clone()]),
766 }
767 }
768}
769
770pub fn mfp_mir_to_lir(mfp: MapFilterProject<MirScalarExpr>) -> MapFilterProject<LirScalarExpr> {
774 let expressions = lses_from_mses(&mfp.expressions);
775 let predicates = mfp
776 .predicates
777 .iter()
778 .map(|(pos, pred)| {
779 (
780 *pos,
781 LirScalarExpr::try_from(pred).expect("unmaterializable in MFP predicate"),
782 )
783 })
784 .collect();
785 MapFilterProject::<LirScalarExpr> {
786 expressions,
787 predicates,
788 projection: mfp.projection,
789 input_arity: mfp.input_arity,
790 }
791}
792
793pub fn safe_mfp_mir_to_lir(plan: SafeMfpPlan<MirScalarExpr>) -> SafeMfpPlan<LirScalarExpr> {
797 SafeMfpPlan::from_mfp(mfp_mir_to_lir(plan.into_mfp()))
798}
799
800pub fn mfp_mir_to_lir_plan(mfp: MapFilterProject<MirScalarExpr>) -> MfpPlan<LirScalarExpr> {
806 let plan = mfp.into_plan().expect("MFP planning failed");
807 mfp_plan_mir_to_lir(plan)
808}
809
810pub fn mfp_plan_mir_to_lir(plan: MfpPlan<MirScalarExpr>) -> MfpPlan<LirScalarExpr> {
816 let (safe, lower, upper) = plan.into_parts();
817 MfpPlan::from_parts(
818 safe_mfp_mir_to_lir(safe),
819 lses_from_mses(&lower),
820 lses_from_mses(&upper),
821 )
822}
823
824pub fn mfp_plan_lir_to_mir(plan: MfpPlan<LirScalarExpr>) -> MfpPlan<MirScalarExpr> {
826 let (safe, lower, upper) = plan.into_parts();
827
828 let mfp = safe.into_mfp();
829 let expressions = mfp.expressions.iter().map(MirScalarExpr::from).collect();
830 let predicates = mfp
831 .predicates
832 .iter()
833 .map(|(pos, pred)| (*pos, MirScalarExpr::from(pred)))
834 .collect();
835 let mir_mfp = MapFilterProject::<MirScalarExpr> {
836 expressions,
837 predicates,
838 projection: mfp.projection,
839 input_arity: mfp.input_arity,
840 };
841
842 let lower = lower.iter().map(MirScalarExpr::from).collect();
843 let upper = upper.iter().map(MirScalarExpr::from).collect();
844 MfpPlan::from_parts(SafeMfpPlan::from_mfp(mir_mfp), lower, upper)
845}
846
847pub(crate) fn lses_from_mses<'a>(
854 exprs: impl IntoIterator<Item = &'a MirScalarExpr>,
855) -> Vec<LirScalarExpr> {
856 match exprs
857 .into_iter()
858 .map(LirScalarExpr::try_from)
859 .collect::<Result<Vec<LirScalarExpr>, _>>()
860 {
861 Ok(exprs) => exprs,
862 Err(funcs) => {
863 panic!(
864 "unmaterializable functions cannot be translated to LirScalarExpr: {}",
865 separated(", ", &funcs)
866 )
867 }
868 }
869}