@@ -29,7 +29,7 @@ use crate::utils::{
2929
3030use datafusion_common:: error:: DataFusionErrorBuilder ;
3131use datafusion_common:: tree_node:: { TreeNode , TreeNodeRecursion } ;
32- use datafusion_common:: { Column , DFSchema , Result , not_impl_err, plan_err} ;
32+ use datafusion_common:: { Column , DFSchema , DFSchemaRef , Result , not_impl_err, plan_err} ;
3333use datafusion_common:: { RecursionUnnestOption , UnnestOptions } ;
3434use datafusion_expr:: expr:: { PlannedReplaceSelectItem , WildcardOptions } ;
3535use datafusion_expr:: expr_rewriter:: {
@@ -90,6 +90,10 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
9090 return not_impl_err ! ( "SORT BY" ) ;
9191 }
9292
93+ // Capture and clear set expression schema so it doesn't leak
94+ // into subqueries planned during FROM clause handling.
95+ let set_expr_left_schema = planner_context. set_set_expr_left_schema ( None ) ;
96+
9397 // Process `from` clause
9498 let plan = self . plan_from_tables ( select. from , planner_context) ?;
9599 let empty_from = matches ! ( plan, LogicalPlan :: EmptyRelation ( _) ) ;
@@ -110,7 +114,8 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
110114 ) ?;
111115
112116 // Having and group by clause may reference aliases defined in select projection
113- let projected_plan = self . project ( base_plan. clone ( ) , select_exprs) ?;
117+ let projected_plan =
118+ self . project ( base_plan. clone ( ) , select_exprs, set_expr_left_schema) ?;
114119 let select_exprs = projected_plan. expressions ( ) ;
115120
116121 let order_by =
@@ -895,18 +900,29 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
895900 & self ,
896901 input : LogicalPlan ,
897902 expr : Vec < SelectExpr > ,
903+ set_expr_left_schema : Option < DFSchemaRef > ,
898904 ) -> Result < LogicalPlan > {
899905 // convert to Expr for validate_schema_satisfies_exprs
900- let exprs = expr
906+ let plain_exprs = expr
901907 . iter ( )
902908 . filter_map ( |e| match e {
903909 SelectExpr :: Expression ( expr) => Some ( expr. to_owned ( ) ) ,
904910 _ => None ,
905911 } )
906912 . collect :: < Vec < _ > > ( ) ;
907- self . validate_schema_satisfies_exprs ( input. schema ( ) , & exprs) ?;
908-
909- LogicalPlanBuilder :: from ( input) . project ( expr) ?. build ( )
913+ self . validate_schema_satisfies_exprs ( input. schema ( ) , & plain_exprs) ?;
914+
915+ // When inside a set expression, pass the left-most schema so
916+ // that expressions get aliased to match, avoiding duplicate
917+ // name errors from expressions like `count(*), count(*)`.
918+ let builder = LogicalPlanBuilder :: from ( input) ;
919+ if let Some ( left_schema) = set_expr_left_schema {
920+ builder
921+ . project_with_validation_and_schema ( expr, & left_schema) ?
922+ . build ( )
923+ } else {
924+ builder. project ( expr) ?. build ( )
925+ }
910926 }
911927
912928 /// Create an aggregate plan.
0 commit comments