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