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]