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.ValueExtractor;
|
||||
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.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
|
@ -24,6 +26,9 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
|
||||
import jakarta.persistence.EnumType;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
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
|
||||
public void addAuxiliaryDatabaseObjects(
|
||||
JavaType<?> javaType,
|
||||
Size columnSize,
|
||||
Database database,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
addAuxiliaryDatabaseObjects( javaType, database, false );
|
||||
}
|
||||
|
||||
private void addAuxiliaryDatabaseObjects(
|
||||
JavaType<?> javaType,
|
||||
Database database,
|
||||
boolean sortEnumValues) {
|
||||
final Dialect dialect = database.getDialect();
|
||||
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 );
|
||||
if ( create != null && create.length>0 ) {
|
||||
if ( create != null && create.length > 0 ) {
|
||||
database.addAuxiliaryDatabaseObject(
|
||||
new NamedAuxiliaryDatabaseObject(
|
||||
enumClass.getSimpleName(),
|
||||
|
|
|
@ -369,7 +369,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
resolution.getRelationalJavaType(),
|
||||
size,
|
||||
getBuildingContext().getMetadataCollector().getDatabase(),
|
||||
getTypeConfiguration()
|
||||
this
|
||||
);
|
||||
|
||||
return resolution;
|
||||
|
|
|
@ -59,6 +59,7 @@ public class EnumType<T extends Enum<T>>
|
|||
|
||||
private Class<T> enumClass;
|
||||
|
||||
private boolean isOrdinal;
|
||||
private JdbcType jdbcType;
|
||||
private EnumJavaType<T> enumJavaType;
|
||||
|
||||
|
@ -131,6 +132,10 @@ public class EnumType<T extends Enum<T>>
|
|||
if ( parameters.containsKey( TYPE ) ) {
|
||||
int jdbcTypeCode = Integer.parseInt( (String) parameters.get( TYPE ) );
|
||||
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 {
|
||||
final LocalJdbcTypeIndicators indicators;
|
||||
|
@ -151,6 +156,7 @@ public class EnumType<T extends Enum<T>>
|
|||
);
|
||||
}
|
||||
jdbcType = descriptor.getRecommendedJdbcType( indicators );
|
||||
isOrdinal = indicators.getEnumeratedType() != STRING;
|
||||
}
|
||||
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
|
@ -295,7 +301,7 @@ public class EnumType<T extends Enum<T>>
|
|||
|
||||
public boolean isOrdinal() {
|
||||
verifyConfigured();
|
||||
return jdbcType.isInteger();
|
||||
return isOrdinal;
|
||||
}
|
||||
|
||||
private class LocalJdbcTypeIndicators implements JdbcTypeIndicators {
|
||||
|
|
|
@ -6,10 +6,34 @@
|
|||
*/
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
Enum<?>[] values = enumClass.getEnumConstants();
|
||||
String[] names = new String[values.length];
|
||||
|
@ -18,4 +42,10 @@ public class EnumHelper {
|
|||
}
|
||||
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 org.hibernate.type.SqlTypes.CHAR;
|
||||
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.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
|
@ -42,12 +43,23 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
|
|||
int sqlType;
|
||||
switch ( type == null ? ORDINAL : type ) {
|
||||
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;
|
||||
case STRING:
|
||||
if ( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) {
|
||||
sqlType = ENUM;
|
||||
}
|
||||
else if ( jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) {
|
||||
sqlType = NAMED_ENUM;
|
||||
}
|
||||
else if ( context.getColumnLength() == 1 ) {
|
||||
sqlType = context.isNationalized() ? NCHAR : CHAR;
|
||||
}
|
||||
|
|
|
@ -357,7 +357,11 @@ public interface JdbcType extends Serializable {
|
|||
callableStatement.registerOutParameter( index, getJdbcTypeCode() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #addAuxiliaryDatabaseObjects(JavaType, Size, Database, JdbcTypeIndicators)} instead
|
||||
*/
|
||||
@Incubating
|
||||
@Deprecated(forRemoval = true)
|
||||
default void addAuxiliaryDatabaseObjects(
|
||||
JavaType<?> javaType,
|
||||
Size columnSize,
|
||||
|
@ -365,6 +369,20 @@ public interface JdbcType extends Serializable {
|
|||
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
|
||||
default String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
||||
return "";
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.type.descriptor.sql.internal;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
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.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.sql.DdlType;
|
||||
|
@ -40,7 +41,10 @@ public class NativeEnumDdlTypeImpl implements DdlType {
|
|||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
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
|
||||
|
|
|
@ -36,6 +36,8 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import static jakarta.persistence.EnumType.STRING;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
|
@ -75,7 +77,10 @@ public class EnumeratedWithMappedSuperclassTest extends BaseUnitTestCase {
|
|||
final Property natureProperty = addressLevelBinding.getProperty( "nature" );
|
||||
//noinspection unchecked
|
||||
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() ) {
|
||||
EntityPersister p = sf.getRuntimeMetamodels()
|
||||
|
@ -83,7 +88,10 @@ public class EnumeratedWithMappedSuperclassTest extends BaseUnitTestCase {
|
|||
.getEntityDescriptor( AddressLevel.class.getName() );
|
||||
//noinspection unchecked
|
||||
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 ) ),
|
||||
Size.nil(),
|
||||
metadata.getDatabase(),
|
||||
typeConfiguration
|
||||
typeConfiguration.getCurrentBaseSqlTypeIndicators()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue