HHH-15503 Add UUID support for MariaDB 10.7

This commit is contained in:
Christian Beikov 2022-09-13 20:01:24 +02:00
parent 56125e2614
commit 69668c32b7
6 changed files with 164 additions and 5 deletions

4
Jenkinsfile vendored
View File

@ -125,7 +125,7 @@ stage('Build') {
break;
case "mariadb":
docker.withRegistry('https://index.docker.io/v1/', 'hibernateci.hub.docker.com') {
docker.image('mariadb:10.5.8').pull()
docker.image('mariadb:10.7.5').pull()
}
sh "./docker_db.sh mariadb"
state[buildEnv.tag]['containerName'] = "mariadb"
@ -148,7 +148,7 @@ stage('Build') {
break;
case "oracle":
docker.withRegistry('https://index.docker.io/v1/', 'hibernateci.hub.docker.com') {
docker.image('quillbuilduser/oracle-18-xe').pull()
docker.image('gvenzl/oracle-xe:18.4.0-full').pull()
}
sh "./docker_db.sh oracle_18"
state[buildEnv.tag]['containerName'] = "oracle"

View File

@ -65,7 +65,7 @@ mysql_8_0() {
mariadb() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d docker.io/mariadb:10.5.8 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake
$CONTAINER_CLI run --name mariadb -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d docker.io/mariadb:10.7.5 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake
OUTPUT=
n=0
until [ "$n" -ge 5 ]

View File

@ -9,6 +9,7 @@ package org.hibernate.dialect;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.sequence.MariaDBSequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
@ -18,6 +19,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
@ -26,6 +28,13 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMariaDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import static org.hibernate.type.SqlTypes.OTHER;
import static org.hibernate.type.SqlTypes.UUID;
/**
* A {@linkplain Dialect SQL dialect} for MariaDB
@ -80,6 +89,44 @@ public class MariaDBDialect extends MySQLDialect {
commonFunctionFactory.inverseDistributionOrderedSetAggregates_windowEmulation();
}
@Override
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.registerColumnTypes( typeContributions, serviceRegistry );
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
if ( getVersion().isSameOrAfter( 10, 7 ) ) {
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( UUID, "uuid", this ) );
}
}
@Override
public JdbcType resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
switch ( jdbcTypeCode ) {
case OTHER:
switch ( columnTypeName ) {
case "uuid":
jdbcTypeCode = UUID;
break;
}
break;
}
return super.resolveSqlTypeDescriptor( columnTypeName, jdbcTypeCode, precision, scale, jdbcTypeRegistry );
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
.getJdbcTypeRegistry();
if ( getVersion().isSameOrAfter( 10, 7 ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( VarcharUUIDJdbcType.INSTANCE );
}
}
@Override
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
return new StandardSqlAstTranslatorFactory() {

View File

@ -0,0 +1,91 @@
/*
* 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.dialect;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.BasicBinder;
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
/**
* Specialized type mapping for {@link UUID} and the UUID SQL data type,
* which binds and reads the UUID through JDBC <code>getString</code>/<code>setString</code> methods.
*
*/
public class VarcharUUIDJdbcType implements JdbcType {
/**
* Singleton access
*/
public static final VarcharUUIDJdbcType INSTANCE = new VarcharUUIDJdbcType();
@Override
public int getJdbcTypeCode() {
return SqlTypes.VARCHAR;
}
@Override
public int getDefaultSqlTypeCode() {
return SqlTypes.UUID;
}
@Override
public String toString() {
return "MariaDBUUIDJdbcType";
}
@Override
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
return UUID.class;
}
@Override
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
return new BasicBinder<>( javaType, this ) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setString( index, getJavaType().unwrap( value, String.class, options ) );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setString( name, getJavaType().unwrap( value, String.class, options ) );
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
return new BasicExtractor<>( javaType, this ) {
@Override
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return getJavaType().wrap( rs.getString( paramIndex ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return getJavaType().wrap( statement.getString( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return getJavaType().wrap( statement.getString( name ), options );
}
};
}
}

View File

@ -13,8 +13,10 @@ import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.VarcharUUIDJdbcType;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.UUIDJavaType;
@ -50,11 +52,18 @@ public class UUIDBasedIdInterpretationTest {
@Test
@JiraKey( "HHH-10564" )
@RequiresDialect( value = MySQLDialect.class, majorVersion = 5 )
@RequiresDialect(value = MySQLDialect.class, matchSubTypes = false)
public void testMySQL(DomainModelScope scope) {
checkUuidTypeUsed( scope, VarbinaryJdbcType.class );
}
@Test
@JiraKey( "HHH-10564" )
@RequiresDialect(value = MariaDBDialect.class, majorVersion = 10, minorVersion = 7)
public void testMariaDB(DomainModelScope scope) {
checkUuidTypeUsed( scope, VarcharUUIDJdbcType.class );
}
@Test
@JiraKey( "HHH-10564" )
@RequiresDialect( value = PostgreSQLDialect.class, majorVersion = 9, minorVersion = 4 )

View File

@ -9,4 +9,16 @@
This guide discusses migration from Hibernate ORM version 6.2. For migration from
earlier versions, see any other pertinent migration guides as well.
* link:../../../6.0/migration-guide/migration-guide.html[6.2 Migration guide]
* link:../../../6.1/migration-guide/migration-guide.html[6.1 Migration guide]
* link:../../../6.0/migration-guide/migration-guide.html[6.0 Migration guide]
== Default DDL type changes
=== UUID mapping changes on MariaDB
On MariaDB, the type code `SqlType.UUID` now by default refers to the DDL type `uuid`, whereas before it was using `binary(16)`.
Due to this change, schema validation errors could occur on existing databases.
The migration to `uuid` requires a migration expression like `cast(old as uuid)`.
To retain backwards compatibility, configure the setting `hibernate.type.preferred_uuid_jdbc_type` to `BINARY`.