Skip to content

Commit 6378fda

Browse files
Monotonicity Transform Refactor (#229)
Co-authored-by: Mustafa Akur <[email protected]>
1 parent 0cfeee2 commit 6378fda

File tree

1 file changed

+22
-42
lines changed

1 file changed

+22
-42
lines changed

datafusion/physical-plan/src/joins/prunability.rs

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ use datafusion_physical_expr::utils::{
2626
};
2727
use datafusion_physical_expr::{PhysicalExpr, PhysicalSortExpr, SortProperties};
2828

29-
use itertools::Itertools;
30-
3129
/// Takes information about the join inputs (i.e. tables) and determines
3230
/// which input can be pruned during the join operation.
3331
///
@@ -168,7 +166,7 @@ fn intermediate_schema_sort_expr(
168166
///
169167
/// While transforming a [`PhysicalExpr`] up, each node holds a [`PrunabilityState`]
170168
/// to propagate these crucial pieces of information.
171-
#[derive(Debug, Clone)]
169+
#[derive(Debug, Clone, Copy)]
172170
struct PrunabilityState {
173171
sort_options: SortProperties,
174172
table_side: TableSide,
@@ -192,35 +190,23 @@ impl Default for PrunabilityState {
192190
struct ExprPrunability {
193191
expr: Arc<dyn PhysicalExpr>,
194192
state: PrunabilityState,
195-
children_states: Vec<PrunabilityState>,
193+
children: Vec<ExprPrunability>,
196194
}
197195

198196
impl ExprPrunability {
199-
/// Creates a new [`ExprPrunability`] with default states for `expr` and
200-
/// its children.
197+
/// Creates a new [`ExprPrunability`] tree with empty states.
201198
fn new(expr: Arc<dyn PhysicalExpr>) -> Self {
202-
let size = expr.children().len();
199+
let children = expr.children();
203200
Self {
204201
expr,
205202
state: PrunabilityState::default(),
206-
children_states: vec![PrunabilityState::default(); size],
203+
children: children.into_iter().map(Self::new).collect(),
207204
}
208205
}
209206

210-
/// Updates this [`ExprPrunability`]'s children states with the given states.
211-
pub fn with_new_children(mut self, children_states: Vec<PrunabilityState>) -> Self {
212-
assert_eq!(self.children_states.len(), children_states.len());
213-
self.children_states = children_states;
214-
self
215-
}
216-
217-
/// Creates new [`ExprPrunability`] objects for each child of the expression.
218-
pub fn children_expr_prunabilities(&self) -> Vec<ExprPrunability> {
219-
self.expr
220-
.children()
221-
.into_iter()
222-
.map(ExprPrunability::new)
223-
.collect()
207+
/// Get state for each child
208+
fn children_state(&self) -> Vec<PrunabilityState> {
209+
self.children.iter().map(|child| child.state).collect()
224210
}
225211
}
226212

@@ -276,21 +262,21 @@ fn update_prunability<F: Fn() -> EquivalenceProperties>(
276262
return Ok(Transformed::Yes(node));
277263
}
278264

279-
if !node.children_states.is_empty() {
265+
if !node.children.is_empty() {
280266
// Handle the intermediate (non-leaf) node case:
281-
let children = &node.children_states;
267+
let children = node.children_state();
282268
let children_sort_options = children
283269
.iter()
284270
.map(|prunability_state| prunability_state.sort_options)
285271
.collect::<Vec<_>>();
286272
let parent_sort_options = node.expr.get_ordering(&children_sort_options);
287273

288-
let parent_table_side = calculate_tableside_from_children(children);
274+
let parent_table_side = calculate_tableside_from_children(&children);
289275

290276
let prune_side = if let Ok(DataType::Boolean) = node.expr.data_type(filter_schema)
291277
{
292278
if let Some(binary) = node.expr.as_any().downcast_ref::<BinaryExpr>() {
293-
calculate_pruneside_from_children(binary, children)
279+
calculate_pruneside_from_children(binary, &children)
294280
} else if let Some(_cast) = node.expr.as_any().downcast_ref::<CastExpr>() {
295281
children[0].prune_side
296282
} else {
@@ -465,8 +451,8 @@ impl TreeNode for ExprPrunability {
465451
where
466452
F: FnMut(&Self) -> Result<VisitRecursion>,
467453
{
468-
for child in self.children_expr_prunabilities() {
469-
match op(&child)? {
454+
for child in &self.children {
455+
match op(child)? {
470456
VisitRecursion::Continue => {}
471457
VisitRecursion::Skip => return Ok(VisitRecursion::Continue),
472458
VisitRecursion::Stop => return Ok(VisitRecursion::Stop),
@@ -475,25 +461,19 @@ impl TreeNode for ExprPrunability {
475461
Ok(VisitRecursion::Continue)
476462
}
477463

478-
fn map_children<F>(self, transform: F) -> Result<Self>
464+
fn map_children<F>(mut self, transform: F) -> Result<Self>
479465
where
480466
F: FnMut(Self) -> Result<Self>,
481467
{
482-
if self.children_states.is_empty() {
468+
if self.children.is_empty() {
483469
Ok(self)
484470
} else {
485-
let child_expr_prunabilities = self.children_expr_prunabilities();
486-
// After mapping over the children, the function `F` applies to the
487-
// current object and updates its state.
488-
Ok(self.with_new_children(
489-
child_expr_prunabilities
490-
.into_iter()
491-
// Update children states after this transformation:
492-
.map(transform)
493-
// Extract the state (i.e. prunability) information:
494-
.map_ok(|c| c.state)
495-
.collect::<Result<Vec<_>>>()?,
496-
))
471+
self.children = self
472+
.children
473+
.into_iter()
474+
.map(transform)
475+
.collect::<Result<Vec<_>>>()?;
476+
Ok(self)
497477
}
498478
}
499479
}

0 commit comments

Comments
 (0)