You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by pa...@apache.org on 2023/08/08 00:26:24 UTC

[shardingsphere] branch master updated: Remove useless findTableNamesByColumnProjection and simplify code (#27963)

This is an automated email from the ASF dual-hosted git repository.

panjuan 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 17dbb3fe233 Remove useless findTableNamesByColumnProjection and simplify code (#27963)
17dbb3fe233 is described below

commit 17dbb3fe2332c74ab9d937e2daf9d7896bfd0d96
Author: Zhengqiang Duan <du...@apache.org>
AuthorDate: Tue Aug 8 08:26:18 2023 +0800

    Remove useless findTableNamesByColumnProjection and simplify code (#27963)
---
 .../encrypt/merge/dql/EncryptMergedResult.java     | 34 ++--------
 .../generator/EncryptProjectionTokenGenerator.java | 79 ++++++++--------------
 .../EncryptProjectionTokenGeneratorTest.java       |  7 +-
 .../mask/merge/dql/MaskAlgorithmMetaData.java      | 23 +------
 .../mask/merge/dql/MaskAlgorithmMetaDataTest.java  |  6 +-
 .../engine/type/standard/SubqueryRouteTest.java    |  2 +-
 .../standard/assertion/ShardingRouteAssert.java    |  3 +-
 .../context/segment/table/TablesContext.java       | 69 -------------------
 .../expression/ExpressionSegmentBinder.java        | 63 +++++++++++++++++
 .../BinaryOperationExpressionBinder.java}          | 27 ++++----
 .../expression/{ => impl}/ColumnSegmentBinder.java |  2 +-
 .../ExistsSubqueryExpressionBinder.java}           | 23 +++----
 .../InExpressionBinder.java}                       | 27 ++++----
 .../SubqueryExpressionSegmentBinder.java}          | 23 +++----
 .../{ => impl}/SubquerySegmentBinder.java          |  2 +-
 .../projection/ProjectionsSegmentBinder.java       | 19 ++++--
 .../impl/ColumnProjectionSegmentBinder.java        |  2 +-
 ...r.java => SubqueryProjectionSegmentBinder.java} | 30 ++++----
 .../WhereSegmentBinder.java}                       | 26 +++----
 .../statement/dml/InsertStatementBinder.java       |  2 +-
 .../statement/dml/SelectStatementBinder.java       |  5 +-
 .../context/segment/table/TablesContextTest.java   | 59 ----------------
 .../resultset/SQLFederationResultSetMetaData.java  |  5 +-
 .../dml/item/SubqueryProjectionSegment.java        |  9 +++
 .../prepare/MySQLComStmtPrepareExecutor.java       |  9 +--
 25 files changed, 220 insertions(+), 336 deletions(-)

diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/merge/dql/EncryptMergedResult.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/merge/dql/EncryptMergedResult.java
index 6432674c11a..32724b912c6 100644
--- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/merge/dql/EncryptMergedResult.java
+++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/merge/dql/EncryptMergedResult.java
@@ -21,7 +21,6 @@ import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
 import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn;
 import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
-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.database.core.type.DatabaseTypeRegistry;
 import org.apache.shardingsphere.infra.merge.result.MergedResult;
@@ -31,8 +30,6 @@ import java.io.InputStream;
 import java.io.Reader;
 import java.sql.SQLException;
 import java.util.Calendar;
-import java.util.Collections;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -60,33 +57,16 @@ public final class EncryptMergedResult implements MergedResult {
         if (!columnProjection.isPresent()) {
             return mergedResult.getValue(columnIndex, type);
         }
-        TablesContext tablesContext = selectStatementContext.getTablesContext();
-        String schemaName = tablesContext.getSchemaName().orElseGet(() -> new DatabaseTypeRegistry(selectStatementContext.getDatabaseType()).getDefaultSchemaName(database.getName()));
-        ColumnProjection originalColumn = new ColumnProjection(columnProjection.get().getOriginalTable(), columnProjection.get().getOriginalColumn(), null, selectStatementContext.getDatabaseType());
-        Map<String, String> expressionTableNames = tablesContext.findTableNamesByColumnProjection(Collections.singletonList(originalColumn), database.getSchema(schemaName));
-        Optional<String> tableName = findTableName(originalColumn, expressionTableNames);
-        if (!tableName.isPresent()) {
-            return mergedResult.getValue(columnIndex, type);
-        }
-        if (!encryptRule.findEncryptTable(tableName.get()).map(optional -> optional.isEncryptColumn(originalColumn.getName().getValue())).orElse(false)) {
+        String originalTableName = columnProjection.get().getOriginalTable().getValue();
+        String originalColumnName = columnProjection.get().getOriginalColumn().getValue();
+        if (!encryptRule.findEncryptTable(originalTableName).map(optional -> optional.isEncryptColumn(originalColumnName)).orElse(false)) {
             return mergedResult.getValue(columnIndex, type);
         }
         Object cipherValue = mergedResult.getValue(columnIndex, Object.class);
-        EncryptColumn encryptColumn = encryptRule.getEncryptTable(tableName.get()).getEncryptColumn(originalColumn.getName().getValue());
-        return encryptColumn.getCipher().decrypt(database.getName(), schemaName, tableName.get(), originalColumn.getName().getValue(), cipherValue);
-    }
-    
-    private Optional<String> findTableName(final ColumnProjection columnProjection, final Map<String, String> columnTableNames) {
-        String tableName = columnTableNames.get(columnProjection.getExpression());
-        if (null != tableName) {
-            return Optional.of(tableName);
-        }
-        for (String each : selectStatementContext.getTablesContext().getTableNames()) {
-            if (encryptRule.findEncryptTable(each).map(optional -> optional.isEncryptColumn(columnProjection.getName().getValue())).orElse(false)) {
-                return Optional.of(each);
-            }
-        }
-        return Optional.empty();
+        EncryptColumn encryptColumn = encryptRule.getEncryptTable(originalTableName).getEncryptColumn(originalColumnName);
+        String schemaName =
+                selectStatementContext.getTablesContext().getSchemaName().orElseGet(() -> new DatabaseTypeRegistry(selectStatementContext.getDatabaseType()).getDefaultSchemaName(database.getName()));
+        return encryptColumn.getCipher().decrypt(database.getName(), schemaName, originalTableName, originalColumnName, cipherValue);
     }
     
     @Override
diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGenerator.java
index 9bfdd0879b5..99bfe795eb5 100644
--- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGenerator.java
+++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGenerator.java
@@ -35,10 +35,8 @@ import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatem
 import org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
-import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.rewrite.sql.token.generator.CollectionSQLTokenGenerator;
 import org.apache.shardingsphere.infra.rewrite.sql.token.generator.aware.PreviousSQLTokensAware;
-import org.apache.shardingsphere.infra.rewrite.sql.token.generator.aware.SchemaMetaDataAware;
 import org.apache.shardingsphere.infra.rewrite.sql.token.pojo.SQLToken;
 import org.apache.shardingsphere.infra.rewrite.sql.token.pojo.generic.SubstitutableColumnNameToken;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.SubqueryType;
@@ -48,29 +46,25 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.Shorthan
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
 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.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 
 /**
  * Projection token generator for encrypt.
  */
 @Setter
-public final class EncryptProjectionTokenGenerator implements CollectionSQLTokenGenerator<SQLStatementContext>, PreviousSQLTokensAware, SchemaMetaDataAware, EncryptRuleAware, DatabaseTypeAware {
+public final class EncryptProjectionTokenGenerator implements CollectionSQLTokenGenerator<SQLStatementContext>, PreviousSQLTokensAware, EncryptRuleAware, DatabaseTypeAware {
     
     private List<SQLToken> previousSQLTokens;
     
     private EncryptRule encryptRule;
     
-    private String databaseName;
-    
-    private Map<String, ShardingSphereSchema> schemas;
-    
     private DatabaseType databaseType;
     
     @Override
@@ -91,31 +85,37 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
     }
     
     private void addGenerateSQLTokens(final Collection<SQLToken> sqlTokens, final SelectStatementContext selectStatementContext) {
-        Map<String, String> columnTableNames = getColumnTableNames(selectStatementContext);
         for (ProjectionSegment each : selectStatementContext.getSqlStatement().getProjections().getProjections()) {
             SubqueryType subqueryType = selectStatementContext.getSubqueryType();
             if (each instanceof ColumnProjectionSegment) {
                 ColumnProjectionSegment columnSegment = (ColumnProjectionSegment) each;
                 ColumnProjection columnProjection = buildColumnProjection(columnSegment);
-                String tableName = columnTableNames.get(columnProjection.getExpression());
-                if (null == tableName) {
-                    continue;
-                }
-                Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(tableName);
-                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(columnProjection.getName().getValue()) && !containsTableSubquery(selectStatementContext)) {
-                    sqlTokens.add(generateSQLToken(encryptTable.get().getEncryptColumn(columnProjection.getName().getValue()), columnSegment, columnProjection, subqueryType));
+                String originalColumnName = columnProjection.getOriginalColumn().getValue();
+                Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(columnProjection.getOriginalTable().getValue());
+                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(originalColumnName) && !containsTableSubquery(selectStatementContext.getSqlStatement().getFrom())) {
+                    sqlTokens.add(generateSQLToken(encryptTable.get().getEncryptColumn(originalColumnName), columnSegment, columnProjection, subqueryType));
                 }
             }
             if (each instanceof ShorthandProjectionSegment) {
                 ShorthandProjectionSegment shorthandSegment = (ShorthandProjectionSegment) each;
                 Collection<Projection> actualColumns = getShorthandProjection(shorthandSegment, selectStatementContext.getProjectionsContext()).getActualColumns();
                 if (!actualColumns.isEmpty()) {
-                    sqlTokens.add(generateSQLToken(shorthandSegment, actualColumns, selectStatementContext, subqueryType, columnTableNames));
+                    sqlTokens.add(generateSQLToken(shorthandSegment, actualColumns, selectStatementContext, subqueryType));
                 }
             }
         }
     }
     
+    private boolean containsTableSubquery(final TableSegment tableSegment) {
+        if (tableSegment instanceof SubqueryTableSegment) {
+            return true;
+        } else if (tableSegment instanceof JoinTableSegment) {
+            JoinTableSegment joinTableSegment = (JoinTableSegment) tableSegment;
+            return containsTableSubquery(joinTableSegment.getLeft()) || containsTableSubquery(joinTableSegment.getRight());
+        }
+        return false;
+    }
+    
     private SubstitutableColumnNameToken generateSQLToken(final EncryptColumn encryptColumn, final ColumnProjectionSegment columnSegment,
                                                           final ColumnProjection columnProjection, final SubqueryType subqueryType) {
         Collection<Projection> projections = generateProjections(encryptColumn, columnProjection, subqueryType, false, null);
@@ -125,16 +125,19 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
     }
     
     private SubstitutableColumnNameToken generateSQLToken(final ShorthandProjectionSegment segment, final Collection<Projection> actualColumns,
-                                                          final SelectStatementContext selectStatementContext, final SubqueryType subqueryType, final Map<String, String> columnTableNames) {
+                                                          final SelectStatementContext selectStatementContext, final SubqueryType subqueryType) {
         List<Projection> projections = new LinkedList<>();
         for (Projection each : actualColumns) {
-            String tableName = columnTableNames.get(each.getExpression());
-            Optional<EncryptTable> encryptTable = null == tableName ? Optional.empty() : encryptRule.findEncryptTable(tableName);
-            if (!encryptTable.isPresent() || !encryptTable.get().isEncryptColumn(each.getColumnLabel()) || containsTableSubquery(selectStatementContext)) {
+            if (each instanceof ColumnProjection) {
+                Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(((ColumnProjection) each).getOriginalTable().getValue());
+                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(((ColumnProjection) each).getOriginalColumn().getValue())
+                        && !containsTableSubquery(selectStatementContext.getSqlStatement().getFrom())) {
+                    EncryptColumn encryptColumn = encryptTable.get().getEncryptColumn(((ColumnProjection) each).getName().getValue());
+                    projections.addAll(generateProjections(encryptColumn, (ColumnProjection) each, subqueryType, true, segment));
+                    continue;
+                }
                 projections.add(each.getAlias().filter(alias -> !DerivedColumn.isDerivedColumnName(alias.getValue()))
                         .map(optional -> (Projection) new ColumnProjection(null, optional, null, databaseType)).orElse(each));
-            } else if (each instanceof ColumnProjection) {
-                projections.addAll(generateProjections(encryptTable.get().getEncryptColumn(((ColumnProjection) each).getName().getValue()), (ColumnProjection) each, subqueryType, true, segment));
             }
         }
         int startIndex = segment.getOwner().isPresent() ? segment.getOwner().get().getStartIndex() : segment.getStartIndex();
@@ -143,34 +146,12 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
         return new SubstitutableColumnNameToken(startIndex, segment.getStopIndex(), projections, dialectDatabaseMetaData.getQuoteCharacter());
     }
     
-    private boolean containsTableSubquery(final SelectStatementContext selectStatementContext) {
-        if (selectStatementContext.getSqlStatement().getFrom() instanceof SubqueryTableSegment) {
-            return true;
-        } else if (selectStatementContext.getSqlStatement().getFrom() instanceof JoinTableSegment) {
-            JoinTableSegment joinTableSegment = (JoinTableSegment) selectStatementContext.getSqlStatement().getFrom();
-            return joinTableSegment.getLeft() instanceof SubqueryTableSegment || joinTableSegment.getRight() instanceof SubqueryTableSegment;
-        }
-        return false;
-    }
-    
     private ColumnProjection buildColumnProjection(final ColumnProjectionSegment segment) {
         IdentifierValue owner = segment.getColumn().getOwner().map(OwnerSegment::getIdentifier).orElse(null);
-        return new ColumnProjection(owner, segment.getColumn().getIdentifier(), segment.getAliasName().isPresent() ? segment.getAlias().orElse(null) : null, databaseType);
-    }
-    
-    private Map<String, String> getColumnTableNames(final SelectStatementContext selectStatementContext) {
-        Collection<ColumnProjection> columns = new LinkedList<>();
-        for (Projection projection : selectStatementContext.getProjectionsContext().getProjections()) {
-            if (projection instanceof ColumnProjection) {
-                columns.add((ColumnProjection) projection);
-            }
-            if (projection instanceof ShorthandProjection) {
-                columns.addAll(((ShorthandProjection) projection).getColumnProjections());
-            }
-        }
-        String defaultSchema = new DatabaseTypeRegistry(selectStatementContext.getDatabaseType()).getDefaultSchemaName(databaseName);
-        ShardingSphereSchema schema = selectStatementContext.getTablesContext().getSchemaName().map(schemas::get).orElseGet(() -> schemas.get(defaultSchema));
-        return selectStatementContext.getTablesContext().findTableNamesByColumnProjection(columns, schema);
+        ColumnProjection result = new ColumnProjection(owner, segment.getColumn().getIdentifier(), segment.getAliasName().isPresent() ? segment.getAlias().orElse(null) : null, databaseType);
+        result.setOriginalColumn(segment.getColumn().getOriginalColumn());
+        result.setOriginalTable(segment.getColumn().getOriginalTable());
+        return result;
     }
     
     private Collection<Projection> generateProjections(final EncryptColumn encryptColumn, final ColumnProjection column,
diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGeneratorTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGeneratorTest.java
index 1180ccb294f..fe4e21962d3 100644
--- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGeneratorTest.java
+++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptProjectionTokenGeneratorTest.java
@@ -24,7 +24,6 @@ import org.apache.shardingsphere.infra.binder.context.segment.select.projection.
 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.database.core.type.DatabaseType;
-import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.rewrite.sql.token.pojo.SQLToken;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
@@ -58,8 +57,6 @@ class EncryptProjectionTokenGeneratorTest {
     @BeforeEach
     void setup() {
         generator.setEncryptRule(mockEncryptRule());
-        generator.setDatabaseName("db_schema");
-        generator.setSchemas(Collections.singletonMap("test", mock(ShardingSphereSchema.class)));
     }
     
     private EncryptRule mockEncryptRule() {
@@ -82,6 +79,8 @@ class EncryptProjectionTokenGeneratorTest {
         SimpleTableSegment doctorTable = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("doctor")));
         doctorTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("a")));
         ColumnSegment column = new ColumnSegment(0, 0, new IdentifierValue("mobile"));
+        column.setOriginalColumn(new IdentifierValue("mobile"));
+        column.setOriginalTable(new IdentifierValue("doctor"));
         column.setOwner(new OwnerSegment(0, 0, new IdentifierValue("a")));
         ProjectionsSegment projections = mock(ProjectionsSegment.class);
         when(projections.getProjections()).thenReturn(Collections.singletonList(new ColumnProjectionSegment(column)));
@@ -101,6 +100,8 @@ class EncryptProjectionTokenGeneratorTest {
         SimpleTableSegment doctorTable = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("doctor")));
         doctorTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("a")));
         ColumnSegment column = new ColumnSegment(0, 0, new IdentifierValue("mobile"));
+        column.setOriginalColumn(new IdentifierValue("mobile"));
+        column.setOriginalTable(new IdentifierValue("doctor"));
         column.setOwner(new OwnerSegment(0, 0, new IdentifierValue("a")));
         ProjectionsSegment projections = mock(ProjectionsSegment.class);
         when(projections.getProjections()).thenReturn(Collections.singletonList(new ColumnProjectionSegment(column)));
diff --git a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaData.java b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaData.java
index 0a4da833854..70b85687899 100644
--- a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaData.java
+++ b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaData.java
@@ -20,16 +20,12 @@ package org.apache.shardingsphere.mask.merge.dql;
 import lombok.RequiredArgsConstructor;
 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.segment.table.TablesContext;
 import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
-import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.mask.rule.MaskRule;
 import org.apache.shardingsphere.mask.spi.MaskAlgorithm;
 
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -56,11 +52,7 @@ public final class MaskAlgorithmMetaData {
         if (!columnProjection.isPresent()) {
             return Optional.empty();
         }
-        TablesContext tablesContext = selectStatementContext.getTablesContext();
-        String schemaName = tablesContext.getSchemaName().orElseGet(() -> new DatabaseTypeRegistry(selectStatementContext.getDatabaseType()).getDefaultSchemaName(database.getName()));
-        Map<String, String> expressionTableNames = tablesContext.findTableNamesByColumnProjection(
-                Collections.singletonList(columnProjection.get()), database.getSchema(schemaName));
-        return findTableName(columnProjection.get(), expressionTableNames).flatMap(optional -> maskRule.findMaskAlgorithm(optional, columnProjection.get().getName().getValue()));
+        return maskRule.findMaskAlgorithm(columnProjection.get().getOriginalTable().getValue(), columnProjection.get().getName().getValue());
     }
     
     private Optional<ColumnProjection> findColumnProjection(final int columnIndex) {
@@ -71,17 +63,4 @@ public final class MaskAlgorithmMetaData {
         Projection projection = expandProjections.get(columnIndex - 1);
         return projection instanceof ColumnProjection ? Optional.of((ColumnProjection) projection) : Optional.empty();
     }
-    
-    private Optional<String> findTableName(final ColumnProjection columnProjection, final Map<String, String> columnTableNames) {
-        String tableName = columnTableNames.get(columnProjection.getExpression());
-        if (null != tableName) {
-            return Optional.of(tableName);
-        }
-        for (String each : selectStatementContext.getTablesContext().getTableNames()) {
-            if (maskRule.findMaskAlgorithm(each, columnProjection.getName().getValue()).isPresent()) {
-                return Optional.of(each);
-            }
-        }
-        return Optional.empty();
-    }
 }
diff --git a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaDataTest.java b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaDataTest.java
index 9de8619e000..eae75d2a29c 100644
--- a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaDataTest.java
+++ b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/merge/dql/MaskAlgorithmMetaDataTest.java
@@ -24,6 +24,7 @@ import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.mask.rule.MaskRule;
 import org.apache.shardingsphere.mask.spi.MaskAlgorithm;
+import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Answers;
@@ -55,7 +56,10 @@ class MaskAlgorithmMetaDataTest {
     @Test
     void assertFindMaskAlgorithmByColumnIndex() {
         when(maskRule.findMaskAlgorithm("t_order", "order_id")).thenReturn(Optional.of(TypedSPILoader.getService(MaskAlgorithm.class, "MD5")));
-        when(selectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Collections.singletonList(new ColumnProjection(null, "order_id", null, mock(DatabaseType.class))));
+        ColumnProjection columnProjection = new ColumnProjection(null, "order_id", null, mock(DatabaseType.class));
+        columnProjection.setOriginalColumn(new IdentifierValue("order_id"));
+        columnProjection.setOriginalTable(new IdentifierValue("t_order"));
+        when(selectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Collections.singletonList(columnProjection));
         when(selectStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singletonList("t_order"));
         Optional<MaskAlgorithm> actual = new MaskAlgorithmMetaData(database, maskRule, selectStatementContext).findMaskAlgorithmByColumnIndex(1);
         assertTrue(actual.isPresent());
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/SubqueryRouteTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/SubqueryRouteTest.java
index 95d9e28a684..2622fe3b6d5 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/SubqueryRouteTest.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/SubqueryRouteTest.java
@@ -45,7 +45,7 @@ class SubqueryRouteTest {
         HintManager hintManager = HintManager.getInstance();
         hintManager.addDatabaseShardingValue("t_hint_test", 1);
         hintManager.addTableShardingValue("t_hint_test", 1);
-        String sql = "select count(*) from t_hint_test where user_id = (select t_hint_test from t_hint_test where user_id in (?,?,?)) ";
+        String sql = "select count(*) from t_hint_test where user_id = (select user_id from t_hint_test where user_id in (?,?,?)) ";
         ShardingRouteAssert.assertRoute(sql, Arrays.asList(1, 3, 5));
         hintManager.close();
     }
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/assertion/ShardingRouteAssert.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/assertion/ShardingRouteAssert.java
index a8caa0b5cde..06b396c70d3 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/assertion/ShardingRouteAssert.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/type/standard/assertion/ShardingRouteAssert.java
@@ -108,7 +108,8 @@ public final class ShardingRouteAssert {
         tables.put("t_category", new ShardingSphereTable("t_category", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
         tables.put("t_product", new ShardingSphereTable("t_product", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
         tables.put("t_user", new ShardingSphereTable("t_user", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
-        tables.put("t_hint_test", new ShardingSphereTable("t_hint_test", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
+        tables.put("t_hint_test", new ShardingSphereTable("t_hint_test", Collections.singleton(new ShardingSphereColumn("user_id", Types.INTEGER, true, false, false, true, false, false)),
+                Collections.emptyList(), Collections.emptyList()));
         return Collections.singletonMap(DefaultDatabase.LOGIC_NAME, new ShardingSphereSchema(tables, Collections.emptyMap()));
     }
 }
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 c899a39a9f2..d47750d7fdb 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
@@ -20,7 +20,6 @@ package org.apache.shardingsphere.infra.binder.context.segment.table;
 import com.google.common.base.Preconditions;
 import lombok.Getter;
 import lombok.ToString;
-import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
 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;
@@ -138,26 +137,6 @@ public final class TablesContext {
         return result;
     }
     
-    /**
-     * Find expression table name map by column projection.
-     *
-     * @param columns column segment collection
-     * @param schema schema meta data
-     * @return expression table name map
-     */
-    public Map<String, String> findTableNamesByColumnProjection(final Collection<ColumnProjection> columns, final ShardingSphereSchema schema) {
-        if (1 == simpleTableSegments.size()) {
-            return findTableNameFromSingleTableByColumnProjection(columns);
-        }
-        Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        Map<String, Collection<String>> ownerColumnNames = getOwnerColumnNamesByColumnProjection(columns);
-        result.putAll(findTableNameFromSQL(ownerColumnNames));
-        Collection<String> noOwnerColumnNames = getNoOwnerColumnNamesByColumnProjection(columns);
-        result.putAll(findTableNameFromMetaData(noOwnerColumnNames, schema));
-        result.putAll(findTableNameFromSubqueryByColumnProjection(columns, result));
-        return result;
-    }
-    
     private Map<String, String> findTableNameFromSubqueryByColumnSegment(final Collection<ColumnSegment> columns, final Map<String, String> ownerTableNames) {
         if (ownerTableNames.size() == columns.size() || subqueryTables.isEmpty()) {
             return Collections.emptyMap();
@@ -178,25 +157,6 @@ public final class TablesContext {
         return result;
     }
     
-    private Map<String, String> findTableNameFromSubqueryByColumnProjection(final Collection<ColumnProjection> columns, final Map<String, String> ownerTableNames) {
-        if (ownerTableNames.size() == columns.size() || subqueryTables.isEmpty()) {
-            return Collections.emptyMap();
-        }
-        Map<String, String> result = new LinkedHashMap<>(columns.size(), 1F);
-        for (ColumnProjection each : columns) {
-            if (ownerTableNames.containsKey(each.getExpression())) {
-                continue;
-            }
-            Collection<SubqueryTableContext> subqueryTableContexts = each.getOwner().map(optional -> subqueryTables.get(each.getOwner().get().getValue())).orElseGet(Collections::emptyList);
-            for (SubqueryTableContext subqueryTableContext : subqueryTableContexts) {
-                if (subqueryTableContext.getColumnNames().contains(each.getName().getValue())) {
-                    result.put(each.getExpression(), subqueryTableContext.getTableName());
-                }
-            }
-        }
-        return result;
-    }
-    
     private Map<String, String> findTableNameFromSingleTableByColumnSegment(final Collection<ColumnSegment> columns) {
         String tableName = simpleTableSegments.iterator().next().getTableName().getIdentifier().getValue();
         Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -206,15 +166,6 @@ public final class TablesContext {
         return result;
     }
     
-    private Map<String, String> findTableNameFromSingleTableByColumnProjection(final Collection<ColumnProjection> columns) {
-        String tableName = simpleTableSegments.iterator().next().getTableName().getIdentifier().getValue();
-        Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        for (ColumnProjection each : columns) {
-            result.putIfAbsent(each.getExpression(), tableName);
-        }
-        return result;
-    }
-    
     private Map<String, Collection<String>> getOwnerColumnNamesByColumnSegment(final Collection<ColumnSegment> columns) {
         Map<String, Collection<String>> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
         for (ColumnSegment each : columns) {
@@ -226,16 +177,6 @@ public final class TablesContext {
         return result;
     }
     
-    private Map<String, Collection<String>> getOwnerColumnNamesByColumnProjection(final Collection<ColumnProjection> columns) {
-        Map<String, Collection<String>> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        for (ColumnProjection each : columns) {
-            if (each.getOwner().isPresent()) {
-                result.computeIfAbsent(each.getOwner().get().getValue(), unused -> new LinkedList<>()).add(each.getExpression());
-            }
-        }
-        return result;
-    }
-    
     private Map<String, String> findTableNameFromSQL(final Map<String, Collection<String>> ownerColumnNames) {
         if (ownerColumnNames.isEmpty()) {
             return Collections.emptyMap();
@@ -280,16 +221,6 @@ public final class TablesContext {
         return result;
     }
     
-    private Collection<String> getNoOwnerColumnNamesByColumnProjection(final Collection<ColumnProjection> columns) {
-        Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
-        for (ColumnProjection each : columns) {
-            if (!each.getOwner().isPresent()) {
-                result.add(each.getName().getValue());
-            }
-        }
-        return result;
-    }
-    
     /**
      * Get database name.
      *
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ExpressionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ExpressionSegmentBinder.java
new file mode 100644
index 00000000000..b342ac81d2e
--- /dev/null
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ExpressionSegmentBinder.java
@@ -0,0 +1,63 @@
+/*
+ * 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.segment.expression;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.BinaryOperationExpressionBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.ExistsSubqueryExpressionBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.InExpressionBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.SubqueryExpressionSegmentBinder;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExistsSubqueryExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubqueryExpressionSegment;
+
+/**
+ * Expression segment binder.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ExpressionSegmentBinder {
+    
+    /**
+     * Bind expression segment with metadata.
+     *
+     * @param segment expression segment
+     * @param metaData metaData
+     * @param defaultDatabaseName default database name
+     * @return bounded expression segment
+     */
+    public static ExpressionSegment bind(final ExpressionSegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        if (segment instanceof BinaryOperationExpression) {
+            return BinaryOperationExpressionBinder.bind((BinaryOperationExpression) segment, metaData, defaultDatabaseName);
+        }
+        if (segment instanceof ExistsSubqueryExpression) {
+            return ExistsSubqueryExpressionBinder.bind((ExistsSubqueryExpression) segment, metaData, defaultDatabaseName);
+        }
+        if (segment instanceof SubqueryExpressionSegment) {
+            return SubqueryExpressionSegmentBinder.bind((SubqueryExpressionSegment) segment, metaData, defaultDatabaseName);
+        }
+        if (segment instanceof InExpression) {
+            return InExpressionBinder.bind((InExpression) segment, metaData, defaultDatabaseName);
+        }
+        // TODO support more ExpressionSegment bind
+        return segment;
+    }
+}
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/BinaryOperationExpressionBinder.java
similarity index 54%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/BinaryOperationExpressionBinder.java
index 7fde0c58618..913aabbcafc 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/BinaryOperationExpressionBinder.java
@@ -15,33 +15,32 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
 
 /**
- * Subquery segment binder.
+ * Binary operation expression binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SubquerySegmentBinder {
+public final class BinaryOperationExpressionBinder {
     
     /**
-     * Bind subquery segment with metadata.
+     * Bind binary operation expression with metadata.
      *
-     * @param segment subquery segment
+     * @param segment binary operation expression segment
      * @param metaData metaData
      * @param defaultDatabaseName default database name
-     * @return bounded subquery segment
+     * @return bounded binary operation expression segment
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
-        SelectStatement boundedSelectStatement = new SelectStatementBinder().bind(segment.getSelect(), metaData, defaultDatabaseName);
-        SubquerySegment result = new SubquerySegment(segment.getStartIndex(), segment.getStopIndex(), boundedSelectStatement);
-        result.setSubqueryType(segment.getSubqueryType());
-        return result;
+    public static BinaryOperationExpression bind(final BinaryOperationExpression segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        ExpressionSegment boundedLeft = ExpressionSegmentBinder.bind(segment.getLeft(), metaData, defaultDatabaseName);
+        ExpressionSegment boundedRight = ExpressionSegmentBinder.bind(segment.getRight(), metaData, defaultDatabaseName);
+        return new BinaryOperationExpression(segment.getStartIndex(), segment.getStopIndex(), boundedLeft, boundedRight, segment.getOperator(), segment.getText());
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ColumnSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
similarity index 99%
rename from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ColumnSegmentBinder.java
rename to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
index cc8a09ac2bd..bead7512381 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/ColumnSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ExistsSubqueryExpressionBinder.java
similarity index 61%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ExistsSubqueryExpressionBinder.java
index 7fde0c58618..dac518c89dd 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ExistsSubqueryExpressionBinder.java
@@ -15,33 +15,32 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExistsSubqueryExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 
 /**
- * Subquery segment binder.
+ * Exists subquery expression binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SubquerySegmentBinder {
+public final class ExistsSubqueryExpressionBinder {
     
     /**
-     * Bind subquery segment with metadata.
+     * Bind exists subquery expression with metadata.
      *
-     * @param segment subquery segment
+     * @param segment exists subquery expression segment
      * @param metaData metaData
      * @param defaultDatabaseName default database name
-     * @return bounded subquery segment
+     * @return bounded exists subquery expression segment
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
-        SelectStatement boundedSelectStatement = new SelectStatementBinder().bind(segment.getSelect(), metaData, defaultDatabaseName);
-        SubquerySegment result = new SubquerySegment(segment.getStartIndex(), segment.getStopIndex(), boundedSelectStatement);
-        result.setSubqueryType(segment.getSubqueryType());
+    public static ExistsSubqueryExpression bind(final ExistsSubqueryExpression segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        SubquerySegment boundedSubquery = SubquerySegmentBinder.bind(segment.getSubquery(), metaData, defaultDatabaseName);
+        ExistsSubqueryExpression result = new ExistsSubqueryExpression(segment.getStartIndex(), segment.getStopIndex(), boundedSubquery);
+        result.setNot(segment.isNot());
         return result;
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/InExpressionBinder.java
similarity index 57%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/InExpressionBinder.java
index 7fde0c58618..3f3f1ba13fe 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/InExpressionBinder.java
@@ -15,33 +15,32 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
 
 /**
- * Subquery segment binder.
+ * In expression binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SubquerySegmentBinder {
+public final class InExpressionBinder {
     
     /**
-     * Bind subquery segment with metadata.
+     * Bind in expression segment with metadata.
      *
-     * @param segment subquery segment
+     * @param segment in expression
      * @param metaData metaData
      * @param defaultDatabaseName default database name
-     * @return bounded subquery segment
+     * @return bounded in expression
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
-        SelectStatement boundedSelectStatement = new SelectStatementBinder().bind(segment.getSelect(), metaData, defaultDatabaseName);
-        SubquerySegment result = new SubquerySegment(segment.getStartIndex(), segment.getStopIndex(), boundedSelectStatement);
-        result.setSubqueryType(segment.getSubqueryType());
-        return result;
+    public static InExpression bind(final InExpression segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        ExpressionSegment boundedLeft = ExpressionSegmentBinder.bind(segment.getLeft(), metaData, defaultDatabaseName);
+        ExpressionSegment boundedRight = ExpressionSegmentBinder.bind(segment.getRight(), metaData, defaultDatabaseName);
+        return new InExpression(segment.getStartIndex(), segment.getStopIndex(), boundedLeft, boundedRight, segment.isNot());
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubqueryExpressionSegmentBinder.java
similarity index 59%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubqueryExpressionSegmentBinder.java
index 7fde0c58618..ac16a62dbaa 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubqueryExpressionSegmentBinder.java
@@ -15,33 +15,30 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubqueryExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 
 /**
- * Subquery segment binder.
+ * Subquery expression segment binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SubquerySegmentBinder {
+public final class SubqueryExpressionSegmentBinder {
     
     /**
-     * Bind subquery segment with metadata.
+     * Bind subquery expression segment with metadata.
      *
-     * @param segment subquery segment
+     * @param segment subquery expression segment
      * @param metaData metaData
      * @param defaultDatabaseName default database name
-     * @return bounded subquery segment
+     * @return bounded subquery expression segment
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
-        SelectStatement boundedSelectStatement = new SelectStatementBinder().bind(segment.getSelect(), metaData, defaultDatabaseName);
-        SubquerySegment result = new SubquerySegment(segment.getStartIndex(), segment.getStopIndex(), boundedSelectStatement);
-        result.setSubqueryType(segment.getSubqueryType());
-        return result;
+    public static SubqueryExpressionSegment bind(final SubqueryExpressionSegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        SubquerySegment boundedSubquery = SubquerySegmentBinder.bind(segment.getSubquery(), metaData, defaultDatabaseName);
+        return new SubqueryExpressionSegment(boundedSubquery);
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubquerySegmentBinder.java
similarity index 99%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubquerySegmentBinder.java
index 7fde0c58618..e3b8b42a7f4 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/SubquerySegmentBinder.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.expression.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
index 2efa2510ff8..1db1dcf1155 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
@@ -17,18 +17,22 @@
 
 package org.apache.shardingsphere.infra.binder.segment.projection;
 
-import java.util.Map;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.segment.projection.impl.ColumnProjectionSegmentBinder;
 import org.apache.shardingsphere.infra.binder.segment.projection.impl.ShorthandProjectionSegmentBinder;
+import org.apache.shardingsphere.infra.binder.segment.projection.impl.SubqueryProjectionSegmentBinder;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 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.dml.item.ProjectionsSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.SubqueryProjectionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
 
+import java.util.Map;
+
 /**
  * Projections segment binder.
  */
@@ -39,24 +43,31 @@ public final class ProjectionsSegmentBinder {
      * Bind projections segment with metadata.
      *
      * @param segment table segment
+     * @param metaData meta data
+     * @param defaultDatabaseName default database name
      * @param boundedTableSegment bounded table segment
      * @param tableBinderContexts table binder contexts
      * @return bounded projections segment
      */
-    public static ProjectionsSegment bind(final ProjectionsSegment segment, final TableSegment boundedTableSegment, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    public static ProjectionsSegment bind(final ProjectionsSegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName, final TableSegment boundedTableSegment,
+                                          final Map<String, TableSegmentBinderContext> tableBinderContexts) {
         ProjectionsSegment result = new ProjectionsSegment(segment.getStartIndex(), segment.getStopIndex());
         result.setDistinctRow(segment.isDistinctRow());
-        segment.getProjections().forEach(each -> result.getProjections().add(bind(each, boundedTableSegment, tableBinderContexts)));
+        segment.getProjections().forEach(each -> result.getProjections().add(bind(each, metaData, defaultDatabaseName, boundedTableSegment, tableBinderContexts)));
         return result;
     }
     
-    private static ProjectionSegment bind(final ProjectionSegment projectionSegment, final TableSegment boundedTableSegment, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    private static ProjectionSegment bind(final ProjectionSegment projectionSegment, final ShardingSphereMetaData metaData, final String defaultDatabaseName, final TableSegment boundedTableSegment,
+                                          final Map<String, TableSegmentBinderContext> tableBinderContexts) {
         if (projectionSegment instanceof ColumnProjectionSegment) {
             return ColumnProjectionSegmentBinder.bind((ColumnProjectionSegment) projectionSegment, tableBinderContexts);
         }
         if (projectionSegment instanceof ShorthandProjectionSegment) {
             return ShorthandProjectionSegmentBinder.bind((ShorthandProjectionSegment) projectionSegment, boundedTableSegment, tableBinderContexts);
         }
+        if (projectionSegment instanceof SubqueryProjectionSegment) {
+            return SubqueryProjectionSegmentBinder.bind((SubqueryProjectionSegment) projectionSegment, metaData, defaultDatabaseName);
+        }
         // TODO support more ProjectionSegment bind
         return projectionSegment;
     }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java
index 60b2796b98c..d131993c87b 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java
@@ -19,7 +19,7 @@ package org.apache.shardingsphere.infra.binder.segment.projection.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.segment.expression.ColumnSegmentBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.ColumnSegmentBinder;
 import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/SubqueryProjectionSegmentBinder.java
similarity index 58%
copy from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java
copy to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/SubqueryProjectionSegmentBinder.java
index 60b2796b98c..47a9431a574 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ColumnProjectionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/SubqueryProjectionSegmentBinder.java
@@ -19,31 +19,29 @@ package org.apache.shardingsphere.infra.binder.segment.projection.impl;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.segment.expression.ColumnSegmentBinder;
-import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
-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 java.util.Map;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.SubquerySegmentBinder;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.SubqueryProjectionSegment;
 
 /**
- * Column projection segment binder.
+ * Subquery projection segment binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class ColumnProjectionSegmentBinder {
+public final class SubqueryProjectionSegmentBinder {
     
     /**
-     * Bind column projection segment with metadata.
+     * Bind subquery projection segment with metadata.
      *
-     * @param segment table segment
-     * @param tableBinderContexts table binder contexts
-     * @return bounded column projection segment
+     * @param segment subquery projection segment
+     * @param metaData meta data
+     * @param defaultDatabaseName default database name
+     * @return bounded subquery projection segment
      */
-    public static ColumnProjectionSegment bind(final ColumnProjectionSegment segment, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
-        ColumnSegment boundedColumn = ColumnSegmentBinder.bind(segment.getColumn(), tableBinderContexts);
-        ColumnProjectionSegment result = new ColumnProjectionSegment(boundedColumn);
+    public static SubqueryProjectionSegment bind(final SubqueryProjectionSegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        SubquerySegment boundedSubquerySegment = SubquerySegmentBinder.bind(segment.getSubquery(), metaData, defaultDatabaseName);
+        SubqueryProjectionSegment result = new SubqueryProjectionSegment(boundedSubquerySegment, segment.getText());
         segment.getAliasSegment().ifPresent(result::setAlias);
-        result.setVisible(segment.isVisible());
         return result;
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/where/WhereSegmentBinder.java
similarity index 53%
rename from infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
rename to infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/where/WhereSegmentBinder.java
index 7fde0c58618..1fd7f2fdb48 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/where/WhereSegmentBinder.java
@@ -15,33 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.binder.segment.expression;
+package org.apache.shardingsphere.infra.binder.segment.where;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
 
 /**
- * Subquery segment binder.
+ * Where segment binder.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SubquerySegmentBinder {
+public final class WhereSegmentBinder {
     
     /**
-     * Bind subquery segment with metadata.
+     * Bind where segment with metadata.
      *
-     * @param segment subquery segment
-     * @param metaData metaData
+     * @param segment where segment
+     * @param metaData meta data
      * @param defaultDatabaseName default database name
-     * @return bounded subquery segment
+     * @return bounded where segment
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
-        SelectStatement boundedSelectStatement = new SelectStatementBinder().bind(segment.getSelect(), metaData, defaultDatabaseName);
-        SubquerySegment result = new SubquerySegment(segment.getStartIndex(), segment.getStopIndex(), boundedSelectStatement);
-        result.setSubqueryType(segment.getSubqueryType());
-        return result;
+    public static WhereSegment bind(final WhereSegment segment, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
+        return new WhereSegment(segment.getStartIndex(), segment.getStopIndex(), ExpressionSegmentBinder.bind(segment.getExpr(), metaData, defaultDatabaseName));
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/InsertStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/InsertStatementBinder.java
index 4e40205ac23..754ad565052 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/InsertStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/InsertStatementBinder.java
@@ -18,7 +18,7 @@
 package org.apache.shardingsphere.infra.binder.statement.dml;
 
 import lombok.SneakyThrows;
-import org.apache.shardingsphere.infra.binder.segment.expression.SubquerySegmentBinder;
+import org.apache.shardingsphere.infra.binder.segment.expression.impl.SubquerySegmentBinder;
 import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
index 7380470fb55..1b506c11948 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
@@ -23,6 +23,7 @@ import org.apache.shardingsphere.infra.binder.segment.combine.CombineSegmentBind
 import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
 import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.segment.projection.ProjectionsSegmentBinder;
+import org.apache.shardingsphere.infra.binder.segment.where.WhereSegmentBinder;
 import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinder;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
@@ -43,9 +44,9 @@ public final class SelectStatementBinder implements SQLStatementBinder<SelectSta
         Map<String, TableSegmentBinderContext> tableBinderContexts = new CaseInsensitiveMap<>();
         TableSegment boundedTableSegment = TableSegmentBinder.bind(sqlStatement.getFrom(), metaData, defaultDatabaseName, sqlStatement.getDatabaseType(), tableBinderContexts);
         result.setFrom(boundedTableSegment);
-        result.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(), boundedTableSegment, tableBinderContexts));
+        result.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(), metaData, defaultDatabaseName, boundedTableSegment, tableBinderContexts));
         // TODO support other segment bind in select statement
-        sqlStatement.getWhere().ifPresent(result::setWhere);
+        sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, metaData, defaultDatabaseName)));
         sqlStatement.getGroupBy().ifPresent(result::setGroupBy);
         sqlStatement.getHaving().ifPresent(result::setHaving);
         sqlStatement.getOrderBy().ifPresent(result::setOrderBy);
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 0057549a06c..7669110ca53 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,7 +17,6 @@
 
 package org.apache.shardingsphere.infra.binder.context.segment.table;
 
-import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
@@ -125,64 +124,6 @@ class TablesContextTest {
         assertThat(actual.get("col"), is("TABLE_1"));
     }
     
-    @Test
-    void assertFindTableNameWhenColumnProjectionWhenSingleTable() {
-        SimpleTableSegment tableSegment = createTableSegment("table_1", "tbl_1");
-        ColumnProjection columnProjection = new ColumnProjection(null, "col", "cl", mock(DatabaseType.class));
-        Map<String, String> actual = new TablesContext(Collections.singletonList(tableSegment), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"))
-                .findTableNamesByColumnProjection(Collections.singletonList(columnProjection), mock(ShardingSphereSchema.class));
-        assertFalse(actual.isEmpty());
-        assertThat(actual.get("col"), is("table_1"));
-    }
-    
-    @Test
-    void assertFindTableNameWhenColumnProjectionOwnerPresent() {
-        SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1");
-        SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2");
-        ColumnProjection columnProjection = new ColumnProjection("table_1", "col", "cl", mock(DatabaseType.class));
-        Map<String, String> actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"))
-                .findTableNamesByColumnProjection(Collections.singletonList(columnProjection), mock(ShardingSphereSchema.class));
-        assertFalse(actual.isEmpty());
-        assertThat(actual.get("table_1.col"), is("table_1"));
-    }
-    
-    @Test
-    void assertFindTableNameWhenColumnProjectionOwnerAbsent() {
-        SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1");
-        SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2");
-        ColumnProjection columnProjection = new ColumnProjection(null, "col", "cl", mock(DatabaseType.class));
-        Map<String, String> actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"))
-                .findTableNamesByColumnProjection(Collections.singletonList(columnProjection), mock(ShardingSphereSchema.class));
-        assertTrue(actual.isEmpty());
-    }
-    
-    @Test
-    void assertFindTableNameWhenColumnProjectionOwnerAbsentAndSchemaMetaDataContainsColumn() {
-        SimpleTableSegment tableSegment1 = createTableSegment("table_1", "tbl_1");
-        SimpleTableSegment tableSegment2 = createTableSegment("table_2", "tbl_2");
-        ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
-        when(schema.getAllColumnNames("table_1")).thenReturn(Collections.singletonList("col"));
-        ColumnProjection columnProjection = new ColumnProjection(null, "col", "cl", mock(DatabaseType.class));
-        Map<String, String> actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"))
-                .findTableNamesByColumnProjection(Collections.singletonList(columnProjection), schema);
-        assertFalse(actual.isEmpty());
-        assertThat(actual.get("col"), is("table_1"));
-    }
-    
-    @Test
-    void assertFindTableNameWhenColumnProjectionOwnerAbsentAndSchemaMetaDataContainsColumnInUpperCase() {
-        SimpleTableSegment tableSegment1 = createTableSegment("TABLE_1", "TBL_1");
-        SimpleTableSegment tableSegment2 = createTableSegment("TABLE_2", "TBL_2");
-        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(Stream.of(table).collect(Collectors.toMap(ShardingSphereTable::getName, value -> value)), Collections.emptyMap());
-        ColumnProjection columnProjection = new ColumnProjection(null, "COL", "CL", mock(DatabaseType.class));
-        Map<String, String> actual = new TablesContext(Arrays.asList(tableSegment1, tableSegment2), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"))
-                .findTableNamesByColumnProjection(Collections.singletonList(columnProjection), schema);
-        assertFalse(actual.isEmpty());
-        assertThat(actual.get("col"), is("TABLE_1"));
-    }
-    
     private SimpleTableSegment createTableSegment(final String tableName, final String alias) {
         SimpleTableSegment result = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue(tableName)));
         AliasSegment aliasSegment = new AliasSegment(0, 0, new IdentifierValue(alias));
diff --git a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/SQLFederationResultSetMetaData.java b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/SQLFederationResultSetMetaData.java
index cdee84ceffa..9e122e7236f 100644
--- a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/SQLFederationResultSetMetaData.java
+++ b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/SQLFederationResultSetMetaData.java
@@ -29,7 +29,6 @@ import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 
 import java.sql.ResultSetMetaData;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -182,9 +181,7 @@ public final class SQLFederationResultSetMetaData extends WrapperAdapter impleme
                 expandProjections.size() < column ? new ColumnProjection(null, resultColumnType.getFieldList().get(column - 1).getName(), null, selectStatementContext.getDatabaseType())
                         : expandProjections.get(column - 1);
         if (projection instanceof ColumnProjection) {
-            Map<String, String> tableNamesByColumnProjection =
-                    selectStatementContext.getTablesContext().findTableNamesByColumnProjection(Collections.singletonList((ColumnProjection) projection), schema);
-            return Optional.of(tableNamesByColumnProjection.get(projection.getExpression()));
+            return Optional.of(((ColumnProjection) projection).getOriginalTable().getValue());
         }
         return Optional.empty();
     }
diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/SubqueryProjectionSegment.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/SubqueryProjectionSegment.java
index e180b0c6eed..10d23113f02 100644
--- a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/SubqueryProjectionSegment.java
+++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/SubqueryProjectionSegment.java
@@ -56,6 +56,15 @@ public final class SubqueryProjectionSegment implements ProjectionSegment, Alias
         return Optional.ofNullable(alias).map(AliasSegment::getIdentifier);
     }
     
+    /**
+     * Get alias segment.
+     * 
+     * @return alias segment
+     */
+    public Optional<AliasSegment> getAliasSegment() {
+        return Optional.ofNullable(alias);
+    }
+    
     @Override
     public int getStartIndex() {
         return subquery.getStartIndex();
diff --git a/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutor.java b/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutor.java
index 23e9a91eaf4..4184e3ad204 100644
--- a/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutor.java
+++ b/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutor.java
@@ -28,7 +28,6 @@ import org.apache.shardingsphere.db.protocol.mysql.packet.command.query.binary.p
 import org.apache.shardingsphere.db.protocol.mysql.packet.command.query.binary.prepare.MySQLComStmtPreparePacket;
 import org.apache.shardingsphere.db.protocol.mysql.packet.generic.MySQLEofPacket;
 import org.apache.shardingsphere.db.protocol.packet.DatabasePacket;
-import org.apache.shardingsphere.infra.exception.mysql.exception.UnsupportedPreparedStatementException;
 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;
@@ -36,6 +35,7 @@ import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatem
 import org.apache.shardingsphere.infra.binder.engine.SQLBindEngine;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
+import org.apache.shardingsphere.infra.exception.mysql.exception.UnsupportedPreparedStatementException;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
@@ -60,7 +60,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.stream.Collectors;
 
 /**
  * COM_STMT_PREPARE command executor for MySQL.
@@ -143,13 +142,11 @@ public final class MySQLComStmtPrepareExecutor implements CommandExecutor {
     private Collection<MySQLPacket> createProjectionColumnDefinition41Packets(final SelectStatementContext selectStatementContext, final int characterSet) {
         Collection<Projection> projections = selectStatementContext.getProjectionsContext().getExpandProjections();
         ShardingSphereSchema schema = getSchema(selectStatementContext);
-        Map<String, String> columnToTableMap = selectStatementContext.getTablesContext()
-                .findTableNamesByColumnProjection(projections.stream().filter(ColumnProjection.class::isInstance).map(ColumnProjection.class::cast).collect(Collectors.toList()), schema);
         Collection<MySQLPacket> result = new ArrayList<>(projections.size());
         for (Projection each : projections) {
             // TODO Calculate column definition flag for other projection types
-            if (each instanceof ColumnProjection && null != ((ColumnProjection) each).getOriginalColumn()) {
-                result.add(Optional.ofNullable(columnToTableMap.get(each.getExpression())).map(schema::getTable)
+            if (each instanceof ColumnProjection) {
+                result.add(Optional.ofNullable(schema.getTable(((ColumnProjection) each).getOriginalTable().getValue()))
                         .map(table -> table.getColumns().get(((ColumnProjection) each).getOriginalColumn().getValue()))
                         .map(column -> createMySQLColumnDefinition41Packet(characterSet, calculateColumnDefinitionFlag(column), MySQLBinaryColumnType.valueOfJDBCType(column.getDataType())))
                         .orElseGet(() -> createMySQLColumnDefinition41Packet(characterSet, 0, MySQLBinaryColumnType.VAR_STRING)));