HHH-16544 add support for Oracle nested tables
... and clean up of some stuff about array type initialization
This commit is contained in:
parent
18ddbe15d6
commit
7c22a537d1
|
@ -74,6 +74,7 @@ import org.hibernate.type.descriptor.java.JavaType;
|
|||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.DynamicParameterizedType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
@ -152,6 +153,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
private TemporalType temporalPrecision;
|
||||
private TimeZoneStorageType timeZoneStorageType;
|
||||
private boolean partitionKey;
|
||||
private Integer jdbcTypeCode;
|
||||
|
||||
private Table table;
|
||||
private AnnotatedColumns columns;
|
||||
|
@ -940,7 +942,13 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
if ( jdbcTypeCodeAnn != null ) {
|
||||
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
||||
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
||||
return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCode );
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
|
||||
if ( jdbcTypeRegistry.getConstructor( jdbcTypeCode ) != null ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1052,15 +1060,15 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
private void normalSupplementalDetails(XProperty attributeXProperty) {
|
||||
|
||||
explicitJavaTypeAccess = typeConfiguration -> {
|
||||
final org.hibernate.annotations.JavaType javaTypeAnn = findAnnotation( attributeXProperty, org.hibernate.annotations.JavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaType<?>> javaTypeClass = normalizeJavaType( javaTypeAnn.value() );
|
||||
final org.hibernate.annotations.JavaType javaType =
|
||||
findAnnotation( attributeXProperty, org.hibernate.annotations.JavaType.class );
|
||||
if ( javaType != null ) {
|
||||
final Class<? extends BasicJavaType<?>> javaTypeClass = normalizeJavaType( javaType.value() );
|
||||
if ( javaTypeClass != null ) {
|
||||
if ( buildingContext.getBuildingOptions().disallowExtensionsInCdi() ) {
|
||||
return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass );
|
||||
}
|
||||
final ManagedBean<? extends BasicJavaType<?>> jtdBean = getManagedBeanRegistry().getBean( javaTypeClass );
|
||||
return jtdBean.getBeanInstance();
|
||||
return getManagedBeanRegistry().getBean( javaTypeClass ).getBeanInstance();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1072,22 +1080,28 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
return null;
|
||||
};
|
||||
|
||||
final org.hibernate.annotations.JdbcTypeCode jdbcType =
|
||||
findAnnotation( attributeXProperty, org.hibernate.annotations.JdbcTypeCode.class );
|
||||
if ( jdbcType != null ) {
|
||||
jdbcTypeCode = jdbcType.value();
|
||||
}
|
||||
|
||||
normalJdbcTypeDetails( attributeXProperty);
|
||||
normalMutabilityDetails( attributeXProperty );
|
||||
|
||||
final Enumerated enumeratedAnn = attributeXProperty.getAnnotation( Enumerated.class );
|
||||
if ( enumeratedAnn != null ) {
|
||||
enumType = enumeratedAnn.value();
|
||||
final Enumerated enumerated = attributeXProperty.getAnnotation( Enumerated.class );
|
||||
if ( enumerated != null ) {
|
||||
enumType = enumerated.value();
|
||||
}
|
||||
|
||||
final Temporal temporalAnn = attributeXProperty.getAnnotation( Temporal.class );
|
||||
if ( temporalAnn != null ) {
|
||||
temporalPrecision = temporalAnn.value();
|
||||
final Temporal temporal = attributeXProperty.getAnnotation( Temporal.class );
|
||||
if ( temporal != null ) {
|
||||
temporalPrecision = temporal.value();
|
||||
}
|
||||
|
||||
final TimeZoneStorage timeZoneStorageAnn = attributeXProperty.getAnnotation( TimeZoneStorage.class );
|
||||
if ( timeZoneStorageAnn != null ) {
|
||||
timeZoneStorageType = timeZoneStorageAnn.value();
|
||||
final TimeZoneStorage timeZoneStorage = attributeXProperty.getAnnotation( TimeZoneStorage.class );
|
||||
if ( timeZoneStorage != null ) {
|
||||
timeZoneStorageType = timeZoneStorage.value();
|
||||
final TimeZoneColumn timeZoneColumnAnn = attributeXProperty.getAnnotation( TimeZoneColumn.class );
|
||||
if ( timeZoneColumnAnn != null ) {
|
||||
if ( timeZoneStorageType != TimeZoneStorageType.AUTO && timeZoneStorageType != TimeZoneStorageType.COLUMN ) {
|
||||
|
@ -1223,6 +1237,10 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
basicValue.setTemporalPrecision( temporalPrecision );
|
||||
}
|
||||
|
||||
if ( jdbcTypeCode != null ) {
|
||||
basicValue.setExplicitJdbcTypeCode( jdbcTypeCode );
|
||||
}
|
||||
|
||||
linkWithValue();
|
||||
|
||||
boolean isInSecondPass = buildingContext.getMetadataCollector().isInSecondPass();
|
||||
|
|
|
@ -72,7 +72,7 @@ public class InferredBasicValueResolver {
|
|||
|
||||
final BasicType<T> jdbcMapping;
|
||||
|
||||
if (explicitJavaType != null) {
|
||||
if ( explicitJavaType != null ) {
|
||||
// we have an explicit JavaType
|
||||
if ( isTemporal( explicitJavaType ) ) {
|
||||
return fromTemporal(
|
||||
|
@ -85,26 +85,21 @@ public class InferredBasicValueResolver {
|
|||
}
|
||||
else if ( explicitJdbcType != null ) {
|
||||
// we also have an explicit JdbcType
|
||||
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
explicitJavaType,
|
||||
explicitJdbcType
|
||||
);
|
||||
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaType, explicitJdbcType );
|
||||
}
|
||||
else {
|
||||
// we need to infer the JdbcType and use that to build the value-mapping
|
||||
final JdbcType inferredJdbcType = explicitJavaType.getRecommendedJdbcType( stdIndicators );
|
||||
if ( inferredJdbcType instanceof ObjectJdbcType && ( explicitJavaType instanceof SerializableJavaType
|
||||
|| explicitJavaType.getJavaType() instanceof Serializable ) ) {
|
||||
if ( inferredJdbcType instanceof ObjectJdbcType
|
||||
&& ( explicitJavaType instanceof SerializableJavaType
|
||||
|| explicitJavaType.getJavaType() instanceof Serializable ) ) {
|
||||
// Use the SerializableType if possible since ObjectJdbcType is our fallback
|
||||
jdbcMapping = new SerializableType( explicitJavaType );
|
||||
}
|
||||
else {
|
||||
jdbcMapping = resolveSqlTypeIndicators(
|
||||
stdIndicators,
|
||||
typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
explicitJavaType,
|
||||
inferredJdbcType
|
||||
),
|
||||
typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaType, inferredJdbcType ),
|
||||
explicitJavaType
|
||||
);
|
||||
}
|
||||
|
@ -201,10 +196,7 @@ public class InferredBasicValueResolver {
|
|||
if ( recommendedJdbcType != null ) {
|
||||
jdbcMapping = resolveSqlTypeIndicators(
|
||||
stdIndicators,
|
||||
typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
reflectedJtd,
|
||||
recommendedJdbcType
|
||||
),
|
||||
typeConfiguration.getBasicTypeRegistry().resolve( reflectedJtd, recommendedJdbcType ),
|
||||
reflectedJtd
|
||||
);
|
||||
}
|
||||
|
@ -241,18 +233,11 @@ public class InferredBasicValueResolver {
|
|||
}
|
||||
}
|
||||
|
||||
final JavaType<T> recommendedJtd = explicitJdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
length,
|
||||
scale,
|
||||
typeConfiguration
|
||||
);
|
||||
|
||||
final JavaType<T> recommendedJtd =
|
||||
explicitJdbcType.getJdbcRecommendedJavaTypeMapping( length, scale, typeConfiguration );
|
||||
jdbcMapping = resolveSqlTypeIndicators(
|
||||
stdIndicators,
|
||||
typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
recommendedJtd,
|
||||
explicitJdbcType
|
||||
),
|
||||
typeConfiguration.getBasicTypeRegistry().resolve( recommendedJtd, explicitJdbcType ),
|
||||
recommendedJtd
|
||||
);
|
||||
}
|
||||
|
|
|
@ -223,13 +223,6 @@ public class OracleArrayJdbcType implements JdbcType {
|
|||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
||||
// final Dialect dialect = database.getDialect();
|
||||
// final BasicPluralJavaType<?> pluralJavaType = (BasicPluralJavaType<?>) javaType;
|
||||
// String elementTypeName = getTypeName( pluralJavaType.getElementJavaType(), dialect );
|
||||
// return " nested table " + columnName + " store as " + tableName + columnName + elementTypeName;
|
||||
// }
|
||||
@Override
|
||||
public String getFriendlyName() {
|
||||
return typeName;
|
||||
|
|
|
@ -100,6 +100,7 @@ import static org.hibernate.LockOptions.SKIP_LOCKED;
|
|||
import static org.hibernate.LockOptions.WAIT_FOREVER;
|
||||
import static org.hibernate.cfg.AvailableSettings.BATCH_VERSIONED_DATA;
|
||||
import static org.hibernate.dialect.OracleJdbcHelper.getArrayJdbcTypeConstructor;
|
||||
import static org.hibernate.dialect.OracleJdbcHelper.getNestedTableJdbcTypeConstructor;
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.DAY;
|
||||
|
@ -125,6 +126,7 @@ import static org.hibernate.type.SqlTypes.REAL;
|
|||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.SQLXML;
|
||||
import static org.hibernate.type.SqlTypes.STRUCT;
|
||||
import static org.hibernate.type.SqlTypes.TABLE;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
|
@ -689,6 +691,7 @@ public class OracleDialect extends Dialect {
|
|||
}
|
||||
|
||||
ddlTypeRegistry.addDescriptor( new ArrayDdlTypeImpl( this ) );
|
||||
ddlTypeRegistry.addDescriptor( TABLE, new ArrayDdlTypeImpl( this ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -833,6 +836,7 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcTypeConstructor( getArrayJdbcTypeConstructor( serviceRegistry ) );
|
||||
typeContributions.contributeJdbcTypeConstructor( getNestedTableJdbcTypeConstructor( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );
|
||||
|
|
|
@ -38,11 +38,15 @@ public class OracleJdbcHelper {
|
|||
return create( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcTypeConstructor" );
|
||||
}
|
||||
|
||||
public static JdbcTypeConstructor getNestedTableJdbcTypeConstructor(ServiceRegistry serviceRegistry) {
|
||||
return create( serviceRegistry, "org.hibernate.dialect.OracleNestedTableJdbcTypeConstructor" );
|
||||
}
|
||||
|
||||
public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return create( serviceRegistry, "org.hibernate.dialect.OracleStructJdbcType" );
|
||||
}
|
||||
|
||||
public static <X> X create(ServiceRegistry serviceRegistry, String className) {
|
||||
private static <X> X create(ServiceRegistry serviceRegistry, String className) {
|
||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
try {
|
||||
return classLoaderService.<X>classForName( className ).getConstructor().newInstance();
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* 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 oracle.jdbc.OracleConnection;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.NamedAuxiliaryDatabaseObject;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
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.BasicPluralJavaType;
|
||||
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.internal.BasicTypeImpl;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
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;
|
||||
|
||||
import static java.sql.Types.ARRAY;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#ARRAY ARRAY} handling.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
* @author Jordan Gigov
|
||||
*/
|
||||
public class OracleNestedTableJdbcType implements JdbcType {
|
||||
|
||||
private final JdbcType elementJdbcType;
|
||||
private final String typeName;
|
||||
|
||||
public OracleNestedTableJdbcType(JdbcType elementJdbcType, String typeName) {
|
||||
this.elementJdbcType = elementJdbcType;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return Types.ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.TABLE;
|
||||
}
|
||||
|
||||
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 <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
|
||||
return java.sql.Array.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
final BasicPluralJavaType<X> containerJavaType = (BasicPluralJavaType<X>) javaTypeDescriptor;
|
||||
return new BasicBinder<>( javaTypeDescriptor, this ) {
|
||||
private String typeName(WrapperOptions options) {
|
||||
return ( typeName == null ? getTypeName( options, containerJavaType ) : typeName )
|
||||
.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
@Override
|
||||
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNull( index, ARRAY, typeName( options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
|
||||
st.setNull( name, ARRAY, typeName( options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||
st.setArray( index, getArray( value, containerJavaType, options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final java.sql.Array arr = getArray( value, containerJavaType, options );
|
||||
try {
|
||||
st.setObject( name, arr, ARRAY );
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
|
||||
}
|
||||
}
|
||||
|
||||
private java.sql.Array getArray(X value, BasicPluralJavaType<X> containerJavaType, WrapperOptions options)
|
||||
throws SQLException {
|
||||
//noinspection unchecked
|
||||
final Class<Object[]> arrayClass = (Class<Object[]>) Array.newInstance(
|
||||
getElementJdbcType().getPreferredJavaTypeClass( options ),
|
||||
0
|
||||
).getClass();
|
||||
final Object[] objects = javaTypeDescriptor.unwrap( value, arrayClass, options );
|
||||
final String arrayTypeName = typeName( options ).toUpperCase(Locale.ROOT);
|
||||
|
||||
final OracleConnection oracleConnection = options.getSession()
|
||||
.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||
.unwrap( OracleConnection.class );
|
||||
try {
|
||||
return oracleConnection.createOracleArray( arrayTypeName, objects );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Couldn't create a java.sql.Array", e );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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 );
|
||||
}
|
||||
|
||||
static String getTypeName(JavaType<?> elementJavaType, Dialect dialect) {
|
||||
return dialect.getArrayTypeName(
|
||||
elementJavaType.getJavaTypeClass().getSimpleName(),
|
||||
null, // not needed by OracleDialect.getArrayTypeName(),
|
||||
null // not needed by OracleDialect.getArrayTypeName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAuxiliaryDatabaseObjects(
|
||||
JavaType<?> javaType,
|
||||
Size columnSize,
|
||||
Database database,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
final Dialect dialect = database.getDialect();
|
||||
final BasicPluralJavaType<?> pluralJavaType = (BasicPluralJavaType<?>) javaType;
|
||||
final JavaType<?> elementJavaType = pluralJavaType.getElementJavaType();
|
||||
final String elementTypeName = typeName==null ? getTypeName( elementJavaType, dialect ) : typeName;
|
||||
final String elementType =
|
||||
typeConfiguration.getDdlTypeRegistry().getTypeName(
|
||||
getElementJdbcType().getDdlTypeCode(),
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
getElementJdbcType(),
|
||||
elementJavaType,
|
||||
columnSize.getPrecision(),
|
||||
columnSize.getScale(),
|
||||
columnSize.getLength()
|
||||
),
|
||||
new BasicTypeImpl<>( elementJavaType, getElementJdbcType() )
|
||||
);
|
||||
database.addAuxiliaryDatabaseObject(
|
||||
new NamedAuxiliaryDatabaseObject(
|
||||
elementTypeName,
|
||||
database.getDefaultNamespace(),
|
||||
getCreateArrayTypeCommand( elementTypeName, elementType ),
|
||||
getDropArrayTypeCommand( elementTypeName ),
|
||||
emptySet(),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
String[] getCreateArrayTypeCommand(String elementTypeName, String elementType) {
|
||||
return new String[]{
|
||||
"create or replace type " + elementTypeName
|
||||
+ " as table of " + elementType
|
||||
};
|
||||
}
|
||||
|
||||
String[] getDropArrayTypeCommand(String elementTypeName) {
|
||||
// for some weird reason dropping the type declarations causes problem in the test suite
|
||||
// return new String[] { "drop type " + elementTypeName };
|
||||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
||||
final Dialect dialect = database.getDialect();
|
||||
final BasicPluralJavaType<?> pluralJavaType = (BasicPluralJavaType<?>) javaType;
|
||||
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,0 +1,50 @@
|
|||
/*
|
||||
* 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.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Factory for {@link OracleNestedTableJdbcType}.
|
||||
*
|
||||
* @see OracleJdbcHelper#getArrayJdbcTypeConstructor
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class OracleNestedTableJdbcTypeConstructor implements JdbcTypeConstructor {
|
||||
@Override
|
||||
public JdbcType resolveType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect, BasicType<?> elementType,
|
||||
ColumnTypeInformation columnTypeInformation) {
|
||||
String typeName = columnTypeInformation.getTypeName();
|
||||
if ( typeName == null || typeName.isBlank() ) {
|
||||
typeName = OracleArrayJdbcType.getTypeName( elementType.getJavaTypeDescriptor(), dialect );
|
||||
}
|
||||
return new OracleNestedTableJdbcType( elementType.getJdbcType(), typeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType resolveType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
JdbcType elementType,
|
||||
ColumnTypeInformation columnTypeInformation) {
|
||||
// a bit wrong, since columnTypeInformation.getTypeName() is typically null!
|
||||
return new OracleNestedTableJdbcType( elementType, columnTypeInformation.getTypeName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlTypeCode() {
|
||||
return SqlTypes.TABLE;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import java.util.Properties;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
|
@ -98,6 +99,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Resolved state - available after `#resolve`
|
||||
private Resolution<?> resolution;
|
||||
private Integer jdbcTypeCode;
|
||||
|
||||
|
||||
public BasicValue(MetadataBuildingContext buildingContext) {
|
||||
|
@ -389,8 +391,8 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
protected Resolution<?> buildResolution() {
|
||||
Properties typeParameters = getTypeParameters();
|
||||
if (typeParameters != null
|
||||
&& parseBoolean(typeParameters.getProperty(DynamicParameterizedType.IS_DYNAMIC))
|
||||
if ( typeParameters != null
|
||||
&& parseBoolean( typeParameters.getProperty(DynamicParameterizedType.IS_DYNAMIC) )
|
||||
&& typeParameters.get(DynamicParameterizedType.PARAMETER_TYPE) == null ) {
|
||||
createParameterImpl();
|
||||
}
|
||||
|
@ -410,14 +412,9 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
|
||||
if ( isVersion() ) {
|
||||
return VersionResolution.from(
|
||||
implicitJavaTypeAccess,
|
||||
timeZoneStorageType,
|
||||
getBuildingContext()
|
||||
);
|
||||
return VersionResolution.from( implicitJavaTypeAccess, timeZoneStorageType, getBuildingContext() );
|
||||
}
|
||||
|
||||
|
||||
// determine JavaType if we can
|
||||
|
||||
final BasicJavaType explicitJavaType = explicitJavaTypeAccess == null ? null
|
||||
|
@ -451,8 +448,8 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
if ( javaType instanceof BasicPluralJavaType<?>
|
||||
&& !attributeConverterDescriptor.getDomainValueResolvedType()
|
||||
.getErasedType()
|
||||
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
|
||||
.getErasedType()
|
||||
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
|
||||
// In this case, the converter applies to the element of a BasicPluralJavaType
|
||||
final BasicPluralJavaType<?> containerJtd = (BasicPluralJavaType<?>) javaType;
|
||||
final BasicType registeredElementType = converterResolution.getLegacyResolvedBasicType();
|
||||
|
@ -620,7 +617,6 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
if ( name.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) ) {
|
||||
final BasicTypeImpl<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name );
|
||||
|
||||
return new NamedBasicTypeResolution<>(
|
||||
basicType.getJavaTypeDescriptor(),
|
||||
basicType,
|
||||
|
@ -896,6 +892,16 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return javaTypeClass == Byte[].class || javaTypeClass == Character[].class;
|
||||
}
|
||||
|
||||
@Incubating
|
||||
public void setExplicitJdbcTypeCode(Integer jdbcTypeCode) {
|
||||
this.jdbcTypeCode = jdbcTypeCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getExplicitJdbcTypeCode() {
|
||||
return jdbcTypeCode == null ? getPreferredSqlTypeCodeForArray() : jdbcTypeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved form of {@link BasicValue} as part of interpreting the
|
||||
* boot-time model into the run-time model
|
||||
|
|
|
@ -287,9 +287,10 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
|
|||
throw new MappingException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine SQL type name for column '%s' of table '%s'",
|
||||
"Unable to determine SQL type name for column '%s' of table '%s': %s",
|
||||
getName(),
|
||||
getValue().getTable().getName()
|
||||
getValue().getTable().getName(),
|
||||
cause.getMessage()
|
||||
),
|
||||
cause
|
||||
);
|
||||
|
|
|
@ -16,21 +16,21 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
|||
* @author Jordan Gigov
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class BasicArrayType<T>
|
||||
extends AbstractSingleColumnStandardBasicType<T[]>
|
||||
implements AdjustableBasicType<T[]>, BasicPluralType<T[], T> {
|
||||
public class BasicArrayType<T,E>
|
||||
extends AbstractSingleColumnStandardBasicType<T>
|
||||
implements AdjustableBasicType<T>, BasicPluralType<T, E> {
|
||||
|
||||
private final BasicType<T> baseDescriptor;
|
||||
private final BasicType<E> baseDescriptor;
|
||||
private final String name;
|
||||
|
||||
public BasicArrayType(BasicType<T> baseDescriptor, JdbcType arrayJdbcType, JavaType<T[]> arrayTypeDescriptor) {
|
||||
public BasicArrayType(BasicType<E> baseDescriptor, JdbcType arrayJdbcType, JavaType<T> arrayTypeDescriptor) {
|
||||
super( arrayJdbcType, arrayTypeDescriptor );
|
||||
this.baseDescriptor = baseDescriptor;
|
||||
this.name = baseDescriptor.getName() + "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType<T> getElementType() {
|
||||
public BasicType<E> getElementType() {
|
||||
return baseDescriptor;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,34 +12,70 @@ import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
|||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
||||
/**
|
||||
* A converted basic array type.
|
||||
* Given a {@link BasicValueConverter} for an array type,
|
||||
*
|
||||
* @param <E> the unconverted element type
|
||||
* @param <T> the unconverted array type
|
||||
* @param <S> the converted array type
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class ConvertedBasicArrayType<T> extends BasicArrayType<T> {
|
||||
public class ConvertedBasicArrayType<T,S,E>
|
||||
extends AbstractSingleColumnStandardBasicType<T>
|
||||
implements AdjustableBasicType<T>, BasicPluralType<T, E> {
|
||||
|
||||
private final BasicValueConverter<T[], ?> converter;
|
||||
private final ValueExtractor<T[]> jdbcValueExtractor;
|
||||
private final ValueBinder<T[]> jdbcValueBinder;
|
||||
private final JdbcLiteralFormatter<T[]> jdbcLiteralFormatter;
|
||||
private final BasicType<E> baseDescriptor;
|
||||
private final String name;
|
||||
|
||||
private final BasicValueConverter<T, S> converter;
|
||||
private final ValueExtractor<T> jdbcValueExtractor;
|
||||
private final ValueBinder<T> jdbcValueBinder;
|
||||
private final JdbcLiteralFormatter<T> jdbcLiteralFormatter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConvertedBasicArrayType(
|
||||
BasicType<T> baseDescriptor,
|
||||
BasicType<E> baseDescriptor,
|
||||
JdbcType arrayJdbcType,
|
||||
JavaType<T[]> arrayTypeDescriptor,
|
||||
BasicValueConverter<T[], ?> converter) {
|
||||
super( baseDescriptor, arrayJdbcType, arrayTypeDescriptor );
|
||||
JavaType<T> arrayTypeDescriptor,
|
||||
BasicValueConverter<T, S> converter) {
|
||||
super( arrayJdbcType, arrayTypeDescriptor );
|
||||
this.converter = converter;
|
||||
this.jdbcValueBinder = (ValueBinder<T[]>) arrayJdbcType.getBinder( converter.getRelationalJavaType() );
|
||||
this.jdbcValueExtractor = (ValueExtractor<T[]>) arrayJdbcType.getExtractor( converter.getRelationalJavaType() );
|
||||
this.jdbcLiteralFormatter = (JdbcLiteralFormatter<T[]>) arrayJdbcType.getJdbcLiteralFormatter( converter.getRelationalJavaType() );
|
||||
//TODO: these type casts look completely bogus (T==E[] and S are distinct array types)
|
||||
this.jdbcValueBinder = (ValueBinder<T>) arrayJdbcType.getBinder( converter.getRelationalJavaType() );
|
||||
this.jdbcValueExtractor = (ValueExtractor<T>) arrayJdbcType.getExtractor( converter.getRelationalJavaType() );
|
||||
this.jdbcLiteralFormatter = (JdbcLiteralFormatter<T>) arrayJdbcType.getJdbcLiteralFormatter( converter.getRelationalJavaType() );
|
||||
this.baseDescriptor = baseDescriptor;
|
||||
this.name = baseDescriptor.getName() + "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValueConverter<T[], ?> getValueConverter() {
|
||||
public BasicType<E> getElementType() {
|
||||
return baseDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerUnderJavaType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, JavaType<X> domainJtd) {
|
||||
// TODO: maybe fallback to some encoding by default if the DB doesn't support arrays natively?
|
||||
// also, maybe move that logic into the ArrayJdbcType
|
||||
//noinspection unchecked
|
||||
return (BasicType<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValueConverter<T, ?> getValueConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
|
@ -49,17 +85,17 @@ public class ConvertedBasicArrayType<T> extends BasicArrayType<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor<T[]> getJdbcValueExtractor() {
|
||||
public ValueExtractor<T> getJdbcValueExtractor() {
|
||||
return jdbcValueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueBinder<T[]> getJdbcValueBinder() {
|
||||
public ValueBinder<T> getJdbcValueBinder() {
|
||||
return jdbcValueBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcLiteralFormatter<T[]> getJdbcLiteralFormatter() {
|
||||
public JdbcLiteralFormatter<T> getJdbcLiteralFormatter() {
|
||||
return jdbcLiteralFormatter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,6 +277,13 @@ public class SqlTypes {
|
|||
*/
|
||||
public final static int ARRAY = Types.ARRAY;
|
||||
|
||||
/**
|
||||
* A type code representing an Oracle-style nested table.
|
||||
*
|
||||
* @see org.hibernate.dialect.OracleNestedTableJdbcType
|
||||
*/
|
||||
public final static int TABLE = 4000;
|
||||
|
||||
/**
|
||||
* A type code representing the generic SQL type {@code BLOB}.
|
||||
*
|
||||
|
@ -527,6 +534,8 @@ public class SqlTypes {
|
|||
* {@link org.hibernate.dialect.MySQLDialect MySQL} where {@code ENUM}
|
||||
* types do not have names.
|
||||
*
|
||||
* @see org.hibernate.dialect.MySQLEnumJdbcType
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
public static final int ENUM = 6000;
|
||||
|
@ -536,6 +545,8 @@ public class SqlTypes {
|
|||
* {@link org.hibernate.dialect.PostgreSQLDialect PostgreSQL} where
|
||||
* {@code ENUM} types must have names.
|
||||
*
|
||||
* @see org.hibernate.dialect.PostgreSQLEnumJdbcType
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
public static final int NAMED_ENUM = 6001;
|
||||
|
|
|
@ -12,72 +12,94 @@ import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
|||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
* Handles conversion to/from an array of a converted element type.
|
||||
* Given a {@link BasicValueConverter} for array elements, handles conversion
|
||||
* to and from an array of the converted element type.
|
||||
*
|
||||
* @param <E> the unconverted element type
|
||||
* @param <F> the converted element type
|
||||
* @param <T> the unconverted array type
|
||||
* @param <S> the converted array type
|
||||
*/
|
||||
public class ArrayConverter<X, Y> implements BasicValueConverter<X, Y> {
|
||||
public class ArrayConverter<T, S, E, F> implements BasicValueConverter<T, S> {
|
||||
|
||||
private final BasicValueConverter<Object, Object> elementConverter;
|
||||
private final JavaType<X> domainJavaType;
|
||||
private final JavaType<Y> relationalJavaType;
|
||||
private final BasicValueConverter<E, F> elementConverter;
|
||||
private final JavaType<T> domainJavaType;
|
||||
private final JavaType<S> relationalJavaType;
|
||||
|
||||
public ArrayConverter(
|
||||
BasicValueConverter<Object, Object> elementConverter,
|
||||
JavaType<X> domainJavaType,
|
||||
JavaType<Y> relationalJavaType) {
|
||||
BasicValueConverter<E, F> elementConverter,
|
||||
JavaType<T> domainJavaType,
|
||||
JavaType<S> relationalJavaType) {
|
||||
this.elementConverter = elementConverter;
|
||||
this.domainJavaType = domainJavaType;
|
||||
this.relationalJavaType = relationalJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X toDomainValue(Y relationalForm) {
|
||||
public T toDomainValue(S relationalForm) {
|
||||
if ( relationalForm == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( relationalForm.getClass().getComponentType() == elementConverter.getDomainJavaType().getJavaTypeClass() ) {
|
||||
//noinspection unchecked
|
||||
return (X) relationalForm;
|
||||
else {
|
||||
final Class<E> elementClass = elementConverter.getDomainJavaType().getJavaTypeClass();
|
||||
if ( relationalForm.getClass().getComponentType() == elementClass) {
|
||||
//noinspection unchecked
|
||||
return (T) relationalForm;
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
return convertTo( (F[]) relationalForm, elementClass );
|
||||
}
|
||||
}
|
||||
final Object[] relationalArray = (Object[]) relationalForm;
|
||||
final Object[] domainArray = (Object[]) Array.newInstance(
|
||||
elementConverter.getDomainJavaType().getJavaTypeClass(),
|
||||
relationalArray.length
|
||||
);
|
||||
}
|
||||
|
||||
private T convertTo(F[] relationalArray, Class<E> elementClass) {
|
||||
//TODO: the following implementation only handles conversion between non-primitive arrays!
|
||||
//noinspection unchecked
|
||||
final E[] domainArray = (E[]) Array.newInstance( elementClass, relationalArray.length );
|
||||
for ( int i = 0; i < relationalArray.length; i++ ) {
|
||||
domainArray[i] = elementConverter.toDomainValue( relationalArray[i] );
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (X) domainArray;
|
||||
return (T) domainArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Y toRelationalValue(X domainForm) {
|
||||
public S toRelationalValue(T domainForm) {
|
||||
if ( domainForm == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( domainForm.getClass().getComponentType() == elementConverter.getRelationalJavaType().getJavaTypeClass() ) {
|
||||
//noinspection unchecked
|
||||
return (Y) domainForm;
|
||||
else {
|
||||
final Class<F> elementClass = elementConverter.getRelationalJavaType().getJavaTypeClass();
|
||||
if ( domainForm.getClass().getComponentType() == elementClass) {
|
||||
//noinspection unchecked
|
||||
return (S) domainForm;
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
return convertFrom((E[]) domainForm, elementClass);
|
||||
}
|
||||
}
|
||||
final Object[] domainArray = (Object[]) domainForm;
|
||||
final Object[] relationalArray = (Object[]) Array.newInstance(
|
||||
elementConverter.getRelationalJavaType().getJavaTypeClass(),
|
||||
domainArray.length
|
||||
);
|
||||
}
|
||||
|
||||
private S convertFrom(E[] domainArray, Class<F> elementClass) {
|
||||
//TODO: the following implementation only handles conversion between non-primitive arrays!
|
||||
//noinspection unchecked
|
||||
final F[] relationalArray = (F[]) Array.newInstance( elementClass, domainArray.length );
|
||||
for ( int i = 0; i < domainArray.length; i++ ) {
|
||||
relationalArray[i] = elementConverter.toRelationalValue( domainArray[i] );
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (Y) relationalArray;
|
||||
return (S) relationalArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<X> getDomainJavaType() {
|
||||
public JavaType<T> getDomainJavaType() {
|
||||
return domainJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<Y> getRelationalJavaType() {
|
||||
public JavaType<S> getRelationalJavaType() {
|
||||
return relationalJavaType;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.sql.Types;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
|
@ -30,10 +28,6 @@ public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<
|
|||
|
||||
private final JavaType<E> componentJavaType;
|
||||
|
||||
public AbstractArrayJavaType(Class<T> clazz, BasicType<E> baseDescriptor, MutabilityPlan<T> mutabilityPlan) {
|
||||
this( clazz, baseDescriptor.getJavaTypeDescriptor(), mutabilityPlan );
|
||||
}
|
||||
|
||||
public AbstractArrayJavaType(Class<T> clazz, JavaType<E> baseDescriptor, MutabilityPlan<T> mutabilityPlan) {
|
||||
super( clazz, mutabilityPlan );
|
||||
this.componentJavaType = baseDescriptor;
|
||||
|
@ -64,39 +58,76 @@ public abstract class AbstractArrayJavaType<T, E> extends AbstractClassJavaType<
|
|||
ColumnTypeInformation columnTypeInformation,
|
||||
JdbcTypeIndicators stdIndicators) {
|
||||
final Class<?> elementJavaTypeClass = elementType.getJavaTypeDescriptor().getJavaTypeClass();
|
||||
if ( elementType instanceof BasicPluralType<?, ?> || elementJavaTypeClass != null && elementJavaTypeClass.isArray() ) {
|
||||
if ( elementType instanceof BasicPluralType<?, ?>
|
||||
|| elementJavaTypeClass != null && elementJavaTypeClass.isArray() ) {
|
||||
return null;
|
||||
}
|
||||
final BasicValueConverter<E, ?> valueConverter = elementType.getValueConverter();
|
||||
if ( valueConverter == null ) {
|
||||
final Function<JavaType<T>, BasicType<T>> creator = javaType -> {
|
||||
final JdbcType arrayJdbcType =
|
||||
getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation );
|
||||
//noinspection unchecked,rawtypes
|
||||
return new BasicArrayType( elementType, arrayJdbcType, javaType );
|
||||
};
|
||||
if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) {
|
||||
return typeConfiguration.standardBasicTypeForJavaType( getJavaType(), creator );
|
||||
}
|
||||
else {
|
||||
return creator.apply( this );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
|
||||
Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass()
|
||||
);
|
||||
//noinspection unchecked,rawtypes
|
||||
return new ConvertedBasicArrayType(
|
||||
elementType,
|
||||
getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation ),
|
||||
this,
|
||||
new ArrayConverter( valueConverter, this, relationalJavaType )
|
||||
);
|
||||
}
|
||||
return valueConverter == null
|
||||
? createType( typeConfiguration, dialect, this, elementType, columnTypeInformation, stdIndicators )
|
||||
: createTypeUsingConverter( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, valueConverter );
|
||||
}
|
||||
|
||||
private static JdbcType getArrayJdbcType(
|
||||
<F> BasicType<T> createTypeUsingConverter(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
BasicType<E> elementType,
|
||||
ColumnTypeInformation columnTypeInformation,
|
||||
JdbcTypeIndicators stdIndicators,
|
||||
BasicValueConverter<E, F> valueConverter) {
|
||||
final Class<F> convertedElementClass = valueConverter.getRelationalJavaType().getJavaTypeClass();
|
||||
final Class<?> convertedArrayClass = Array.newInstance( convertedElementClass, 0 ).getClass();
|
||||
final JavaType<?> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor( convertedArrayClass );
|
||||
return new ConvertedBasicArrayType<>(
|
||||
elementType,
|
||||
getArrayJdbcType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
stdIndicators.getExplicitJdbcTypeCode(),
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
),
|
||||
this,
|
||||
new ArrayConverter<>( valueConverter, this, relationalJavaType )
|
||||
);
|
||||
}
|
||||
|
||||
BasicType<T> createType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
AbstractArrayJavaType<T,E> arrayJavaType,
|
||||
BasicType<E> elementType,
|
||||
ColumnTypeInformation columnTypeInformation,
|
||||
JdbcTypeIndicators stdIndicators) {
|
||||
return typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType
|
||||
? typeConfiguration.standardBasicTypeForJavaType(
|
||||
arrayJavaType.getJavaType(),
|
||||
javaType -> basicArrayType( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, arrayJavaType )
|
||||
)
|
||||
: basicArrayType( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, arrayJavaType );
|
||||
}
|
||||
|
||||
BasicType<T> basicArrayType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
BasicType<E> elementType,
|
||||
ColumnTypeInformation columnTypeInformation,
|
||||
JdbcTypeIndicators stdIndicators,
|
||||
JavaType<T> javaType) {
|
||||
return new BasicArrayType<>(
|
||||
elementType,
|
||||
getArrayJdbcType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
stdIndicators.getExplicitJdbcTypeCode(),
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
),
|
||||
javaType
|
||||
);
|
||||
}
|
||||
|
||||
static JdbcType getArrayJdbcType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
int preferredSqlTypeCodeForArray,
|
||||
|
|
|
@ -9,8 +9,6 @@ package org.hibernate.type.descriptor.java;
|
|||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
|
@ -19,17 +17,11 @@ import org.hibernate.engine.jdbc.BinaryStream;
|
|||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.descriptor.converter.internal.ArrayConverter;
|
||||
import org.hibernate.type.BasicArrayType;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ConvertedBasicArrayType;
|
||||
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.JdbcTypeConstructor;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
|
@ -75,7 +67,8 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
|
|||
}
|
||||
}
|
||||
final Class<?> elementJavaTypeClass = elementType.getJavaTypeDescriptor().getJavaTypeClass();
|
||||
if ( elementType instanceof BasicPluralType<?, ?> || elementJavaTypeClass != null && elementJavaTypeClass.isArray() ) {
|
||||
if ( elementType instanceof BasicPluralType<?, ?>
|
||||
|| elementJavaTypeClass != null && elementJavaTypeClass.isArray() ) {
|
||||
return null;
|
||||
}
|
||||
final ArrayJavaType<T> arrayJavaType;
|
||||
|
@ -88,52 +81,9 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
|
|||
typeConfiguration.getJavaTypeRegistry().addDescriptor( arrayJavaType );
|
||||
}
|
||||
final BasicValueConverter<T, ?> valueConverter = elementType.getValueConverter();
|
||||
if ( valueConverter == null ) {
|
||||
final Function<JavaType<T[]>, BasicType<T[]>> creator = javaType -> {
|
||||
final JdbcType arrayJdbcType =
|
||||
getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation );
|
||||
return new BasicArrayType<>( elementType, arrayJdbcType, javaType );
|
||||
};
|
||||
if ( typeConfiguration.getBasicTypeRegistry().getRegisteredType( elementType.getName() ) == elementType ) {
|
||||
return typeConfiguration.standardBasicTypeForJavaType( arrayJavaType.getJavaType(), creator );
|
||||
}
|
||||
return creator.apply( arrayJavaType );
|
||||
}
|
||||
else {
|
||||
final JavaType<Object> relationalJavaType = typeConfiguration.getJavaTypeRegistry().getDescriptor(
|
||||
Array.newInstance( valueConverter.getRelationalJavaType().getJavaTypeClass(), 0 ).getClass()
|
||||
);
|
||||
//noinspection unchecked,rawtypes
|
||||
return new ConvertedBasicArrayType(
|
||||
elementType,
|
||||
getArrayJdbcType( typeConfiguration, dialect, Types.ARRAY, elementType, columnTypeInformation ),
|
||||
arrayJavaType,
|
||||
new ArrayConverter( valueConverter, arrayJavaType, relationalJavaType )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: copy/pasted from AbstractArrayJavaType
|
||||
private static JdbcType getArrayJdbcType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
int preferredSqlTypeCodeForArray,
|
||||
BasicType<?> elementType,
|
||||
ColumnTypeInformation columnTypeInformation) {
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
|
||||
final JdbcTypeConstructor arrayJdbcTypeConstructor =
|
||||
jdbcTypeRegistry.getConstructor( preferredSqlTypeCodeForArray );
|
||||
if ( arrayJdbcTypeConstructor != null ) {
|
||||
return arrayJdbcTypeConstructor.resolveType(
|
||||
typeConfiguration,
|
||||
dialect,
|
||||
elementType,
|
||||
columnTypeInformation
|
||||
);
|
||||
}
|
||||
else {
|
||||
return jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForArray );
|
||||
}
|
||||
return valueConverter == null
|
||||
? createType( typeConfiguration, dialect, arrayJavaType, elementType, columnTypeInformation, stdIndicators )
|
||||
: createTypeUsingConverter( typeConfiguration, dialect, elementType, columnTypeInformation, stdIndicators, valueConverter );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,14 +74,17 @@ public class ArrayJdbcType implements JdbcType {
|
|||
//noinspection unchecked
|
||||
elementJavaType = (JavaType<T>) ByteJavaType.INSTANCE;
|
||||
}
|
||||
else {
|
||||
else if (javaTypeDescriptor instanceof BasicPluralJavaType) {
|
||||
//noinspection unchecked
|
||||
elementJavaType = javaTypeDescriptor instanceof BasicPluralJavaType
|
||||
? ( (BasicPluralJavaType<T>) javaTypeDescriptor ).getElementJavaType()
|
||||
: null; //TODO: what should really happen here?
|
||||
elementJavaType = ((BasicPluralJavaType<T>) javaTypeDescriptor).getElementJavaType();
|
||||
}
|
||||
final JdbcLiteralFormatter<T> elementFormatter = elementJdbcType.getJdbcLiteralFormatter( elementJavaType );
|
||||
return new JdbcLiteralFormatterArray<>( javaTypeDescriptor, elementFormatter );
|
||||
else {
|
||||
throw new IllegalArgumentException("not a BasicPluralJavaType");
|
||||
}
|
||||
return new JdbcLiteralFormatterArray<>(
|
||||
javaTypeDescriptor,
|
||||
elementJdbcType.getJdbcLiteralFormatter( elementJavaType )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,7 @@ import jakarta.persistence.EnumType;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
@ -151,6 +152,17 @@ public interface JdbcTypeIndicators {
|
|||
return NO_COLUMN_SCALE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used (for now) only to choose a container {@link JdbcType} for
|
||||
* SQL arrays.
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
@Incubating
|
||||
default Integer getExplicitJdbcTypeCode() {
|
||||
return getPreferredSqlTypeCodeForArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default {@link TimeZoneStorageStrategy}.
|
||||
*
|
||||
|
|
|
@ -88,6 +88,7 @@ public class ConvertedBasicTypeImpl<J> implements ConvertedBasicType<J>,
|
|||
this.converter = converter;
|
||||
this.jdbcType = jdbcType;
|
||||
this.sqlTypes = new int[] { jdbcType.getDdlTypeCode() };
|
||||
//TODO: these type casts look completely bogus
|
||||
this.jdbcValueBinder = (ValueBinder<J>) jdbcType.getBinder( converter.getRelationalJavaType() );
|
||||
this.jdbcValueExtractor = (ValueExtractor<J>) jdbcType.getExtractor( converter.getRelationalJavaType() );
|
||||
this.jdbcLiteralFormatter = (JdbcLiteralFormatter<J>) jdbcType.getJdbcLiteralFormatter( converter.getRelationalJavaType() );
|
||||
|
|
|
@ -157,7 +157,7 @@ public class SessionFactoryExtension
|
|||
return sessionFactory;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException( "Could not build SessionFactory", e );
|
||||
throw new RuntimeException( "Could not build SessionFactory: " + e.getMessage(), e );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue