You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2023/08/11 07:22:49 UTC

[shardingsphere] branch master updated: distinguish table subquery and join subquery to fix rewriting wrong result when join segment contains subquery table (#28040)

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

zhaojinchao 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 30054d77e95 distinguish table subquery and join subquery to fix rewriting wrong result when join segment contains subquery table (#28040)
30054d77e95 is described below

commit 30054d77e95bd10a5d5b418cce0fd03386ce3408
Author: Zhengqiang Duan <du...@apache.org>
AuthorDate: Fri Aug 11 15:22:42 2023 +0800

    distinguish table subquery and join subquery to fix rewriting wrong result when join segment contains subquery table (#28040)
    
    * distinguish table subquery and join subquery to fix rewriting wrong result when join segment contains subquery table
    
    * revert it-env.properties
---
 .../generator/EncryptProjectionTokenGenerator.java | 88 ++++++++++------------
 .../EncryptProjectionTokenGeneratorTest.java       |  5 +-
 .../statement/dml/SelectStatementContext.java      |  9 +++
 .../statement/dml/SelectStatementContextTest.java  | 21 ++++++
 .../sql/parser/sql/common/enums/SubqueryType.java  |  2 +-
 .../sql/common/util/SubqueryExtractUtils.java      | 27 +++++--
 .../dml/select/select-subquery.xml                 | 10 +--
 .../dml/select/select-subquery.xml                 |  8 +-
 8 files changed, 100 insertions(+), 70 deletions(-)

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 09359858d5b..1891e99fb3e 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
@@ -33,6 +33,7 @@ import org.apache.shardingsphere.infra.binder.context.segment.select.projection.
 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
 import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData;
+import org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
@@ -46,9 +47,6 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnPr
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
 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;
@@ -94,11 +92,11 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
                 ColumnProjection columnProjection = buildColumnProjection(columnSegment);
                 String originalColumnName = columnProjection.getOriginalColumn().getValue();
                 Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(columnProjection.getOriginalTable().getValue());
-                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(originalColumnName) && !containsTableSubquery(selectStatementContext.getSqlStatement().getFrom())) {
+                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(originalColumnName) && !selectStatementContext.containsTableSubquery()) {
                     sqlTokens.add(generateSQLToken(encryptTable.get().getEncryptColumn(originalColumnName), columnSegment, columnProjection, subqueryType));
                 }
             }
-            ShardingSpherePreconditions.checkState(!(each instanceof ShorthandProjectionSegment) || !containsTableSubquery(selectStatementContext.getSqlStatement().getFrom()),
+            ShardingSpherePreconditions.checkState(!(each instanceof ShorthandProjectionSegment) || !selectStatementContext.containsTableSubquery(),
                     () -> new UnsupportedSQLOperationException("Can not support encrypt shorthand expand with subquery statement"));
             if (each instanceof ShorthandProjectionSegment) {
                 ShorthandProjectionSegment shorthandSegment = (ShorthandProjectionSegment) each;
@@ -110,16 +108,6 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
         }
     }
     
-    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);
@@ -133,11 +121,11 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
         List<Projection> projections = new LinkedList<>();
         for (Projection each : actualColumns) {
             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));
+                ColumnProjection columnProjection = (ColumnProjection) each;
+                Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(columnProjection.getOriginalTable().getValue());
+                if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(columnProjection.getOriginalColumn().getValue()) && !selectStatementContext.containsTableSubquery()) {
+                    EncryptColumn encryptColumn = encryptTable.get().getEncryptColumn(columnProjection.getOriginalColumn().getValue());
+                    projections.addAll(generateProjections(encryptColumn, columnProjection, subqueryType, true, segment));
                     continue;
                 }
             }
@@ -158,57 +146,59 @@ public final class EncryptProjectionTokenGenerator implements CollectionSQLToken
         return result;
     }
     
-    private Collection<Projection> generateProjections(final EncryptColumn encryptColumn, final ColumnProjection column,
-                                                       final SubqueryType subqueryType, final boolean shorthand, final ShorthandProjectionSegment segment) {
+    private Collection<Projection> generateProjections(final EncryptColumn encryptColumn, final ColumnProjection columnProjection,
+                                                       final SubqueryType subqueryType, final boolean shorthandProjection, final ShorthandProjectionSegment segment) {
         Collection<Projection> result = new LinkedList<>();
         if (SubqueryType.PREDICATE_SUBQUERY == subqueryType) {
-            result.add(generatePredicateSubqueryProjection(encryptColumn, column, shorthand));
-        } else if (SubqueryType.TABLE_SUBQUERY == subqueryType) {
-            result.addAll(generateTableSubqueryProjections(encryptColumn, column, shorthand));
+            result.add(generatePredicateSubqueryProjection(encryptColumn, columnProjection, shorthandProjection));
+        } else if (SubqueryType.TABLE_SUBQUERY == subqueryType || SubqueryType.JOIN_SUBQUERY == subqueryType) {
+            result.addAll(generateTableSegmentSubqueryProjections(encryptColumn, columnProjection, shorthandProjection, subqueryType));
         } else if (SubqueryType.EXISTS_SUBQUERY == subqueryType) {
-            result.addAll(generateExistsSubqueryProjections(encryptColumn, column, shorthand));
+            result.addAll(generateExistsSubqueryProjections(encryptColumn, columnProjection, shorthandProjection));
         } else {
-            result.add(generateCommonProjection(encryptColumn, column, segment, shorthand));
+            result.add(generateCommonProjection(encryptColumn, columnProjection, segment, shorthandProjection));
         }
         return result;
     }
     
-    private ColumnProjection generatePredicateSubqueryProjection(final EncryptColumn encryptColumn, final ColumnProjection column, final boolean shorthand) {
+    private ColumnProjection generatePredicateSubqueryProjection(final EncryptColumn encryptColumn, final ColumnProjection columnProjection, final boolean shorthandProjection) {
         Optional<AssistedQueryColumnItem> assistedQueryColumn = encryptColumn.getAssistedQuery();
+        IdentifierValue owner = columnProjection.getOwner().orElse(null);
         return assistedQueryColumn
-                .map(optional -> new ColumnProjection(column.getOwner().orElse(null), new IdentifierValue(optional.getName(), column.getName().getQuoteCharacter()), null, databaseType))
-                .orElseGet(() -> createCipherColumn(column.getOwner().orElse(null), encryptColumn.getCipher().getName(), column, shorthand));
+                .map(optional -> new ColumnProjection(owner, new IdentifierValue(optional.getName(), columnProjection.getName().getQuoteCharacter()), null, databaseType))
+                .orElseGet(() -> createCipherColumn(owner, new IdentifierValue(encryptColumn.getCipher().getName(), columnProjection.getName().getQuoteCharacter()),
+                        columnProjection.getAlias().orElse(columnProjection.getName()), shorthandProjection));
     }
     
-    private Collection<ColumnProjection> generateTableSubqueryProjections(final EncryptColumn encryptColumn, final ColumnProjection cipherColumn, final boolean shorthand) {
+    private Collection<ColumnProjection> generateTableSegmentSubqueryProjections(final EncryptColumn encryptColumn, final ColumnProjection columnProjection, final boolean shorthandProjection,
+                                                                                 final SubqueryType subqueryType) {
         Collection<ColumnProjection> result = new LinkedList<>();
-        IdentifierValue owner = cipherColumn.getOwner().orElse(null);
-        result.add(createCipherColumn(owner, encryptColumn.getCipher().getName(), cipherColumn, shorthand));
-        encryptColumn.getAssistedQuery()
-                .ifPresent(optional -> result.add(new ColumnProjection(owner, new IdentifierValue(optional.getName(), cipherColumn.getName().getQuoteCharacter()), null, databaseType)));
-        encryptColumn.getLikeQuery()
-                .ifPresent(optional -> result.add(new ColumnProjection(owner, new IdentifierValue(optional.getName(), cipherColumn.getName().getQuoteCharacter()), null, databaseType)));
+        IdentifierValue owner = columnProjection.getOwner().orElse(null);
+        QuoteCharacter quoteCharacter = columnProjection.getName().getQuoteCharacter();
+        IdentifierValue columnName = new IdentifierValue(encryptColumn.getCipher().getName(), quoteCharacter);
+        IdentifierValue alias = SubqueryType.JOIN_SUBQUERY == subqueryType ? null : columnProjection.getAlias().orElse(columnProjection.getName());
+        result.add(createCipherColumn(owner, columnName, alias, shorthandProjection));
+        encryptColumn.getAssistedQuery().ifPresent(optional -> result.add(new ColumnProjection(owner, new IdentifierValue(optional.getName(), quoteCharacter), null, databaseType)));
+        encryptColumn.getLikeQuery().ifPresent(optional -> result.add(new ColumnProjection(owner, new IdentifierValue(optional.getName(), quoteCharacter), null, databaseType)));
         return result;
     }
     
-    private ColumnProjection createCipherColumn(final IdentifierValue owner, final String cipherColumn, final ColumnProjection columnProjection, final boolean shorthand) {
-        if (shorthand || !columnProjection.getOwner().isPresent()) {
-            return new ColumnProjection(owner, new IdentifierValue(cipherColumn, columnProjection.getName().getQuoteCharacter()), columnProjection.getAlias().orElse(columnProjection.getName()),
-                    databaseType);
-        }
-        return new ColumnProjection(null, new IdentifierValue(cipherColumn, columnProjection.getName().getQuoteCharacter()), columnProjection.getAlias().orElse(columnProjection.getName()),
-                databaseType);
+    private ColumnProjection createCipherColumn(final IdentifierValue owner, final IdentifierValue columnName, final IdentifierValue alias, final boolean shorthandProjection) {
+        return new ColumnProjection(shorthandProjection ? owner : null, columnName, alias, databaseType);
     }
     
-    private Collection<ColumnProjection> generateExistsSubqueryProjections(final EncryptColumn encryptColumn, final ColumnProjection column, final boolean shorthand) {
+    private Collection<ColumnProjection> generateExistsSubqueryProjections(final EncryptColumn encryptColumn, final ColumnProjection columnProjection, final boolean shorthandProjection) {
         Collection<ColumnProjection> result = new LinkedList<>();
-        result.add(createCipherColumn(column.getOwner().orElse(null), encryptColumn.getCipher().getName(), column, shorthand));
+        IdentifierValue columnName = new IdentifierValue(encryptColumn.getCipher().getName(), columnProjection.getName().getQuoteCharacter());
+        result.add(createCipherColumn(columnProjection.getOwner().orElse(null), columnName, columnProjection.getAlias().orElse(columnProjection.getName()), shorthandProjection));
         return result;
     }
     
-    private ColumnProjection generateCommonProjection(final EncryptColumn encryptColumn, final ColumnProjection column, final ShorthandProjectionSegment segment, final boolean shorthand) {
-        IdentifierValue owner = (null == segment || !segment.getOwner().isPresent()) ? column.getOwner().orElse(null) : segment.getOwner().get().getIdentifier();
-        return createCipherColumn(owner, encryptColumn.getCipher().getName(), column, shorthand);
+    private ColumnProjection generateCommonProjection(final EncryptColumn encryptColumn, final ColumnProjection columnProjection, final ShorthandProjectionSegment segment,
+                                                      final boolean shorthandProjection) {
+        IdentifierValue owner = (null == segment || !segment.getOwner().isPresent()) ? columnProjection.getOwner().orElse(null) : segment.getOwner().get().getIdentifier();
+        IdentifierValue columnName = new IdentifierValue(encryptColumn.getCipher().getName(), columnProjection.getName().getQuoteCharacter());
+        return createCipherColumn(owner, columnName, columnProjection.getAlias().orElse(columnProjection.getName()), shorthandProjection);
     }
     
     private ShorthandProjection getShorthandProjection(final ShorthandProjectionSegment segment, final ProjectionsContext projectionsContext) {
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 d30545ceab7..22d927bf71d 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
@@ -28,16 +28,13 @@ import org.apache.shardingsphere.infra.exception.core.external.sql.type.generic.
 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;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
 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.generic.AliasSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
 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.TableNameSegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -143,7 +140,7 @@ class EncryptProjectionTokenGeneratorTest {
     @Test
     void assertGenerateSQLTokensWhenShorthandExpandContainsSubqueryTable() {
         SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS);
-        when(sqlStatementContext.getSqlStatement().getFrom()).thenReturn(new SubqueryTableSegment(new SubquerySegment(0, 0, mock(SelectStatement.class))));
+        when(sqlStatementContext.containsTableSubquery()).thenReturn(true);
         when(sqlStatementContext.getSqlStatement().getProjections().getProjections()).thenReturn(Collections.singleton(new ShorthandProjectionSegment(0, 0)));
         assertThrows(UnsupportedSQLOperationException.class, () -> generator.generateSQLTokens(sqlStatementContext));
     }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContext.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContext.java
index f634f5e4c47..96c19fbc7be 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContext.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContext.java
@@ -374,6 +374,15 @@ public final class SelectStatementContext extends CommonSQLStatementContext impl
         return result;
     }
     
+    /**
+     * Judge whether sql statement contains table subquery segment or not.
+     *
+     * @return whether sql statement contains table subquery segment or not
+     */
+    public boolean containsTableSubquery() {
+        return getSqlStatement().getFrom() instanceof SubqueryTableSegment;
+    }
+    
     @Override
     public void setUpParameters(final List<Object> params) {
         paginationContext = new PaginationContextEngine().createPaginationContext(getSqlStatement(), projectionsContext, params, whereSegments);
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContextTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContextTest.java
index ae2e8cb3ff1..051f9c819f2 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContextTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/dml/SelectStatementContextTest.java
@@ -51,6 +51,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.AliasSegm
 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.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
@@ -626,4 +627,24 @@ class SelectStatementContextTest {
         SelectStatementContext actual = new SelectStatementContext(metaData, Collections.emptyList(), selectStatement, DefaultDatabase.LOGIC_NAME);
         assertTrue(actual.isContainsEnhancedTable());
     }
+    
+    @Test
+    void assertContainsEnhancedTable() {
+        SelectStatement selectStatement = new MySQLSelectStatement();
+        selectStatement.setProjections(new ProjectionsSegment(0, 0));
+        selectStatement.setFrom(new SubqueryTableSegment(new SubquerySegment(0, 0, createSubSelectStatement())));
+        ShardingSphereMetaData metaData = new ShardingSphereMetaData(Collections.singletonMap(DefaultDatabase.LOGIC_NAME, mockDatabase()), mock(ResourceMetaData.class),
+                mock(RuleMetaData.class), mock(ConfigurationProperties.class));
+        SelectStatementContext actual = new SelectStatementContext(metaData, Collections.emptyList(), selectStatement, DefaultDatabase.LOGIC_NAME);
+        assertTrue(actual.containsTableSubquery());
+    }
+    
+    private SelectStatement createSubSelectStatement() {
+        ProjectionsSegment projectionsSegment = new ProjectionsSegment(0, 0);
+        projectionsSegment.getProjections().add(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))));
+        SelectStatement result = new MySQLSelectStatement();
+        result.setProjections(projectionsSegment);
+        result.setFrom(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order"))));
+        return result;
+    }
 }
diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/enums/SubqueryType.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/enums/SubqueryType.java
index 00a07321f49..383c9ede9d4 100644
--- a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/enums/SubqueryType.java
+++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/enums/SubqueryType.java
@@ -22,5 +22,5 @@ package org.apache.shardingsphere.sql.parser.sql.common.enums;
  */
 public enum SubqueryType {
     
-    PROJECTION_SUBQUERY, TABLE_SUBQUERY, PREDICATE_SUBQUERY, INSERT_SELECT_SUBQUERY, EXISTS_SUBQUERY
+    PROJECTION_SUBQUERY, TABLE_SUBQUERY, JOIN_SUBQUERY, PREDICATE_SUBQUERY, INSERT_SELECT_SUBQUERY, EXISTS_SUBQUERY
 }
diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SubqueryExtractUtils.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SubqueryExtractUtils.java
index 522e5c55676..22e360b253f 100644
--- a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SubqueryExtractUtils.java
+++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SubqueryExtractUtils.java
@@ -88,19 +88,32 @@ public final class SubqueryExtractUtils {
     }
     
     private static void extractSubquerySegmentsFromTableSegment(final List<SubquerySegment> result, final TableSegment tableSegment) {
-        if (null == tableSegment) {
-            return;
+        if (tableSegment instanceof SubqueryTableSegment) {
+            extractSubquerySegmentsFromSubqueryTableSegment(result, (SubqueryTableSegment) tableSegment);
         }
+        if (tableSegment instanceof JoinTableSegment) {
+            extractSubquerySegmentsFromJoinTableSegment(result, ((JoinTableSegment) tableSegment).getLeft());
+            extractSubquerySegmentsFromJoinTableSegment(result, ((JoinTableSegment) tableSegment).getRight());
+        }
+    }
+    
+    private static void extractSubquerySegmentsFromJoinTableSegment(final List<SubquerySegment> result, final TableSegment tableSegment) {
         if (tableSegment instanceof SubqueryTableSegment) {
             SubquerySegment subquery = ((SubqueryTableSegment) tableSegment).getSubquery();
-            subquery.setSubqueryType(SubqueryType.TABLE_SUBQUERY);
+            subquery.setSubqueryType(SubqueryType.JOIN_SUBQUERY);
             result.add(subquery);
             extractSubquerySegments(result, subquery.getSelect());
+        } else if (tableSegment instanceof JoinTableSegment) {
+            extractSubquerySegmentsFromJoinTableSegment(result, ((JoinTableSegment) tableSegment).getLeft());
+            extractSubquerySegmentsFromJoinTableSegment(result, ((JoinTableSegment) tableSegment).getRight());
         }
-        if (tableSegment instanceof JoinTableSegment) {
-            extractSubquerySegmentsFromTableSegment(result, ((JoinTableSegment) tableSegment).getLeft());
-            extractSubquerySegmentsFromTableSegment(result, ((JoinTableSegment) tableSegment).getRight());
-        }
+    }
+    
+    private static void extractSubquerySegmentsFromSubqueryTableSegment(final List<SubquerySegment> result, final SubqueryTableSegment subqueryTableSegment) {
+        SubquerySegment subquery = subqueryTableSegment.getSubquery();
+        subquery.setSubqueryType(SubqueryType.TABLE_SUBQUERY);
+        result.add(subquery);
+        extractSubquerySegments(result, subquery.getSelect());
     }
     
     private static void extractSubquerySegmentsFromExpression(final List<SubquerySegment> result, final ExpressionSegment expressionSegment) {
diff --git a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-subquery.xml b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-subquery.xml
index b5ffed1df65..69216088fc1 100644
--- a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-subquery.xml
+++ b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-subquery.xml
@@ -24,12 +24,12 @@
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment" db-types="MySQL">
         <input sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT certificate_number FROM t_account) o, t_account u WHERE o.certificate_number=u.certificate_number AND u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT cipher_certificate_number AS certificate_number, assisted_query_certificate_number, like_query_certificate_number FROM t_account) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password, o.cipher_certificate_number AS certificate_number FROM (SELECT cipher_certificate_number, assisted_query_certificate_number, like_query_certificate_number FROM t_account) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_query_password=?" parameters="assisted_query_1" />
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_refed" db-types="MySQL">
         <input sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT certificate_number FROM t_account_bak) o, t_account u WHERE o.certificate_number=u.certificate_number AND u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT cipher_certificate_number AS certificate_number, assisted_query_certificate_number, like_query_certificate_number FROM t_account_bak) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password, o.cipher_certificate_number AS certificate_number FROM (SELECT cipher_certificate_number, assisted_query_certificate_number, like_query_certificate_number FROM t_account_bak) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_query_password=?" parameters="assisted_query_1" />
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_alias" db-types="MySQL">
@@ -39,17 +39,17 @@
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_with_shorthand_project_alias" db-types="MySQL">
         <input sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT a.* FROM t_account a) o, t_account u WHERE o.certificate_number=u.certificate_number AND u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT a.`account_id`, a.`cipher_certificate_number` AS `certificate_number`, a.`assisted_query_certificate_number`, a.`like_query_certificate_number`, a.`cipher_password` AS `password`, a.`assisted_query_password`, a.`like_query_password`, a.`cipher_amount` AS `amount` FROM t_account a) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_query_password=?"  [...]
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password, o.cipher_certificate_number AS certificate_number FROM (SELECT a.`account_id`, a.`cipher_certificate_number`, a.`assisted_query_certificate_number`, a.`like_query_certificate_number`, a.`cipher_password`, a.`assisted_query_password`, a.`like_query_password`, a.`cipher_amount` FROM t_account a) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_que [...]
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_with_shorthand_project_alias_quote" db-types="MySQL">
         <input sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT a.* FROM t_account `a`) o, t_account u WHERE o.certificate_number=u.certificate_number AND u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT `a`.`account_id`, `a`.`cipher_certificate_number` AS `certificate_number`, `a`.`assisted_query_certificate_number`, `a`.`like_query_certificate_number`, `a`.`cipher_password` AS `password`, `a`.`assisted_query_password`, `a`.`like_query_password`, `a`.`cipher_amount` AS `amount` FROM t_account `a`) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number AND u.assisted_ [...]
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password, o.cipher_certificate_number AS certificate_number FROM (SELECT `a`.`account_id`, `a`.`cipher_certificate_number`, `a`.`assisted_query_certificate_number`, `a`.`like_query_certificate_number`, `a`.`cipher_password`, `a`.`assisted_query_password`, `a`.`like_query_password`, `a`.`cipher_amount` FROM t_account `a`) o, t_account u WHERE o.assisted_query_certificate_number=u.assisted_query_certificate_number  [...]
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_with_shorthand_project" db-types="MySQL">
         <input sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT * FROM t_account) o, t_account u WHERE o.certificate_number=u.certificate_number AND u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password, o.certificate_number FROM (SELECT t_account.`account_id`, t_account.`cipher_certificate_number` AS `certificate_number`, t_account.`assisted_query_certificate_number`, t_account.`like_query_certificate_number`, t_account.`cipher_password` AS `password`, t_account.`assisted_query_password`, t_account.`like_query_password`, t_account.`cipher_amount` AS `amount` FROM t_account) o, t_account u WHERE o.assisted_query_certificate_number=u.assis [...]
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password, o.cipher_certificate_number AS certificate_number FROM (SELECT t_account.`account_id`, t_account.`cipher_certificate_number`, t_account.`assisted_query_certificate_number`, t_account.`like_query_certificate_number`, t_account.`cipher_password`, t_account.`assisted_query_password`, t_account.`like_query_password`, t_account.`cipher_amount` FROM t_account) o, t_account u WHERE o.assisted_query_certificate [...]
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_predicate_right_equal_condition" db-types="MySQL">
diff --git a/test/it/rewriter/src/test/resources/scenario/mix/case/query-with-cipher/dml/select/select-subquery.xml b/test/it/rewriter/src/test/resources/scenario/mix/case/query-with-cipher/dml/select/select-subquery.xml
index e0ccbe45cde..90828aac50a 100644
--- a/test/it/rewriter/src/test/resources/scenario/mix/case/query-with-cipher/dml/select/select-subquery.xml
+++ b/test/it/rewriter/src/test/resources/scenario/mix/case/query-with-cipher/dml/select/select-subquery.xml
@@ -25,14 +25,14 @@
     
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_with_shorthand_project_alias" db-types="MySQL">
         <input sql="SELECT u.amount, u.password FROM (SELECT a.* FROM t_account a) o, t_account u WHERE u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password FROM (SELECT a.`account_id`, a.`cipher_password` AS `password`, a.`assisted_query_password`, a.`cipher_amount` AS `amount` FROM t_account_0 a) o, t_account_0 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
-        <output sql="SELECT u.amount, u.password FROM (SELECT a.`account_id`, a.`cipher_password` AS `password`, a.`assisted_query_password`, a.`cipher_amount` AS `amount` FROM t_account_1 a) o, t_account_1 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password FROM (SELECT a.`account_id`, a.`cipher_password`, a.`assisted_query_password`, a.`cipher_amount` FROM t_account_0 a) o, t_account_0 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password FROM (SELECT a.`account_id`, a.`cipher_password`, a.`assisted_query_password`, a.`cipher_amount` FROM t_account_1 a) o, t_account_1 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
     </rewrite-assertion>
 
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_with_shorthand_project_alias_quote" db-types="MySQL">
         <input sql="SELECT u.amount, u.password FROM (SELECT `a`.* FROM t_account `a`) o, t_account u WHERE u.password=?" parameters="1" />
-        <output sql="SELECT u.amount, u.password FROM (SELECT `a`.`account_id`, `a`.`cipher_password` AS `password`, `a`.`assisted_query_password`, `a`.`cipher_amount` AS `amount` FROM t_account_0 `a`) o, t_account_0 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
-        <output sql="SELECT u.amount, u.password FROM (SELECT `a`.`account_id`, `a`.`cipher_password` AS `password`, `a`.`assisted_query_password`, `a`.`cipher_amount` AS `amount` FROM t_account_1 `a`) o, t_account_1 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password FROM (SELECT `a`.`account_id`, `a`.`cipher_password`, `a`.`assisted_query_password`, `a`.`cipher_amount` FROM t_account_0 `a`) o, t_account_0 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
+        <output sql="SELECT u.cipher_amount AS amount, u.cipher_password AS password FROM (SELECT `a`.`account_id`, `a`.`cipher_password`, `a`.`assisted_query_password`, `a`.`cipher_amount` FROM t_account_1 `a`) o, t_account_1 u WHERE u.assisted_query_password=?" parameters="assisted_query_1" />
     </rewrite-assertion>
     
     <rewrite-assertion id="select_not_nested_subquery_in_table_segment_alias" db-types="MySQL">