Skip to content

Commit 1bd4684

Browse files
committed
Use standard tree walk in Projection Pushdown
1 parent 3f84764 commit 1bd4684

1 file changed

Lines changed: 29 additions & 118 deletions

File tree

datafusion/optimizer/src/optimize_projections.rs

Lines changed: 29 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ use datafusion_common::{
3636
use datafusion_expr::expr::{Alias, ScalarFunction, ScalarFunctionDefinition};
3737
use datafusion_expr::{
3838
logical_plan::LogicalPlan, projection_schema, Aggregate, BinaryExpr, Cast, Distinct,
39-
Expr, GroupingSet, Projection, TableScan, Window,
39+
Expr, Projection, TableScan, Window,
4040
};
4141

42+
use datafusion_expr::utils::inspect_expr_pre;
4243
use hashbrown::HashMap;
4344
use itertools::{izip, Itertools};
4445

@@ -531,7 +532,7 @@ macro_rules! rewrite_expr_with_check {
531532
///
532533
/// - `Ok(Some(Expr))`: Rewrite was successful. Contains the rewritten result.
533534
/// - `Ok(None)`: Signals that `expr` can not be rewritten.
534-
/// - `Err(error)`: An error occured during the function call.
535+
/// - `Err(error)`: An error occurred during the function call.
535536
fn rewrite_expr(expr: &Expr, input: &Projection) -> Result<Option<Expr>> {
536537
let result = match expr {
537538
Expr::Column(col) => {
@@ -574,129 +575,39 @@ fn rewrite_expr(expr: &Expr, input: &Projection) -> Result<Option<Expr>> {
574575
Ok(Some(result))
575576
}
576577

577-
/// Retrieves a set of outer-referenced columns by the given expression, `expr`.
578-
/// Note that the `Expr::to_columns()` function doesn't return these columns.
579-
///
580-
/// # Parameters
581-
///
582-
/// * `expr` - The expression to analyze for outer-referenced columns.
583-
///
584-
/// # Returns
585-
///
586-
/// returns a `HashSet<Column>` containing all outer-referenced columns.
587-
fn outer_columns(expr: &Expr) -> HashSet<Column> {
588-
let mut columns = HashSet::new();
589-
outer_columns_helper(expr, &mut columns);
590-
columns
591-
}
592-
593-
/// A recursive subroutine that accumulates outer-referenced columns by the
578+
/// Accumulates outer-referenced columns by the
594579
/// given expression, `expr`.
595580
///
596581
/// # Parameters
597582
///
598583
/// * `expr` - The expression to analyze for outer-referenced columns.
599584
/// * `columns` - A mutable reference to a `HashSet<Column>` where detected
600585
/// columns are collected.
601-
fn outer_columns_helper(expr: &Expr, columns: &mut HashSet<Column>) {
602-
match expr {
603-
Expr::OuterReferenceColumn(_, col) => {
604-
columns.insert(col.clone());
605-
}
606-
Expr::BinaryExpr(binary_expr) => {
607-
outer_columns_helper(&binary_expr.left, columns);
608-
outer_columns_helper(&binary_expr.right, columns);
609-
}
610-
Expr::ScalarSubquery(subquery) => {
611-
let exprs = subquery.outer_ref_columns.iter();
612-
outer_columns_helper_multi(exprs, columns);
613-
}
614-
Expr::Exists(exists) => {
615-
let exprs = exists.subquery.outer_ref_columns.iter();
616-
outer_columns_helper_multi(exprs, columns);
617-
}
618-
Expr::Alias(alias) => outer_columns_helper(&alias.expr, columns),
619-
Expr::InSubquery(insubquery) => {
620-
let exprs = insubquery.subquery.outer_ref_columns.iter();
621-
outer_columns_helper_multi(exprs, columns);
622-
}
623-
Expr::Cast(cast) => outer_columns_helper(&cast.expr, columns),
624-
Expr::Sort(sort) => outer_columns_helper(&sort.expr, columns),
625-
Expr::AggregateFunction(aggregate_fn) => {
626-
outer_columns_helper_multi(aggregate_fn.args.iter(), columns);
627-
if let Some(filter) = aggregate_fn.filter.as_ref() {
628-
outer_columns_helper(filter, columns);
586+
fn outer_columns(expr: &Expr, columns: &mut HashSet<Column>) {
587+
// inspect_expr_pre doesn't handle subquery references, so find them explicitly
588+
inspect_expr_pre(expr, |expr| {
589+
match expr {
590+
Expr::OuterReferenceColumn(_, col) => {
591+
columns.insert(col.clone());
629592
}
630-
if let Some(obs) = aggregate_fn.order_by.as_ref() {
631-
outer_columns_helper_multi(obs.iter(), columns);
593+
Expr::ScalarSubquery(subquery) => {
594+
outer_columns_helper_multi(&subquery.outer_ref_columns, columns);
632595
}
633-
}
634-
Expr::WindowFunction(window_fn) => {
635-
outer_columns_helper_multi(window_fn.args.iter(), columns);
636-
outer_columns_helper_multi(window_fn.order_by.iter(), columns);
637-
outer_columns_helper_multi(window_fn.partition_by.iter(), columns);
638-
}
639-
Expr::GroupingSet(groupingset) => match groupingset {
640-
GroupingSet::GroupingSets(multi_exprs) => {
641-
multi_exprs
642-
.iter()
643-
.for_each(|e| outer_columns_helper_multi(e.iter(), columns));
596+
Expr::Exists(exists) => {
597+
outer_columns_helper_multi(&exists.subquery.outer_ref_columns, columns);
644598
}
645-
GroupingSet::Cube(exprs) | GroupingSet::Rollup(exprs) => {
646-
outer_columns_helper_multi(exprs.iter(), columns);
599+
Expr::InSubquery(insubquery) => {
600+
outer_columns_helper_multi(
601+
&insubquery.subquery.outer_ref_columns,
602+
columns,
603+
);
647604
}
648-
},
649-
Expr::ScalarFunction(scalar_fn) => {
650-
outer_columns_helper_multi(scalar_fn.args.iter(), columns);
651-
}
652-
Expr::Like(like) => {
653-
outer_columns_helper(&like.expr, columns);
654-
outer_columns_helper(&like.pattern, columns);
655-
}
656-
Expr::InList(in_list) => {
657-
outer_columns_helper(&in_list.expr, columns);
658-
outer_columns_helper_multi(in_list.list.iter(), columns);
659-
}
660-
Expr::Case(case) => {
661-
let when_then_exprs = case
662-
.when_then_expr
663-
.iter()
664-
.flat_map(|(first, second)| [first.as_ref(), second.as_ref()]);
665-
outer_columns_helper_multi(when_then_exprs, columns);
666-
if let Some(expr) = case.expr.as_ref() {
667-
outer_columns_helper(expr, columns);
668-
}
669-
if let Some(expr) = case.else_expr.as_ref() {
670-
outer_columns_helper(expr, columns);
671-
}
672-
}
673-
Expr::SimilarTo(similar_to) => {
674-
outer_columns_helper(&similar_to.expr, columns);
675-
outer_columns_helper(&similar_to.pattern, columns);
676-
}
677-
Expr::TryCast(try_cast) => outer_columns_helper(&try_cast.expr, columns),
678-
Expr::GetIndexedField(index) => outer_columns_helper(&index.expr, columns),
679-
Expr::Between(between) => {
680-
outer_columns_helper(&between.expr, columns);
681-
outer_columns_helper(&between.low, columns);
682-
outer_columns_helper(&between.high, columns);
683-
}
684-
Expr::Not(expr)
685-
| Expr::IsNotFalse(expr)
686-
| Expr::IsFalse(expr)
687-
| Expr::IsTrue(expr)
688-
| Expr::IsNotTrue(expr)
689-
| Expr::IsUnknown(expr)
690-
| Expr::IsNotUnknown(expr)
691-
| Expr::IsNotNull(expr)
692-
| Expr::IsNull(expr)
693-
| Expr::Negative(expr) => outer_columns_helper(expr, columns),
694-
Expr::Column(_)
695-
| Expr::Literal(_)
696-
| Expr::Wildcard { .. }
697-
| Expr::ScalarVariable { .. }
698-
| Expr::Placeholder(_) => (),
699-
}
605+
_ => {}
606+
};
607+
Ok(()) as Result<()>
608+
})
609+
// unwrap: closure above never returns Err, so can not be Err here
610+
.unwrap();
700611
}
701612

702613
/// A recursive subroutine that accumulates outer-referenced columns by the
@@ -708,10 +619,10 @@ fn outer_columns_helper(expr: &Expr, columns: &mut HashSet<Column>) {
708619
/// * `columns` - A mutable reference to a `HashSet<Column>` where detected
709620
/// columns are collected.
710621
fn outer_columns_helper_multi<'a>(
711-
exprs: impl Iterator<Item = &'a Expr>,
622+
exprs: impl IntoIterator<Item = &'a Expr>,
712623
columns: &mut HashSet<Column>,
713624
) {
714-
exprs.for_each(|e| outer_columns_helper(e, columns));
625+
exprs.into_iter().for_each(|e| outer_columns(e, columns));
715626
}
716627

717628
/// Generates the required expressions (columns) that reside at `indices` of
@@ -779,8 +690,8 @@ fn indices_referred_by_expr(
779690
expr: &Expr,
780691
) -> Result<Vec<usize>> {
781692
let mut cols = expr.to_columns()?;
782-
// Get outer-referenced columns:
783-
cols.extend(outer_columns(expr));
693+
// Get outer-referenced (subquery) columns:
694+
outer_columns(expr, &mut cols);
784695
Ok(cols
785696
.iter()
786697
.flat_map(|col| input_schema.index_of_column(col))

0 commit comments

Comments
 (0)