Skip to content

Commit ed3b127

Browse files
committed
Use bound expressions in physical plans
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1 parent c21a17e commit ed3b127

2 files changed

Lines changed: 39 additions & 30 deletions

File tree

vortex-layout/src/plan/plans/expression.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::borrow::Cow;
55
use std::sync::Arc;
66

77
use vortex_array::dtype::DType;
8-
use vortex_array::expr::Expression;
9-
use vortex_array::expr::is_root;
10-
use vortex_array::expr::root;
11-
use vortex_array::expr::transform::replace;
8+
use vortex_array::expr::BoundExpression;
9+
use vortex_array::expr::traversal::NodeExt;
10+
use vortex_array::expr::traversal::Transformed;
11+
use vortex_array::expr::traversal::TraversalOrder;
1212
use vortex_error::VortexResult;
1313
use vortex_error::vortex_bail;
1414

@@ -17,24 +17,18 @@ use crate::plan::PlanRef;
1717

1818
/// A physical plan that applies an expression to the output of `child`.
1919
pub struct ExpressionPlan {
20-
expression: Expression,
20+
expression: BoundExpression,
2121
child: PlanRef,
22-
dtype: DType,
2322
}
2423

2524
impl ExpressionPlan {
26-
/// Creates an expression plan and validates its output dtype.
27-
pub fn try_new(expression: Expression, child: PlanRef) -> VortexResult<Self> {
28-
let dtype = expression.return_dtype(child.dtype())?;
29-
Ok(Self {
30-
expression,
31-
child,
32-
dtype,
33-
})
25+
/// Creates an expression plan from an expression bound to the child's dtype.
26+
pub fn new(expression: BoundExpression, child: PlanRef) -> Self {
27+
Self { expression, child }
3428
}
3529

3630
/// Returns the expression evaluated by this plan.
37-
pub fn expression(&self) -> &Expression {
31+
pub fn expression(&self) -> &BoundExpression {
3832
&self.expression
3933
}
4034

@@ -51,22 +45,18 @@ impl Plan for ExpressionPlan {
5145

5246
fn optimize(&self) -> VortexResult<PlanRef> {
5347
let child = self.child.optimize()?;
54-
let expression = self.expression.optimize_recursive(child.dtype())?;
55-
if is_root(&expression) {
48+
if self.expression.is_root() {
5649
return Ok(child);
5750
}
5851
if let Some(inner) = child.downcast_ref::<Self>() {
59-
let expression = replace(expression, &root(), inner.expression.clone());
60-
return Ok(Arc::new(Self::try_new(
61-
expression,
62-
Arc::clone(&inner.child),
63-
)?));
52+
let expression = replace_root(self.expression.clone(), inner.expression.clone())?;
53+
return Ok(Arc::new(Self::new(expression, Arc::clone(&inner.child))));
6454
}
65-
Ok(Arc::new(Self::try_new(expression, child)?))
55+
Ok(Arc::new(Self::new(self.expression.clone(), child)))
6656
}
6757

6858
fn dtype(&self) -> &DType {
69-
&self.dtype
59+
self.expression.dtype()
7060
}
7161

7262
fn row_count(&self) -> u64 {
@@ -92,3 +82,22 @@ impl Plan for ExpressionPlan {
9282
}
9383
}
9484
}
85+
86+
fn replace_root(
87+
expression: BoundExpression,
88+
replacement: BoundExpression,
89+
) -> VortexResult<BoundExpression> {
90+
Ok(expression
91+
.transform_down(|node| {
92+
if node.is_root() {
93+
Ok(Transformed {
94+
value: replacement.clone(),
95+
order: TraversalOrder::Skip,
96+
changed: true,
97+
})
98+
} else {
99+
Ok(Transformed::no(node))
100+
}
101+
})?
102+
.into_inner())
103+
}

vortex-layout/src/plan/tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,9 @@ fn plan_display_matches_array_tree_display_shape() -> VortexResult<()> {
308308
vec![flat(3, field_dtype.clone(), 0), flat(3, field_dtype, 1)],
309309
)
310310
.into_layout();
311-
let plan: PlanRef = Arc::new(ExpressionPlan::try_new(
312-
get_item("a", root()),
313-
make_plan(layout)?,
314-
)?);
311+
let child = make_plan(layout)?;
312+
let expression = get_item("a", root()).bind(child.dtype())?;
313+
let plan: PlanRef = Arc::new(ExpressionPlan::new(expression, child));
315314

316315
assert_eq!(plan.to_string(), "ExpressionPlan(i32, rows=3)");
317316
insta::assert_snapshot!(plan.tree_display(), @r"
@@ -442,12 +441,13 @@ fn list_plan_display_handles_optional_validity() -> VortexResult<()> {
442441
fn row_idx_plan_preserves_row_index_expressions() -> VortexResult<()> {
443442
let layout = flat(3, primitive(PType::I32, Nullability::NonNullable), 0);
444443
let plan = RowIdxPlan::new_ref(10, make_plan(layout)?);
445-
let plan = ExpressionPlan::try_new(row_idx(), plan)?.optimize()?;
444+
let bound_expression = row_idx().bind(plan.dtype())?;
445+
let plan = ExpressionPlan::new(bound_expression.clone(), plan).optimize()?;
446446
let expression = plan
447447
.downcast_ref::<ExpressionPlan>()
448448
.ok_or_else(|| vortex_err!("optimized plan is not an expression plan"))?;
449449

450-
assert_eq!(expression.expression(), &row_idx());
450+
assert_eq!(expression.expression(), &bound_expression);
451451
assert!(expression.child_plan().is::<RowIdxPlan>());
452452
assert_eq!(expression.row_count(), 3);
453453
Ok(())

0 commit comments

Comments
 (0)