HHH-9548 - Allow propagation of NULL for stored-procedure argument parameters to database

This commit is contained in:
Steve Ebersole 2016-02-09 16:08:22 -06:00
parent 19d86c3d65
commit 13bbddfd30
5 changed files with 81 additions and 17 deletions

View File

@ -17,7 +17,7 @@ public interface ParameterBind<T> {
*
* @return The bound value.
*/
public T getValue();
T getValue();
/**
* If {@code <T>} represents a DATE/TIME type value, JPA usually allows specifying the particular parts of
@ -25,5 +25,5 @@ public interface ParameterBind<T> {
*
* @return The explicitly supplied TemporalType.
*/
public TemporalType getExplicitTemporalType();
TemporalType getExplicitTemporalType();
}

View File

@ -35,6 +35,16 @@ public interface ParameterRegistrationImplementor<T> extends ParameterRegistrati
*/
Type getHibernateType();
/**
* If no value is bound for this parameter registration, is the passing of NULL
* to the JDBC CallableStatement for that parameter enabled? This effectively controls
* whether default values for the argument as defined in the database are applied or not.
*
* @return {@code true} indicates that NULL will be passed to the JDBC driver, effectively disabling
* the application of the default argument value defined in the database; {@code false} indicates
* that the parameter will simply be ignored, with the assumption that the corresponding argument
* defined a default value.
*/
boolean isPassNullsEnabled();
/**

View File

@ -28,12 +28,13 @@ import org.hibernate.LockMode;
import org.hibernate.jpa.spi.BaseQueryImpl;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.jpa.spi.ParameterBind;
import org.hibernate.jpa.spi.ParameterRegistration;
import org.hibernate.jpa.spi.StoredProcedureQueryParameterRegistration;
import org.hibernate.procedure.NoSuchParameterException;
import org.hibernate.procedure.ParameterStrategyException;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.ProcedureOutputs;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
import org.hibernate.result.NoMoreReturnsException;
import org.hibernate.result.Output;
import org.hibernate.result.ResultSetOutput;
@ -62,7 +63,12 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
super( entityManager );
this.procedureCall = memento.makeProcedureCall( entityManager.getSession() );
for ( org.hibernate.procedure.ParameterRegistration nativeParamReg : procedureCall.getRegisteredParameters() ) {
registerParameter( new ParameterRegistrationImpl( this, nativeParamReg ) );
registerParameter(
new ParameterRegistrationImpl(
this,
(ParameterRegistrationImplementor) nativeParamReg
)
);
}
}
@ -111,7 +117,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
registerParameter(
new ParameterRegistrationImpl(
this,
procedureCall.registerParameter( position, type, mode )
(ParameterRegistrationImplementor) procedureCall.registerParameter( position, type, mode )
)
);
}
@ -135,7 +141,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
registerParameter(
new ParameterRegistrationImpl(
this,
procedureCall.registerParameter( parameterName, type, mode )
(ParameterRegistrationImplementor) procedureCall.registerParameter( parameterName, type, mode )
)
);
}
@ -453,15 +459,15 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
return procedureCall;
}
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
private static class ParameterRegistrationImpl<T> implements StoredProcedureQueryParameterRegistration<T> {
private final StoredProcedureQueryImpl query;
private final org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration;
private final ParameterRegistrationImplementor<T> nativeParamRegistration;
private ParameterBind<T> bind;
public ParameterRegistrationImpl(
StoredProcedureQueryImpl query,
org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration) {
ParameterRegistrationImplementor<T> nativeParamRegistration) {
this.query = query;
this.nativeParamRegistration = nativeParamRegistration;
}
@ -496,6 +502,16 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
return nativeParamRegistration.getMode();
}
@Override
public boolean isPassNullsEnabled() {
return nativeParamRegistration.isPassNullsEnabled();
}
@Override
public void enablePassingNulls(boolean enabled) {
nativeParamRegistration.enablePassingNulls( enabled );
}
@Override
public boolean isBindable() {
return getMode() == ParameterMode.IN || getMode() == ParameterMode.INOUT;
@ -510,7 +526,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
public void bindValue(T value, TemporalType specifiedTemporalType) {
validateBinding( getParameterType(), value, specifiedTemporalType );
nativeParamRegistration.bindValue( value,specifiedTemporalType );
nativeParamRegistration.bindValue( value, specifiedTemporalType );
if ( bind == null ) {
bind = new ParameterBind<T>() {

View File

@ -31,14 +31,14 @@ public interface ParameterRegistration<T> extends Parameter<T> {
* we have either a named parameter ({@link #getName()} would return a non-{@code null} value) or a native
* Hibernate positional parameter.
*/
public boolean isJpaPositionalParameter();
boolean isJpaPositionalParameter();
/**
* Access to the query that this parameter belongs to.
*
* @return The defining query
*/
public Query getQuery();
Query getQuery();
/**
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
@ -46,7 +46,7 @@ public interface ParameterRegistration<T> extends Parameter<T> {
*
* @return The parameter mode.
*/
public ParameterMode getMode();
ParameterMode getMode();
/**
* Can we bind (set) values on this parameter? Generally this is {@code true}, but would not be in the case
@ -54,14 +54,14 @@ public interface ParameterRegistration<T> extends Parameter<T> {
*
* @return Whether the parameter is bindable (can set be called).
*/
public boolean isBindable();
boolean isBindable();
/**
* If bindable, bind the value.
*
* @param value The value to bind.
*/
public void bindValue(T value);
void bindValue(T value);
/**
* If bindable, bind the value using the specific temporal type.
@ -69,12 +69,12 @@ public interface ParameterRegistration<T> extends Parameter<T> {
* @param value The value to bind
* @param specifiedTemporalType The temporal type to use in binding
*/
public void bindValue(T value, TemporalType specifiedTemporalType);
void bindValue(T value, TemporalType specifiedTemporalType);
/**
* If bindable, get the current binding.
*
* @return The current binding
*/
public ParameterBind<T> getBind();
ParameterBind<T> getBind();
}

View File

@ -0,0 +1,38 @@
/*
* 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.jpa.spi;
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
/**
* ParameterRegistration extension specifically for stored procedure parameters
* exposing some functionality of Hibernate's native
* {@link org.hibernate.procedure.ParameterRegistration} contract
*
* @author Steve Ebersole
*/
public interface StoredProcedureQueryParameterRegistration<T> extends ParameterRegistration<T> {
/**
* How will an unbound value be handled in terms of the JDBC parameter?
*
* @return {@code true} here indicates that NULL should be passed; {@code false} indicates
* that it is ignored.
*
* @see ParameterRegistrationImplementor#isPassNullsEnabled()
*/
boolean isPassNullsEnabled();
/**
* Controls how unbound values for this IN/INOUT parameter registration will be handled prior to
* execution. For details see {@link org.hibernate.procedure.ParameterRegistration#enablePassingNulls}
*
* @param enabled {@code true} indicates that the NULL should be passed; {@code false} indicates it should not.
*
* @see org.hibernate.procedure.ParameterRegistration#enablePassingNulls
*/
void enablePassingNulls(boolean enabled);
}