From cf0b19a0b511f91135725f3abcc60a57dfebd9ad Mon Sep 17 00:00:00 2001 From: Zhengqiang Duan Date: Tue, 24 Dec 2024 16:14:18 +0800 Subject: [PATCH] Remove TablesContext#findTableNames method and implement select order by, group by bind logic (#34123) * Remove TablesContext#findTableNames method and use sql bind info to replace * fix unit test * optimize select statement binder * update release note --- RELEASE-NOTES.md | 1 + .../EncryptOrderByItemSupportedChecker.java | 10 +- ...ncryptPredicateColumnSupportedChecker.java | 9 +- .../condition/EncryptConditionEngine.java | 28 +--- .../EncryptSQLRewriteContextDecorator.java | 5 +- .../EncryptGroupByItemTokenGenerator.java | 20 +-- ...ncryptOrderByItemSupportedCheckerTest.java | 4 + ...ptPredicateColumnSupportedCheckerTest.java | 2 - ...PredicateRightValueTokenGeneratorTest.java | 2 +- .../EncryptGroupByItemTokenGeneratorTest.java | 6 +- .../WhereClauseShardingConditionEngine.java | 27 ++-- .../sharding/rule/ShardingRule.java | 17 +-- ...hereClauseShardingConditionEngineTest.java | 5 - .../sharding/rule/ShardingRuleTest.java | 13 +- .../context/segment/table/TablesContext.java | 127 ------------------ .../expression/ExpressionSegmentBinder.java | 5 + .../type/BetweenExpressionSegmentBinder.java | 54 ++++++++ .../segment/order/GroupBySegmentBinder.java | 71 ++++++++++ .../segment/order/OrderBySegmentBinder.java | 71 ++++++++++ .../item/ColumnOrderByItemSegmentBinder.java | 52 +++++++ .../ExpressionOrderByItemSegmentBinder.java | 52 +++++++ .../order/item/OrderByItemSegmentBinder.java | 58 ++++++++ .../predicate/HavingSegmentBinder.java | 51 +++++++ .../WhereSegmentBinder.java | 2 +- .../statement/dml/DeleteStatementBinder.java | 2 +- .../statement/dml/SelectStatementBinder.java | 28 +++- .../statement/dml/UpdateStatementBinder.java | 2 +- .../segment/table/TablesContextTest.java | 70 ---------- .../WhereSegmentBinderTest.java | 2 +- 29 files changed, 498 insertions(+), 298 deletions(-) create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BetweenExpressionSegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/GroupBySegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/OrderBySegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ColumnOrderByItemSegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ExpressionOrderByItemSegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/OrderByItemSegmentBinder.java create mode 100644 infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/HavingSegmentBinder.java rename infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/{where => predicate}/WhereSegmentBinder.java (97%) rename infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/{where => predicate}/WhereSegmentBinderTest.java (97%) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index b1f96d7cd956d..318dd2e0892a8 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -37,6 +37,7 @@ 1. SQL Binder: Add sql bind logic for create table statement - [#34074](https://github.com/apache/shardingsphere/pull/34074) 1. SQL Binder: Support create index statement sql bind - [#34112](https://github.com/apache/shardingsphere/pull/34112) 1. SQL Parser: Support MySQL update with statement parse - [#34126](https://github.com/apache/shardingsphere/pull/34126) +1. SQL Binder: Remove TablesContext#findTableNames method and implement select order by, group by bind logic - [#34123](https://github.com/apache/shardingsphere/pull/34123) ### Bug Fixes diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedChecker.java index f12994d2ea1a7..45ec1217aa6ab 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedChecker.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedChecker.java @@ -32,9 +32,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment; import java.util.Collection; -import java.util.Collections; import java.util.LinkedList; -import java.util.Map; import java.util.Optional; /** @@ -64,7 +62,7 @@ private boolean containsOrderByItem(final SelectStatementContext sqlStatementCon public void check(final EncryptRule rule, final ShardingSphereDatabase database, final ShardingSphereSchema currentSchema, final SelectStatementContext sqlStatementContext) { for (OrderByItem each : getOrderByItems(sqlStatementContext)) { if (each.getSegment() instanceof ColumnOrderByItemSegment) { - checkColumnOrderByItem(rule, currentSchema, sqlStatementContext, ((ColumnOrderByItemSegment) each.getSegment()).getColumn()); + checkColumnOrderByItem(rule, ((ColumnOrderByItemSegment) each.getSegment()).getColumn()); } } } @@ -80,10 +78,8 @@ private Collection getOrderByItems(final SelectStatementContext sql return result; } - private void checkColumnOrderByItem(final EncryptRule rule, final ShardingSphereSchema schema, final SelectStatementContext sqlStatementContext, final ColumnSegment columnSegment) { - Map columnTableNames = sqlStatementContext.getTablesContext().findTableNames(Collections.singleton(columnSegment), schema); - String tableName = columnTableNames.getOrDefault(columnSegment.getExpression(), ""); - Optional encryptTable = rule.findEncryptTable(tableName); + private void checkColumnOrderByItem(final EncryptRule rule, final ColumnSegment columnSegment) { + Optional encryptTable = rule.findEncryptTable(columnSegment.getColumnBoundInfo().getOriginalTable().getValue()); String columnName = columnSegment.getIdentifier().getValue(); ShardingSpherePreconditions.checkState(!encryptTable.isPresent() || !encryptTable.get().isEncryptColumn(columnName), () -> new UnsupportedEncryptSQLException("ORDER BY")); } diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedChecker.java index 9938819dc23e6..129e69441bbea 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedChecker.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedChecker.java @@ -25,7 +25,6 @@ import org.apache.shardingsphere.infra.binder.context.extractor.SQLStatementContextExtractor; import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; -import org.apache.shardingsphere.infra.binder.context.type.TableAvailable; import org.apache.shardingsphere.infra.binder.context.type.WhereAvailable; import org.apache.shardingsphere.infra.checker.SupportedSQLChecker; import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions; @@ -40,7 +39,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; import java.util.Collection; -import java.util.Map; import java.util.Optional; /** @@ -60,13 +58,12 @@ public void check(final EncryptRule rule, final ShardingSphereDatabase database, Collection joinConditions = SQLStatementContextExtractor.getJoinConditions((WhereAvailable) sqlStatementContext, allSubqueryContexts); ShardingSpherePreconditions.checkState(JoinConditionsEncryptorComparator.isSame(joinConditions, rule), () -> new UnsupportedSQLOperationException("Can not use different encryptor in join condition")); - check(rule, currentSchema, (WhereAvailable) sqlStatementContext); + check(rule, (WhereAvailable) sqlStatementContext); } - private void check(final EncryptRule rule, final ShardingSphereSchema schema, final WhereAvailable sqlStatementContext) { - Map columnExpressionTableNames = ((TableAvailable) sqlStatementContext).getTablesContext().findTableNames(sqlStatementContext.getColumnSegments(), schema); + private void check(final EncryptRule rule, final WhereAvailable sqlStatementContext) { for (ColumnSegment each : sqlStatementContext.getColumnSegments()) { - Optional encryptTable = rule.findEncryptTable(columnExpressionTableNames.getOrDefault(each.getExpression(), "")); + Optional encryptTable = rule.findEncryptTable(each.getColumnBoundInfo().getOriginalTable().getValue()); String columnName = each.getIdentifier().getValue(); if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(columnName) && includesLike(sqlStatementContext.getWhereSegments(), each)) { String tableName = encryptTable.get().getTable(); diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/condition/EncryptConditionEngine.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/condition/EncryptConditionEngine.java index ecee22e14e1ae..2c66ec5d512ec 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/condition/EncryptConditionEngine.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/condition/EncryptConditionEngine.java @@ -24,12 +24,8 @@ import org.apache.shardingsphere.encrypt.rule.EncryptRule; import org.apache.shardingsphere.encrypt.rule.table.EncryptTable; import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation; -import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; -import org.apache.shardingsphere.infra.binder.context.type.TableAvailable; -import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry; import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions; import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; import org.apache.shardingsphere.sql.parser.statement.core.extractor.ColumnExtractor; import org.apache.shardingsphere.sql.parser.statement.core.extractor.ExpressionExtractor; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; @@ -43,13 +39,11 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.AndPredicate; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; -import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; @@ -89,44 +83,36 @@ public final class EncryptConditionEngine { * Create encrypt conditions. * * @param whereSegments where segments - * @param columnSegments column segments - * @param sqlStatementContext SQL statement context - * @param databaseName database name * @return encrypt conditions */ - public Collection createEncryptConditions(final Collection whereSegments, final Collection columnSegments, - final SQLStatementContext sqlStatementContext, final String databaseName) { + public Collection createEncryptConditions(final Collection whereSegments) { Collection result = new LinkedList<>(); - String defaultSchema = new DatabaseTypeRegistry(sqlStatementContext.getDatabaseType()).getDefaultSchemaName(databaseName); - ShardingSphereSchema schema = ((TableAvailable) sqlStatementContext).getTablesContext().getSchemaName().map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchema)); - Map expressionTableNames = ((TableAvailable) sqlStatementContext).getTablesContext().findTableNames(columnSegments, schema); for (WhereSegment each : whereSegments) { Collection andPredicates = ExpressionExtractor.extractAndPredicates(each.getExpr()); for (AndPredicate predicate : andPredicates) { - addEncryptConditions(result, predicate.getPredicates(), expressionTableNames); + addEncryptConditions(result, predicate.getPredicates()); } } return result; } - private void addEncryptConditions(final Collection encryptConditions, final Collection predicates, final Map expressionTableNames) { + private void addEncryptConditions(final Collection encryptConditions, final Collection predicates) { Collection stopIndexes = new HashSet<>(predicates.size(), 1F); for (ExpressionSegment each : predicates) { if (stopIndexes.add(each.getStopIndex())) { - addEncryptConditions(encryptConditions, each, expressionTableNames); + addEncryptConditions(encryptConditions, each); } } } - private void addEncryptConditions(final Collection encryptConditions, final ExpressionSegment expression, final Map expressionTableNames) { + private void addEncryptConditions(final Collection encryptConditions, final ExpressionSegment expression) { if (!findNotContainsNullLiteralsExpression(expression).isPresent()) { return; } for (ColumnSegment each : ColumnExtractor.extract(expression)) { - ColumnSegmentBoundInfo columnBoundInfo = each.getColumnBoundInfo(); - String tableName = columnBoundInfo.getOriginalTable().getValue().isEmpty() ? expressionTableNames.getOrDefault(each.getExpression(), "") : columnBoundInfo.getOriginalTable().getValue(); + String tableName = each.getColumnBoundInfo().getOriginalTable().getValue(); Optional encryptTable = rule.findEncryptTable(tableName); - if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(each.getIdentifier().getValue())) { + if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(each.getColumnBoundInfo().getOriginalColumn().getValue())) { createEncryptCondition(expression, tableName).ifPresent(encryptConditions::add); } } diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/context/EncryptSQLRewriteContextDecorator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/context/EncryptSQLRewriteContextDecorator.java index 045a014ba0094..7f7fab2ad91e4 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/context/EncryptSQLRewriteContextDecorator.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/context/EncryptSQLRewriteContextDecorator.java @@ -37,7 +37,6 @@ import org.apache.shardingsphere.infra.rewrite.parameter.rewriter.ParameterRewritersBuilder; import org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.builder.SQLTokenGeneratorBuilder; import org.apache.shardingsphere.infra.route.context.RouteContext; -import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; import java.util.Collection; @@ -93,9 +92,7 @@ private Collection createEncryptConditions(final EncryptRule r } Collection allSubqueryContexts = SQLStatementContextExtractor.getAllSubqueryContexts(sqlStatementContext); Collection whereSegments = SQLStatementContextExtractor.getWhereSegments((WhereAvailable) sqlStatementContext, allSubqueryContexts); - Collection columnSegments = SQLStatementContextExtractor.getColumnSegments((WhereAvailable) sqlStatementContext, allSubqueryContexts); - return new EncryptConditionEngine(rule, sqlRewriteContext.getDatabase()).createEncryptConditions(whereSegments, columnSegments, sqlStatementContext, - sqlRewriteContext.getDatabase().getName()); + return new EncryptConditionEngine(rule, sqlRewriteContext.getDatabase()).createEncryptConditions(whereSegments); } private void rewriteParameters(final SQLRewriteContext sqlRewriteContext, final Collection parameterRewriters) { diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGenerator.java index 2abad5c730490..cfc5d86a68956 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGenerator.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGenerator.java @@ -30,9 +30,7 @@ import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; import org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; import org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.CollectionSQLTokenGenerator; -import org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.aware.SchemaMetaDataAware; import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken; import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.generic.SubstitutableColumnNameToken; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; @@ -42,7 +40,6 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedList; -import java.util.Map; import java.util.Optional; /** @@ -51,14 +48,10 @@ @HighFrequencyInvocation @RequiredArgsConstructor @Setter -public final class EncryptGroupByItemTokenGenerator implements CollectionSQLTokenGenerator, SchemaMetaDataAware { +public final class EncryptGroupByItemTokenGenerator implements CollectionSQLTokenGenerator { private final EncryptRule rule; - private Map schemas; - - private ShardingSphereSchema defaultSchema; - @Override public boolean isGenerateSQLToken(final SQLStatementContext sqlStatementContext) { return sqlStatementContext instanceof SelectStatementContext && containsGroupByItem((SelectStatementContext) sqlStatementContext); @@ -79,21 +72,18 @@ private boolean containsGroupByItem(final SelectStatementContext sqlStatementCon @Override public Collection generateSQLTokens(final SelectStatementContext sqlStatementContext) { Collection result = new LinkedList<>(); - ShardingSphereSchema schema = sqlStatementContext.getTablesContext().getSchemaName().map(schemas::get).orElseGet(() -> defaultSchema); for (OrderByItem each : getGroupByItems(sqlStatementContext)) { if (each.getSegment() instanceof ColumnOrderByItemSegment) { ColumnSegment columnSegment = ((ColumnOrderByItemSegment) each.getSegment()).getColumn(); - Map columnTableNames = sqlStatementContext.getTablesContext().findTableNames(Collections.singleton(columnSegment), schema); - generateSQLToken(columnSegment, columnTableNames, sqlStatementContext.getDatabaseType()).ifPresent(result::add); + generateSQLToken(columnSegment, sqlStatementContext.getDatabaseType()).ifPresent(result::add); } } return result; } - private Optional generateSQLToken(final ColumnSegment columnSegment, final Map columnTableNames, final DatabaseType databaseType) { - String tableName = columnTableNames.getOrDefault(columnSegment.getExpression(), ""); - Optional encryptTable = rule.findEncryptTable(tableName); - String columnName = columnSegment.getIdentifier().getValue(); + private Optional generateSQLToken(final ColumnSegment columnSegment, final DatabaseType databaseType) { + Optional encryptTable = rule.findEncryptTable(columnSegment.getColumnBoundInfo().getOriginalTable().getValue()); + String columnName = columnSegment.getColumnBoundInfo().getOriginalColumn().getValue(); if (!encryptTable.isPresent() || !encryptTable.get().isEncryptColumn(columnName)) { return Optional.empty(); } diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedCheckerTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedCheckerTest.java index bd54b59414a6a..edaaffc99ea84 100644 --- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedCheckerTest.java +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/orderby/EncryptOrderByItemSupportedCheckerTest.java @@ -33,6 +33,8 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; 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; @@ -116,6 +118,8 @@ private SelectStatementContext mockSelectStatementContext(final String tableName simpleTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("a"))); ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("foo_col")); columnSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("a"))); + columnSegment.setColumnBoundInfo( + new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue(tableName), new IdentifierValue("foo_col"))); SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); when(result.getDatabaseType()).thenReturn(databaseType); ColumnOrderByItemSegment columnOrderByItemSegment = new ColumnOrderByItemSegment(columnSegment, OrderDirection.ASC, NullsOrderType.FIRST); diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedCheckerTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedCheckerTest.java index 1c2ef0ba5aff8..b82a0c37a5e7a 100644 --- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedCheckerTest.java +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/predicate/EncryptPredicateColumnSupportedCheckerTest.java @@ -88,7 +88,6 @@ private SQLStatementContext mockSelectStatementContextWithLike() { columnSegment.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_schema")), new IdentifierValue("t_user"), new IdentifierValue("user_name"))); SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(result.getTablesContext().findTableNames(Collections.singleton(columnSegment), null)).thenReturn(Collections.singletonMap("user_name", "t_user")); when(result.getColumnSegments()).thenReturn(Collections.singleton(columnSegment)); when(result.getWhereSegments()).thenReturn(Collections.singleton(new WhereSegment(0, 0, new BinaryOperationExpression(0, 0, columnSegment, columnSegment, "LIKE", "")))); when(result.getSubqueryContexts()).thenReturn(Collections.emptyMap()); @@ -106,7 +105,6 @@ private SQLStatementContext mockSelectStatementContextWithEqual() { columnSegment.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_schema")), new IdentifierValue("t_user"), new IdentifierValue("user_name"))); SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(result.getTablesContext().findTableNames(Collections.singleton(columnSegment), null)).thenReturn(Collections.singletonMap("user_name", "t_user")); when(result.getColumnSegments()).thenReturn(Collections.singleton(columnSegment)); when(result.getWhereSegments()).thenReturn(Collections.singleton(new WhereSegment(0, 0, new BinaryOperationExpression(0, 0, columnSegment, columnSegment, "=", "")))); when(result.getSubqueryContexts()).thenReturn(Collections.emptyMap()); diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGeneratorTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGeneratorTest.java index d37fea852b784..002e641a26ffc 100644 --- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGeneratorTest.java +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGeneratorTest.java @@ -63,6 +63,6 @@ void assertGenerateSQLTokenFromGenerateNewSQLToken() { private Collection getEncryptConditions(final UpdateStatementContext updateStatementContext) { ShardingSphereDatabase database = new ShardingSphereDatabase("foo_db", mock(), mock(), mock(), Collections.singleton(new ShardingSphereSchema("foo_db"))); return new EncryptConditionEngine(EncryptGeneratorFixtureBuilder.createEncryptRule(), database) - .createEncryptConditions(updateStatementContext.getWhereSegments(), updateStatementContext.getColumnSegments(), updateStatementContext, "foo_db"); + .createEncryptConditions(updateStatementContext.getWhereSegments()); } } diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGeneratorTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGeneratorTest.java index add57075398b5..ab0011e86f5a4 100644 --- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGeneratorTest.java +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/select/EncryptGroupByItemTokenGeneratorTest.java @@ -25,13 +25,14 @@ import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; import org.apache.shardingsphere.infra.database.core.metadata.database.enums.NullsOrderType; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.sql.parser.statement.core.enums.OrderDirection; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; 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; @@ -56,7 +57,6 @@ class EncryptGroupByItemTokenGeneratorTest { @BeforeEach void setup() { generator = new EncryptGroupByItemTokenGenerator(mockEncryptRule()); - generator.setSchemas(Collections.singletonMap("test", mock(ShardingSphereSchema.class))); } private EncryptRule mockEncryptRule() { @@ -79,6 +79,8 @@ private SelectStatementContext buildSelectStatementContext() { SimpleTableSegment simpleTableSegment = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_encrypt"))); simpleTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("a"))); ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("certificate_number")); + columnSegment.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue("t_encrypt"), + new IdentifierValue("certificate_number"))); columnSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("a"))); SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); when(result.getDatabaseType()).thenReturn(databaseType); diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java index 752f68dbff152..8a9eb3f0aecf0 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngine.java @@ -36,12 +36,12 @@ import org.apache.shardingsphere.sharding.route.engine.condition.value.RangeShardingConditionValue; import org.apache.shardingsphere.sharding.route.engine.condition.value.ShardingConditionValue; import org.apache.shardingsphere.sharding.rule.ShardingRule; +import org.apache.shardingsphere.sql.parser.statement.core.extractor.ColumnExtractor; +import org.apache.shardingsphere.sql.parser.statement.core.extractor.ExpressionExtractor; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.AndPredicate; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; -import org.apache.shardingsphere.sql.parser.statement.core.extractor.ColumnExtractor; -import org.apache.shardingsphere.sql.parser.statement.core.extractor.ExpressionExtractor; import org.apache.shardingsphere.sql.parser.statement.core.util.SafeNumberOperationUtils; import org.apache.shardingsphere.timeservice.core.rule.TimestampServiceRule; @@ -80,23 +80,18 @@ public List createShardingConditions(final SQLStatementContex if (!(sqlStatementContext instanceof WhereAvailable)) { return Collections.emptyList(); } - Collection columnSegments = ((WhereAvailable) sqlStatementContext).getColumnSegments(); - ShardingSphereSchema schema = getSchema(sqlStatementContext, database); - Map columnExpressionTableNames = sqlStatementContext instanceof TableAvailable - ? ((TableAvailable) sqlStatementContext).getTablesContext().findTableNames(columnSegments, schema) - : Collections.emptyMap(); List result = new ArrayList<>(); for (WhereSegment each : SQLStatementContextExtractor.getAllWhereSegments(sqlStatementContext)) { - result.addAll(createShardingConditions(each.getExpr(), params, columnExpressionTableNames)); + result.addAll(createShardingConditions(each.getExpr(), params)); } return result; } - private Collection createShardingConditions(final ExpressionSegment expression, final List params, final Map columnExpressionTableNames) { + private Collection createShardingConditions(final ExpressionSegment expression, final List params) { Collection andPredicates = ExpressionExtractor.extractAndPredicates(expression); Collection result = new LinkedList<>(); for (AndPredicate each : andPredicates) { - Map> shardingConditionValues = createShardingConditionValueMap(each.getPredicates(), params, columnExpressionTableNames); + Map> shardingConditionValues = createShardingConditionValueMap(each.getPredicates(), params); if (shardingConditionValues.isEmpty()) { return Collections.emptyList(); } @@ -115,18 +110,16 @@ private ShardingSphereSchema getSchema(final SQLStatementContext sqlStatementCon : database.getSchema(defaultSchemaName); } - private Map> createShardingConditionValueMap(final Collection predicates, - final List params, final Map columnTableNames) { + private Map> createShardingConditionValueMap(final Collection predicates, final List params) { Map> result = new HashMap<>(predicates.size(), 1F); for (ExpressionSegment each : predicates) { for (ColumnSegment columnSegment : ColumnExtractor.extract(each)) { - Optional tableName = Optional.ofNullable(Optional.ofNullable(columnTableNames.get(columnSegment.getExpression())) - .orElse(columnSegment.getColumnBoundInfo().getOriginalTable().getValue())); - Optional shardingColumn = tableName.flatMap(optional -> shardingRule.findShardingColumn(columnSegment.getColumnBoundInfo().getOriginalColumn().getValue(), optional)); - if (!tableName.isPresent() || !shardingColumn.isPresent()) { + String tableName = columnSegment.getColumnBoundInfo().getOriginalTable().getValue(); + Optional shardingColumn = shardingRule.findShardingColumn(columnSegment.getColumnBoundInfo().getOriginalColumn().getValue(), tableName); + if (!shardingColumn.isPresent()) { continue; } - Column column = new Column(shardingColumn.get(), tableName.get()); + Column column = new Column(shardingColumn.get(), tableName); Optional shardingConditionValue = ConditionValueGeneratorFactory.generate(each, column, params, timestampServiceRule); if (!shardingConditionValue.isPresent()) { continue; diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java index 758d45b663c96..6c3e63386eacf 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java @@ -68,7 +68,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; import javax.sql.DataSource; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -586,8 +585,8 @@ private boolean isJoinConditionContainsShardingColumns(final ShardingSphereSchem return false; } for (AndPredicate andPredicate : andPredicates) { - databaseJoinConditionTables.addAll(getJoinConditionTables(schema, select, andPredicate.getPredicates(), true)); - tableJoinConditionTables.addAll(getJoinConditionTables(schema, select, andPredicate.getPredicates(), false)); + databaseJoinConditionTables.addAll(getJoinConditionTables(andPredicate.getPredicates(), true)); + tableJoinConditionTables.addAll(getJoinConditionTables(andPredicate.getPredicates(), false)); } } ShardingTable shardingTable = getShardingTable(tableNames.iterator().next()); @@ -598,8 +597,7 @@ private boolean isJoinConditionContainsShardingColumns(final ShardingSphereSchem return containsDatabaseShardingColumns && containsTableShardingColumns; } - private Collection getJoinConditionTables(final ShardingSphereSchema schema, final SelectStatementContext select, - final Collection predicates, final boolean isDatabaseJoinCondition) { + private Collection getJoinConditionTables(final Collection predicates, final boolean isDatabaseJoinCondition) { Collection result = new LinkedList<>(); for (ExpressionSegment each : predicates) { if (!isJoinConditionExpression(each)) { @@ -607,9 +605,8 @@ private Collection getJoinConditionTables(final ShardingSphereSchema sch } ColumnSegment leftColumn = (ColumnSegment) ((BinaryOperationExpression) each).getLeft(); ColumnSegment rightColumn = (ColumnSegment) ((BinaryOperationExpression) each).getRight(); - Map columnExpressionTableNames = select.getTablesContext().findTableNames(Arrays.asList(leftColumn, rightColumn), schema); - Optional leftShardingTable = findShardingTable(columnExpressionTableNames.get(leftColumn.getExpression())); - Optional rightShardingTable = findShardingTable(columnExpressionTableNames.get(rightColumn.getExpression())); + Optional leftShardingTable = findShardingTable(leftColumn.getColumnBoundInfo().getOriginalTable().getValue()); + Optional rightShardingTable = findShardingTable(rightColumn.getColumnBoundInfo().getOriginalTable().getValue()); if (!leftShardingTable.isPresent() || !rightShardingTable.isPresent()) { continue; } @@ -621,8 +618,8 @@ private Collection getJoinConditionTables(final ShardingSphereSchema sch : getTableShardingStrategyConfiguration(rightShardingTable.get()); if (findShardingColumn(leftConfig, leftColumn.getIdentifier().getValue()).isPresent() && findShardingColumn(rightConfig, rightColumn.getIdentifier().getValue()).isPresent()) { - result.add(columnExpressionTableNames.get(leftColumn.getExpression())); - result.add(columnExpressionTableNames.get(rightColumn.getExpression())); + result.add(leftColumn.getColumnBoundInfo().getOriginalTable().getValue()); + result.add(rightColumn.getColumnBoundInfo().getOriginalTable().getValue()); } } return result; diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngineTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngineTest.java index 307d85fc262ee..d85bba0435e9c 100644 --- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngineTest.java +++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/WhereClauseShardingConditionEngineTest.java @@ -17,7 +17,6 @@ package org.apache.shardingsphere.sharding.route.engine.condition.engine; -import org.apache.groovy.util.Maps; import org.apache.shardingsphere.infra.binder.context.segment.table.TablesContext; import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; import org.apache.shardingsphere.infra.config.props.ConfigurationProperties; @@ -52,7 +51,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -78,9 +76,6 @@ void setUp() { shardingConditionEngine = new WhereClauseShardingConditionEngine(ShardingSphereDatabase.create("test_db", TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), new ConfigurationProperties(new Properties())), shardingRule, mock(TimestampServiceRule.class)); when(sqlStatementContext.getWhereSegments()).thenReturn(Collections.singleton(whereSegment)); - when(sqlStatementContext.getTablesContext()).thenReturn(tablesContext); - when(sqlStatementContext.getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class, "FIXTURE")); - when(tablesContext.findTableNames(anyCollection(), any())).thenReturn(Maps.of("foo_sharding_col", "table_1")); } @Test diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rule/ShardingRuleTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rule/ShardingRuleTest.java index 4d2c328ee126f..9caefec97bf8f 100644 --- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rule/ShardingRuleTest.java +++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rule/ShardingRuleTest.java @@ -53,6 +53,8 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.JoinTableSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment; @@ -653,7 +655,6 @@ void assertIsAllBindingTableWithJoinQueryWithDatabaseJoinCondition() { when(sqlStatementContext.getDatabaseType()).thenReturn(databaseType); when(sqlStatementContext.getTablesContext().getSchemaName()).thenReturn(Optional.empty()); ShardingSphereSchema schema = mock(ShardingSphereSchema.class); - when(sqlStatementContext.getTablesContext().findTableNames(Arrays.asList(leftDatabaseJoin, rightDatabaseJoin), schema)).thenReturn(createColumnTableNameMap()); ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS); when(database.getName()).thenReturn("foo_db"); when(database.getSchema("foo_db")).thenReturn(schema); @@ -686,10 +687,18 @@ void assertIsAllBindingTableWithJoinQueryWithDatabaseJoinConditionInUpperCaseAnd @Test void assertIsAllBindingTableWithJoinQueryWithDatabaseTableJoinCondition() { ColumnSegment leftDatabaseJoin = createColumnSegment("user_id", "logic_Table"); + leftDatabaseJoin.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue("logic_Table"), + new IdentifierValue("user_id"))); ColumnSegment rightDatabaseJoin = createColumnSegment("user_id", "sub_Logic_Table"); + rightDatabaseJoin.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue("sub_Logic_Table"), + new IdentifierValue("user_id"))); BinaryOperationExpression databaseJoin = createBinaryOperationExpression(leftDatabaseJoin, rightDatabaseJoin, EQUAL); ColumnSegment leftTableJoin = createColumnSegment("order_id", "logic_Table"); + leftTableJoin.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue("logic_Table"), + new IdentifierValue("order_id"))); ColumnSegment rightTableJoin = createColumnSegment("order_id", "sub_Logic_Table"); + rightTableJoin.setColumnBoundInfo(new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new IdentifierValue("foo_db"), new IdentifierValue("foo_db")), new IdentifierValue("sub_Logic_Table"), + new IdentifierValue("order_id"))); BinaryOperationExpression tableJoin = createBinaryOperationExpression(leftTableJoin, rightTableJoin, EQUAL); JoinTableSegment joinTable = mock(JoinTableSegment.class); BinaryOperationExpression condition = createBinaryOperationExpression(databaseJoin, tableJoin, AND); @@ -703,8 +712,6 @@ void assertIsAllBindingTableWithJoinQueryWithDatabaseTableJoinCondition() { when(sqlStatementContext.getTablesContext().getSchemaName()).thenReturn(Optional.empty()); when(sqlStatementContext.getWhereSegments()).thenReturn(Collections.singleton(new WhereSegment(0, 0, condition))); ShardingSphereSchema schema = mock(ShardingSphereSchema.class); - when(sqlStatementContext.getTablesContext().findTableNames(Arrays.asList(leftDatabaseJoin, rightDatabaseJoin), schema)).thenReturn(createColumnTableNameMap()); - when(sqlStatementContext.getTablesContext().findTableNames(Arrays.asList(leftTableJoin, rightTableJoin), schema)).thenReturn(createColumnTableNameMap()); ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS); when(database.getName()).thenReturn("foo_db"); when(database.getSchema("foo_db")).thenReturn(schema); diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContext.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContext.java index 50fb33851a60e..b274f0d8eaa05 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContext.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContext.java @@ -17,19 +17,14 @@ package org.apache.shardingsphere.infra.binder.context.segment.table; -import com.cedarsoftware.util.CaseInsensitiveMap; import com.cedarsoftware.util.CaseInsensitiveSet; import com.google.common.base.Preconditions; import lombok.AccessLevel; import lombok.Getter; import lombok.ToString; -import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation; import org.apache.shardingsphere.infra.binder.context.segment.select.subquery.SubqueryTableContext; import org.apache.shardingsphere.infra.binder.context.segment.select.subquery.engine.SubqueryTableContextEngine; import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable; -import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment; @@ -38,11 +33,9 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import java.util.Optional; -import java.util.TreeSet; /** * Tables context. @@ -111,126 +104,6 @@ private Map> createSubqueryTables(final return result; } - /** - * Find expression table name map. - * - * @param columns column segments - * @param schema schema - * @return expression table name map - */ - @HighFrequencyInvocation - public Map findTableNames(final Collection columns, final ShardingSphereSchema schema) { - if (1 == simpleTables.size()) { - return findTableNameFromSingleTable(columns); - } - Map result = new CaseInsensitiveMap<>(); - Map> ownerColumnNames = getOwnerColumnNames(columns); - result.putAll(findTableNameFromSQL(ownerColumnNames)); - Collection noOwnerColumnNames = getNoOwnerColumnNames(columns); - result.putAll(findTableNameFromMetaData(noOwnerColumnNames, schema)); - result.putAll(findTableNameFromSubquery(columns, result)); - return result; - } - - @HighFrequencyInvocation - private Map findTableNameFromSingleTable(final Collection columns) { - String tableName = simpleTables.iterator().next().getTableName().getIdentifier().getValue(); - Map result = new CaseInsensitiveMap<>(); - for (ColumnSegment each : columns) { - result.putIfAbsent(each.getExpression(), tableName); - } - return result; - } - - @HighFrequencyInvocation - private Map> getOwnerColumnNames(final Collection columns) { - Map> result = new CaseInsensitiveMap<>(); - for (ColumnSegment each : columns) { - if (!each.getOwner().isPresent()) { - continue; - } - result.computeIfAbsent(each.getOwner().get().getIdentifier().getValue(), unused -> new LinkedList<>()).add(each.getExpression()); - } - return result; - } - - @HighFrequencyInvocation - private Map findTableNameFromSQL(final Map> ownerColumnNames) { - if (ownerColumnNames.isEmpty()) { - return Collections.emptyMap(); - } - Map result = new LinkedHashMap<>(simpleTables.size(), 1F); - for (SimpleTableSegment each : simpleTables) { - String tableName = each.getTableName().getIdentifier().getValue(); - if (ownerColumnNames.containsKey(tableName)) { - ownerColumnNames.get(tableName).forEach(column -> result.put(column, tableName)); - } - Optional alias = each.getAliasName(); - if (alias.isPresent() && ownerColumnNames.containsKey(alias.get())) { - ownerColumnNames.get(alias.get()).forEach(column -> result.put(column, tableName)); - } - } - return result; - } - - @HighFrequencyInvocation - private Map findTableNameFromMetaData(final Collection noOwnerColumnNames, final ShardingSphereSchema schema) { - if (noOwnerColumnNames.isEmpty()) { - return Collections.emptyMap(); - } - Map result = new LinkedHashMap<>(noOwnerColumnNames.size(), 1F); - for (SimpleTableSegment each : simpleTables) { - String tableName = each.getTableName().getIdentifier().getValue(); - if (schema.containsTable(tableName)) { - filterColumnNames(noOwnerColumnNames, schema.getTable(tableName)).forEach(columnName -> result.put(columnName, tableName)); - } - } - return result; - } - - @HighFrequencyInvocation - private Collection filterColumnNames(final Collection noOwnerColumnNames, final ShardingSphereTable table) { - Collection result = new LinkedList<>(); - for (String each : noOwnerColumnNames) { - if (table.containsColumn(each)) { - result.add(each); - } - } - return result; - } - - @HighFrequencyInvocation - private Collection getNoOwnerColumnNames(final Collection columns) { - Collection result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - for (ColumnSegment each : columns) { - if (!each.getOwner().isPresent()) { - result.add(each.getIdentifier().getValue()); - } - } - return result; - } - - @HighFrequencyInvocation - private Map findTableNameFromSubquery(final Collection columns, final Map ownerTableNames) { - if (ownerTableNames.size() == columns.size() || subqueryTables.isEmpty()) { - return Collections.emptyMap(); - } - Map result = new LinkedHashMap<>(columns.size(), 1F); - for (ColumnSegment each : columns) { - if (ownerTableNames.containsKey(each.getExpression())) { - continue; - } - String owner = each.getOwner().map(optional -> optional.getIdentifier().getValue()).orElse(""); - Collection subqueryTableContexts = subqueryTables.getOrDefault(owner, Collections.emptyList()); - for (SubqueryTableContext subqueryTableContext : subqueryTableContexts) { - if (subqueryTableContext.getColumnNames().contains(each.getIdentifier().getValue())) { - result.put(each.getExpression(), subqueryTableContext.getTableName()); - } - } - } - return result; - } - /** * Get database name. * diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java index 5adaf40ff5d11..78b395fc203b8 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java @@ -23,6 +23,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.BetweenExpressionSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.BinaryOperationExpressionBinder; import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.ColumnSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.ExistsSubqueryExpressionBinder; @@ -33,6 +34,7 @@ import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExistsSubqueryExpression; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment; @@ -84,6 +86,9 @@ public static ExpressionSegment bind(final ExpressionSegment segment, final Segm if (segment instanceof FunctionSegment) { return FunctionExpressionSegmentBinder.bind((FunctionSegment) segment, parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts); } + if (segment instanceof BetweenExpression) { + return BetweenExpressionSegmentBinder.bind((BetweenExpression) segment, binderContext, tableBinderContexts, outerTableBinderContexts); + } // TODO support more ExpressionSegment bound return segment; } diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BetweenExpressionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BetweenExpressionSegmentBinder.java new file mode 100644 index 0000000000000..b12f2c5feaaf4 --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BetweenExpressionSegmentBinder.java @@ -0,0 +1,54 @@ +/* + * 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.engine.segment.expression.type; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.expression.ExpressionSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment; + +/** + * Between expression binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BetweenExpressionSegmentBinder { + + /** + * Bind between expression. + * + * @param segment between expression segment + * @param binderContext SQL statement binder context + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @return bound between segment + */ + public static BetweenExpression bind(final BetweenExpression segment, final SQLStatementBinderContext binderContext, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts) { + ExpressionSegment boundLeft = ExpressionSegmentBinder.bind(segment.getLeft(), SegmentType.PREDICATE, binderContext, tableBinderContexts, outerTableBinderContexts); + ExpressionSegment boundBetweenExpr = ExpressionSegmentBinder.bind(segment.getBetweenExpr(), SegmentType.PREDICATE, binderContext, tableBinderContexts, outerTableBinderContexts); + ExpressionSegment boundAndExpr = ExpressionSegmentBinder.bind(segment.getAndExpr(), SegmentType.PREDICATE, binderContext, tableBinderContexts, outerTableBinderContexts); + return new BetweenExpression(segment.getStartIndex(), segment.getStopIndex(), boundLeft, boundBetweenExpr, boundAndExpr, segment.isNot()); + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/GroupBySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/GroupBySegmentBinder.java new file mode 100644 index 0000000000000..8d36597ed7460 --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/GroupBySegmentBinder.java @@ -0,0 +1,71 @@ +/* + * 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.engine.segment.order; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.segment.order.item.OrderByItemSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.exception.kernel.metadata.ColumnNotFoundException; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.GroupBySegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment; + +import java.util.Collection; +import java.util.LinkedList; + +/** + * Group by segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class GroupBySegmentBinder { + + /** + * Bind group by segment. + * + * @param segment group by segment + * @param binderContext SQL statement binder context + * @param currentTableBinderContexts current table binder contexts + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @return bound group by segment + */ + public static GroupBySegment bind(final GroupBySegment segment, final SQLStatementBinderContext binderContext, + final Multimap currentTableBinderContexts, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts) { + Collection boundGroupByItems = new LinkedList<>(); + for (OrderByItemSegment each : segment.getGroupByItems()) { + boundGroupByItems.add(bind(binderContext, currentTableBinderContexts, tableBinderContexts, outerTableBinderContexts, each)); + } + return new GroupBySegment(segment.getStartIndex(), segment.getStopIndex(), boundGroupByItems); + } + + private static OrderByItemSegment bind(final SQLStatementBinderContext binderContext, final Multimap currentTableBinderContexts, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts, final OrderByItemSegment groupByItemSegment) { + try { + return OrderByItemSegmentBinder.bind(groupByItemSegment, binderContext, currentTableBinderContexts, outerTableBinderContexts, SegmentType.GROUP_BY); + } catch (final ColumnNotFoundException ignored) { + return OrderByItemSegmentBinder.bind(groupByItemSegment, binderContext, tableBinderContexts, outerTableBinderContexts, SegmentType.GROUP_BY); + } + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/OrderBySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/OrderBySegmentBinder.java new file mode 100644 index 0000000000000..426549e60141a --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/OrderBySegmentBinder.java @@ -0,0 +1,71 @@ +/* + * 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.engine.segment.order; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.segment.order.item.OrderByItemSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.exception.kernel.metadata.ColumnNotFoundException; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.OrderBySegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment; + +import java.util.Collection; +import java.util.LinkedList; + +/** + * Order by segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class OrderBySegmentBinder { + + /** + * Bind order by segment. + * + * @param segment order by segment + * @param binderContext SQL statement binder context + * @param currentTableBinderContexts current table binder contexts + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @return bound order by segment + */ + public static OrderBySegment bind(final OrderBySegment segment, final SQLStatementBinderContext binderContext, + final Multimap currentTableBinderContexts, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts) { + Collection boundGroupByItems = new LinkedList<>(); + for (OrderByItemSegment each : segment.getOrderByItems()) { + boundGroupByItems.add(bind(binderContext, currentTableBinderContexts, tableBinderContexts, outerTableBinderContexts, each)); + } + return new OrderBySegment(segment.getStartIndex(), segment.getStopIndex(), boundGroupByItems); + } + + private static OrderByItemSegment bind(final SQLStatementBinderContext binderContext, final Multimap currentTableBinderContexts, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts, final OrderByItemSegment orderByItemSegment) { + try { + return OrderByItemSegmentBinder.bind(orderByItemSegment, binderContext, currentTableBinderContexts, outerTableBinderContexts, SegmentType.ORDER_BY); + } catch (final ColumnNotFoundException ignored) { + return OrderByItemSegmentBinder.bind(orderByItemSegment, binderContext, tableBinderContexts, outerTableBinderContexts, SegmentType.ORDER_BY); + } + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ColumnOrderByItemSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ColumnOrderByItemSegmentBinder.java new file mode 100644 index 0000000000000..abedd2763b122 --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ColumnOrderByItemSegmentBinder.java @@ -0,0 +1,52 @@ +/* + * 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.engine.segment.order.item; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.ColumnSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment; + +/** + * Column order by item segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ColumnOrderByItemSegmentBinder { + + /** + * Bind column order by item segment. + * + * @param segment column order by item segment + * @param binderContext SQL statement binder context + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @param segmentType segment type + * @return bound column order by item segment + */ + public static ColumnOrderByItemSegment bind(final ColumnOrderByItemSegment segment, final SQLStatementBinderContext binderContext, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts, final SegmentType segmentType) { + return new ColumnOrderByItemSegment(ColumnSegmentBinder.bind(segment.getColumn(), segmentType, binderContext, tableBinderContexts, outerTableBinderContexts), segment.getOrderDirection(), + segment.getNullsOrderType().orElse(null)); + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ExpressionOrderByItemSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ExpressionOrderByItemSegmentBinder.java new file mode 100644 index 0000000000000..454fa2142f380 --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/ExpressionOrderByItemSegmentBinder.java @@ -0,0 +1,52 @@ +/* + * 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.engine.segment.order.item; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.expression.ExpressionSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ExpressionOrderByItemSegment; + +/** + * Expression order by item segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ExpressionOrderByItemSegmentBinder { + + /** + * Bind expression order by item segment. + * + * @param segment expression order by item segment + * @param binderContext SQL statement binder context + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @param segmentType segment type + * @return bound expression order by item segment + */ + public static ExpressionOrderByItemSegment bind(final ExpressionOrderByItemSegment segment, final SQLStatementBinderContext binderContext, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts, final SegmentType segmentType) { + return new ExpressionOrderByItemSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getExpression(), segment.getOrderDirection(), segment.getNullsOrderType().orElse(null), + ExpressionSegmentBinder.bind(segment.getExpr(), segmentType, binderContext, tableBinderContexts, outerTableBinderContexts)); + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/OrderByItemSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/OrderByItemSegmentBinder.java new file mode 100644 index 0000000000000..b1e152b4938ad --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/order/item/OrderByItemSegmentBinder.java @@ -0,0 +1,58 @@ +/* + * 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.engine.segment.order.item; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ExpressionOrderByItemSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment; + +/** + * Order by item segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class OrderByItemSegmentBinder { + + /** + * Bind order by item segment. + * + * @param segment order by item segment + * @param binderContext SQL statement binder context + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @param segmentType segment type + * @return bound order by item segment + */ + public static OrderByItemSegment bind(final OrderByItemSegment segment, final SQLStatementBinderContext binderContext, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts, final SegmentType segmentType) { + if (segment instanceof ColumnOrderByItemSegment) { + return ColumnOrderByItemSegmentBinder.bind((ColumnOrderByItemSegment) segment, binderContext, tableBinderContexts, outerTableBinderContexts, segmentType); + } + if (segment instanceof ExpressionOrderByItemSegment) { + return ExpressionOrderByItemSegmentBinder.bind((ExpressionOrderByItemSegment) segment, binderContext, tableBinderContexts, outerTableBinderContexts, segmentType); + } + return segment; + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/HavingSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/HavingSegmentBinder.java new file mode 100644 index 0000000000000..d321b700a2fba --- /dev/null +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/HavingSegmentBinder.java @@ -0,0 +1,51 @@ +/* + * 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.engine.segment.predicate; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.Multimap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType; +import org.apache.shardingsphere.infra.binder.engine.segment.expression.ExpressionSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.HavingSegment; + +/** + * Having segment binder. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class HavingSegmentBinder { + + /** + * Bind having segment. + * + * @param segment having segment + * @param binderContext SQL statement binder context + * @param tableBinderContexts table binder contexts + * @param outerTableBinderContexts outer table binder contexts + * @return bound having segment + */ + public static HavingSegment bind(final HavingSegment segment, final SQLStatementBinderContext binderContext, + final Multimap tableBinderContexts, + final Multimap outerTableBinderContexts) { + return new HavingSegment(segment.getStartIndex(), segment.getStopIndex(), + ExpressionSegmentBinder.bind(segment.getExpr(), SegmentType.PREDICATE, binderContext, tableBinderContexts, outerTableBinderContexts)); + } +} diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinder.java similarity index 97% rename from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java rename to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinder.java index 8c96935e7e874..c9e57d1cb7871 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinder.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.shardingsphere.infra.binder.engine.segment.where; +package org.apache.shardingsphere.infra.binder.engine.segment.predicate; import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; import com.google.common.collect.Multimap; diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java index 663c8f5bb45d4..30ad9a5519971 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java @@ -23,7 +23,7 @@ import lombok.SneakyThrows; import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; -import org.apache.shardingsphere.infra.binder.engine.segment.where.WhereSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.predicate.WhereSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.DeleteStatement; diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java index 47c8357c87dc8..521d949a899f9 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java @@ -25,14 +25,22 @@ import org.apache.shardingsphere.infra.binder.engine.segment.combine.CombineSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext; import org.apache.shardingsphere.infra.binder.engine.segment.lock.LockSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.order.GroupBySegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.order.OrderBySegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.predicate.HavingSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.predicate.WhereSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.projection.ProjectionsSegmentBinder; -import org.apache.shardingsphere.infra.binder.engine.segment.where.WhereSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.binder.engine.util.SubqueryTableBindUtils; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment; import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.SelectStatement; +import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; +import java.util.Collection; import java.util.Optional; /** @@ -57,16 +65,27 @@ public SelectStatement bind(final SelectStatement sqlStatement, final SQLStateme sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, binderContext, tableBinderContexts, outerTableBinderContexts))); sqlStatement.getCombine().ifPresent(optional -> result.setCombine(CombineSegmentBinder.bind(optional, binderContext, outerTableBinderContexts))); sqlStatement.getLock().ifPresent(optional -> result.setLock(LockSegmentBinder.bind(optional, binderContext, tableBinderContexts, outerTableBinderContexts))); + Multimap currentTableBinderContexts = createCurrentTableBinderContexts(binderContext, result); + sqlStatement.getGroupBy().ifPresent(optional -> result.setGroupBy( + GroupBySegmentBinder.bind(optional, binderContext, currentTableBinderContexts, tableBinderContexts, outerTableBinderContexts))); + sqlStatement.getOrderBy().ifPresent(optional -> result.setOrderBy( + OrderBySegmentBinder.bind(optional, binderContext, currentTableBinderContexts, tableBinderContexts, outerTableBinderContexts))); + sqlStatement.getHaving().ifPresent(optional -> result.setHaving(HavingSegmentBinder.bind(optional, binderContext, currentTableBinderContexts, outerTableBinderContexts))); // TODO support other segment bind in select statement return result; } + private Multimap createCurrentTableBinderContexts(final SQLStatementBinderContext binderContext, final SelectStatement selectStatement) { + Multimap result = LinkedHashMultimap.create(); + Collection subqueryProjections = SubqueryTableBindUtils.createSubqueryProjections( + selectStatement.getProjections().getProjections(), new IdentifierValue(""), binderContext.getSqlStatement().getDatabaseType()); + result.put(new CaseInsensitiveString(""), new SimpleTableSegmentBinderContext(subqueryProjections)); + return result; + } + @SneakyThrows(ReflectiveOperationException.class) private SelectStatement copy(final SelectStatement sqlStatement) { SelectStatement result = sqlStatement.getClass().getDeclaredConstructor().newInstance(); - sqlStatement.getGroupBy().ifPresent(result::setGroupBy); - sqlStatement.getHaving().ifPresent(result::setHaving); - sqlStatement.getOrderBy().ifPresent(result::setOrderBy); sqlStatement.getLimit().ifPresent(result::setLimit); sqlStatement.getWindow().ifPresent(result::setWindow); sqlStatement.getModelSegment().ifPresent(result::setModelSegment); @@ -74,6 +93,7 @@ private SelectStatement copy(final SelectStatement sqlStatement) { sqlStatement.getWithSegment().ifPresent(result::setWithSegment); result.addParameterMarkerSegments(sqlStatement.getParameterMarkerSegments()); result.getCommentSegments().addAll(sqlStatement.getCommentSegments()); + result.getVariableNames().addAll(sqlStatement.getVariableNames()); return result; } } diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java index 2747106952de2..1de69236fdd96 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java @@ -24,7 +24,7 @@ import org.apache.shardingsphere.infra.binder.engine.segment.assign.AssignmentSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext; -import org.apache.shardingsphere.infra.binder.engine.segment.where.WhereSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.segment.predicate.WhereSegmentBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.UpdateStatement; diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContextTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContextTest.java index 377c317dfb3da..20fd15c36b2ff 100644 --- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContextTest.java +++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/table/TablesContextTest.java @@ -17,10 +17,6 @@ package org.apache.shardingsphere.infra.binder.context.segment.table; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; -import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable; -import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; @@ -33,16 +29,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.Map; import java.util.Optional; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class TablesContextTest { @@ -75,61 +68,6 @@ void assertInstanceCreatedWhenNoExceptionThrown() { assertThat(tablesContext.getTableNames(), is(Collections.singleton("tbl"))); } - @Test - void assertFindTableNameWhenSingleTable() { - SimpleTableSegment tableSegment = createTableSegment("table_1", "tbl_1", "sharding_db_1"); - ColumnSegment columnSegment = createColumnSegment(null, "col"); - Map actual = new TablesContext(Collections.singletonList(tableSegment)).findTableNames(Collections.singletonList(columnSegment), mock()); - assertFalse(actual.isEmpty()); - assertThat(actual.get("col"), is("table_1")); - } - - @Test - void assertFindTableNameWhenColumnSegmentOwnerPresent() { - SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1", "sharding_db_1"); - SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2", "sharding_db_1"); - ColumnSegment columnSegment = createColumnSegment("table_1", "col"); - Map actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2)).findTableNames(Collections.singletonList(columnSegment), mock()); - assertFalse(actual.isEmpty()); - assertThat(actual.get("table_1.col"), is("table_1")); - } - - @Test - void assertFindTableNameWhenColumnSegmentOwnerAbsent() { - SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1", "sharding_db_1"); - SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2", "sharding_db_1"); - ColumnSegment columnSegment = createColumnSegment(null, "col"); - Map actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2)).findTableNames(Collections.singletonList(columnSegment), mock()); - assertTrue(actual.isEmpty()); - } - - @Test - void assertFindTableNameWhenColumnSegmentOwnerAbsentAndSchemaMetaDataContainsColumn() { - SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1", "sharding_db_1"); - SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2", "sharding_db_1"); - ShardingSphereSchema schema = mock(ShardingSphereSchema.class); - when(schema.containsTable("table_1")).thenReturn(true); - ShardingSphereTable table = mock(ShardingSphereTable.class); - when(table.containsColumn("col")).thenReturn(true); - when(schema.getTable("table_1")).thenReturn(table); - ColumnSegment columnSegment = createColumnSegment(null, "col"); - Map actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2)).findTableNames(Collections.singletonList(columnSegment), schema); - assertThat(actual.get("col"), is("table_1")); - } - - @Test - void assertFindTableNameWhenColumnSegmentOwnerAbsentAndSchemaMetaDataContainsColumnInUpperCase() { - SimpleTableSegment tableSegment1 = createTableSegment("TABLE_1", "TBL_1", "sharding_db_1"); - SimpleTableSegment tableSegment2 = createTableSegment("TABLE_2", "TBL_2", "sharding_db_1"); - ShardingSphereTable table = new ShardingSphereTable("TABLE_1", - Collections.singletonList(new ShardingSphereColumn("COL", 0, false, false, true, true, false, false)), Collections.emptyList(), Collections.emptyList()); - ShardingSphereSchema schema = new ShardingSphereSchema("foo_db", Collections.singleton(table), Collections.emptyList()); - ColumnSegment columnSegment = createColumnSegment(null, "COL"); - Map actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2)).findTableNames(Collections.singletonList(columnSegment), schema); - assertFalse(actual.isEmpty()); - assertThat(actual.get("col"), is("TABLE_1")); - } - private SimpleTableSegment createTableSegment(final String tableName, final String alias, final String databaseName) { TableNameSegment tableNameSegment = new TableNameSegment(0, 0, new IdentifierValue(tableName)); tableNameSegment.setTableBoundInfo(new TableSegmentBoundInfo(new IdentifierValue(databaseName), new IdentifierValue(databaseName))); @@ -139,14 +77,6 @@ private SimpleTableSegment createTableSegment(final String tableName, final Stri return result; } - private ColumnSegment createColumnSegment(final String owner, final String name) { - ColumnSegment result = new ColumnSegment(0, 0, new IdentifierValue(name)); - if (null != owner) { - result.setOwner(new OwnerSegment(0, 0, new IdentifierValue(owner))); - } - return result; - } - @Test void assertGetSchemaNameWithSameSchemaAndSameTable() { SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1", "sharding_db_1"); diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinderTest.java similarity index 97% rename from infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java rename to infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinderTest.java index 84815358e6316..ebb18e15c6c21 100644 --- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java +++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/predicate/WhereSegmentBinderTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.shardingsphere.infra.binder.engine.segment.where; +package org.apache.shardingsphere.infra.binder.engine.segment.predicate; import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; import com.google.common.collect.LinkedHashMultimap;