HHH-16224 Refactor discovery of exact JDBC drivers, avoid static state in specialized types
This commit is contained in:
parent
02b7c5afb5
commit
8d93c0ca33
|
@ -30,15 +30,11 @@ import org.hibernate.boot.model.TypeContributions;
|
|||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.NationalizationSupport;
|
||||
import org.hibernate.dialect.PgJdbcHelper;
|
||||
import org.hibernate.dialect.PostgreSQLCastingInetJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLCastingIntervalSecondJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLCastingJsonJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLDriverKind;
|
||||
import org.hibernate.dialect.PostgreSQLInetJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLJsonJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLJsonbJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLPGObjectJdbcType;
|
||||
import org.hibernate.dialect.RowLockStrategy;
|
||||
import org.hibernate.dialect.SimpleDatabaseVersion;
|
||||
import org.hibernate.dialect.SpannerDialect;
|
||||
|
@ -331,15 +327,15 @@ public class CockroachLegacyDialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantAsTimestampWithTimeZoneJdbcType.INSTANCE );
|
||||
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );
|
||||
|
||||
if ( getVersion().isSameOrAfter( 20, 0 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonJdbcType( serviceRegistry ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -23,12 +23,11 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.dialect.BooleanDecoder;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleArrayJdbcType;
|
||||
import org.hibernate.dialect.OracleBooleanJdbcType;
|
||||
import org.hibernate.dialect.OracleJdbcHelper;
|
||||
import org.hibernate.dialect.OracleJsonJdbcType;
|
||||
import org.hibernate.dialect.OracleReflectionStructJdbcType;
|
||||
import org.hibernate.dialect.OracleTypes;
|
||||
import org.hibernate.dialect.OracleStructJdbcType;
|
||||
import org.hibernate.dialect.OracleTypesHelper;
|
||||
import org.hibernate.dialect.OracleXmlJdbcType;
|
||||
import org.hibernate.dialect.Replacer;
|
||||
import org.hibernate.dialect.RowLockStrategy;
|
||||
|
@ -94,6 +93,7 @@ import org.hibernate.type.SqlTypes;
|
|||
import org.hibernate.type.StandardBasicTypes;
|
||||
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.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
|
||||
|
@ -777,7 +777,12 @@ public class OracleLegacyDialect extends Dialect {
|
|||
|
||||
typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( OracleStructJdbcType.INSTANCE );
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );
|
||||
}
|
||||
|
||||
if ( getVersion().isSameOrAfter( 12 ) ) {
|
||||
// account for Oracle's deprecated support for LONGVARBINARY
|
||||
|
@ -802,7 +807,12 @@ public class OracleLegacyDialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
typeContributions.contributeJdbcType( OracleArrayJdbcType.INSTANCE );
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
typeContributions.contributeJdbcType( ArrayJdbcType.INSTANCE );
|
||||
}
|
||||
// Oracle requires a custom binder for binding untyped nulls with the NULL type
|
||||
typeContributions.contributeJdbcType( NullJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( ObjectNullAsNullTypeJdbcType.INSTANCE );
|
||||
|
@ -984,7 +994,7 @@ public class OracleLegacyDialect extends Dialect {
|
|||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
|
||||
// register the type of the out param - an Oracle specific type
|
||||
statement.registerOutParameter( col, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() );
|
||||
statement.registerOutParameter( col, OracleTypes.CURSOR );
|
||||
col++;
|
||||
return col;
|
||||
}
|
||||
|
@ -1371,7 +1381,7 @@ public class OracleLegacyDialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException {
|
||||
statement.registerOutParameter( name, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() );
|
||||
statement.registerOutParameter( name, OracleTypes.CURSOR );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,17 +30,12 @@ import org.hibernate.dialect.DatabaseVersion;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.NationalizationSupport;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.PgJdbcHelper;
|
||||
import org.hibernate.dialect.PostgreSQLCastingInetJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLCastingIntervalSecondJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLCastingJsonJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLCastingStructJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLDriverKind;
|
||||
import org.hibernate.dialect.PostgreSQLInetJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLJsonJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLJsonbJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLPGObjectJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLStructJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLStructCastingJdbcType;
|
||||
import org.hibernate.dialect.Replacer;
|
||||
import org.hibernate.dialect.RowLockStrategy;
|
||||
import org.hibernate.dialect.SelectItemReferenceStrategy;
|
||||
|
@ -1334,15 +1329,15 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptor( XmlJdbcType.INSTANCE );
|
||||
|
||||
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getStructJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE );
|
||||
}
|
||||
|
||||
if ( getVersion().isSameOrAfter( 8, 2 ) ) {
|
||||
|
@ -1350,16 +1345,16 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
if ( getVersion().isSameOrAfter( 9, 2 ) ) {
|
||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSON_INSTANCE );
|
||||
|
@ -1371,7 +1366,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE );
|
||||
|
||||
if ( getVersion().isSameOrAfter( 8, 2 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
|
|
|
@ -45,6 +45,7 @@ dependencies {
|
|||
compileOnly jakartaLibs.jsonbApi
|
||||
compileOnly libs.jackson
|
||||
compileOnly libs.jacksonXml
|
||||
compileOnly dbLibs.postgresql
|
||||
|
||||
testImplementation project(':hibernate-testing')
|
||||
testImplementation project(':hibernate-ant')
|
||||
|
|
|
@ -1,74 +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.dialect;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public abstract class AbstractPostgreSQLJsonJdbcType extends PostgreSQLPGObjectJdbcType implements AggregateJdbcType {
|
||||
|
||||
private final EmbeddableMappingType embeddableMappingType;
|
||||
|
||||
public AbstractPostgreSQLJsonJdbcType(EmbeddableMappingType embeddableMappingType, String typeName) {
|
||||
super( typeName, SqlTypes.JSON );
|
||||
this.embeddableMappingType = embeddableMappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getEmbeddableMappingType() {
|
||||
return embeddableMappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> X fromString(String string, JavaType<X> javaType, WrapperOptions options) throws SQLException {
|
||||
if ( embeddableMappingType != null ) {
|
||||
return JsonHelper.fromString(
|
||||
embeddableMappingType,
|
||||
string,
|
||||
javaType.getJavaTypeClass() != Object[].class,
|
||||
options
|
||||
);
|
||||
}
|
||||
return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().fromString(
|
||||
string,
|
||||
javaType,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
|
||||
if ( embeddableMappingType != null ) {
|
||||
return JsonHelper.toString( embeddableMappingType, value, options );
|
||||
}
|
||||
return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().toString(
|
||||
value,
|
||||
javaType,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException {
|
||||
assert embeddableMappingType != null;
|
||||
return JsonHelper.toString( embeddableMappingType, domainValue, options );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
||||
assert embeddableMappingType != null;
|
||||
return JsonHelper.fromString( embeddableMappingType, (String) rawJdbcValue, false, options );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
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 org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
|
||||
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public abstract class AbstractPostgreSQLJsonPGObjectType extends JsonJdbcType {
|
||||
|
||||
private final boolean jsonb;
|
||||
protected AbstractPostgreSQLJsonPGObjectType(EmbeddableMappingType embeddableMappingType, boolean jsonb) {
|
||||
super( embeddableMappingType );
|
||||
this.jsonb = jsonb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.OTHER;
|
||||
}
|
||||
|
||||
@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 {
|
||||
final String stringValue = ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( jsonb ? "jsonb" : "json" );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( index, holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( jsonb ? "jsonb" : "json" );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( name, holder );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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 getObject( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getObject( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getObject( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getObject(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
return ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).fromString(
|
||||
object.toString(),
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
|
@ -30,6 +34,7 @@ import org.hibernate.metamodel.mapping.MappingType;
|
|||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
@ -39,6 +44,7 @@ import org.hibernate.type.descriptor.java.JavaType;
|
|||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
|
||||
|
@ -54,9 +60,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType implements AggregateJdbcType {
|
||||
|
||||
public static final PostgreSQLStructJdbcType INSTANCE = new PostgreSQLStructJdbcType( null, null, null );
|
||||
public abstract class AbstractPostgreSQLStructJdbcType implements AggregateJdbcType {
|
||||
|
||||
private static final DateTimeFormatter LOCAL_DATE_TIME;
|
||||
static {
|
||||
|
@ -83,14 +87,16 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
.appendOffset( "+HH:mm", "+00" )
|
||||
.toFormatter();
|
||||
}
|
||||
|
||||
private final String typeName;
|
||||
private final int[] orderMapping;
|
||||
private final int[] inverseOrderMapping;
|
||||
private final EmbeddableMappingType embeddableMappingType;
|
||||
private final ValueExtractor<Object[]> objectArrayExtractor;
|
||||
|
||||
public PostgreSQLStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
|
||||
super( typeName, SqlTypes.STRUCT );
|
||||
protected AbstractPostgreSQLStructJdbcType(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
String typeName,
|
||||
int[] orderMapping) {
|
||||
this.typeName = typeName;
|
||||
this.embeddableMappingType = embeddableMappingType;
|
||||
this.orderMapping = orderMapping;
|
||||
if ( orderMapping == null ) {
|
||||
|
@ -103,10 +109,6 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
}
|
||||
this.inverseOrderMapping = inverseOrderMapping;
|
||||
}
|
||||
// We cache the extractor for Obje
|
||||
// We cache the extractor for Object[] here
|
||||
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
|
||||
this.objectArrayExtractor = super.getExtractor( new UnknownBasicJavaType<>( Object[].class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,20 +116,8 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
return SqlTypes.STRUCT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregateJdbcType resolveAggregateJdbcType(
|
||||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new PostgreSQLStructJdbcType(
|
||||
mappingType,
|
||||
sqlType,
|
||||
creationContext.getBootModel()
|
||||
.getDatabase()
|
||||
.getDefaultNamespace()
|
||||
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
|
||||
.getOrderMapping()
|
||||
);
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -151,14 +141,36 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
|
||||
if ( javaType.getJavaTypeClass() == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
return (ValueExtractor<X>) objectArrayExtractor;
|
||||
}
|
||||
return super.getExtractor( javaType );
|
||||
return new BasicExtractor<>( javaType, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
return getObject( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getObject( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getObject( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getObject(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
return ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).fromString(
|
||||
object.toString(),
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected <X> X fromString(String string, JavaType<X> javaType, WrapperOptions options) throws SQLException {
|
||||
if ( string == null ) {
|
||||
return null;
|
||||
|
@ -407,9 +419,9 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
if ( string.charAt( i + 1 ) == '(' ) {
|
||||
// This could be a nested struct
|
||||
final JdbcMapping jdbcMapping = getJdbcValueSelectable( column ).getJdbcMapping();
|
||||
if ( jdbcMapping.getJdbcType() instanceof PostgreSQLStructJdbcType ) {
|
||||
final PostgreSQLStructJdbcType structJdbcType;
|
||||
structJdbcType = (PostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
|
||||
if ( jdbcMapping.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) {
|
||||
final AbstractPostgreSQLStructJdbcType structJdbcType;
|
||||
structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
|
||||
final Object[] subValues = new Object[structJdbcType.embeddableMappingType.getJdbcValueCount()];
|
||||
final int subEnd = structJdbcType.deserializeStruct(
|
||||
string,
|
||||
|
@ -655,7 +667,6 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
|
@ -718,7 +729,7 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
|
|||
continue;
|
||||
}
|
||||
appender.quoteStart();
|
||||
( (PostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo(
|
||||
( (AbstractPostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo(
|
||||
appender,
|
||||
attributeValue,
|
||||
options
|
|
@ -342,10 +342,10 @@ public class CockroachDialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantAsTimestampWithTimeZoneJdbcType.INSTANCE );
|
||||
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
package org.hibernate.dialect;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
|
@ -29,7 +28,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import oracle.jdbc.OracleConnection;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#ARRAY ARRAY} handling.
|
||||
|
@ -39,43 +38,14 @@ import org.jboss.logging.Logger;
|
|||
*/
|
||||
public class OracleArrayJdbcType extends ArrayJdbcType {
|
||||
|
||||
public static final OracleArrayJdbcType INSTANCE = new OracleArrayJdbcType( null, ObjectJdbcType.INSTANCE );
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OracleArrayJdbcType.class.getName() );
|
||||
private static final ClassValue<Method> NAME_BINDER = new ClassValue<Method>() {
|
||||
@Override
|
||||
protected Method computeValue(Class<?> type) {
|
||||
try {
|
||||
return type.getMethod( "setArray", String.class, java.sql.Array.class );
|
||||
}
|
||||
catch ( Exception ex ) {
|
||||
// add logging? Did we get NoSuchMethodException or SecurityException?
|
||||
// Doesn't matter which. We can't use it.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
private static final Class<?> ORACLE_CONNECTION_CLASS;
|
||||
private static final Method CREATE_ARRAY_METHOD;
|
||||
|
||||
static {
|
||||
Class<?> oracleConnectionClass = null;
|
||||
Method createArrayMethod = null;
|
||||
try {
|
||||
oracleConnectionClass = Class.forName( "oracle.jdbc.OracleConnection" );
|
||||
createArrayMethod = oracleConnectionClass.getMethod( "createOracleArray", String.class, Object.class );
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Ignore since #resolveType should be called anyway and the OracleArrayJdbcType shouldn't be used
|
||||
// if driver classes are unavailable
|
||||
LOG.warn( "Oracle JDBC driver classes are inaccessible and thus, certain DDL types like ARRAY can not be used!", e );
|
||||
}
|
||||
ORACLE_CONNECTION_CLASS = oracleConnectionClass;
|
||||
CREATE_ARRAY_METHOD = createArrayMethod;
|
||||
}
|
||||
|
||||
private final String typeName;
|
||||
|
||||
public OracleArrayJdbcType(String typeName, JdbcType elementJdbcType) {
|
||||
public OracleArrayJdbcType() {
|
||||
super( ObjectJdbcType.INSTANCE );
|
||||
this.typeName = null;
|
||||
}
|
||||
|
||||
private OracleArrayJdbcType(String typeName, JdbcType elementJdbcType) {
|
||||
super( elementJdbcType );
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
@ -101,7 +71,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
)
|
||||
);
|
||||
}
|
||||
if ( typeName == null || CREATE_ARRAY_METHOD == null ) {
|
||||
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 );
|
||||
|
@ -111,9 +81,6 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
|
||||
if ( CREATE_ARRAY_METHOD == null ) {
|
||||
throw new RuntimeException( "OracleArrayJdbcType shouldn't be used since JDBC driver classes are not visible." );
|
||||
}
|
||||
//noinspection unchecked
|
||||
final BasicPluralJavaType<X> containerJavaType = (BasicPluralJavaType<X>) javaTypeDescriptor;
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
@ -137,27 +104,13 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final java.sql.Array arr = getArray( value, containerJavaType, options );
|
||||
final Method nameBinder = NAME_BINDER.get( st.getClass() );
|
||||
if ( nameBinder == null ) {
|
||||
try {
|
||||
st.setObject( name, arr, Types.ARRAY );
|
||||
return;
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
|
||||
}
|
||||
}
|
||||
// Not that it's supposed to have setArray(String,Array) by standard.
|
||||
// There are numerous missing methods that only have versions for positional parameter,
|
||||
// but not named ones.
|
||||
|
||||
try {
|
||||
nameBinder.invoke( st, name, arr );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new HibernateException( t );
|
||||
}
|
||||
}
|
||||
|
||||
private java.sql.Array getArray(
|
||||
X value,
|
||||
|
@ -171,10 +124,10 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
final Object[] objects = javaTypeDescriptor.unwrap( value, arrayClass, options );
|
||||
|
||||
final SharedSessionContractImplementor session = options.getSession();
|
||||
final Object oracleConnection = session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||
.unwrap( ORACLE_CONNECTION_CLASS );
|
||||
final OracleConnection oracleConnection = session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection()
|
||||
.unwrap( OracleConnection.class );
|
||||
try {
|
||||
return (java.sql.Array) CREATE_ARRAY_METHOD.invoke( oracleConnection, typeName, objects );
|
||||
return oracleConnection.createOracleArray( typeName, objects );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Couldn't create a java.sql.Array", e );
|
||||
|
@ -194,11 +147,11 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
|
||||
OracleArrayJdbcType that = (OracleArrayJdbcType) o;
|
||||
|
||||
return typeName.equals( that.typeName );
|
||||
return Objects.equals( typeName, that.typeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return typeName.hashCode();
|
||||
return typeName != null ? typeName.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ import org.hibernate.type.NullType;
|
|||
import org.hibernate.type.StandardBasicTypes;
|
||||
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.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
|
||||
|
@ -782,7 +783,12 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( OracleStructJdbcType.INSTANCE );
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );
|
||||
}
|
||||
|
||||
if ( getVersion().isSameOrAfter( 12 ) ) {
|
||||
// account for Oracle's deprecated support for LONGVARBINARY
|
||||
|
@ -807,7 +813,12 @@ public class OracleDialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
typeContributions.contributeJdbcType( OracleArrayJdbcType.INSTANCE );
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE );
|
||||
}
|
||||
// Oracle requires a custom binder for binding untyped nulls with the NULL type
|
||||
typeContributions.contributeJdbcType( NullJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( ObjectNullAsNullTypeJdbcType.INSTANCE );
|
||||
|
@ -976,7 +987,7 @@ public class OracleDialect extends Dialect {
|
|||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
|
||||
// register the type of the out param - an Oracle specific type
|
||||
statement.registerOutParameter( col, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() );
|
||||
statement.registerOutParameter( col, OracleTypes.CURSOR );
|
||||
col++;
|
||||
return col;
|
||||
}
|
||||
|
@ -1374,7 +1385,7 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException {
|
||||
statement.registerOutParameter( name, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() );
|
||||
statement.registerOutParameter( name, OracleTypes.CURSOR );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.hibernate.HibernateError;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* The following class provides some convenience methods for accessing JdbcType instance,
|
||||
* that are loaded into the app class loader, where they have access to the JDBC driver classes.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class OracleJdbcHelper {
|
||||
|
||||
public static boolean isUsable(ServiceRegistry serviceRegistry) {
|
||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
try {
|
||||
classLoaderService.classForName( "oracle.jdbc.OracleConnection" );
|
||||
return true;
|
||||
}
|
||||
catch (ClassLoadingException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static JdbcType getArrayJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcType" );
|
||||
}
|
||||
|
||||
public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleStructJdbcType" );
|
||||
}
|
||||
|
||||
public static JdbcType createJdbcType(ServiceRegistry serviceRegistry, String className) {
|
||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
try {
|
||||
final Class<?> clazz = classLoaderService.classForName( className );
|
||||
final Constructor<?> constructor = clazz.getConstructor();
|
||||
return (JdbcType) constructor.newInstance();
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new HibernateError( "Class does not have an empty constructor", e );
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new HibernateError( "Could not construct JdbcType", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class OracleReflectionStructJdbcType extends StructJdbcType {
|
||||
public static final AggregateJdbcType INSTANCE = new OracleReflectionStructJdbcType();
|
||||
|
||||
private static final ClassValue<Method> RAW_JDBC_TRANSFORMER = new ClassValue<>() {
|
||||
@Override
|
||||
protected Method computeValue(Class<?> type) {
|
||||
if ( "oracle.sql.TIMESTAMPTZ".equals( type.getName() ) ) {
|
||||
try {
|
||||
return type.getMethod( "offsetDateTimeValue", Connection.class );
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private OracleReflectionStructJdbcType() {
|
||||
// The default instance is for reading only and will return an Object[]
|
||||
this( null, null, null );
|
||||
}
|
||||
|
||||
public OracleReflectionStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
|
||||
super(
|
||||
embeddableMappingType,
|
||||
typeName == null ? null : typeName.toUpperCase( Locale.ROOT ),
|
||||
orderMapping
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregateJdbcType resolveAggregateJdbcType(
|
||||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new OracleReflectionStructJdbcType(
|
||||
mappingType,
|
||||
sqlType,
|
||||
creationContext.getBootModel()
|
||||
.getDatabase()
|
||||
.getDefaultNamespace()
|
||||
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
|
||||
.getOrderMapping()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||
Method rawJdbcTransformer = RAW_JDBC_TRANSFORMER.get( rawJdbcValue.getClass() );
|
||||
if ( rawJdbcTransformer == null ) {
|
||||
return rawJdbcValue;
|
||||
}
|
||||
try {
|
||||
return rawJdbcTransformer.invoke(
|
||||
rawJdbcValue,
|
||||
options.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getPhysicalConnection()
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Could not transform the raw jdbc value", e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,88 +6,33 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Struct;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
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 org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import oracle.sql.TIMESTAMPTZ;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class OracleStructJdbcType implements AggregateJdbcType {
|
||||
public class OracleStructJdbcType extends StructJdbcType {
|
||||
|
||||
public static final AggregateJdbcType INSTANCE = new OracleStructJdbcType();
|
||||
|
||||
private static final ClassValue<Method> RAW_JDBC_TRANSFORMER = new ClassValue<>() {
|
||||
@Override
|
||||
protected Method computeValue(Class<?> type) {
|
||||
if ( "oracle.sql.TIMESTAMPTZ".equals( type.getName() ) ) {
|
||||
try {
|
||||
return type.getMethod( "offsetDateTimeValue", Connection.class );
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final String oracleTypeName;
|
||||
private final int[] orderMapping;
|
||||
private final int[] inverseOrderMapping;
|
||||
private final EmbeddableMappingType embeddableMappingType;
|
||||
private final ValueExtractor<Object[]> objectArrayExtractor;
|
||||
|
||||
private OracleStructJdbcType() {
|
||||
public OracleStructJdbcType() {
|
||||
// The default instance is for reading only and will return an Object[]
|
||||
this( null, null, null );
|
||||
}
|
||||
|
||||
public OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
|
||||
this.embeddableMappingType = embeddableMappingType;
|
||||
this.oracleTypeName = typeName == null ? null : typeName.toUpperCase( Locale.ROOT );
|
||||
this.orderMapping = orderMapping;
|
||||
if ( orderMapping == null ) {
|
||||
this.inverseOrderMapping = null;
|
||||
}
|
||||
else {
|
||||
final int[] inverseOrderMapping = new int[orderMapping.length];
|
||||
for ( int i = 0; i < orderMapping.length; i++ ) {
|
||||
inverseOrderMapping[orderMapping[i]] = i;
|
||||
}
|
||||
this.inverseOrderMapping = inverseOrderMapping;
|
||||
}
|
||||
// We cache the extractor for Object[] here
|
||||
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
|
||||
this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.STRUCT;
|
||||
private OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
|
||||
super(
|
||||
embeddableMappingType,
|
||||
typeName == null ? null : typeName.toUpperCase( Locale.ROOT ),
|
||||
orderMapping
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,320 +52,10 @@ public class OracleStructJdbcType implements AggregateJdbcType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getEmbeddableMappingType() {
|
||||
return embeddableMappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( embeddableMappingType == null ) {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor( Object[].class );
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
return (JavaType<T>) embeddableMappingType.getMappedJavaType();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutParameter(CallableStatement callableStatement, String name) throws SQLException {
|
||||
callableStatement.registerOutParameter( name, getJdbcTypeCode(), oracleTypeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException {
|
||||
callableStatement.registerOutParameter( index, getJdbcTypeCode(), oracleTypeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException {
|
||||
final Object[] jdbcValues = StructHelper.getJdbcValues(
|
||||
embeddableMappingType,
|
||||
orderMapping,
|
||||
embeddableMappingType.getValues( domainValue ),
|
||||
options
|
||||
);
|
||||
return options.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getPhysicalConnection()
|
||||
.createStruct( oracleTypeName, jdbcValues );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
||||
final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes();
|
||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options );
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@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, createJdbcValue( value, options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setObject( name, createJdbcValue( value, options ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
|
||||
if ( javaType.getJavaTypeClass() == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
return (ValueExtractor<X>) objectArrayExtractor;
|
||||
}
|
||||
return createBasicExtractor( javaType );
|
||||
}
|
||||
|
||||
private <X> BasicExtractor<X> createBasicExtractor(JavaType<X> javaType) {
|
||||
return new BasicExtractor<>( javaType, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
return getValue( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getValue( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getValue( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getValue(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
final Struct struct = (Struct) object;
|
||||
final Object[] values = struct.getAttributes();
|
||||
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
|
||||
if ( jdbcRepresentation ) {
|
||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, values, 0, options );
|
||||
//noinspection unchecked
|
||||
return (X) values;
|
||||
}
|
||||
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
|
||||
final Object[] attributeValues = getAttributeValues(
|
||||
embeddableMappingType,
|
||||
orderMapping,
|
||||
values,
|
||||
options
|
||||
);
|
||||
//noinspection unchecked
|
||||
return (X) embeddableMappingType.getRepresentationStrategy().getInstantiator().instantiate(
|
||||
() -> attributeValues,
|
||||
options.getSessionFactory()
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Object[] getAttributeValues(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int[] orderMapping,
|
||||
Object[] rawJdbcValues,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
final Object[] attributeValues;
|
||||
if ( numberOfAttributeMappings != rawJdbcValues.length || orderMapping != null ) {
|
||||
attributeValues = new Object[numberOfAttributeMappings];
|
||||
}
|
||||
else {
|
||||
attributeValues = rawJdbcValues;
|
||||
}
|
||||
int jdbcIndex = 0;
|
||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||
final int attributeIndex;
|
||||
if ( orderMapping == null ) {
|
||||
attributeIndex = i;
|
||||
}
|
||||
else {
|
||||
attributeIndex = orderMapping[i];
|
||||
}
|
||||
final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( attributeIndex );
|
||||
jdbcIndex += injectAttributeValue(
|
||||
attributeMapping,
|
||||
attributeValues,
|
||||
attributeIndex,
|
||||
rawJdbcValues,
|
||||
jdbcIndex,
|
||||
options
|
||||
);
|
||||
}
|
||||
return attributeValues;
|
||||
}
|
||||
|
||||
private static int injectAttributeValue(
|
||||
AttributeMapping attributeMapping,
|
||||
Object[] attributeValues,
|
||||
int attributeIndex,
|
||||
Object[] rawJdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
final int jdbcValueCount;
|
||||
final Object rawJdbcValue = rawJdbcValues[jdbcIndex];
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||
if ( embeddableMappingType.getAggregateMapping() != null ) {
|
||||
jdbcValueCount = 1;
|
||||
if ( rawJdbcValue == null ) {
|
||||
attributeValues[attributeIndex] = null;
|
||||
}
|
||||
else {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
final Object[] subValues;
|
||||
if ( aggregateJdbcType instanceof OracleStructJdbcType ) {
|
||||
subValues = getAttributeValues(
|
||||
embeddableMappingType,
|
||||
( (OracleStructJdbcType) aggregateJdbcType ).orderMapping,
|
||||
( (Struct) rawJdbcValue ).getAttributes(),
|
||||
options
|
||||
);
|
||||
}
|
||||
else {
|
||||
subValues = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
}
|
||||
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
|
||||
.getInstantiator()
|
||||
.instantiate(
|
||||
() -> subValues,
|
||||
embeddableMappingType.findContainingEntityMapping()
|
||||
.getEntityPersister()
|
||||
.getFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
jdbcValueCount = embeddableMappingType.getJdbcValueCount();
|
||||
final Object[] jdbcValues = new Object[jdbcValueCount];
|
||||
System.arraycopy( rawJdbcValues, jdbcIndex, jdbcValues, 0, jdbcValues.length );
|
||||
final Object[] subValues = getAttributeValues( embeddableMappingType, null, jdbcValues, options );
|
||||
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
|
||||
.getInstantiator()
|
||||
.instantiate(
|
||||
() -> subValues,
|
||||
embeddableMappingType.findContainingEntityMapping()
|
||||
.getEntityPersister()
|
||||
.getFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||
jdbcValueCount = 1;
|
||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
||||
final Object jdbcValue;
|
||||
if ( rawJdbcValue == null ) {
|
||||
jdbcValue = null;
|
||||
}
|
||||
else {
|
||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||
case SqlTypes.TIMESTAMP_UTC:
|
||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||
jdbcValue = jdbcMapping.getJdbcJavaType()
|
||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||
break;
|
||||
default:
|
||||
jdbcValue = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributeValues[attributeIndex] = jdbcMapping.convertToDomainValue( jdbcValue );
|
||||
}
|
||||
return jdbcValueCount;
|
||||
}
|
||||
|
||||
private static int wrapRawJdbcValues(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int[] orderMapping,
|
||||
int[] inverseOrderMapping,
|
||||
Object[] jdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final Object[] targetJdbcValues;
|
||||
if ( orderMapping == null ) {
|
||||
targetJdbcValues = jdbcValues;
|
||||
}
|
||||
else {
|
||||
targetJdbcValues = jdbcValues.clone();
|
||||
}
|
||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||
final AttributeMapping attributeMapping;
|
||||
if ( orderMapping == null ) {
|
||||
attributeMapping = embeddableMappingType.getAttributeMapping( i );
|
||||
}
|
||||
else {
|
||||
attributeMapping = embeddableMappingType.getAttributeMapping( orderMapping[i] );
|
||||
}
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType;
|
||||
if ( embeddableType.getAggregateMapping() != null ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
jdbcIndex++;
|
||||
}
|
||||
else {
|
||||
jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
if ( rawJdbcValue != null ) {
|
||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||
case SqlTypes.TIMESTAMP_UTC:
|
||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||
break;
|
||||
default:
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
}
|
||||
jdbcIndex++;
|
||||
}
|
||||
}
|
||||
if ( orderMapping != null ) {
|
||||
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues );
|
||||
}
|
||||
return jdbcIndex;
|
||||
}
|
||||
|
||||
private static Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||
Method rawJdbcTransformer = RAW_JDBC_TRANSFORMER.get( rawJdbcValue.getClass() );
|
||||
if ( rawJdbcTransformer == null ) {
|
||||
return rawJdbcValue;
|
||||
}
|
||||
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||
if ( rawJdbcValue.getClass() == TIMESTAMPTZ.class ) {
|
||||
try {
|
||||
return rawJdbcTransformer.invoke(
|
||||
rawJdbcValue,
|
||||
return ( (TIMESTAMPTZ) rawJdbcValue ).offsetDateTimeValue(
|
||||
options.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
|
@ -431,5 +66,7 @@ public class OracleStructJdbcType implements AggregateJdbcType {
|
|||
throw new HibernateException( "Could not transform the raw jdbc value", e );
|
||||
}
|
||||
}
|
||||
return rawJdbcValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,5 +10,6 @@ package org.hibernate.dialect;
|
|||
* The Oracle specific JDBC type code.
|
||||
*/
|
||||
public class OracleTypes {
|
||||
public static final int CURSOR = -10;
|
||||
public static final int JSON = 2016;
|
||||
}
|
||||
|
|
|
@ -1,111 +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.dialect;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* A Helper for dealing with the OracleTypes class
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OracleTypesHelper {
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger( CoreMessageLogger.class, OracleTypesHelper.class.getName() );
|
||||
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final OracleTypesHelper INSTANCE = new OracleTypesHelper();
|
||||
|
||||
private static final String ORACLE_TYPES_CLASS_NAME = "oracle.jdbc.OracleTypes";
|
||||
private static final String DEPRECATED_ORACLE_TYPES_CLASS_NAME = "oracle.jdbc.driver.OracleTypes";
|
||||
|
||||
private final int oracleCursorTypeSqlType;
|
||||
|
||||
private OracleTypesHelper() {
|
||||
int typeCode = -99;
|
||||
try {
|
||||
typeCode = extractOracleCursorTypeValue();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn( "Unable to resolve Oracle CURSOR JDBC type code: the class OracleTypesHelper was initialized but the Oracle JDBC driver could not be loaded." );
|
||||
}
|
||||
oracleCursorTypeSqlType = typeCode;
|
||||
}
|
||||
|
||||
private int extractOracleCursorTypeValue() {
|
||||
try {
|
||||
return locateOracleTypesClass().getField( "CURSOR" ).getInt( null );
|
||||
}
|
||||
catch ( Exception se ) {
|
||||
throw new HibernateException( "Unable to access OracleTypes.CURSOR value", se );
|
||||
}
|
||||
}
|
||||
|
||||
private Class locateOracleTypesClass() {
|
||||
try {
|
||||
return ReflectHelper.classForName( ORACLE_TYPES_CLASS_NAME );
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
try {
|
||||
return ReflectHelper.classForName( DEPRECATED_ORACLE_TYPES_CLASS_NAME );
|
||||
}
|
||||
catch (ClassNotFoundException e2) {
|
||||
throw new HibernateException(
|
||||
String.format(
|
||||
"Unable to locate OracleTypes class using either known FQN [%s, %s]",
|
||||
ORACLE_TYPES_CLASS_NAME,
|
||||
DEPRECATED_ORACLE_TYPES_CLASS_NAME
|
||||
),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getOracleCursorTypeSqlType() {
|
||||
return oracleCursorTypeSqlType;
|
||||
}
|
||||
|
||||
// initial code as copied from Oracle8iDialect
|
||||
//
|
||||
// private int oracleCursorTypeSqlType = INIT_ORACLETYPES_CURSOR_VALUE;
|
||||
//
|
||||
// public int getOracleCursorTypeSqlType() {
|
||||
// if ( oracleCursorTypeSqlType == INIT_ORACLETYPES_CURSOR_VALUE ) {
|
||||
// // todo : is there really any reason to keep trying if this fails once?
|
||||
// oracleCursorTypeSqlType = extractOracleCursorTypeValue();
|
||||
// }
|
||||
// return oracleCursorTypeSqlType;
|
||||
// }
|
||||
//
|
||||
// private int extractOracleCursorTypeValue() {
|
||||
// Class oracleTypesClass;
|
||||
// try {
|
||||
// oracleTypesClass = ReflectHelper.classForName( ORACLE_TYPES_CLASS_NAME );
|
||||
// }
|
||||
// catch ( ClassNotFoundException cnfe ) {
|
||||
// try {
|
||||
// oracleTypesClass = ReflectHelper.classForName( DEPRECATED_ORACLE_TYPES_CLASS_NAME );
|
||||
// }
|
||||
// catch ( ClassNotFoundException e ) {
|
||||
// throw new HibernateException( "Unable to locate OracleTypes class", e );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// return oracleTypesClass.getField( "CURSOR" ).getInt( null );
|
||||
// }
|
||||
// catch ( Exception se ) {
|
||||
// throw new HibernateException( "Unable to access OracleTypes.CURSOR value", se );
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.hibernate.HibernateError;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* The following class provides some convenience methods for accessing JdbcType instance,
|
||||
* that are loaded into the app class loader, where they have access to the JDBC driver classes.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public final class PgJdbcHelper {
|
||||
|
||||
public static boolean isUsable(ServiceRegistry serviceRegistry) {
|
||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
try {
|
||||
classLoaderService.classForName( "org.postgresql.util.PGobject" );
|
||||
return true;
|
||||
}
|
||||
catch (ClassLoadingException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLStructPGObjectJdbcType" );
|
||||
}
|
||||
|
||||
public static JdbcType getIntervalJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType" );
|
||||
}
|
||||
|
||||
public static JdbcType getInetJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLInetJdbcType" );
|
||||
}
|
||||
|
||||
public static JdbcType getJsonJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLJsonPGObjectJsonType" );
|
||||
}
|
||||
|
||||
public static JdbcType getJsonbJdbcType(ServiceRegistry serviceRegistry) {
|
||||
return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType" );
|
||||
}
|
||||
|
||||
public static JdbcType createJdbcType(ServiceRegistry serviceRegistry, String className) {
|
||||
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
try {
|
||||
final Class<?> clazz = classLoaderService.classForName( className );
|
||||
final Constructor<?> constructor = clazz.getConstructor();
|
||||
return (JdbcType) constructor.newInstance();
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new HibernateError( "Class does not have an empty constructor", e );
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new HibernateError( "Could not construct JdbcType", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1337,16 +1337,16 @@ public class PostgreSQLDialect extends Dialect {
|
|||
if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) {
|
||||
// HHH-9562
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE );
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getStructJdbcType( serviceRegistry ) );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) );
|
||||
}
|
||||
else {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE );
|
||||
}
|
||||
}
|
||||
|
@ -1354,7 +1354,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE );
|
||||
}
|
||||
|
||||
|
|
|
@ -6,22 +6,45 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
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 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.postgresql.util.PGobject;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLInetJdbcType extends PostgreSQLPGObjectJdbcType {
|
||||
public class PostgreSQLInetJdbcType implements JdbcType {
|
||||
|
||||
public static final PostgreSQLInetJdbcType INSTANCE = new PostgreSQLInetJdbcType();
|
||||
|
||||
public PostgreSQLInetJdbcType() {
|
||||
super( "inet", SqlTypes.INET );
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return Types.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlTypeCode() {
|
||||
return SqlTypes.INET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
// No literal support for now
|
||||
return null;
|
||||
}
|
||||
|
||||
protected <X> X fromString(String string, JavaType<X> javaType, WrapperOptions options) {
|
||||
final String host;
|
||||
if ( string == null ) {
|
||||
|
@ -39,4 +62,61 @@ public class PostgreSQLInetJdbcType extends PostgreSQLPGObjectJdbcType {
|
|||
}
|
||||
return javaType.wrap( host, options );
|
||||
}
|
||||
|
||||
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
|
||||
return javaType.unwrap( value, String.class, options );
|
||||
}
|
||||
|
||||
@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 {
|
||||
final String stringValue = PostgreSQLInetJdbcType.this.toString( value, getJavaType(), options );
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( "inet" );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( index, holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = PostgreSQLInetJdbcType.this.toString( value, getJavaType(), options );
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( "inet" );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( name, holder );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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 getObject( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getObject( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getObject( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getObject(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
return fromString( object.toString(), getJavaType(), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -16,8 +13,6 @@ import java.sql.SQLException;
|
|||
import java.sql.Types;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
|
@ -30,62 +25,16 @@ import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
|||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
||||
import org.postgresql.util.PGInterval;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType {
|
||||
|
||||
public static final PostgreSQLIntervalSecondJdbcType INSTANCE = new PostgreSQLIntervalSecondJdbcType();
|
||||
private static final Class<?> PG_INTERVAL_CLASS;
|
||||
private static final Constructor<Object> PG_INTERVAL_CONSTRUCTOR;
|
||||
private static final Method PG_INTERVAL_GET_DAYS;
|
||||
private static final Method PG_INTERVAL_GET_HOURS;
|
||||
private static final Method PG_INTERVAL_GET_MINUTES;
|
||||
private static final Method PG_INTERVAL_GET_SECONDS;
|
||||
private static final Method PG_INTERVAL_GET_MICRO_SECONDS;
|
||||
private static final long SECONDS_PER_DAY = 86400;
|
||||
private static final long SECONDS_PER_HOUR = 3600;
|
||||
private static final long SECONDS_PER_MINUTE = 60;
|
||||
|
||||
static {
|
||||
Constructor<Object> constructor;
|
||||
Class<?> pgIntervalClass;
|
||||
Method pgIntervalGetDays;
|
||||
Method pgIntervalGetHours;
|
||||
Method pgIntervalGetMinutes;
|
||||
Method pgIntervalGetSeconds;
|
||||
Method pgIntervalGetMicroSeconds;
|
||||
try {
|
||||
pgIntervalClass = ReflectHelper.classForName(
|
||||
"org.postgresql.util.PGInterval",
|
||||
PostgreSQLIntervalSecondJdbcType.class
|
||||
);
|
||||
constructor = (Constructor<Object>) pgIntervalClass.getConstructor(
|
||||
int.class,
|
||||
int.class,
|
||||
int.class,
|
||||
int.class,
|
||||
int.class,
|
||||
double.class
|
||||
);
|
||||
pgIntervalGetDays = pgIntervalClass.getDeclaredMethod( "getDays" );
|
||||
pgIntervalGetHours = pgIntervalClass.getDeclaredMethod( "getHours" );
|
||||
pgIntervalGetMinutes = pgIntervalClass.getDeclaredMethod( "getMinutes" );
|
||||
pgIntervalGetSeconds = pgIntervalClass.getDeclaredMethod( "getWholeSeconds" );
|
||||
pgIntervalGetMicroSeconds = pgIntervalClass.getDeclaredMethod( "getMicroSeconds" );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException( "Could not initialize PostgreSQLPGObjectJdbcType", e );
|
||||
}
|
||||
PG_INTERVAL_CLASS = pgIntervalClass;
|
||||
PG_INTERVAL_CONSTRUCTOR = constructor;
|
||||
PG_INTERVAL_GET_DAYS = pgIntervalGetDays;
|
||||
PG_INTERVAL_GET_HOURS = pgIntervalGetHours;
|
||||
PG_INTERVAL_GET_MINUTES = pgIntervalGetMinutes;
|
||||
PG_INTERVAL_GET_SECONDS = pgIntervalGetSeconds;
|
||||
PG_INTERVAL_GET_MICRO_SECONDS = pgIntervalGetMicroSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return Types.OTHER;
|
||||
|
@ -161,8 +110,7 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType {
|
|||
double seconds = ( (double) ( secondsLong - minutesLong * 60 ) )
|
||||
+ ( (double) d.getNano() ) / 1_000_000_000d;
|
||||
|
||||
try {
|
||||
return PG_INTERVAL_CONSTRUCTOR.newInstance(
|
||||
return new PGInterval(
|
||||
0,// years
|
||||
0, // months
|
||||
days,
|
||||
|
@ -171,10 +119,6 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType {
|
|||
seconds
|
||||
);
|
||||
}
|
||||
catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -198,20 +142,16 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType {
|
|||
}
|
||||
|
||||
private Object getValue(Object value) {
|
||||
if ( PG_INTERVAL_CLASS.isInstance( value ) ) {
|
||||
try {
|
||||
final long seconds = (int) PG_INTERVAL_GET_SECONDS.invoke( value )
|
||||
+ SECONDS_PER_DAY * (int) PG_INTERVAL_GET_DAYS.invoke( value )
|
||||
+ SECONDS_PER_HOUR * (int) PG_INTERVAL_GET_HOURS.invoke( value )
|
||||
+ SECONDS_PER_MINUTE * (int) PG_INTERVAL_GET_MINUTES.invoke( value );
|
||||
final long nanos = 1000L * (int) PG_INTERVAL_GET_MICRO_SECONDS.invoke( value );
|
||||
if ( value instanceof PGInterval ) {
|
||||
final PGInterval interval = (PGInterval) value;
|
||||
final long seconds = ( (long) interval.getSeconds() )
|
||||
+ SECONDS_PER_DAY * ( (long) interval.getDays() )
|
||||
+ SECONDS_PER_HOUR * ( (long) interval.getHours() )
|
||||
+ SECONDS_PER_MINUTE * ( (long) interval.getMinutes() );
|
||||
final long nanos = 1000L * ( (long) interval.getMicroSeconds() );
|
||||
|
||||
return Duration.ofSeconds( seconds, nanos );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Couldn't create Duration from interval", e );
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,12 +13,12 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
|||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLJsonbJdbcType extends AbstractPostgreSQLJsonJdbcType {
|
||||
|
||||
public static final PostgreSQLJsonbJdbcType INSTANCE = new PostgreSQLJsonbJdbcType( null );
|
||||
|
||||
public PostgreSQLJsonbJdbcType(EmbeddableMappingType embeddableMappingType) {
|
||||
super( embeddableMappingType, "jsonb" );
|
||||
public class PostgreSQLJsonPGObjectJsonType extends AbstractPostgreSQLJsonPGObjectType {
|
||||
public PostgreSQLJsonPGObjectJsonType() {
|
||||
this( null, false );
|
||||
}
|
||||
private PostgreSQLJsonPGObjectJsonType(EmbeddableMappingType embeddableMappingType, boolean jsonb) {
|
||||
super( embeddableMappingType, jsonb );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,6 +26,6 @@ public class PostgreSQLJsonbJdbcType extends AbstractPostgreSQLJsonJdbcType {
|
|||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new PostgreSQLJsonbJdbcType( mappingType );
|
||||
return new PostgreSQLJsonPGObjectJsonType( mappingType, false );
|
||||
}
|
||||
}
|
|
@ -13,12 +13,13 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
|||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLJsonJdbcType extends AbstractPostgreSQLJsonJdbcType {
|
||||
public class PostgreSQLJsonPGObjectJsonbType extends AbstractPostgreSQLJsonPGObjectType {
|
||||
|
||||
public static final PostgreSQLJsonJdbcType INSTANCE = new PostgreSQLJsonJdbcType( null );
|
||||
|
||||
private PostgreSQLJsonJdbcType(EmbeddableMappingType embeddableMappingType) {
|
||||
super( embeddableMappingType, "json" );
|
||||
public PostgreSQLJsonPGObjectJsonbType() {
|
||||
this( null, true );
|
||||
}
|
||||
protected PostgreSQLJsonPGObjectJsonbType(EmbeddableMappingType embeddableMappingType, boolean jsonb) {
|
||||
super( embeddableMappingType, jsonb );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,7 +27,6 @@ public class PostgreSQLJsonJdbcType extends AbstractPostgreSQLJsonJdbcType {
|
|||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new PostgreSQLJsonJdbcType( mappingType );
|
||||
return new PostgreSQLJsonPGObjectJsonbType( mappingType, true );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,176 +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.dialect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public abstract class PostgreSQLPGObjectJdbcType implements JdbcType {
|
||||
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( PostgreSQLPGObjectJdbcType.class );
|
||||
private static final Constructor<Object> PG_OBJECT_CONSTRUCTOR;
|
||||
private static final Method TYPE_SETTER;
|
||||
private static final Method VALUE_SETTER;
|
||||
|
||||
static {
|
||||
Constructor<Object> constructor = null;
|
||||
Method typeSetter = null;
|
||||
Method valueSetter = null;
|
||||
try {
|
||||
final Class<?> pgObjectClass = ReflectHelper.classForName(
|
||||
"org.postgresql.util.PGobject",
|
||||
PostgreSQLPGObjectJdbcType.class
|
||||
);
|
||||
//noinspection unchecked
|
||||
constructor = (Constructor<Object>) pgObjectClass.getConstructor();
|
||||
typeSetter = ReflectHelper.setterMethodOrNull( pgObjectClass, "type", String.class );
|
||||
valueSetter = ReflectHelper.setterMethodOrNull( pgObjectClass, "value", String.class );
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.postgreSQLJdbcDriverNotAccessible();
|
||||
}
|
||||
PG_OBJECT_CONSTRUCTOR = constructor;
|
||||
TYPE_SETTER = typeSetter;
|
||||
VALUE_SETTER = valueSetter;
|
||||
}
|
||||
|
||||
private final String typeName;
|
||||
private final int sqlTypeCode;
|
||||
|
||||
public PostgreSQLPGObjectJdbcType(String typeName, int sqlTypeCode) {
|
||||
this.typeName = typeName;
|
||||
this.sqlTypeCode = sqlTypeCode;
|
||||
}
|
||||
|
||||
public static boolean isUsable() {
|
||||
return PG_OBJECT_CONSTRUCTOR != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return Types.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlTypeCode() {
|
||||
return sqlTypeCode;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
protected <X> X fromString(String string, JavaType<X> javaType, WrapperOptions options) throws SQLException {
|
||||
return javaType.wrap( string, options );
|
||||
}
|
||||
|
||||
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
|
||||
return javaType.unwrap( value, String.class, options );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
|
||||
// No literal support for now
|
||||
return null;
|
||||
}
|
||||
|
||||
@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 {
|
||||
final String stringValue = ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
try {
|
||||
Object holder = PG_OBJECT_CONSTRUCTOR.newInstance();
|
||||
TYPE_SETTER.invoke( holder, typeName );
|
||||
VALUE_SETTER.invoke( holder, stringValue );
|
||||
st.setObject( index, holder );
|
||||
}
|
||||
catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
try {
|
||||
Object holder = PG_OBJECT_CONSTRUCTOR.newInstance();
|
||||
TYPE_SETTER.invoke( holder, typeName );
|
||||
VALUE_SETTER.invoke( holder, stringValue );
|
||||
st.setObject( name, holder );
|
||||
}
|
||||
catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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 getObject( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getObject( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getObject( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getObject(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
return ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).fromString(
|
||||
object.toString(),
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -23,11 +23,14 @@ import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
|||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType {
|
||||
public class PostgreSQLStructCastingJdbcType extends AbstractPostgreSQLStructJdbcType {
|
||||
|
||||
public static final PostgreSQLCastingStructJdbcType INSTANCE = new PostgreSQLCastingStructJdbcType( null, null, null );
|
||||
public static final PostgreSQLStructCastingJdbcType INSTANCE = new PostgreSQLStructCastingJdbcType();
|
||||
public PostgreSQLStructCastingJdbcType() {
|
||||
this( null, null, null );
|
||||
}
|
||||
|
||||
public PostgreSQLCastingStructJdbcType(
|
||||
private PostgreSQLStructCastingJdbcType(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
String typeName,
|
||||
int[] orderMapping) {
|
||||
|
@ -39,7 +42,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType {
|
|||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new PostgreSQLCastingStructJdbcType(
|
||||
return new PostgreSQLStructCastingJdbcType(
|
||||
mappingType,
|
||||
sqlType,
|
||||
creationContext.getBootModel()
|
||||
|
@ -68,7 +71,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType {
|
|||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = ( (PostgreSQLCastingStructJdbcType) getJdbcType() ).toString(
|
||||
final String stringValue = ( (PostgreSQLStructCastingJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
|
@ -79,7 +82,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType {
|
|||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = ( (PostgreSQLCastingStructJdbcType) getJdbcType() ).toString(
|
||||
final String stringValue = ( (PostgreSQLStructCastingJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
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.java.spi.UnknownBasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLStructPGObjectJdbcType extends AbstractPostgreSQLStructJdbcType {
|
||||
|
||||
private final ValueExtractor<Object[]> objectArrayExtractor;
|
||||
|
||||
public PostgreSQLStructPGObjectJdbcType() {
|
||||
this( null, null, null );
|
||||
}
|
||||
|
||||
private PostgreSQLStructPGObjectJdbcType(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
String typeName,
|
||||
int[] orderMapping) {
|
||||
super( embeddableMappingType, typeName, orderMapping );
|
||||
this.objectArrayExtractor = super.getExtractor( new UnknownBasicJavaType<>( Object[].class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregateJdbcType resolveAggregateJdbcType(
|
||||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new PostgreSQLStructPGObjectJdbcType(
|
||||
mappingType,
|
||||
sqlType,
|
||||
creationContext.getBootModel()
|
||||
.getDatabase()
|
||||
.getDefaultNamespace()
|
||||
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
|
||||
.getOrderMapping()
|
||||
);
|
||||
}
|
||||
|
||||
@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 {
|
||||
final String stringValue = ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( getTypeName() );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( index, holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String stringValue = ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).toString(
|
||||
value,
|
||||
getJavaType(),
|
||||
options
|
||||
);
|
||||
final PGobject holder = new PGobject();
|
||||
holder.setType( getTypeName() );
|
||||
holder.setValue( stringValue );
|
||||
st.setObject( name, holder );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
|
||||
if ( javaType.getJavaTypeClass() == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
return (ValueExtractor<X>) objectArrayExtractor;
|
||||
}
|
||||
return super.getExtractor( javaType );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* 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 java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Struct;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
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 org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class StructJdbcType implements AggregateJdbcType {
|
||||
|
||||
public static final AggregateJdbcType INSTANCE = new StructJdbcType();
|
||||
|
||||
private final String typeName;
|
||||
private final int[] orderMapping;
|
||||
private final int[] inverseOrderMapping;
|
||||
private final EmbeddableMappingType embeddableMappingType;
|
||||
private final ValueExtractor<Object[]> objectArrayExtractor;
|
||||
|
||||
private StructJdbcType() {
|
||||
// The default instance is for reading only and will return an Object[]
|
||||
this( null, null, null );
|
||||
}
|
||||
|
||||
public StructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
|
||||
this.embeddableMappingType = embeddableMappingType;
|
||||
this.typeName = typeName;
|
||||
this.orderMapping = orderMapping;
|
||||
if ( orderMapping == null ) {
|
||||
this.inverseOrderMapping = null;
|
||||
}
|
||||
else {
|
||||
final int[] inverseOrderMapping = new int[orderMapping.length];
|
||||
for ( int i = 0; i < orderMapping.length; i++ ) {
|
||||
inverseOrderMapping[orderMapping[i]] = i;
|
||||
}
|
||||
this.inverseOrderMapping = inverseOrderMapping;
|
||||
}
|
||||
// We cache the extractor for Object[] here
|
||||
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
|
||||
this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.STRUCT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregateJdbcType resolveAggregateJdbcType(
|
||||
EmbeddableMappingType mappingType,
|
||||
String sqlType,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
return new StructJdbcType(
|
||||
mappingType,
|
||||
sqlType,
|
||||
creationContext.getBootModel()
|
||||
.getDatabase()
|
||||
.getDefaultNamespace()
|
||||
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
|
||||
.getOrderMapping()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getEmbeddableMappingType() {
|
||||
return embeddableMappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( embeddableMappingType == null ) {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor( Object[].class );
|
||||
}
|
||||
else {
|
||||
//noinspection unchecked
|
||||
return (JavaType<T>) embeddableMappingType.getMappedJavaType();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutParameter(CallableStatement callableStatement, String name) throws SQLException {
|
||||
callableStatement.registerOutParameter( name, getJdbcTypeCode(), typeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException {
|
||||
callableStatement.registerOutParameter( index, getJdbcTypeCode(), typeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException {
|
||||
final Object[] jdbcValues = StructHelper.getJdbcValues(
|
||||
embeddableMappingType,
|
||||
orderMapping,
|
||||
embeddableMappingType.getValues( domainValue ),
|
||||
options
|
||||
);
|
||||
return options.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getPhysicalConnection()
|
||||
.createStruct( typeName, jdbcValues );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
|
||||
final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes();
|
||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options );
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@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, createJdbcValue( value, options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setObject( name, createJdbcValue( value, options ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
|
||||
if ( javaType.getJavaTypeClass() == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
return (ValueExtractor<X>) objectArrayExtractor;
|
||||
}
|
||||
return createBasicExtractor( javaType );
|
||||
}
|
||||
|
||||
private <X> BasicExtractor<X> createBasicExtractor(JavaType<X> javaType) {
|
||||
return new BasicExtractor<>( javaType, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
return getValue( rs.getObject( paramIndex ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return getValue( statement.getObject( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return getValue( statement.getObject( name ), options );
|
||||
}
|
||||
|
||||
private X getValue(Object object, WrapperOptions options) throws SQLException {
|
||||
if ( object == null ) {
|
||||
return null;
|
||||
}
|
||||
final Struct struct = (Struct) object;
|
||||
final Object[] values = struct.getAttributes();
|
||||
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
|
||||
if ( jdbcRepresentation ) {
|
||||
wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, values, 0, options );
|
||||
//noinspection unchecked
|
||||
return (X) values;
|
||||
}
|
||||
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
|
||||
final Object[] attributeValues = getAttributeValues(
|
||||
embeddableMappingType,
|
||||
orderMapping,
|
||||
values,
|
||||
options
|
||||
);
|
||||
//noinspection unchecked
|
||||
return (X) embeddableMappingType.getRepresentationStrategy().getInstantiator().instantiate(
|
||||
() -> attributeValues,
|
||||
options.getSessionFactory()
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Object[] getAttributeValues(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int[] orderMapping,
|
||||
Object[] rawJdbcValues,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
final Object[] attributeValues;
|
||||
if ( numberOfAttributeMappings != rawJdbcValues.length || orderMapping != null ) {
|
||||
attributeValues = new Object[numberOfAttributeMappings];
|
||||
}
|
||||
else {
|
||||
attributeValues = rawJdbcValues;
|
||||
}
|
||||
int jdbcIndex = 0;
|
||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||
final int attributeIndex;
|
||||
if ( orderMapping == null ) {
|
||||
attributeIndex = i;
|
||||
}
|
||||
else {
|
||||
attributeIndex = orderMapping[i];
|
||||
}
|
||||
final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( attributeIndex );
|
||||
jdbcIndex += injectAttributeValue(
|
||||
attributeMapping,
|
||||
attributeValues,
|
||||
attributeIndex,
|
||||
rawJdbcValues,
|
||||
jdbcIndex,
|
||||
options
|
||||
);
|
||||
}
|
||||
return attributeValues;
|
||||
}
|
||||
|
||||
private int injectAttributeValue(
|
||||
AttributeMapping attributeMapping,
|
||||
Object[] attributeValues,
|
||||
int attributeIndex,
|
||||
Object[] rawJdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
final int jdbcValueCount;
|
||||
final Object rawJdbcValue = rawJdbcValues[jdbcIndex];
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
|
||||
if ( embeddableMappingType.getAggregateMapping() != null ) {
|
||||
jdbcValueCount = 1;
|
||||
if ( rawJdbcValue == null ) {
|
||||
attributeValues[attributeIndex] = null;
|
||||
}
|
||||
else {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
final Object[] subValues;
|
||||
if ( aggregateJdbcType instanceof StructJdbcType ) {
|
||||
subValues = getAttributeValues(
|
||||
embeddableMappingType,
|
||||
( (StructJdbcType) aggregateJdbcType ).orderMapping,
|
||||
( (Struct) rawJdbcValue ).getAttributes(),
|
||||
options
|
||||
);
|
||||
}
|
||||
else {
|
||||
subValues = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
}
|
||||
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
|
||||
.getInstantiator()
|
||||
.instantiate(
|
||||
() -> subValues,
|
||||
embeddableMappingType.findContainingEntityMapping()
|
||||
.getEntityPersister()
|
||||
.getFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
jdbcValueCount = embeddableMappingType.getJdbcValueCount();
|
||||
final Object[] jdbcValues = new Object[jdbcValueCount];
|
||||
System.arraycopy( rawJdbcValues, jdbcIndex, jdbcValues, 0, jdbcValues.length );
|
||||
final Object[] subValues = getAttributeValues( embeddableMappingType, null, jdbcValues, options );
|
||||
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
|
||||
.getInstantiator()
|
||||
.instantiate(
|
||||
() -> subValues,
|
||||
embeddableMappingType.findContainingEntityMapping()
|
||||
.getEntityPersister()
|
||||
.getFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||
jdbcValueCount = 1;
|
||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
||||
final Object jdbcValue;
|
||||
if ( rawJdbcValue == null ) {
|
||||
jdbcValue = null;
|
||||
}
|
||||
else {
|
||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||
case SqlTypes.TIMESTAMP_UTC:
|
||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||
jdbcValue = jdbcMapping.getJdbcJavaType()
|
||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||
break;
|
||||
default:
|
||||
jdbcValue = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributeValues[attributeIndex] = jdbcMapping.convertToDomainValue( jdbcValue );
|
||||
}
|
||||
return jdbcValueCount;
|
||||
}
|
||||
|
||||
private int wrapRawJdbcValues(
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
int[] orderMapping,
|
||||
int[] inverseOrderMapping,
|
||||
Object[] jdbcValues,
|
||||
int jdbcIndex,
|
||||
WrapperOptions options) throws SQLException {
|
||||
final Object[] targetJdbcValues;
|
||||
if ( orderMapping == null ) {
|
||||
targetJdbcValues = jdbcValues;
|
||||
}
|
||||
else {
|
||||
targetJdbcValues = jdbcValues.clone();
|
||||
}
|
||||
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
|
||||
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
|
||||
final AttributeMapping attributeMapping;
|
||||
if ( orderMapping == null ) {
|
||||
attributeMapping = embeddableMappingType.getAttributeMapping( i );
|
||||
}
|
||||
else {
|
||||
attributeMapping = embeddableMappingType.getAttributeMapping( orderMapping[i] );
|
||||
}
|
||||
final MappingType mappedType = attributeMapping.getMappedType();
|
||||
|
||||
if ( mappedType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType;
|
||||
if ( embeddableType.getAggregateMapping() != null ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
|
||||
.getJdbcMapping()
|
||||
.getJdbcType();
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
|
||||
jdbcIndex++;
|
||||
}
|
||||
else {
|
||||
jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert attributeMapping.getJdbcTypeCount() == 1;
|
||||
final Object rawJdbcValue = targetJdbcValues[jdbcIndex];
|
||||
if ( rawJdbcValue != null ) {
|
||||
final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping();
|
||||
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
|
||||
case SqlTypes.TIMESTAMP_UTC:
|
||||
// Only transform the raw jdbc value if it could be a TIMESTAMPTZ
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType()
|
||||
.wrap( transformRawJdbcValue( rawJdbcValue, options ), options );
|
||||
break;
|
||||
default:
|
||||
targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options );
|
||||
break;
|
||||
}
|
||||
}
|
||||
jdbcIndex++;
|
||||
}
|
||||
}
|
||||
if ( orderMapping != null ) {
|
||||
StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues );
|
||||
}
|
||||
return jdbcIndex;
|
||||
}
|
||||
|
||||
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
|
||||
return rawJdbcValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ package org.hibernate.procedure.internal;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.dialect.PostgreSQLStructJdbcType;
|
||||
import org.hibernate.dialect.AbstractPostgreSQLStructJdbcType;
|
||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
||||
|
@ -156,9 +156,9 @@ public class PostgreSQLCallableStatementSupport extends AbstractStandardCallable
|
|||
);
|
||||
final OutputableType<?> type = registration.getParameterType();
|
||||
final String castType;
|
||||
if ( type != null && type.getJdbcType() instanceof PostgreSQLStructJdbcType ) {
|
||||
if ( type != null && type.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) {
|
||||
// We have to cast struct type parameters so that PostgreSQL understands nulls
|
||||
castType = ( (PostgreSQLStructJdbcType) type.getJdbcType() ).getTypeName();
|
||||
castType = ( (AbstractPostgreSQLStructJdbcType) type.getJdbcType() ).getTypeName();
|
||||
buffer.append( "cast(" );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -37,19 +37,6 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
public class ArrayJdbcType implements JdbcType {
|
||||
|
||||
public static final ArrayJdbcType INSTANCE = new ArrayJdbcType( ObjectJdbcType.INSTANCE );
|
||||
private static final ClassValue<Method> NAME_BINDER = new ClassValue<>() {
|
||||
@Override
|
||||
protected Method computeValue(Class<?> type) {
|
||||
try {
|
||||
return type.getMethod( "setArray", String.class, java.sql.Array.class );
|
||||
}
|
||||
catch ( Exception ex ) {
|
||||
// add logging? Did we get NoSuchMethodException or SecurityException?
|
||||
// Doesn't matter which. We can't use it.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final JdbcType elementJdbcType;
|
||||
|
||||
|
@ -126,27 +113,13 @@ public class ArrayJdbcType implements JdbcType {
|
|||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final java.sql.Array arr = getArray( value, containerJavaType, options );
|
||||
final Method nameBinder = NAME_BINDER.get( st.getClass() );
|
||||
if ( nameBinder == null ) {
|
||||
try {
|
||||
st.setObject( name, arr, java.sql.Types.ARRAY );
|
||||
return;
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
|
||||
}
|
||||
}
|
||||
// Note that it's supposed to have setArray(String,Array) by standard.
|
||||
// There are numerous missing methods that only have versions for positional parameter,
|
||||
// but not named ones.
|
||||
|
||||
try {
|
||||
nameBinder.invoke( st, name, arr );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new HibernateException( t );
|
||||
}
|
||||
}
|
||||
|
||||
private java.sql.Array getArray(
|
||||
X value,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.orm.test.id.usertype.inet;
|
||||
|
||||
import org.hibernate.dialect.PostgreSQLInetJdbcType;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.id.usertype.json;
|
||||
|
||||
import org.hibernate.dialect.PostgreSQLJsonbJdbcType;
|
||||
import org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType;
|
||||
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||
|
||||
public class JsonType extends AbstractSingleColumnStandardBasicType<Json> {
|
||||
|
@ -14,7 +14,7 @@ public class JsonType extends AbstractSingleColumnStandardBasicType<Json> {
|
|||
public static final JsonType INSTANCE = new JsonType();
|
||||
|
||||
public JsonType() {
|
||||
super( PostgreSQLJsonbJdbcType.INSTANCE, JsonJavaType.INSTANCE );
|
||||
super( new PostgreSQLJsonPGObjectJsonbType(), JsonJavaType.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.spatial.JTSGeometryJavaType;
|
|||
*/
|
||||
public interface ContributorImplementor {
|
||||
|
||||
default void contributeJavaTypes(TypeContributions typeContributions) {
|
||||
default void contributeJavaTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
typeContributions.contributeJavaType( GeolatteGeometryJavaType.GEOMETRY_INSTANCE );
|
||||
typeContributions.contributeJavaType( GeolatteGeometryJavaType.POINT_INSTANCE );
|
||||
typeContributions.contributeJavaType( GeolatteGeometryJavaType.LINESTRING_INSTANCE );
|
||||
|
@ -40,7 +40,7 @@ public interface ContributorImplementor {
|
|||
|
||||
}
|
||||
|
||||
void contributeJdbcTypes(TypeContributions typeContributions);
|
||||
void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry);
|
||||
|
||||
void contributeFunctions(FunctionContributions functionContributions);
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ public class SpatialTypeContributor implements TypeContributor {
|
|||
ContributorImplementor contributorImplementor = ContributorResolver.resolveSpatialtypeContributorImplementor( serviceRegistry );
|
||||
|
||||
if (contributorImplementor != null) {
|
||||
contributorImplementor.contributeJavaTypes( typeContributions );
|
||||
contributorImplementor.contributeJdbcTypes( typeContributions );
|
||||
contributorImplementor.contributeJavaTypes( typeContributions, serviceRegistry );
|
||||
contributorImplementor.contributeJdbcTypes( typeContributions, serviceRegistry );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.spatial.dialect.cockroachdb;
|
|||
|
||||
import org.hibernate.boot.model.FunctionContributions;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.PostgreSQLPGObjectJdbcType;
|
||||
import org.hibernate.dialect.PgJdbcHelper;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.spatial.FunctionKey;
|
||||
|
@ -30,9 +30,9 @@ public class CockroachDbContributor implements ContributorImplementor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( PGGeometryJdbcType.INSTANCE_WKB_2 );
|
||||
typeContributions.contributeJdbcType( PGGeographyJdbcType.INSTANCE_WKB_2 );
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class H2GisDialectContributor implements ContributorImplementor {
|
|||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
typeContributions.contributeJdbcType( H2GISGeometryType.INSTANCE );
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class MariaDBDialectContributor implements ContributorImplementor {
|
|||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
typeContributions.contributeJdbcType( MySQLGeometryJdbcType.INSTANCE );
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class MySQLDialectContributor implements ContributorImplementor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
typeContributions.contributeJdbcType( MySQLGeometryJdbcType.INSTANCE);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class OracleDialectContributor implements ContributorImplementor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
final ConfigurationService cfgService = getServiceRegistry().getService( ConfigurationService.class );
|
||||
final StrategySelector strategySelector = getServiceRegistry().getService( StrategySelector.class );
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.spatial.dialect.postgis;
|
|||
|
||||
import org.hibernate.boot.model.FunctionContributions;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.PostgreSQLPGObjectJdbcType;
|
||||
import org.hibernate.dialect.PgJdbcHelper;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.spatial.HSMessageLogger;
|
||||
|
@ -17,16 +17,16 @@ import org.hibernate.spatial.contributor.ContributorImplementor;
|
|||
|
||||
public class PostgisDialectContributor implements ContributorImplementor {
|
||||
|
||||
private final ServiceRegistry serviceRegistryegistry;
|
||||
private final ServiceRegistry serviceRegistry;
|
||||
|
||||
public PostgisDialectContributor(ServiceRegistry serviceRegistry) {
|
||||
this.serviceRegistryegistry = serviceRegistry;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
if ( PostgreSQLPGObjectJdbcType.isUsable() ) {
|
||||
if ( PgJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( PGGeometryJdbcType.INSTANCE_WKB_2 );
|
||||
typeContributions.contributeJdbcType( PGGeographyJdbcType.INSTANCE_WKB_2 );
|
||||
}
|
||||
|
@ -50,6 +50,6 @@ public class PostgisDialectContributor implements ContributorImplementor {
|
|||
|
||||
@Override
|
||||
public ServiceRegistry getServiceRegistry() {
|
||||
return this.serviceRegistryegistry;
|
||||
return this.serviceRegistry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class SqlServerDialectContributor implements ContributorImplementor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions) {
|
||||
public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() );
|
||||
typeContributions.contributeJdbcType( SqlServerGeometryType.INSTANCE );
|
||||
typeContributions.contributeJdbcType( SqlServerGeographyType.INSTANCE );
|
||||
|
|
Loading…
Reference in New Issue