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

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


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

commit 6174205301546cb1ad32ca65b77677d61de681bc
Author: zy-kkk <[email protected]>
AuthorDate: Fri Dec 19 10:33:51 2025 +0800

    branch-3.1: [fix](parser) Fix FROM DUAL incorrectly matching table names 
starting with dual #59003 (#59144)
    
    picked from #59003
---
 .../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 c2aff94c461..23af3ac02e9 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
@@ -692,9 +692,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 783b0f5f6d8..55270771dfd 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
@@ -1222,7 +1222,8 @@ whereClause
     ;
 
 fromClause
-    : FROM relations
+    : FROM DUAL          #fromDual
+    | FROM relations     #fromRelations
     ;
 
 // For PL-SQL
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 171d6ed137b..7c981bc1c55 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
@@ -111,7 +111,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.GroupingElementContext;
 import org.apache.doris.nereids.DorisParser.GroupingSetContext;
 import org.apache.doris.nereids.DorisParser.HavingClauseContext;
@@ -1026,8 +1027,8 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         LogicalPlan query = LogicalPlanBuilderAssistant.withCheckPolicy(new 
UnboundRelation(
                 StatementScopeIdGenerator.newRelationId(), 
visitMultipartIdentifier(ctx.tableName)));
         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;
@@ -1452,7 +1453,7 @@ 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) {
                 SelectColumnClauseContext columnCtx = 
selectCtx.selectColumnClause();
                 if (columnCtx.EXCEPT() != null) {
                     throw new ParseException("select-except cannot be used in 
one row relation", selectCtx);
@@ -1460,7 +1461,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                 relation = new 
LogicalOneRowRelation(StatementScopeIdGenerator.newRelationId(),
                         ImmutableList.of(new Alias(Literal.of(0))));
             } else {
-                relation = visitFromClause(ctx.fromClause());
+                relation = visitFromRelations((FromRelationsContext) 
ctx.fromClause());
             }
             if (ctx.intoClause() != null && 
!ConnectContext.get().isRunProcedure()) {
                 throw new ParseException("Only procedure supports insert into 
variables", selectCtx);
@@ -2429,7 +2430,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 964ca49f3ab..5fc41bf923a 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