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() {


Reply via email to