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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5c6745e7c3f Issue 31437 with keyword query error mysql (#34163)
5c6745e7c3f is described below

commit 5c6745e7c3f318300b42e9f29abb2e7ce8cbd873
Author: Yash-cor <yash.tiw...@coriolis.co.in>
AuthorDate: Thu Jan 9 07:58:37 2025 +0530

    Issue 31437 with keyword query error mysql (#34163)
    
    * Added the With Segment Binder which improves the working of With Query 
and resolved the CheckTableExist error during With keyword Query execution
    
    * Resolves Merge Conflicts
    
    * Added unique Alias Exception while using Common Table Expression
    
    * Fix Spotless error
    
    * Added Release Notes
    
    * Added SQL bind test case for WithSegmentBinder
    
    * Added Release Notes
    
    * Resolve Merge Conflict
    
    * Added Release Notes
    
    * Solved Spotless and Checkstyle error
    
    * Changed the working for Unique Alias Name Exception handling for CTE's
    
    * Update Release Notes
    
    * Changed Release Notes to resolve merge conflict
    
    * Sync With Master Branch
    
    * Removed the Changes for with Clause in DeleteStatement will raise it with 
a different PR.
    
    * Added SQLBinderIT test case for with clause.
    
    * Updated documentation for the new Exception created
    
    * Added e2e test case for with clause in e2e\sql\resources\cases\dql
    
    * Corrected e2e test case for with clause
    
    * Refactor to sync master branch
    
    * Updates for e2e test case failure
    
    * Changes made in e2e test case for db and tbl
    
    * Changes in e2e test case
    
    ---------
    
    Co-authored-by: Zhengqiang Duan <duanzhengqi...@apache.org>
---
 .../user-manual/error-code/sql-error-code.cn.md    |   1 +
 .../user-manual/error-code/sql-error-code.en.md    |   1 +
 .../segment/dml/combine/CombineSegmentBinder.java  |   2 +
 .../dml/expression/type/SubquerySegmentBinder.java |   2 +
 .../dml/from/type/SimpleTableSegmentBinder.java    |   3 +
 .../dml/from/type/SubqueryTableSegmentBinder.java  |   2 +
 .../with/CommonTableExpressionSegmentBinder.java   |   7 +
 .../statement/SQLStatementBinderContext.java       |   2 +
 .../infra/binder/with/WithSegmentBinderTest.java   | 120 ++++++++++++++
 ...plicateCommonTableExpressionAliasException.java |  33 ++++
 .../dql/e2e-dql-select-using-with-clause.xml}      |  12 +-
 .../binder/src/test/resources/cases/dml/select.xml | 184 +++++++++++++++++++++
 .../binder/src/test/resources/sqls/dml/select.xml  |   1 +
 13 files changed, 363 insertions(+), 7 deletions(-)

diff --git a/docs/document/content/user-manual/error-code/sql-error-code.cn.md 
b/docs/document/content/user-manual/error-code/sql-error-code.cn.md
index a09db6bb79f..7c411a7986e 100644
--- a/docs/document/content/user-manual/error-code/sql-error-code.cn.md
+++ b/docs/document/content/user-manual/error-code/sql-error-code.cn.md
@@ -70,6 +70,7 @@ SQL 错误码以标准的 SQL State,Vendor Code 和详细错误信息提供,
 | 12101       | 42000     | Can not accept SQL type '%s'.            |
 | 12200       | 42000     | Hint data source '%s' does not exist.    |
 | 12300       | 0A000     | DROP TABLE ... CASCADE is not supported. |
+| 12500       | 42000     | Not unique table/alias: '%s'             |
 
 ### 连接
 
diff --git a/docs/document/content/user-manual/error-code/sql-error-code.en.md 
b/docs/document/content/user-manual/error-code/sql-error-code.en.md
index 282e53f2ea8..cde5dbb6cf5 100644
--- a/docs/document/content/user-manual/error-code/sql-error-code.en.md
+++ b/docs/document/content/user-manual/error-code/sql-error-code.en.md
@@ -70,6 +70,7 @@ SQL error codes provide by standard `SQL State`, `Vendor 
Code` and `Reason`, whi
 | 12101       | 42000     | Can not accept SQL type '%s'.            |
 | 12200       | 42000     | Hint data source '%s' does not exist.    |
 | 12300       | 0A000     | DROP TABLE ... CASCADE is not supported. |
+| 12500       | 42000     | Not unique table/alias: '%s'             |
 
 ### Connection
 
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/combine/CombineSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/combine/CombineSegmentBinder.java
index 73c70fd7fd6..8074355d8d6 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/combine/CombineSegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/combine/CombineSegmentBinder.java
@@ -54,7 +54,9 @@ public final class CombineSegmentBinder {
         SQLStatementBinderContext subqueryBinderContext =
                 new SQLStatementBinderContext(binderContext.getMetaData(), 
binderContext.getCurrentDatabaseName(), binderContext.getHintValueContext(), 
segment.getSelect());
         
subqueryBinderContext.getExternalTableBinderContexts().putAll(binderContext.getExternalTableBinderContexts());
+        
subqueryBinderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(binderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         result.setSelect(new 
SelectStatementBinder(outerTableBinderContexts).bind(segment.getSelect(), 
subqueryBinderContext));
+        
binderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(subqueryBinderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         return result;
     }
 }
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/SubquerySegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/SubquerySegmentBinder.java
index e12eafd2e21..4e468206f33 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/SubquerySegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/SubquerySegmentBinder.java
@@ -46,7 +46,9 @@ public final class SubquerySegmentBinder {
         SQLStatementBinderContext selectBinderContext =
                 new SQLStatementBinderContext(binderContext.getMetaData(), 
binderContext.getCurrentDatabaseName(), binderContext.getHintValueContext(), 
segment.getSelect());
         
selectBinderContext.getExternalTableBinderContexts().putAll(binderContext.getExternalTableBinderContexts());
+        
selectBinderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(binderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         SelectStatement boundSelectStatement = new 
SelectStatementBinder(outerTableBinderContexts).bind(segment.getSelect(), 
selectBinderContext);
+        
binderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(selectBinderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         return new SubquerySegment(segment.getStartIndex(), 
segment.getStopIndex(), boundSelectStatement, segment.getText());
     }
 }
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SimpleTableSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SimpleTableSegmentBinder.java
index ebe77511e21..20d5a615b22 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SimpleTableSegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SimpleTableSegmentBinder.java
@@ -172,6 +172,9 @@ public final class SimpleTableSegmentBinder {
         if (binderContext.getExternalTableBinderContexts().containsKey(new 
CaseInsensitiveString(tableName))) {
             return;
         }
+        if 
(binderContext.getCommonTableExpressionsSegmentsUniqueAliases().contains(tableName))
 {
+            return;
+        }
         
ShardingSpherePreconditions.checkState(schema.containsTable(tableName), () -> 
new TableNotFoundException(tableName));
     }
     
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SubqueryTableSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SubqueryTableSegmentBinder.java
index e4c94bd49e4..c9b646cec11 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SubqueryTableSegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/from/type/SubqueryTableSegmentBinder.java
@@ -54,7 +54,9 @@ public final class SubqueryTableSegmentBinder {
         SQLStatementBinderContext subqueryBinderContext =
                 new SQLStatementBinderContext(binderContext.getMetaData(), 
binderContext.getCurrentDatabaseName(), binderContext.getHintValueContext(), 
segment.getSubquery().getSelect());
         
subqueryBinderContext.getExternalTableBinderContexts().putAll(binderContext.getExternalTableBinderContexts());
+        
subqueryBinderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(binderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         SelectStatement boundSubSelect = new 
SelectStatementBinder(outerTableBinderContexts).bind(segment.getSubquery().getSelect(),
 subqueryBinderContext);
+        
binderContext.getCommonTableExpressionsSegmentsUniqueAliases().addAll(subqueryBinderContext.getCommonTableExpressionsSegmentsUniqueAliases());
         SubquerySegment boundSubquerySegment = new 
SubquerySegment(segment.getSubquery().getStartIndex(), 
segment.getSubquery().getStopIndex(), boundSubSelect, 
segment.getSubquery().getText());
         IdentifierValue subqueryTableName = 
segment.getAliasSegment().map(AliasSegment::getIdentifier).orElseGet(() -> new 
IdentifierValue(""));
         SubqueryTableSegment result = new 
SubqueryTableSegment(segment.getStartIndex(), segment.getStopIndex(), 
boundSubquerySegment);
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
index 6f5d3cbe651..ed15495ddf8 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
@@ -24,6 +24,8 @@ import lombok.NoArgsConstructor;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.type.SimpleTableSegmentBinderContext;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.type.SubqueryTableSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import 
org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
+import 
org.apache.shardingsphere.infra.exception.kernel.syntax.DuplicateCommonTableExpressionAliasException;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
@@ -45,6 +47,11 @@ public final class CommonTableExpressionSegmentBinder {
      * @return bound common table expression segment
      */
     public static CommonTableExpressionSegment bind(final 
CommonTableExpressionSegment segment, final SQLStatementBinderContext 
binderContext, final boolean recursive) {
+        if (segment.getAliasName().isPresent()) {
+            
ShardingSpherePreconditions.checkState(!binderContext.getCommonTableExpressionsSegmentsUniqueAliases().contains(segment.getAliasName().get()),
+                    () -> new 
DuplicateCommonTableExpressionAliasException(segment.getAliasName().get()));
+            
binderContext.getCommonTableExpressionsSegmentsUniqueAliases().add(segment.getAliasName().get());
+        }
         if (recursive && segment.getAliasName().isPresent()) {
             binderContext.getExternalTableBinderContexts().put(new 
CaseInsensitiveString(segment.getAliasName().get()),
                     new 
SimpleTableSegmentBinderContext(segment.getColumns().stream().map(ColumnProjectionSegment::new).collect(Collectors.toList())));
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
index d21f286a08c..a289e20bbcb 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
@@ -47,6 +47,8 @@ public final class SQLStatementBinderContext {
     
     private final SQLStatement sqlStatement;
     
+    private final Collection<String> 
commonTableExpressionsSegmentsUniqueAliases = new CaseInsensitiveSet<>();
+    
     private final Collection<String> usingColumnNames = new 
CaseInsensitiveSet<>();
     
     private final Collection<ProjectionSegment> joinTableProjectionSegments = 
new LinkedList<>();
diff --git 
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/with/WithSegmentBinderTest.java
 
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/with/WithSegmentBinderTest.java
new file mode 100644
index 00000000000..808c42c7bb6
--- /dev/null
+++ 
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/with/WithSegmentBinderTest.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.binder.with;
+
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.type.SimpleTableSegmentBinderContext;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.dml.with.WithSegmentBinder;
+import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import org.apache.shardingsphere.infra.hint.HintValueContext;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import 
org.apache.shardingsphere.sql.parser.statement.mysql.dml.MySQLSelectStatement;
+import org.junit.jupiter.api.Test;
+
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+
+public class WithSegmentBinderTest {
+    
+    @Test
+    void assertBind() {
+        
+        MySQLSelectStatement mySQLSelectStatement = new MySQLSelectStatement();
+        ProjectionsSegment projectionSegment = new ProjectionsSegment(42, 48);
+        ColumnSegment columnSegment = new ColumnSegment(42, 48, new 
IdentifierValue("user_id"));
+        projectionSegment.getProjections().add(new 
ColumnProjectionSegment(columnSegment));
+        mySQLSelectStatement.setProjections(projectionSegment);
+        mySQLSelectStatement.setFrom(new SimpleTableSegment(new 
TableNameSegment(55, 57, new IdentifierValue("cte"))));
+        
+        MySQLSelectStatement subqueryMySQLSelectStatement = new 
MySQLSelectStatement();
+        ProjectionsSegment subqueryProjectionSegment = new 
ProjectionsSegment(20, 20);
+        ShorthandProjectionSegment shorthandProjectionSegment = new 
ShorthandProjectionSegment(20, 20);
+        
subqueryProjectionSegment.getProjections().add(shorthandProjectionSegment);
+        subqueryMySQLSelectStatement.setProjections(subqueryProjectionSegment);
+        subqueryMySQLSelectStatement.setFrom(new SimpleTableSegment(new 
TableNameSegment(27, 32, new IdentifierValue("t_user"))));
+        SubquerySegment subquerySegment = new SubquerySegment(5, 33, 
subqueryMySQLSelectStatement, "(SELECT * FROM t_user)");
+        Collection<CommonTableExpressionSegment> commonTableExpressionSegments 
= new LinkedList<>();
+        commonTableExpressionSegments.add(new CommonTableExpressionSegment(5, 
33, new AliasSegment(5, 7, new IdentifierValue("cte")), subquerySegment));
+        WithSegment withSegment = new WithSegment(0, 33, 
commonTableExpressionSegments);
+        mySQLSelectStatement.setWithSegment(withSegment);
+        
+        SQLStatementBinderContext binderContext = new 
SQLStatementBinderContext(createMetaData(), "foo_db", new HintValueContext(), 
mySQLSelectStatement);
+        WithSegment actual = WithSegmentBinder.bind(withSegment, 
binderContext, binderContext.getExternalTableBinderContexts());
+        
+        assertThat(binderContext.getExternalTableBinderContexts().size(), 
is(1));
+        
assertThat(binderContext.getCommonTableExpressionsSegmentsUniqueAliases().size(),
 is(1));
+        assertThat(actual.getStartIndex(), is(0));
+        
assertTrue(binderContext.getExternalTableBinderContexts().containsKey(new 
CaseInsensitiveString("cte")));
+        
assertTrue(actual.getCommonTableExpressions().iterator().next().getAliasName().isPresent());
+        
assertThat(actual.getCommonTableExpressions().iterator().next().getAliasName().get(),
 is("cte"));
+        
assertThat(binderContext.getCommonTableExpressionsSegmentsUniqueAliases().iterator().next(),
 is("cte"));
+        
+        SimpleTableSegmentBinderContext simpleTableSegment = 
(SimpleTableSegmentBinderContext) 
binderContext.getExternalTableBinderContexts().get(new 
CaseInsensitiveString("cte")).iterator().next();
+        ArrayList<ColumnProjectionSegment> columnProjectionSegments = new 
ArrayList<>();
+        simpleTableSegment.getProjectionSegments().forEach(each -> 
columnProjectionSegments.add((ColumnProjectionSegment) each));
+        
+        
assertThat(columnProjectionSegments.get(0).getColumn().getIdentifier().getValue(),
 is("user_id"));
+        
assertThat(columnProjectionSegments.get(1).getColumn().getIdentifier().getValue(),
 is("name"));
+        
assertTrue(columnProjectionSegments.get(1).getColumn().getOwner().isPresent());
+        
assertThat(columnProjectionSegments.get(1).getColumn().getOwner().get().getIdentifier().getValue(),
 is("t_user"));
+        
assertTrue(columnProjectionSegments.get(0).getColumn().getOwner().isPresent());
+        
assertThat(columnProjectionSegments.get(0).getColumn().getOwner().get().getIdentifier().getValue(),
 is("t_user"));
+        
assertThat(columnProjectionSegments.get(0).getColumn().getIdentifier().getValue(),
 is("user_id"));
+        
assertThat(columnProjectionSegments.get(1).getColumn().getColumnBoundInfo().getOriginalSchema().getValue(),
 is("foo_db"));
+        
assertThat(columnProjectionSegments.get(0).getColumn().getColumnBoundInfo().getOriginalSchema().getValue(),
 is("foo_db"));
+        
assertThat(actual.getCommonTableExpressions().iterator().next().getSubquery().getText(),
 is("(SELECT * FROM t_user)"));
+    }
+    
+    private ShardingSphereMetaData createMetaData() {
+        ShardingSphereSchema schema = mock(ShardingSphereSchema.class, 
RETURNS_DEEP_STUBS);
+        
when(schema.getTable("t_user").getAllColumns()).thenReturn(Arrays.asList(
+                new ShardingSphereColumn("user_id", Types.INTEGER, true, 
false, false, true, false, false),
+                new ShardingSphereColumn("name", Types.VARCHAR, false, false, 
false, true, false, false)));
+        
+        ShardingSphereMetaData result = mock(ShardingSphereMetaData.class, 
RETURNS_DEEP_STUBS);
+        
when(result.getDatabase("foo_db").getSchema("foo_db")).thenReturn(schema);
+        when(result.containsDatabase("foo_db")).thenReturn(true);
+        
when(result.getDatabase("foo_db").containsSchema("foo_db")).thenReturn(true);
+        
when(result.getDatabase("foo_db").getSchema("foo_db").containsTable("t_user")).thenReturn(true);
+        return result;
+    }
+    
+}
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/exception/kernel/syntax/DuplicateCommonTableExpressionAliasException.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/exception/kernel/syntax/DuplicateCommonTableExpressionAliasException.java
new file mode 100644
index 00000000000..d74481b264e
--- /dev/null
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/exception/kernel/syntax/DuplicateCommonTableExpressionAliasException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.exception.kernel.syntax;
+
+import 
org.apache.shardingsphere.infra.exception.core.external.sql.sqlstate.XOpenSQLState;
+import 
org.apache.shardingsphere.infra.exception.core.external.sql.type.kernel.category.SyntaxSQLException;
+
+/**
+ * Duplicate common table expression alias exception.
+ */
+public final class DuplicateCommonTableExpressionAliasException extends 
SyntaxSQLException {
+    
+    private static final long serialVersionUID = -8206891094419297634L;
+    
+    public DuplicateCommonTableExpressionAliasException(final String alias) {
+        super(XOpenSQLState.SYNTAX_ERROR, 500, "Not unique table/alias: '%s'", 
alias);
+    }
+}
diff --git a/test/it/binder/src/test/resources/sqls/dml/select.xml 
b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-using-with-clause.xml
similarity index 55%
copy from test/it/binder/src/test/resources/sqls/dml/select.xml
copy to 
test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-using-with-clause.xml
index ced2c64e8b2..abcb45b553d 100644
--- a/test/it/binder/src/test/resources/sqls/dml/select.xml
+++ 
b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-using-with-clause.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one or more
   ~ contributor license agreements.  See the NOTICE file distributed with
@@ -16,9 +15,8 @@
   ~ limitations under the License.
   -->
 
-<sql-cases>
-    <sql-case id="select_with_shorthand_projection" value="SELECT * FROM 
t_order o" db-types="MySQL"/>
-    <sql-case id="select_with_group_by_order_by" value="SELECT order_id, 
COUNT(1) count FROM t_order o GROUP BY order_id HAVING count > 1 ORDER BY 
order_id" db-types="MySQL"/>
-    <sql-case id="select_with_with_clause" value="WITH t_order_tmp AS (SELECT 
* FROM t_order o) SELECT * FROM t_order_tmp" db-types="MySQL"/>
-    <sql-case id="select_with_current_select_projection_reference" 
value="SELECT order_id AS orderId, (SELECT orderId) AS tempOrderId FROM 
t_order" db-types="MySQL"/>
-</sql-cases>
+<e2e-test-cases>
+    <test-case sql="WITH products AS (SELECT * FROM t_product) SELECT * FROM 
products" db-types="MySQL" scenario-types="db">
+        <assertion />
+    </test-case>
+</e2e-test-cases>
\ No newline at end of file
diff --git a/test/it/binder/src/test/resources/cases/dml/select.xml 
b/test/it/binder/src/test/resources/cases/dml/select.xml
index da40c0135de..9d800befa4f 100644
--- a/test/it/binder/src/test/resources/cases/dml/select.xml
+++ b/test/it/binder/src/test/resources/cases/dml/select.xml
@@ -294,6 +294,190 @@
         </from>
     </select>
 
+    <select sql-case-id="select_with_clause_with_multiple_cte_definitions">
+        <with start-index="0" stop-index="141">
+            <common-table-expression name="cte1" start-index="5" 
stop-index="68">
+                <subquery-expression start-index="5" stop-index="68">
+                    <select>
+                        <from>
+                            <simple-table name="t_order" start-index="59" 
stop-index="67" alias="a">
+                                <table-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                </table-bound>
+                            </simple-table>
+                        </from>
+                        <projections start-index="38" stop-index="52">
+                            <column-projection name="status" start-index="38" 
stop-index="43" >
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order" />
+                                    <original-column name="status" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                            </column-projection>
+                            <column-projection name="user_id" start-index="46" 
stop-index="52" >
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order" />
+                                    <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                            </column-projection>
+                        </projections>
+                    </select>
+                </subquery-expression>
+                <column name="status" start-index="10" stop-index="15" >
+                    <column-bound>
+                        <original-database name="foo_db_1" />
+                        <original-schema name="foo_db_1" />
+                        <original-table name="t_order" />
+                        <original-column name="status" start-delimiter="`" 
end-delimiter="`" />
+                    </column-bound>
+                </column>
+                <column name="user_id" start-index="18" stop-index="24" >
+                    <column-bound>
+                        <original-database name="foo_db_1" />
+                        <original-schema name="foo_db_1" />
+                        <original-table name="t_order" />
+                        <original-column name="user_id" start-delimiter="`" 
end-delimiter="`" />
+                    </column-bound>
+                </column>
+            </common-table-expression>
+            <common-table-expression name="cte2" start-index="71" 
stop-index="141">
+                <subquery-expression start-index="71" stop-index="141">
+                    <select>
+                        <from>
+                            <simple-table name="t_order_item" 
start-index="127" stop-index="140" alias="b">
+                                <table-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                </table-bound>
+                            </simple-table>
+                        </from>
+                        <projections start-index="105" stop-index="120">
+                            <column-projection name="user_id" 
start-index="105" stop-index="111" >
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order_item" />
+                                    <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                            </column-projection>
+                            <column-projection name="item_id" 
start-index="114" stop-index="120" >
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order_item" />
+                                    <original-column name="item_id" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                            </column-projection>
+                        </projections>
+                    </select>
+                </subquery-expression>
+                <column name="user_id" start-index="76" stop-index="82" >
+                    <column-bound>
+                        <original-database name="foo_db_1" />
+                        <original-schema name="foo_db_1" />
+                        <original-table name="t_order_item" />
+                        <original-column name="user_id" start-delimiter="`" 
end-delimiter="`" />
+                    </column-bound>
+                </column>
+                <column name="item_id" start-index="85" stop-index="91" >
+                    <column-bound>
+                        <original-database name="foo_db_1" />
+                        <original-schema name="foo_db_1" />
+                        <original-table name="t_order_item" />
+                        <original-column name="item_id" start-delimiter="`" 
end-delimiter="`" />
+                    </column-bound>
+                </column>
+            </common-table-expression>
+        </with>
+        <from start-index="180" stop-index="230">
+            <join-table join-type="INNER">
+                <left>
+                    <simple-table name="cte1" start-index="180" 
stop-index="183" >
+                        <table-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                        </table-bound>
+                    </simple-table>
+                </left>
+                <right>
+                    <simple-table name="cte2" start-index="196" 
stop-index="199" >
+                        <table-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                        </table-bound>
+                    </simple-table>
+                </right>
+                <on-condition>
+                    <binary-operation-expression start-index="204" 
stop-index="230">
+                        <left>
+                            <column name="user_id" start-index="204" 
stop-index="215">
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order" />
+                                    <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                                <owner name="cte1" start-index="204" 
stop-index="207" >
+                                    <table-bound>
+                                        <original-database name="foo_db_1" />
+                                        <original-schema name="foo_db_1" />
+                                    </table-bound>
+                                </owner>
+                            </column>
+                        </left>
+                        <operator>=</operator>
+                        <right>
+                            <column name="user_id" start-index="219" 
stop-index="230">
+                                <column-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                    <original-table name="t_order_item" />
+                                    <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                                </column-bound>
+                                <owner name="cte2" start-index="219" 
stop-index="222" >
+                                    <table-bound>
+                                        <original-database name="foo_db_1" />
+                                        <original-schema name="foo_db_1" />
+                                    </table-bound>
+                                </owner>
+                            </column>
+                        </right>
+                    </binary-operation-expression>
+                </on-condition>
+            </join-table>
+        </from>
+        <projections start-index="150" stop-index="173">
+            <column-projection name="status" start-index="150" 
stop-index="155">
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order" />
+                    <original-column name="status" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-projection>
+            <column-projection name="user_id" start-index="158" 
stop-index="164">
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order_item" />
+                    <original-column name="user_id" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-projection>
+            <column-projection name="item_id" start-index="167" 
stop-index="173">
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order_item" />
+                    <original-column name="item_id" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-projection>
+        </projections>
+    </select>
+
     <select sql-case-id="select_with_current_select_projection_reference">
         <projections start-index="7" stop-index="58">
             <column-projection name="order_id" start-index="7" stop-index="25" 
alias="orderId">
diff --git a/test/it/binder/src/test/resources/sqls/dml/select.xml 
b/test/it/binder/src/test/resources/sqls/dml/select.xml
index ced2c64e8b2..c7e09f622ae 100644
--- a/test/it/binder/src/test/resources/sqls/dml/select.xml
+++ b/test/it/binder/src/test/resources/sqls/dml/select.xml
@@ -20,5 +20,6 @@
     <sql-case id="select_with_shorthand_projection" value="SELECT * FROM 
t_order o" db-types="MySQL"/>
     <sql-case id="select_with_group_by_order_by" value="SELECT order_id, 
COUNT(1) count FROM t_order o GROUP BY order_id HAVING count > 1 ORDER BY 
order_id" db-types="MySQL"/>
     <sql-case id="select_with_with_clause" value="WITH t_order_tmp AS (SELECT 
* FROM t_order o) SELECT * FROM t_order_tmp" db-types="MySQL"/>
+    <sql-case id="select_with_clause_with_multiple_cte_definitions" 
value="WITH cte1(status, user_id) AS (SELECT status, user_id FROM t_order a), 
cte2(user_id, item_id) AS (SELECT user_id, item_id FROM t_order_item b) SELECT 
status, user_id, item_id FROM cte1 INNER JOIN cte2 ON cte1.user_id = 
cte2.user_id" db-types="MySQL" />
     <sql-case id="select_with_current_select_projection_reference" 
value="SELECT order_id AS orderId, (SELECT orderId) AS tempOrderId FROM 
t_order" db-types="MySQL"/>
 </sql-cases>


Reply via email to