HHH-18512 @EnumeratedValue and PostgreSQL named enum types
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
5dcbdf64f1
commit
64a98417e2
|
@ -7,18 +7,14 @@
|
||||||
package org.hibernate.boot.model.process.internal;
|
package org.hibernate.boot.model.process.internal;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.boot.spi.BootstrapContext;
|
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
|
||||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ 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.converter.spi.BasicValueConverter;
|
||||||
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;
|
||||||
|
@ -30,6 +30,7 @@ import java.util.Arrays;
|
||||||
|
|
||||||
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;
|
||||||
|
import static org.hibernate.type.descriptor.converter.internal.EnumHelper.getEnumeratedValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a named {@code enum} type on Oracle 23ai+.
|
* Represents a named {@code enum} type on Oracle 23ai+.
|
||||||
|
@ -92,13 +93,13 @@ public class OracleEnumJdbcType implements JdbcType {
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
st.setString( index, ((Enum<?>) value).name() );
|
st.setString( index, getJavaType().unwrap( value, String.class, options ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
st.setString( name, ((Enum<?>) value).name() );
|
st.setString( name, getJavaType().unwrap( value, String.class, options ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -126,10 +127,11 @@ public class OracleEnumJdbcType implements JdbcType {
|
||||||
@Override
|
@Override
|
||||||
public void addAuxiliaryDatabaseObjects(
|
public void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
JdbcTypeIndicators context) {
|
JdbcTypeIndicators context) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, true );
|
addAuxiliaryDatabaseObjects( javaType, valueConverter, database, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -138,20 +140,26 @@ public class OracleEnumJdbcType implements JdbcType {
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, true );
|
addAuxiliaryDatabaseObjects( javaType, null, database, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAuxiliaryDatabaseObjects(
|
private void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Database database,
|
Database database,
|
||||||
boolean sortEnumValues) {
|
boolean sortEnumValues) {
|
||||||
final Dialect dialect = database.getDialect();
|
@SuppressWarnings("unchecked")
|
||||||
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
||||||
final String enumTypeName = enumClass.getSimpleName();
|
final String enumTypeName = enumClass.getSimpleName();
|
||||||
final String[] enumeratedValues = EnumHelper.getEnumeratedValues( enumClass );
|
@SuppressWarnings("unchecked")
|
||||||
|
final String[] enumeratedValues =
|
||||||
|
valueConverter == null
|
||||||
|
? getEnumeratedValues( enumClass )
|
||||||
|
: getEnumeratedValues( enumClass, (BasicValueConverter<Enum<?>,?>) valueConverter ) ;
|
||||||
if ( sortEnumValues ) {
|
if ( sortEnumValues ) {
|
||||||
Arrays.sort( enumeratedValues );
|
Arrays.sort( enumeratedValues );
|
||||||
}
|
}
|
||||||
|
final Dialect dialect = database.getDialect();
|
||||||
final String[] create = getCreateEnumTypeCommand(
|
final String[] create = getCreateEnumTypeCommand(
|
||||||
javaType.getJavaTypeClass().getSimpleName(),
|
javaType.getJavaTypeClass().getSimpleName(),
|
||||||
enumeratedValues
|
enumeratedValues
|
||||||
|
|
|
@ -14,6 +14,7 @@ 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.converter.internal.EnumHelper;
|
||||||
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
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;
|
||||||
|
@ -116,6 +117,7 @@ public class OracleOrdinalEnumJdbcType extends OracleEnumJdbcType {
|
||||||
@Override
|
@Override
|
||||||
public void addAuxiliaryDatabaseObjects(
|
public void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
JdbcTypeIndicators context) {
|
JdbcTypeIndicators context) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ 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.converter.spi.BasicValueConverter;
|
||||||
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;
|
||||||
|
@ -28,11 +28,10 @@ import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.Arrays;
|
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;
|
||||||
import static org.hibernate.type.SqlTypes.OTHER;
|
import static org.hibernate.type.SqlTypes.OTHER;
|
||||||
|
import static org.hibernate.type.descriptor.converter.internal.EnumHelper.getEnumeratedValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a named {@code enum} type on PostgreSQL.
|
* Represents a named {@code enum} type on PostgreSQL.
|
||||||
|
@ -66,7 +65,8 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||||
return (appender, value, dialect, wrapperOptions) -> appender.appendSql( "'" + ((Enum<?>) value).name() + "'::"
|
return (appender, value, dialect, wrapperOptions)
|
||||||
|
-> appender.appendSql( "'" + ((Enum<?>) value).name() + "'::"
|
||||||
+ dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) javaType.getJavaType() ) );
|
+ dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) javaType.getJavaType() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,13 +96,13 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
st.setObject( index, ((Enum<?>) value).name(), Types.OTHER );
|
st.setObject( index, getJavaType().unwrap( value, String.class, options ), Types.OTHER );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
st.setObject( name, ((Enum<?>) value).name(), Types.OTHER );
|
st.setObject( name, getJavaType().unwrap( value, String.class, options ), Types.OTHER );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -130,10 +130,11 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
|
||||||
@Override
|
@Override
|
||||||
public void addAuxiliaryDatabaseObjects(
|
public void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
JdbcTypeIndicators context) {
|
JdbcTypeIndicators context) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, true );
|
addAuxiliaryDatabaseObjects( javaType, valueConverter, database, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -142,20 +143,26 @@ public class PostgreSQLEnumJdbcType implements JdbcType {
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, true );
|
addAuxiliaryDatabaseObjects( javaType, null, database, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addAuxiliaryDatabaseObjects(
|
protected void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Database database,
|
Database database,
|
||||||
boolean sortEnumValues) {
|
boolean sortEnumValues) {
|
||||||
final Dialect dialect = database.getDialect();
|
@SuppressWarnings("unchecked")
|
||||||
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
|
||||||
final String enumTypeName = enumClass.getSimpleName();
|
final String enumTypeName = enumClass.getSimpleName();
|
||||||
final String[] enumeratedValues = EnumHelper.getEnumeratedValues( enumClass );
|
@SuppressWarnings("unchecked")
|
||||||
|
final String[] enumeratedValues =
|
||||||
|
valueConverter == null
|
||||||
|
? getEnumeratedValues( enumClass )
|
||||||
|
: getEnumeratedValues( enumClass, (BasicValueConverter<Enum<?>,?>) valueConverter ) ;
|
||||||
if ( sortEnumValues ) {
|
if ( sortEnumValues ) {
|
||||||
Arrays.sort( enumeratedValues );
|
Arrays.sort( enumeratedValues );
|
||||||
}
|
}
|
||||||
|
final Dialect dialect = database.getDialect();
|
||||||
final String[] create = dialect.getCreateEnumTypeCommand(
|
final String[] create = dialect.getCreateEnumTypeCommand(
|
||||||
javaType.getJavaTypeClass().getSimpleName(),
|
javaType.getJavaTypeClass().getSimpleName(),
|
||||||
enumeratedValues
|
enumeratedValues
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.dialect;
|
||||||
|
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
@ -42,10 +43,10 @@ public class PostgreSQLOrdinalEnumJdbcType extends PostgreSQLEnumJdbcType {
|
||||||
@Override
|
@Override
|
||||||
public void addAuxiliaryDatabaseObjects(
|
public void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
Size columnSize,
|
BasicValueConverter<?, ?> valueConverter, Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
JdbcTypeIndicators context) {
|
JdbcTypeIndicators context) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, false );
|
addAuxiliaryDatabaseObjects( javaType, valueConverter, database, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,6 +55,6 @@ public class PostgreSQLOrdinalEnumJdbcType extends PostgreSQLEnumJdbcType {
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
addAuxiliaryDatabaseObjects( javaType, database, false );
|
addAuxiliaryDatabaseObjects( javaType, null, database, false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,6 +365,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
||||||
|
|
||||||
resolution.getJdbcType().addAuxiliaryDatabaseObjects(
|
resolution.getJdbcType().addAuxiliaryDatabaseObjects(
|
||||||
resolution.getRelationalJavaType(),
|
resolution.getRelationalJavaType(),
|
||||||
|
resolution.getValueConverter(),
|
||||||
size,
|
size,
|
||||||
getBuildingContext().getMetadataCollector().getDatabase(),
|
getBuildingContext().getMetadataCollector().getDatabase(),
|
||||||
this
|
this
|
||||||
|
|
|
@ -8,9 +8,11 @@ package org.hibernate.type.descriptor.converter.internal;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.SqlTypes;
|
import org.hibernate.type.SqlTypes;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,14 +41,28 @@ public class EnumHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
public static String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
||||||
Enum<?>[] values = enumClass.getEnumConstants();
|
final Enum<?>[] values = enumClass.getEnumConstants();
|
||||||
String[] names = new String[values.length];
|
final String[] names = new String[values.length];
|
||||||
for ( int i = 0; i < values.length; i++ ) {
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
names[i] = values[i].name();
|
names[i] = values[i].name();
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String[] getEnumeratedValues(
|
||||||
|
Class<? extends Enum<?>> enumClass, BasicValueConverter<Enum<?>,?> converter) {
|
||||||
|
final Enum<?>[] values = enumClass.getEnumConstants();
|
||||||
|
final String[] names = new String[values.length];
|
||||||
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
|
final Object relationalValue = converter.toRelationalValue( values[i] );
|
||||||
|
if ( relationalValue == null ) {
|
||||||
|
throw new HibernateException( "Enum value converter returned null for enum class '" + enumClass.getName() + "'" );
|
||||||
|
}
|
||||||
|
names[i] = relationalValue.toString();
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
public static String[] getSortedEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
public static String[] getSortedEnumeratedValues(Class<? extends Enum<?>> enumClass) {
|
||||||
final String[] names = getEnumeratedValues( enumClass );
|
final String[] names = getEnumeratedValues( enumClass );
|
||||||
Arrays.sort( names );
|
Arrays.sort( names );
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
package org.hibernate.type.descriptor.converter.spi;
|
package org.hibernate.type.descriptor.converter.spi;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
|
|
@ -248,25 +248,20 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
|
||||||
* Convert a value of the enum type to its name value
|
* Convert a value of the enum type to its name value
|
||||||
*/
|
*/
|
||||||
public String toName(T domainForm) {
|
public String toName(T domainForm) {
|
||||||
if ( domainForm == null ) {
|
return domainForm == null ? null : domainForm.name();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return domainForm.name();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interpret a string value as the named value of the enum type
|
* Interpret a string value as the named value of the enum type
|
||||||
*/
|
*/
|
||||||
public T fromName(String relationalForm) {
|
public T fromName(String relationalForm) {
|
||||||
if ( relationalForm == null ) {
|
return relationalForm == null ? null : Enum.valueOf( getJavaTypeClass(), relationalForm.trim() );
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Enum.valueOf( getJavaTypeClass(), relationalForm.trim() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter<?, ?> converter, Dialect dialect) {
|
public String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter<?, ?> converter, Dialect dialect) {
|
||||||
if ( converter != null ) {
|
if ( converter != null
|
||||||
|
&& jdbcType.getDefaultSqlTypeCode() != NAMED_ENUM ) {
|
||||||
return renderConvertedEnumCheckConstraint( columnName, jdbcType, converter, dialect );
|
return renderConvertedEnumCheckConstraint( columnName, jdbcType, converter, dialect );
|
||||||
}
|
}
|
||||||
else if ( jdbcType.isInteger() ) {
|
else if ( jdbcType.isInteger() ) {
|
||||||
|
|
|
@ -373,7 +373,7 @@ public interface JdbcType extends Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #addAuxiliaryDatabaseObjects(JavaType, Size, Database, JdbcTypeIndicators)} instead
|
* @deprecated Use {@link #addAuxiliaryDatabaseObjects(JavaType, BasicValueConverter, Size, Database, JdbcTypeIndicators)} instead
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
@Deprecated(forRemoval = true)
|
@Deprecated(forRemoval = true)
|
||||||
|
@ -392,6 +392,7 @@ public interface JdbcType extends Serializable {
|
||||||
@Incubating
|
@Incubating
|
||||||
default void addAuxiliaryDatabaseObjects(
|
default void addAuxiliaryDatabaseObjects(
|
||||||
JavaType<?> javaType,
|
JavaType<?> javaType,
|
||||||
|
BasicValueConverter<?, ?> valueConverter,
|
||||||
Size columnSize,
|
Size columnSize,
|
||||||
Database database,
|
Database database,
|
||||||
JdbcTypeIndicators context) {
|
JdbcTypeIndicators context) {
|
||||||
|
|
|
@ -77,6 +77,7 @@ public class ArrayAggregateTest {
|
||||||
"StringArray"
|
"StringArray"
|
||||||
).addAuxiliaryDatabaseObjects(
|
).addAuxiliaryDatabaseObjects(
|
||||||
new ArrayJavaType<>( javaTypeRegistry.getDescriptor( String.class ) ),
|
new ArrayJavaType<>( javaTypeRegistry.getDescriptor( String.class ) ),
|
||||||
|
null,
|
||||||
Size.nil(),
|
Size.nil(),
|
||||||
metadata.getDatabase(),
|
metadata.getDatabase(),
|
||||||
typeConfiguration.getCurrentBaseSqlTypeIndicators()
|
typeConfiguration.getCurrentBaseSqlTypeIndicators()
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* 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.mapping.enumeratedvalue;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EnumType;
|
||||||
|
import jakarta.persistence.Enumerated;
|
||||||
|
import jakarta.persistence.EnumeratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
|
import org.hibernate.dialect.PostgreSQLDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
import org.hibernate.type.SqlTypes;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spec says that for {@linkplain EnumType#STRING}, only {@linkplain String}
|
||||||
|
* is supported. But {@code char} / {@linkplain Character} make a lot of sense to support as well
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@RequiresDialect(PostgreSQLDialect.class)
|
||||||
|
public class PostgresqlNamedEnumEnumerateValueTests {
|
||||||
|
@Test
|
||||||
|
@DomainModel(annotatedClasses = Person.class)
|
||||||
|
@SessionFactory
|
||||||
|
void testBasicUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.persist( new Person( 1, "John", Gender.MALE ) );
|
||||||
|
} );
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertEquals( Gender.MALE, session.find( Person.class, 1 ).gender );
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.doWork( (connection) -> {
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
try (ResultSet resultSet = statement.executeQuery( "select gender from persons" )) {
|
||||||
|
assertThat( resultSet.next() ).isTrue();
|
||||||
|
final String storedGender = resultSet.getString( 1 );
|
||||||
|
assertThat( storedGender ).isEqualTo( "M" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@DomainModel(annotatedClasses = Person.class)
|
||||||
|
@SessionFactory
|
||||||
|
@Test
|
||||||
|
void testNulls(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.persist( new Person( 1, "John", null ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.doWork( (connection) -> {
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
try (ResultSet resultSet = statement.executeQuery( "select gender from persons" )) {
|
||||||
|
assertThat( resultSet.next() ).isTrue();
|
||||||
|
final String storedGender = resultSet.getString( 1 );
|
||||||
|
assertThat( resultSet.wasNull() ).isTrue();
|
||||||
|
assertThat( storedGender ).isNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@DomainModel(annotatedClasses = Person.class)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsColumnCheck.class )
|
||||||
|
@Test
|
||||||
|
void verifyCheckConstraints(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> session.doWork( (connection) -> {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement( "insert into persons (id, gender) values (?, ?)" ) ) {
|
||||||
|
statement.setInt( 1, 100 );
|
||||||
|
statement.setString( 2, "X" );
|
||||||
|
statement.executeUpdate();
|
||||||
|
fail( "Expecting a failure" );
|
||||||
|
}
|
||||||
|
catch (SQLException expected) {
|
||||||
|
}
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@DomainModel(annotatedClasses = Person.class)
|
||||||
|
@SessionFactory
|
||||||
|
@SkipForDialect( dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase (at least jTDS driver) truncates the value so the constraint is not violated" )
|
||||||
|
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsColumnCheck.class )
|
||||||
|
@Test
|
||||||
|
void verifyCheckConstraints2(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> session.doWork( (connection) -> {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement( "insert into persons (id, gender) values (?, ?)" ) ) {
|
||||||
|
statement.setInt( 1, 200 );
|
||||||
|
// this would work without check constraints or with check constraints based solely on EnumType#STRING
|
||||||
|
statement.setString( 2, "MALE" );
|
||||||
|
statement.executeUpdate();
|
||||||
|
fail( "Expecting a failure" );
|
||||||
|
}
|
||||||
|
catch (SQLException expected) {
|
||||||
|
}
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> session.createMutationQuery( "delete Person" ).executeUpdate() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Gender {
|
||||||
|
MALE( 'M' ),
|
||||||
|
FEMALE( 'F' ),
|
||||||
|
OTHER( 'U' );
|
||||||
|
|
||||||
|
@EnumeratedValue
|
||||||
|
private final char code;
|
||||||
|
|
||||||
|
Gender(char code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
|
||||||
|
@Entity(name="Person")
|
||||||
|
@Table(name="persons")
|
||||||
|
public static class Person {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
|
||||||
|
@Column(length = 1)
|
||||||
|
private Gender gender;
|
||||||
|
|
||||||
|
public Person() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person(Integer id, String name, Gender gender) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.gender = gender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue