@@ -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:: { Alias , 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 =
@@ -879,18 +884,29 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
879884 & self ,
880885 input : LogicalPlan ,
881886 expr : Vec < SelectExpr > ,
887+ set_expr_left_schema : Option < DFSchemaRef > ,
882888 ) -> Result < LogicalPlan > {
883889 // convert to Expr for validate_schema_satisfies_exprs
884- let exprs = expr
890+ let plain_exprs = expr
885891 . iter ( )
886892 . filter_map ( |e| match e {
887893 SelectExpr :: Expression ( expr) => Some ( expr. to_owned ( ) ) ,
888894 _ => None ,
889895 } )
890896 . collect :: < Vec < _ > > ( ) ;
891- self . validate_schema_satisfies_exprs ( input. schema ( ) , & exprs) ?;
892-
893- LogicalPlanBuilder :: from ( input) . project ( expr) ?. build ( )
897+ self . validate_schema_satisfies_exprs ( input. schema ( ) , & plain_exprs) ?;
898+
899+ // When inside a set expression, pass the left-most schema so
900+ // that expressions get aliased to match, avoiding duplicate
901+ // name errors from expressions like `count(*), count(*)`.
902+ let builder = LogicalPlanBuilder :: from ( input) ;
903+ if let Some ( left_schema) = set_expr_left_schema {
904+ builder
905+ . project_with_validation_and_schema ( expr, & left_schema) ?
906+ . build ( )
907+ } else {
908+ builder. project ( expr) ?. build ( )
909+ }
894910 }
895911
896912 /// Create an aggregate plan.
0 commit comments