@@ -27,19 +27,19 @@ use crate::utils::{
27
27
28
28
use datafusion_common:: error:: DataFusionErrorBuilder ;
29
29
use datafusion_common:: tree_node:: { TreeNode , TreeNodeRecursion } ;
30
- use datafusion_common:: { not_impl_err, plan_err, Result } ;
30
+ use datafusion_common:: { not_impl_err, plan_err, Column , Result } ;
31
31
use datafusion_common:: { RecursionUnnestOption , UnnestOptions } ;
32
32
use datafusion_expr:: expr:: { Alias , PlannedReplaceSelectItem , WildcardOptions } ;
33
33
use datafusion_expr:: expr_rewriter:: {
34
34
normalize_col, normalize_col_with_schemas_and_ambiguity_check, normalize_sorts,
35
35
} ;
36
36
use datafusion_expr:: utils:: {
37
- expr_as_column_expr, expr_to_columns, find_aggregate_exprs, find_window_exprs,
37
+ expand_qualified_wildcard, expand_wildcard, expr_as_column_expr, expr_to_columns,
38
+ find_aggregate_exprs, find_window_exprs,
38
39
} ;
39
40
use datafusion_expr:: {
40
- qualified_wildcard_with_options, wildcard_with_options, Aggregate , Expr , Filter ,
41
- GroupingSet , LogicalPlan , LogicalPlanBuilder , LogicalPlanBuilderOptions ,
42
- Partitioning ,
41
+ Aggregate , Expr , Filter , GroupingSet , LogicalPlan , LogicalPlanBuilder ,
42
+ LogicalPlanBuilderOptions , Partitioning ,
43
43
} ;
44
44
45
45
use indexmap:: IndexMap ;
@@ -92,6 +92,12 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
92
92
planner_context,
93
93
) ?;
94
94
95
+ // TOOD: remove this after Expr::Wildcard is removed
96
+ #[ allow( deprecated) ]
97
+ for expr in & select_exprs {
98
+ debug_assert ! ( !matches!( expr, Expr :: Wildcard { .. } ) ) ;
99
+ }
100
+
95
101
// Having and group by clause may reference aliases defined in select projection
96
102
let projected_plan = self . project ( base_plan. clone ( ) , select_exprs. clone ( ) ) ?;
97
103
@@ -583,7 +589,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
583
589
let mut error_builder = DataFusionErrorBuilder :: new ( ) ;
584
590
for expr in projection {
585
591
match self . sql_select_to_rex ( expr, plan, empty_from, planner_context) {
586
- Ok ( expr) => prepared_select_exprs. push ( expr) ,
592
+ Ok ( expr) => prepared_select_exprs. extend ( expr) ,
587
593
Err ( err) => error_builder. add_error ( err) ,
588
594
}
589
595
}
@@ -597,7 +603,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
597
603
plan : & LogicalPlan ,
598
604
empty_from : bool ,
599
605
planner_context : & mut PlannerContext ,
600
- ) -> Result < Expr > {
606
+ ) -> Result < Vec < Expr > > {
601
607
match sql {
602
608
SelectItem :: UnnamedExpr ( expr) => {
603
609
let expr = self . sql_to_expr ( expr, plan. schema ( ) , planner_context) ?;
@@ -606,7 +612,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
606
612
& [ & [ plan. schema ( ) ] ] ,
607
613
& plan. using_columns ( ) ?,
608
614
) ?;
609
- Ok ( col)
615
+ Ok ( vec ! [ col] )
610
616
}
611
617
SelectItem :: ExprWithAlias { expr, alias } => {
612
618
let select_expr =
@@ -622,7 +628,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
622
628
Expr :: Column ( column) if column. name . eq ( & name) => col,
623
629
_ => col. alias ( name) ,
624
630
} ;
625
- Ok ( expr)
631
+ Ok ( vec ! [ expr] )
626
632
}
627
633
SelectItem :: Wildcard ( options) => {
628
634
Self :: check_wildcard_options ( & options) ?;
@@ -635,7 +641,17 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
635
641
planner_context,
636
642
options,
637
643
) ?;
638
- Ok ( wildcard_with_options ( planned_options) )
644
+
645
+ let expanded =
646
+ expand_wildcard ( plan. schema ( ) , plan, Some ( & planned_options) ) ?;
647
+
648
+ // If there is a REPLACE statement, replace that column with the given
649
+ // replace expression. Column name remains the same.
650
+ if let Some ( replace) = planned_options. replace {
651
+ replace_columns ( expanded, & replace)
652
+ } else {
653
+ Ok ( expanded)
654
+ }
639
655
}
640
656
SelectItem :: QualifiedWildcard ( object_name, options) => {
641
657
Self :: check_wildcard_options ( & options) ?;
@@ -646,7 +662,19 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
646
662
planner_context,
647
663
options,
648
664
) ?;
649
- Ok ( qualified_wildcard_with_options ( qualifier, planned_options) )
665
+
666
+ let expanded = expand_qualified_wildcard (
667
+ & qualifier,
668
+ plan. schema ( ) ,
669
+ Some ( & planned_options) ,
670
+ ) ?;
671
+ // If there is a REPLACE statement, replace that column with the given
672
+ // replace expression. Column name remains the same.
673
+ if let Some ( replace) = planned_options. replace {
674
+ replace_columns ( expanded, & replace)
675
+ } else {
676
+ Ok ( expanded)
677
+ }
650
678
}
651
679
}
652
680
}
@@ -698,7 +726,10 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
698
726
planner_context,
699
727
)
700
728
} )
701
- . collect :: < Result < Vec < _ > > > ( ) ?;
729
+ . collect :: < Result < Vec < _ > > > ( ) ?
730
+ . into_iter ( )
731
+ . flatten ( )
732
+ . collect ( ) ;
702
733
let planned_replace = PlannedReplaceSelectItem {
703
734
items : replace. items . into_iter ( ) . map ( |i| * i) . collect ( ) ,
704
735
planned_expressions : replace_expr,
@@ -884,3 +915,26 @@ fn match_window_definitions(
884
915
}
885
916
Ok ( ( ) )
886
917
}
918
+
919
+ /// If there is a REPLACE statement in the projected expression in the form of
920
+ /// "REPLACE (some_column_within_an_expr AS some_column)", this function replaces
921
+ /// that column with the given replace expression. Column name remains the same.
922
+ /// Multiple REPLACEs are also possible with comma separations.
923
+ fn replace_columns (
924
+ mut exprs : Vec < Expr > ,
925
+ replace : & PlannedReplaceSelectItem ,
926
+ ) -> Result < Vec < Expr > > {
927
+ for expr in exprs. iter_mut ( ) {
928
+ if let Expr :: Column ( Column { name, .. } ) = expr {
929
+ if let Some ( ( _, new_expr) ) = replace
930
+ . items ( )
931
+ . iter ( )
932
+ . zip ( replace. expressions ( ) . iter ( ) )
933
+ . find ( |( item, _) | item. column_name . value == * name)
934
+ {
935
+ * expr = new_expr. clone ( ) . alias ( name. clone ( ) )
936
+ }
937
+ }
938
+ }
939
+ Ok ( exprs)
940
+ }
0 commit comments