HHH-16125 complete redesign of how enum mappings work

- introduce SqlTypes.ENUM
- no more converters!
- finish of Potgres enum support
- disable BIND for enums in Criteria on PostgreSQL
  (PostgreSQL doesn't do the needed type conversion to the enum type)
This commit is contained in:
Gavin 2023-04-27 16:36:37 +02:00 committed by Gavin King
parent d348ae2d8c
commit febf39cc55
36 changed files with 585 additions and 693 deletions

View File

@ -1,188 +0,0 @@
/*
* 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.boot.model.process.internal;
import java.util.Locale;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.ConvertedBasicType;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.ObjectJavaType;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.EnumType;
import static org.hibernate.type.SqlTypes.CHAR;
import static org.hibernate.type.SqlTypes.VARCHAR;
import static org.hibernate.type.SqlTypes.isCharacterType;
/**
* Resolution for {@linkplain Enum enum} mappings using {@link jakarta.persistence.Enumerated},
* either implicitly or explicitly
*
* @author Steve Ebersole
*/
public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValue.Resolution<E> {
public static final String PREFIX = "enum::";
private final EnumValueConverter<E,R> valueConverter;
private final ConvertedBasicType<E> jdbcMapping;
public EnumeratedValueResolution(
JdbcType jdbcType,
EnumValueConverter<E, R> valueConverter) {
this.valueConverter = valueConverter;
final String externalizableName = createName( valueConverter );
this.jdbcMapping = new ConvertedBasicTypeImpl<>( externalizableName, jdbcType, valueConverter );
// todo (enum) : register database objects if needed
}
private String createName(EnumValueConverter<E, R> valueConverter) {
return String.format(
Locale.ROOT,
PREFIX + "%s::%s",
valueConverter.getDomainJavaType().getJavaType().getName(),
enumStyle( valueConverter ).name()
);
}
private static EnumType enumStyle(EnumValueConverter<?,?> valueConverter) {
if ( valueConverter instanceof NamedEnumValueConverter
|| valueConverter instanceof NativeEnumValueConverter ) {
return EnumType.STRING;
}
else if ( valueConverter instanceof OrdinalEnumValueConverter ) {
return EnumType.ORDINAL;
}
throw new UnsupportedOperationException();
}
@Override
public ConvertedBasicType<E> getJdbcMapping() {
return jdbcMapping;
}
@Override
public ConvertedBasicType<E> getLegacyResolvedBasicType() {
return jdbcMapping;
}
@Override
public JavaType<E> getDomainJavaType() {
return jdbcMapping.getJavaTypeDescriptor();
}
@Override
public JavaType<?> getRelationalJavaType() {
return jdbcMapping.getJdbcJavaType();
}
@Override
public JdbcType getJdbcType() {
return jdbcMapping.getJdbcType();
}
@Override
public EnumValueConverter<E,R> getValueConverter() {
return valueConverter;
}
@Override
public MutabilityPlan<E> getMutabilityPlan() {
return ImmutableMutabilityPlan.instance();
}
public static <E extends Enum<E>> EnumeratedValueResolution<E,?> fromName(
String name,
JdbcTypeIndicators jdbcTypeIndicators,
MetadataBuildingContext context) {
assert name != null;
assert name.startsWith( PREFIX );
final String[] parts = StringHelper.split( "::", name );
assert parts.length == 3;
assert "enum".equals( parts[0] );
final TypeConfiguration typeConfiguration = context.getBootstrapContext().getTypeConfiguration();
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
final Class<E> enumClass = resolveEnumClass( parts[1], context.getBootstrapContext() );
final jakarta.persistence.EnumType style = jakarta.persistence.EnumType.valueOf( parts[ 2 ] );
@SuppressWarnings({"unchecked", "rawtypes"})
final EnumJavaType<E> enumJavaType = (EnumJavaType) javaTypeRegistry.getDescriptor( enumClass );
final JdbcType jdbcType = enumJavaType.getRecommendedJdbcType( jdbcTypeIndicators );
final EnumValueConverter<E,?> converter;
switch ( style ) {
case ORDINAL:
final JavaType<Integer> integerJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
jdbcTypeIndicators.getColumnPrecision(),
jdbcTypeIndicators.getColumnScale(),
typeConfiguration
);
converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, integerJavaType );
break;
case STRING:
if (jdbcType instanceof NativeEnumJdbcType) {
converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() {
@Override
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
if ( String.class.equals(type) && value instanceof Enum) {
return (X) ((Enum<?>) value).name();
}
else {
return super.unwrap(value, type, options);
}
}
} );
}
else {
final JavaType<String> stringJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
jdbcTypeIndicators.getColumnPrecision(),
jdbcTypeIndicators.getColumnScale(),
typeConfiguration
);
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, stringJavaType );
}
break;
default:
throw new IllegalArgumentException( );
}
return new EnumeratedValueResolution<>( jdbcType, converter );
}
private static <E extends Enum<E>> Class<E> resolveEnumClass(String enumClassName, BootstrapContext bootstrapContext) {
final ServiceRegistry serviceRegistry = bootstrapContext.getServiceRegistry();
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
return classLoaderService.classForName( enumClassName );
}
}

View File

@ -12,6 +12,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.MappingException;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.BasicValue;
@ -23,32 +24,23 @@ import org.hibernate.type.AdjustableBasicType;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType;
import org.hibernate.type.SerializableType;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.NativeEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.JavaTypeHelper;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.ObjectJavaType;
import org.hibernate.type.descriptor.java.SerializableJavaType;
import org.hibernate.type.descriptor.java.TemporalJavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.EnumType;
import jakarta.persistence.TemporalType;
import static org.hibernate.type.SqlTypes.SMALLINT;
import static org.hibernate.type.SqlTypes.TINYINT;
import static org.hibernate.type.SqlTypes.isCharacterType;
import static org.hibernate.type.descriptor.java.JavaTypeHelper.isTemporal;
/**
* BasicValue.Resolution resolver for cases where no explicit
@ -69,7 +61,8 @@ public class InferredBasicValueResolver {
String propertyName,
MetadataBuildingContext buildingContext) {
final Dialect dialect = buildingContext.getMetadataCollector().getDatabase().getDialect();
final TypeConfiguration typeConfiguration = buildingContext.getBootstrapContext().getTypeConfiguration();
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
final JavaType<T> reflectedJtd = reflectedJtdResolver.get();
@ -79,31 +72,19 @@ public class InferredBasicValueResolver {
final BasicType<T> jdbcMapping;
if ( explicitJavaType != null ) {
if (explicitJavaType != null) {
// we have an explicit JavaType
if ( explicitJavaType instanceof EnumJavaType ) {
return fromEnum(
(EnumJavaType) explicitJavaType,
null,
explicitJdbcType,
stdIndicators,
buildingContext
);
}
else if ( JavaTypeHelper.isTemporal( explicitJavaType ) ) {
if ( isTemporal( explicitJavaType ) ) {
return fromTemporal(
(TemporalJavaType<T>) explicitJavaType,
null,
explicitJdbcType,
resolvedJavaType,
explicitMutabilityPlanAccess,
stdIndicators,
typeConfiguration
stdIndicators
);
}
else if ( explicitJdbcType != null ) {
// we also have an explicit JdbcType
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
explicitJavaType,
explicitJdbcType
@ -132,30 +113,25 @@ public class InferredBasicValueResolver {
else if ( reflectedJtd != null ) {
// we were able to determine the "reflected java-type"
// Use JTD if we know it to apply any specialized resolutions
if ( reflectedJtd instanceof EnumJavaType ) {
return fromEnum(
(EnumJavaType) reflectedJtd,
null,
explicitJdbcType,
stdIndicators,
buildingContext
bootstrapContext
);
}
else if ( JavaTypeHelper.isTemporal( reflectedJtd ) ) {
else if ( isTemporal( reflectedJtd ) ) {
return fromTemporal(
(TemporalJavaType<T>) reflectedJtd,
null,
explicitJdbcType,
resolvedJavaType,
explicitMutabilityPlanAccess,
stdIndicators,
typeConfiguration
stdIndicators
);
}
else if ( explicitJdbcType != null ) {
// we also have an explicit JdbcType
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
reflectedJtd,
explicitJdbcType
@ -170,24 +146,20 @@ public class InferredBasicValueResolver {
final JavaType<?> elementJtd = containerJtd.getElementJavaType();
final BasicType registeredElementType;
if ( elementJtd instanceof EnumJavaType ) {
final EnumeratedValueResolution<?,?> resolution = fromEnum(
final BasicValue.Resolution<?> resolution = fromEnum(
(EnumJavaType<?>) elementJtd,
null,
null,
explicitJdbcType,
stdIndicators,
buildingContext
);
registeredElementType = resolution.getJdbcMapping();
bootstrapContext);
registeredElementType = (BasicType<?>) resolution.getJdbcMapping();
}
else if ( JavaTypeHelper.isTemporal( elementJtd ) ) {
final InferredBasicValueResolution resolution = InferredBasicValueResolver.fromTemporal(
(TemporalJavaType<T>) elementJtd,
else if ( isTemporal( elementJtd ) ) {
final BasicValue.Resolution<?> resolution = fromTemporal(
(TemporalJavaType<?>) elementJtd,
null,
null,
resolvedJavaType,
explicitMutabilityPlanAccess,
stdIndicators,
typeConfiguration
stdIndicators
);
registeredElementType = resolution.getLegacyResolvedBasicType();
}
@ -330,163 +302,40 @@ public class InferredBasicValueResolver {
}
}
public static <E extends Enum<E>, R> EnumeratedValueResolution<E,R> fromEnum(
public static <E extends Enum<E>> BasicValue.Resolution<E> fromEnum(
EnumJavaType<E> enumJavaType,
BasicJavaType<R> explicitJavaType,
JdbcType explicitJdbcType,
JdbcTypeIndicators stdIndicators,
MetadataBuildingContext context) {
final EnumType enumStyle = stdIndicators.getEnumeratedType();
if ( enumStyle == null ) {
// NOTE : separate from the explicit ORDINAL check to facilitate
// handling native database enum types. In theory anyway - atm
// we cannot discern an implicit (default value) or explicit style
// due to HCANN and annotation handling for default values
//noinspection unchecked
return (EnumeratedValueResolution<E, R>) ordinalEnumValueResolution(
enumJavaType,
(BasicJavaType<? extends Number>)explicitJavaType,
explicitJdbcType,
context
);
}
switch ( enumStyle ) {
case STRING:
//noinspection unchecked
return (EnumeratedValueResolution<E, R>) stringEnumValueResolution(
enumJavaType,
explicitJavaType,
explicitJdbcType,
stdIndicators,
context
);
case ORDINAL:
//noinspection unchecked
return (EnumeratedValueResolution<E, R>) ordinalEnumValueResolution(
enumJavaType,
(BasicJavaType<? extends Number>)explicitJavaType,
explicitJdbcType,
context
);
default:
throw new MappingException( "Unknown enumeration-style (JPA EnumType) : " + enumStyle );
}
}
private static <E extends Enum<E>, N extends Number> EnumeratedValueResolution<E,N> ordinalEnumValueResolution(
EnumJavaType<E> enumJavaType,
BasicJavaType<N> explicitJavaType,
JdbcType explicitJdbcType,
MetadataBuildingContext context) {
final JdbcType jdbcType = ordinalJdbcType( explicitJdbcType, enumJavaType, context );
final JavaType<N> relationalJavaType = ordinalJavaType( explicitJavaType, jdbcType, context );
return new EnumeratedValueResolution<>(
jdbcType,
new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, relationalJavaType )
);
}
private static JdbcType ordinalJdbcType(
JdbcType explicitJdbcType,
EnumJavaType<?> enumJavaType,
MetadataBuildingContext context) {
return explicitJdbcType != null
? explicitJdbcType
: context.getMetadataCollector().getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
}
private static <N extends Number> JavaType<N> ordinalJavaType(
JavaType<N> explicitJavaType,
JdbcType jdbcType,
MetadataBuildingContext context) {
if ( explicitJavaType != null ) {
if ( !Integer.class.isAssignableFrom( explicitJavaType.getJavaTypeClass() ) ) {
throw new MappingException(
"Explicit JavaType [" + explicitJavaType +
"] applied to enumerated value with EnumType#ORDINAL" +
" should handle `java.lang.Integer` as its relational type descriptor"
);
}
return explicitJavaType;
}
else {
return jdbcType.getJdbcRecommendedJavaTypeMapping(
null,
null,
context.getMetadataCollector().getTypeConfiguration()
);
}
}
private static <E extends Enum<E>> EnumeratedValueResolution<E,?> stringEnumValueResolution(
EnumJavaType<E> enumJavaType,
BasicJavaType<?> explicitJavaType,
JdbcType explicitJdbcType,
JdbcTypeIndicators stdIndicators,
MetadataBuildingContext context) {
BootstrapContext bootstrapContext) {
final JdbcType jdbcType = explicitJdbcType == null
? enumJavaType.getRecommendedJdbcType( stdIndicators )
: explicitJdbcType;
final EnumValueConverter<E,?> converter;
if ( jdbcType instanceof NativeEnumJdbcType ) {
converter = new NativeEnumValueConverter<>( enumJavaType, jdbcType, new ObjectJavaType() {
@Override
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
if ( String.class.equals(type) && value instanceof Enum) {
return (X) ((Enum<?>) value).name();
}
else {
return super.unwrap(value, type, options);
}
}
} );
}
else {
converter = new NamedEnumValueConverter<>(
final BasicTypeImpl<E> basicType = new BasicTypeImpl<>( enumJavaType, jdbcType );
bootstrapContext.registerAdHocBasicType( basicType );
return new InferredBasicValueResolution<>(
basicType,
enumJavaType,
enumJavaType,
jdbcType,
stringJavaType( explicitJavaType, stdIndicators, context )
basicType,
ImmutableMutabilityPlan.instance()
);
}
return new EnumeratedValueResolution<>( jdbcType, converter );
}
private static JavaType<String> stringJavaType(
BasicJavaType<?> explicitJavaType,
JdbcTypeIndicators stdIndicators,
MetadataBuildingContext context) {
if ( explicitJavaType != null ) {
if ( ! String.class.isAssignableFrom( explicitJavaType.getJavaTypeClass() ) ) {
throw new MappingException(
"Explicit JavaType [" + explicitJavaType +
"] applied to enumerated value with EnumType#STRING" +
" should handle `java.lang.String` as its relational type descriptor"
);
}
return (JavaType<String>) explicitJavaType;
}
else {
return context.getMetadataCollector().getTypeConfiguration().getJavaTypeRegistry()
.getDescriptor( stdIndicators.getColumnLength() == 1 ? Character.class : String.class );
}
}
public static <T> InferredBasicValueResolution<T,T> fromTemporal(
public static <T> BasicValue.Resolution<T> fromTemporal(
TemporalJavaType<T> reflectedJtd,
BasicJavaType<?> explicitJavaType,
JdbcType explicitJdbcType,
Type resolvedJavaType,
Function<TypeConfiguration, MutabilityPlan> explicitMutabilityPlanAccess,
JdbcTypeIndicators stdIndicators,
TypeConfiguration typeConfiguration) {
JdbcTypeIndicators stdIndicators) {
final TypeConfiguration typeConfiguration = stdIndicators.getTypeConfiguration();
final TemporalType requestedTemporalPrecision = stdIndicators.getTemporalPrecision();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Case #1 - explicit JavaType
if ( explicitJavaType != null ) {
if ( !JavaTypeHelper.isTemporal( explicitJavaType ) ) {
if ( !isTemporal( explicitJavaType ) ) {
throw new MappingException(
"Explicit JavaType [" + explicitJavaType +
"] defined for temporal value must implement TemporalJavaType"
@ -495,7 +344,6 @@ public class InferredBasicValueResolver {
@SuppressWarnings("unchecked")
final TemporalJavaType<T> explicitTemporalJtd = (TemporalJavaType<T>) explicitJavaType;
if ( requestedTemporalPrecision != null && explicitTemporalJtd.getPrecision() != requestedTemporalPrecision ) {
throw new MappingException(
"Temporal precision (`jakarta.persistence.TemporalType`) mismatch... requested precision = " + requestedTemporalPrecision +
@ -507,9 +355,7 @@ public class InferredBasicValueResolver {
final JdbcType jdbcType = explicitJdbcType != null
? explicitJdbcType
: explicitTemporalJtd.getRecommendedJdbcType( stdIndicators );
final BasicType<T> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitTemporalJtd, jdbcType );
final MutabilityPlan<T> mutabilityPlan = determineMutabilityPlan( explicitMutabilityPlanAccess, explicitTemporalJtd, typeConfiguration );
return new InferredBasicValueResolution<>(
jdbcMapping,
@ -531,10 +377,7 @@ public class InferredBasicValueResolver {
final TemporalJavaType<T> jtd;
if ( requestedTemporalPrecision != null ) {
jtd = reflectedJtd.resolveTypeForPrecision(
requestedTemporalPrecision,
typeConfiguration
);
jtd = reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration );
}
else {
jtd = reflectedJtd;

View File

@ -38,7 +38,6 @@ import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
@ -64,7 +63,7 @@ import jakarta.persistence.AttributeConverter;
*
* @since 5.0
*/
public interface InFlightMetadataCollector extends Mapping, MetadataImplementor {
public interface InFlightMetadataCollector extends MetadataImplementor {
BootstrapContext getBootstrapContext();
/**

View File

@ -204,6 +204,7 @@ import static org.hibernate.cfg.AvailableSettings.NON_CONTEXTUAL_LOB_CREATION;
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS;
import static org.hibernate.internal.util.StringHelper.parseCommaSeparatedString;
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
import static org.hibernate.type.SqlTypes.ARRAY;
import static org.hibernate.type.SqlTypes.BIGINT;
import static org.hibernate.type.SqlTypes.BINARY;
@ -762,7 +763,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
public String[] getCreateEnumTypeCommand(String name, String[] values) {
return null;
return EMPTY_STRING_ARRAY;
}
public String[] getCreateEnumTypeCommand(Class<? extends Enum<?>> enumType) {
@ -771,6 +772,14 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
return getCreateEnumTypeCommand( enumType.getSimpleName(), values );
}
public String[] getDropEnumTypeCommand(String name) {
return EMPTY_STRING_ARRAY;
}
public String[] getDropEnumTypeCommand(Class<? extends Enum<?>> enumType) {
return getDropEnumTypeCommand( enumType.getSimpleName() );
}
/**
* Render a SQL check condition for a column that represents an enumerated value
* by its {@linkplain jakarta.persistence.EnumType#STRING string representation}.

View File

@ -76,6 +76,7 @@ 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.spi.DdlTypeRegistry;
import jakarta.persistence.TemporalType;
@ -378,6 +379,8 @@ public class MySQLDialect extends Dialect {
.withTypeCapacity( maxLobLen, "text" )
.build()
);
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl(this) );
}
@Deprecated
@ -641,6 +644,8 @@ public class MySQLDialect extends Dialect {
.getDescriptor( Object.class )
)
);
jdbcTypeRegistry.addDescriptor( new MySQLEnumJdbcType() );
}
@Override
@ -869,6 +874,11 @@ public class MySQLDialect extends Dialect {
return getMySQLVersion().isSameOrAfter( 8, 0, 16 );
}
@Override
public boolean hasNativeEnums() {
return true;
}
@Override
public String getEnumTypeDeclaration(String name, String[] values) {
StringBuilder type = new StringBuilder();

View File

@ -0,0 +1,82 @@
/*
* 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.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;
/**
* @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 );
}
};
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.dialect;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.BooleanJdbcType;
@ -14,7 +15,7 @@ public class OracleBooleanJdbcType extends BooleanJdbcType {
public static final OracleBooleanJdbcType INSTANCE = new OracleBooleanJdbcType();
@Override
public String getCheckCondition(String columnName, JavaType<?> javaType, Dialect dialect) {
public String getCheckCondition(String columnName, JavaType<?> javaType, BasicValueConverter<?, ?> converter, Dialect dialect) {
return columnName + " in (0,1)";
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.dialect;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
@ -41,7 +42,7 @@ public class OracleJsonJdbcType extends OracleJsonBlobJdbcType {
}
@Override
public String getCheckCondition(String columnName, JavaType<?> javaType, Dialect dialect) {
public String getCheckCondition(String columnName, JavaType<?> javaType, BasicValueConverter<?, ?> converter, Dialect dialect) {
// No check constraint necessary, because the JSON DDL type is already OSON encoded
return null;
}

View File

@ -87,6 +87,7 @@ import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
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.NamedNativeEnumDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -271,6 +272,8 @@ public class PostgreSQLDialect extends Dialect {
// Prefer jsonb if possible
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "jsonb", this ) );
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
}
@Override
@ -421,6 +424,11 @@ public class PostgreSQLDialect extends Dialect {
return new String[] { type.toString(), cast1.toString(), cast2.toString() };
}
@Override
public String[] getDropEnumTypeCommand(String name) {
return new String[] { "drop type if exists " + name + " cascade" };
}
@Override
public String currentTime() {
return "localtime";
@ -1408,6 +1416,8 @@ public class PostgreSQLDialect extends Dialect {
.getDescriptor( Object.class )
)
);
jdbcTypeRegistry.addDescriptor( new PostgreSQLEnumJdbcType() );
}
@Override

View File

@ -0,0 +1,116 @@
/*
* 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.boot.model.relational.NamedAuxiliaryDatabaseObject;
import org.hibernate.boot.spi.InFlightMetadataCollector;
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 java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import static java.util.Collections.emptySet;
import static org.hibernate.type.SqlTypes.ENUM;
/**
* @author Gavin King
*/
public class PostgreSQLEnumJdbcType implements JdbcType {
@Override
public int getJdbcTypeCode() {
return ENUM;
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
return (appender, value, dialect, wrapperOptions) -> appender.appendSql( "'" + ((Enum<?>) value).name() + "'::"
+ dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) javaType.getJavaType() ) );
}
@Override
public String getFriendlyName() {
return "ENUM";
}
@Override
public String toString() {
return "EnumTypeDescriptor";
}
@Override
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
return new BasicBinder<>( javaType, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
st.setNull( index, Types.OTHER );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
st.setNull( name, Types.OTHER );
}
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setObject( index, value, Types.OTHER );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, Types.OTHER );
}
};
}
@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.getObject( paramIndex ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return getJavaType().wrap( statement.getObject( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return getJavaType().wrap( statement.getObject( name ), options );
}
};
}
@Override
public void addAuxiliaryDatabaseObjects(JavaType<?> javaType, InFlightMetadataCollector metadataCollector) {
Database database = metadataCollector.getDatabase();
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) javaType.getJavaType();
String name = enumClass.getSimpleName();
String[] create = database.getDialect().getCreateEnumTypeCommand( enumClass );
if ( create != null ) {
String[] drop = database.getDialect().getDropEnumTypeCommand( enumClass );
database.addAuxiliaryDatabaseObject(
new NamedAuxiliaryDatabaseObject( name, database.getDefaultNamespace(), create, drop, emptySet(), true )
);
}
}
}

View File

@ -20,15 +20,12 @@ import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext;
import org.hibernate.boot.model.process.internal.EnumeratedValueResolution;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolution;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.boot.model.process.internal.NamedBasicTypeResolution;
import org.hibernate.boot.model.process.internal.NamedConverterResolution;
import org.hibernate.boot.model.process.internal.UserTypeResolution;
import org.hibernate.boot.model.process.internal.VersionResolution;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
@ -320,18 +317,11 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
resolveColumn( (Column) selectable, getDialect() );
}
Database database = getBuildingContext().getMetadataCollector().getDatabase();
BasicValueConverter<?, ?> valueConverter = resolution.getValueConverter();
if ( valueConverter != null ) {
AuxiliaryDatabaseObject udt = valueConverter.getAuxiliaryDatabaseObject(
resolution.getJdbcType(),
database.getDialect(),
database.getDefaultNamespace()
resolution.getJdbcType()
.addAuxiliaryDatabaseObjects(
resolution.getRelationalJavaType(),
getBuildingContext().getMetadataCollector()
);
if ( udt != null ) {
database.addAuxiliaryDatabaseObject( udt );
}
}
return resolution;
}
@ -605,9 +595,9 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
);
}
if ( name.startsWith( EnumeratedValueResolution.PREFIX ) ) {
return EnumeratedValueResolution.fromName( name, stdIndicators, context );
}
// if ( name.startsWith( EnumeratedValueResolution.PREFIX ) ) {
// return EnumeratedValueResolution.fromName( name, stdIndicators, context );
// }
if ( name.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) ) {
final BasicTypeImpl<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name );

View File

@ -273,8 +273,9 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
try {
final Type type = getValue().getType();
sqlTypeName = isArray( type )
//TODO: remove the special case for array types, this should be handled by the DdlType!
? dialect.getArrayTypeName( getArrayElementTypeName( dialect, ddlTypeRegistry, getArrayElementType( type ) ) )
: ddlTypeRegistry.getTypeName( getSqlTypeCode( mapping ), getColumnSize( dialect, mapping ) );
: ddlTypeRegistry.getTypeName( getSqlTypeCode( mapping ), getColumnSize( dialect, mapping ), getUnderlyingType( mapping, type, typeIndex ) );
}
catch ( Exception cause ) {
throw new MappingException(
@ -291,6 +292,27 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
return sqlTypeName;
}
private static Type getUnderlyingType(Mapping mapping, Type type, int typeIndex) {
if ( type.isComponentType() ) {
int cols = 0;
for ( Type subtype : ((ComponentType) type).getSubtypes() ) {
int columnSpan = subtype.getColumnSpan( mapping );
if ( cols+columnSpan > typeIndex ) {
return getUnderlyingType( mapping, subtype, typeIndex-cols );
}
cols += columnSpan;
}
throw new IndexOutOfBoundsException();
}
else if ( type.isEntityType() ) {
Type idType = ((EntityType) type).getIdentifierOrUniqueKeyType(mapping);
return getUnderlyingType( mapping, idType, typeIndex );
}
else {
return type;
}
}
private String getArrayElementTypeName(Dialect dialect, DdlTypeRegistry ddlTypeRegistry, BasicType<?> elementType) {
return ddlTypeRegistry.getTypeName(
elementType.getJdbcType().getDdlTypeCode(),

View File

@ -42,8 +42,8 @@ import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.TupleType;
import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl;
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
@ -150,6 +150,7 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.JavaTypeHelper;
import org.hibernate.type.spi.TypeConfiguration;
@ -1122,7 +1123,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
@SuppressWarnings("unchecked")
public SqmExpression<Number> quot(Number x, Expression<? extends Number> y) {
return createSqmArithmeticNode(
BinaryArithmeticOperator.QUOT,
@ -1209,7 +1209,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
return new SqmLiteralNull<>( this );
}
final SqmExpressible<T> expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() );
SqmExpressible<T> expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() );
if ( expressible.getExpressibleJavaType().isInstance( value ) ) {
return new SqmLiteral<>( value, expressible, this );
}
@ -1228,21 +1228,27 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
}
@SuppressWarnings({"rawtypes","unchecked"})
private static <T> SqmExpressible<T> resolveInferredType(
T value,
SqmExpression<? extends T> typeInferenceSource,
TypeConfiguration typeConfiguration) {
if ( typeInferenceSource != null ) {
//noinspection unchecked
return (SqmExpressible<T>) typeInferenceSource.getNodeType();
}
if ( value == null ) {
else if ( value == null ) {
return null;
}
//noinspection unchecked
return (BasicType<T>) typeConfiguration.getBasicTypeForJavaType( value.getClass() );
else {
Class type = value.getClass();
BasicType<T> result = typeConfiguration.getBasicTypeForJavaType( type );
if ( result == null && value instanceof Enum ) {
return new BasicTypeImpl<>( new EnumJavaType<>( type ) );
}
else {
return result;
}
}
}
@Override
@ -1770,7 +1776,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
if ( value instanceof SqmExpression ) {
return (SqmExpression<T>) value;
}
if ( criteriaValueHandlingMode == ValueHandlingMode.INLINE ) {
if ( inlineValue( value ) ) {
return literal( value, typeInferenceSource );
}
@ -1846,7 +1852,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
if ( value instanceof SqmExpression ) {
return (SqmExpression<T>) value;
}
if ( criteriaValueHandlingMode == ValueHandlingMode.INLINE ) {
if ( inlineValue( value ) ) {
return literal( value );
}
else {
@ -1858,6 +1864,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
}
private <T> boolean inlineValue(T value) {
return criteriaValueHandlingMode == ValueHandlingMode.INLINE || value instanceof Enum
&& queryEngine.getCriteriaBuilder().getSessionFactory().getJdbcServices().getDialect().hasNativeEnums();
}
@Override
public <V, C extends Collection<V>> SqmExpression<Collection<V>> values(C collection) {
throw new UnsupportedOperationException();
@ -1905,7 +1916,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y> JpaCoalesce<Y> coalesce(Expression<? extends Y> x, Y y) {
//noinspection unchecked
return coalesce( x, value( y, (SqmExpression<? extends Y>) x ) );
}
@ -2063,7 +2073,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Expression<? extends Y> lower, Expression<? extends Y> upper) {
assertComparable( value, lower );
assertComparable( value, upper );
//noinspection unchecked
return new SqmBetweenPredicate(
(SqmExpression<? extends Y>) value,
(SqmExpression<? extends Y>) lower,
@ -2074,7 +2083,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
@SuppressWarnings("unchecked")
public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Y lower, Y upper) {
final SqmExpression<? extends Y> valueExpression = (SqmExpression<? extends Y>) value;
final SqmExpression<?> lowerExpr = value( lower, valueExpression );
@ -2208,7 +2216,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr );
@ -2232,7 +2239,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr );

View File

@ -23,6 +23,7 @@ import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
@ -200,7 +201,7 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
}
break;
case STRING:
if ( !isCharacterType(code) && code != ENUM_UNKNOWN_JDBC_TYPE ) {
if ( !isCharacterType(code) && code != SqlTypes.ENUM && code != ENUM_UNKNOWN_JDBC_TYPE) {
throwError(type, javaType, functionName, count);
}
break;

View File

@ -392,14 +392,11 @@ import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.hibernate.type.BasicType;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.JavaTypeHelper;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserVersionType;
import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
@ -410,6 +407,7 @@ import jakarta.persistence.TemporalType;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import static java.util.Collections.singletonList;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
import static org.hibernate.query.sqm.BinaryArithmeticOperator.ADD;
@ -2213,7 +2211,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( selectionNode instanceof SqmPath<?> ) {
prepareForSelection( (SqmPath<?>) selectionNode );
}
resultProducers = Collections.singletonList(
resultProducers = singletonList(
new AbstractMap.SimpleEntry<>(
sqmSelection.getAlias(),
(DomainResultProducer<?>) selectionNode.accept( this )
@ -4236,7 +4234,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(
functionDescriptor.getName(),
functionDescriptor,
Collections.singletonList( new QueryLiteral<>( 1, integerType ) ),
singletonList( new QueryLiteral<>( 1, integerType ) ),
null,
integerType,
integerType
@ -4585,7 +4583,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
arguments = subQueryColumns;
}
else {
arguments = Collections.singletonList( new SqlTuple( subQueryColumns, modelPart ) );
arguments = singletonList( new SqlTuple( subQueryColumns, modelPart ) );
}
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(
functionDescriptor.getName(),
@ -4707,7 +4705,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return new SelfRenderingFunctionSqlAstExpression(
pathName,
(sqlAppender, sqlAstArguments, walker) -> sqlAstArguments.get( 0 ).accept( walker ),
Collections.singletonList(
singletonList(
new ColumnReference(
identifierVariable,
tableReference.getColumnNames().get( 0 ),
@ -4871,9 +4869,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
mappingModelExpressible = determineCurrentExpressible( literal );
}
if ( mappingModelExpressible instanceof BasicValuedMapping ) {
return new QueryLiteral<>( null, (BasicValuedMapping) mappingModelExpressible);
return new QueryLiteral<>( null, (BasicValuedMapping) mappingModelExpressible );
}
final MappingModelExpressible<?> keyExpressible = getKeyExpressible(mappingModelExpressible);
final MappingModelExpressible<?> keyExpressible = getKeyExpressible( mappingModelExpressible );
if ( keyExpressible == null ) {
// Default to the Object type
return new QueryLiteral<>( null, basicType( Object.class ) );
@ -4897,10 +4895,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
else {
keyExpressible.forEachJdbcType(
(index, jdbcMapping) -> expressions.add(
new QueryLiteral<>(
null,
(BasicValuedMapping) jdbcMapping
)
new QueryLiteral<>( null, (BasicValuedMapping) jdbcMapping )
)
);
}
@ -4951,10 +4946,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
)
);
}
return new QueryLiteral<>(
sqlLiteralValue,
basicValuedMapping
);
return new QueryLiteral<>( sqlLiteralValue, basicValuedMapping );
}
}
@ -6472,35 +6464,27 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override
public Object visitEnumLiteral(SqmEnumLiteral<?> sqmEnumLiteral) {
final BasicValuedMapping inferrableType = (BasicValuedMapping) resolveInferredType();
if ( inferrableType != null ) {
final Object jdbcValue = inferrableType.getJdbcMapping().convertToRelationalValue( sqmEnumLiteral.getEnumValue() );
return new QueryLiteral<>( jdbcValue, inferrableType );
final BasicValuedMapping inferredType = (BasicValuedMapping) resolveInferredType();
if ( inferredType != null ) {
return new QueryLiteral<>(
inferredType.getJdbcMapping().convertToRelationalValue( sqmEnumLiteral.getEnumValue() ),
inferredType
);
}
else {
// This can only happen when selecting an enum literal, in which case we default to ordinal encoding
final EnumJavaType<?> enumJtd = sqmEnumLiteral.getExpressibleJavaType();
final TypeConfiguration typeConfiguration = getTypeConfiguration();
final JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SMALLINT );
final JavaType<Number> relationalJtd = typeConfiguration.getJavaTypeRegistry().getDescriptor( Integer.class );
return queryLiteral( sqmEnumLiteral, enumJtd, typeConfiguration, jdbcType, relationalJtd );
return queryLiteral( sqmEnumLiteral, getTypeConfiguration() );
}
}
private static <T extends Enum<T>, N extends Number> QueryLiteral<Integer> queryLiteral(
SqmEnumLiteral<?> sqmEnumLiteral,
EnumJavaType<T> enumJtd,
TypeConfiguration typeConfiguration,
JdbcType jdbcType,
JavaType<N> relationalJtd) {
private static <T extends Enum<T>> QueryLiteral<T> queryLiteral(
SqmEnumLiteral<T> sqmEnumLiteral,
TypeConfiguration typeConfiguration) {
return new QueryLiteral<>(
sqmEnumLiteral.getEnumValue().ordinal(),
new ConvertedBasicTypeImpl<>(
null,
"Query literal implicit Enum type descriptor",
jdbcType,
new OrdinalEnumValueConverter<>( enumJtd, jdbcType, relationalJtd )
sqmEnumLiteral.getEnumValue(),
new BasicTypeImpl<>(
sqmEnumLiteral.getExpressibleJavaType(),
typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SMALLINT )
)
);
}

View File

@ -13,7 +13,6 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
@ -33,7 +32,6 @@ public class QueryLiteral<T> implements Literal, DomainResultProducer<T> {
private final BasicValuedMapping type;
public QueryLiteral(T value, BasicValuedMapping type) {
assert value == null || type.getJdbcMapping().getJdbcJavaType().isInstance( value );
this.value = value;
this.type = type;
}
@ -62,9 +60,8 @@ public class QueryLiteral<T> implements Literal, DomainResultProducer<T> {
public DomainResult<T> createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState()
.getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver()
.resolveSqlSelection(
this,
type.getJdbcMapping().getJdbcJavaType(),
null,

View File

@ -159,6 +159,15 @@ public interface BasicType<T> extends Type, BasicDomainType<T>, MappingType, Bas
checkCondition = getJdbcType().getCheckCondition(
columnName,
getMappedJavaType(),
valueConverter,
dialect
);
}
if ( checkCondition == null ) {
checkCondition = getMappedJavaType().getCheckCondition(
columnName,
getJdbcType(),
valueConverter,
dialect
);
}

View File

@ -522,6 +522,13 @@ public class SqlTypes {
*/
public static final int GEOGRAPHY = 3250;
/**
* A type code representing a SQL {@code ENUM} type.
*
* @since 6.3
*/
public static final int ENUM = 6000;
private SqlTypes() {
}

View File

@ -10,7 +10,7 @@ package org.hibernate.type.descriptor.converter.internal;
* @author Gavin King
*/
public class EnumHelper {
public static final String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
public static String[] getEnumeratedValues(Class<? extends Enum<?>> enumClass) {
Enum<?>[] values = enumClass.getEnumConstants();
String[] names = new String[values.length];
for ( int i = 0; i < values.length; i++ ) {

View File

@ -8,23 +8,20 @@ package org.hibernate.type.descriptor.converter.internal;
import java.io.Serializable;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import static java.util.Collections.emptySet;
/**
* BasicValueConverter handling the conversion of an enum based on
* JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name)
*
* @author Steve Ebersole
*
* @deprecated we no longer use converters to handle enum mappings
*/
@Deprecated(since="6.3", forRemoval=true)
public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConverter<E,String>, Serializable {
private final EnumJavaType<E> domainTypeDescriptor;
private final JdbcType jdbcType;
@ -68,28 +65,4 @@ public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConv
public String toSqlLiteral(Object value) {
return "'" + ( (Enum<?>) value ).name() + "'";
}
@Override
public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) {
return dialect.getCheckCondition( columnName, getDomainJavaType().getJavaTypeClass() );
}
@Override
public String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) {
return dialect.getEnumTypeDeclaration( getDomainJavaType().getJavaTypeClass() );
}
@Override
public AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) {
Class<? extends Enum<?>> enumClass = getDomainJavaType().getJavaTypeClass();
String name = enumClass.getSimpleName();
String[] create = dialect.getCreateEnumTypeCommand( enumClass );
if ( create != null ) {
String[] drop = new String[] { "drop type " + name + " cascade" }; //TODO: move to Dialect
return new NamedAuxiliaryDatabaseObject( name, defaultNamespace, create, drop, emptySet(), true );
}
else {
return null;
}
}
}

View File

@ -1,97 +0,0 @@
/*
* 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.converter.internal;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import java.io.Serializable;
import static java.util.Collections.emptySet;
/**
* BasicValueConverter handling the conversion of an enum based on
* JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name)
*
* @author Steve Ebersole
*/
public class NativeEnumValueConverter<E extends Enum<E>> implements EnumValueConverter<E,Object>, Serializable {
private final EnumJavaType<E> domainTypeDescriptor;
private final JdbcType jdbcType;
private final JavaType<Object> relationalTypeDescriptor;
public NativeEnumValueConverter(
EnumJavaType<E> domainTypeDescriptor,
JdbcType jdbcType,
JavaType<Object> relationalTypeDescriptor) {
this.domainTypeDescriptor = domainTypeDescriptor;
this.jdbcType = jdbcType;
this.relationalTypeDescriptor = relationalTypeDescriptor;
}
@Override
public EnumJavaType<E> getDomainJavaType() {
return domainTypeDescriptor;
}
@Override
public JavaType<Object> getRelationalJavaType() {
return relationalTypeDescriptor;
}
@Override
public E toDomainValue(Object relationalForm) {
return relationalForm instanceof String
? domainTypeDescriptor.fromName( (String) relationalForm )
: (E) relationalForm;
}
@Override
public Object toRelationalValue(E domainForm) {
return domainForm;
}
@Override
public int getJdbcTypeCode() {
return jdbcType.getDefaultSqlTypeCode();
}
@Override
public String toSqlLiteral(Object value) {
return "'" + ( (Enum<?>) value ).name() + "'";
}
@Override
public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) {
return dialect.getCheckCondition( columnName, getDomainJavaType().getJavaTypeClass() );
}
@Override
public String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) {
return dialect.getEnumTypeDeclaration( getDomainJavaType().getJavaTypeClass() );
}
@Override
public AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) {
Class<? extends Enum<?>> enumClass = getDomainJavaType().getJavaTypeClass();
String name = enumClass.getSimpleName();
String[] create = dialect.getCreateEnumTypeCommand( enumClass );
if ( create != null ) {
String[] drop = new String[] { "drop type " + name + " cascade" }; //TODO: move to Dialect
return new NamedAuxiliaryDatabaseObject( name, defaultNamespace, create, drop, emptySet(), true );
}
else {
return null;
}
}
}

View File

@ -8,7 +8,6 @@ package org.hibernate.type.descriptor.converter.internal;
import java.io.Serializable;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
@ -19,7 +18,10 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
* JPA {@link jakarta.persistence.EnumType#ORDINAL} strategy (storing the ordinal)
*
* @author Steve Ebersole
*
* @deprecated we no longer use converters to handle enum mappings
*/
@Deprecated(since="6.3", forRemoval=true)
public class OrdinalEnumValueConverter<E extends Enum<E>, N extends Number> implements EnumValueConverter<E, N>, Serializable {
private final EnumJavaType<E> enumJavaType;
@ -64,10 +66,4 @@ public class OrdinalEnumValueConverter<E extends Enum<E>, N extends Number> impl
public String toSqlLiteral(Object value) {
return Integer.toString( ( (Enum<?>) value ).ordinal() );
}
@Override
public String getCheckCondition(String columnName, JdbcType jdbcType, Dialect dialect) {
int max = getDomainJavaType().getJavaTypeClass().getEnumConstants().length - 1;
return dialect.getCheckCondition( columnName, 0, max );
}
}

View File

@ -7,8 +7,6 @@
package org.hibernate.type.descriptor.converter.spi;
import org.hibernate.Incubating;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -68,9 +66,4 @@ public interface BasicValueConverter<D,R> {
default String getSpecializedTypeDeclaration(JdbcType jdbcType, Dialect dialect) {
return null;
}
@Incubating
default AuxiliaryDatabaseObject getAuxiliaryDatabaseObject(JdbcType jdbcType, Dialect dialect, Namespace defaultNamespace) {
return null;
}
}

View File

@ -9,14 +9,15 @@ package org.hibernate.type.descriptor.java;
import jakarta.persistence.EnumType;
import org.hibernate.AssertionFailure;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.NativeEnumJdbcType;
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.NCHAR;
import static org.hibernate.type.SqlTypes.NVARCHAR;
import static org.hibernate.type.SqlTypes.SMALLINT;
@ -35,7 +36,6 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
@Override
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
final JdbcTypeRegistry registry = context.getTypeConfiguration().getJdbcTypeRegistry();
final EnumType type = context.getEnumeratedType();
int sqlType;
switch ( type == null ? ORDINAL : type ) {
@ -44,7 +44,7 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
break;
case STRING:
if ( context.getDialect().hasNativeEnums() ) {
return NativeEnumJdbcType.INSTANCE;
sqlType = ENUM;
}
else if ( context.getColumnLength() == 1 ) {
sqlType = context.isNationalized() ? NCHAR : CHAR;
@ -56,7 +56,7 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
default:
throw new AssertionFailure("unknown EnumType");
}
return registry.getDescriptor( sqlType );
return context.getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( sqlType );
}
public boolean hasManyValues() {
@ -254,4 +254,21 @@ public class EnumJavaType<T extends Enum<T>> extends AbstractClassJavaType<T> {
}
}
@Override
public String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter<?, ?> converter, Dialect dialect) {
if ( converter != null ) {
//TODO: actually convert the enum values to create the check constraint
return null;
}
else if ( jdbcType.isInteger() ) {
int max = getJavaTypeClass().getEnumConstants().length - 1;
return dialect.getCheckCondition( columnName, 0, max );
}
else if ( jdbcType.isString() ) {
return dialect.getCheckCondition( columnName, getJavaTypeClass() );
}
else {
return null;
}
}
}

View File

@ -21,6 +21,7 @@ import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.spi.TypeConfiguration;
@ -332,4 +333,18 @@ public interface JavaType<T> extends Serializable {
return false;
}
/**
* The check constraint that should be added to the column
* definition in generated DDL.
*
* @param columnName the name of the column
* @param jdbcType the {@link JdbcType} of the mapped column
* @param converter the converter, if any, or null
* @param dialect the SQL {@link Dialect}
* @return a check constraint condition or null
* @since 6.2
*/
default String getCheckCondition(String columnName, JdbcType jdbcType, BasicValueConverter<?, ?> converter, Dialect dialect) {
return null;
}
}

View File

@ -15,7 +15,6 @@ import java.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterNumericData;
import org.hibernate.type.spi.TypeConfiguration;

View File

@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.Incubating;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.query.sqm.CastType;
@ -22,6 +23,7 @@ import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -156,11 +158,12 @@ public interface JdbcType extends Serializable {
*
* @param columnName the name of the column
* @param javaType the {@link JavaType} of the mapped column
* @param converter the converter, if any, or null
* @param dialect the SQL {@link Dialect}
* @return a check constraint condition or null
* @since 6.2
*/
default String getCheckCondition(String columnName, JavaType<?> javaType, Dialect dialect) {
default String getCheckCondition(String columnName, JavaType<?> javaType, BasicValueConverter<?, ?> converter, Dialect dialect) {
return null;
}
@ -322,4 +325,8 @@ public interface JdbcType extends Serializable {
default void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException {
callableStatement.registerOutParameter( index, getJdbcTypeCode() );
}
@Incubating
default void addAuxiliaryDatabaseObjects(JavaType<?> javaType, InFlightMetadataCollector metadataCollector) {
}
}

View File

@ -1,55 +0,0 @@
package org.hibernate.type.descriptor.jdbc;
import org.hibernate.type.SqlTypes;
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 java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class NativeEnumJdbcType extends VarcharJdbcType {
public static final NativeEnumJdbcType INSTANCE = new NativeEnumJdbcType();
@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.setObject( index, value, SqlTypes.OTHER );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, SqlTypes.OTHER );
}
};
}
@Override
@SuppressWarnings("unchecked")
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 (X) rs.getObject( paramIndex );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return (X) statement.getObject( index );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return (X) statement.getObject( name );
}
};
}
}

View File

@ -20,6 +20,7 @@ import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -61,7 +62,7 @@ public class OracleJsonBlobJdbcType implements AggregateJdbcType {
}
@Override
public String getCheckCondition(String columnName, JavaType<?> javaType, Dialect dialect) {
public String getCheckCondition(String columnName, JavaType<?> javaType, BasicValueConverter<?, ?> converter, Dialect dialect) {
return columnName + " is json";
}

View File

@ -89,5 +89,8 @@ public class JdbcTypeBaseline {
target.addDescriptor( new LongVarcharJdbcType(SqlTypes.LONG32NVARCHAR) );
target.addDescriptor( RowIdJdbcType.INSTANCE );
// by default, map named enums to varchar columns
target.addDescriptor( SqlTypes.ENUM, VarcharJdbcType.INSTANCE );
}
}

View File

@ -36,32 +36,46 @@ public interface DdlType extends Serializable {
*/
int getSqlTypeCode();
default String getTypeName(Size columnSize, Class<?> returnedClass) {
return getTypeName( columnSize );
}
/**
* Returns the default type name without precision/length and scale parameters.
*
* @deprecated not appropriate for named enum or array types
*/
@Deprecated(since = "6.3")
String getRawTypeName();
/**
* Returns all type names without precision/length and scale parameters.
*
* @deprecated not appropriate for named enum or array types
*/
@Incubating
@Deprecated(since = "6.3")
default String[] getRawTypeNames() {
return new String[] { getRawTypeName() };
}
String getTypeNamePattern();
/**
* Return a type with length, precision, and scale specified by the given
* {@linkplain Size size object}.
*
* @deprecated not appropriate for named enum or array types
*/
@Deprecated(since = "6.3")
default String getTypeName(Size size) {
return getTypeName( size.getLength(), size.getPrecision(), size.getScale() );
}
/**
* Return a type with the given length, precision, and scale.
*
* @deprecated not appropriate for named enum or array types
*/
@Deprecated(since = "6.3")
String getTypeName(Long size, Integer precision, Integer scale);
/**

View File

@ -63,11 +63,6 @@ public class DdlTypeImpl implements DdlType {
return typeNamePattern;
}
@Override
public String getTypeNamePattern() {
return typeNamePattern;
}
@Override
public String getTypeName(Long size, Integer precision, Integer scale) {
return replace( typeNamePattern, size, precision, scale );

View File

@ -0,0 +1,57 @@
/*
* 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.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.sql.DdlType;
import static org.hibernate.type.SqlTypes.ENUM;
/**
* @author Gavin King
*/
public class NamedNativeEnumDdlTypeImpl implements DdlType {
private final Dialect dialect;
public NamedNativeEnumDdlTypeImpl(Dialect dialect) {
this.dialect = dialect;
}
@Override
public int getSqlTypeCode() {
return ENUM;
}
@Override
public String getTypeName(Size columnSize, Class<?> returnedClass) {
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) returnedClass );
}
@Override
public String getRawTypeName() {
// this
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

@ -0,0 +1,57 @@
/*
* 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.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.sql.DdlType;
import static org.hibernate.type.SqlTypes.ENUM;
/**
* @author Gavin King
*/
public class NativeEnumDdlTypeImpl implements DdlType {
private final Dialect dialect;
public NativeEnumDdlTypeImpl(Dialect dialect) {
this.dialect = dialect;
}
@Override
public int getSqlTypeCode() {
return ENUM;
}
@Override
public String getTypeName(Size columnSize, Class<?> returnedClass) {
return dialect.getEnumTypeDeclaration( (Class<? extends Enum<?>>) returnedClass );
}
@Override
public String getRawTypeName() {
// this
return "enum";
}
@Override
public String getTypeName(Long size, Integer precision, Integer scale) {
return "varchar(" + size + ")";
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType) {
return "varchar";
}
@Override
public String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType, Long length, Integer precision, Integer scale) {
return getTypeName( length, precision, scale );
}
}

View File

@ -16,6 +16,7 @@ import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.spi.TypeConfiguration;
@ -179,11 +180,28 @@ public class DdlTypeRegistry implements Serializable {
*
* @return the associated type name with the smallest capacity that accommodates
* the given size, if available, and the default type name otherwise
*
* @deprecated not appropriate for named enum or array types
*/
@Deprecated(since = "6.3")
public String getTypeName(int typeCode, Size size) {
return getTypeName( typeCode, size.getLength(), size.getPrecision(), size.getScale() );
}
public String getTypeName(int typeCode, Size columnSize, Type type) {
final DdlType descriptor = getDescriptor( typeCode );
if ( descriptor == null ) {
throw new HibernateException(
String.format(
"No type mapping for org.hibernate.type.SqlTypes code: %s (%s)",
typeCode,
JdbcTypeNameMapper.getTypeName( typeCode )
)
);
}
return descriptor.getTypeName( columnSize, type.getReturnedClass() );
}
/**
* Get the SQL type name for the specified {@link java.sql.Types JDBC type code}
* and size, filling in the placemarkers {@code $l}, {@code $p}, and {@code $s}
@ -197,7 +215,10 @@ public class DdlTypeRegistry implements Serializable {
*
* @return the associated type name with the smallest capacity that accommodates
* the given size, if available, and the default type name otherwise
*
* @deprecated not appropriate for named enum or array types
*/
@Deprecated(since = "6.3")
public String getTypeName(int typeCode, Long size, Integer precision, Integer scale) {
final DdlType descriptor = getDescriptor( typeCode );
if ( descriptor == null ) {
@ -230,5 +251,4 @@ public class DdlTypeRegistry implements Serializable {
return false;
}
}

View File

@ -17,11 +17,9 @@ import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Value;
import org.hibernate.type.BasicType;
import org.hibernate.type.ConvertedBasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
/**