HHH-17884 Respect ordering guarantee of ORDINAL/STRING when using native enums
This commit is contained in:
parent
7e29539153
commit
95641b2366
|
@ -12,11 +12,13 @@ import org.hibernate.engine.jdbc.Size;
|
||||||
import org.hibernate.type.descriptor.ValueBinder;
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
import org.hibernate.type.descriptor.ValueExtractor;
|
import org.hibernate.type.descriptor.ValueExtractor;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
import org.hibernate.type.descriptor.converter.internal.EnumHelper;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
|
@ -24,6 +26,9 @@ import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import jakarta.persistence.EnumType;
|
||||||
|
|
||||||
import static java.util.Collections.emptySet;
|
import static java.util.Collections.emptySet;
|
||||||
import static org.hibernate.type.SqlTypes.NAMED_ENUM;
|
import static org.hibernate.type.SqlTypes.NAMED_ENUM;
|
||||||
|
@ -114,17 +119,40 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAuxiliaryDatabaseObjects(
|
||||||
|
JavaType<?> javaType,
|
||||||
|
Size columnSize,
|
||||||
|
Database database,
|
||||||
|
JdbcTypeIndicators context) {
|
||||||
|
addAuxiliaryDatabaseObjects( javaType, database, context.getEnumeratedType() == EnumType.STRING );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAuxiliaryDatabaseObjects(
|
public void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
|
addAuxiliaryDatabaseObjects( javaType, database, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAuxiliaryDatabaseObjects(
|
||||||
|
JavaType<?> javaType,
|
||||||
|
Database database,
|
||||||
|
boolean sortEnumValues) {
|
||||||
final Dialect dialect = database.getDialect();
|
final Dialect dialect = database.getDialect();
|
||||||
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
||||||
final String[] create = dialect.getCreateEnumTypeCommand( enumClass );
|
final String[] enumeratedValues = EnumHelper.getEnumeratedValues( enumClass );
|
||||||
|
if ( sortEnumValues ) {
|
||||||
|
Arrays.sort( enumeratedValues );
|
||||||
|
}
|
||||||
|
final String[] create = dialect.getCreateEnumTypeCommand(
|
||||||
|
javaType.getJavaTypeClass().getSimpleName(),
|
||||||
|
enumeratedValues
|
||||||
|
);
|
||||||
final String[] drop = dialect.getDropEnumTypeCommand( enumClass );
|
final String[] drop = dialect.getDropEnumTypeCommand( enumClass );
|
||||||
if ( create != null && create.length>0 ) {
|
if ( create != null && create.length > 0 ) {
|
||||||
database.addAuxiliaryDatabaseObject(
|
database.addAuxiliaryDatabaseObject(
|
||||||
new NamedAuxiliaryDatabaseObject(
|
new NamedAuxiliaryDatabaseObject(
|
||||||
enumClass.getSimpleName(),
|
enumClass.getSimpleName(),
|
||||||
|
|
|
@ -369,7 +369,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
||||||
resolution.getRelationalJavaType(),
|
resolution.getRelationalJavaType(),
|
||||||
size,
|
size,
|
||||||
getBuildingContext().getMetadataCollector().getDatabase(),
|
getBuildingContext().getMetadataCollector().getDatabase(),
|
||||||
getTypeConfiguration()
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
return resolution;
|
return resolution;
|
||||||
|
|
|
@ -59,6 +59,7 @@ public class EnumType<T extends Enum<T>>
|
||||||
|
|
||||||
private Class<T> enumClass;
|
private Class<T> enumClass;
|
||||||
|
|
||||||
|
private boolean isOrdinal;
|
||||||
private JdbcType jdbcType;
|
private JdbcType jdbcType;
|
||||||
private EnumJavaType<T> enumJavaType;
|
private EnumJavaType<T> enumJavaType;
|
||||||
|
|
||||||
|
@ -131,6 +132,10 @@ public class EnumType<T extends Enum<T>>
|
||||||
if ( parameters.containsKey( TYPE ) ) {
|
if ( parameters.containsKey( TYPE ) ) {
|
||||||
int jdbcTypeCode = Integer.parseInt( (String) parameters.get( TYPE ) );
|
int jdbcTypeCode = Integer.parseInt( (String) parameters.get( TYPE ) );
|
||||||
jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCode );
|
jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCode );
|
||||||
|
isOrdinal = jdbcType.isInteger()
|
||||||
|
// Both, ENUM and NAMED_ENUM are treated like ordinal with respect to the ordering
|
||||||
|
|| jdbcType.getDefaultSqlTypeCode() == SqlTypes.ENUM
|
||||||
|
|| jdbcType.getDefaultSqlTypeCode() == SqlTypes.NAMED_ENUM;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final LocalJdbcTypeIndicators indicators;
|
final LocalJdbcTypeIndicators indicators;
|
||||||
|
@ -151,6 +156,7 @@ public class EnumType<T extends Enum<T>>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
jdbcType = descriptor.getRecommendedJdbcType( indicators );
|
jdbcType = descriptor.getRecommendedJdbcType( indicators );
|
||||||
|
isOrdinal = indicators.getEnumeratedType() != STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( LOG.isDebugEnabled() ) {
|
if ( LOG.isDebugEnabled() ) {
|
||||||
|
@ -295,7 +301,7 @@ public class EnumType<T extends Enum<T>>
|
||||||
|
|
||||||
public boolean isOrdinal() {
|
public boolean isOrdinal() {
|
||||||
verifyConfigured();
|
verifyConfigured();
|
||||||
return jdbcType.isInteger();
|
return isOrdinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocalJdbcTypeIndicators implements JdbcTypeIndicators {
|
private class LocalJdbcTypeIndicators implements JdbcTypeIndicators {
|
||||||
|
|
|
@ -6,10 +6,34 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.converter.internal;
|
package org.hibernate.type.descriptor.converter.internal;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class EnumHelper {
|
public class EnumHelper {
|
||||||
|
|
||||||
|
public static String[] getEnumeratedValues(Type type) {
|
||||||
|
return getEnumeratedValues( type.getReturnedClass(), ( (BasicType<?>) type ).getJdbcType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getEnumeratedValues(Class<?> javaType, JdbcType jdbcType) {
|
||||||
|
//noinspection unchecked
|
||||||
|
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType;
|
||||||
|
final String[] enumValues;
|
||||||
|
if ( jdbcType.isString() ) {
|
||||||
|
enumValues = getSortedEnumeratedValues( enumClass );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
enumValues = getEnumeratedValues( enumClass );
|
||||||
|
}
|
||||||
|
return enumValues;
|
||||||
|
}
|
||||||
|
|
||||||
public static String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
public static String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
||||||
Enum<?>[] values = enumClass.getEnumConstants();
|
Enum<?>[] values = enumClass.getEnumConstants();
|
||||||
String[] names = new String[values.length];
|
String[] names = new String[values.length];
|
||||||
|
@ -18,4 +42,10 @@ public class EnumHelper {
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String[] getSortedEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
||||||
|
final String[] names = getEnumeratedValues( enumClass );
|
||||||
|
Arrays.sort( names );
|
||||||
|
return names;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||||
import static jakarta.persistence.EnumType.ORDINAL;
|
import static jakarta.persistence.EnumType.ORDINAL;
|
||||||
import static org.hibernate.type.SqlTypes.CHAR;
|
import static org.hibernate.type.SqlTypes.CHAR;
|
||||||
import static org.hibernate.type.SqlTypes.ENUM;
|
import static org.hibernate.type.SqlTypes.ENUM;
|
||||||
|
import static org.hibernate.type.SqlTypes.NAMED_ENUM;
|
||||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||||
|
@ -42,12 +43,23 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
|
||||||
int sqlType;
|
int sqlType;
|
||||||
switch ( type == null ? ORDINAL : type ) {
|
switch ( type == null ? ORDINAL : type ) {
|
||||||
case ORDINAL:
|
case ORDINAL:
|
||||||
sqlType = hasManyValues() ? SMALLINT : TINYINT;
|
if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) {
|
||||||
|
sqlType = ENUM;
|
||||||
|
}
|
||||||
|
else if ( jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) {
|
||||||
|
sqlType = NAMED_ENUM;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sqlType = hasManyValues() ? SMALLINT : TINYINT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) {
|
if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) {
|
||||||
sqlType = ENUM;
|
sqlType = ENUM;
|
||||||
}
|
}
|
||||||
|
else if ( jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) {
|
||||||
|
sqlType = NAMED_ENUM;
|
||||||
|
}
|
||||||
else if ( context.getColumnLength() == 1 ) {
|
else if ( context.getColumnLength() == 1 ) {
|
||||||
sqlType = context.isNationalized() ? NCHAR : CHAR;
|
sqlType = context.isNationalized() ? NCHAR : CHAR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,7 +357,11 @@ public interface JdbcType extends Serializable {
|
||||||
callableStatement.registerOutParameter( index, getJdbcTypeCode() );
|
callableStatement.registerOutParameter( index, getJdbcTypeCode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #addAuxiliaryDatabaseObjects(JavaType, Size, Database, JdbcTypeIndicators)} instead
|
||||||
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
default void addAuxiliaryDatabaseObjects(
|
default void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
|
@ -365,6 +369,20 @@ public interface JdbcType extends Serializable {
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add auxiliary database objects for this {@linkplain JdbcType} to the {@link Database} object.
|
||||||
|
*
|
||||||
|
* @since 6.5
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
default void addAuxiliaryDatabaseObjects(
|
||||||
|
JavaType<?> javaType,
|
||||||
|
Size columnSize,
|
||||||
|
Database database,
|
||||||
|
JdbcTypeIndicators context) {
|
||||||
|
addAuxiliaryDatabaseObjects( javaType, columnSize, database, context.getTypeConfiguration() );
|
||||||
|
}
|
||||||
|
|
||||||
@Incubating
|
@Incubating
|
||||||
default String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
default String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.type.descriptor.sql.internal;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.descriptor.converter.internal.EnumHelper;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
import org.hibernate.type.descriptor.sql.DdlType;
|
import org.hibernate.type.descriptor.sql.DdlType;
|
||||||
|
@ -40,7 +41,10 @@ public class NativeEnumDdlTypeImpl implements DdlType {
|
||||||
|
|
||||||
@Override @SuppressWarnings("unchecked")
|
@Override @SuppressWarnings("unchecked")
|
||||||
public String getTypeName(Size columnSize, Type type, DdlTypeRegistry ddlTypeRegistry) {
|
public String getTypeName(Size columnSize, Type type, DdlTypeRegistry ddlTypeRegistry) {
|
||||||
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) type.getReturnedClass() );
|
return dialect.getEnumTypeDeclaration(
|
||||||
|
type.getReturnedClass().getSimpleName(),
|
||||||
|
EnumHelper.getEnumeratedValues( type )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,6 +36,8 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static jakarta.persistence.EnumType.STRING;
|
import static jakarta.persistence.EnumType.STRING;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.isOneOf;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +77,10 @@ public class EnumeratedWithMappedSuperclassTest extends BaseUnitTestCase {
|
||||||
final Property natureProperty = addressLevelBinding.getProperty( "nature" );
|
final Property natureProperty = addressLevelBinding.getProperty( "nature" );
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
BasicType<Nature> natureMapping = (BasicType<Nature>) natureProperty.getType();
|
BasicType<Nature> natureMapping = (BasicType<Nature>) natureProperty.getType();
|
||||||
assertEquals( SqlTypes.VARCHAR, natureMapping.getJdbcType().getJdbcTypeCode() );
|
assertThat(
|
||||||
|
natureMapping.getJdbcType().getJdbcTypeCode(),
|
||||||
|
isOneOf( SqlTypes.VARCHAR, SqlTypes.ENUM, SqlTypes.NAMED_ENUM )
|
||||||
|
);
|
||||||
|
|
||||||
try ( SessionFactoryImplementor sf = (SessionFactoryImplementor) metadata.buildSessionFactory() ) {
|
try ( SessionFactoryImplementor sf = (SessionFactoryImplementor) metadata.buildSessionFactory() ) {
|
||||||
EntityPersister p = sf.getRuntimeMetamodels()
|
EntityPersister p = sf.getRuntimeMetamodels()
|
||||||
|
@ -83,7 +88,10 @@ public class EnumeratedWithMappedSuperclassTest extends BaseUnitTestCase {
|
||||||
.getEntityDescriptor( AddressLevel.class.getName() );
|
.getEntityDescriptor( AddressLevel.class.getName() );
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
BasicType<Nature> runtimeType = (BasicType<Nature>) p.getPropertyType( "nature" );
|
BasicType<Nature> runtimeType = (BasicType<Nature>) p.getPropertyType( "nature" );
|
||||||
assertEquals( SqlTypes.VARCHAR, runtimeType.getJdbcType().getJdbcTypeCode() );
|
assertThat(
|
||||||
|
runtimeType.getJdbcType().getJdbcTypeCode(),
|
||||||
|
isOneOf( SqlTypes.VARCHAR, SqlTypes.ENUM, SqlTypes.NAMED_ENUM )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class ArrayAggregateTest {
|
||||||
new ArrayJavaType<>( javaTypeRegistry.getDescriptor( String.class ) ),
|
new ArrayJavaType<>( javaTypeRegistry.getDescriptor( String.class ) ),
|
||||||
Size.nil(),
|
Size.nil(),
|
||||||
metadata.getDatabase(),
|
metadata.getDatabase(),
|
||||||
typeConfiguration
|
typeConfiguration.getCurrentBaseSqlTypeIndicators()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue