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 59bc2771eeb Refactor SingleSQLRouter code style and logic for schema 
rewrite (#27349)
59bc2771eeb is described below

commit 59bc2771eeb016ba5d17b92486f55bb19ca3920e
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Fri Jul 21 12:56:13 2023 +0800

    Refactor SingleSQLRouter code style and logic for schema rewrite (#27349)
---
 .../single/decider/SingleSQLFederationDecider.java | 65 ++++------------
 .../single/route/SingleSQLRouter.java              | 75 +++++--------------
 .../route/engine/SingleRouteEngineFactory.java     | 10 +--
 .../route/engine/SingleStandardRouteEngine.java    | 51 +++++++++----
 .../shardingsphere/single/rule/SingleRule.java     | 86 ++++++++++++++--------
 .../decider/SingleSQLFederationDeciderTest.java    | 18 ++---
 .../route/engine/SingleRouteEngineFactoryTest.java |  2 +-
 .../shardingsphere/single/rule/SingleRuleTest.java | 27 +++----
 .../query/ShowUnloadedSingleTableExecutor.java     |  3 +-
 9 files changed, 149 insertions(+), 188 deletions(-)

diff --git 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDecider.java
 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDecider.java
index b70623aa359..b932bed815a 100644
--- 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDecider.java
+++ 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDecider.java
@@ -17,26 +17,18 @@
 
 package org.apache.shardingsphere.single.decider;
 
-import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
 import 
org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
-import org.apache.shardingsphere.infra.binder.type.IndexAvailable;
-import org.apache.shardingsphere.infra.database.spi.DatabaseType;
-import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
 import org.apache.shardingsphere.infra.datanode.DataNode;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData;
 import org.apache.shardingsphere.infra.metadata.database.schema.QualifiedTable;
-import 
org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
 import org.apache.shardingsphere.single.constant.SingleOrder;
 import org.apache.shardingsphere.single.rule.SingleRule;
-import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sqlfederation.spi.SQLFederationDecider;
 
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * Single SQL federation decider.
@@ -46,39 +38,25 @@ public final class SingleSQLFederationDecider implements 
SQLFederationDecider<Si
     @Override
     public boolean decide(final SelectStatementContext selectStatementContext, 
final List<Object> parameters,
                           final ShardingSphereRuleMetaData globalRuleMetaData, 
final ShardingSphereDatabase database, final SingleRule rule, final 
Collection<DataNode> includedDataNodes) {
-        Collection<QualifiedTable> singleTableNames = 
getSingleTableNames(selectStatementContext, database, rule);
-        if (singleTableNames.isEmpty()) {
+        Collection<QualifiedTable> singleTables = 
getSingleTables(selectStatementContext, database, rule);
+        if (singleTables.isEmpty()) {
             return false;
         }
-        if (containsView(database, singleTableNames)) {
+        if (containsView(database, singleTables)) {
             return true;
         }
-        boolean isAllTablesInSameDataSource = 
isAllTablesInSameDataSource(includedDataNodes, rule, singleTableNames);
-        includedDataNodes.addAll(getTableDataNodes(rule, singleTableNames));
-        return !isAllTablesInSameDataSource;
+        boolean isAllTablesInSameComputeNode = 
rule.isAllTablesInSameComputeNode(includedDataNodes, singleTables);
+        includedDataNodes.addAll(getTableDataNodes(rule, singleTables));
+        return !isAllTablesInSameComputeNode;
     }
     
-    private Collection<QualifiedTable> getSingleTableNames(final 
SQLStatementContext sqlStatementContext, final ShardingSphereDatabase database, 
final SingleRule rule) {
-        DatabaseType databaseType = sqlStatementContext.getDatabaseType();
-        Collection<QualifiedTable> result = getQualifiedTables(database, 
databaseType, sqlStatementContext.getTablesContext().getSimpleTableSegments());
-        if (result.isEmpty() && sqlStatementContext instanceof IndexAvailable) 
{
-            result = IndexMetaDataUtils.getTableNames(database, databaseType, 
((IndexAvailable) sqlStatementContext).getIndexes());
-        }
-        return rule.getSingleTableNames(result);
+    private Collection<QualifiedTable> getSingleTables(final 
SelectStatementContext selectStatementContext, final ShardingSphereDatabase 
database, final SingleRule rule) {
+        Collection<QualifiedTable> qualifiedTables = 
rule.getQualifiedTables(selectStatementContext, database);
+        return rule.getSingleTables(qualifiedTables);
     }
     
-    private Collection<QualifiedTable> getQualifiedTables(final 
ShardingSphereDatabase database, final DatabaseType databaseType, final 
Collection<SimpleTableSegment> tableSegments) {
-        Collection<QualifiedTable> result = new LinkedList<>();
-        String schemaName = 
DatabaseTypeEngine.getDefaultSchemaName(databaseType, database.getName());
-        for (SimpleTableSegment each : tableSegments) {
-            String actualSchemaName = each.getOwner().map(optional -> 
optional.getIdentifier().getValue()).orElse(schemaName);
-            result.add(new QualifiedTable(actualSchemaName, 
each.getTableName().getIdentifier().getValue()));
-        }
-        return result;
-    }
-    
-    private boolean containsView(final ShardingSphereDatabase database, final 
Collection<QualifiedTable> singleTableNames) {
-        for (QualifiedTable each : singleTableNames) {
+    private boolean containsView(final ShardingSphereDatabase database, final 
Collection<QualifiedTable> singleTables) {
+        for (QualifiedTable each : singleTables) {
             if 
(database.getSchema(each.getSchemaName()).containsView(each.getTableName())) {
                 return true;
             }
@@ -86,26 +64,9 @@ public final class SingleSQLFederationDecider implements 
SQLFederationDecider<Si
         return false;
     }
     
-    private boolean isAllTablesInSameDataSource(final Collection<DataNode> 
includedDataNodes, final SingleRule rule, final Collection<QualifiedTable> 
singleTableNames) {
-        if (!rule.isSingleTablesInSameDataSource(singleTableNames)) {
-            return false;
-        }
-        QualifiedTable sampleTable = singleTableNames.iterator().next();
-        Optional<DataNode> dataNode = 
rule.findTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
-        if (!dataNode.isPresent()) {
-            return true;
-        }
-        for (DataNode each : includedDataNodes) {
-            if 
(!each.getDataSourceName().equalsIgnoreCase(dataNode.get().getDataSourceName()))
 {
-                return false;
-            }
-        }
-        return true;
-    }
-    
-    private Collection<DataNode> getTableDataNodes(final SingleRule rule, 
final Collection<QualifiedTable> singleTableNames) {
+    private Collection<DataNode> getTableDataNodes(final SingleRule rule, 
final Collection<QualifiedTable> singleTables) {
         Collection<DataNode> result = new HashSet<>();
-        for (QualifiedTable each : singleTableNames) {
+        for (QualifiedTable each : singleTables) {
             rule.findTableDataNode(each.getSchemaName(), 
each.getTableName()).ifPresent(result::add);
         }
         return result;
diff --git 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/SingleSQLRouter.java
 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/SingleSQLRouter.java
index 0162f7df33a..42797b6a071 100644
--- 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/SingleSQLRouter.java
+++ 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/SingleSQLRouter.java
@@ -17,17 +17,12 @@
 
 package org.apache.shardingsphere.single.route;
 
-import com.google.common.base.Preconditions;
 import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
-import org.apache.shardingsphere.infra.binder.type.IndexAvailable;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import 
org.apache.shardingsphere.infra.connection.validator.ShardingSphereMetaDataValidateUtils;
-import org.apache.shardingsphere.infra.database.spi.DatabaseType;
-import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData;
 import org.apache.shardingsphere.infra.metadata.database.schema.QualifiedTable;
-import 
org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
 import org.apache.shardingsphere.infra.route.SQLRouter;
 import org.apache.shardingsphere.infra.route.context.RouteContext;
 import org.apache.shardingsphere.infra.route.context.RouteMapper;
@@ -36,21 +31,13 @@ import 
org.apache.shardingsphere.infra.session.connection.ConnectionContext;
 import org.apache.shardingsphere.infra.session.query.QueryContext;
 import org.apache.shardingsphere.single.constant.SingleOrder;
 import org.apache.shardingsphere.single.route.engine.SingleRouteEngineFactory;
-import 
org.apache.shardingsphere.single.route.validator.SingleMetaDataValidator;
 import 
org.apache.shardingsphere.single.route.validator.SingleMetaDataValidatorFactory;
 import org.apache.shardingsphere.single.rule.SingleRule;
-import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateTableStatement;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DeleteStatement;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.UpdateStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DMLStatement;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
-import java.util.Optional;
 
 /**
  * Single SQL router.
@@ -65,30 +52,32 @@ public final class SingleSQLRouter implements 
SQLRouter<SingleRule> {
         }
         RouteContext result = new RouteContext();
         SQLStatementContext sqlStatementContext = 
queryContext.getSqlStatementContext();
-        SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
-        Optional<SingleMetaDataValidator> validator = 
SingleMetaDataValidatorFactory.newInstance(sqlStatement);
-        validator.ifPresent(optional -> optional.validate(rule, 
sqlStatementContext, database));
-        Collection<QualifiedTable> singleTableNames = 
getSingleTableNames(sqlStatementContext, database, rule, result);
-        if (!singleTableNames.isEmpty()) {
-            if (sqlStatement instanceof InsertStatement || sqlStatement 
instanceof DeleteStatement || sqlStatement instanceof UpdateStatement || 
sqlStatement instanceof SelectStatement) {
-                
ShardingSphereMetaDataValidateUtils.validateTableExist(sqlStatementContext, 
database);
-            }
-            validateSameDataSource(rule, singleTableNames, result);
-        }
-        SingleRouteEngineFactory.newInstance(singleTableNames, 
sqlStatement).ifPresent(optional -> optional.route(result, rule));
+        
SingleMetaDataValidatorFactory.newInstance(sqlStatementContext.getSqlStatement()).ifPresent(optional
 -> optional.validate(rule, sqlStatementContext, database));
+        Collection<QualifiedTable> singleTables = getSingleTables(database, 
rule, result, sqlStatementContext);
+        validateSingleTableMetaData(database, sqlStatementContext, 
singleTables);
+        SingleRouteEngineFactory.newInstance(singleTables, 
sqlStatementContext.getSqlStatement()).ifPresent(optional -> 
optional.route(result, rule));
         return result;
     }
     
+    private void validateSingleTableMetaData(final ShardingSphereDatabase 
database, final SQLStatementContext sqlStatementContext, final 
Collection<QualifiedTable> singleTables) {
+        // TODO move single table metadata validate logic to infra validator
+        if (!singleTables.isEmpty() && sqlStatementContext.getSqlStatement() 
instanceof DMLStatement) {
+            
ShardingSphereMetaDataValidateUtils.validateTableExist(sqlStatementContext, 
database);
+        }
+    }
+    
+    private Collection<QualifiedTable> getSingleTables(ShardingSphereDatabase 
database, SingleRule rule, RouteContext result, SQLStatementContext 
sqlStatementContext) {
+        Collection<QualifiedTable> qualifiedTables = 
rule.getQualifiedTables(sqlStatementContext, database);
+        return result.getRouteUnits().isEmpty() && 
sqlStatementContext.getSqlStatement() instanceof CreateTableStatement ? 
qualifiedTables : rule.getSingleTables(qualifiedTables);
+    }
+    
     @Override
     public void decorateRouteContext(final RouteContext routeContext, final 
QueryContext queryContext, final ShardingSphereDatabase database,
                                      final SingleRule rule, final 
ConfigurationProperties props, final ConnectionContext connectionContext) {
         SQLStatementContext sqlStatementContext = 
queryContext.getSqlStatementContext();
-        Collection<QualifiedTable> singleTableNames = 
getSingleTableNames(sqlStatementContext, database, rule, routeContext);
-        if (singleTableNames.isEmpty()) {
-            return;
-        }
-        validateSameDataSource(rule, singleTableNames, routeContext);
-        SingleRouteEngineFactory.newInstance(singleTableNames, 
sqlStatementContext.getSqlStatement()).ifPresent(optional -> 
optional.route(routeContext, rule));
+        Collection<QualifiedTable> singleTables = getSingleTables(database, 
rule, routeContext, sqlStatementContext);
+        validateSingleTableMetaData(database, sqlStatementContext, 
singleTables);
+        SingleRouteEngineFactory.newInstance(singleTables, 
sqlStatementContext.getSqlStatement()).ifPresent(optional -> 
optional.route(routeContext, rule));
     }
     
     private RouteContext createSingleDataSourceRouteContext(final SingleRule 
rule, final ShardingSphereDatabase database) {
@@ -99,30 +88,6 @@ public final class SingleSQLRouter implements 
SQLRouter<SingleRule> {
         return result;
     }
     
-    private Collection<QualifiedTable> getSingleTableNames(final 
SQLStatementContext sqlStatementContext,
-                                                           final 
ShardingSphereDatabase database, final SingleRule rule, final RouteContext 
routeContext) {
-        DatabaseType databaseType = sqlStatementContext.getDatabaseType();
-        Collection<QualifiedTable> result = getQualifiedTables(database, 
databaseType, sqlStatementContext.getTablesContext().getSimpleTableSegments());
-        if (result.isEmpty() && sqlStatementContext instanceof IndexAvailable) 
{
-            result = IndexMetaDataUtils.getTableNames(database, databaseType, 
((IndexAvailable) sqlStatementContext).getIndexes());
-        }
-        return routeContext.getRouteUnits().isEmpty() && 
sqlStatementContext.getSqlStatement() instanceof CreateTableStatement ? result 
: rule.getSingleTableNames(result);
-    }
-    
-    private Collection<QualifiedTable> getQualifiedTables(final 
ShardingSphereDatabase database, final DatabaseType databaseType, final 
Collection<SimpleTableSegment> tableSegments) {
-        Collection<QualifiedTable> result = new LinkedList<>();
-        String schemaName = 
DatabaseTypeEngine.getDefaultSchemaName(databaseType, database.getName());
-        for (SimpleTableSegment each : tableSegments) {
-            String actualSchemaName = each.getOwner().map(optional -> 
optional.getIdentifier().getValue()).orElse(schemaName);
-            result.add(new QualifiedTable(actualSchemaName, 
each.getTableName().getIdentifier().getValue()));
-        }
-        return result;
-    }
-    
-    private void validateSameDataSource(final SingleRule rule, final 
Collection<QualifiedTable> singleTableNames, final RouteContext routeContext) {
-        
Preconditions.checkState(rule.isAllTablesInSameDataSource(routeContext, 
singleTableNames), "All tables must be in the same datasource.");
-    }
-    
     @Override
     public int getOrder() {
         return SingleOrder.ORDER;
diff --git 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactory.java
 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactory.java
index 01983c4501b..53eba7bbace 100644
--- 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactory.java
+++ 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactory.java
@@ -37,15 +37,15 @@ public final class SingleRouteEngineFactory {
     /**
      * Create new instance of single route engine.
      *
-     * @param singleTableNames single table names
+     * @param singleTables single tables
      * @param sqlStatement SQL statement
      * @return created instance
      */
-    public static Optional<SingleRouteEngine> newInstance(final 
Collection<QualifiedTable> singleTableNames, final SQLStatement sqlStatement) {
-        // TODO Consider to add route logic for more statements
-        if (!singleTableNames.isEmpty()) {
-            return Optional.of(new SingleStandardRouteEngine(singleTableNames, 
sqlStatement));
+    public static Optional<SingleRouteEngine> newInstance(final 
Collection<QualifiedTable> singleTables, final SQLStatement sqlStatement) {
+        if (!singleTables.isEmpty()) {
+            return Optional.of(new SingleStandardRouteEngine(singleTables, 
sqlStatement));
         }
+        // TODO move this logic to common route logic
         if (isSchemaDDLStatement(sqlStatement)) {
             return Optional.of(new SingleDatabaseBroadcastRouteEngine());
         }
diff --git 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngine.java
 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngine.java
index 26cc5edb06f..adf00977f8c 100644
--- 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngine.java
+++ 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngine.java
@@ -24,17 +24,21 @@ import 
org.apache.shardingsphere.infra.metadata.database.schema.QualifiedTable;
 import org.apache.shardingsphere.infra.route.context.RouteContext;
 import org.apache.shardingsphere.infra.route.context.RouteMapper;
 import org.apache.shardingsphere.infra.route.context.RouteUnit;
+import 
org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
+import 
org.apache.shardingsphere.infra.util.exception.external.sql.type.generic.UnsupportedSQLOperationException;
 import org.apache.shardingsphere.single.exception.SingleTableNotFoundException;
 import org.apache.shardingsphere.single.rule.SingleRule;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.AlterTableStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateTableStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DDLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropTableStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.handler.ddl.CreateTableStatementHandler;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
@@ -47,36 +51,42 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 public final class SingleStandardRouteEngine implements SingleRouteEngine {
     
-    private final Collection<QualifiedTable> singleTableNames;
+    private final Collection<QualifiedTable> singleTables;
     
     private final SQLStatement sqlStatement;
     
     @Override
     public void route(final RouteContext routeContext, final SingleRule 
singleRule) {
         if (routeContext.getRouteUnits().isEmpty() || sqlStatement instanceof 
SelectStatement) {
-            route0(routeContext, singleRule);
+            routeStatement(routeContext, singleRule);
         } else {
             RouteContext newRouteContext = new RouteContext();
-            route0(newRouteContext, singleRule);
+            routeStatement(newRouteContext, singleRule);
             combineRouteContext(routeContext, newRouteContext);
         }
     }
     
-    private void combineRouteContext(final RouteContext routeContext, final 
RouteContext newRouteContext) {
-        Map<String, RouteUnit> dataSourceRouteUnits = 
getDataSourceRouteUnits(newRouteContext);
-        routeContext.getRouteUnits().removeIf(each -> 
!dataSourceRouteUnits.containsKey(each.getDataSourceMapper().getLogicName()));
-        for (Entry<String, RouteUnit> entry : dataSourceRouteUnits.entrySet()) 
{
-            routeContext.putRouteUnit(entry.getValue().getDataSourceMapper(), 
entry.getValue().getTableMappers());
+    private void routeStatement(final RouteContext routeContext, final 
SingleRule rule) {
+        if (sqlStatement instanceof DDLStatement) {
+            routeDDLStatement(routeContext, rule);
+        } else {
+            boolean allTablesInSameComputeNode = 
rule.isAllTablesInSameComputeNode(getDataNodes(routeContext), singleTables);
+            ShardingSpherePreconditions.checkState(allTablesInSameComputeNode, 
() -> new UnsupportedSQLOperationException("all tables must be in the same 
compute node"));
+            fillRouteContext(rule, routeContext, singleTables);
         }
     }
     
-    private Map<String, RouteUnit> getDataSourceRouteUnits(final RouteContext 
newRouteContext) {
-        return 
newRouteContext.getRouteUnits().stream().collect(Collectors.toMap(each -> 
each.getDataSourceMapper().getLogicName(), Function.identity()));
+    private Collection<DataNode> getDataNodes(final RouteContext routeContext) 
{
+        Collection<DataNode> result = new LinkedList<>();
+        for (Collection<DataNode> each : routeContext.getOriginalDataNodes()) {
+            result.addAll(each);
+        }
+        return result;
     }
     
-    private void route0(final RouteContext routeContext, final SingleRule 
rule) {
+    private void routeDDLStatement(final RouteContext routeContext, final 
SingleRule rule) {
         if (sqlStatement instanceof CreateTableStatement) {
-            QualifiedTable table = singleTableNames.iterator().next();
+            QualifiedTable table = singleTables.iterator().next();
             Optional<DataNode> dataNodeOptional = 
rule.findTableDataNode(table.getSchemaName(), table.getTableName());
             boolean containsIfNotExists = 
CreateTableStatementHandler.ifNotExists((CreateTableStatement) sqlStatement);
             if (dataNodeOptional.isPresent() && containsIfNotExists) {
@@ -88,8 +98,9 @@ public final class SingleStandardRouteEngine implements 
SingleRouteEngine {
                 String dataSourceName = rule.assignNewDataSourceName();
                 routeContext.getRouteUnits().add(new RouteUnit(new 
RouteMapper(dataSourceName, dataSourceName), Collections.singleton(new 
RouteMapper(table.getTableName(), table.getTableName()))));
             }
-        } else if (sqlStatement instanceof AlterTableStatement || sqlStatement 
instanceof DropTableStatement || rule.isAllTablesInSameDataSource(routeContext, 
singleTableNames)) {
-            fillRouteContext(rule, routeContext, 
rule.getSingleTableNames(singleTableNames));
+        }
+        if (sqlStatement instanceof AlterTableStatement || sqlStatement 
instanceof DropTableStatement) {
+            fillRouteContext(rule, routeContext, singleTables);
         }
     }
     
@@ -104,4 +115,16 @@ public final class SingleStandardRouteEngine implements 
SingleRouteEngine {
             routeContext.putRouteUnit(new RouteMapper(dataSource, dataSource), 
Collections.singletonList(new RouteMapper(tableName, tableName)));
         }
     }
+    
+    private void combineRouteContext(final RouteContext routeContext, final 
RouteContext newRouteContext) {
+        Map<String, RouteUnit> dataSourceRouteUnits = 
getDataSourceRouteUnits(newRouteContext);
+        routeContext.getRouteUnits().removeIf(each -> 
!dataSourceRouteUnits.containsKey(each.getDataSourceMapper().getLogicName()));
+        for (Entry<String, RouteUnit> entry : dataSourceRouteUnits.entrySet()) 
{
+            routeContext.putRouteUnit(entry.getValue().getDataSourceMapper(), 
entry.getValue().getTableMappers());
+        }
+    }
+    
+    private Map<String, RouteUnit> getDataSourceRouteUnits(final RouteContext 
newRouteContext) {
+        return 
newRouteContext.getRouteUnits().stream().collect(Collectors.toMap(each -> 
each.getDataSourceMapper().getLogicName(), Function.identity()));
+    }
 }
diff --git 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/rule/SingleRule.java
 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/rule/SingleRule.java
index 67af6345e08..065e2e78be9 100644
--- 
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/rule/SingleRule.java
+++ 
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/rule/SingleRule.java
@@ -18,14 +18,16 @@
 package org.apache.shardingsphere.single.rule;
 
 import lombok.Getter;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.binder.type.IndexAvailable;
 import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
 import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
 import org.apache.shardingsphere.infra.database.spi.DatabaseType;
 import org.apache.shardingsphere.infra.datanode.DataNode;
 import org.apache.shardingsphere.infra.datasource.state.DataSourceStateManager;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.metadata.database.schema.QualifiedTable;
-import org.apache.shardingsphere.infra.route.context.RouteContext;
-import org.apache.shardingsphere.infra.route.context.RouteUnit;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
 import org.apache.shardingsphere.infra.rule.identifier.scope.DatabaseRule;
 import 
org.apache.shardingsphere.infra.rule.identifier.type.DataNodeContainedRule;
@@ -37,6 +39,7 @@ import 
org.apache.shardingsphere.infra.rule.identifier.type.exportable.constant.
 import org.apache.shardingsphere.single.api.config.SingleRuleConfiguration;
 import org.apache.shardingsphere.single.datanode.SingleTableDataNodeLoader;
 import org.apache.shardingsphere.single.util.SingleTableLoadUtils;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 
 import javax.sql.DataSource;
 import java.util.ArrayList;
@@ -90,14 +93,31 @@ public final class SingleRule implements DatabaseRule, 
DataNodeContainedRule, Ta
     }
     
     /**
-     * Judge whether single tables are in same data source or not.
-     *
-     * @param singleTableNames single table names
-     * @return whether single tables are in same data source or not
+     * Judge whether all tables are in same compute node or not.
+     * 
+     * @param dataNodes data nodes
+     * @param singleTables single tables
+     * @return whether all tables are in same compute node or not
      */
-    public boolean isSingleTablesInSameDataSource(final 
Collection<QualifiedTable> singleTableNames) {
+    public boolean isAllTablesInSameComputeNode(final Collection<DataNode> 
dataNodes, final Collection<QualifiedTable> singleTables) {
+        if (!isSingleTablesInSameComputeNode(singleTables)) {
+            return false;
+        }
+        QualifiedTable sampleTable = singleTables.iterator().next();
+        Optional<DataNode> dataNode = 
findTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
+        if (dataNode.isPresent()) {
+            for (DataNode each : dataNodes) {
+                if 
(!each.getDataSourceName().equalsIgnoreCase(dataNode.get().getDataSourceName()))
 {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    
+    private boolean isSingleTablesInSameComputeNode(final 
Collection<QualifiedTable> singleTables) {
         String firstFoundDataSourceName = null;
-        for (QualifiedTable each : singleTableNames) {
+        for (QualifiedTable each : singleTables) {
             Optional<DataNode> dataNode = 
findTableDataNode(each.getSchemaName(), each.getTableName());
             if (!dataNode.isPresent()) {
                 continue;
@@ -113,36 +133,13 @@ public final class SingleRule implements DatabaseRule, 
DataNodeContainedRule, Ta
         return true;
     }
     
-    /**
-     * Judge whether all tables are in same data source or not.
-     * 
-     * @param routeContext route context
-     * @param singleTableNames single table names
-     * @return whether all tables are in same data source or not
-     */
-    public boolean isAllTablesInSameDataSource(final RouteContext 
routeContext, final Collection<QualifiedTable> singleTableNames) {
-        if (!isSingleTablesInSameDataSource(singleTableNames)) {
-            return false;
-        }
-        QualifiedTable sampleTable = singleTableNames.iterator().next();
-        Optional<DataNode> dataNode = 
findTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
-        if (dataNode.isPresent()) {
-            for (RouteUnit each : routeContext.getRouteUnits()) {
-                if 
(!each.getDataSourceMapper().getLogicName().equals(dataNode.get().getDataSourceName()))
 {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-    
     /**
      * Get single table names.
      *
      * @param qualifiedTables qualified tables
      * @return single table names
      */
-    public Collection<QualifiedTable> getSingleTableNames(final 
Collection<QualifiedTable> qualifiedTables) {
+    public Collection<QualifiedTable> getSingleTables(final 
Collection<QualifiedTable> qualifiedTables) {
         Collection<QualifiedTable> result = new LinkedList<>();
         for (QualifiedTable each : qualifiedTables) {
             Collection<DataNode> dataNodes = 
singleTableDataNodes.getOrDefault(each.getTableName().toLowerCase(), new 
LinkedList<>());
@@ -162,6 +159,31 @@ public final class SingleRule implements DatabaseRule, 
DataNodeContainedRule, Ta
         return false;
     }
     
+    /**
+     * Get qualified tables.
+     *
+     * @param sqlStatementContext sql statement context
+     * @param database database
+     * @return qualified tables
+     */
+    public Collection<QualifiedTable> getQualifiedTables(final 
SQLStatementContext sqlStatementContext, final ShardingSphereDatabase database) 
{
+        Collection<QualifiedTable> result = getQualifiedTables(database, 
databaseType, sqlStatementContext.getTablesContext().getSimpleTableSegments());
+        if (result.isEmpty() && sqlStatementContext instanceof IndexAvailable) 
{
+            result = IndexMetaDataUtils.getTableNames(database, databaseType, 
((IndexAvailable) sqlStatementContext).getIndexes());
+        }
+        return result;
+    }
+    
+    private Collection<QualifiedTable> getQualifiedTables(final 
ShardingSphereDatabase database, final DatabaseType databaseType, final 
Collection<SimpleTableSegment> tableSegments) {
+        Collection<QualifiedTable> result = new LinkedList<>();
+        String schemaName = 
DatabaseTypeEngine.getDefaultSchemaName(databaseType, database.getName());
+        for (SimpleTableSegment each : tableSegments) {
+            String actualSchemaName = each.getOwner().map(optional -> 
optional.getIdentifier().getValue()).orElse(schemaName);
+            result.add(new QualifiedTable(actualSchemaName, 
each.getTableName().getIdentifier().getValue()));
+        }
+        return result;
+    }
+    
     @Override
     public void put(final String dataSourceName, final String schemaName, 
final String tableName) {
         if (dataSourceNames.contains(dataSourceName)) {
diff --git 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDeciderTest.java
 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDeciderTest.java
index f1061f24699..ddc20fb0ca2 100644
--- 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDeciderTest.java
+++ 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDeciderTest.java
@@ -54,52 +54,52 @@ class SingleSQLFederationDeciderTest {
     }
     
     @Test
-    void assertDecideWhenAllSingleTablesInSameDataSource() {
+    void assertDecideWhenAllSingleTablesInSameComputeNode() {
         Collection<QualifiedTable> qualifiedTables = Arrays.asList(new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order"), new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order_item"));
         SingleRule rule = createSingleRule(qualifiedTables);
-        
when(rule.isSingleTablesInSameDataSource(qualifiedTables)).thenReturn(true);
         SelectStatementContext select = createStatementContext();
         Collection<DataNode> includedDataNodes = new HashSet<>();
+        when(rule.isAllTablesInSameComputeNode(includedDataNodes, 
qualifiedTables)).thenReturn(true);
         assertFalse(new SingleSQLFederationDecider().decide(select, 
Collections.emptyList(), mock(ShardingSphereRuleMetaData.class), 
createDatabase(), rule, includedDataNodes));
         assertThat(includedDataNodes.size(), is(2));
     }
     
     @Test
-    void assertDecideWhenAllSingleTablesNotInSameDataSource() {
+    void assertDecideWhenAllSingleTablesNotInSameComputeNode() {
         Collection<QualifiedTable> qualifiedTables = Arrays.asList(new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order"), new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order_item"));
         SingleRule rule = createSingleRule(qualifiedTables);
-        
when(rule.isSingleTablesInSameDataSource(qualifiedTables)).thenReturn(false);
         SelectStatementContext select = createStatementContext();
         Collection<DataNode> includedDataNodes = new HashSet<>();
+        when(rule.isAllTablesInSameComputeNode(includedDataNodes, 
qualifiedTables)).thenReturn(false);
         assertTrue(new SingleSQLFederationDecider().decide(select, 
Collections.emptyList(), mock(ShardingSphereRuleMetaData.class), 
createDatabase(), rule, includedDataNodes));
         assertThat(includedDataNodes.size(), is(2));
     }
     
     @Test
-    void assertDecideWhenAllTablesInSameDataSource() {
+    void assertDecideWhenAllTablesInSameComputeNode() {
         Collection<QualifiedTable> qualifiedTables = Arrays.asList(new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order"), new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order_item"));
         SingleRule rule = createSingleRule(qualifiedTables);
-        
when(rule.isSingleTablesInSameDataSource(qualifiedTables)).thenReturn(true);
         SelectStatementContext select = createStatementContext();
         Collection<DataNode> includedDataNodes = new 
HashSet<>(Collections.singleton(new DataNode("ds_0", "t_user")));
+        when(rule.isAllTablesInSameComputeNode(includedDataNodes, 
qualifiedTables)).thenReturn(true);
         assertFalse(new SingleSQLFederationDecider().decide(select, 
Collections.emptyList(), mock(ShardingSphereRuleMetaData.class), 
createDatabase(), rule, includedDataNodes));
         assertThat(includedDataNodes.size(), is(3));
     }
     
     @Test
-    void assertDecideWhenAllTablesNotInSameDataSource() {
+    void assertDecideWhenAllTablesNotInSameComputeNode() {
         Collection<QualifiedTable> qualifiedTables = Arrays.asList(new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order"), new 
QualifiedTable(DefaultDatabase.LOGIC_NAME, "t_order_item"));
         SingleRule rule = createSingleRule(qualifiedTables);
-        
when(rule.isSingleTablesInSameDataSource(qualifiedTables)).thenReturn(true);
         SelectStatementContext select = createStatementContext();
         Collection<DataNode> includedDataNodes = new 
HashSet<>(Collections.singleton(new DataNode("ds_1", "t_user")));
+        when(rule.isAllTablesInSameComputeNode(includedDataNodes, 
qualifiedTables)).thenReturn(false);
         assertTrue(new SingleSQLFederationDecider().decide(select, 
Collections.emptyList(), mock(ShardingSphereRuleMetaData.class), 
createDatabase(), rule, includedDataNodes));
         assertThat(includedDataNodes.size(), is(3));
     }
     
     private SingleRule createSingleRule(final Collection<QualifiedTable> 
qualifiedTables) {
         SingleRule result = mock(SingleRule.class);
-        when(result.getSingleTableNames(any())).thenReturn(qualifiedTables);
+        when(result.getSingleTables(any())).thenReturn(qualifiedTables);
         when(result.findTableDataNode(DefaultDatabase.LOGIC_NAME, 
"t_order")).thenReturn(Optional.of(new DataNode("ds_0", "t_order")));
         when(result.findTableDataNode(DefaultDatabase.LOGIC_NAME, 
"t_order_item")).thenReturn(Optional.of(new DataNode("ds_0", "t_order_item")));
         return result;
diff --git 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactoryTest.java
 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactoryTest.java
index 35fe287b8bb..475563975ec 100644
--- 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactoryTest.java
+++ 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleRouteEngineFactoryTest.java
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.mock;
 class SingleRouteEngineFactoryTest {
     
     @Test
-    void assertNewInstanceWithNotEmptySingleTableNames() {
+    void assertNewInstanceWithNotEmptySingleTables() {
         
assertTrue(SingleRouteEngineFactory.newInstance(Collections.singleton(new 
QualifiedTable("demo_ds", "t_order")), mock(SQLStatement.class)).isPresent());
     }
     
diff --git 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/rule/SingleRuleTest.java
 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/rule/SingleRuleTest.java
index 7af2dc3ca48..7bb44fbce66 100644
--- 
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/rule/SingleRuleTest.java
+++ 
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/rule/SingleRuleTest.java
@@ -141,19 +141,10 @@ class SingleRuleTest {
         assertThat(actual.get().getTableName(), is("employee"));
     }
     
-    @Test
-    void assertIsSingleTablesInSameDataSource() {
-        DataNodeContainedRule dataNodeContainedRule = 
mock(DataNodeContainedRule.class);
-        SingleRule singleRule = new SingleRule(ruleConfig, 
DefaultDatabase.LOGIC_NAME, dataSourceMap, 
Collections.singleton(dataNodeContainedRule));
-        Collection<QualifiedTable> singleTableNames = new LinkedList<>();
-        singleTableNames.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"employee"));
-        
assertTrue(singleRule.isSingleTablesInSameDataSource(singleTableNames));
-    }
-    
     @Test
     void assertIsAllTablesInSameDataSource() {
-        Collection<QualifiedTable> singleTableNames = new LinkedList<>();
-        singleTableNames.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"employee"));
+        Collection<QualifiedTable> singleTables = new LinkedList<>();
+        singleTables.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"employee"));
         RouteMapper dataSourceMapper = new RouteMapper("foo_ds", null);
         Collection<RouteMapper> tableMappers = new LinkedList<>();
         tableMappers.add(dataSourceMapper);
@@ -161,7 +152,7 @@ class SingleRuleTest {
         routeContext.putRouteUnit(dataSourceMapper, tableMappers);
         DataNodeContainedRule dataNodeContainedRule = 
mock(DataNodeContainedRule.class);
         SingleRule singleRule = new SingleRule(ruleConfig, 
DefaultDatabase.LOGIC_NAME, dataSourceMap, 
Collections.singleton(dataNodeContainedRule));
-        assertTrue(singleRule.isAllTablesInSameDataSource(routeContext, 
singleTableNames));
+        
assertTrue(singleRule.isAllTablesInSameComputeNode(routeContext.getOriginalDataNodes().stream().flatMap(Collection::stream).collect(Collectors.toList()),
 singleTables));
     }
     
     @Test
@@ -174,13 +165,13 @@ class SingleRuleTest {
     }
     
     @Test
-    void assertGetSingleTableNames() {
+    void assertGetSingleTables() {
         DataNodeContainedRule dataNodeContainedRule = 
mock(DataNodeContainedRule.class);
         SingleRule singleRule = new SingleRule(ruleConfig, 
DefaultDatabase.LOGIC_NAME, dataSourceMap, 
Collections.singleton(dataNodeContainedRule));
         Collection<QualifiedTable> tableNames = new LinkedList<>();
         tableNames.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"employee"));
-        
assertThat(singleRule.getSingleTableNames(tableNames).iterator().next().getSchemaName(),
 is(DefaultDatabase.LOGIC_NAME));
-        
assertThat(singleRule.getSingleTableNames(tableNames).iterator().next().getTableName(),
 is("employee"));
+        
assertThat(singleRule.getSingleTables(tableNames).iterator().next().getSchemaName(),
 is(DefaultDatabase.LOGIC_NAME));
+        
assertThat(singleRule.getSingleTables(tableNames).iterator().next().getTableName(),
 is("employee"));
     }
     
     @Test
@@ -192,8 +183,8 @@ class SingleRuleTest {
         singleRule.put(dataSourceName, DefaultDatabase.LOGIC_NAME, tableName);
         Collection<QualifiedTable> tableNames = new LinkedList<>();
         tableNames.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"teacher"));
-        
assertThat(singleRule.getSingleTableNames(tableNames).iterator().next().getSchemaName(),
 is(DefaultDatabase.LOGIC_NAME));
-        
assertThat(singleRule.getSingleTableNames(tableNames).iterator().next().getTableName(),
 is("teacher"));
+        
assertThat(singleRule.getSingleTables(tableNames).iterator().next().getSchemaName(),
 is(DefaultDatabase.LOGIC_NAME));
+        
assertThat(singleRule.getSingleTables(tableNames).iterator().next().getTableName(),
 is("teacher"));
         assertTrue(singleRule.getLogicTableMapper().contains("employee"));
         assertTrue(singleRule.getLogicTableMapper().contains("student"));
         assertTrue(singleRule.getLogicTableMapper().contains("t_order_0"));
@@ -209,7 +200,7 @@ class SingleRuleTest {
         singleRule.remove(DefaultDatabase.LOGIC_NAME, tableName);
         Collection<QualifiedTable> tableNames = new LinkedList<>();
         tableNames.add(new QualifiedTable(DefaultDatabase.LOGIC_NAME, 
"employee"));
-        assertTrue(singleRule.getSingleTableNames(tableNames).isEmpty());
+        assertTrue(singleRule.getSingleTables(tableNames).isEmpty());
         assertTrue(singleRule.getLogicTableMapper().contains("student"));
         assertTrue(singleRule.getLogicTableMapper().contains("t_order_0"));
         assertTrue(singleRule.getLogicTableMapper().contains("t_order_1"));
diff --git 
a/kernel/single/distsql/handler/src/main/java/org/apache/shardingsphere/single/distsql/handler/query/ShowUnloadedSingleTableExecutor.java
 
b/kernel/single/distsql/handler/src/main/java/org/apache/shardingsphere/single/distsql/handler/query/ShowUnloadedSingleTableExecutor.java
index 5d5890d898c..b20a22797ef 100644
--- 
a/kernel/single/distsql/handler/src/main/java/org/apache/shardingsphere/single/distsql/handler/query/ShowUnloadedSingleTableExecutor.java
+++ 
b/kernel/single/distsql/handler/src/main/java/org/apache/shardingsphere/single/distsql/handler/query/ShowUnloadedSingleTableExecutor.java
@@ -50,8 +50,7 @@ public final class ShowUnloadedSingleTableExecutor implements 
RQLExecutor<ShowUn
         Map<String, Collection<DataNode>> actualDataNodes = 
getActualDataNodes(database);
         Optional<SingleRule> singleRule = 
database.getRuleMetaData().findSingleRule(SingleRule.class);
         if (singleRule.isPresent()) {
-            Collection<String> singleTableNames = 
singleRule.get().getLogicTableMapper().getTableNames();
-            for (String each : singleTableNames) {
+            for (String each : 
singleRule.get().getLogicTableMapper().getTableNames()) {
                 actualDataNodes.remove(each);
             }
         }


Reply via email to