mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-16 16:15:06 +00:00
cleaner approach to work around Oracle setNull(BOOLEAN) bug
- introduce doBindNull() in BasicBinder - use WrapperOptions and FastSessionServices - use getPreferredSqlTypeCodeForBoolean()
This commit is contained in:
parent
0ecd66fd46
commit
e60e3736a7
@ -29,7 +29,6 @@
|
||||
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;
|
||||
@ -57,18 +56,11 @@
|
||||
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.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.BooleanTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
@ -78,8 +70,6 @@
|
||||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.TemporalUnit.*;
|
||||
|
||||
@ -656,79 +646,6 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
||||
|
||||
typeContributions.contributeJdbcTypeDescriptor( descriptor );
|
||||
}
|
||||
typeContributions.contributeJdbcTypeDescriptor( new OracleBooleanTypeDescriptor() );
|
||||
}
|
||||
|
||||
private static final class OracleBooleanTypeDescriptor extends BooleanTypeDescriptor {
|
||||
|
||||
private static final Logger log = CoreLogging.logger( BasicBinder.class );
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new ValueBinder<X>() {
|
||||
|
||||
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
|
||||
|
@ -28,6 +28,11 @@ public boolean useStreamForLobBinding() {
|
||||
return delegate().useStreamForLobBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return delegate().getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobCreator getLobCreator() {
|
||||
return delegate().getLobCreator();
|
||||
|
@ -1095,6 +1095,11 @@ public boolean useStreamForLobBinding() {
|
||||
return delegate.useStreamForLobBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return delegate.getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobCreator getLobCreator() {
|
||||
return delegate.getLobCreator();
|
||||
|
@ -557,6 +557,11 @@ public boolean useStreamForLobBinding() {
|
||||
return fastSessionServices.useStreamForLobBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return fastSessionServices.preferredSqlTypeCodeForBoolean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobCreator getLobCreator() {
|
||||
return Hibernate.getLobCreator( this );
|
||||
|
@ -142,6 +142,7 @@ public final class FastSessionServices {
|
||||
//Intentionally Package private:
|
||||
final boolean disallowOutOfTransactionUpdateOperations;
|
||||
final boolean useStreamForLobBinding;
|
||||
final int preferredSqlTypeCodeForBoolean;
|
||||
final boolean requiresMultiTenantConnectionProvider;
|
||||
final ConnectionProvider connectionProvider;
|
||||
final MultiTenantConnectionProvider multiTenantConnectionProvider;
|
||||
@ -210,6 +211,7 @@ public final class FastSessionServices {
|
||||
this.dialect = jdbcServices.getJdbcEnvironment().getDialect();
|
||||
this.disallowOutOfTransactionUpdateOperations = !sessionFactoryOptions.isAllowOutOfTransactionUpdateOperations();
|
||||
this.useStreamForLobBinding = Environment.useStreamsForBinary() || dialect.useInputStreamToInsertBlob();
|
||||
this.preferredSqlTypeCodeForBoolean = sessionFactoryOptions.getPreferredSqlTypeCodeForBoolean();
|
||||
this.requiresMultiTenantConnectionProvider = sf.getSettings().getMultiTenancyStrategy().requiresMultiTenantConnectionProvider();
|
||||
|
||||
//Some "hot" services:
|
||||
@ -343,4 +345,8 @@ public boolean useStreamForLobBinding() {
|
||||
public void firePostLoadEvent(final PostLoadEvent postLoadEvent) {
|
||||
eventListenerGroup_POST_LOAD.fireEventOnEachListener( postLoadEvent, PostLoadEventListener::onPostLoad );
|
||||
}
|
||||
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return preferredSqlTypeCodeForBoolean;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,6 @@
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.FetchClauseType;
|
||||
import org.hibernate.query.Limit;
|
||||
import org.hibernate.query.NullPrecedence;
|
||||
import org.hibernate.query.SortOrder;
|
||||
@ -69,7 +68,6 @@
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteColumn;
|
||||
import org.hibernate.sql.ast.tree.cte.CteContainer;
|
||||
import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.cte.SearchClauseSpecification;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
@ -268,6 +266,11 @@ public boolean useStreamForLobBinding() {
|
||||
return sessionFactory.getFastSessionServices().useStreamForLobBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return sessionFactory.getFastSessionServices().getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcTypeDescriptor remapSqlTypeDescriptor(JdbcTypeDescriptor jdbcTypeDescriptor) {
|
||||
return sessionFactory.getFastSessionServices().remapSqlTypeDescriptor( jdbcTypeDescriptor );
|
||||
|
@ -33,6 +33,11 @@ public interface WrapperOptions {
|
||||
*/
|
||||
boolean useStreamForLobBinding();
|
||||
|
||||
/**
|
||||
* Get the JDBC {@link java.sql.Types type code} used to bind a null boolean value
|
||||
*/
|
||||
int getPreferredSqlTypeCodeForBoolean();
|
||||
|
||||
/**
|
||||
* Obtain access to the {@link LobCreator}
|
||||
*
|
||||
|
@ -55,7 +55,7 @@ public final void bind(PreparedStatement st, J value, int index, WrapperOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
st.setNull( index, jdbcTypeDescriptor.getJdbcType() );
|
||||
doBindNull( st, index, options );
|
||||
}
|
||||
else {
|
||||
if ( JdbcBindingLogging.TRACE_ENABLED ) {
|
||||
@ -84,7 +84,7 @@ public final void bind(CallableStatement st, J value, String name, WrapperOption
|
||||
)
|
||||
);
|
||||
}
|
||||
st.setNull( name, jdbcTypeDescriptor.getJdbcType() );
|
||||
doBindNull( st, name, options );
|
||||
}
|
||||
else {
|
||||
if ( JdbcBindingLogging.TRACE_ENABLED ) {
|
||||
@ -101,6 +101,32 @@ public final void bind(CallableStatement st, J value, String name, WrapperOption
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the null binding.
|
||||
*
|
||||
* @param st The prepared statement
|
||||
* @param index The index at which to bind
|
||||
* @param options The binding options
|
||||
*
|
||||
* @throws SQLException Indicates a problem binding to the prepared statement.
|
||||
*/
|
||||
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNull( index, jdbcTypeDescriptor.getJdbcType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the null binding.
|
||||
*
|
||||
* @param st The CallableStatement
|
||||
* @param name The name at which to bind
|
||||
* @param options The binding options
|
||||
*
|
||||
* @throws SQLException Indicates a problem binding to the callable statement.
|
||||
*/
|
||||
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
|
||||
st.setNull( name, jdbcTypeDescriptor.getJdbcType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the binding. Safe to assume that value is not null.
|
||||
*
|
||||
@ -122,7 +148,7 @@ protected abstract void doBind(PreparedStatement st, J value, int index, Wrapper
|
||||
* @param name The name at which to bind
|
||||
* @param options The binding options
|
||||
*
|
||||
* @throws SQLException Indicates a problem binding to the prepared statement.
|
||||
* @throws SQLException Indicates a problem binding to the callable statement.
|
||||
*/
|
||||
protected abstract void doBind(CallableStatement st, J value, String name, WrapperOptions options)
|
||||
throws SQLException;
|
||||
|
@ -63,6 +63,16 @@ public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T>
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNull( index, options.getPreferredSqlTypeCodeForBoolean() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
|
||||
st.setNull( name, options.getPreferredSqlTypeCodeForBoolean() );;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||
st.setBoolean( index, javaTypeDescriptor.unwrap( value, Boolean.class, options ) );
|
||||
|
@ -12,6 +12,7 @@
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
@ -98,6 +99,11 @@ public boolean useStreamForLobBinding() {
|
||||
return useStreamForLobBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return Types.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobCreator getLobCreator() {
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user