This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new f9867ed0742 [fix](parser) Fix FROM DUAL incorrectly matching table 
names starting with dual (#59003)
f9867ed0742 is described below

commit f9867ed074236306a090421a6a88d0d19ad3467c
Author: zy-kkk <[email protected]>
AuthorDate: Sun Dec 14 23:00:57 2025 +0800

    [fix](parser) Fix FROM DUAL incorrectly matching table names starting with 
dual (#59003)
    
    The lexer rule `FROM_DUAL` was matching `FROM dualtbl` as `FROM DUAL` +
    `tbl`,
      causing parse errors when using table/CTE names starting with 'dual'.
    
      Move DUAL handling from lexer to parser level
    
      - Remove `FROM_DUAL` lexer rule
      - Add `#fromDual` branch in `fromClause` parser rule
      - Handle `FromDualContext` in LogicalPlanBuilder
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  3 ---
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  3 ++-
 .../doris/nereids/parser/LogicalPlanBuilder.java   | 13 +++++-----
 regression-test/data/query_p0/dual/dual.out        | 15 +++++++++++
 regression-test/suites/query_p0/dual/dual.groovy   | 30 ++++++++++++++++++++++
 5 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index 4b270915f03..33282dc4a6b 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -716,9 +716,6 @@ BRACKETED_COMMENT
     ;
 
 
-FROM_DUAL
-    : 'FROM' WS+ 'DUAL' -> channel(HIDDEN);
-
 WS
     : [ \r\n\t]+ -> channel(HIDDEN)
     ;
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index b3873b38447..fee1619a7d9 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -1256,7 +1256,8 @@ whereClause
     ;
 
 fromClause
-    : FROM relations
+    : FROM DUAL          #fromDual
+    | FROM relations     #fromRelations
     ;
 
 relations
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index d95473698f1..cf7ea6aede9 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -216,7 +216,8 @@ import org.apache.doris.nereids.DorisParser.ExportContext;
 import org.apache.doris.nereids.DorisParser.ExpressionWithEofContext;
 import org.apache.doris.nereids.DorisParser.ExpressionWithOrderContext;
 import org.apache.doris.nereids.DorisParser.FixedPartitionDefContext;
-import org.apache.doris.nereids.DorisParser.FromClauseContext;
+import org.apache.doris.nereids.DorisParser.FromDualContext;
+import org.apache.doris.nereids.DorisParser.FromRelationsContext;
 import org.apache.doris.nereids.DorisParser.FunctionArgumentsContext;
 import org.apache.doris.nereids.DorisParser.FunctionIdentifierContext;
 import org.apache.doris.nereids.DorisParser.GroupConcatContext;
@@ -1921,8 +1922,8 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                 )
         );
         query = withTableAlias(query, ctx.tableAlias());
-        if (ctx.fromClause() != null) {
-            query = withRelations(query, 
ctx.fromClause().relations().relation());
+        if (ctx.fromClause() instanceof FromRelationsContext) {
+            query = withRelations(query, ((FromRelationsContext) 
ctx.fromClause()).relations().relation());
         }
         query = withFilter(query, Optional.ofNullable(ctx.whereClause()));
         String tableAlias = null;
@@ -2522,11 +2523,11 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
             SelectClauseContext selectCtx = ctx.selectClause();
             LogicalPlan selectPlan;
             LogicalPlan relation;
-            if (ctx.fromClause() == null) {
+            if (ctx.fromClause() == null || ctx.fromClause() instanceof 
FromDualContext) {
                 relation = new 
LogicalOneRowRelation(StatementScopeIdGenerator.newRelationId(),
                         ImmutableList.of(new Alias(Literal.of(0))));
             } else {
-                relation = visitFromClause(ctx.fromClause());
+                relation = visitFromRelations((FromRelationsContext) 
ctx.fromClause());
             }
             selectPlan = withSelectQuerySpecification(
                     ctx, relation,
@@ -3656,7 +3657,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
     }
 
     @Override
-    public LogicalPlan visitFromClause(FromClauseContext ctx) {
+    public LogicalPlan visitFromRelations(FromRelationsContext ctx) {
         return ParserUtils.withOrigin(ctx, () -> 
visitRelations(ctx.relations()));
     }
 
diff --git a/regression-test/data/query_p0/dual/dual.out 
b/regression-test/data/query_p0/dual/dual.out
index fee517f8f2c..fa14b5f70a7 100644
--- a/regression-test/data/query_p0/dual/dual.out
+++ b/regression-test/data/query_p0/dual/dual.out
@@ -63,6 +63,21 @@
 -- !sql --
 1
 
+-- !sql --
+1      2
+
+-- !sql --
+2
+
+-- !sql --
+1
+
+-- !sql --
+1
+
+-- !sql --
+3
+
 -- !sql --
 1
 1
diff --git a/regression-test/suites/query_p0/dual/dual.groovy 
b/regression-test/suites/query_p0/dual/dual.groovy
index 868fdce895b..373b6c108f9 100644
--- a/regression-test/suites/query_p0/dual/dual.groovy
+++ b/regression-test/suites/query_p0/dual/dual.groovy
@@ -42,6 +42,36 @@ suite('dual') {
     qt_sql 'select a from (select 1 as a from dual union all select 2 as a 
from dual) u'
     qt_sql 'select row_number() over (order by 1) from dual;'
 
+    // Test CTE with name starting with 'dual' - should not be confused with 
FROM DUAL
+    qt_sql '''
+        with dualtbl as (
+            select 1 as col1, 2 as col2
+        )
+        select col1, col2 from dualtbl
+    '''
+
+    qt_sql '''
+        with dualtbl as (
+            select 1 as a
+        ),
+        dual2 as (
+            select a + 1 as b from dualtbl
+        )
+        select * from dual2
+    '''
+
+    // Test subquery alias starting with 'dual'
+    qt_sql 'select * from (select 1 as x) dualtbl'
+    qt_sql 'select dualtbl.x from (select 1 as x) dualtbl'
+
+    // Multiple CTEs referencing each other with dual-prefix names
+    qt_sql '''
+        with duala as (select 1 as v),
+             dualb as (select v + 1 as v from duala),
+             dualc as (select v + 1 as v from dualb)
+        select * from dualc
+    '''
+
     // Dropping and creating a table named 'dual' to test behavior when dual 
is a real table
     sql 'drop table if exists `dual`'
     sql '''


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to