Skip to content

Commit

Permalink
HHH-16125 introduce JdbcTypeConstructor instead of using JdbcTypes as…
Browse files Browse the repository at this point in the history
… their own factories

previously, there was a global instance of ArrayJdbcType registered by the Dialects, in
an inconsistent state, that acted as a factory for correctly-initialized instances
  • Loading branch information
gavinking committed May 2, 2023
1 parent cd0504c commit 473984f
Show file tree
Hide file tree
Showing 18 changed files with 391 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
Expand Down Expand Up @@ -285,21 +285,21 @@ public JdbcType resolveSqlTypeDescriptor(
}
break;
case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) {
if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType(
return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(),
this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
ColumnTypeInformation.EMPTY
);
}
}
return jdbcType;
break;
}
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
}

if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) );
typeContributions.contributeJdbcTypeConstructor( OracleJdbcHelper.getArrayJdbcTypeConstructor( serviceRegistry ) );
}
else {
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
Expand Down Expand Up @@ -337,21 +337,21 @@ public JdbcType resolveSqlTypeDescriptor(
}
break;
case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) {
if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType(
return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(),
this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
ColumnTypeInformation.EMPTY
);
}
}
return jdbcType;
break;
case STRUCT:
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName );
if ( aggregateDescriptor != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.hibernate.type.StandardBasicTypeTemplate;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration;
Expand Down Expand Up @@ -48,6 +49,10 @@ default void contributeJdbcType(JdbcType descriptor) {
getTypeConfiguration().getJdbcTypeRegistry().addDescriptor( descriptor );
}

default void contributeJdbcTypeConstructor(JdbcTypeConstructor typeConstructor) {
getTypeConfiguration().getJdbcTypeRegistry().addTypeConstructor( typeConstructor );
}

/**
* Register a {@link UserType} as the implicit (auto-applied)
* type for values of type {@link UserType#returnedClass()}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
Expand Down Expand Up @@ -304,21 +304,21 @@ public JdbcType resolveSqlTypeDescriptor(
}
break;
case ARRAY:
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
// PostgreSQL names array types by prepending an underscore to the base name
if ( jdbcType instanceof ArrayJdbcType && columnTypeName.charAt( 0 ) == '_' ) {
if ( jdbcTypeConstructor != null && columnTypeName.charAt( 0 ) == '_' ) {
final String componentTypeName = columnTypeName.substring( 1 );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType(
return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(),
this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
ColumnTypeInformation.EMPTY
);
}
}
return jdbcType;
break;
}
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
}
Expand Down
39 changes: 21 additions & 18 deletions hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,12 @@
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.LongNVarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
Expand Down Expand Up @@ -694,25 +695,27 @@ public JdbcType resolveSqlTypeDescriptor(
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
final JdbcType jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
if ( jdbcTypeCode == Types.ARRAY && jdbcType instanceof ArrayJdbcType ) {
// Special handling for array types, because we need the proper element/component type
// To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode
final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" );
if ( arraySuffixIndex != -1 ) {
final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) {
return ( (ArrayJdbcType) jdbcType ).resolveType(
jdbcTypeRegistry.getTypeConfiguration(),
this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
ColumnTypeInformation.EMPTY
);
if ( jdbcTypeCode == ARRAY ) {
final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode );
if ( jdbcTypeConstructor != null ) {
// Special handling for array types, because we need the proper element/component type
// To determine the element JdbcType, we pass the database reported type to #resolveSqlTypeCode
final int arraySuffixIndex = columnTypeName.toLowerCase( Locale.ROOT ).indexOf( " array" );
if ( arraySuffixIndex != -1 ) {
final String componentTypeName = columnTypeName.substring( 0, arraySuffixIndex );
final Integer sqlTypeCode = resolveSqlTypeCode( componentTypeName, jdbcTypeRegistry.getTypeConfiguration() );
if ( sqlTypeCode != null ) {
return jdbcTypeConstructor.resolveType(
jdbcTypeRegistry.getTypeConfiguration(),
this,
jdbcTypeRegistry.getDescriptor( sqlTypeCode ),
ColumnTypeInformation.EMPTY
);
}
}
}
}
return jdbcType;
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
}

/**
Expand Down Expand Up @@ -1626,7 +1629,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
}

if ( supportsStandardArrays() ) {
jdbcTypeRegistry.addDescriptor( ArrayJdbcType.INSTANCE );
jdbcTypeRegistry.addTypeConstructor( ArrayJdbcTypeConstructor.INSTANCE );
}
if ( supportsMaterializedLobAccess() ) {
jdbcTypeRegistry.addDescriptor( SqlTypes.MATERIALIZED_BLOB, BlobJdbcType.MATERIALIZED );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.lang.reflect.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
Expand All @@ -17,14 +18,13 @@
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
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.internal.BasicTypeImpl;
Expand All @@ -42,49 +42,48 @@
* @author Christian Beikov
* @author Jordan Gigov
*/
public class OracleArrayJdbcType extends ArrayJdbcType {
public class OracleArrayJdbcType implements JdbcType {

private final JdbcType elementJdbcType;
private final String typeName;

public OracleArrayJdbcType() {
this( null, null );
}

public OracleArrayJdbcType(JdbcType elementJdbcType, String typeName) {
super( elementJdbcType );
this.elementJdbcType = elementJdbcType;
this.typeName = typeName;
}

@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
return null;
public int getJdbcTypeCode() {
return Types.ARRAY;
}

public JdbcType getElementJdbcType() {
return elementJdbcType;
}

@Override
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(
Integer precision,
Integer scale,
TypeConfiguration typeConfiguration) {
final JavaType<Object> elementJavaType = elementJdbcType.getJdbcRecommendedJavaTypeMapping(
precision,
scale,
typeConfiguration
);
return typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
Array.newInstance( elementJavaType.getJavaTypeClass(), 0 ).getClass()
);
}

@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect, BasicType<?> elementType,
ColumnTypeInformation columnTypeInformation) {
String typeName = columnTypeInformation.getTypeName();
if ( typeName == null || typeName.isBlank() ) {
typeName = getTypeName( elementType.getJavaTypeDescriptor(), dialect );
}
// if ( typeName == null ) {
// // Fallback to XML type for the representation of arrays as the native JSON type was only introduced in 21
// // Also, use the XML type if the Oracle JDBC driver classes are not visible
// return typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SQLXML );
// }
return new OracleArrayJdbcType( elementType.getJdbcType(), typeName );
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
return null;
}

@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
// a bit wrong!
return new OracleArrayJdbcType( elementType, columnTypeInformation.getTypeName() );
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
return java.sql.Array.class;
}

@Override
Expand Down Expand Up @@ -146,12 +145,32 @@ private java.sql.Array getArray(X value, BasicPluralJavaType<X> containerJavaTyp
};
}

private static String getTypeName(WrapperOptions options, BasicPluralJavaType<?> containerJavaType) {
@Override
public <X> ValueExtractor<X> getExtractor(final JavaType<X> javaTypeDescriptor) {
return new BasicExtractor<>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getArray( paramIndex ), options );
}

@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getArray( index ), options );
}

@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getArray( name ), options );
}
};
}

static String getTypeName(WrapperOptions options, BasicPluralJavaType<?> containerJavaType) {
Dialect dialect = options.getSessionFactory().getJdbcServices().getDialect();
return getTypeName( containerJavaType.getElementJavaType(), dialect );
}

private static String getTypeName(JavaType<?> elementJavaType, Dialect dialect) {
static String getTypeName(JavaType<?> elementJavaType, Dialect dialect) {
return dialect.getArrayTypeName(
elementJavaType.getJavaTypeClass().getSimpleName(),
null // not needed by OracleDialect.getArrayTypeName()
Expand Down Expand Up @@ -212,4 +231,14 @@ String[] getDropArrayTypeCommand(String elementTypeName) {
// String elementTypeName = getTypeName( pluralJavaType.getElementJavaType(), dialect );
// return " nested table " + columnName + " store as " + tableName + columnName + elementTypeName;
// }
@Override
public String getFriendlyName() {
return typeName;
}

@Override
public String toString() {
return "OracleArrayTypeDescriptor(" + typeName + ")";
}
}

0 comments on commit 473984f

Please sign in to comment.