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/06/12 09:24:25 UTC

[shardingsphere] branch master updated: Add MetaDataHeldRule for SQLFederationRule to refresh plannerContext when metadata change (#26301)

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 92cbe9f2fed Add MetaDataHeldRule for SQLFederationRule to refresh plannerContext when metadata change (#26301)
92cbe9f2fed is described below

commit 92cbe9f2fedf8f53a76d98792bed10a38cff50fb
Author: Zhengqiang Duan <du...@apache.org>
AuthorDate: Mon Jun 12 17:24:17 2023 +0800

    Add MetaDataHeldRule for SQLFederationRule to refresh plannerContext when metadata change (#26301)
    
    * Add MetaDataHeldRule for SQLFederationRule to refresh plannerContext when metadata change
    
    * modify javadoc
    
    * add alterMetaDataHeldRule in reloadDatabaseMetaData
---
 .../rule/identifier/type/MetaDataHeldRule.java     | 41 ++++++++++++++++++++++
 .../rule/identifier/type/MutableDataNodeRule.java  |  6 ++--
 .../single/decider/SingleSQLFederationDecider.java |  4 +--
 .../route/engine/SingleStandardRouteEngine.java    |  4 +--
 .../shardingsphere/single/rule/SingleRule.java     |  6 ++--
 .../decider/SingleSQLFederationDeciderTest.java    |  4 +--
 .../engine/SingleStandardRouteEngineTest.java      |  2 +-
 .../shardingsphere/single/rule/SingleRuleTest.java |  4 +--
 .../optimizer/SQLFederationCompiler.java           |  4 +--
 .../optimizer/context/OptimizerContext.java        | 19 ++++++++++
 .../sqlfederation/rule/SQLFederationRule.java      | 16 ++++++++-
 .../mode/manager/ContextManager.java               | 32 +++++++++++++----
 .../mode/manager/ContextManagerTest.java           |  2 +-
 .../standalone/StandaloneModeContextManager.java   | 12 ++++++-
 14 files changed, 129 insertions(+), 27 deletions(-)

diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MetaDataHeldRule.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MetaDataHeldRule.java
new file mode 100644
index 00000000000..8f825b3ab32
--- /dev/null
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MetaDataHeldRule.java
@@ -0,0 +1,41 @@
+/*
+ * 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.rule.identifier.type;
+
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+
+/**
+ * ShardingSphere rule which held metadata.
+ */
+public interface MetaDataHeldRule extends ShardingSphereRule {
+    
+    /**
+     * Alter database.
+     * 
+     * @param database database
+     */
+    void alterDatabase(ShardingSphereDatabase database);
+    
+    /**
+     * Drop database.
+     * 
+     * @param databaseName database name
+     */
+    void dropDatabase(String databaseName);
+}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MutableDataNodeRule.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MutableDataNodeRule.java
index f5a9fa8592b..80794b4a9cd 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MutableDataNodeRule.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/rule/identifier/type/MutableDataNodeRule.java
@@ -57,13 +57,13 @@ public interface MutableDataNodeRule extends ShardingSphereRule {
     void remove(Collection<String> schemaNames, String tableName);
     
     /**
-     * Find single data node.
+     * Find table data node.
      *
      * @param schemaName schema name
      * @param tableName table name
-     * @return single table data node
+     * @return table data node
      */
-    Optional<DataNode> findSingleTableDataNode(String schemaName, String tableName);
+    Optional<DataNode> findTableDataNode(String schemaName, String tableName);
     
     /**
      * Reload single rule.
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 66813c6d1a7..81505878976 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
@@ -91,7 +91,7 @@ public final class SingleSQLFederationDecider implements SQLFederationDecider<Si
             return false;
         }
         QualifiedTable sampleTable = singleTableNames.iterator().next();
-        Optional<DataNode> dataNode = rule.findSingleTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
+        Optional<DataNode> dataNode = rule.findTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
         if (!dataNode.isPresent()) {
             return true;
         }
@@ -106,7 +106,7 @@ public final class SingleSQLFederationDecider implements SQLFederationDecider<Si
     private Collection<DataNode> getTableDataNodes(final SingleRule rule, final Collection<QualifiedTable> singleTableNames) {
         Collection<DataNode> result = new HashSet<>();
         for (QualifiedTable each : singleTableNames) {
-            rule.findSingleTableDataNode(each.getSchemaName(), each.getTableName()).ifPresent(result::add);
+            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/engine/SingleStandardRouteEngine.java b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngine.java
index 88f6d4d2e4f..26cc5edb06f 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
@@ -77,7 +77,7 @@ public final class SingleStandardRouteEngine implements SingleRouteEngine {
     private void route0(final RouteContext routeContext, final SingleRule rule) {
         if (sqlStatement instanceof CreateTableStatement) {
             QualifiedTable table = singleTableNames.iterator().next();
-            Optional<DataNode> dataNodeOptional = rule.findSingleTableDataNode(table.getSchemaName(), table.getTableName());
+            Optional<DataNode> dataNodeOptional = rule.findTableDataNode(table.getSchemaName(), table.getTableName());
             boolean containsIfNotExists = CreateTableStatementHandler.ifNotExists((CreateTableStatement) sqlStatement);
             if (dataNodeOptional.isPresent() && containsIfNotExists) {
                 String dataSourceName = dataNodeOptional.map(DataNode::getDataSourceName).orElse(null);
@@ -96,7 +96,7 @@ public final class SingleStandardRouteEngine implements SingleRouteEngine {
     private void fillRouteContext(final SingleRule singleRule, final RouteContext routeContext, final Collection<QualifiedTable> logicTables) {
         for (QualifiedTable each : logicTables) {
             String tableName = each.getTableName();
-            Optional<DataNode> dataNode = singleRule.findSingleTableDataNode(each.getSchemaName(), tableName);
+            Optional<DataNode> dataNode = singleRule.findTableDataNode(each.getSchemaName(), tableName);
             if (!dataNode.isPresent()) {
                 throw new SingleTableNotFoundException(tableName);
             }
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 14fb92b46bb..4ceae345101 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
@@ -131,7 +131,7 @@ public final class SingleRule implements DatabaseRule, DataNodeContainedRule, Ta
     public boolean isSingleTablesInSameDataSource(final Collection<QualifiedTable> singleTableNames) {
         String firstFoundDataSourceName = null;
         for (QualifiedTable each : singleTableNames) {
-            Optional<DataNode> dataNode = findSingleTableDataNode(each.getSchemaName(), each.getTableName());
+            Optional<DataNode> dataNode = findTableDataNode(each.getSchemaName(), each.getTableName());
             if (!dataNode.isPresent()) {
                 continue;
             }
@@ -158,7 +158,7 @@ public final class SingleRule implements DatabaseRule, DataNodeContainedRule, Ta
             return false;
         }
         QualifiedTable sampleTable = singleTableNames.iterator().next();
-        Optional<DataNode> dataNode = findSingleTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
+        Optional<DataNode> dataNode = findTableDataNode(sampleTable.getSchemaName(), sampleTable.getTableName());
         if (dataNode.isPresent()) {
             for (RouteUnit each : routeContext.getRouteUnits()) {
                 if (!each.getDataSourceMapper().getLogicName().equals(dataNode.get().getDataSourceName())) {
@@ -225,7 +225,7 @@ public final class SingleRule implements DatabaseRule, DataNodeContainedRule, Ta
     }
     
     @Override
-    public Optional<DataNode> findSingleTableDataNode(final String schemaName, final String tableName) {
+    public Optional<DataNode> findTableDataNode(final String schemaName, final String tableName) {
         Collection<DataNode> dataNodes = singleTableDataNodes.getOrDefault(tableName.toLowerCase(), new LinkedHashSet<>());
         for (DataNode each : dataNodes) {
             if (schemaName.equalsIgnoreCase(each.getSchemaName())) {
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 72e57550f23..0fc051d7c86 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
@@ -100,8 +100,8 @@ class SingleSQLFederationDeciderTest {
     private SingleRule createSingleRule(final Collection<QualifiedTable> qualifiedTables) {
         SingleRule result = mock(SingleRule.class);
         when(result.getSingleTableNames(any())).thenReturn(qualifiedTables);
-        when(result.findSingleTableDataNode(DefaultDatabase.LOGIC_NAME, "t_order")).thenReturn(Optional.of(new DataNode("ds_0", "t_order")));
-        when(result.findSingleTableDataNode(DefaultDatabase.LOGIC_NAME, "t_order_item")).thenReturn(Optional.of(new DataNode("ds_0", "t_order_item")));
+        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/SingleStandardRouteEngineTest.java b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngineTest.java
index b4856a0056c..f9a60cf1ec3 100644
--- a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngineTest.java
+++ b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/route/engine/SingleStandardRouteEngineTest.java
@@ -149,7 +149,7 @@ class SingleStandardRouteEngineTest {
     private SingleRule mockSingleRule() {
         SingleRule result = mock(SingleRule.class);
         DataNode dataNode = mock(DataNode.class);
-        when(result.findSingleTableDataNode(DefaultDatabase.LOGIC_NAME, "t_order")).thenReturn(Optional.of(dataNode));
+        when(result.findTableDataNode(DefaultDatabase.LOGIC_NAME, "t_order")).thenReturn(Optional.of(dataNode));
         return result;
     }
 }
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 19c93e10e71..61f1c888d26 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
@@ -121,7 +121,7 @@ class SingleRuleTest {
     void assertFindSingleTableDataNode() {
         DataNodeContainedRule dataNodeContainedRule = mock(DataNodeContainedRule.class);
         SingleRule singleRule = new SingleRule(new SingleRuleConfiguration(), DefaultDatabase.LOGIC_NAME, dataSourceMap, Collections.singleton(dataNodeContainedRule));
-        Optional<DataNode> actual = singleRule.findSingleTableDataNode(DefaultDatabase.LOGIC_NAME, "employee");
+        Optional<DataNode> actual = singleRule.findTableDataNode(DefaultDatabase.LOGIC_NAME, "employee");
         assertTrue(actual.isPresent());
         assertThat(actual.get().getDataSourceName(), is("foo_ds"));
         assertThat(actual.get().getTableName(), is("employee"));
@@ -131,7 +131,7 @@ class SingleRuleTest {
     void assertFindSingleTableDataNodeWithUpperCase() {
         DataNodeContainedRule dataNodeContainedRule = mock(DataNodeContainedRule.class);
         SingleRule singleRule = new SingleRule(new SingleRuleConfiguration(), DefaultDatabase.LOGIC_NAME, dataSourceMap, Collections.singleton(dataNodeContainedRule));
-        Optional<DataNode> actual = singleRule.findSingleTableDataNode(DefaultDatabase.LOGIC_NAME, "EMPLOYEE");
+        Optional<DataNode> actual = singleRule.findTableDataNode(DefaultDatabase.LOGIC_NAME, "EMPLOYEE");
         assertTrue(actual.isPresent());
         assertThat(actual.get().getDataSourceName(), is("foo_ds"));
         assertThat(actual.get().getTableName(), is("employee"));
diff --git a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLFederationCompiler.java b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLFederationCompiler.java
index 9dcffdab4e1..f3e52168028 100644
--- a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLFederationCompiler.java
+++ b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLFederationCompiler.java
@@ -22,7 +22,7 @@ import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider;
-import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.metadata.RelMetadataQueryBase;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
@@ -48,7 +48,7 @@ public final class SQLFederationCompiler {
      * @return sql federation execution plan
      */
     public SQLFederationExecutionPlan compile(final SQLStatement sqlStatement) {
-        RelMetadataQuery.THREAD_PROVIDERS.set(JaninoRelMetadataProvider.DEFAULT);
+        RelMetadataQueryBase.THREAD_PROVIDERS.set(JaninoRelMetadataProvider.DEFAULT);
         SqlNode sqlNode = SQLNodeConverterEngine.convert(sqlStatement);
         RelNode logicPlan = converter.convertQuery(sqlNode, true, true).rel;
         RelDataType resultColumnType = Objects.requireNonNull(converter.validator).getValidatedNodeType(sqlNode);
diff --git a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/OptimizerContext.java b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/OptimizerContext.java
index 0e270e35f89..a8d4d6db019 100644
--- a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/OptimizerContext.java
+++ b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/OptimizerContext.java
@@ -57,4 +57,23 @@ public final class OptimizerContext {
     public OptimizerPlannerContext getPlannerContext(final String databaseName) {
         return plannerContexts.get(databaseName.toLowerCase());
     }
+    
+    /**
+     * Put planner context.
+     * 
+     * @param databaseName database name
+     * @param plannerContext planner context
+     */
+    public void putPlannerContext(final String databaseName, final OptimizerPlannerContext plannerContext) {
+        plannerContexts.put(databaseName.toLowerCase(), plannerContext);
+    }
+    
+    /**
+     * Remove planner context.
+     * 
+     * @param databaseName database name
+     */
+    public void removePlannerContext(final String databaseName) {
+        plannerContexts.remove(databaseName.toLowerCase());
+    }
 }
diff --git a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/rule/SQLFederationRule.java b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/rule/SQLFederationRule.java
index 9af676fce63..e61c695d6b0 100644
--- a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/rule/SQLFederationRule.java
+++ b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/rule/SQLFederationRule.java
@@ -21,10 +21,13 @@ import lombok.Getter;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.rule.identifier.scope.GlobalRule;
+import org.apache.shardingsphere.infra.rule.identifier.type.MetaDataHeldRule;
 import org.apache.shardingsphere.sqlfederation.api.config.SQLFederationRuleConfiguration;
 import org.apache.shardingsphere.sqlfederation.executor.SQLFederationExecutor;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContextFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContext;
+import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContextFactory;
 
 import java.util.Map;
 
@@ -32,7 +35,7 @@ import java.util.Map;
  * SQL federation rule.
  */
 @Getter
-public final class SQLFederationRule implements GlobalRule {
+public final class SQLFederationRule implements GlobalRule, MetaDataHeldRule {
     
     private final SQLFederationRuleConfiguration configuration;
     
@@ -46,6 +49,17 @@ public final class SQLFederationRule implements GlobalRule {
         optimizerContext = OptimizerContextFactory.create(databases, props);
     }
     
+    @Override
+    public void alterDatabase(final ShardingSphereDatabase database) {
+        OptimizerPlannerContext plannerContext = OptimizerPlannerContextFactory.create(database, optimizerContext.getParserContext(database.getName()), optimizerContext.getSqlParserRule());
+        optimizerContext.putPlannerContext(database.getName(), plannerContext);
+    }
+    
+    @Override
+    public void dropDatabase(final String databaseName) {
+        optimizerContext.removePlannerContext(databaseName);
+    }
+    
     @Override
     public String getType() {
         return SQLFederationRule.class.getSimpleName();
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
index fff537ab4b7..1087f2ad81b 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
@@ -44,6 +44,7 @@ import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSp
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereView;
 import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
+import org.apache.shardingsphere.infra.rule.identifier.type.MetaDataHeldRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.MutableDataNodeRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.ResourceHeldRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.TableContainedRule;
@@ -133,6 +134,12 @@ public final class ContextManager implements AutoCloseable {
         }
         DatabaseType protocolType = DatabaseTypeEngine.getProtocolType(Collections.emptyMap(), metaDataContexts.get().getMetaData().getProps());
         metaDataContexts.get().getMetaData().addDatabase(databaseName, protocolType);
+        ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
+        alterMetaDataHeldRule(database);
+    }
+    
+    private void alterMetaDataHeldRule(final ShardingSphereDatabase database) {
+        metaDataContexts.get().getMetaData().getGlobalRuleMetaData().findRules(MetaDataHeldRule.class).forEach(each -> each.alterDatabase(database));
     }
     
     /**
@@ -145,6 +152,7 @@ public final class ContextManager implements AutoCloseable {
             return;
         }
         metaDataContexts.get().getMetaData().dropDatabase(metaDataContexts.get().getMetaData().getDatabase(databaseName).getName());
+        metaDataContexts.get().getMetaData().getGlobalRuleMetaData().findRules(MetaDataHeldRule.class).forEach(each -> each.dropDatabase(databaseName));
     }
     
     /**
@@ -154,10 +162,12 @@ public final class ContextManager implements AutoCloseable {
      * @param schemaName schema name
      */
     public synchronized void addSchema(final String databaseName, final String schemaName) {
-        if (metaDataContexts.get().getMetaData().getDatabase(databaseName).containsSchema(schemaName)) {
+        ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
+        if (database.containsSchema(schemaName)) {
             return;
         }
-        metaDataContexts.get().getMetaData().getDatabase(databaseName).putSchema(schemaName, new ShardingSphereSchema());
+        database.putSchema(schemaName, new ShardingSphereSchema());
+        alterMetaDataHeldRule(database);
     }
     
     /**
@@ -167,10 +177,12 @@ public final class ContextManager implements AutoCloseable {
      * @param schemaName schema name
      */
     public synchronized void dropSchema(final String databaseName, final String schemaName) {
-        if (!metaDataContexts.get().getMetaData().getDatabase(databaseName).containsSchema(schemaName)) {
+        ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
+        if (!database.containsSchema(schemaName)) {
             return;
         }
-        metaDataContexts.get().getMetaData().getDatabase(databaseName).removeSchema(schemaName);
+        database.removeSchema(schemaName);
+        alterMetaDataHeldRule(database);
     }
     
     /**
@@ -184,6 +196,7 @@ public final class ContextManager implements AutoCloseable {
     public synchronized void alterSchema(final String databaseName, final String schemaName, final String toBeDeletedTableName, final String toBeDeletedViewName) {
         Optional.ofNullable(toBeDeletedTableName).ifPresent(optional -> dropTable(databaseName, schemaName, optional));
         Optional.ofNullable(toBeDeletedViewName).ifPresent(optional -> dropView(databaseName, schemaName, optional));
+        alterMetaDataHeldRule(metaDataContexts.get().getMetaData().getDatabase(databaseName));
     }
     
     /**
@@ -200,6 +213,7 @@ public final class ContextManager implements AutoCloseable {
         }
         Optional.ofNullable(toBeChangedTable).ifPresent(optional -> alterTable(databaseName, schemaName, optional));
         Optional.ofNullable(toBeChangedView).ifPresent(optional -> alterView(databaseName, schemaName, optional));
+        alterMetaDataHeldRule(metaDataContexts.get().getMetaData().getDatabase(databaseName));
     }
     
     private synchronized void dropTable(final String databaseName, final String schemaName, final String toBeDeletedTableName) {
@@ -467,15 +481,17 @@ public final class ContextManager implements AutoCloseable {
      */
     public synchronized void reloadDatabaseMetaData(final String databaseName) {
         try {
-            ShardingSphereResourceMetaData currentResourceMetaData = metaDataContexts.get().getMetaData().getDatabase(databaseName).getResourceMetaData();
+            ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
+            ShardingSphereResourceMetaData currentResourceMetaData = database.getResourceMetaData();
             Map<String, DataSourceProperties> dataSourceProps = metaDataContexts.get().getPersistService().getDataSourceService().load(databaseName);
             SwitchingResource switchingResource = new ResourceSwitchManager().createByAlterDataSourceProps(currentResourceMetaData, dataSourceProps);
-            metaDataContexts.get().getMetaData().getDatabases().putAll(renewDatabase(metaDataContexts.get().getMetaData().getDatabase(databaseName), switchingResource));
+            metaDataContexts.get().getMetaData().getDatabases().putAll(renewDatabase(database, switchingResource));
             MetaDataContexts reloadedMetaDataContexts = createMetaDataContexts(databaseName, switchingResource);
-            deletedSchemaNames(databaseName, reloadedMetaDataContexts.getMetaData().getDatabase(databaseName), metaDataContexts.get().getMetaData().getDatabase(databaseName));
+            deletedSchemaNames(databaseName, reloadedMetaDataContexts.getMetaData().getDatabase(databaseName), database);
             metaDataContexts.set(reloadedMetaDataContexts);
             metaDataContexts.get().getMetaData().getDatabases().values().forEach(each -> each.getSchemas()
                     .forEach((schemaName, schema) -> metaDataContexts.get().getPersistService().getDatabaseMetaDataService().compareAndPersist(each.getName(), schemaName, schema)));
+            alterMetaDataHeldRule(database);
             switchingResource.closeStaleDataSources();
         } catch (final SQLException ex) {
             log.error("Reload database meta data: {} failed", databaseName, ex);
@@ -513,6 +529,7 @@ public final class ContextManager implements AutoCloseable {
                 metaDataContexts.get().getPersistService().getDatabaseMetaDataService()
                         .compareAndPersist(metaDataContexts.get().getMetaData().getDatabase(databaseName).getName(), schemaName, reloadedSchema);
             }
+            alterMetaDataHeldRule(metaDataContexts.get().getMetaData().getDatabase(databaseName));
         } catch (final SQLException ex) {
             log.error("Reload meta data of database: {} schema: {} with data source: {} failed", databaseName, schemaName, dataSourceName, ex);
         }
@@ -574,6 +591,7 @@ public final class ContextManager implements AutoCloseable {
             dropTable(databaseName, schemaName, tableName);
         }
         metaDataContexts.get().getPersistService().getDatabaseMetaDataService().compareAndPersist(database.getName(), schemaName, database.getSchema(schemaName));
+        alterMetaDataHeldRule(metaDataContexts.get().getMetaData().getDatabase(databaseName));
     }
     
     /**
diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
index df32950d568..477324887d6 100644
--- a/mode/core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
+++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
@@ -96,7 +96,7 @@ class ContextManagerTest {
         when(result.getProtocolType()).thenReturn(new MySQLDatabaseType());
         when(result.getResourceMetaData().getStorageTypes()).thenReturn(Collections.singletonMap("ds_0", new MySQLDatabaseType()));
         MutableDataNodeRule mutableDataNodeRule = mock(MutableDataNodeRule.class, RETURNS_DEEP_STUBS);
-        when(mutableDataNodeRule.findSingleTableDataNode("foo_schema", "foo_tbl")).thenReturn(Optional.of(mock(DataNode.class)));
+        when(mutableDataNodeRule.findTableDataNode("foo_schema", "foo_tbl")).thenReturn(Optional.of(mock(DataNode.class)));
         when(result.getRuleMetaData()).thenReturn(new ShardingSphereRuleMetaData(Collections.singleton(mutableDataNodeRule)));
         when(result.getSchemas()).thenReturn(new HashMap<>(Collections.singletonMap("foo_schema", new ShardingSphereSchema())));
         return result;
diff --git a/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/StandaloneModeContextManager.java b/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/StandaloneModeContextManager.java
index 489b94d59dc..51c7ef73935 100644
--- a/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/StandaloneModeContextManager.java
+++ b/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/StandaloneModeContextManager.java
@@ -27,6 +27,7 @@ import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSp
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereView;
 import org.apache.shardingsphere.infra.metadata.database.schema.pojo.AlterSchemaMetaDataPOJO;
 import org.apache.shardingsphere.infra.metadata.database.schema.pojo.AlterSchemaPOJO;
+import org.apache.shardingsphere.infra.rule.identifier.type.MetaDataHeldRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.MutableDataNodeRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.ResourceHeldRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.TableContainedRule;
@@ -72,7 +73,9 @@ public final class StandaloneModeContextManager implements ModeContextManager, C
     @Override
     public void createSchema(final String databaseName, final String schemaName) {
         ShardingSphereSchema schema = new ShardingSphereSchema();
-        contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).putSchema(schemaName, schema);
+        ShardingSphereDatabase database = contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName);
+        database.putSchema(schemaName, schema);
+        refreshMetaDataHeldRule(database);
         contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService().persist(databaseName, schemaName, schema);
     }
     
@@ -81,6 +84,7 @@ public final class StandaloneModeContextManager implements ModeContextManager, C
         ShardingSphereDatabase database = contextManager.getMetaDataContexts().getMetaData().getDatabase(alterSchemaPOJO.getDatabaseName());
         putSchemaMetaData(database, alterSchemaPOJO.getSchemaName(), alterSchemaPOJO.getRenameSchemaName(), alterSchemaPOJO.getLogicDataSourceName());
         removeSchemaMetaData(database, alterSchemaPOJO.getSchemaName());
+        refreshMetaDataHeldRule(database);
         DatabaseMetaDataBasedPersistService databaseMetaDataService = contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService();
         databaseMetaDataService.persist(alterSchemaPOJO.getDatabaseName(), alterSchemaPOJO.getRenameSchemaName(), database.getSchema(alterSchemaPOJO.getRenameSchemaName()));
         databaseMetaDataService.getViewMetaDataPersistService().persist(alterSchemaPOJO.getDatabaseName(), alterSchemaPOJO.getRenameSchemaName(),
@@ -175,6 +179,7 @@ public final class StandaloneModeContextManager implements ModeContextManager, C
             tobeRemovedSchemas.add(each.toLowerCase());
         }
         removeDataNode(database.getRuleMetaData().findRules(MutableDataNodeRule.class), tobeRemovedSchemas, tobeRemovedTables);
+        refreshMetaDataHeldRule(database);
     }
     
     @Override
@@ -186,6 +191,7 @@ public final class StandaloneModeContextManager implements ModeContextManager, C
         Map<String, ShardingSphereView> views = alterSchemaMetaDataPOJO.getAlteredViews().stream().collect(Collectors.toMap(ShardingSphereView::getName, view -> view));
         addDataNode(database, alterSchemaMetaDataPOJO.getLogicDataSourceName(), schemaName, tables, views);
         removeDataNode(database, schemaName, alterSchemaMetaDataPOJO.getDroppedTables(), alterSchemaMetaDataPOJO.getDroppedViews());
+        refreshMetaDataHeldRule(database);
         DatabaseMetaDataBasedPersistService databaseMetaDataService = contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService();
         databaseMetaDataService.getTableMetaDataPersistService().persist(databaseName, schemaName, tables);
         databaseMetaDataService.getViewMetaDataPersistService().persist(databaseName, schemaName, views);
@@ -193,6 +199,10 @@ public final class StandaloneModeContextManager implements ModeContextManager, C
         alterSchemaMetaDataPOJO.getDroppedViews().forEach(each -> databaseMetaDataService.getViewMetaDataPersistService().delete(databaseName, schemaName, each));
     }
     
+    private void refreshMetaDataHeldRule(final ShardingSphereDatabase database) {
+        contextManager.getMetaDataContexts().getMetaData().getGlobalRuleMetaData().findRules(MetaDataHeldRule.class).forEach(each -> each.alterDatabase(database));
+    }
+    
     @Override
     public void registerStorageUnits(final String databaseName, final Map<String, DataSourceProperties> toBeRegisterStorageUnitProps) throws SQLException {
         SwitchingResource switchingResource =