HHH-15511 - fix version determination for CockroachDB
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
e62a376262
commit
1d76f970e8
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.dialect;
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
import java.sql.DatabaseMetaData;
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
@ -14,6 +15,8 @@ import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import jakarta.persistence.TemporalType;
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
|
@ -34,6 +37,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
|
@ -63,6 +67,8 @@ import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||||
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
|
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
|
||||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import static org.hibernate.query.sqm.TemporalUnit.DAY;
|
import static org.hibernate.query.sqm.TemporalUnit.DAY;
|
||||||
import static org.hibernate.query.sqm.TemporalUnit.NATIVE;
|
import static org.hibernate.query.sqm.TemporalUnit.NATIVE;
|
||||||
import static org.hibernate.type.SqlTypes.BINARY;
|
import static org.hibernate.type.SqlTypes.BINARY;
|
||||||
|
@ -97,10 +103,14 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
|
||||||
*/
|
*/
|
||||||
public class CockroachDialect extends Dialect {
|
public class CockroachDialect extends Dialect {
|
||||||
|
|
||||||
|
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, CockroachDialect.class.getName() );
|
||||||
private static final CockroachDBIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new CockroachDBIdentityColumnSupport();
|
private static final CockroachDBIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new CockroachDBIdentityColumnSupport();
|
||||||
// KNOWN LIMITATIONS:
|
// KNOWN LIMITATIONS:
|
||||||
// * no support for java.sql.Clob
|
// * no support for java.sql.Clob
|
||||||
|
|
||||||
|
// Pre-compile and reuse pattern
|
||||||
|
private static final Pattern CRDB_VERSION_PATTERN = Pattern.compile( "v[\\d]+(\\.[\\d]+)?(\\.[\\d]+)?" );
|
||||||
|
|
||||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 21, 1 );
|
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 21, 1 );
|
||||||
|
|
||||||
private final PostgreSQLDriverKind driverKind;
|
private final PostgreSQLDriverKind driverKind;
|
||||||
|
@ -110,8 +120,8 @@ public class CockroachDialect extends Dialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CockroachDialect(DialectResolutionInfo info) {
|
public CockroachDialect(DialectResolutionInfo info) {
|
||||||
super(info);
|
this( fetchDataBaseVersion( info ), PostgreSQLDriverKind.determineKind( info ) );
|
||||||
driverKind = PostgreSQLDriverKind.determineKind( info );
|
registerKeywords( info );
|
||||||
}
|
}
|
||||||
|
|
||||||
public CockroachDialect(DatabaseVersion version) {
|
public CockroachDialect(DatabaseVersion version) {
|
||||||
|
@ -124,6 +134,46 @@ public class CockroachDialect extends Dialect {
|
||||||
this.driverKind = driverKind;
|
this.driverKind = driverKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static DatabaseVersion fetchDataBaseVersion( DialectResolutionInfo info ) {
|
||||||
|
String versionString = null;
|
||||||
|
if ( info.getDatabaseMetadata() != null ) {
|
||||||
|
try (java.sql.Statement s = info.getDatabaseMetadata().getConnection().createStatement() ) {
|
||||||
|
final ResultSet rs = s.executeQuery( "SELECT version()" );
|
||||||
|
if ( rs.next() ) {
|
||||||
|
versionString = rs.getString( 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parseVersion( versionString );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static DatabaseVersion parseVersion(String versionString ) {
|
||||||
|
DatabaseVersion databaseVersion = null;
|
||||||
|
// What the DB select returns is similar to "CockroachDB CCL v21.2.10 (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)"
|
||||||
|
Matcher m = CRDB_VERSION_PATTERN.matcher( versionString == null ? "" : versionString );
|
||||||
|
if ( m.find() ) {
|
||||||
|
String[] versionParts = m.group().substring( 1 ).split( "\\." );
|
||||||
|
// if we got to this point, there is at least a major version, so no need to check [].length > 0
|
||||||
|
int majorVersion = Integer.parseInt( versionParts[0] );
|
||||||
|
int minorVersion = versionParts.length > 1 ? Integer.parseInt( versionParts[1] ) : 0;
|
||||||
|
int microVersion = versionParts.length > 2 ? Integer.parseInt( versionParts[2] ) : 0;
|
||||||
|
|
||||||
|
databaseVersion= new SimpleDatabaseVersion( majorVersion, minorVersion, microVersion);
|
||||||
|
}
|
||||||
|
if ( databaseVersion == null ) {
|
||||||
|
LOG.unableToDetermineCockroachDatabaseVersion(
|
||||||
|
MINIMUM_VERSION.getDatabaseMajorVersion() + "." +
|
||||||
|
MINIMUM_VERSION.getDatabaseMinorVersion() + "." +
|
||||||
|
MINIMUM_VERSION.getDatabaseMicroVersion()
|
||||||
|
);
|
||||||
|
databaseVersion = MINIMUM_VERSION;
|
||||||
|
}
|
||||||
|
return databaseVersion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DatabaseVersion getMinimumSupportedVersion() {
|
protected DatabaseVersion getMinimumSupportedVersion() {
|
||||||
return MINIMUM_VERSION;
|
return MINIMUM_VERSION;
|
||||||
|
|
|
@ -1794,4 +1794,8 @@ public interface CoreMessageLogger extends BasicLogger {
|
||||||
@Message(value = "The %2$s version for [%s] is no longer supported, hence certain features may not work properly. The minimum supported version is %3$s. Check the community dialects project for available legacy versions.", id = 511)
|
@Message(value = "The %2$s version for [%s] is no longer supported, hence certain features may not work properly. The minimum supported version is %3$s. Check the community dialects project for available legacy versions.", id = 511)
|
||||||
void unsupportedDatabaseVersion(String databaseName, String actualVersion, String minimumVersion);
|
void unsupportedDatabaseVersion(String databaseName, String actualVersion, String minimumVersion);
|
||||||
|
|
||||||
|
@LogMessage(level = WARN)
|
||||||
|
@Message(value = "The database version version for the Cockroach Dialect could not be determined. The minimum supported version (%s) has been set instead.", id = 512)
|
||||||
|
void unableToDetermineCockroachDatabaseVersion(String minimumVersion);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.dialect.unit;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.CockroachDialect;
|
||||||
|
import org.hibernate.dialect.DatabaseVersion;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.logger.Triggerable;
|
||||||
|
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jan Schatteman
|
||||||
|
*/
|
||||||
|
public class CockroachDialectVersionTest {
|
||||||
|
|
||||||
|
private Triggerable triggerable;
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public LoggerInspectionExtension logger = LoggerInspectionExtension
|
||||||
|
.builder().setLogger(
|
||||||
|
Logger.getMessageLogger( CoreMessageLogger.class, CockroachDialect.class.getName() )
|
||||||
|
).build();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
triggerable = logger.watchForLogMessages("HHH000512" );
|
||||||
|
triggerable.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-15511")
|
||||||
|
public void testCockroachDialectVersionParsing() {
|
||||||
|
String failMsg = "HHH000511: The database version version for the Cockroach Dialect could not be determined ... should have been logged";
|
||||||
|
|
||||||
|
CockroachDBTestDialect testDialect = new CockroachDBTestDialect( null );
|
||||||
|
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
|
||||||
|
DatabaseVersion dv = testDialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() );
|
||||||
|
triggerable.reset();
|
||||||
|
|
||||||
|
testDialect = new CockroachDBTestDialect( "" );
|
||||||
|
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
|
||||||
|
dv = testDialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() );
|
||||||
|
triggerable.reset();
|
||||||
|
|
||||||
|
testDialect = new CockroachDBTestDialect( "Some version lacking string" );
|
||||||
|
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
|
||||||
|
dv = testDialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() );
|
||||||
|
assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() );
|
||||||
|
triggerable.reset();
|
||||||
|
|
||||||
|
// using a fictitious major version, to avoid minimum version warnings
|
||||||
|
Dialect dialect = new CockroachDBTestDialect( "CockroachDB CCL v99.2.10 (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)" );
|
||||||
|
|
||||||
|
dv = dialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( 99, dv.getMajor() );
|
||||||
|
assertEquals( 2, dv.getMinor() );
|
||||||
|
assertEquals( 10, dv.getMicro() );
|
||||||
|
|
||||||
|
dialect = new CockroachDBTestDialect("CockroachDB CCL v99.2. (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)");
|
||||||
|
dv = dialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( 99, dv.getMajor() );
|
||||||
|
assertEquals( 2, dv.getMinor() );
|
||||||
|
assertEquals( 0, dv.getMicro() );
|
||||||
|
|
||||||
|
dialect = new CockroachDBTestDialect("CockroachDB CCL v99.2 (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)");
|
||||||
|
dv = dialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( 99, dv.getMajor() );
|
||||||
|
assertEquals( 2, dv.getMinor() );
|
||||||
|
assertEquals( 0, dv.getMicro() );
|
||||||
|
|
||||||
|
dialect = new CockroachDBTestDialect("CockroachDB CCL v99. (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)");
|
||||||
|
dv = dialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( 99, dv.getMajor() );
|
||||||
|
assertEquals( 0, dv.getMinor() );
|
||||||
|
assertEquals( 0, dv.getMicro() );
|
||||||
|
|
||||||
|
dialect = new CockroachDBTestDialect("CockroachDB CCL v99 (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)");
|
||||||
|
dv = dialect.getVersion();
|
||||||
|
assertNotNull( dv );
|
||||||
|
assertEquals( 99, dv.getMajor() );
|
||||||
|
assertEquals( 0, dv.getMinor() );
|
||||||
|
assertEquals( 0, dv.getMicro() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CockroachDBTestDialect extends CockroachDialect {
|
||||||
|
private CockroachDBTestDialect(String versionString) {
|
||||||
|
super (parseVersion( versionString ));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatabaseVersion getMinimumVersion() {
|
||||||
|
return getMinimumSupportedVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue