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;
+ }
}
}