HHH-18080 Fix default version handling in dialects when not using JDBC metadata

* Use the minimum supported version instead of '0.0.0'
* Don't warn about version '0.0.0'
This commit is contained in:
Yoann Rodière 2024-05-07 09:19:39 +02:00 committed by Steve Ebersole
parent dc0ca6382f
commit fa35e99543
18 changed files with 122 additions and 32 deletions

View File

@ -66,7 +66,7 @@ public class AltibaseDialect extends Dialect {
} }
public AltibaseDialect(DialectResolutionInfo info) { public AltibaseDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( MINIMUM_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }

View File

@ -42,13 +42,15 @@ public class DB2iLegacyDialect extends DB2LegacyDialect {
final static DatabaseVersion DB2_LUW_VERSION9 = DatabaseVersion.make( 9, 0); final static DatabaseVersion DB2_LUW_VERSION9 = DatabaseVersion.make( 9, 0);
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 7 );
public DB2iLegacyDialect(DialectResolutionInfo info) { public DB2iLegacyDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }
public DB2iLegacyDialect() { public DB2iLegacyDialect() {
this( DatabaseVersion.make(7) ); this( DEFAULT_VERSION );
} }
public DB2iLegacyDialect(DatabaseVersion version) { public DB2iLegacyDialect(DatabaseVersion version) {

View File

@ -50,13 +50,15 @@ public class DB2zLegacyDialect extends DB2LegacyDialect {
final static DatabaseVersion DB2_LUW_VERSION9 = DatabaseVersion.make( 9, 0); final static DatabaseVersion DB2_LUW_VERSION9 = DatabaseVersion.make( 9, 0);
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 7 );
public DB2zLegacyDialect(DialectResolutionInfo info) { public DB2zLegacyDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }
public DB2zLegacyDialect() { public DB2zLegacyDialect() {
this( DatabaseVersion.make( 7 ) ); this( DEFAULT_VERSION );
} }
public DB2zLegacyDialect(DatabaseVersion version) { public DB2zLegacyDialect(DatabaseVersion version) {

View File

@ -36,6 +36,7 @@ import org.hibernate.dialect.BooleanDecoder;
import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport; import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.dialect.SimpleDatabaseVersion;
import org.hibernate.dialect.TimeZoneSupport; import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport;
@ -116,13 +117,15 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
*/ */
public class FirebirdDialect extends Dialect { public class FirebirdDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 2, 5 );
@SuppressWarnings("unused") @SuppressWarnings("unused")
public FirebirdDialect() { public FirebirdDialect() {
this( DatabaseVersion.make( 2, 5 ) ); this( DEFAULT_VERSION );
} }
public FirebirdDialect(DialectResolutionInfo info) { public FirebirdDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }

View File

@ -84,16 +84,18 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
*/ */
public class InformixDialect extends Dialect { public class InformixDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 7, 0 );
private final UniqueDelegate uniqueDelegate; private final UniqueDelegate uniqueDelegate;
private final LimitHandler limitHandler; private final LimitHandler limitHandler;
public InformixDialect(DialectResolutionInfo info) { public InformixDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }
public InformixDialect() { public InformixDialect() {
this( DatabaseVersion.make( 7, 0 ) ); this( DEFAULT_VERSION );
} }
/** /**

View File

@ -100,15 +100,17 @@ import static org.hibernate.type.SqlTypes.VARBINARY;
*/ */
public class IngresDialect extends Dialect { public class IngresDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 9, 2 );
private final LimitHandler limitHandler; private final LimitHandler limitHandler;
private final SequenceSupport sequenceSupport; private final SequenceSupport sequenceSupport;
public IngresDialect() { public IngresDialect() {
this( DatabaseVersion.make( 9, 2 ) ); this( DEFAULT_VERSION );
} }
public IngresDialect(DialectResolutionInfo info) { public IngresDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }

View File

@ -112,6 +112,8 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
*/ */
public class MySQLLegacyDialect extends Dialect { public class MySQLLegacyDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 5, 0 );
private final MySQLStorageEngine storageEngine = createStorageEngine(); private final MySQLStorageEngine storageEngine = createStorageEngine();
private final SizeStrategy sizeStrategy = new SizeStrategyImpl() { private final SizeStrategy sizeStrategy = new SizeStrategyImpl() {
@Override @Override
@ -138,7 +140,7 @@ public class MySQLLegacyDialect extends Dialect {
private final boolean noBackslashEscapesEnabled; private final boolean noBackslashEscapesEnabled;
public MySQLLegacyDialect() { public MySQLLegacyDialect() {
this( DatabaseVersion.make( 5, 0 ) ); this( DEFAULT_VERSION );
} }
public MySQLLegacyDialect(DatabaseVersion version) { public MySQLLegacyDialect(DatabaseVersion version) {
@ -179,7 +181,7 @@ public class MySQLLegacyDialect extends Dialect {
// Ignore // Ignore
} }
} }
return info.makeCopy(); return info.makeCopyOrDefault( DEFAULT_VERSION );
} }
@Override @Override

View File

@ -95,15 +95,17 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
*/ */
public class SQLiteDialect extends Dialect { public class SQLiteDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 2, 0 );
private final UniqueDelegate uniqueDelegate; private final UniqueDelegate uniqueDelegate;
public SQLiteDialect(DialectResolutionInfo info) { public SQLiteDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }
public SQLiteDialect() { public SQLiteDialect() {
this( DatabaseVersion.make( 2, 0 ) ); this( DEFAULT_VERSION );
} }
public SQLiteDialect(DatabaseVersion version) { public SQLiteDialect(DatabaseVersion version) {

View File

@ -75,15 +75,17 @@ import static org.hibernate.type.SqlTypes.VARBINARY;
*/ */
public class TeradataDialect extends Dialect { public class TeradataDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 12, 0 );
private static final int PARAM_LIST_SIZE_LIMIT = 1024; private static final int PARAM_LIST_SIZE_LIMIT = 1024;
public TeradataDialect(DialectResolutionInfo info) { public TeradataDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }
public TeradataDialect() { public TeradataDialect() {
this( DatabaseVersion.make( 12, 0 ) ); this( DEFAULT_VERSION );
} }
public TeradataDialect(DatabaseVersion version) { public TeradataDialect(DatabaseVersion version) {

View File

@ -142,7 +142,7 @@ public class CockroachDialect extends Dialect {
public CockroachDialect(DialectResolutionInfo info, String versionString) { public CockroachDialect(DialectResolutionInfo info, String versionString) {
this( this(
versionString != null ? parseVersion( versionString ) : info.makeCopy(), versionString != null ? parseVersion( versionString ) : info.makeCopyOrDefault( MINIMUM_VERSION ),
PostgreSQLDriverKind.determineKind( info ) PostgreSQLDriverKind.determineKind( info )
); );
registerKeywords( info ); registerKeywords( info );
@ -175,7 +175,7 @@ public class CockroachDialect extends Dialect {
// default to the dialect-specific configuration setting // default to the dialect-specific configuration setting
versionString = ConfigurationHelper.getString( COCKROACH_VERSION_STRING, info.getConfigurationValues() ); versionString = ConfigurationHelper.getString( COCKROACH_VERSION_STRING, info.getConfigurationValues() );
} }
return versionString != null ? parseVersion( versionString ) : info.makeCopy(); return versionString != null ? parseVersion( versionString ) : info.makeCopyOrDefault( MINIMUM_VERSION );
} }
public static DatabaseVersion parseVersion( String versionString ) { public static DatabaseVersion parseVersion( String versionString ) {

View File

@ -42,7 +42,7 @@ public class DB2iDialect extends DB2Dialect {
final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION; final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION;
public DB2iDialect(DialectResolutionInfo info) { public DB2iDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( MINIMUM_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }

View File

@ -49,7 +49,7 @@ public class DB2zDialect extends DB2Dialect {
final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION; final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION;
public DB2zDialect(DialectResolutionInfo info) { public DB2zDialect(DialectResolutionInfo info) {
this( info.makeCopy() ); this( info.makeCopyOrDefault( MINIMUM_VERSION ) );
registerKeywords( info ); registerKeywords( info );
} }

View File

@ -97,8 +97,26 @@ public interface DatabaseVersion {
} }
/** /**
* Make a simple copy of this version object * Make a simple copy of this version object,
* unless this version object has {@link #NO_VERSION no version information},
* in which case just return the given {@code defaultVersion}.
* @param defaultVersion The default version, to be returned if
* this version object has {@link #NO_VERSION no version information}.
* @return The copy, or {@code defaultVersion}.
*/ */
default DatabaseVersion makeCopyOrDefault(DatabaseVersion defaultVersion) {
if ( getMajor() == NO_VERSION && getMinor() == NO_VERSION && getMicro() == NO_VERSION ) {
return defaultVersion;
}
return makeCopy();
}
/**
* Make a simple copy of this version object
* @deprecated In dialect implementations, prefer {@link #makeCopyOrDefault(DatabaseVersion)} to gracefully default
* to the minimum supported version.
*/
@Deprecated
default DatabaseVersion makeCopy() { default DatabaseVersion makeCopy() {
return new SimpleDatabaseVersion( this ); return new SimpleDatabaseVersion( this );
} }
@ -106,7 +124,10 @@ public interface DatabaseVersion {
/** /**
* Make a copy of this version object, possibly converting {@link #NO_VERSION} * Make a copy of this version object, possibly converting {@link #NO_VERSION}
* to zero * to zero
* @deprecated In dialect implementations, prefer {@link #makeCopyOrDefault(DatabaseVersion)} to gracefully default
* to the minimum supported version.
*/ */
@Deprecated
default DatabaseVersion makeCopy(boolean noVersionAsZero) { default DatabaseVersion makeCopy(boolean noVersionAsZero) {
return new SimpleDatabaseVersion( this, noVersionAsZero ); return new SimpleDatabaseVersion( this, noVersionAsZero );
} }

View File

@ -340,7 +340,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
} }
protected Dialect(DialectResolutionInfo info) { protected Dialect(DialectResolutionInfo info) {
this.version = info.makeCopy(); this.version = info.makeCopyOrDefault( getMinimumSupportedVersion() );
checkVersion(); checkVersion();
registerDefaultKeywords(); registerDefaultKeywords();
registerKeywords(info); registerKeywords(info);

View File

@ -204,7 +204,7 @@ public class MySQLDialect extends Dialect {
} }
} }
} }
return info.makeCopy(); return info.makeCopyOrDefault( MINIMUM_VERSION );
} }
@Override @Override

View File

@ -15,6 +15,7 @@ import java.util.StringTokenizer;
import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.cfg.JdbcSettings; import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
@ -163,13 +164,13 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
final DialectResolutionInfo dialectResolutionInfo = new DialectResolutionInfoImpl( final DialectResolutionInfo dialectResolutionInfo = new DialectResolutionInfoImpl(
null, null,
explicitDatabaseName, explicitDatabaseName,
explicitDatabaseVersion != null ? explicitDatabaseVersion : "0", explicitDatabaseVersion,
explicitDatabaseMajorVersion != null ? explicitDatabaseMajorVersion : 0, explicitDatabaseMajorVersion != null ? explicitDatabaseMajorVersion : DatabaseVersion.NO_VERSION,
explicitDatabaseMinorVersion != null ? explicitDatabaseMinorVersion : 0, explicitDatabaseMinorVersion != null ? explicitDatabaseMinorVersion : DatabaseVersion.NO_VERSION,
0, DatabaseVersion.NO_VERSION,
null, null,
0, DatabaseVersion.NO_VERSION,
0, DatabaseVersion.NO_VERSION,
null, null,
configurationValues configurationValues
); );

View File

@ -11,25 +11,47 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.JdbcSettings; import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.OracleDialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.spi.ServiceException; import org.hibernate.service.spi.ServiceException;
import org.hibernate.testing.env.TestingDatabaseInfo; import org.hibernate.testing.env.TestingDatabaseInfo;
import org.hibernate.testing.logger.Triggerable;
import org.hibernate.testing.orm.junit.Jira; import org.hibernate.testing.orm.junit.Jira;
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import org.jboss.logging.Logger;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Jira( "https://hibernate.atlassian.net/browse/HHH-17269" ) @Jira( "https://hibernate.atlassian.net/browse/HHH-17269" )
public class MetadataAccessTests { public class MetadataAccessTests {
private Triggerable triggerable;
@RegisterExtension
public LoggerInspectionExtension logger = LoggerInspectionExtension
.builder().setLogger(
Logger.getMessageLogger( CoreMessageLogger.class, Dialect.class.getName() )
).build();
@BeforeEach
public void setUp() {
triggerable = logger.watchForLogMessages( "HHH000511" );
triggerable.reset();
}
@Test @Test
void testAccessAllowed() { void testAccessAllowed() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder(); final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
@ -70,11 +92,17 @@ public class MetadataAccessTests {
final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class ); final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
final Dialect dialect = jdbcEnvironment.getDialect(); final Dialect dialect = jdbcEnvironment.getDialect();
assertThat( dialect ).isInstanceOf( OracleDialect.class ); assertThat( dialect ).isInstanceOf( OracleDialect.class );
assertThat( dialect.getVersion() ).isEqualTo( getOracleMinimumSupportedVersion() );
} }
assertThat( triggerable.triggerMessages() )
.as( triggerable.toString() )
.isEmpty();
} }
@Test @Test
@Jira("https://hibernate.atlassian.net/browse/HHH-18079") @Jira("https://hibernate.atlassian.net/browse/HHH-18079")
@Jira("https://hibernate.atlassian.net/browse/HHH-18080")
void testAccessDisabledExplicitProductName() { void testAccessDisabledExplicitProductName() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder(); final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
registryBuilder.clearSettings(); registryBuilder.clearSettings();
@ -88,10 +116,16 @@ public class MetadataAccessTests {
final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class ); final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
final Dialect dialect = jdbcEnvironment.getDialect(); final Dialect dialect = jdbcEnvironment.getDialect();
assertThat( dialect ).isInstanceOf( OracleDialect.class ); assertThat( dialect ).isInstanceOf( OracleDialect.class );
assertThat( dialect.getVersion() ).isEqualTo( getOracleMinimumSupportedVersion() );
} }
assertThat( triggerable.triggerMessages() )
.as( triggerable.toString() )
.isEmpty();
} }
@Test @Test
@Jira("https://hibernate.atlassian.net/browse/HHH-18080")
void testAccessDisabledNoDialectNorProductName() { void testAccessDisabledNoDialectNorProductName() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder(); final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
registryBuilder.clearSettings(); registryBuilder.clearSettings();
@ -110,4 +144,18 @@ public class MetadataAccessTests {
assertThat( cause.getMessage() ).startsWith( "Unable to determine Dialect without JDBC metadata" ); assertThat( cause.getMessage() ).startsWith( "Unable to determine Dialect without JDBC metadata" );
} }
} }
// Ugly hack because neither MINIMUM_VERSION nor getMinimumSupportedVersion()
// can be accessed from this test.
private Object getOracleMinimumSupportedVersion() {
return new OracleDialect() {
// Change access from protected to public
@Override
public DatabaseVersion getMinimumSupportedVersion() {
return super.getMinimumSupportedVersion();
}
}
// Call the now-accessible method
.getMinimumSupportedVersion();
}
} }

View File

@ -10,8 +10,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.logging.Logger.Level; import org.jboss.logging.Logger.Level;
@ -29,6 +27,11 @@ public final class TriggerOnPrefixLogListener implements LogListener, Triggerabl
this.expectedPrefixes = expectedPrefixes; this.expectedPrefixes = expectedPrefixes;
} }
@Override
public String toString() {
return getClass().getSimpleName() + "{expectedPrefixes=" + expectedPrefixes + "}";
}
@Override @Override
public void loggedEvent(Level level, String renderedMessage, Throwable thrown) { public void loggedEvent(Level level, String renderedMessage, Throwable thrown) {
if ( renderedMessage != null ) { if ( renderedMessage != null ) {