vortex_layout/plan/plans/
eval.rs1use std::borrow::Cow;
5use std::fmt;
6
7use vortex_array::EmptyMetadata;
8use vortex_array::expr::BoundExpression;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_session::registry::CachedId;
12
13use crate::plan::Plan;
14use crate::plan::PlanChildren;
15use crate::plan::PlanId;
16use crate::plan::PlanParts;
17use crate::plan::PlanRef;
18use crate::plan::PlanVTable;
19use crate::plan::check_child_count;
20use crate::plan::optimizer::PlanReduceRule;
21
22#[derive(Clone, Debug)]
24pub struct Eval;
25
26#[derive(Clone, Debug)]
28pub struct EvalData {
29 expression: BoundExpression,
30}
31
32pub type EvalPlan = Plan<Eval>;
34
35impl EvalPlan {
36 pub fn try_new(expression: BoundExpression, child: PlanRef) -> VortexResult<Self> {
38 validate_expression_child(&expression, &child)?;
39
40 Ok(unsafe { Self::new_unchecked(expression, child) })
42 }
43
44 pub unsafe fn new_unchecked(expression: BoundExpression, child: PlanRef) -> Self {
50 PlanParts {
51 vtable: Eval,
52 dtype: expression.dtype().clone(),
53 row_count: child.row_count(),
54 children: vec![child].into(),
55 data: EvalData { expression },
56 }
57 .into_typed()
58 }
59
60 pub fn expression(&self) -> &BoundExpression {
62 &self.data().expression
63 }
64
65 pub fn child_plan(&self) -> VortexResult<PlanRef> {
67 self.child_required(0)
68 }
69}
70
71impl PlanVTable for Eval {
72 type PlanData = EvalData;
73 type Metadata = EmptyMetadata;
74
75 fn id(&self) -> PlanId {
76 static ID: CachedId = CachedId::new("vortex.plan.eval");
77 *ID
78 }
79
80 fn fmt(plan: &Plan<Self>, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(formatter, " expr={}", plan.expression())
82 }
83
84 fn metadata(_plan: &Plan<Self>) -> Option<Self::Metadata> {
85 None
87 }
88
89 fn with_children(
90 plan: &Plan<Self>,
91 children: &PlanChildren,
92 _data: &mut Self::PlanData,
93 ) -> VortexResult<()> {
94 check_child_count("Eval", children, 1)?;
95 let child = children
96 .get(0)?
97 .ok_or_else(|| vortex_error::vortex_err!("Eval child is absent"))?;
98 validate_expression_child(plan.expression(), &child)?;
99 if child.row_count() != plan.row_count() {
100 vortex_error::vortex_bail!(
101 "Eval child has {} rows but the plan has {}",
102 child.row_count(),
103 plan.row_count()
104 );
105 }
106 Ok(())
107 }
108
109 fn child_name(_plan: &Plan<Self>, index: usize) -> Cow<'_, str> {
110 if index == 0 {
111 Cow::Borrowed("child")
112 } else {
113 Cow::Owned(format!("child[{index}]"))
114 }
115 }
116}
117
118fn validate_expression_child(expression: &BoundExpression, child: &PlanRef) -> VortexResult<()> {
119 if !expression.is_root_bound_to(child.dtype()) {
120 vortex_bail!(
121 "Eval expression is not bound to child dtype {}",
122 child.dtype()
123 );
124 }
125 Ok(())
126}
127
128#[derive(Debug)]
130pub(crate) struct EvalIdentityRule;
131
132impl PlanReduceRule<Eval> for EvalIdentityRule {
133 fn reduce(&self, plan: &Plan<Eval>) -> VortexResult<Option<PlanRef>> {
134 if plan.expression().is_root() {
135 Ok(Some(plan.child_plan()?))
136 } else {
137 Ok(None)
138 }
139 }
140}