1515// specific language governing permissions and limitations
1616// under the License.
1717
18- use std:: collections:: HashSet ;
18+ use std:: collections:: { HashMap , HashSet } ;
1919use std:: ops:: ControlFlow ;
2020use std:: sync:: Arc ;
2121
@@ -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 , Diagnostic , Result , Span , not_impl_err, plan_err} ;
3333use datafusion_common:: { RecursionUnnestOption , UnnestOptions } ;
3434use datafusion_expr:: expr:: { Alias , PlannedReplaceSelectItem , WildcardOptions } ;
3535use datafusion_expr:: expr_rewriter:: {
@@ -50,7 +50,9 @@ use sqlparser::ast::{
5050 SelectItemQualifiedWildcardKind , WildcardAdditionalOptions , WindowType ,
5151 visit_expressions_mut,
5252} ;
53- use sqlparser:: ast:: { NamedWindowDefinition , Select , SelectItem , TableWithJoins } ;
53+ use sqlparser:: ast:: {
54+ NamedWindowDefinition , Select , SelectItem , Spanned , TableFactor , TableWithJoins ,
55+ } ;
5456
5557/// Result of the `aggregate` function, containing the aggregate plan and
5658/// rewritten expressions that reference the aggregate output columns.
@@ -690,21 +692,81 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
690692 self . plan_table_with_joins ( input, planner_context)
691693 }
692694 _ => {
695+ let extract_table_name =
696+ |t : & TableWithJoins | -> Option < ( String , Option < Span > ) > {
697+ let span =
698+ Span :: try_from_sqlparser_span ( t. relation . span ( ) ) ;
699+ match & t. relation {
700+ TableFactor :: Table { alias : Some ( a) , .. } => {
701+ let name = self
702+ . ident_normalizer
703+ . normalize ( a. name . clone ( ) ) ;
704+ Some ( ( name, span) )
705+ }
706+ TableFactor :: Table { name, alias : None , .. } => {
707+ let table_name = name
708+ . 0
709+ . iter ( )
710+ . filter_map ( |p| p. as_ident ( ) )
711+ . map ( |id| {
712+ self . ident_normalizer
713+ . normalize ( id. clone ( ) )
714+ } )
715+ . last ( ) ?;
716+ Some ( ( table_name, span) )
717+ }
718+ _ => None ,
719+ }
720+ } ;
721+
722+ let mut alias_spans: HashMap < String , Option < Span > > =
723+ HashMap :: new ( ) ;
724+
693725 let mut from = from. into_iter ( ) ;
726+ let first = from. next ( ) . unwrap ( ) ;
727+
728+ if let Some ( ( name, span) ) = extract_table_name ( & first) {
729+ alias_spans. entry ( name) . or_insert ( span) ;
730+ }
731+
732+ let mut left = LogicalPlanBuilder :: from (
733+ self . plan_table_with_joins ( first, planner_context) ?,
734+ ) ;
694735
695- let mut left = LogicalPlanBuilder :: from ( {
696- let input = from. next ( ) . unwrap ( ) ;
697- self . plan_table_with_joins ( input, planner_context) ?
698- } ) ;
699736 let old_outer_from_schema = {
700737 let left_schema = Some ( Arc :: clone ( left. schema ( ) ) ) ;
701738 planner_context. set_outer_from_schema ( left_schema)
702739 } ;
703740 for input in from {
704- // Join `input` with the current result (`left`).
705- let right = self . plan_table_with_joins ( input, planner_context) ?;
706- left = left. cross_join ( right) ?;
707- // Update the outer FROM schema.
741+ let current_span =
742+ Span :: try_from_sqlparser_span ( input. relation . span ( ) ) ;
743+ let current_name = extract_table_name ( & input) ;
744+
745+ if let Some ( ( ref name, _) ) = current_name {
746+ alias_spans. entry ( name. clone ( ) ) . or_insert ( current_span) ;
747+ }
748+
749+ let right =
750+ self . plan_table_with_joins ( input, planner_context) ?;
751+
752+ left = left. cross_join ( right) . map_err ( |e| {
753+ if let Some ( ( ref name, _) ) = current_name {
754+ if let Some ( prior_span) =
755+ alias_spans. get ( name) . copied ( ) . flatten ( )
756+ {
757+ let mut diagnostic = Diagnostic :: new_error (
758+ "duplicate table alias in FROM clause" ,
759+ current_span,
760+ ) ;
761+ diagnostic = diagnostic. with_note (
762+ "first defined here" ,
763+ Some ( prior_span) ,
764+ ) ;
765+ return e. with_diagnostic ( diagnostic) ;
766+ }
767+ }
768+ e
769+ } ) ?;
708770 let left_schema = Some ( Arc :: clone ( left. schema ( ) ) ) ;
709771 planner_context. set_outer_from_schema ( left_schema) ;
710772 }
0 commit comments