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 <[email protected]>
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 <[email protected]>
---
.../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>