From a641c25b4074d93a8ace9ed78516a7e551cd528d Mon Sep 17 00:00:00 2001 From: babyfish-ct Date: Tue, 3 Dec 2024 01:43:29 +0800 Subject: [PATCH] #815 --- .../jimmer/spring/JSpringSqlClient.java | 6 +- .../spring/dialect/DialectDetector.java | 115 ++++++++++-------- 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/JSpringSqlClient.java b/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/JSpringSqlClient.java index d743b406a3..7a0c26b942 100644 --- a/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/JSpringSqlClient.java +++ b/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/JSpringSqlClient.java @@ -95,6 +95,7 @@ protected JSqlClient.Builder createBuilder() { DatabaseNamingStrategy databaseNamingStrategy = getOptionalBean(DatabaseNamingStrategy.class); MetaStringResolver metaStringResolver = getOptionalBean(MetaStringResolver.class); Dialect dialect = getOptionalBean(Dialect.class); + DialectDetector dialectDetector = getOptionalBean(DialectDetector.class); Executor executor = getOptionalBean(Executor.class); SqlFormatter sqlFormatter = getOptionalBean(SqlFormatter.class); CacheFactory cacheFactory = getOptionalBean(CacheFactory.class); @@ -205,11 +206,14 @@ protected JSqlClient.Builder createBuilder() { builder.setConnectionManager(connectionManager); if (((JSqlClientImplementor.Builder) builder).getDialect().getClass() == DefaultDialect.class) { + DialectDetector finalDetector = dialectDetector != null ? + dialectDetector : + DialectDetector.INSTANCE; builder.setDialect( optionalFirstNonNullOf( () -> dialect, properties::getDialect, - () -> connectionManager.execute(DialectDetector::detectDialect) + () -> connectionManager.execute(finalDetector::detectDialect) ) ); } diff --git a/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/dialect/DialectDetector.java b/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/dialect/DialectDetector.java index 8abf5196f0..35c0a6a174 100644 --- a/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/dialect/DialectDetector.java +++ b/project/jimmer-spring-boot-starter/src/main/java/org/babyfish/jimmer/spring/dialect/DialectDetector.java @@ -15,60 +15,79 @@ import java.sql.DatabaseMetaData; import java.sql.SQLException; -public class DialectDetector { - - private static final Logger LOGGER = LoggerFactory.getLogger(DialectDetector.class); +/** + * When dialect is not specified explicitly, + * the default instance {@link #INSTANCE} of + * this interface will be used to guess dialect + * by JDBC connection. + * + *

You can define your customized + * `DialectDetector` and register it into + * spring context to override the default + * dialect guessing behavior.

+ */ +public interface DialectDetector { @Nullable - public static Dialect detectDialect(@NotNull Connection con) { - try { - String productName = JdbcUtils.commonDatabaseName( - extractDatabaseMetaData(con, DatabaseMetaData::getDatabaseProductName)); - DatabaseDriver driver = DatabaseDriver.fromProductName(productName); - return getDialectOrNullForDriver(driver); - } catch (MetaDataAccessException e) { - LOGGER.warn("Failed to autodetect jimmer dialect", e); - return null; + Dialect detectDialect(@NotNull Connection con); + + DialectDetector INSTANCE = new Impl(); + + class Impl implements DialectDetector { + + private static final Logger LOGGER = LoggerFactory.getLogger(DialectDetector.class); + + @Nullable + @Override + public Dialect detectDialect(@NotNull Connection con) { + try { + String productName = JdbcUtils.commonDatabaseName( + extractDatabaseMetaData(con, DatabaseMetaData::getDatabaseProductName)); + DatabaseDriver driver = DatabaseDriver.fromProductName(productName); + return getDialectOrNullForDriver(driver); + } catch (MetaDataAccessException e) { + LOGGER.warn("Failed to autodetect jimmer dialect", e); + return null; + } } - } - @Nullable - private static T extractDatabaseMetaData( - @NotNull Connection con, - @NotNull DatabaseMetaDataCallback action - ) throws MetaDataAccessException { - try { - DatabaseMetaData metaData = con.getMetaData(); - if (metaData == null) { - // should only happen in test environments - throw new MetaDataAccessException("DatabaseMetaData returned by Connection [" + con + "] was null"); + private static T extractDatabaseMetaData( + @NotNull Connection con, + @NotNull DatabaseMetaDataCallback action + ) throws MetaDataAccessException { + try { + DatabaseMetaData metaData = con.getMetaData(); + if (metaData == null) { + // should only happen in test environments + throw new MetaDataAccessException("DatabaseMetaData returned by Connection [" + con + "] was null"); + } + return action.processMetaData(metaData); + } catch (CannotGetJdbcConnectionException ex) { + throw new MetaDataAccessException("Could not get Connection for extracting meta-data", ex); + } catch (SQLException ex) { + throw new MetaDataAccessException("Error while extracting DatabaseMetaData", ex); + } catch (AbstractMethodError err) { + throw new MetaDataAccessException( + "JDBC DatabaseMetaData method not implemented by JDBC driver - upgrade your driver", err); } - return action.processMetaData(metaData); - } catch (CannotGetJdbcConnectionException ex) { - throw new MetaDataAccessException("Could not get Connection for extracting meta-data", ex); - } catch (SQLException ex) { - throw new MetaDataAccessException("Error while extracting DatabaseMetaData", ex); - } catch (AbstractMethodError err) { - throw new MetaDataAccessException( - "JDBC DatabaseMetaData method not implemented by JDBC driver - upgrade your driver", err); } - } - @Nullable - private static Dialect getDialectOrNullForDriver(@NotNull DatabaseDriver driver) { - switch (driver) { - case POSTGRESQL: - return new PostgresDialect(); - case ORACLE: - return new OracleDialect(); - case MYSQL: - return new MySqlDialect(); - case SQLSERVER: - return new SqlServerDialect(); - case H2: - return new H2Dialect(); - default: - return null; + @Nullable + private static Dialect getDialectOrNullForDriver(@NotNull DatabaseDriver driver) { + switch (driver) { + case POSTGRESQL: + return new PostgresDialect(); + case ORACLE: + return new OracleDialect(); + case MYSQL: + return new MySqlDialect(); + case SQLSERVER: + return new SqlServerDialect(); + case H2: + return new H2Dialect(); + default: + return null; + } } } -} +} \ No newline at end of file