HHH-16224 Refactor discovery of exact JDBC drivers, avoid static state in specialized types

This commit is contained in:
Christian Beikov 2023-03-02 20:36:48 +01:00
parent 02b7c5afb5
commit 8d93c0ca33
38 changed files with 1131 additions and 1050 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 );

View File

@ -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')

View File

@ -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 );
}
}

View File

@ -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
);
}
};
}
}

View File

@ -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
);
}
};
}
@Override
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

View File

@ -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 );

View File

@ -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,25 +104,11 @@ 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 );
st.setObject( name, arr, Types.ARRAY );
}
catch ( Throwable t ) {
throw new HibernateException( t );
catch (SQLException ex) {
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
}
}
@ -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;
}
}

View File

@ -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;
}

View File

@ -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 );
}
}
}

View File

@ -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 );
}
}
}

View File

@ -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,329 +52,21 @@ 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()
protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) {
if ( rawJdbcValue.getClass() == TIMESTAMPTZ.class ) {
try {
return ( (TIMESTAMPTZ) rawJdbcValue ).offsetDateTimeValue(
options.getSession()
.getJdbcCoordinator()
.getLogicalConnection()
.getPhysicalConnection()
);
}
};
}
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()
);
catch (Exception e) {
throw new HibernateException( "Could not transform the raw jdbc value", e );
}
}
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;
}
try {
return rawJdbcTransformer.invoke(
rawJdbcValue,
options.getSession()
.getJdbcCoordinator()
.getLogicalConnection()
.getPhysicalConnection()
);
}
catch (Exception e) {
throw new HibernateException( "Could not transform the raw jdbc value", e );
}
return rawJdbcValue;
}
}

View File

@ -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;
}

View File

@ -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 );
// }
// }
}

View File

@ -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 );
}
}
}

View File

@ -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 );
}

View File

@ -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 );
}
};
}
}

View File

@ -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,19 +110,14 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType {
double seconds = ( (double) ( secondsLong - minutesLong * 60 ) )
+ ( (double) d.getNano() ) / 1_000_000_000d;
try {
return PG_INTERVAL_CONSTRUCTOR.newInstance(
0,// years
0, // months
days,
hours,
minutes,
seconds
);
}
catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new IllegalArgumentException( e );
}
return new PGInterval(
0,// years
0, // months
days,
hours,
minutes,
seconds
);
}
};
}
@ -198,19 +142,15 @@ 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 Duration.ofSeconds( seconds, nanos );
}
return value;
}

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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
);
}
};
}
}

View File

@ -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

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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,25 +113,11 @@ 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 );
st.setObject( name, arr, java.sql.Types.ARRAY );
}
catch ( Throwable t ) {
throw new HibernateException( t );
catch (SQLException ex) {
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
}
}

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 );
}
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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);
}

View File

@ -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 );

View File

@ -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;
}
}

View File

@ -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 );