HHH-17884 Introduce special SqlTypes constants for ordinal based enums

This commit is contained in:
Christian Beikov 2024-04-18 18:58:19 +02:00
parent cd577a813b
commit 11d22531bb
21 changed files with 425 additions and 91 deletions

View File

@ -67,6 +67,8 @@ import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -257,6 +259,8 @@ public class CockroachLegacyDialect extends Dialect {
else {
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
}
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -349,6 +353,8 @@ public class CockroachLegacyDialect extends Dialect {
// Don't use this type due to https://github.com/pgjdbc/pgjdbc/issues/2862
//jdbcTypeRegistry.addDescriptor( TimestampUtcAsOffsetDateTimeJdbcType.INSTANCE );
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLUUIDJdbcType.INSTANCE );
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );

View File

@ -69,8 +69,10 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
import org.hibernate.type.descriptor.jdbc.H2FormatJsonJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.OrdinalEnumJdbcType;
import org.hibernate.type.descriptor.jdbc.TimeAsTimestampWithTimeZoneJdbcType;
import org.hibernate.type.descriptor.jdbc.TimeUtcAsJdbcTimeJdbcType;
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
@ -79,6 +81,7 @@ import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -265,6 +268,7 @@ public class H2LegacyDialect extends Dialect {
}
}
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -292,7 +296,8 @@ public class H2LegacyDialect extends Dialect {
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( H2FormatJsonJdbcType.INSTANCE );
}
jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() );
jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( OrdinalEnumJdbcType.INSTANCE );
}
@Override

View File

@ -72,6 +72,8 @@ import org.hibernate.type.descriptor.jdbc.NullJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import jakarta.persistence.TemporalType;
@ -379,6 +381,9 @@ public class MySQLLegacyDialect extends Dialect {
.withTypeCapacity( maxLobLen, "text" )
.build()
);
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NativeOrdinalEnumDdlTypeImpl( this ) );
}
@Deprecated

View File

@ -87,6 +87,8 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -260,6 +262,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
}
}
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -1382,6 +1386,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE );
}
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
if ( getVersion().isSameOrAfter( 8, 2 ) ) {
// HHH-9562 / HHH-14358
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLUUIDJdbcType.INSTANCE );

View File

@ -68,6 +68,8 @@ import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -275,6 +277,9 @@ public class CockroachDialect extends Dialect {
// Prefer jsonb if possible
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( INET, "inet", this ) );
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "jsonb", this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -367,6 +372,8 @@ public class CockroachDialect extends Dialect {
// Don't use this type due to https://github.com/pgjdbc/pgjdbc/issues/2862
//jdbcTypeRegistry.addDescriptor( TimestampUtcAsOffsetDateTimeJdbcType.INSTANCE );
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLUUIDJdbcType.INSTANCE );
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );

View File

@ -65,14 +65,17 @@ import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
import org.hibernate.type.descriptor.jdbc.H2FormatJsonJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.OrdinalEnumJdbcType;
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsInstantJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -227,7 +230,8 @@ public class H2Dialect extends Dialect {
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( GEOMETRY, "geometry", this ) );
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( INTERVAL_SECOND, "interval second($p,$s)", this ) );
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this) );
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -242,7 +246,8 @@ public class H2Dialect extends Dialect {
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptorIfAbsent( H2DurationIntervalSecondJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptorIfAbsent( H2FormatJsonJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() );
jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( OrdinalEnumJdbcType.INSTANCE );
}
@Override

View File

@ -71,12 +71,15 @@ import org.hibernate.type.NullType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
import org.hibernate.type.descriptor.jdbc.OrdinalEnumJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import jakarta.persistence.TemporalType;
@ -423,7 +426,8 @@ public class MySQLDialect extends Dialect {
.build()
);
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl(this) );
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NativeOrdinalEnumDdlTypeImpl( this ) );
}
@Deprecated
@ -694,7 +698,8 @@ public class MySQLDialect extends Dialect {
)
);
jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() );
jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( OrdinalEnumJdbcType.INSTANCE );
}
@Override

View File

@ -6,22 +6,7 @@
*/
package org.hibernate.dialect;
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.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterCharacterData;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import static org.hibernate.type.SqlTypes.ENUM;
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
/**
* Represents an {@code enum} type on MySQL.
@ -31,60 +16,10 @@ import static org.hibernate.type.SqlTypes.ENUM;
*
* @see org.hibernate.type.SqlTypes#ENUM
* @see MySQLDialect#getEnumTypeDeclaration(String, String[])
* @deprecated Use {@link EnumJdbcType} instead
*
* @author Gavin King
*/
public class MySQLEnumJdbcType implements JdbcType {
@Override
public int getJdbcTypeCode() {
return ENUM;
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
return new JdbcLiteralFormatterCharacterData<>( javaType );
}
@Override
public String getFriendlyName() {
return "ENUM";
}
@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 );
}
};
}
@Deprecated(forRemoval = true)
public class MySQLEnumJdbcType extends EnumJdbcType {
}

View File

@ -90,6 +90,7 @@ import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -280,6 +281,7 @@ public class PostgreSQLDialect extends Dialect {
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "jsonb", this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeOrdinalEnumDdlTypeImpl( this ) );
}
@Override
@ -1469,7 +1471,8 @@ public class PostgreSQLDialect extends Dialect {
)
);
jdbcTypeRegistry.addDescriptor( new PostgreSQLEnumJdbcType() );
jdbcTypeRegistry.addDescriptor( PostgreSQLEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( PostgreSQLOrdinalEnumJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( PostgreSQLUUIDJdbcType.INSTANCE );
}

View File

@ -32,6 +32,7 @@ import jakarta.persistence.EnumType;
import static java.util.Collections.emptySet;
import static org.hibernate.type.SqlTypes.NAMED_ENUM;
import static org.hibernate.type.SqlTypes.OTHER;
/**
* Represents a named {@code enum} type on PostgreSQL.
@ -51,8 +52,15 @@ import static org.hibernate.type.SqlTypes.NAMED_ENUM;
*/
public class PostgreSQLEnumJdbcType implements JdbcType {
public static final PostgreSQLEnumJdbcType INSTANCE = new PostgreSQLEnumJdbcType();
@Override
public int getJdbcTypeCode() {
return OTHER;
}
@Override
public int getDefaultSqlTypeCode() {
return NAMED_ENUM;
}
@ -125,7 +133,7 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
Size columnSize,
Database database,
JdbcTypeIndicators context) {
addAuxiliaryDatabaseObjects( javaType, database, context.getEnumeratedType() == EnumType.STRING );
addAuxiliaryDatabaseObjects( javaType, database, true );
}
@Override
@ -134,10 +142,10 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
Size columnSize,
Database database,
TypeConfiguration typeConfiguration) {
addAuxiliaryDatabaseObjects( javaType, database, false );
addAuxiliaryDatabaseObjects( javaType, database, true );
}
private void addAuxiliaryDatabaseObjects(
protected void addAuxiliaryDatabaseObjects(
JavaType<?> javaType,
Database database,
boolean sortEnumValues) {

View File

@ -0,0 +1,59 @@
/*
* 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 org.hibernate.boot.model.relational.Database;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.EnumType;
import static org.hibernate.type.SqlTypes.NAMED_ORDINAL_ENUM;
/**
* Represents a named {@code enum} type on PostgreSQL.
* <p>
* Hibernate does <em>not</em> automatically use this for enums
* mapped as {@link EnumType#ORDINAL}, and
* instead this type must be explicitly requested using:
* <pre>
* &#64;JdbcTypeCode(SqlTypes.NAMED_ORDINAL_ENUM)
* </pre>
*
* @see org.hibernate.type.SqlTypes#NAMED_ORDINAL_ENUM
* @see PostgreSQLDialect#getEnumTypeDeclaration(String, String[])
* @see PostgreSQLDialect#getCreateEnumTypeCommand(String, String[])
*/
public class PostgreSQLOrdinalEnumJdbcType extends PostgreSQLEnumJdbcType {
public static final PostgreSQLOrdinalEnumJdbcType INSTANCE = new PostgreSQLOrdinalEnumJdbcType();
@Override
public int getDefaultSqlTypeCode() {
return NAMED_ORDINAL_ENUM;
}
@Override
public void addAuxiliaryDatabaseObjects(
JavaType<?> javaType,
Size columnSize,
Database database,
JdbcTypeIndicators context) {
addAuxiliaryDatabaseObjects( javaType, database, false );
}
@Override
public void addAuxiliaryDatabaseObjects(
JavaType<?> javaType,
Size columnSize,
Database database,
TypeConfiguration typeConfiguration) {
addAuxiliaryDatabaseObjects( javaType, database, false );
}
}

View File

@ -7,6 +7,8 @@
package org.hibernate.type;
import org.hibernate.Internal;
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
import org.hibernate.type.descriptor.jdbc.OrdinalEnumJdbcType;
import java.sql.Types;
@ -635,7 +637,7 @@ public class SqlTypes {
* {@link org.hibernate.dialect.MySQLDialect MySQL} where {@code ENUM}
* types do not have names.
*
* @see org.hibernate.dialect.MySQLEnumJdbcType
* @see EnumJdbcType
*
* @since 6.3
*/
@ -652,6 +654,28 @@ public class SqlTypes {
*/
public static final int NAMED_ENUM = 6001;
/**
* A type code representing a SQL {@code ENUM} type for databases like
* {@link org.hibernate.dialect.MySQLDialect MySQL} where {@code ENUM}
* types do not have names. Enum values are ordered by ordinal.
*
* @see OrdinalEnumJdbcType
*
* @since 6.5
*/
public static final int ORDINAL_ENUM = 6002;
/**
* A type code representing a SQL {@code ENUM} type for databases like
* {@link org.hibernate.dialect.PostgreSQLDialect PostgreSQL} where
* {@code ENUM} types must have names. Enum values are ordered by ordinal.
*
* @see org.hibernate.dialect.PostgreSQLEnumJdbcType
*
* @since 6.5
*/
public static final int NAMED_ORDINAL_ENUM = 6003;
/**
* A type code representing an {@code embedding vector} type for databases like

View File

@ -9,6 +9,7 @@ package org.hibernate.type.descriptor.converter.internal;
import java.util.Arrays;
import org.hibernate.type.BasicType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -25,11 +26,14 @@ public class EnumHelper {
//noinspection unchecked
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType;
final String[] enumValues;
if ( jdbcType.isString() ) {
enumValues = getSortedEnumeratedValues( enumClass );
}
else {
enumValues = getEnumeratedValues( enumClass );
switch ( jdbcType.getDefaultSqlTypeCode() ) {
case SqlTypes.ENUM:
case SqlTypes.NAMED_ENUM:
enumValues = getSortedEnumeratedValues( enumClass );
break;
default:
enumValues = getEnumeratedValues( enumClass );
break;
}
return enumValues;
}

View File

@ -20,6 +20,8 @@ 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.ORDINAL_ENUM;
import static org.hibernate.type.SqlTypes.NAMED_ORDINAL_ENUM;
import static org.hibernate.type.SqlTypes.NCHAR;
import static org.hibernate.type.SqlTypes.NVARCHAR;
import static org.hibernate.type.SqlTypes.SMALLINT;
@ -44,11 +46,11 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
int sqlType;
switch ( type == null ? ORDINAL : type ) {
case ORDINAL:
if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ) {
sqlType = ENUM;
if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( ORDINAL_ENUM ) ) {
sqlType = ORDINAL_ENUM;
}
else if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ENUM ) ) {
sqlType = NAMED_ENUM;
else if ( preferNativeEnumTypesEnabled && jdbcTypeRegistry.hasRegisteredDescriptor( NAMED_ORDINAL_ENUM ) ) {
sqlType = NAMED_ORDINAL_ENUM;
}
else {
sqlType = hasManyValues() ? SMALLINT : TINYINT;
@ -76,7 +78,7 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
public boolean hasManyValues() {
// a bit arbitrary, but gives us some headroom
return getJavaTypeClass().getEnumConstants().length > 128;
return getJavaTypeClass().getEnumConstants().length > 128;
}
@Override

View File

@ -0,0 +1,95 @@
/*
* 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.type.descriptor.jdbc;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.dialect.MySQLDialect;
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.internal.JdbcLiteralFormatterCharacterData;
import static org.hibernate.type.SqlTypes.ENUM;
import static org.hibernate.type.SqlTypes.VARCHAR;
/**
* Represents an {@code enum} type for databases like MySQL and H2.
* <p>
* Hibernate will automatically use this for enums mapped
* as {@link jakarta.persistence.EnumType#STRING}.
*
* @see org.hibernate.type.SqlTypes#ENUM
* @see MySQLDialect#getEnumTypeDeclaration(String, String[])
*
* @author Gavin King
*/
public class EnumJdbcType implements JdbcType {
public static final EnumJdbcType INSTANCE = new EnumJdbcType();
@Override
public int getJdbcTypeCode() {
return VARCHAR;
}
@Override
public int getDefaultSqlTypeCode() {
return ENUM;
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
return new JdbcLiteralFormatterCharacterData<>( javaType );
}
@Override
public String getFriendlyName() {
return "ENUM";
}
@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

@ -0,0 +1,31 @@
/*
* 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.type.descriptor.jdbc;
import org.hibernate.dialect.MySQLDialect;
import static org.hibernate.type.SqlTypes.ORDINAL_ENUM;
/**
* Represents an {@code enum} type for databases like MySQL and H2.
* <p>
* Hibernate will automatically use this for enums mapped
* as {@link jakarta.persistence.EnumType#ORDINAL}.
*
* @see org.hibernate.type.SqlTypes#ORDINAL_ENUM
* @see MySQLDialect#getEnumTypeDeclaration(String, String[])
*/
public class OrdinalEnumJdbcType extends EnumJdbcType {
public static final OrdinalEnumJdbcType INSTANCE = new OrdinalEnumJdbcType();
@Override
public int getDefaultSqlTypeCode() {
return ORDINAL_ENUM;
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.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.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import static org.hibernate.type.SqlTypes.NAMED_ORDINAL_ENUM;
/**
* A {@link DdlType} representing a named native SQL {@code enum} type,
* one that often <em>cannot</em> be treated as a {@code int}.
*
* @see org.hibernate.type.SqlTypes#NAMED_ORDINAL_ENUM
* @see Dialect#getEnumTypeDeclaration(Class)
*
* @author Gavin King
*/
public class NamedNativeOrdinalEnumDdlTypeImpl implements DdlType {
private final Dialect dialect;
public NamedNativeOrdinalEnumDdlTypeImpl(Dialect dialect) {
this.dialect = dialect;
}
@Override
public int getSqlTypeCode() {
return NAMED_ORDINAL_ENUM;
}
@Override @SuppressWarnings("unchecked")
public String getTypeName(Size columnSize, Type type, DdlTypeRegistry ddlTypeRegistry) {
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) type.getReturnedClass() );
}
@Override
public String getRawTypeName() {
return "enum";
}
@Override
public String getTypeName(Long size, Integer precision, Integer scale) {
throw new UnsupportedOperationException( "native enum type" );
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType) {
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) javaType.getJavaType() );
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType, Long length, Integer precision, Integer scale) {
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) javaType.getJavaType() );
}
}

View File

@ -15,6 +15,8 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.checkerframework.checker.units.qual.N;
import static org.hibernate.type.SqlTypes.ENUM;
/**

View File

@ -0,0 +1,68 @@
/*
* 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.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;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import static org.hibernate.type.SqlTypes.ORDINAL_ENUM;
/**
* A {@link DdlType} representing a SQL {@code enum} type that
* may be treated as {@code int} for most purposes.
*
* @see org.hibernate.type.SqlTypes#ORDINAL_ENUM
* @see Dialect#getEnumTypeDeclaration(Class)
*/
public class NativeOrdinalEnumDdlTypeImpl implements DdlType {
private final Dialect dialect;
public NativeOrdinalEnumDdlTypeImpl(Dialect dialect) {
this.dialect = dialect;
}
@Override
public int getSqlTypeCode() {
return ORDINAL_ENUM;
}
@Override @SuppressWarnings("unchecked")
public String getTypeName(Size columnSize, Type type, DdlTypeRegistry ddlTypeRegistry) {
return dialect.getEnumTypeDeclaration(
type.getReturnedClass().getSimpleName(),
EnumHelper.getEnumeratedValues( type )
);
}
@Override
public String getRawTypeName() {
// this
return "enum";
}
@Override
public String getTypeName(Long size, Integer precision, Integer scale) {
return "int";
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType) {
return "int";
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType, Long length, Integer precision, Integer scale) {
return getTypeName( length, precision, scale );
}
}

View File

@ -67,7 +67,7 @@ public class EnumeratedSmokeTest {
}
else {
// Assertions.assertThat( valueConverter ).isInstanceOf( NamedEnumValueConverter.class );
Assertions.assertThat(jdbcType.isString() || jdbcType.getJdbcTypeCode() == SqlTypes.ENUM).isTrue();
Assertions.assertThat( jdbcType.isString() || jdbcType.getDefaultSqlTypeCode() == SqlTypes.ENUM ).isTrue();
}
}

View File

@ -48,7 +48,7 @@ public class OrmXmlEnumTypeTest extends BaseUnitTestCase {
BasicTypeImpl<?> enumMapping = ExtraAssertions.assertTyping( BasicTypeImpl.class, bindingPropertyType );
assertEquals(
jdbcTypeRegistry.getDescriptor( jdbcTypeRegistry.hasRegisteredDescriptor( ENUM ) ? ENUM : VARCHAR ),
jdbcTypeRegistry.getDescriptor( enumMapping.getJdbcType().getJdbcTypeCode() )
jdbcTypeRegistry.getDescriptor( enumMapping.getJdbcType().getDefaultSqlTypeCode() )
);
}
finally {