Skip to content

HHH-16125 POC #6232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.io.Serializable;
import java.lang.reflect.Type;
import java.sql.Types;
import java.util.function.Function;
import java.util.function.Supplier;

Expand All @@ -22,6 +23,7 @@
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.SerializableType;
import org.hibernate.type.descriptor.converter.internal.ObjectEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
import org.hibernate.type.descriptor.java.BasicJavaType;
Expand Down Expand Up @@ -333,13 +335,15 @@ public static <E extends Enum<E>, N extends Number> InferredBasicValueResolution

switch ( enumStyle ) {
case STRING: {
return stringEnumValueResolution(
enumJavaType,
explicitJavaType,
explicitJdbcType,
stdIndicators,
typeConfiguration
);
return stdIndicators.getDialect().hasNamedEnumTypes()
? objectEnumResolution( enumJavaType, typeConfiguration )
: stringEnumValueResolution(
enumJavaType,
explicitJavaType,
explicitJdbcType,
stdIndicators,
typeConfiguration
);
}
case ORDINAL: {
return ordinalEnumValueResolution(
Expand Down Expand Up @@ -437,7 +441,34 @@ private static <E extends Enum<E>> InferredBasicValueResolution<E, String> strin
final CustomType<E> customType = new CustomType<>(
new org.hibernate.type.EnumType<>(
enumJavaType.getJavaTypeClass(),
new NamedEnumValueConverter<E>(
new NamedEnumValueConverter<>(
enumJavaType,
jdbcType,
relationalJtd
),
typeConfiguration
),
typeConfiguration
);
return new InferredBasicValueResolution<>(
customType,
enumJavaType,
relationalJtd,
jdbcType,
customType,
ImmutableMutabilityPlan.instance()
);
}

private static <E extends Enum<E>> InferredBasicValueResolution<E, E> objectEnumResolution(
EnumJavaType<E> enumJavaType,
TypeConfiguration typeConfiguration) {
JavaType<E> relationalJtd = typeConfiguration.getJavaTypeRegistry().findDescriptor( Object.class );
JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.OTHER );
final CustomType<E> customType = new CustomType<>(
new org.hibernate.type.EnumType<>(
enumJavaType.getJavaTypeClass(),
new ObjectEnumValueConverter(
enumJavaType,
jdbcType,
relationalJtd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ public NamedAuxiliaryDatabaseObject(
this.name = name;
}

public NamedAuxiliaryDatabaseObject(
String name,
Namespace namespace,
String createString,
String dropString,
Set<String> dialectScopes,
boolean beforeTables) {
super( namespace, createString, dropString, dialectScopes, beforeTables );
this.name = name;
}

@Override
public String getExportIdentifier() {
return new QualifiedNameImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,41 @@ public class SimpleAuxiliaryDatabaseObject extends AbstractAuxiliaryDatabaseObje
private final String[] createStrings;
private final String[] dropStrings;

private static String extractName(Identifier identifier) {
return identifier == null ? null : identifier.getText();
}

public SimpleAuxiliaryDatabaseObject(
Namespace namespace,
String createString,
String dropString,
Set<String> dialectScopes,
boolean beforeTables) {
this(
namespace,
new String[] { createString },
new String[] { dropString },
dialectScopes,
beforeTables
);
}

public SimpleAuxiliaryDatabaseObject(
Namespace namespace,
String[] createStrings,
String[] dropStrings,
Set<String> dialectScopes,
boolean beforeTables) {
this(
dialectScopes,
extractName( namespace.getPhysicalName().getCatalog() ),
extractName( namespace.getPhysicalName().getSchema() ),
createStrings,
dropStrings,
beforeTables
);
}

public SimpleAuxiliaryDatabaseObject(
Namespace namespace,
String createString,
Expand Down Expand Up @@ -57,8 +92,19 @@ public SimpleAuxiliaryDatabaseObject(
);
}

private static String extractName(Identifier identifier) {
return identifier == null ? null : identifier.getText();

public SimpleAuxiliaryDatabaseObject(
Set<String> dialectScopes,
String catalogName,
String schemaName,
String[] createStrings,
String[] dropStrings,
boolean beforeTables) {
super( beforeTables, dialectScopes );
this.catalogName = catalogName;
this.schemaName = schemaName;
this.createStrings = createStrings;
this.dropStrings = dropStrings;
}

public SimpleAuxiliaryDatabaseObject(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,15 @@ public String getEnumTypeDeclaration(String[] values) {
return null;
}

/**
* Does this database support PostgreSQL-style named {@code enum} types,
* that is, does it support the syntax {@code create type ... as enum .... }.
*/
@Incubating
public boolean hasNamedEnumTypes() {
return false;
}

/**
* Render a SQL check condition for a column that represents an enumerated value
* by its {@linkplain jakarta.persistence.EnumType#STRING string representation}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
Expand Down Expand Up @@ -113,7 +112,6 @@
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithNanos;

/**
* A {@linkplain Dialect SQL dialect} for MySQL 5.7 and above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,29 @@ protected Integer resolveSqlTypeCode(String columnTypeName, TypeConfiguration ty
return super.resolveSqlTypeCode( columnTypeName, typeConfiguration );
}

@Override
public String getEnumTypeDeclaration(String[] values) {
StringBuilder type = new StringBuilder();
type.append( "enum (" );
String separator = "";
for ( String value : values ) {
type.append( separator ).append('\'').append( value ).append('\'');
separator = ",";
}
return type.append( ')' ).toString();
}

@Override
public String getCheckCondition(String columnName, String[] values) {
//not needed, because we use an 'enum' type
return null;
}

@Override
public boolean hasNamedEnumTypes() {
return true;
}

@Override
public String currentTime() {
return "localtime";
Expand Down
15 changes: 15 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
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;
Expand Down Expand Up @@ -316,6 +318,19 @@ public Resolution<?> resolve() {
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()
);
if ( udt != null ) {
database.addAuxiliaryDatabaseObject( udt );
}
}

return resolution;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,28 @@ private static void appendColumnDefinition(
Table table,
Metadata metadata,
Dialect dialect) {
final String columnType = column.getSqlType(metadata);
if ( isIdentityColumn(column, table, metadata, dialect) ) {
if ( isIdentityColumn( column, table, metadata, dialect ) ) {
// to support dialects that have their own identity data type
if ( dialect.getIdentityColumnSupport().hasDataTypeInIdentityColumn() ) {
final String columnType = column.getSqlType( metadata );
definition.append( ' ' ).append( columnType );
}
final String identityColumnString = dialect.getIdentityColumnSupport()
.getIdentityColumnString( column.getSqlTypeCode(metadata) );
definition.append( ' ' ).append( identityColumnString );
}
else {
final String columnType;
if ( column.hasSpecializedTypeDeclaration() ) {
definition.append( ' ' ).append( column.getSpecializedTypeDeclaration() );
}
else if ( column.getGeneratedAs() == null || dialect.hasDataTypeBeforeGeneratedAs() ) {
columnType = column.getSpecializedTypeDeclaration();
definition.append( ' ' ).append( columnType );
}
else {
columnType = column.getSqlType( metadata );
if ( column.getGeneratedAs() == null || dialect.hasDataTypeBeforeGeneratedAs() ) {
definition.append( ' ' ).append( columnType );
}
}

final String defaultValue = column.getDefaultValue();
if ( defaultValue != null ) {
Expand Down
16 changes: 14 additions & 2 deletions hibernate-core/src/main/java/org/hibernate/type/CustomType.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,20 @@ else if ( userType instanceof UserVersionType ) {
valueExtractor = (ValueExtractor<J>) jdbcType.getExtractor( jdbcJavaType );
//noinspection unchecked
valueBinder = (ValueBinder<J>) jdbcType.getBinder( jdbcJavaType );
//noinspection unchecked
jdbcLiteralFormatter = (JdbcLiteralFormatter<J>) jdbcType.getJdbcLiteralFormatter( jdbcJavaType );
if ( userType instanceof EnhancedUserType ) {
// because of the way QueryLiteral handling is implemented in the
// BaseSqmToSqlAstConverter.visitEnumLiteral(), we can't just use
// jdbcType.getJdbcLiteralFormatter( mappedJavaType ) here, since
// we need to un-convert the value back to the enum type
// TODO: sort this out!
EnhancedUserType enhancedUserType = (EnhancedUserType) userType;
jdbcLiteralFormatter = (appender, value, dialect, wrapperOptions)
-> appender.appendSql( enhancedUserType.toSqlLiteral( convertToDomainValue( value ) ) );
}
else {
//noinspection unchecked
jdbcLiteralFormatter = (JdbcLiteralFormatter<J>) jdbcType.getJdbcLiteralFormatter( jdbcJavaType );
}
}
else {
// create a JdbcType adapter that uses the UserType binder/extract handling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package org.hibernate.type.descriptor.converter.internal;

import java.io.Serializable;
import java.util.Locale;

import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
Expand All @@ -19,8 +18,9 @@
import static org.hibernate.type.descriptor.converter.internal.EnumHelper.getEnumeratedValues;

/**
* BasicValueConverter handling the conversion of an enum based on
* JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name)
* {@link org.hibernate.type.descriptor.converter.spi.BasicValueConverter} handling the
* conversion of an enum according to the JPA-defined {@link jakarta.persistence.EnumType#STRING}
* strategy (storing the name)
*
* @author Steve Ebersole
*/
Expand Down Expand Up @@ -65,8 +65,7 @@ public int getJdbcTypeCode() {

@Override
public String toSqlLiteral(Object value) {
//noinspection rawtypes
return String.format( Locale.ROOT, "'%s'", ( (Enum) value ).name() );
return "'" + ( (Enum) value ).name() + "'";
}

@Override
Expand Down
Loading