This is an automated email from the ASF dual-hosted git repository.
sunnianjun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 613867ab330 Add unsupported check for join using and natural join
statement (#28220)
613867ab330 is described below
commit 613867ab3305b144fda233109c88316698e3aca6
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Tue Aug 22 18:37:10 2023 +0800
Add unsupported check for join using and natural join statement (#28220)
---
.../rewrite/token/EncryptTokenGenerateBuilder.java | 14 +--
.../EncryptPredicateColumnTokenGenerator.java | 46 +---------
.../token/util/EncryptTokenGeneratorUtils.java | 100 +++++++++++++++++++++
.../context/segment/table/TablesContext.java | 4 +
.../expression/impl/ColumnSegmentBinder.java | 55 ++++++++++--
.../segment/from/impl/JoinTableSegmentBinder.java | 45 ++++++++--
.../impl/ShorthandProjectionSegmentBinder.java | 2 +-
.../from/impl/JoinTableSegmentBinderTest.java | 10 +--
.../impl/ShorthandProjectionSegmentBinderTest.java | 2 +-
.../common/segment/dml/column/ColumnSegment.java | 2 +
.../segment/generic/table/JoinTableSegment.java | 4 +-
11 files changed, 212 insertions(+), 72 deletions(-)
diff --git
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/EncryptTokenGenerateBuilder.java
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/EncryptTokenGenerateBuilder.java
index cb83d615712..d88307b641e 100644
---
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/EncryptTokenGenerateBuilder.java
+++
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/EncryptTokenGenerateBuilder.java
@@ -19,23 +19,24 @@ package org.apache.shardingsphere.encrypt.rewrite.token;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.encrypt.rewrite.aware.DatabaseNameAware;
+import org.apache.shardingsphere.encrypt.rewrite.aware.DatabaseTypeAware;
import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptConditionsAware;
+import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptRuleAware;
import org.apache.shardingsphere.encrypt.rewrite.condition.EncryptCondition;
-import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertDerivedColumnsTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptAlterTableTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptAssignmentTokenGenerator;
-import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptIndexColumnTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptCreateTableTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptForUseDefaultInsertColumnsTokenGenerator;
-import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertOnUpdateTokenGenerator;
-import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertValuesTokenGenerator;
+import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptIndexColumnTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptOrderByItemTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptPredicateColumnTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptPredicateRightValueTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.EncryptProjectionTokenGenerator;
import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertCipherNameTokenGenerator;
+import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertDerivedColumnsTokenGenerator;
+import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertOnUpdateTokenGenerator;
+import
org.apache.shardingsphere.encrypt.rewrite.token.generator.insert.EncryptInsertValuesTokenGenerator;
import org.apache.shardingsphere.encrypt.rule.EncryptRule;
-import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptRuleAware;
import
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import
org.apache.shardingsphere.infra.rewrite.sql.token.generator.SQLTokenGenerator;
import
org.apache.shardingsphere.infra.rewrite.sql.token.generator.builder.SQLTokenGeneratorBuilder;
@@ -93,5 +94,8 @@ public final class EncryptTokenGenerateBuilder implements
SQLTokenGeneratorBuild
if (toBeAddedSQLTokenGenerator instanceof DatabaseNameAware) {
((DatabaseNameAware)
toBeAddedSQLTokenGenerator).setDatabaseName(databaseName);
}
+ if (toBeAddedSQLTokenGenerator instanceof DatabaseTypeAware) {
+ ((DatabaseTypeAware)
toBeAddedSQLTokenGenerator).setDatabaseType(sqlStatementContext.getDatabaseType());
+ }
}
}
diff --git
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptPredicateColumnTokenGenerator.java
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptPredicateColumnTokenGenerator.java
index eda1c1cc2a0..dcedd90a791 100644
---
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptPredicateColumnTokenGenerator.java
+++
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptPredicateColumnTokenGenerator.java
@@ -21,10 +21,10 @@ import lombok.Setter;
import
org.apache.shardingsphere.encrypt.exception.syntax.UnsupportedEncryptSQLException;
import org.apache.shardingsphere.encrypt.rewrite.aware.DatabaseTypeAware;
import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptRuleAware;
+import
org.apache.shardingsphere.encrypt.rewrite.token.util.EncryptTokenGeneratorUtils;
import org.apache.shardingsphere.encrypt.rule.EncryptRule;
import org.apache.shardingsphere.encrypt.rule.EncryptTable;
import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn;
-import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
import
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
@@ -82,15 +82,15 @@ public final class EncryptPredicateColumnTokenGenerator
implements CollectionSQL
whereSegments = ((WhereAvailable)
sqlStatementContext).getWhereSegments();
joinConditions = ((WhereAvailable)
sqlStatementContext).getJoinConditions();
}
-
ShardingSpherePreconditions.checkState(isAllJoinConditionsUseSameEncryptor(joinConditions),
() -> new UnsupportedSQLOperationException("Can not use different encryptor in
join condition"));
+
ShardingSpherePreconditions.checkState(EncryptTokenGeneratorUtils.isAllJoinConditionsUseSameEncryptor(joinConditions,
encryptRule),
+ () -> new UnsupportedSQLOperationException("Can not use
different encryptor in join condition"));
String defaultSchema = new
DatabaseTypeRegistry(sqlStatementContext.getDatabaseType()).getDefaultSchemaName(databaseName);
ShardingSphereSchema schema =
sqlStatementContext.getTablesContext().getSchemaName().map(schemas::get).orElseGet(()
-> schemas.get(defaultSchema));
Map<String, String> columnExpressionTableNames =
sqlStatementContext.getTablesContext().findTableNamesByColumnSegment(columnSegments,
schema);
return generateSQLTokens(columnSegments, columnExpressionTableNames,
whereSegments);
}
- private Collection<SQLToken> generateSQLTokens(final
Collection<ColumnSegment> columnSegments,
- final Map<String, String>
columnExpressionTableNames, final Collection<WhereSegment> whereSegments) {
+ private Collection<SQLToken> generateSQLTokens(final
Collection<ColumnSegment> columnSegments, final Map<String, String>
columnExpressionTableNames, final Collection<WhereSegment> whereSegments) {
Collection<SQLToken> result = new LinkedHashSet<>();
for (ColumnSegment each : columnSegments) {
String tableName =
Optional.ofNullable(columnExpressionTableNames.get(each.getExpression())).orElse("");
@@ -102,44 +102,6 @@ public final class EncryptPredicateColumnTokenGenerator
implements CollectionSQL
return result;
}
- private boolean isAllJoinConditionsUseSameEncryptor(final
Collection<BinaryOperationExpression> joinConditions) {
- for (BinaryOperationExpression each : joinConditions) {
- if (!(each.getLeft() instanceof ColumnSegment) ||
!(each.getRight() instanceof ColumnSegment)) {
- continue;
- }
- EncryptAlgorithm<?, ?> leftColumnEncryptor =
getColumnEncryptor((ColumnSegment) each.getLeft());
- EncryptAlgorithm<?, ?> rightColumnEncryptor =
getColumnEncryptor((ColumnSegment) each.getRight());
- if (!isSameEncryptor(leftColumnEncryptor, rightColumnEncryptor)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean isSameEncryptor(final EncryptAlgorithm<?, ?>
leftColumnEncryptor, final EncryptAlgorithm<?, ?> rightColumnEncryptor) {
- if (null != leftColumnEncryptor && null != rightColumnEncryptor) {
- if
(!leftColumnEncryptor.getType().equals(rightColumnEncryptor.getType())) {
- return false;
- }
- return leftColumnEncryptor.equals(rightColumnEncryptor);
- }
- return null == leftColumnEncryptor && null == rightColumnEncryptor;
- }
-
- private EncryptAlgorithm<?, ?> getColumnEncryptor(final ColumnSegment
columnSegment) {
- String tableName =
columnSegment.getColumnBoundedInfo().getOriginalTable().getValue();
- String columnName =
columnSegment.getColumnBoundedInfo().getOriginalColumn().getValue();
- if (!encryptRule.findEncryptTable(tableName).isPresent() ||
!encryptRule.getEncryptTable(tableName).isEncryptColumn(columnName)) {
- return null;
- }
- EncryptTable encryptTable = encryptRule.getEncryptTable(tableName);
- EncryptColumn encryptColumn =
encryptTable.getEncryptColumn(columnName);
- if (encryptColumn.getAssistedQuery().isPresent()) {
- return encryptColumn.getAssistedQuery().get().getEncryptor();
- }
- return encryptColumn.getCipher().getEncryptor();
- }
-
private SubstitutableColumnNameToken
buildSubstitutableColumnNameToken(final EncryptColumn encryptColumn, final
ColumnSegment columnSegment, final Collection<WhereSegment> whereSegments) {
int startIndex = columnSegment.getOwner().isPresent() ?
columnSegment.getOwner().get().getStopIndex() + 2 :
columnSegment.getStartIndex();
int stopIndex = columnSegment.getStopIndex();
diff --git
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/util/EncryptTokenGeneratorUtils.java
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/util/EncryptTokenGeneratorUtils.java
new file mode 100644
index 00000000000..e191301196c
--- /dev/null
+++
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/util/EncryptTokenGeneratorUtils.java
@@ -0,0 +1,100 @@
+/*
+ * 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.encrypt.rewrite.token.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.encrypt.rule.EncryptRule;
+import org.apache.shardingsphere.encrypt.rule.EncryptTable;
+import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn;
+import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.bounded.ColumnSegmentBoundedInfo;
+
+import java.util.Collection;
+
+/**
+ * Encrypt token generator utils.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class EncryptTokenGeneratorUtils {
+
+ /**
+ * Judge whether all join conditions use same encryptor or not.
+ *
+ * @param joinConditions join conditions
+ * @param encryptRule encrypt rule
+ * @return whether all join conditions use same encryptor or not
+ */
+ public static boolean isAllJoinConditionsUseSameEncryptor(final
Collection<BinaryOperationExpression> joinConditions, final EncryptRule
encryptRule) {
+ for (BinaryOperationExpression each : joinConditions) {
+ if (!(each.getLeft() instanceof ColumnSegment) ||
!(each.getRight() instanceof ColumnSegment)) {
+ continue;
+ }
+ EncryptAlgorithm<?, ?> leftColumnEncryptor =
getColumnEncryptor(((ColumnSegment) each.getLeft()).getColumnBoundedInfo(),
encryptRule);
+ EncryptAlgorithm<?, ?> rightColumnEncryptor =
getColumnEncryptor(((ColumnSegment) each.getRight()).getColumnBoundedInfo(),
encryptRule);
+ if (!isSameEncryptor(leftColumnEncryptor, rightColumnEncryptor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Judge whether all using columns use same encryptor or not.
+ *
+ * @param usingColumns using columns
+ * @param encryptRule encrypt rule
+ * @return whether all using columns use same encryptor or not
+ */
+ public static boolean isAllUsingConditionsUseSameEncryptor(final
Collection<ColumnSegment> usingColumns, final EncryptRule encryptRule) {
+ for (ColumnSegment each : usingColumns) {
+ EncryptAlgorithm<?, ?> leftColumnEncryptor =
getColumnEncryptor(each.getColumnBoundedInfo(), encryptRule);
+ EncryptAlgorithm<?, ?> rightColumnEncryptor =
getColumnEncryptor(each.getOtherUsingColumnBoundedInfo(), encryptRule);
+ if (!isSameEncryptor(leftColumnEncryptor, rightColumnEncryptor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isSameEncryptor(final EncryptAlgorithm<?, ?>
leftColumnEncryptor, final EncryptAlgorithm<?, ?> rightColumnEncryptor) {
+ if (null != leftColumnEncryptor && null != rightColumnEncryptor) {
+ if
(!leftColumnEncryptor.getType().equals(rightColumnEncryptor.getType())) {
+ return false;
+ }
+ return leftColumnEncryptor.equals(rightColumnEncryptor);
+ }
+ return null == leftColumnEncryptor && null == rightColumnEncryptor;
+ }
+
+ private static EncryptAlgorithm<?, ?> getColumnEncryptor(final
ColumnSegmentBoundedInfo columnBoundedInfo, final EncryptRule encryptRule) {
+ String tableName = columnBoundedInfo.getOriginalTable().getValue();
+ String columnName = columnBoundedInfo.getOriginalColumn().getValue();
+ if (!encryptRule.findEncryptTable(tableName).isPresent() ||
!encryptRule.getEncryptTable(tableName).isEncryptColumn(columnName)) {
+ return null;
+ }
+ EncryptTable encryptTable = encryptRule.getEncryptTable(tableName);
+ EncryptColumn encryptColumn =
encryptTable.getEncryptColumn(columnName);
+ if (encryptColumn.getAssistedQuery().isPresent()) {
+ return encryptColumn.getAssistedQuery().get().getEncryptor();
+ }
+ return encryptColumn.getCipher().getEncryptor();
+ }
+}
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 d47750d7fdb..09836ebed26 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
@@ -32,6 +32,7 @@ import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegm
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
import java.util.Collection;
import java.util.Collections;
@@ -63,6 +64,8 @@ public final class TablesContext {
private final Map<String, Collection<SubqueryTableContext>> subqueryTables
= new HashMap<>();
+ private final Map<String, IdentifierValue> tableNameAliasMap = new
HashMap<>();
+
public TablesContext(final SimpleTableSegment tableSegment, final
DatabaseType databaseType) {
this(Collections.singletonList(tableSegment), databaseType);
}
@@ -83,6 +86,7 @@ public final class TablesContext {
tableNames.add(simpleTableSegment.getTableName().getIdentifier().getValue());
simpleTableSegment.getOwner().ifPresent(optional ->
schemaNames.add(optional.getIdentifier().getValue()));
findDatabaseName(simpleTableSegment,
databaseType).ifPresent(databaseNames::add);
+
tableNameAliasMap.put(simpleTableSegment.getTableName().getIdentifier().getValue().toLowerCase(),
each.getAlias().orElse(simpleTableSegment.getTableName().getIdentifier()));
}
if (each instanceof SubqueryTableSegment) {
subqueryTables.putAll(createSubqueryTables(subqueryContexts,
(SubqueryTableSegment) each));
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
index bac14132113..0356b40deaf 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
@@ -33,7 +33,9 @@ import
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.Identifi
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;
@@ -63,14 +65,7 @@ public final class ColumnSegmentBinder {
segment.getOwner().ifPresent(result::setOwner);
Collection<TableSegmentBinderContext> tableBinderContextValues =
getTableSegmentBinderContexts(segment, statementBinderContext,
tableBinderContexts, outerTableBinderContexts);
Optional<ColumnSegment> inputColumnSegment =
findInputColumnSegment(segment.getIdentifier().getValue(),
tableBinderContextValues);
- IdentifierValue originalDatabase = inputColumnSegment.map(optional ->
optional.getColumnBoundedInfo().getOriginalDatabase()).orElse(null);
- IdentifierValue originalSchema = inputColumnSegment.map(optional ->
optional.getColumnBoundedInfo().getOriginalSchema()).orElse(null);
- IdentifierValue originalTable = null ==
segment.getColumnBoundedInfo().getOriginalTable() ?
inputColumnSegment.map(optional ->
optional.getColumnBoundedInfo().getOriginalTable()).orElse(null)
- : segment.getColumnBoundedInfo().getOriginalTable();
- IdentifierValue originalColumn =
- null == segment.getColumnBoundedInfo().getOriginalColumn() ?
inputColumnSegment.map(optional ->
optional.getColumnBoundedInfo().getOriginalColumn()).orElse(null)
- : segment.getColumnBoundedInfo().getOriginalColumn();
- result.setColumnBoundedInfo(new
ColumnSegmentBoundedInfo(originalDatabase, originalSchema, originalTable,
originalColumn));
+ result.setColumnBoundedInfo(createColumnSegmentBoundedInfo(segment,
inputColumnSegment.orElse(null)));
return result;
}
@@ -111,4 +106,48 @@ public final class ColumnSegmentBinder {
ShardingSpherePreconditions.checkState(null != projectionSegment, ()
-> new UnknownColumnException(columnName));
return Optional.ofNullable(result);
}
+
+ private static ColumnSegmentBoundedInfo
createColumnSegmentBoundedInfo(final ColumnSegment segment, final ColumnSegment
inputColumnSegment) {
+ IdentifierValue originalDatabase = null == inputColumnSegment ? null :
inputColumnSegment.getColumnBoundedInfo().getOriginalDatabase();
+ IdentifierValue originalSchema = null == inputColumnSegment ? null :
inputColumnSegment.getColumnBoundedInfo().getOriginalSchema();
+ IdentifierValue originalTable =
+ null == segment.getColumnBoundedInfo().getOriginalTable() ?
Optional.ofNullable(inputColumnSegment).map(optional ->
optional.getColumnBoundedInfo().getOriginalTable()).orElse(null)
+ : segment.getColumnBoundedInfo().getOriginalTable();
+ IdentifierValue originalColumn =
+ null == segment.getColumnBoundedInfo().getOriginalColumn() ?
Optional.ofNullable(inputColumnSegment).map(optional ->
optional.getColumnBoundedInfo().getOriginalColumn()).orElse(null)
+ : segment.getColumnBoundedInfo().getOriginalColumn();
+ return new ColumnSegmentBoundedInfo(originalDatabase, originalSchema,
originalTable, originalColumn);
+ }
+
+ /**
+ * Bind using column segment with metadata.
+ *
+ * @param segment using column segment
+ * @param tableBinderContexts table binder contexts
+ * @return bounded using column segment
+ */
+ public static ColumnSegment bindUsingColumn(final ColumnSegment segment,
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ ColumnSegment result = new ColumnSegment(segment.getStartIndex(),
segment.getStopIndex(), segment.getIdentifier());
+ segment.getOwner().ifPresent(result::setOwner);
+ Collection<TableSegmentBinderContext> tableBinderContextValues =
tableBinderContexts.values();
+ Collection<ColumnSegment> usingInputColumnSegments =
findUsingInputColumnSegments(segment.getIdentifier().getValue(),
tableBinderContextValues);
+ if (usingInputColumnSegments.size() >= 2) {
+ Iterator<ColumnSegment> iterator =
usingInputColumnSegments.iterator();
+
result.setColumnBoundedInfo(createColumnSegmentBoundedInfo(segment,
iterator.next()));
+
result.setOtherUsingColumnBoundedInfo(createColumnSegmentBoundedInfo(segment,
iterator.next()));
+ }
+ return result;
+ }
+
+ private static Collection<ColumnSegment>
findUsingInputColumnSegments(final String columnName, final
Collection<TableSegmentBinderContext> tableBinderContexts) {
+ ProjectionSegment projectionSegment;
+ Collection<ColumnSegment> result = new LinkedList<>();
+ for (TableSegmentBinderContext each : tableBinderContexts) {
+ projectionSegment =
each.getProjectionSegmentByColumnLabel(columnName);
+ if (projectionSegment instanceof ColumnProjectionSegment) {
+ result.add(((ColumnProjectionSegment)
projectionSegment).getColumn());
+ }
+ }
+ return result;
+ }
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
index 240707463cd..3bce8ffd49a 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
@@ -20,6 +20,7 @@ package
org.apache.shardingsphere.infra.binder.segment.from.impl;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import
org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
+import
org.apache.shardingsphere.infra.binder.segment.expression.impl.ColumnSegmentBinder;
import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import
org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
@@ -28,6 +29,7 @@ import
org.apache.shardingsphere.infra.database.mysql.type.MySQLDatabaseType;
import
org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
@@ -38,6 +40,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
/**
@@ -64,22 +67,46 @@ public final class JoinTableSegmentBinder {
result.setJoinType(segment.getJoinType());
result.setRight(TableSegmentBinder.bind(segment.getRight(),
statementBinderContext, tableBinderContexts));
result.setCondition(ExpressionSegmentBinder.bind(segment.getCondition(),
statementBinderContext, tableBinderContexts, Collections.emptyMap()));
- // TODO bind using column in join table segment
- result.setUsing(segment.getUsing());
-
result.getJoinTableProjectionSegments().addAll(getJoinTableProjectionSegments(result,
statementBinderContext.getDatabaseType(), tableBinderContexts));
-
statementBinderContext.getJoinTableProjectionSegments().addAll(result.getJoinTableProjectionSegments());
+ result.setUsing(bindUsingColumns(segment.getUsing(),
tableBinderContexts));
+ Map<String, ProjectionSegment> usingColumnsByNaturalJoin =
Collections.emptyMap();
+ if (result.isNatural()) {
+ usingColumnsByNaturalJoin = getUsingColumnsByNaturalJoin(result,
tableBinderContexts);
+ Collection<ColumnSegment> derivedUsingColumns =
getDerivedUsingColumns(usingColumnsByNaturalJoin);
+ result.setDerivedUsing(bindUsingColumns(derivedUsingColumns,
tableBinderContexts));
+ }
+
result.getDerivedJoinTableProjectionSegments().addAll(getDerivedJoinTableProjectionSegments(result,
statementBinderContext.getDatabaseType(), usingColumnsByNaturalJoin,
tableBinderContexts));
+
statementBinderContext.getJoinTableProjectionSegments().addAll(result.getDerivedJoinTableProjectionSegments());
+ return result;
+ }
+
+ private static Collection<ColumnSegment> getDerivedUsingColumns(final
Map<String, ProjectionSegment> usingColumnsByNaturalJoin) {
+ Collection<ColumnSegment> result = new LinkedList<>();
+ for (ProjectionSegment each : usingColumnsByNaturalJoin.values()) {
+ if (each instanceof ColumnProjectionSegment) {
+ ColumnSegment column = ((ColumnProjectionSegment)
each).getColumn();
+ result.add(new ColumnSegment(column.getStartIndex(),
column.getStopIndex(), column.getIdentifier()));
+ }
+ }
+ return result;
+ }
+
+ private static List<ColumnSegment> bindUsingColumns(final
Collection<ColumnSegment> usingColumns, final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
+ List<ColumnSegment> result = new LinkedList<>();
+ for (ColumnSegment each : usingColumns) {
+ result.add(ColumnSegmentBinder.bindUsingColumn(each,
tableBinderContexts));
+ }
return result;
}
- private static Collection<ProjectionSegment>
getJoinTableProjectionSegments(final JoinTableSegment segment, final
DatabaseType databaseType,
-
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ private static Collection<ProjectionSegment>
getDerivedJoinTableProjectionSegments(final JoinTableSegment segment, final
DatabaseType databaseType,
+
final Map<String, ProjectionSegment> usingColumnsByNaturalJoin,
+
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
Collection<ProjectionSegment> projectionSegments =
getProjectionSegments(segment, databaseType, tableBinderContexts);
if (segment.getUsing().isEmpty() && !segment.isNatural()) {
return projectionSegments;
}
Collection<ProjectionSegment> result = new LinkedList<>();
- Map<String, ProjectionSegment> originalUsingColumns =
- segment.getUsing().isEmpty() ?
getUsingColumnsByNaturalJoin(segment, tableBinderContexts) :
getUsingColumns(projectionSegments, segment.getUsing());
+ Map<String, ProjectionSegment> originalUsingColumns =
segment.getUsing().isEmpty() ? usingColumnsByNaturalJoin :
getUsingColumns(projectionSegments, segment.getUsing());
Collection<ProjectionSegment> orderedUsingColumns =
databaseType instanceof MySQLDatabaseType ?
getJoinUsingColumnsByProjectionOrder(projectionSegments, originalUsingColumns)
: originalUsingColumns.values();
result.addAll(orderedUsingColumns);
@@ -106,7 +133,7 @@ public final class JoinTableSegmentBinder {
String tableAliasOrName = tableSegment.getAliasName().orElseGet(()
-> ((SimpleTableSegment)
tableSegment).getTableName().getIdentifier().getValue());
result.addAll(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableAliasOrName));
} else if (tableSegment instanceof JoinTableSegment) {
- result.addAll(((JoinTableSegment)
tableSegment).getJoinTableProjectionSegments());
+ result.addAll(((JoinTableSegment)
tableSegment).getDerivedJoinTableProjectionSegments());
} else if (tableSegment instanceof SubqueryTableSegment) {
result.addAll(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableSegment.getAliasName().orElse("")));
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
index 0f96d49f80d..2d6b8a6b421 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
@@ -78,7 +78,7 @@ public final class ShorthandProjectionSegmentBinder {
String tableAliasOrName =
boundedTableSegment.getAliasName().orElseGet(() -> ((SimpleTableSegment)
boundedTableSegment).getTableName().getIdentifier().getValue());
expandVisibleColumn(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableAliasOrName), segment);
} else if (boundedTableSegment instanceof JoinTableSegment) {
- expandVisibleColumn(((JoinTableSegment)
boundedTableSegment).getJoinTableProjectionSegments(), segment);
+ expandVisibleColumn(((JoinTableSegment)
boundedTableSegment).getDerivedJoinTableProjectionSegments(), segment);
} else if (boundedTableSegment instanceof SubqueryTableSegment) {
expandVisibleColumn(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
boundedTableSegment.getAliasName().orElse("")), segment);
}
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
index 15b4b59478a..1cbed4b5952 100644
---
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
@@ -73,7 +73,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
-
assertJoinTableProjectionSegments(actual.getJoinTableProjectionSegments());
+
assertJoinTableProjectionSegments(actual.getDerivedJoinTableProjectionSegments());
assertTrue(tableBinderContexts.containsKey("o"));
assertTrue(tableBinderContexts.containsKey("i"));
}
@@ -114,7 +114,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
-
assertJoinTableProjectionSegments(actual.getJoinTableProjectionSegments());
+
assertJoinTableProjectionSegments(actual.getDerivedJoinTableProjectionSegments());
assertTrue(tableBinderContexts.containsKey("t_order"));
assertTrue(tableBinderContexts.containsKey("t_order_item"));
}
@@ -139,7 +139,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
-
assertJoinTableProjectionSegmentsWithNaturalJoin(actual.getJoinTableProjectionSegments());
+
assertJoinTableProjectionSegmentsWithNaturalJoin(actual.getDerivedJoinTableProjectionSegments());
assertTrue(tableBinderContexts.containsKey("o"));
assertTrue(tableBinderContexts.containsKey("i"));
}
@@ -178,7 +178,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
-
assertJoinTableProjectionSegmentsWithUsing(actual.getJoinTableProjectionSegments());
+
assertJoinTableProjectionSegmentsWithUsing(actual.getDerivedJoinTableProjectionSegments());
assertTrue(tableBinderContexts.containsKey("o"));
assertTrue(tableBinderContexts.containsKey("i"));
}
@@ -220,7 +220,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getTableBoundedInfo().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
- assertThat(actual.getJoinTableProjectionSegments().size(), is(10));
+ assertThat(actual.getDerivedJoinTableProjectionSegments().size(),
is(10));
assertTrue(tableBinderContexts.containsKey("o"));
assertTrue(tableBinderContexts.containsKey("o2"));
assertTrue(tableBinderContexts.containsKey("i"));
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
index ece3353aab6..416b4ebd2d1 100644
---
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
@@ -95,7 +95,7 @@ class ShorthandProjectionSegmentBinderTest {
void assertBindWithoutOwnerForJoinTableSegment() {
ShorthandProjectionSegment shorthandProjectionSegment = new
ShorthandProjectionSegment(0, 0);
JoinTableSegment boundedTableSegment = new JoinTableSegment();
- boundedTableSegment.getJoinTableProjectionSegments().add(new
ColumnProjectionSegment(new ColumnSegment(0, 0, new
IdentifierValue("order_id"))));
+ boundedTableSegment.getDerivedJoinTableProjectionSegments().add(new
ColumnProjectionSegment(new ColumnSegment(0, 0, new
IdentifierValue("order_id"))));
ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment,
boundedTableSegment, Collections.emptyMap());
assertThat(actual.getActualProjectionSegments().size(), is(1));
ProjectionSegment visibleColumn =
actual.getActualProjectionSegments().iterator().next();
diff --git
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/column/ColumnSegment.java
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/column/ColumnSegment.java
index 3ef6404d02d..5703b4fff69 100644
---
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/column/ColumnSegment.java
+++
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/column/ColumnSegment.java
@@ -48,6 +48,8 @@ public final class ColumnSegment implements
ExpressionSegment, OwnerAvailable {
private ColumnSegmentBoundedInfo columnBoundedInfo;
+ private ColumnSegmentBoundedInfo otherUsingColumnBoundedInfo;
+
public ColumnSegment(final int startIndex, final int stopIndex, final
IdentifierValue identifier) {
this.startIndex = startIndex;
this.stopIndex = stopIndex;
diff --git
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
index 2e5aa535e75..2c381a3e968 100644
---
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
+++
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
@@ -53,7 +53,9 @@ public final class JoinTableSegment implements TableSegment {
private List<ColumnSegment> using = Collections.emptyList();
- private Collection<ProjectionSegment> joinTableProjectionSegments = new
LinkedList<>();
+ private List<ColumnSegment> derivedUsing = Collections.emptyList();
+
+ private Collection<ProjectionSegment> derivedJoinTableProjectionSegments =
new LinkedList<>();
@Override
public Optional<String> getAliasName() {