@@ -36,9 +36,10 @@ use datafusion_common::{
3636use datafusion_expr:: expr:: { Alias , ScalarFunction , ScalarFunctionDefinition } ;
3737use 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;
4243use hashbrown:: HashMap ;
4344use 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.
535536fn 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.
710621fn 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