Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 31437 with keyword query error mysql #34163

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8544d67
Added the With Segment Binder which improves the working of With Quer…
Yash-cor Dec 24, 2024
1653664
Added the changes
Yash-cor Dec 24, 2024
2029eaf
Resolves Merge Conflicts
Yash-cor Dec 26, 2024
068962b
Merge
Yash-cor Dec 26, 2024
f973677
Added unique Alias Exception while using Common Table Expression
Yash-cor Dec 26, 2024
027ea9f
Fix Spotless error
Yash-cor Dec 26, 2024
6c8660a
Merge remote-tracking branch 'refs/remotes/origin/master' into ISSUE_…
Yash-cor Dec 26, 2024
88a1300
Added Release Notes
Yash-cor Dec 26, 2024
e2e18ea
Added SQL bind test case for WithSegmentBinder
Yash-cor Dec 27, 2024
ab34b8e
Added Release Notes
Yash-cor Dec 27, 2024
6a2640c
Resolve Merge Conflict
Yash-cor Dec 27, 2024
2b0c960
Resolve Merge Conflict
Yash-cor Dec 27, 2024
52f639f
Added Release Notes
Yash-cor Dec 27, 2024
949ff51
Solved Spotless and Checkstyle error
Yash-cor Dec 27, 2024
a27ede2
Merge branch 'master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERROR_MYSQL
strongduanmu Dec 30, 2024
893cea5
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Dec 30, 2024
7fbb92f
Changed the working for Unique Alias Name Exception handling for CTE's
Yash-cor Dec 31, 2024
5023a65
Update Release Notes
Yash-cor Dec 31, 2024
c340ae3
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Dec 31, 2024
791c956
Changed Release Notes to resolve merge conflict
Yash-cor Dec 31, 2024
7a9cd89
Merge remote-tracking branch 'origin/ISSUE_31437_WITH_KEYWORD_QUERY_E…
Yash-cor Dec 31, 2024
ff11f5e
Sync With Master Branch
Yash-cor Dec 31, 2024
aa99360
Removed the Changes for with Clause in DeleteStatement will raise it …
Yash-cor Dec 31, 2024
03cc31d
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Jan 2, 2025
01f9e2f
Added SQLBinderIT test case for with clause.
Yash-cor Jan 2, 2025
30e3647
Merge
Yash-cor Jan 2, 2025
0e7a6f1
Merge remote-tracking branch 'origin/ISSUE_31437_WITH_KEYWORD_QUERY_E…
Yash-cor Jan 2, 2025
d32b7d4
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Jan 7, 2025
67df1d8
Updated documentation for the new Exception created
Yash-cor Jan 7, 2025
56147e3
Added e2e test case for with clause in e2e\sql\resources\cases\dql
Yash-cor Jan 7, 2025
58d2c21
Corrected e2e test case for with clause
Yash-cor Jan 7, 2025
ce53b70
Refactor to sync master branch
Yash-cor Jan 7, 2025
c77d035
Updates for e2e test case failure
Yash-cor Jan 7, 2025
30e9acd
Changes made in e2e test case for db and tbl
Yash-cor Jan 8, 2025
d9ea315
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Jan 8, 2025
b9131f7
Sync master branch
Yash-cor Jan 8, 2025
5acbb84
Changes in e2e test case
Yash-cor Jan 8, 2025
761355a
Merge branch 'apache:master' into ISSUE_31437_WITH_KEYWORD_QUERY_ERRO…
Yash-cor Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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' |

### 连接

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ private static SubquerySegment bindSubquerySegment(final SubquerySegment segment
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public static SubquerySegment bind(final SubquerySegment segment, final SQLState
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ private static void checkTableExists(final SQLStatementBinderContext binderConte
if (binderContext.getExternalTableBinderContexts().containsKey(new CaseInsensitiveString(tableName))) {
return;
}
if (binderContext.getCommonTableExpressionsSegmentsUniqueAliases().contains(tableName)) {
return;
}
ShardingSpherePreconditions.checkState(schema.containsTable(tableName), () -> new TableNotFoundException(tableName));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public static SubqueryTableSegment bind(final SubqueryTableSegment segment, fina
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
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;
Expand All @@ -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())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Yash-cor marked this conversation as resolved.
Show resolved Hide resolved

@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;
}

}
Original file line number Diff line number Diff line change
@@ -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) {
Yash-cor marked this conversation as resolved.
Show resolved Hide resolved
super(XOpenSQLState.SYNTAX_ERROR, 500, "Not unique table/alias: '%s'", alias);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!--
~ 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.
-->

<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>
Loading
Loading