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/03/19 16:34:34 UTC

(shardingsphere) branch master updated: Create DatabaseIdentifierContext use storage unit database type (#38521)

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

menghaoran 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 088a885bf63 Create DatabaseIdentifierContext use storage unit database type (#38521)
088a885bf63 is described below

commit 088a885bf63fffcf971ed1668d9b56670f116b63
Author: Haoran Meng <me...@gmail.com>
AuthorDate: Fri Mar 20 00:34:27 2026 +0800

    Create DatabaseIdentifierContext use storage unit database type (#38521)
---
 .../DatabaseIdentifierContextFactory.java          | 42 +++++++++-
 .../DatabaseIdentifierContextFactoryTest.java      | 95 ++++++++++++++++++++--
 2 files changed, 126 insertions(+), 11 deletions(-)

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 124cdb8ad22..bc6715eff83 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,12 +19,17 @@ package org.apache.shardingsphere.infra.metadata.identifier;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRuleSet;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRuleSets;
 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.LinkedHashSet;
+import java.util.Optional;
 import java.util.Properties;
 
 /**
@@ -62,7 +67,7 @@ public final class DatabaseIdentifierContextFactory {
      * @return identifier context
      */
     public static DatabaseIdentifierContext create(final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
-        return create(protocolType, getProps(props), getFirstDataSource(resourceMetaData));
+        return new DatabaseIdentifierContext(createRuleSet(protocolType, resourceMetaData, getProps(props)));
     }
     
     private static DatabaseIdentifierContext create(final DatabaseType protocolType, final ConfigurationProperties props, final DataSource dataSource) {
@@ -89,7 +94,7 @@ public final class DatabaseIdentifierContextFactory {
      * @param props configuration properties
      */
     public static void refresh(final DatabaseIdentifierContext identifierContext, final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
-        identifierContext.refresh(new IdentifierCaseRuleResolver().resolve(protocolType, getProps(props), getFirstDataSource(resourceMetaData)));
+        identifierContext.refresh(createRuleSet(protocolType, resourceMetaData, getProps(props)));
     }
     
     private static ConfigurationProperties getProps(final ConfigurationProperties props) {
@@ -102,4 +107,37 @@ public final class DatabaseIdentifierContextFactory {
         }
         return resourceMetaData.getStorageUnits().values().iterator().next().getDataSource();
     }
+    
+    private static IdentifierCaseRuleSet createRuleSet(final DatabaseType protocolType, final ResourceMetaData resourceMetaData, final ConfigurationProperties props) {
+        if (hasMixedIdentifierRuleDatabaseTypes(resourceMetaData)) {
+            return IdentifierCaseRuleSets.newInsensitiveRuleSet();
+        }
+        DatabaseType resolvedDatabaseType = getIdentifierRuleDatabaseType(resourceMetaData).orElse(protocolType);
+        return new IdentifierCaseRuleResolver().resolve(resolvedDatabaseType, props, getFirstDataSource(resourceMetaData));
+    }
+    
+    private static Optional<DatabaseType> getIdentifierRuleDatabaseType(final ResourceMetaData resourceMetaData) {
+        if (null == resourceMetaData || null == resourceMetaData.getStorageUnits() || resourceMetaData.getStorageUnits().isEmpty()) {
+            return Optional.empty();
+        }
+        Collection<DatabaseType> storageDatabaseTypes = new LinkedHashSet<>(resourceMetaData.getStorageUnits().size(), 1F);
+        for (StorageUnit each : resourceMetaData.getStorageUnits().values()) {
+            storageDatabaseTypes.add(each.getStorageType());
+        }
+        return storageDatabaseTypes.stream().findFirst();
+    }
+    
+    private static boolean hasMixedIdentifierRuleDatabaseTypes(final ResourceMetaData resourceMetaData) {
+        if (null == resourceMetaData || null == resourceMetaData.getStorageUnits() || resourceMetaData.getStorageUnits().isEmpty()) {
+            return false;
+        }
+        Collection<DatabaseType> storageDatabaseTypes = new LinkedHashSet<>(resourceMetaData.getStorageUnits().size(), 1F);
+        for (StorageUnit each : resourceMetaData.getStorageUnits().values()) {
+            storageDatabaseTypes.add(each.getStorageType());
+            if (1 < storageDatabaseTypes.size()) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
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 5a97429bc81..35c19e8efc8 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
@@ -26,7 +26,9 @@ import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
 import org.apache.shardingsphere.infra.config.props.MetadataIdentifierCaseSensitivity;
 import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import org.apache.shardingsphere.infra.metadata.database.resource.node.StorageNode;
 import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
+import org.apache.shardingsphere.infra.datasource.pool.props.domain.DataSourcePoolProperties;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.infra.util.props.PropertiesBuilder;
 import org.apache.shardingsphere.infra.util.props.PropertiesBuilder.Property;
@@ -37,18 +39,26 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 import javax.sql.DataSource;
 import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
 import java.util.stream.Stream;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 class DatabaseIdentifierContextFactoryTest {
     
     private static final DatabaseType DATABASE_TYPE = TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
     
+    private static final DatabaseType MYSQL_DATABASE_TYPE = TypedSPILoader.getService(DatabaseType.class, "MySQL");
+    
     @Test
     void assertCreateDefault() {
         DatabaseIdentifierContext actual = DatabaseIdentifierContextFactory.createDefault();
@@ -118,7 +128,12 @@ class DatabaseIdentifierContextFactoryTest {
                 Arguments.of("empty storage units keep explicit sensitive rules", DATABASE_TYPE, new ResourceMetaData(Collections.emptyMap(), Collections.emptyMap()),
                         createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false),
                 Arguments.of("first data source path keeps explicit sensitive rules", DATABASE_TYPE, createResourceMetaDataWithFirstDataSource(),
-                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false));
+                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false),
+                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),
+                Arguments.of("mixed storage trunk types fallback to insensitive rules", MYSQL_DATABASE_TYPE,
+                        createResourceMetaDataWithStorageUrls("jdbc:mysql://localhost:3306/foo_db", "jdbc:oracle:thin:@localhost:1521:xe"),
+                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.NORMALIZED, "Foo", "foo", true));
     }
     
     private static Stream<Arguments> refreshWithProtocolTypeAndPropsArguments() {
@@ -138,7 +153,12 @@ class DatabaseIdentifierContextFactoryTest {
                 Arguments.of("empty storage units refresh to exact lookup", DATABASE_TYPE, new ResourceMetaData(Collections.emptyMap(), Collections.emptyMap()),
                         createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false),
                 Arguments.of("first data source path refreshes to exact lookup", DATABASE_TYPE, createResourceMetaDataWithFirstDataSource(),
-                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false));
+                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.EXACT, "Foo", "foo", false),
+                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),
+                Arguments.of("refresh falls back to insensitive rules for mixed storage types", MYSQL_DATABASE_TYPE,
+                        createResourceMetaDataWithStorageUrls("jdbc:mysql://localhost:3306/foo_db", "jdbc:oracle:thin:@localhost:1521:xe"),
+                        createConfigurationProperties(MetadataIdentifierCaseSensitivity.SENSITIVE), LookupMode.NORMALIZED, "Foo", "foo", true));
     }
     
     private static ConfigurationProperties createConfigurationProperties(final MetadataIdentifierCaseSensitivity caseSensitivity) {
@@ -146,10 +166,67 @@ class DatabaseIdentifierContextFactoryTest {
     }
     
     private static ResourceMetaData createResourceMetaDataWithFirstDataSource() {
-        ResourceMetaData result = mock(ResourceMetaData.class);
-        StorageUnit storageUnit = mock(StorageUnit.class);
-        when(storageUnit.getDataSource()).thenReturn(mock(DataSource.class));
-        when(result.getStorageUnits()).thenReturn(Collections.singletonMap("foo_ds", storageUnit));
-        return result;
+        return createResourceMetaDataWithStorageUrls("jdbc:mysql://localhost:3306/foo_db");
+    }
+    
+    private static ResourceMetaData createResourceMetaDataWithStorageUrls(final String... urls) {
+        Map<String, StorageUnit> storageUnits = new LinkedHashMap<>(urls.length, 1F);
+        for (int i = 0; i < urls.length; i++) {
+            storageUnits.put("ds_" + i, createStorageUnit("ds_" + i, urls[i]));
+        }
+        return new ResourceMetaData(Collections.emptyMap(), storageUnits);
+    }
+    
+    private static StorageUnit createStorageUnit(final String name, final String url) {
+        Map<String, Object> props = new LinkedHashMap<>(2, 1F);
+        props.put("url", url);
+        props.put("username", "root");
+        return new StorageUnit(new StorageNode(name), new DataSourcePoolProperties("com.zaxxer.hikari.HikariDataSource", props), new FixtureDataSource());
+    }
+    
+    private static final class FixtureDataSource implements DataSource {
+        
+        @Override
+        public Connection getConnection() throws SQLException {
+            throw new SQLFeatureNotSupportedException("Not supported in fixture.");
+        }
+        
+        @Override
+        public Connection getConnection(final String username, final String password) throws SQLException {
+            throw new SQLFeatureNotSupportedException("Not supported in fixture.");
+        }
+        
+        @Override
+        public PrintWriter getLogWriter() {
+            return null;
+        }
+        
+        @Override
+        public void setLogWriter(final PrintWriter out) {
+        }
+        
+        @Override
+        public void setLoginTimeout(final int seconds) {
+        }
+        
+        @Override
+        public int getLoginTimeout() {
+            return 0;
+        }
+        
+        @Override
+        public Logger getParentLogger() {
+            return Logger.getGlobal();
+        }
+        
+        @Override
+        public <T> T unwrap(final Class<T> iface) throws SQLException {
+            throw new SQLFeatureNotSupportedException("Not supported in fixture.");
+        }
+        
+        @Override
+        public boolean isWrapperFor(final Class<?> iface) {
+            return false;
+        }
     }
 }