Skip to content

Commit 4c6cfbb

Browse files
committed
HHH-16125 attempt to support PostgreSQL enum types
1 parent 540fb0c commit 4c6cfbb

19 files changed

+480
-123
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
import org.hibernate.type.StandardBasicTypes;
7878
import org.hibernate.type.descriptor.java.JavaType;
7979
import org.hibernate.type.descriptor.jdbc.JdbcType;
80-
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
8180
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
8281
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
8382
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
@@ -796,7 +795,7 @@ public boolean supportsColumnCheck() {
796795
}
797796

798797
@Override
799-
public String getEnumTypeDeclaration(String[] values) {
798+
public String getEnumTypeDeclaration(String name, String[] values) {
800799
StringBuilder type = new StringBuilder();
801800
type.append( "enum (" );
802801
String separator = "";

hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/EnumeratedValueResolution.java

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,29 @@
1515
import org.hibernate.mapping.BasicValue;
1616
import org.hibernate.service.ServiceRegistry;
1717
import org.hibernate.type.ConvertedBasicType;
18+
import org.hibernate.type.descriptor.WrapperOptions;
1819
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
20+
import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter;
1921
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
2022
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
2123
import org.hibernate.type.descriptor.java.EnumJavaType;
2224
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
2325
import org.hibernate.type.descriptor.java.JavaType;
2426
import org.hibernate.type.descriptor.java.MutabilityPlan;
27+
import org.hibernate.type.descriptor.java.ObjectJavaType;
2528
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
2629
import org.hibernate.type.descriptor.jdbc.JdbcType;
2730
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
31+
import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType;
2832
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
2933
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
3034
import org.hibernate.type.spi.TypeConfiguration;
3135

3236
import jakarta.persistence.EnumType;
3337

3438
import static org.hibernate.type.SqlTypes.CHAR;
35-
import static org.hibernate.type.SqlTypes.SMALLINT;
36-
import static org.hibernate.type.SqlTypes.TINYINT;
3739
import static org.hibernate.type.SqlTypes.VARCHAR;
40+
import static org.hibernate.type.SqlTypes.isCharacterType;
3841

3942
/**
4043
* Resolution for {@linkplain Enum enum} mappings using {@link jakarta.persistence.Enumerated},
@@ -50,8 +53,7 @@ public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValu
5053

5154
public EnumeratedValueResolution(
5255
JdbcType jdbcType,
53-
EnumValueConverter<E, R> valueConverter,
54-
MetadataBuildingContext context) {
56+
EnumValueConverter<E, R> valueConverter) {
5557
this.valueConverter = valueConverter;
5658

5759
final String externalizableName = createName( valueConverter );
@@ -70,7 +72,8 @@ private String createName(EnumValueConverter<E, R> valueConverter) {
7072
}
7173

7274
private static EnumType enumStyle(EnumValueConverter<?,?> valueConverter) {
73-
if ( valueConverter instanceof NamedEnumValueConverter ) {
75+
if ( valueConverter instanceof NamedEnumValueConverter
76+
|| valueConverter instanceof NativeEnumValueConverter ) {
7477
return EnumType.STRING;
7578
}
7679
else if ( valueConverter instanceof OrdinalEnumValueConverter ) {
@@ -132,35 +135,48 @@ public static <E extends Enum<E>> EnumeratedValueResolution<E,?> fromName(
132135
final Class<E> enumClass = resolveEnumClass( parts[1], context.getBootstrapContext() );
133136
final jakarta.persistence.EnumType style = jakarta.persistence.EnumType.valueOf( parts[ 2 ] );
134137

135-
//noinspection unchecked,rawtypes
138+
@SuppressWarnings({"unchecked", "rawtypes"})
136139
final EnumJavaType<E> enumJavaType = (EnumJavaType) javaTypeRegistry.getDescriptor( enumClass );
137-
final JdbcType jdbcType;
140+
final JdbcType jdbcType = enumJavaType.getRecommendedJdbcType( jdbcTypeIndicators );
138141
final EnumValueConverter<E,?> converter;
139142

140-
if ( style == EnumType.ORDINAL ) {
141-
jdbcType = jdbcTypeRegistry.getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
142-
143-
final JavaType<Integer> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
144-
jdbcTypeIndicators.getColumnPrecision(),
145-
jdbcTypeIndicators.getColumnScale(),
146-
typeConfiguration
147-
);
148-
converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
149-
}
150-
else if ( style == EnumType.STRING ) {
151-
jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeIndicators.getColumnLength() == 1 ? CHAR : VARCHAR );
152-
final JavaType<String> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
153-
jdbcTypeIndicators.getColumnPrecision(),
154-
jdbcTypeIndicators.getColumnScale(),
155-
typeConfiguration
156-
);
157-
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
158-
}
159-
else {
160-
throw new IllegalArgumentException( );
143+
switch ( style ) {
144+
case ORDINAL:
145+
final JavaType<Integer> integerJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
146+
jdbcTypeIndicators.getColumnPrecision(),
147+
jdbcTypeIndicators.getColumnScale(),
148+
typeConfiguration
149+
);
150+
converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, integerJavaType );
151+
break;
152+
case STRING:
153+
if (jdbcType instanceof NativeEnumJdbcType) {
154+
converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() {
155+
@Override
156+
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
157+
if ( String.class.equals(type) && value instanceof Enum) {
158+
return (X) ((Enum<?>) value).name();
159+
}
160+
else {
161+
return super.unwrap(value, type, options);
162+
}
163+
}
164+
} );
165+
}
166+
else {
167+
final JavaType<String> stringJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
168+
jdbcTypeIndicators.getColumnPrecision(),
169+
jdbcTypeIndicators.getColumnScale(),
170+
typeConfiguration
171+
);
172+
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, stringJavaType );
173+
}
174+
break;
175+
default:
176+
throw new IllegalArgumentException( );
161177
}
162178

163-
return new EnumeratedValueResolution<>( jdbcType, converter, context );
179+
return new EnumeratedValueResolution<>( jdbcType, converter );
164180
}
165181

166182
private static <E extends Enum<E>> Class<E> resolveEnumClass(String enumClassName, BootstrapContext bootstrapContext) {

hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,23 @@
2323
import org.hibernate.type.BasicPluralType;
2424
import org.hibernate.type.BasicType;
2525
import org.hibernate.type.SerializableType;
26+
import org.hibernate.type.descriptor.WrapperOptions;
2627
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
28+
import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter;
2729
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
30+
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
2831
import org.hibernate.type.descriptor.java.BasicJavaType;
2932
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
3033
import org.hibernate.type.descriptor.java.EnumJavaType;
3134
import org.hibernate.type.descriptor.java.JavaType;
3235
import org.hibernate.type.descriptor.java.JavaTypeHelper;
3336
import org.hibernate.type.descriptor.java.MutabilityPlan;
37+
import org.hibernate.type.descriptor.java.ObjectJavaType;
3438
import org.hibernate.type.descriptor.java.SerializableJavaType;
3539
import org.hibernate.type.descriptor.java.TemporalJavaType;
3640
import org.hibernate.type.descriptor.jdbc.JdbcType;
3741
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
42+
import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType;
3843
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
3944
import org.hibernate.type.spi.TypeConfiguration;
4045

@@ -43,6 +48,7 @@
4348

4449
import static org.hibernate.type.SqlTypes.SMALLINT;
4550
import static org.hibernate.type.SqlTypes.TINYINT;
51+
import static org.hibernate.type.SqlTypes.isCharacterType;
4652

4753
/**
4854
* BasicValue.Resolution resolver for cases where no explicit
@@ -331,28 +337,6 @@ public static <E extends Enum<E>, R> EnumeratedValueResolution<E,R> fromEnum(
331337
JdbcTypeIndicators stdIndicators,
332338
MetadataBuildingContext context) {
333339
final EnumType enumStyle = stdIndicators.getEnumeratedType();
334-
335-
if ( enumStyle == EnumType.STRING ) {
336-
//noinspection unchecked
337-
return (EnumeratedValueResolution<E, R>) stringEnumValueResolution(
338-
enumJavaType,
339-
explicitJavaType,
340-
explicitJdbcType,
341-
stdIndicators,
342-
context
343-
);
344-
}
345-
346-
if ( enumStyle == EnumType.ORDINAL ) {
347-
//noinspection unchecked
348-
return (EnumeratedValueResolution<E, R>) ordinalEnumValueResolution(
349-
enumJavaType,
350-
(BasicJavaType<? extends Number>)explicitJavaType,
351-
explicitJdbcType,
352-
context
353-
);
354-
}
355-
356340
if ( enumStyle == null ) {
357341
// NOTE : separate from the explicit ORDINAL check to facilitate
358342
// handling native database enum types. In theory anyway - atm
@@ -367,8 +351,27 @@ public static <E extends Enum<E>, R> EnumeratedValueResolution<E,R> fromEnum(
367351
context
368352
);
369353
}
370-
371-
throw new MappingException( "Unknown enumeration-style (JPA EnumType) : " + enumStyle );
354+
switch ( enumStyle ) {
355+
case STRING:
356+
//noinspection unchecked
357+
return (EnumeratedValueResolution<E, R>) stringEnumValueResolution(
358+
enumJavaType,
359+
explicitJavaType,
360+
explicitJdbcType,
361+
stdIndicators,
362+
context
363+
);
364+
case ORDINAL:
365+
//noinspection unchecked
366+
return (EnumeratedValueResolution<E, R>) ordinalEnumValueResolution(
367+
enumJavaType,
368+
(BasicJavaType<? extends Number>)explicitJavaType,
369+
explicitJdbcType,
370+
context
371+
);
372+
default:
373+
throw new MappingException( "Unknown enumeration-style (JPA EnumType) : " + enumStyle );
374+
}
372375
}
373376

374377
private static <E extends Enum<E>, N extends Number> EnumeratedValueResolution<E,N> ordinalEnumValueResolution(
@@ -378,11 +381,9 @@ private static <E extends Enum<E>, N extends Number> EnumeratedValueResolution<E
378381
MetadataBuildingContext context) {
379382
final JdbcType jdbcType = ordinalJdbcType( explicitJdbcType, enumJavaType, context );
380383
final JavaType<N> relationalJavaType = ordinalJavaType( explicitJavaType, jdbcType, context );
381-
382384
return new EnumeratedValueResolution<>(
383385
jdbcType,
384-
new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, relationalJavaType ),
385-
context
386+
new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, relationalJavaType )
386387
);
387388
}
388389

@@ -418,7 +419,7 @@ private static <N extends Number> JavaType<N> ordinalJavaType(
418419
}
419420
}
420421

421-
private static <E extends Enum<E>> EnumeratedValueResolution<E,String> stringEnumValueResolution(
422+
private static <E extends Enum<E>> EnumeratedValueResolution<E,?> stringEnumValueResolution(
422423
EnumJavaType<E> enumJavaType,
423424
BasicJavaType<?> explicitJavaType,
424425
JdbcType explicitJdbcType,
@@ -427,19 +428,28 @@ private static <E extends Enum<E>> EnumeratedValueResolution<E,String> stringEnu
427428
final JdbcType jdbcType = explicitJdbcType == null
428429
? enumJavaType.getRecommendedJdbcType( stdIndicators )
429430
: explicitJdbcType;
430-
final JavaType<String> relationalJtd = stringJavaType( explicitJavaType, stdIndicators, context );
431-
432-
return new EnumeratedValueResolution<>(
433-
jdbcType,
434-
new NamedEnumValueConverter<>( enumJavaType, jdbcType, relationalJtd ),
435-
context
436-
);
437-
}
438-
439-
private static JdbcType stringJdbcType(JdbcType explicitJdbcType, JdbcTypeIndicators stdIndicators, JavaType<String> relationalJtd) {
440-
return explicitJdbcType != null
441-
? explicitJdbcType
442-
: relationalJtd.getRecommendedJdbcType( stdIndicators );
431+
final EnumValueConverter<E,?> converter;
432+
if ( jdbcType instanceof NativeEnumJdbcType ) {
433+
converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() {
434+
@Override
435+
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
436+
if ( String.class.equals(type) && value instanceof Enum) {
437+
return (X) ((Enum<?>) value).name();
438+
}
439+
else {
440+
return super.unwrap(value, type, options);
441+
}
442+
}
443+
} );
444+
}
445+
else {
446+
converter = new NamedEnumValueConverter<>(
447+
enumJavaType,
448+
jdbcType,
449+
stringJavaType( explicitJavaType, stdIndicators, context )
450+
);
451+
}
452+
return new EnumeratedValueResolution<>( jdbcType, converter );
443453
}
444454

445455
private static JavaType<String> stringJavaType(

hibernate-core/src/main/java/org/hibernate/boot/model/relational/NamedAuxiliaryDatabaseObject.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ public class NamedAuxiliaryDatabaseObject
1818
implements Exportable {
1919
private final String name;
2020

21+
public NamedAuxiliaryDatabaseObject(
22+
String name,
23+
Namespace namespace,
24+
String[] createStrings,
25+
String[] dropStrings,
26+
Set<String> dialectScopes) {
27+
super( namespace, createStrings, dropStrings, dialectScopes );
28+
this.name = name;
29+
}
30+
31+
public NamedAuxiliaryDatabaseObject(
32+
String name,
33+
Namespace namespace,
34+
String[] createStrings,
35+
String[] dropStrings,
36+
Set<String> dialectScopes,
37+
boolean beforeTables) {
38+
super( namespace, createStrings, dropStrings, dialectScopes, beforeTables );
39+
this.name = name;
40+
}
41+
2142
public NamedAuxiliaryDatabaseObject(
2243
String name,
2344
Namespace namespace,
@@ -28,6 +49,17 @@ public NamedAuxiliaryDatabaseObject(
2849
this.name = name;
2950
}
3051

52+
public NamedAuxiliaryDatabaseObject(
53+
String name,
54+
Namespace namespace,
55+
String createString,
56+
String dropString,
57+
Set<String> dialectScopes,
58+
boolean beforeTables) {
59+
super( namespace, createString, dropString, dialectScopes, beforeTables );
60+
this.name = name;
61+
}
62+
3163
@Override
3264
public String getExportIdentifier() {
3365
return new QualifiedNameImpl(

0 commit comments

Comments
 (0)