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 73edbac469
commit 32d4f1596e
18 changed files with 122 additions and 32 deletions

View File

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

View File

@ -42,13 +42,15 @@ public class DB2iLegacyDialect extends DB2LegacyDialect {
final static DatabaseVersion DB2_LUW_VERSION9 = DatabaseVersion.make( 9, 0);
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 7 );
public DB2iLegacyDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info );
}
public DB2iLegacyDialect() {
this( DatabaseVersion.make(7) );
this( DEFAULT_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);
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 7 );
public DB2zLegacyDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info );
}
public DB2zLegacyDialect() {
this( DatabaseVersion.make( 7 ) );
this( DEFAULT_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.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.dialect.SimpleDatabaseVersion;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
@ -116,13 +117,15 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
*/
public class FirebirdDialect extends Dialect {
private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 2, 5 );
@SuppressWarnings("unused")
public FirebirdDialect() {
this( DatabaseVersion.make( 2, 5 ) );
this( DEFAULT_VERSION );
}
public FirebirdDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
registerKeywords( info );
}

View File

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

View File

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

View File

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

View File

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

View File

@ -144,7 +144,7 @@ public class CockroachDialect extends Dialect {
public CockroachDialect(DialectResolutionInfo info, String versionString) {
this(
versionString != null ? parseVersion( versionString ) : info.makeCopy(),
versionString != null ? parseVersion( versionString ) : info.makeCopyOrDefault( MINIMUM_VERSION ),
PostgreSQLDriverKind.determineKind( info )
);
registerKeywords( info );
@ -177,7 +177,7 @@ public class CockroachDialect extends Dialect {
// default to the dialect-specific configuration setting
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 ) {

View File

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

View File

@ -49,7 +49,7 @@ public class DB2zDialect extends DB2Dialect {
final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION;
public DB2zDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
this( info.makeCopyOrDefault( MINIMUM_VERSION ) );
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() {
return new SimpleDatabaseVersion( this );
}
@ -106,7 +124,10 @@ public interface DatabaseVersion {
/**
* Make a copy of this version object, possibly converting {@link #NO_VERSION}
* to zero
* @deprecated In dialect implementations, prefer {@link #makeCopyOrDefault(DatabaseVersion)} to gracefully default
* to the minimum supported version.
*/
@Deprecated
default DatabaseVersion makeCopy(boolean noVersionAsZero) {
return new SimpleDatabaseVersion( this, noVersionAsZero );
}

View File

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

View File

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

View File

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

View File

@ -11,25 +11,47 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.spi.ServiceException;
import org.hibernate.testing.env.TestingDatabaseInfo;
import org.hibernate.testing.logger.Triggerable;
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.extension.RegisterExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
@Jira( "https://hibernate.atlassian.net/browse/HHH-17269" )
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
void testAccessAllowed() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
@ -70,11 +92,17 @@ public class MetadataAccessTests {
final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
final Dialect dialect = jdbcEnvironment.getDialect();
assertThat( dialect ).isInstanceOf( OracleDialect.class );
assertThat( dialect.getVersion() ).isEqualTo( getOracleMinimumSupportedVersion() );
}
assertThat( triggerable.triggerMessages() )
.as( triggerable.toString() )
.isEmpty();
}
@Test
@Jira("https://hibernate.atlassian.net/browse/HHH-18079")
@Jira("https://hibernate.atlassian.net/browse/HHH-18080")
void testAccessDisabledExplicitProductName() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
registryBuilder.clearSettings();
@ -88,10 +116,16 @@ public class MetadataAccessTests {
final JdbcEnvironment jdbcEnvironment = registry.getService( JdbcEnvironment.class );
final Dialect dialect = jdbcEnvironment.getDialect();
assertThat( dialect ).isInstanceOf( OracleDialect.class );
assertThat( dialect.getVersion() ).isEqualTo( getOracleMinimumSupportedVersion() );
}
assertThat( triggerable.triggerMessages() )
.as( triggerable.toString() )
.isEmpty();
}
@Test
@Jira("https://hibernate.atlassian.net/browse/HHH-18080")
void testAccessDisabledNoDialectNorProductName() {
final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
registryBuilder.clearSettings();
@ -110,4 +144,18 @@ public class MetadataAccessTests {
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.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.logging.Logger.Level;
@ -29,6 +27,11 @@ public final class TriggerOnPrefixLogListener implements LogListener, Triggerabl
this.expectedPrefixes = expectedPrefixes;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{expectedPrefixes=" + expectedPrefixes + "}";
}
@Override
public void loggedEvent(Level level, String renderedMessage, Throwable thrown) {
if ( renderedMessage != null ) {