You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by me...@apache.org on 2026/07/15 10:18:21 UTC

(shardingsphere) branch master updated: Simplify and unify identifier case policy resolution (#39129)

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

menghaoranss 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 85f4887b659 Simplify and unify identifier case policy resolution (#39129)
85f4887b659 is described below

commit 85f4887b659c942246dcfc976b321fd846bf5a50
Author: Haoran Meng <me...@gmail.com>
AuthorDate: Wed Jul 15 18:18:14 2026 +0800

    Simplify and unify identifier case policy resolution (#39129)
---
 .../MySQLIdentifierCasePolicyProvider.java         |   2 +-
 .../MySQLIdentifierCasePolicyProviderTest.java     |   2 +-
 .../DatabaseIdentifierContextFactory.java          | 116 +++++++--------------
 .../identifier/IdentifierCasePolicyResolver.java   |  29 ++++--
 .../DatabaseIdentifierContextFactoryTest.java      |  55 ++++++----
 .../IdentifierCasePolicyResolverTest.java          |  13 +--
 .../jdbc/MCPJdbcDatabaseProfileLoader.java         |   2 +-
 .../jdbc/MCPJdbcDatabaseProfileLoaderTest.java     |  36 +++----
 .../manager/resource/StorageUnitManagerTest.java   |   6 ++
 9 files changed, 128 insertions(+), 133 deletions(-)

diff --git a/database/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProvider.java b/database/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProvider.java
index e316cfd51b0..bb7ed87faf0 100644
--- a/database/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProvider.java
+++ b/database/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProvider.java
@@ -41,7 +41,7 @@ public final class MySQLIdentifierCasePolicyProvider implements IdentifierCasePo
     @Override
     public IdentifierCasePolicySet provide(final IdentifierCasePolicyProviderContext context) {
         if (null == context.getDataSource()) {
-            return IdentifierCasePolicyFactory.newInsensitivePolicySet();
+            return IdentifierCasePolicyFactory.newMySQLInsensitivePolicySet();
         }
         try (Connection connection = context.getDataSource().getConnection()) {
             if (null == connection) {
diff --git a/database/connector/dialect/mysql/src/test/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProviderTest.java b/database/connector/dialect/mysql/src/test/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProviderTest.java
index ea2d56898f6..3df6585b7c8 100644
--- a/database/connector/dialect/mysql/src/test/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProviderTest.java
+++ b/database/connector/dialect/mysql/src/test/java/org/apache/shardingsphere/database/connector/mysql/metadata/identifier/MySQLIdentifierCasePolicyProviderTest.java
@@ -72,7 +72,7 @@ class MySQLIdentifierCasePolicyProviderTest {
     
     private static Stream<Arguments> provideArguments() {
         return Stream.of(
-                Arguments.of("null_data_source", new IdentifierCasePolicyProviderContext(DATABASE_TYPE, null), LookupMode.EXACT, LookupMode.NORMALIZED, true),
+                Arguments.of("null_data_source", new IdentifierCasePolicyProviderContext(DATABASE_TYPE, null), LookupMode.NORMALIZED, LookupMode.NORMALIZED, true),
                 Arguments.of("null_connection", new IdentifierCasePolicyProviderContext(DATABASE_TYPE, new NullConnectionFixtureDataSource()), LookupMode.EXACT, LookupMode.NORMALIZED, true),
                 Arguments.of("lower_case_table_names_0", new IdentifierCasePolicyProviderContext(DATABASE_TYPE, new FixtureDataSource(true, 0)),
                         LookupMode.EXACT, LookupMode.EXACT, false),
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
index d69014b32df..f5715e5aa07 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
@@ -19,23 +19,20 @@ package org.apache.shardingsphere.infra.metadata.identifier;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
-import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicySet;
-import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyFactory;
+import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicySet;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
 
-import javax.sql.DataSource;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumMap;
-import java.util.LinkedHashSet;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
 
 /**
  * Database identifier context factory.
@@ -60,11 +57,8 @@ public final class DatabaseIdentifierContextFactory {
      * @return identifier context
      */
     public static DatabaseIdentifierContext create(final DatabaseType protocolType, final ConfigurationProperties props) {
-        ConfigurationProperties actualProps = getProps(props);
-        IdentifierCasePolicyResolver resolver = new IdentifierCasePolicyResolver();
-        IdentifierCasePolicySet protocolPolicySet = resolver.resolve(protocolType, actualProps, null);
-        IdentifierCasePolicySet scopeAwarePolicySet = createScopeAwarePolicySet(protocolPolicySet, protocolPolicySet);
-        return new DatabaseIdentifierContext(scopeAwarePolicySet, false);
+        ResolvedIdentifierContext resolvedContext = resolve(protocolType, null, props);
+        return new DatabaseIdentifierContext(resolvedContext.policySet, resolvedContext.heterogeneousTableLookupEnabled);
     }
     
     /**
@@ -76,27 +70,8 @@ public final class DatabaseIdentifierContextFactory {
      * @return identifier context
      */
     public static DatabaseIdentifierContext create(final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
-        ConfigurationProperties actualProps = getProps(props);
-        IdentifierCasePolicyResolver resolver = new IdentifierCasePolicyResolver();
-        IdentifierCasePolicySet protocolPolicySet = resolver.resolve(protocolType, actualProps, getFirstDataSource(resourceMetaData));
-        Optional<DatabaseType> storageDatabaseType = getIdentifierPolicyDatabaseType(resourceMetaData);
-        IdentifierCasePolicySet storagePolicySet = resolver.resolve(storageDatabaseType.orElse(protocolType), actualProps, getFirstDataSource(resourceMetaData));
-        IdentifierCasePolicySet scopeAwarePolicySet = createScopeAwarePolicySet(protocolPolicySet, storagePolicySet);
-        return new DatabaseIdentifierContext(scopeAwarePolicySet, isHeterogeneous(protocolType, getStorageDatabaseTypes(resourceMetaData)));
-    }
-    
-    /**
-     * Refresh identifier context with protocol-aware identifier policies.
-     *
-     * @param identifierContext identifier context
-     * @param protocolType protocol type
-     * @param props configuration properties
-     */
-    public static void refresh(final DatabaseIdentifierContext identifierContext, final DatabaseType protocolType, final ConfigurationProperties props) {
-        ConfigurationProperties actualProps = getProps(props);
-        IdentifierCasePolicyResolver resolver = new IdentifierCasePolicyResolver();
-        IdentifierCasePolicySet protocolPolicySet = resolver.resolve(protocolType, actualProps, null);
-        identifierContext.refresh(createScopeAwarePolicySet(protocolPolicySet, protocolPolicySet), false);
+        ResolvedIdentifierContext resolvedContext = resolve(protocolType, resourceMetaData, props);
+        return new DatabaseIdentifierContext(resolvedContext.policySet, resolvedContext.heterogeneousTableLookupEnabled);
     }
     
     /**
@@ -108,70 +83,57 @@ public final class DatabaseIdentifierContextFactory {
      * @param props configuration properties
      */
     public static void refresh(final DatabaseIdentifierContext identifierContext, final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
-        ConfigurationProperties actualProps = getProps(props);
-        IdentifierCasePolicyResolver resolver = new IdentifierCasePolicyResolver();
-        IdentifierCasePolicySet protocolPolicySet = resolver.resolve(protocolType, actualProps, getFirstDataSource(resourceMetaData));
-        Optional<DatabaseType> storageDatabaseType = getIdentifierPolicyDatabaseType(resourceMetaData);
-        IdentifierCasePolicySet storagePolicySet = resolver.resolve(storageDatabaseType.orElse(protocolType), actualProps, getFirstDataSource(resourceMetaData));
-        identifierContext.refresh(createScopeAwarePolicySet(protocolPolicySet, storagePolicySet), isHeterogeneous(protocolType, getStorageDatabaseTypes(resourceMetaData)));
+        ResolvedIdentifierContext resolvedContext = resolve(protocolType, resourceMetaData, props);
+        identifierContext.refresh(resolvedContext.policySet, resolvedContext.heterogeneousTableLookupEnabled);
     }
     
-    private static ConfigurationProperties getProps(final ConfigurationProperties props) {
-        return null == props ? new ConfigurationProperties(new Properties()) : props;
+    private static ResolvedIdentifierContext resolve(final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
+        Collection<StorageUnit> storageUnits = getStorageUnits(resourceMetaData);
+        StorageUnit storageUnit = storageUnits.stream().findFirst().orElse(null);
+        IdentifierCasePolicySet protocolPolicySet = IdentifierCasePolicyResolver.resolveProtocol(protocolType, props);
+        IdentifierCasePolicySet storagePolicySet = null == storageUnit
+                ? protocolPolicySet
+                : IdentifierCasePolicyResolver.resolveStorage(storageUnit.getStorageType(), props, storageUnit.getDataSource());
+        return new ResolvedIdentifierContext(createScopeAwarePolicySet(protocolPolicySet, storagePolicySet), isHeterogeneous(protocolType, storageUnits));
     }
     
-    private static DataSource getFirstDataSource(final ResourceMetaData resourceMetaData) {
+    private static Collection<StorageUnit> getStorageUnits(final ResourceMetaData resourceMetaData) {
         if (null == resourceMetaData || null == resourceMetaData.getStorageUnits() || resourceMetaData.getStorageUnits().isEmpty()) {
-            return null;
+            return Collections.emptyList();
         }
-        return resourceMetaData.getStorageUnits().values().iterator().next().getDataSource();
+        return resourceMetaData.getStorageUnits().values();
     }
     
     private static IdentifierCasePolicySet createScopeAwarePolicySet(final IdentifierCasePolicySet protocolPolicySet, final IdentifierCasePolicySet storagePolicySet) {
-        IdentifierCasePolicySet databasePolicySet = IdentifierCasePolicyFactory.newInsensitivePolicySet();
-        IdentifierCasePolicySet storageObjectPolicySet = IdentifierCasePolicyFactory.newQuotedInsensitivePolicySet();
         Map<IdentifierScope, IdentifierCasePolicy> scopedPolicies = new EnumMap<>(IdentifierScope.class);
         for (IdentifierScope each : IdentifierScope.values()) {
-            if (IdentifierScope.DATABASE == each) {
-                scopedPolicies.put(each, databasePolicySet.getPolicy(each));
-                continue;
-            }
-            if (isStorageObjectScope(each)) {
-                scopedPolicies.put(each, storageObjectPolicySet.getPolicy(each));
-                continue;
-            }
-            scopedPolicies.put(each, IdentifierScope.SCHEMA == each ? protocolPolicySet.getPolicy(each) : storagePolicySet.getPolicy(each));
+            scopedPolicies.put(each, storagePolicySet.getPolicy(each));
         }
+        IdentifierCasePolicy databasePolicy = IdentifierCasePolicyFactory.newInsensitivePolicySet().getPolicy(IdentifierScope.DATABASE);
+        IdentifierCasePolicy storageObjectPolicy = IdentifierCasePolicyFactory.newQuotedInsensitivePolicySet().getPolicy(IdentifierScope.COLUMN);
+        scopedPolicies.put(IdentifierScope.DATABASE, databasePolicy);
+        scopedPolicies.put(IdentifierScope.SCHEMA, protocolPolicySet.getPolicy(IdentifierScope.SCHEMA));
         scopedPolicies.put(IdentifierScope.LOGICAL_TABLE, protocolPolicySet.getPolicy(IdentifierScope.LOGICAL_TABLE));
+        scopedPolicies.put(IdentifierScope.COLUMN, storageObjectPolicy);
+        scopedPolicies.put(IdentifierScope.INDEX, storageObjectPolicy);
+        scopedPolicies.put(IdentifierScope.CONSTRAINT, storageObjectPolicy);
         return new IdentifierCasePolicySet(storagePolicySet.getPolicy(IdentifierScope.TABLE), scopedPolicies);
     }
     
-    private static boolean isStorageObjectScope(final IdentifierScope identifierScope) {
-        return IdentifierScope.COLUMN == identifierScope || IdentifierScope.INDEX == identifierScope || IdentifierScope.CONSTRAINT == identifierScope;
-    }
-    
-    private static Optional<DatabaseType> getIdentifierPolicyDatabaseType(final ResourceMetaData resourceMetaData) {
-        Collection<DatabaseType> storageDatabaseTypes = getStorageDatabaseTypes(resourceMetaData);
-        return storageDatabaseTypes.stream().findFirst();
-    }
-    
-    private static Collection<DatabaseType> getStorageDatabaseTypes(final ResourceMetaData resourceMetaData) {
-        if (null == resourceMetaData || null == resourceMetaData.getStorageUnits() || resourceMetaData.getStorageUnits().isEmpty()) {
-            return Collections.emptyList();
-        }
-        Collection<DatabaseType> storageDatabaseTypes = new LinkedHashSet<>(resourceMetaData.getStorageUnits().size(), 1F);
-        for (StorageUnit each : resourceMetaData.getStorageUnits().values()) {
-            storageDatabaseTypes.add(each.getStorageType());
-        }
-        return storageDatabaseTypes;
-    }
-    
-    private static boolean isHeterogeneous(final DatabaseType protocolType, final Collection<DatabaseType> storageDatabaseTypes) {
-        return null != protocolType && null != protocolType.getType() && storageDatabaseTypes.stream()
-                .anyMatch(each -> null != each && null != each.getType() && !isSameProtocolType(protocolType, each));
+    private static boolean isHeterogeneous(final DatabaseType protocolType, final Collection<StorageUnit> storageUnits) {
+        return null != protocolType && null != protocolType.getType() && storageUnits.stream()
+                .map(StorageUnit::getStorageType).anyMatch(each -> null != each && null != each.getType() && !isSameProtocolType(protocolType, each));
     }
     
     private static boolean isSameProtocolType(final DatabaseType protocolType, final DatabaseType storageType) {
         return protocolType.getType().equalsIgnoreCase(storageType.getType());
     }
+    
+    @RequiredArgsConstructor
+    private static final class ResolvedIdentifierContext {
+        
+        private final IdentifierCasePolicySet policySet;
+        
+        private final boolean heterogeneousTableLookupEnabled;
+    }
 }
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolver.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolver.java
index ec4fd4b7aba..9acb706a46e 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolver.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolver.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.metadata.identifier;
 
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProviderContext;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicySet;
@@ -33,20 +35,33 @@ import javax.sql.DataSource;
 /**
  * Resolver of identifier case policy.
  */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class IdentifierCasePolicyResolver {
     
     /**
-     * Resolve identifier case policy.
+     * Resolve protocol identifier case policy.
      *
-     * @param databaseType database type
+     * @param protocolType protocol type
      * @param props configuration properties
-     * @param dataSource data source
      * @return identifier case policy set
      */
-    public IdentifierCasePolicySet resolve(final DatabaseType databaseType, final ConfigurationProperties props, final DataSource dataSource) {
-        if (null == databaseType || null == databaseType.getType()) {
-            return IdentifierCasePolicyFactory.newInsensitivePolicySet();
-        }
+    public static IdentifierCasePolicySet resolveProtocol(final DatabaseType protocolType, final ConfigurationProperties props) {
+        return resolve(protocolType, props, null);
+    }
+    
+    /**
+     * Resolve storage identifier case policy.
+     *
+     * @param storageType storage type
+     * @param props configuration properties
+     * @param dataSource storage data source
+     * @return identifier case policy set
+     */
+    public static IdentifierCasePolicySet resolveStorage(final DatabaseType storageType, final ConfigurationProperties props, final DataSource dataSource) {
+        return resolve(storageType, props, dataSource);
+    }
+    
+    private static IdentifierCasePolicySet resolve(final DatabaseType databaseType, final ConfigurationProperties props, final DataSource dataSource) {
         MetadataIdentifierCaseSensitivity configuredCaseSensitivity = new TemporaryConfigurationProperties(props.getProps())
                 .getValue(TemporaryConfigurationPropertyKey.METADATA_IDENTIFIER_CASE_SENSITIVITY);
         if (MetadataIdentifierCaseSensitivity.INSENSITIVE == configuredCaseSensitivity) {
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
index dcbb5c2db4e..65e7b1af2c2 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
@@ -121,17 +121,6 @@ class DatabaseIdentifierContextFactoryTest {
         assertThat(actualRule.matches(actualIdentifier, logicIdentifier, QuoteCharacter.NONE), is(expectedMatched));
     }
     
-    @ParameterizedTest(name = "{0}")
-    @MethodSource("refreshWithProtocolTypeAndPropsArguments")
-    void assertRefreshWithProtocolTypeAndProps(final String name, final DatabaseType protocolType, final ConfigurationProperties props, final LookupMode expectedLookupMode,
-                                               final String actualIdentifier, final String logicIdentifier, final boolean expectedMatched) {
-        DatabaseIdentifierContext actual = DatabaseIdentifierContextFactory.createDefault();
-        DatabaseIdentifierContextFactory.refresh(actual, protocolType, props);
-        IdentifierCasePolicy actualRule = actual.getPolicy(IdentifierScope.TABLE);
-        assertThat(actualRule.getLookupMode(QuoteCharacter.NONE), is(expectedLookupMode));
-        assertThat(actualRule.matches(actualIdentifier, logicIdentifier, QuoteCharacter.NONE), is(expectedMatched));
-    }
-    
     @ParameterizedTest(name = "{0}")
     @MethodSource("refreshWithResourceMetaDataAndPropsArguments")
     void assertRefreshWithResourceMetaDataAndProps(final String name, final DatabaseType protocolType, final ResourceMetaData resourceMetaData,
@@ -184,6 +173,21 @@ class DatabaseIdentifierContextFactoryTest {
         assertTrue(actualTableRule.matches("T_ORDER", "t_order", QuoteCharacter.NONE));
     }
     
+    @Test
+    void assertCreateDoesNotUseStorageDataSourceForProtocolPolicy() {
+        DatabaseIdentifierContext actual = DatabaseIdentifierContextFactory.create(MYSQL_DATABASE_TYPE,
+                createResourceMetaDataWithStorageUnit("jdbc:oracle:thin:@localhost:1521:xe", createDataSourceFailingOnConnection()), new ConfigurationProperties(new Properties()));
+        assertTrue(actual.getPolicy(IdentifierScope.LOGICAL_TABLE).matches("t_order", "T_ORDER", QuoteCharacter.NONE));
+    }
+    
+    @Test
+    void assertRefreshDoesNotUseStorageDataSourceForProtocolPolicy() {
+        DatabaseIdentifierContext actual = DatabaseIdentifierContextFactory.createDefault();
+        DatabaseIdentifierContextFactory.refresh(actual, MYSQL_DATABASE_TYPE,
+                createResourceMetaDataWithStorageUnit("jdbc:oracle:thin:@localhost:1521:xe", createDataSourceFailingOnConnection()), new ConfigurationProperties(new Properties()));
+        assertTrue(actual.getPolicy(IdentifierScope.LOGICAL_TABLE).matches("t_order", "T_ORDER", QuoteCharacter.NONE));
+    }
+    
     @Test
     void assertCreateUsesInsensitiveRuleForLogicalTableWhenMySQLLowerCaseTableNamesIsZero() {
         DatabaseIdentifierContext actual = DatabaseIdentifierContextFactory.create(MYSQL_DATABASE_TYPE, MYSQL_SENSITIVE_STORAGE_RESOURCE_META_DATA, new ConfigurationProperties(new Properties()));
@@ -389,25 +393,19 @@ class DatabaseIdentifierContextFactoryTest {
     
     private static Stream<Arguments> createWithProtocolTypeAndPropsArguments() {
         return Stream.of(
-                Arguments.of("null protocol type and null props use insensitive rules", null, null, LookupMode.NORMALIZED, "Foo", "foo", true),
+                Arguments.of("empty props use insensitive rules", DATABASE_TYPE, new ConfigurationProperties(new Properties()), LookupMode.NORMALIZED, "Foo", "foo", true),
                 Arguments.of("insensitive props normalize identifiers", DATABASE_TYPE,
                         createConfigurationProperties(MetadataIdentifierCaseSensitivity.INSENSITIVE), LookupMode.NORMALIZED, "Foo", "foo", true));
     }
     
     private static Stream<Arguments> createWithResourceMetaDataAndPropsArguments() {
         return Stream.of(
-                Arguments.of("null resource metadata and null props use insensitive rules", null, null, null, LookupMode.NORMALIZED, "Foo", "foo", true),
+                Arguments.of("null resource metadata and empty props use insensitive rules", DATABASE_TYPE, null, new ConfigurationProperties(new Properties()), LookupMode.NORMALIZED, "Foo", "foo",
+                        true),
                 Arguments.of("storage type overrides protocol type for oracle backend", MYSQL_DATABASE_TYPE, createResourceMetaDataWithStorageUrls("jdbc:oracle:thin:@localhost:1521:xe"),
                         new ConfigurationProperties(new Properties()), LookupMode.NORMALIZED, "T_ORDER", "t_order", true));
     }
     
-    private static Stream<Arguments> refreshWithProtocolTypeAndPropsArguments() {
-        return Stream.of(
-                Arguments.of("null protocol type and null props refresh to insensitive rules", null, null, LookupMode.NORMALIZED, "Foo", "foo", true),
-                Arguments.of("insensitive props refresh to normalized lookup", DATABASE_TYPE,
-                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.INSENSITIVE), LookupMode.NORMALIZED, "Foo", "foo", true));
-    }
-    
     private static Stream<Arguments> createWithSupportedDatabaseSchemaLookupArguments() {
         return Stream.of(
                 createNormalizedLookupArguments("mysql schema", MYSQL_DATABASE_TYPE, MYSQL_INSENSITIVE_RESOURCE_META_DATA, "foo_schema", "`"),
@@ -439,7 +437,9 @@ class DatabaseIdentifierContextFactoryTest {
     
     private static Stream<Arguments> refreshWithResourceMetaDataAndPropsArguments() {
         return Stream.of(
-                Arguments.of("null resource metadata and null props refresh to insensitive rules", null, null, null, LookupMode.NORMALIZED, "Foo", "foo", true),
+                Arguments.of("null resource metadata and empty props refresh to insensitive rules", DATABASE_TYPE, null, new ConfigurationProperties(new Properties()), LookupMode.NORMALIZED, "Foo",
+                        "foo",
+                        true),
                 Arguments.of("refresh uses oracle storage type when protocol type is mysql", MYSQL_DATABASE_TYPE, createResourceMetaDataWithStorageUrls("jdbc:oracle:thin:@localhost:1521:xe"),
                         new ConfigurationProperties(new Properties()), LookupMode.NORMALIZED, "T_ORDER", "t_order", true));
     }
@@ -680,6 +680,19 @@ class DatabaseIdentifierContextFactoryTest {
         return new ResourceMetaData(Collections.emptyMap(), storageUnits);
     }
     
+    private static ResourceMetaData createResourceMetaDataWithStorageUnit(final String url, final DataSource dataSource) {
+        return new ResourceMetaData(Collections.emptyMap(), Collections.singletonMap("ds_0", createStorageUnit("ds_0", url, dataSource)));
+    }
+    
+    private static DataSource createDataSourceFailingOnConnection() {
+        return (DataSource) Proxy.newProxyInstance(DataSource.class.getClassLoader(), new Class[]{DataSource.class}, (proxy, method, args) -> {
+            if ("getConnection".equals(method.getName())) {
+                throw new AssertionError("Storage data source must not be used to resolve protocol policy.");
+            }
+            return null;
+        });
+    }
+    
     private static StorageUnit createStorageUnit(final String name, final String url) {
         return createStorageUnit(name, url, new FixtureDataSource());
     }
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolverTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolverTest.java
index 12e46c1518a..6b439f120fa 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolverTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/IdentifierCasePolicyResolverTest.java
@@ -38,12 +38,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class IdentifierCasePolicyResolverTest {
     
-    private final IdentifierCasePolicyResolver resolver = new IdentifierCasePolicyResolver();
-    
     @Test
     void assertResolveWithInsensitiveConfiguration() {
         IdentifierCasePolicy actual =
-                resolver.resolve(TypedSPILoader.getService(DatabaseType.class, "Oracle"), new ConfigurationProperties(createProperties("insensitive")), null)
+                IdentifierCasePolicyResolver.resolveProtocol(TypedSPILoader.getService(DatabaseType.class, "Oracle"), new ConfigurationProperties(createProperties("insensitive")))
                         .getPolicy(IdentifierScope.TABLE);
         assertThat(actual.getLookupMode(QuoteCharacter.NONE), is(LookupMode.NORMALIZED));
         assertTrue(actual.matches("Foo", "foo", QuoteCharacter.NONE));
@@ -51,7 +49,7 @@ class IdentifierCasePolicyResolverTest {
     
     @Test
     void assertResolveWithAutoPostgreSQLRule() {
-        IdentifierCasePolicy actual = resolver.resolve(TypedSPILoader.getService(DatabaseType.class, "PostgreSQL"), new ConfigurationProperties(new Properties()), null)
+        IdentifierCasePolicy actual = IdentifierCasePolicyResolver.resolveProtocol(TypedSPILoader.getService(DatabaseType.class, "PostgreSQL"), new ConfigurationProperties(new Properties()))
                 .getPolicy(IdentifierScope.TABLE);
         assertTrue(actual.matches("foo", "FOO", QuoteCharacter.NONE));
         assertFalse(actual.matches("Foo", "foo", QuoteCharacter.NONE));
@@ -59,15 +57,18 @@ class IdentifierCasePolicyResolverTest {
     
     @Test
     void assertResolveWithAutoOracleRule() {
-        IdentifierCasePolicy actual = resolver.resolve(TypedSPILoader.getService(DatabaseType.class, "Oracle"), new ConfigurationProperties(new Properties()), null).getPolicy(IdentifierScope.TABLE);
+        IdentifierCasePolicy actual = IdentifierCasePolicyResolver.resolveProtocol(TypedSPILoader.getService(DatabaseType.class, "Oracle"), new ConfigurationProperties(new Properties()))
+                .getPolicy(IdentifierScope.TABLE);
         assertTrue(actual.matches("FOO", "foo", QuoteCharacter.NONE));
         assertFalse(actual.matches("Foo", "foo", QuoteCharacter.NONE));
     }
     
     @Test
     void assertResolveWithAutoMySQLRule() {
-        IdentifierCasePolicy actual = resolver.resolve(TypedSPILoader.getService(DatabaseType.class, "MySQL"), new ConfigurationProperties(new Properties()), null).getPolicy(IdentifierScope.TABLE);
+        IdentifierCasePolicy actual = IdentifierCasePolicyResolver.resolveProtocol(TypedSPILoader.getService(DatabaseType.class, "MySQL"), new ConfigurationProperties(new Properties()))
+                .getPolicy(IdentifierScope.TABLE);
         assertTrue(actual.matches("Foo", "foo", QuoteCharacter.NONE));
+        assertTrue(actual.matches("Foo", "foo", QuoteCharacter.BACK_QUOTE));
     }
     
     private Properties createProperties(final String value) {
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoader.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoader.java
index 58632b6d7e0..f09564e64cb 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoader.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoader.java
@@ -91,7 +91,7 @@ public final class MCPJdbcDatabaseProfileLoader {
     
     private IdentifierCasePolicySet resolveIdentifierCasePolicySet(final String databaseName, final DatabaseType databaseType,
                                                                    final RuntimeDatabaseConfiguration runtimeDatabaseConfig) {
-        return new IdentifierCasePolicyResolver().resolve(databaseType, new ConfigurationProperties(new Properties()),
+        return IdentifierCasePolicyResolver.resolveStorage(databaseType, new ConfigurationProperties(new Properties()),
                 new RuntimeDatabaseDataSource(databaseName, runtimeDatabaseConfig));
     }
     
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoaderTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoaderTest.java
index 112c38c34bc..efcc8c4ad7e 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoaderTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/database/metadata/jdbc/MCPJdbcDatabaseProfileLoaderTest.java
@@ -27,7 +27,6 @@ import org.apache.shardingsphere.infra.metadata.identifier.IdentifierCasePolicyR
 import org.apache.shardingsphere.mcp.support.database.metadata.TransactionCapability;
 import org.apache.shardingsphere.mcp.support.fixture.SupportDatabaseTypeFactoryMocker;
 import org.junit.jupiter.api.Test;
-import org.mockito.MockedConstruction;
 import org.mockito.MockedStatic;
 
 import javax.sql.DataSource;
@@ -45,7 +44,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -59,8 +57,8 @@ class MCPJdbcDatabaseProfileLoaderTest {
         IdentifierCasePolicySet expectedIdentifierCasePolicySet = IdentifierCasePolicyFactory.newSensitivePolicySet();
         try (
                 MockedStatic<DatabaseTypeFactory> ignored = SupportDatabaseTypeFactoryMocker.mockByConnectionMetadata();
-                MockedConstruction<IdentifierCasePolicyResolver> ignoredResolver = mockConstruction(IdentifierCasePolicyResolver.class,
-                        (mock, context) -> when(mock.resolve(any(), any(), any())).thenReturn(expectedIdentifierCasePolicySet))) {
+                MockedStatic<IdentifierCasePolicyResolver> ignoredResolver = mockStatic(IdentifierCasePolicyResolver.class)) {
+            ignoredResolver.when(() -> IdentifierCasePolicyResolver.resolveStorage(any(), any(), any())).thenReturn(expectedIdentifierCasePolicySet);
             RuntimeDatabaseProfile actual =
                     new MCPJdbcDatabaseProfileLoader().load("logic_db", createRuntimeDatabaseConfiguration(SupportDatabaseTypeFactoryMocker.createJdbcUrl("FixtureDB"), "1.0", true, true));
             assertThat(actual.getDatabase(), is("logic_db"));
@@ -108,12 +106,12 @@ class MCPJdbcDatabaseProfileLoaderTest {
                 firstConnection, IdentifierCasePolicyFactory.newSensitivePolicySet(), secondConnection, IdentifierCasePolicyFactory.newInsensitivePolicySet());
         try (
                 MockedStatic<DatabaseTypeFactory> ignored = SupportDatabaseTypeFactoryMocker.mockByConnectionMetadata();
-                MockedConstruction<IdentifierCasePolicyResolver> ignoredResolver = mockConstruction(IdentifierCasePolicyResolver.class,
-                        (mock, context) -> when(mock.resolve(any(), any(), any())).thenAnswer(invocation -> {
-                            try (Connection connection = invocation.getArgument(2, DataSource.class).getConnection()) {
-                                return policies.get(connection);
-                            }
-                        }))) {
+                MockedStatic<IdentifierCasePolicyResolver> ignoredResolver = mockStatic(IdentifierCasePolicyResolver.class)) {
+            ignoredResolver.when(() -> IdentifierCasePolicyResolver.resolveStorage(any(), any(), any())).thenAnswer(invocation -> {
+                try (Connection connection = invocation.getArgument(2, DataSource.class).getConnection()) {
+                    return policies.get(connection);
+                }
+            });
             Map<String, RuntimeDatabaseProfile> actual = new MCPJdbcDatabaseProfileLoader().load(runtimeDatabases);
             assertFalse(actual.get("first_db").getIdentifierCasePolicySet().getPolicy(IdentifierScope.TABLE).matches("phone", "Phone", QuoteCharacter.NONE));
             assertTrue(actual.get("second_db").getIdentifierCasePolicySet().getPolicy(IdentifierScope.TABLE).matches("phone", "Phone", QuoteCharacter.NONE));
@@ -134,15 +132,15 @@ class MCPJdbcDatabaseProfileLoaderTest {
                 .thenThrow(RuntimeDatabaseConnectionException.connectionFailed("logic_db", connectionFailure));
         try (
                 MockedStatic<DatabaseTypeFactory> ignored = SupportDatabaseTypeFactoryMocker.mockByConnectionMetadata();
-                MockedConstruction<IdentifierCasePolicyResolver> ignoredResolver = mockConstruction(IdentifierCasePolicyResolver.class,
-                        (mock, context) -> when(mock.resolve(any(), any(), any())).thenAnswer(invocation -> {
-                            try (Connection ignoredConnection = invocation.getArgument(2, DataSource.class).getConnection()) {
-                                return IdentifierCasePolicyFactory.newSensitivePolicySet();
-                            } catch (final SQLException ex) {
-                                assertThat(ex, is(connectionFailure));
-                                return IdentifierCasePolicyFactory.newInsensitivePolicySet();
-                            }
-                        }))) {
+                MockedStatic<IdentifierCasePolicyResolver> ignoredResolver = mockStatic(IdentifierCasePolicyResolver.class)) {
+            ignoredResolver.when(() -> IdentifierCasePolicyResolver.resolveStorage(any(), any(), any())).thenAnswer(invocation -> {
+                try (Connection ignoredConnection = invocation.getArgument(2, DataSource.class).getConnection()) {
+                    return IdentifierCasePolicyFactory.newSensitivePolicySet();
+                } catch (final SQLException ex) {
+                    assertThat(ex, is(connectionFailure));
+                    return IdentifierCasePolicyFactory.newInsensitivePolicySet();
+                }
+            });
             RuntimeDatabaseProfile actual = new MCPJdbcDatabaseProfileLoader().load("logic_db", runtimeDatabaseConfig);
             assertTrue(actual.getIdentifierCasePolicySet().getPolicy(IdentifierScope.TABLE).matches("phone", "Phone", QuoteCharacter.NONE));
             verify(runtimeDatabaseConfig, times(2)).openConnection("logic_db");
diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/resource/StorageUnitManagerTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/resource/StorageUnitManagerTest.java
index 6b421260cd4..7ea570598c0 100644
--- a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/resource/StorageUnitManagerTest.java
+++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/resource/StorageUnitManagerTest.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.mode.metadata.manager.resource;
 
 import lombok.SneakyThrows;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationProperties;
 import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
@@ -27,6 +28,7 @@ import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaDa
 import org.apache.shardingsphere.infra.metadata.database.resource.node.StorageNode;
 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.mode.metadata.factory.MetaDataContextsFactory;
 import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistFacade;
@@ -76,8 +78,10 @@ class StorageUnitManagerTest {
         when(resourceSwitchManager.switchByRegisterStorageUnit(any(ResourceMetaData.class), any(Map.class), anyBoolean())).thenReturn(switchingResource);
         ShardingSphereDatabase reloadDatabase = mock(ShardingSphereDatabase.class);
         when(reloadDatabase.getAllSchemas()).thenReturn(Collections.singleton(new ShardingSphereSchema("foo_schema", mock(DatabaseType.class))));
+        when(reloadDatabase.getProtocolType()).thenReturn(TypedSPILoader.getService(DatabaseType.class, "FIXTURE"));
         MetaDataContexts reloadMetaDataContexts = mock(MetaDataContexts.class, RETURNS_DEEP_STUBS);
         when(reloadMetaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(reloadDatabase);
+        when(reloadMetaDataContexts.getMetaData().getProps()).thenReturn(new ConfigurationProperties(new Properties()));
         try (
                 MockedConstruction<MetaDataContextsFactory> ignored = mockConstruction(MetaDataContextsFactory.class,
                         (mock, context) -> when(mock.createBySwitchResource(DATABASE_NAME, switchingResource, metaDataContexts)).thenReturn(reloadMetaDataContexts))) {
@@ -127,6 +131,7 @@ class StorageUnitManagerTest {
         ShardingSphereDatabase reloadDatabase = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS);
         MetaDataContexts reloadMetaDataContexts = mock(MetaDataContexts.class, RETURNS_DEEP_STUBS);
         when(reloadMetaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(reloadDatabase);
+        when(reloadMetaDataContexts.getMetaData().getProps()).thenReturn(new ConfigurationProperties(new Properties()));
         when(reloadDatabase.getAllSchemas()).thenReturn(Collections.singleton(new ShardingSphereSchema("foo_schema", mock(DatabaseType.class))));
         try (
                 MockedConstruction<MetaDataContextsFactory> ignored = mockConstruction(MetaDataContextsFactory.class,
@@ -158,6 +163,7 @@ class StorageUnitManagerTest {
         ShardingSphereDatabase reloadDatabase = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS);
         MetaDataContexts reloadMetaDataContexts = mock(MetaDataContexts.class, RETURNS_DEEP_STUBS);
         when(reloadMetaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(reloadDatabase);
+        when(reloadMetaDataContexts.getMetaData().getProps()).thenReturn(new ConfigurationProperties(new Properties()));
         when(reloadDatabase.getAllSchemas()).thenReturn(Collections.singleton(new ShardingSphereSchema("foo_schema", mock(DatabaseType.class))));
         try (
                 MockedConstruction<MetaDataContextsFactory> ignored = mockConstruction(MetaDataContextsFactory.class,