From e29f616d77951655f3e04fcb06c5e842a3482a12 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 18 Mar 2021 18:44:31 +0100 Subject: [PATCH] Add Oracle specific SqlTypeDescriptor for Boolean that binds with type BIT for null boolean --- .../org/hibernate/dialect/OracleDialect.java | 83 +++++++++++++++++++ .../java/org/hibernate/type/BooleanType.java | 10 ++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 599e4fe4a6..c010b6dc0a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -29,6 +29,7 @@ import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; +import org.hibernate.internal.CoreLogging; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -56,11 +57,18 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.JdbcTypeNameMapper; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; +import org.hibernate.type.descriptor.sql.BooleanTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry; import java.sql.CallableStatement; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -70,6 +78,8 @@ import java.util.regex.Pattern; import javax.persistence.TemporalType; +import org.jboss.logging.Logger; + import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.query.TemporalUnit.*; @@ -643,6 +653,79 @@ public class OracleDialect extends Dialect { typeContributions.contributeSqlTypeDescriptor( descriptor ); } + typeContributions.contributeSqlTypeDescriptor( new OracleBooleanTypeDescriptor() ); + } + + private static final class OracleBooleanTypeDescriptor extends BooleanTypeDescriptor { + + private static final Logger log = CoreLogging.logger( BasicBinder.class ); + + @Override + public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { + return new ValueBinder() { + + private static final String BIND_MSG_TEMPLATE = "binding parameter [%s] as [%s] - [%s]"; + private static final String NULL_BIND_MSG_TEMPLATE = "binding parameter [%s] as [%s] - [null]"; + + @Override + public final void bind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + if ( value == null ) { + if ( log.isTraceEnabled() ) { + log.trace( + String.format( + NULL_BIND_MSG_TEMPLATE, + index, + JdbcTypeNameMapper.getTypeName( Types.BOOLEAN ) + ) + ); + } + st.setNull( index, Types.BIT ); + } + else { + if ( log.isTraceEnabled() ) { + log.trace( + String.format( + BIND_MSG_TEMPLATE, + index, + JdbcTypeNameMapper.getTypeName( Types.BOOLEAN ), + javaTypeDescriptor.extractLoggableRepresentation( value ) + ) + ); + } + st.setBoolean( index, javaTypeDescriptor.unwrap( value, Boolean.class, options ) ); + } + } + + @Override + public final void bind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { + if ( value == null ) { + if ( log.isTraceEnabled() ) { + log.trace( + String.format( + NULL_BIND_MSG_TEMPLATE, + name, + JdbcTypeNameMapper.getTypeName( Types.BOOLEAN ) + ) + ); + } + st.setNull( name, Types.BIT ); + } + else { + if ( log.isTraceEnabled() ) { + log.trace( + String.format( + BIND_MSG_TEMPLATE, + name, + JdbcTypeNameMapper.getTypeName( Types.BOOLEAN ), + javaTypeDescriptor.extractLoggableRepresentation( value ) + ) + ); + } + st.setBoolean( name, javaTypeDescriptor.unwrap( value, Boolean.class, options ) ); + } + } + }; + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/BooleanType.java b/hibernate-core/src/main/java/org/hibernate/type/BooleanType.java index 991da967f1..e021b7b550 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BooleanType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BooleanType.java @@ -62,11 +62,19 @@ public class BooleanType @Override public BasicType resolveIndicatedType(SqlTypeDescriptorIndicators indicators) { final int preferredSqlTypeCodeForBoolean = indicators.getPreferredSqlTypeCodeForBoolean(); + final SqlTypeDescriptor sqlTypeDescriptor; // We treat BIT like BOOLEAN because it uses the same JDBC access methods if ( preferredSqlTypeCodeForBoolean != Types.BIT && preferredSqlTypeCodeForBoolean != getSqlTypeDescriptor().getJdbcTypeCode() ) { - final SqlTypeDescriptor sqlTypeDescriptor = indicators.getTypeConfiguration() + sqlTypeDescriptor = indicators.getTypeConfiguration() .getSqlTypeDescriptorRegistry() .getDescriptor( preferredSqlTypeCodeForBoolean ); + } + else { + sqlTypeDescriptor = indicators.getTypeConfiguration() + .getSqlTypeDescriptorRegistry() + .getDescriptor( Types.BOOLEAN ); + } + if ( sqlTypeDescriptor != getSqlTypeDescriptor() ) { //noinspection unchecked return (BasicType) indicators.getTypeConfiguration() .getBasicTypeRegistry()