Using the new JPA 2.1 stored procedure call, is there any way to pass a null parameter?
Here is an example usage:
StoredProcedureQuery storedProcedur
Here are my findings for Hibernate 4.3 which are relevant to JPA 2.1.
This will throw an exception if the DB does not support default parameters:
ProcedureCall procedure = getSession().createStoredProcedureCall("my_procedure");
procedure.registerParameter("my_nullable_param", String.class, ParameterMode.IN)
.bindValue(null);
// execute
procedure.getOutputs();
From Hibernate's source for binding the parameter to the underlying CallableStatement
:
public abstract class AbstractParameterRegistrationImpl {
..
@Override
public void prepare(CallableStatement statement, int startIndex) throws SQLException {
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
if ( bind == null || bind.getValue() == null ) {
// the user did not bind a value to the parameter being processed. That might be ok *if* the
// procedure as defined in the database defines a default value for that parameter.
// Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure
// parameter defines a default value. So we simply allow the procedure execution to happen
// assuming that the database will complain appropriately if not setting the given parameter
// bind value is an error.
log.debugf("Stored procedure [%s] IN/INOUT parameter [%s] not bound; assuming procedure defines default value", procedureCall.getProcedureName(), this);
} else {
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, session() );
}
}
}
..
}
The above comment reads:
The user did not bind a value to the parameter being processed. That might be ok if the procedure as defined in the database defines a default value for that parameter. Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure parameter defines a default value. So we simply allow the procedure execution to happen assuming that the database will complain appropriately if not setting the given parameter bind value is an error.
I am interpreting that as JPA (specifically Hibernate) DOES NOT support setting null parameters at all. It looks like they are in a struggle with supporting default parameter values versus substituting a null value when appropriate. They choose to support the former. It looks like those who need support for the latter (nullable values) must use java.sql.CallableStatement
:
getSession().doWork(new Work() {
@Override
public void execute(Connection conn) throws SQLException {
CallableStatement stmt = conn.prepareCall("{ call my_prodecure(:my_nullable_param) }");
if(stringVariableThatIsNull != null) {
stmt.setString("my_nullable_param", stringVariableThatIsNull);
} else {
stmt.setNull("my_nullable_param", Types.VARCHAR);
}
stmt.execute();
stmt.close();
}
});
tl;dr we are still forced to deal with low-level JDBC because neither JPA or Hibernate seem to address nullable parameters. They are supporting procedure parameter default values over substituting a null value.