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

terrymanu 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 1f47e5ccf21 Refactor database type detection to use metadata fallback 
SPI (#39013)
1f47e5ccf21 is described below

commit 1f47e5ccf21b775c3aa18d57172882754a5a4955
Author: Liang Zhang <[email protected]>
AuthorDate: Sun Jul 5 23:24:28 2026 +0800

    Refactor database type detection to use metadata fallback SPI (#39013)
---
 .../connector/core/type/DatabaseTypeFactory.java   |  20 ++-
 .../core/type/DatabaseTypeFactoryTest.java         |  83 +++++++++---
 .../infra/database/DatabaseTypeEngine.java         |  20 +--
 .../infra/database/DatabaseTypeEngineTest.java     | 145 ++++++++-------------
 .../savepoint/ConnectionSavepointManager.java      |   2 +-
 .../fixture/CoreDatabaseTypeFactoryMocker.java     |   4 +
 .../jdbc/MCPJdbcDatabaseProfileLoader.java         |   6 +-
 .../jdbc/MCPJdbcDatabaseProfileLoaderTest.java     |   3 +-
 .../fixture/SupportDatabaseTypeFactoryMocker.java  |   4 +
 9 files changed, 152 insertions(+), 135 deletions(-)

diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactory.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactory.java
index e2d412610ee..01ebc1082dc 100644
--- 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactory.java
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactory.java
@@ -20,13 +20,16 @@ package 
org.apache.shardingsphere.database.connector.core.type;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import 
org.apache.shardingsphere.database.connector.core.exception.UnsupportedStorageTypeException;
+import 
org.apache.shardingsphere.database.connector.core.jdbcurl.DialectJdbcUrlFetcher;
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
-import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 
+import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
 import java.util.Collection;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
@@ -60,7 +63,20 @@ public final class DatabaseTypeFactory {
      * @throws SQLException SQL exception
      */
     public static DatabaseType get(final DatabaseMetaData metaData) throws 
SQLException {
-        return metaData.getDatabaseProductName().contains("Hive") ? 
TypedSPILoader.getService(DatabaseType.class, "Hive") : get(metaData.getURL());
+        try {
+            return get(metaData.getURL());
+        } catch (final SQLFeatureNotSupportedException ex) {
+            return 
findByDialectJdbcUrlFetcher(metaData.getConnection()).orElseThrow(() -> ex);
+        }
+    }
+    
+    private static Optional<DatabaseType> findByDialectJdbcUrlFetcher(final 
Connection connection) throws SQLException {
+        for (DialectJdbcUrlFetcher each : 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)) {
+            if (connection.isWrapperFor(each.getConnectionClass())) {
+                return Optional.of(get(each.fetch(connection)));
+            }
+        }
+        return Optional.empty();
     }
     
     private static boolean matchURLs(final String url, final DatabaseType 
databaseType) {
diff --git 
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactoryTest.java
 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactoryTest.java
index 553a4202d96..56473da1a4f 100644
--- 
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactoryTest.java
+++ 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/type/DatabaseTypeFactoryTest.java
@@ -18,8 +18,8 @@
 package org.apache.shardingsphere.database.connector.core.type;
 
 import 
org.apache.shardingsphere.database.connector.core.exception.UnsupportedStorageTypeException;
+import 
org.apache.shardingsphere.database.connector.core.jdbcurl.DialectJdbcUrlFetcher;
 import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
-import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
 import org.junit.jupiter.api.Test;
@@ -27,10 +27,11 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.MockedStatic;
 
+import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -40,8 +41,8 @@ import java.util.stream.Stream;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
@@ -50,7 +51,8 @@ class DatabaseTypeFactoryTest {
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("getDatabaseTypeWithRecognizedURLArguments")
-    void assertGetWithRecognizedURL(final String name, final String url, final 
Collection<DatabaseType> databaseTypes, final DatabaseType 
expectedDatabaseType) {
+    void assertGetWithRecognizedURL(final String name, final String url, final 
Collection<DatabaseType> databaseTypes,
+                                    final DatabaseType expectedDatabaseType) {
         
when(ShardingSphereServiceLoader.getServiceInstances(DatabaseType.class)).thenReturn(databaseTypes);
         assertThat(DatabaseTypeFactory.get(url), is(expectedDatabaseType));
     }
@@ -65,40 +67,81 @@ class DatabaseTypeFactoryTest {
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("getDatabaseTypeWithDatabaseMetaDataArguments")
-    void assertGetWithDatabaseMetaData(final String name, final String 
productName, final String url, final Collection<DatabaseType> databaseTypes,
-                                       final DatabaseType 
expectedDatabaseType, final boolean isHive) throws SQLException {
+    void assertGetWithDatabaseMetaData(final String name, final String url, 
final Collection<DatabaseType> databaseTypes,
+                                       final DatabaseType 
expectedDatabaseType) throws SQLException {
         DatabaseMetaData metaData = mock(DatabaseMetaData.class);
-        when(metaData.getDatabaseProductName()).thenReturn(productName);
-        if (isHive) {
-            DatabaseType hiveDatabaseType = mock(DatabaseType.class);
-            try (MockedStatic<TypedSPILoader> typedSPILoader = 
mockStatic(TypedSPILoader.class)) {
-                typedSPILoader.when(() -> 
TypedSPILoader.getService(DatabaseType.class, 
"Hive")).thenReturn(hiveDatabaseType);
-                assertThat(DatabaseTypeFactory.get(metaData), 
is(hiveDatabaseType));
-            }
-            return;
-        }
         when(metaData.getURL()).thenReturn(url);
         
when(ShardingSphereServiceLoader.getServiceInstances(DatabaseType.class)).thenReturn(databaseTypes);
         assertThat(DatabaseTypeFactory.get(metaData), 
is(expectedDatabaseType));
     }
     
+    @Test
+    void assertGetWithUnsupportedMetadataURLAndDialectJdbcUrlFetcher() throws 
SQLException {
+        DatabaseType databaseType = mockDatabaseType("jdbc:trunk:", null);
+        DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+        Connection connection = mock(Connection.class);
+        DialectJdbcUrlFetcher jdbcUrlFetcher = 
mock(DialectJdbcUrlFetcher.class);
+        when(metaData.getURL()).thenThrow(new 
SQLFeatureNotSupportedException("unsupported"));
+        when(metaData.getConnection()).thenReturn(connection);
+        doReturn(Connection.class).when(jdbcUrlFetcher).getConnectionClass();
+        when(connection.isWrapperFor(Connection.class)).thenReturn(true);
+        
when(jdbcUrlFetcher.fetch(connection)).thenReturn("jdbc:trunk://localhost:3306/test");
+        
when(ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(Collections.singleton(jdbcUrlFetcher));
+        
when(ShardingSphereServiceLoader.getServiceInstances(DatabaseType.class)).thenReturn(Collections.singleton(databaseType));
+        assertThat(DatabaseTypeFactory.get(metaData), is(databaseType));
+    }
+    
+    @Test
+    void assertGetWithUnsupportedMetadataURLAndNoDialectJdbcUrlFetcher() 
throws SQLException {
+        SQLFeatureNotSupportedException expectedException = new 
SQLFeatureNotSupportedException("unsupported");
+        DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+        Connection connection = mock(Connection.class);
+        DialectJdbcUrlFetcher jdbcUrlFetcher = 
mock(DialectJdbcUrlFetcher.class);
+        when(metaData.getURL()).thenThrow(expectedException);
+        when(metaData.getConnection()).thenReturn(connection);
+        doReturn(Connection.class).when(jdbcUrlFetcher).getConnectionClass();
+        when(connection.isWrapperFor(Connection.class)).thenReturn(false);
+        
when(ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(Collections.singleton(jdbcUrlFetcher));
+        SQLFeatureNotSupportedException actualException = 
assertThrows(SQLFeatureNotSupportedException.class, () -> 
DatabaseTypeFactory.get(metaData));
+        assertThat(actualException, is(expectedException));
+    }
+    
+    @Test
+    void assertGetWithUnsupportedDialectJdbcUrlFetcherURL() throws 
SQLException {
+        DatabaseType databaseType = mock(DatabaseType.class);
+        DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+        Connection connection = mock(Connection.class);
+        DialectJdbcUrlFetcher jdbcUrlFetcher = 
mock(DialectJdbcUrlFetcher.class);
+        
when(databaseType.getJdbcUrlPrefixes()).thenReturn(Collections.singleton("jdbc:trunk:"));
+        when(metaData.getURL()).thenThrow(new 
SQLFeatureNotSupportedException("unsupported"));
+        when(metaData.getConnection()).thenReturn(connection);
+        doReturn(Connection.class).when(jdbcUrlFetcher).getConnectionClass();
+        when(connection.isWrapperFor(Connection.class)).thenReturn(true);
+        
when(jdbcUrlFetcher.fetch(connection)).thenReturn("jdbc:not-existed:test");
+        
when(ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(Collections.singleton(jdbcUrlFetcher));
+        
when(ShardingSphereServiceLoader.getServiceInstances(DatabaseType.class)).thenReturn(Collections.singleton(databaseType));
+        assertThrows(UnsupportedStorageTypeException.class, () -> 
DatabaseTypeFactory.get(metaData));
+    }
+    
     private static Stream<Arguments> 
getDatabaseTypeWithRecognizedURLArguments() {
         DatabaseType trunkDatabaseType = mockDatabaseType("jdbc:trunk:", null);
         DatabaseType branchDatabaseType = 
mockDatabaseType("jdbc:trunk:branch:", trunkDatabaseType);
         DatabaseType branchOnlyDatabaseType = 
mockDatabaseType("jdbc:branch-only:", mock(DatabaseType.class));
         return Stream.of(
                 Arguments.of("trunk url", "jdbc:trunk://localhost:3306/test", 
Collections.singletonList(trunkDatabaseType), trunkDatabaseType),
-                Arguments.of("branch url", 
"jdbc:trunk:branch://localhost:3306/test?databaseType=BRANCH", 
Arrays.asList(trunkDatabaseType, branchDatabaseType), trunkDatabaseType),
-                Arguments.of("branch only url", 
"jdbc:branch-only://localhost:3306/test", 
Collections.singletonList(branchOnlyDatabaseType), branchOnlyDatabaseType));
+                Arguments.of("branch url", 
"jdbc:trunk:branch://localhost:3306/test?databaseType=BRANCH",
+                        Arrays.asList(trunkDatabaseType, branchDatabaseType), 
trunkDatabaseType),
+                Arguments.of("branch only url", 
"jdbc:branch-only://localhost:3306/test",
+                        Collections.singletonList(branchOnlyDatabaseType), 
branchOnlyDatabaseType));
     }
     
     private static Stream<Arguments> 
getDatabaseTypeWithDatabaseMetaDataArguments() {
         DatabaseType trunkDatabaseType = mockDatabaseType("jdbc:trunk:", null);
         DatabaseType branchOnlyDatabaseType = 
mockDatabaseType("jdbc:branch-only:", mock(DatabaseType.class));
         return Stream.of(
-                Arguments.of("hive database product", "Apache Hive", 
"jdbc:hive://localhost:3306/test", Collections.emptyList(), null, true),
-                Arguments.of("non hive with trunk url", "MySQL", 
"jdbc:trunk://localhost:3306/test", 
Collections.singletonList(trunkDatabaseType), trunkDatabaseType, false),
-                Arguments.of("non hive with branch only url", "MySQL", 
"jdbc:branch-only://localhost:3306/test", 
Collections.singletonList(branchOnlyDatabaseType), branchOnlyDatabaseType, 
false));
+                Arguments.of("trunk url", "jdbc:trunk://localhost:3306/test", 
Collections.singletonList(trunkDatabaseType), trunkDatabaseType),
+                Arguments.of("branch only url", 
"jdbc:branch-only://localhost:3306/test",
+                        Collections.singletonList(branchOnlyDatabaseType), 
branchOnlyDatabaseType));
     }
     
     private static DatabaseType mockDatabaseType(final String jdbcUrlPrefix, 
final DatabaseType trunkDatabaseType) {
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngine.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngine.java
index 8eedaeafd03..a071eb99c85 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngine.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngine.java
@@ -19,20 +19,17 @@ package org.apache.shardingsphere.infra.database;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import 
org.apache.shardingsphere.database.connector.core.jdbcurl.DialectJdbcUrlFetcher;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeFactory;
 import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
 import 
org.apache.shardingsphere.infra.exception.external.sql.type.wrapper.SQLWrapperException;
-import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -101,27 +98,12 @@ public final class DatabaseTypeEngine {
      */
     public static DatabaseType getStorageType(final DataSource dataSource) {
         try (Connection connection = dataSource.getConnection()) {
-            return DatabaseTypeFactory.get(connection.getMetaData().getURL());
-        } catch (final SQLFeatureNotSupportedException 
sqlFeatureNotSupportedException) {
-            return findStorageType(dataSource).orElseThrow(() -> new 
SQLWrapperException(sqlFeatureNotSupportedException));
+            return DatabaseTypeFactory.get(connection.getMetaData());
         } catch (final SQLException ex) {
             throw new SQLWrapperException(ex);
         }
     }
     
-    private static Optional<DatabaseType> findStorageType(final DataSource 
dataSource) {
-        try (Connection connection = dataSource.getConnection()) {
-            for (DialectJdbcUrlFetcher each : 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)) {
-                if (connection.isWrapperFor(each.getConnectionClass())) {
-                    return 
Optional.of(DatabaseTypeFactory.get(each.fetch(connection)));
-                }
-            }
-        } catch (final SQLException ex) {
-            throw new SQLWrapperException(ex);
-        }
-        return Optional.empty();
-    }
-    
     /**
      * Get default storage type.
      *
diff --git 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngineTest.java
 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngineTest.java
index 60fd01b6eb1..6fbcbbf86db 100644
--- 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngineTest.java
+++ 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/database/DatabaseTypeEngineTest.java
@@ -18,14 +18,13 @@
 package org.apache.shardingsphere.infra.database;
 
 import 
org.apache.shardingsphere.database.connector.core.exception.UnsupportedStorageTypeException;
-import 
org.apache.shardingsphere.database.connector.core.jdbcurl.DialectJdbcUrlFetcher;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeFactory;
 import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
 import 
org.apache.shardingsphere.infra.exception.external.sql.type.wrapper.SQLWrapperException;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
-import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
 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,10 +36,8 @@ import org.mockito.MockedStatic;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -50,9 +47,7 @@ import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.isA;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
@@ -74,44 +69,66 @@ class DatabaseTypeEngineTest {
         assertThat(DatabaseTypeEngine.getProtocolType(databaseConfigs, props), 
is(expectedDatabaseType));
     }
     
-    @ParameterizedTest(name = "{0}")
-    @MethodSource("getStorageTypeArguments")
-    void assertGetStorageType(final String name, final DataSource dataSource, 
final Collection<DialectJdbcUrlFetcher> fetchers, final DatabaseType 
expectedDatabaseType) {
-        try (MockedStatic<ShardingSphereServiceLoader> mocked = 
mockStatic(ShardingSphereServiceLoader.class, CALLS_REAL_METHODS)) {
-            mocked.when(() -> 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(fetchers);
-            assertThat(DatabaseTypeEngine.getStorageType(dataSource), 
is(expectedDatabaseType));
+    @Test
+    void assertGetStorageType() throws SQLException {
+        DatabaseType expectedDatabaseType = mock(DatabaseType.class);
+        DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
+        try (MockedStatic<DatabaseTypeFactory> mocked = 
mockStatic(DatabaseTypeFactory.class)) {
+            mocked.when(() -> 
DatabaseTypeFactory.get(databaseMetaData)).thenReturn(expectedDatabaseType);
+            
assertThat(DatabaseTypeEngine.getStorageType(createDataSource(createConnectionWithMetadata(databaseMetaData))),
 is(expectedDatabaseType));
         }
     }
     
-    @ParameterizedTest(name = "{0}")
-    @MethodSource("getStorageTypeWithSQLWrapperExceptionArguments")
-    void assertGetStorageTypeWithSQLWrapperException(final String name,
-                                                     final DataSource 
dataSource, final Collection<DialectJdbcUrlFetcher> fetchers, final Class<? 
extends SQLException> expectedCauseType) {
-        try (MockedStatic<ShardingSphereServiceLoader> mocked = 
mockStatic(ShardingSphereServiceLoader.class, CALLS_REAL_METHODS)) {
-            mocked.when(() -> 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(fetchers);
-            assertThat(assertThrows(SQLWrapperException.class, () -> 
DatabaseTypeEngine.getStorageType(dataSource)).getCause(), 
isA(expectedCauseType));
+    @Test
+    void assertGetStorageTypeWithConnectionException() throws SQLException {
+        SQLException expectedCause = new SQLException("connection failed");
+        DataSource dataSource = mock(DataSource.class);
+        when(dataSource.getConnection()).thenThrow(expectedCause);
+        SQLWrapperException actual = assertThrows(SQLWrapperException.class, 
() -> DatabaseTypeEngine.getStorageType(dataSource));
+        assertThat(actual.getCause(), is(expectedCause));
+    }
+    
+    @Test
+    void assertGetStorageTypeWithMetadataException() throws SQLException {
+        SQLException expectedCause = new SQLException("metadata failed");
+        Connection connection = mock(Connection.class);
+        when(connection.getMetaData()).thenThrow(expectedCause);
+        SQLWrapperException actual = assertThrows(SQLWrapperException.class, 
() -> DatabaseTypeEngine.getStorageType(createDataSource(connection)));
+        assertThat(actual.getCause(), is(expectedCause));
+    }
+    
+    @Test
+    void assertGetStorageTypeWithDatabaseTypeFactorySQLException() {
+        SQLException expectedCause = new SQLException("factory failed");
+        DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
+        try (MockedStatic<DatabaseTypeFactory> mocked = 
mockStatic(DatabaseTypeFactory.class)) {
+            mocked.when(() -> 
DatabaseTypeFactory.get(databaseMetaData)).thenThrow(expectedCause);
+            SQLWrapperException actual = 
assertThrows(SQLWrapperException.class,
+                    () -> 
DatabaseTypeEngine.getStorageType(createDataSource(createConnectionWithMetadata(databaseMetaData))));
+            assertThat(actual.getCause(), is(expectedCause));
         }
     }
     
     @Test
-    void assertGetStorageTypeWithUnsupportedStorageType() throws SQLException {
-        Connection firstConnection = createConnectionWithUnsupportedUrl();
-        Connection secondConnection = mock(Connection.class);
-        DialectJdbcUrlFetcher fetcher = 
createDialectJdbcUrlFetcher(secondConnection, 
"jdbc:unsupported://localhost:3306/test");
-        DataSource dataSource = createDataSource(firstConnection, 
secondConnection);
-        try (MockedStatic<ShardingSphereServiceLoader> mocked = 
mockStatic(ShardingSphereServiceLoader.class, CALLS_REAL_METHODS)) {
-            mocked.when(() -> 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenReturn(Collections.singleton(fetcher));
-            assertThrows(UnsupportedStorageTypeException.class, () -> 
DatabaseTypeEngine.getStorageType(dataSource));
+    void assertGetStorageTypeWithUnsupportedStorageType() {
+        UnsupportedStorageTypeException expectedException = new 
UnsupportedStorageTypeException("jdbc:unsupported:test");
+        DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
+        try (MockedStatic<DatabaseTypeFactory> mocked = 
mockStatic(DatabaseTypeFactory.class)) {
+            mocked.when(() -> 
DatabaseTypeFactory.get(databaseMetaData)).thenThrow(expectedException);
+            UnsupportedStorageTypeException actual = 
assertThrows(UnsupportedStorageTypeException.class,
+                    () -> 
DatabaseTypeEngine.getStorageType(createDataSource(createConnectionWithMetadata(databaseMetaData))));
+            assertThat(actual, is(expectedException));
         }
     }
     
     @Test
-    void assertGetStorageTypeWithRuntimeException() throws SQLException {
-        Connection firstConnection = createConnectionWithUnsupportedUrl();
-        DataSource dataSource = createDataSource(firstConnection, null);
-        try (MockedStatic<ShardingSphereServiceLoader> mocked = 
mockStatic(ShardingSphereServiceLoader.class, CALLS_REAL_METHODS)) {
-            mocked.when(() -> 
ShardingSphereServiceLoader.getServiceInstances(DialectJdbcUrlFetcher.class)).thenThrow(new
 IllegalStateException("boom"));
-            assertThat(assertThrows(IllegalStateException.class, () -> 
DatabaseTypeEngine.getStorageType(dataSource)).getMessage(), is("boom"));
+    void assertGetStorageTypeWithRuntimeException() {
+        DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
+        try (MockedStatic<DatabaseTypeFactory> mocked = 
mockStatic(DatabaseTypeFactory.class)) {
+            mocked.when(() -> 
DatabaseTypeFactory.get(databaseMetaData)).thenThrow(new 
IllegalStateException("boom"));
+            IllegalStateException actual = 
assertThrows(IllegalStateException.class,
+                    () -> 
DatabaseTypeEngine.getStorageType(createDataSource(createConnectionWithMetadata(databaseMetaData))));
+            assertThat(actual.getMessage(), is("boom"));
         }
     }
     
@@ -154,37 +171,6 @@ class DatabaseTypeEngineTest {
                         TypedSPILoader.getService(DatabaseType.class, 
"MySQL")));
     }
     
-    private static Stream<Arguments> getStorageTypeArguments() throws 
SQLException {
-        Connection firstConnection = createConnectionWithUnsupportedUrl();
-        Connection secondConnection = mock(Connection.class);
-        DialectJdbcUrlFetcher fetcher = 
createDialectJdbcUrlFetcher(secondConnection, 
"jdbc:postgresql://localhost:5432/test");
-        return Stream.of(
-                Arguments.of("direct_h2_url", 
createDataSource(createConnectionWithUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL")),
-                        Collections.emptyList(), 
TypedSPILoader.getService(DatabaseType.class, "H2")),
-                Arguments.of("direct_mysql_url", 
createDataSource(createConnectionWithUrl("jdbc:mysql://localhost:3306/test")),
-                        Collections.emptyList(), 
TypedSPILoader.getService(DatabaseType.class, "MySQL")),
-                Arguments.of("dialect_fetcher_postgresql_url", 
createDataSource(firstConnection, secondConnection),
-                        Collections.singleton(fetcher), 
TypedSPILoader.getService(DatabaseType.class, "PostgreSQL")));
-    }
-    
-    private static Stream<Arguments> 
getStorageTypeWithSQLWrapperExceptionArguments() throws SQLException {
-        DialectJdbcUrlFetcher unmatchedFetcher = 
mock(DialectJdbcUrlFetcher.class);
-        DialectJdbcUrlFetcher fetcher = mock(DialectJdbcUrlFetcher.class);
-        Connection fourthConnection = mock(Connection.class);
-        when(unmatchedFetcher.getConnectionClass()).thenAnswer(invocation -> 
Connection.class);
-        when(fetcher.getConnectionClass()).thenAnswer(invocation -> 
Connection.class);
-        when(fourthConnection.isWrapperFor(Connection.class)).thenThrow(new 
SQLException("wrapper error"));
-        return Stream.of(
-                Arguments.of("get_connection_error", 
createDataSourceWithConnectionException(), Collections.emptyList(), 
SQLException.class),
-                
Arguments.of("sql_feature_not_supported_with_unmatched_dialect_fetcher",
-                        createDataSource(createConnectionWithUnsupportedUrl(), 
mock(Connection.class)),
-                        Collections.singleton(unmatchedFetcher), 
SQLFeatureNotSupportedException.class),
-                Arguments.of("sql_feature_not_supported_with_null_connection",
-                        createDataSource(createConnectionWithUnsupportedUrl(), 
null), Collections.emptyList(), SQLFeatureNotSupportedException.class),
-                Arguments.of("sql_feature_not_supported_with_wrapper_error",
-                        createDataSource(createConnectionWithUnsupportedUrl(), 
fourthConnection), Collections.singleton(fetcher), SQLException.class));
-    }
-    
     private static DatabaseConfiguration createDatabaseConfiguration(final 
Map<String, DataSource> dataSources) {
         DatabaseConfiguration result = mock(DatabaseConfiguration.class);
         Map<String, StorageUnit> storageUnits = new 
LinkedHashMap<>(dataSources.size(), 1F);
@@ -201,20 +187,9 @@ class DatabaseTypeEngineTest {
         return new ConfigurationProperties(PropertiesBuilder.build(new 
Property(ConfigurationPropertyKey.PROXY_FRONTEND_DATABASE_PROTOCOL_TYPE.getKey(),
 databaseType)));
     }
     
-    private static DataSource createDataSource(final Connection... 
connections) throws SQLException {
+    private static DataSource createDataSource(final Connection connection) 
throws SQLException {
         DataSource result = mock(DataSource.class);
-        if (1 == connections.length) {
-            when(result.getConnection()).thenReturn(connections[0]);
-            return result;
-        }
-        Connection[] remainingConnections = Arrays.copyOfRange(connections, 1, 
connections.length);
-        when(result.getConnection()).thenReturn(connections[0], 
remainingConnections);
-        return result;
-    }
-    
-    private static DataSource createDataSourceWithConnectionException() throws 
SQLException {
-        DataSource result = mock(DataSource.class);
-        when(result.getConnection()).thenThrow(SQLException.class);
+        when(result.getConnection()).thenReturn(connection);
         return result;
     }
     
@@ -224,17 +199,9 @@ class DatabaseTypeEngineTest {
         return result;
     }
     
-    private static Connection createConnectionWithUnsupportedUrl() throws 
SQLException {
-        Connection result = mock(Connection.class, RETURNS_DEEP_STUBS);
-        
when(result.getMetaData().getURL()).thenThrow(SQLFeatureNotSupportedException.class);
-        return result;
-    }
-    
-    private static DialectJdbcUrlFetcher createDialectJdbcUrlFetcher(final 
Connection connection, final String url) throws SQLException {
-        DialectJdbcUrlFetcher result = mock(DialectJdbcUrlFetcher.class);
-        when(result.getConnectionClass()).thenAnswer(invocation -> 
Connection.class);
-        when(connection.isWrapperFor(Connection.class)).thenReturn(true);
-        when(result.fetch(connection)).thenReturn(url);
+    private static Connection createConnectionWithMetadata(final 
DatabaseMetaData databaseMetaData) throws SQLException {
+        Connection result = mock(Connection.class);
+        when(result.getMetaData()).thenReturn(databaseMetaData);
         return result;
     }
 }
diff --git 
a/kernel/transaction/core/src/main/java/org/apache/shardingsphere/transaction/savepoint/ConnectionSavepointManager.java
 
b/kernel/transaction/core/src/main/java/org/apache/shardingsphere/transaction/savepoint/ConnectionSavepointManager.java
index b705dc80278..1f0cbfc49a8 100644
--- 
a/kernel/transaction/core/src/main/java/org/apache/shardingsphere/transaction/savepoint/ConnectionSavepointManager.java
+++ 
b/kernel/transaction/core/src/main/java/org/apache/shardingsphere/transaction/savepoint/ConnectionSavepointManager.java
@@ -97,7 +97,7 @@ public final class ConnectionSavepointManager {
         if (!result.isPresent()) {
             return;
         }
-        DatabaseType databaseType = 
DatabaseTypeFactory.get(connection.getMetaData().getURL());
+        DatabaseType databaseType = 
DatabaseTypeFactory.get(connection.getMetaData());
         databaseType = 
databaseType.getTrunkDatabaseType().orElse(databaseType);
         Optional<SavepointReleaseSQLProvider> savepointReleaseSQLProvider = 
DatabaseTypedSPILoader.findService(SavepointReleaseSQLProvider.class, 
databaseType);
         if (savepointReleaseSQLProvider.isPresent()) {
diff --git 
a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/fixture/CoreDatabaseTypeFactoryMocker.java
 
b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/fixture/CoreDatabaseTypeFactoryMocker.java
index a856646b4f5..786f9827ed6 100644
--- 
a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/fixture/CoreDatabaseTypeFactoryMocker.java
+++ 
b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/fixture/CoreDatabaseTypeFactoryMocker.java
@@ -25,10 +25,12 @@ import 
org.apache.shardingsphere.mcp.support.database.capability.MCPDatabaseCapa
 import 
org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
 import org.mockito.MockedStatic;
 
+import java.sql.DatabaseMetaData;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.mock;
@@ -49,6 +51,8 @@ public final class CoreDatabaseTypeFactoryMocker {
     public static MockedStatic<DatabaseTypeFactory> mockByConnectionMetadata() 
{
         MockedStatic<DatabaseTypeFactory> result = 
mockStatic(DatabaseTypeFactory.class, CALLS_REAL_METHODS);
         result.when(() -> 
DatabaseTypeFactory.get(anyString())).thenAnswer(invocation -> 
createDatabaseType(invocation.getArgument(0, String.class)));
+        result.when(() -> DatabaseTypeFactory.get(any(DatabaseMetaData.class)))
+                .thenAnswer(invocation -> 
createDatabaseType(invocation.getArgument(0, DatabaseMetaData.class).getURL()));
         return result;
     }
     
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 2a13882a515..fe4183375d4 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
@@ -60,7 +60,7 @@ public final class MCPJdbcDatabaseProfileLoader {
     public RuntimeDatabaseProfile load(final String databaseName, final 
RuntimeDatabaseConfiguration runtimeDatabaseConfig) {
         try (Connection connection = 
runtimeDatabaseConfig.openConnection(databaseName)) {
             DatabaseMetaData databaseMetaData = connection.getMetaData();
-            DatabaseType databaseType = loadDatabaseType(databaseName, 
databaseMetaData.getURL());
+            DatabaseType databaseType = loadDatabaseType(databaseName, 
databaseMetaData);
             String databaseVersion = 
Objects.toString(databaseMetaData.getDatabaseProductVersion(), "").trim();
             return new RuntimeDatabaseProfile(databaseName, 
databaseType.getType(), databaseVersion);
         } catch (final SQLException ex) {
@@ -68,9 +68,9 @@ public final class MCPJdbcDatabaseProfileLoader {
         }
     }
     
-    private DatabaseType loadDatabaseType(final String databaseName, final 
String jdbcUrl) {
+    private DatabaseType loadDatabaseType(final String databaseName, final 
DatabaseMetaData databaseMetaData) throws SQLException {
         try {
-            return DatabaseTypeFactory.get(jdbcUrl);
+            return DatabaseTypeFactory.get(databaseMetaData);
         } catch (final ShardingSphereExternalException ex) {
             throw 
RuntimeDatabaseConnectionException.invalidConfiguration(databaseName, ex);
         }
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 48350aca15e..1e5ca38b83f 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
@@ -30,6 +30,7 @@ import java.sql.SQLException;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
@@ -51,7 +52,7 @@ class MCPJdbcDatabaseProfileLoaderTest {
     void assertLoadWithInvalidJdbcUrl() {
         try (MockedStatic<DatabaseTypeFactory> mocked = 
mockStatic(DatabaseTypeFactory.class)) {
             ShardingSphereExternalException expectedCause = 
mock(ShardingSphereExternalException.class);
-            mocked.when(() -> 
DatabaseTypeFactory.get("jdbc:unknown:test")).thenThrow(expectedCause);
+            mocked.when(() -> 
DatabaseTypeFactory.get(any(DatabaseMetaData.class))).thenThrow(expectedCause);
             RuntimeDatabaseConnectionException actual = 
assertThrows(RuntimeDatabaseConnectionException.class,
                     () -> new MCPJdbcDatabaseProfileLoader().load("logic_db", 
createRuntimeDatabaseConfiguration("jdbc:unknown:test", "8.0.32")));
             assertThat(actual.getCategory(), 
is(RuntimeDatabaseConnectionException.CATEGORY_INVALID_CONFIGURATION));
diff --git 
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/fixture/SupportDatabaseTypeFactoryMocker.java
 
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/fixture/SupportDatabaseTypeFactoryMocker.java
index d2e4cd678ba..c8b4135ef82 100644
--- 
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/fixture/SupportDatabaseTypeFactoryMocker.java
+++ 
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/fixture/SupportDatabaseTypeFactoryMocker.java
@@ -25,10 +25,12 @@ import 
org.apache.shardingsphere.mcp.support.database.capability.MCPDatabaseCapa
 import 
org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
 import org.mockito.MockedStatic;
 
+import java.sql.DatabaseMetaData;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.mock;
@@ -49,6 +51,8 @@ public final class SupportDatabaseTypeFactoryMocker {
     public static MockedStatic<DatabaseTypeFactory> mockByConnectionMetadata() 
{
         MockedStatic<DatabaseTypeFactory> result = 
mockStatic(DatabaseTypeFactory.class, CALLS_REAL_METHODS);
         result.when(() -> 
DatabaseTypeFactory.get(anyString())).thenAnswer(invocation -> 
createDatabaseType(invocation.getArgument(0, String.class)));
+        result.when(() -> DatabaseTypeFactory.get(any(DatabaseMetaData.class)))
+                .thenAnswer(invocation -> 
createDatabaseType(invocation.getArgument(0, DatabaseMetaData.class).getURL()));
         return result;
     }
     


Reply via email to