HHH-9548 - Allow propagation of NULL for stored-procedure argument parameters to database
This commit is contained in:
parent
90b7f9e07c
commit
a5e65834a1
|
@ -81,6 +81,7 @@ import static org.hibernate.cfg.AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLV
|
||||||
import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS;
|
import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS;
|
||||||
import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES;
|
import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES;
|
||||||
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
|
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
|
||||||
|
import static org.hibernate.cfg.AvailableSettings.PROCEDURE_NULL_PARAM_PASSING;
|
||||||
import static org.hibernate.cfg.AvailableSettings.QUERY_CACHE_FACTORY;
|
import static org.hibernate.cfg.AvailableSettings.QUERY_CACHE_FACTORY;
|
||||||
import static org.hibernate.cfg.AvailableSettings.QUERY_STARTUP_CHECKING;
|
import static org.hibernate.cfg.AvailableSettings.QUERY_STARTUP_CHECKING;
|
||||||
import static org.hibernate.cfg.AvailableSettings.QUERY_SUBSTITUTIONS;
|
import static org.hibernate.cfg.AvailableSettings.QUERY_SUBSTITUTIONS;
|
||||||
|
@ -525,6 +526,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
private Map querySubstitutions;
|
private Map querySubstitutions;
|
||||||
private boolean strictJpaQueryLanguageCompliance;
|
private boolean strictJpaQueryLanguageCompliance;
|
||||||
private boolean namedQueryStartupCheckingEnabled;
|
private boolean namedQueryStartupCheckingEnabled;
|
||||||
|
private final boolean procedureParameterNullPassingEnabled;
|
||||||
|
|
||||||
// Caching
|
// Caching
|
||||||
private boolean secondLevelCacheEnabled;
|
private boolean secondLevelCacheEnabled;
|
||||||
|
@ -640,6 +642,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
this.querySubstitutions = ConfigurationHelper.toMap( QUERY_SUBSTITUTIONS, " ,=;:\n\t\r\f", configurationSettings );
|
this.querySubstitutions = ConfigurationHelper.toMap( QUERY_SUBSTITUTIONS, " ,=;:\n\t\r\f", configurationSettings );
|
||||||
this.strictJpaQueryLanguageCompliance = cfgService.getSetting( JPAQL_STRICT_COMPLIANCE, BOOLEAN, false );
|
this.strictJpaQueryLanguageCompliance = cfgService.getSetting( JPAQL_STRICT_COMPLIANCE, BOOLEAN, false );
|
||||||
this.namedQueryStartupCheckingEnabled = cfgService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true );
|
this.namedQueryStartupCheckingEnabled = cfgService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true );
|
||||||
|
this.procedureParameterNullPassingEnabled = cfgService.getSetting( PROCEDURE_NULL_PARAM_PASSING, BOOLEAN, false );
|
||||||
|
|
||||||
this.secondLevelCacheEnabled = cfgService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true );
|
this.secondLevelCacheEnabled = cfgService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true );
|
||||||
this.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
|
this.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
|
||||||
|
@ -889,6 +892,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
return namedQueryStartupCheckingEnabled;
|
return namedQueryStartupCheckingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProcedureParameterNullPassingEnabled() {
|
||||||
|
return procedureParameterNullPassingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecondLevelCacheEnabled() {
|
public boolean isSecondLevelCacheEnabled() {
|
||||||
return secondLevelCacheEnabled;
|
return secondLevelCacheEnabled;
|
||||||
|
@ -1160,6 +1168,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
return options.isNamedQueryStartupCheckingEnabled();
|
return options.isNamedQueryStartupCheckingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProcedureParameterNullPassingEnabled() {
|
||||||
|
return options.isProcedureParameterNullPassingEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecondLevelCacheEnabled() {
|
public boolean isSecondLevelCacheEnabled() {
|
||||||
return options.isSecondLevelCacheEnabled();
|
return options.isSecondLevelCacheEnabled();
|
||||||
|
|
|
@ -89,6 +89,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
||||||
private final Map querySubstitutions;
|
private final Map querySubstitutions;
|
||||||
private final boolean strictJpaQueryLanguageCompliance;
|
private final boolean strictJpaQueryLanguageCompliance;
|
||||||
private final boolean namedQueryStartupCheckingEnabled;
|
private final boolean namedQueryStartupCheckingEnabled;
|
||||||
|
private final boolean procedureParameterNullPassingEnabled;
|
||||||
|
|
||||||
// Caching
|
// Caching
|
||||||
private final boolean secondLevelCacheEnabled;
|
private final boolean secondLevelCacheEnabled;
|
||||||
|
@ -159,6 +160,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
||||||
this.querySubstitutions = state.getQuerySubstitutions();
|
this.querySubstitutions = state.getQuerySubstitutions();
|
||||||
this.strictJpaQueryLanguageCompliance = state.isStrictJpaQueryLanguageCompliance();
|
this.strictJpaQueryLanguageCompliance = state.isStrictJpaQueryLanguageCompliance();
|
||||||
this.namedQueryStartupCheckingEnabled = state.isNamedQueryStartupCheckingEnabled();
|
this.namedQueryStartupCheckingEnabled = state.isNamedQueryStartupCheckingEnabled();
|
||||||
|
this.procedureParameterNullPassingEnabled = state.isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
this.secondLevelCacheEnabled = state.isSecondLevelCacheEnabled();
|
this.secondLevelCacheEnabled = state.isSecondLevelCacheEnabled();
|
||||||
this.queryCacheEnabled = state.isQueryCacheEnabled();
|
this.queryCacheEnabled = state.isQueryCacheEnabled();
|
||||||
|
@ -336,6 +338,11 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
||||||
return namedQueryStartupCheckingEnabled;
|
return namedQueryStartupCheckingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProcedureParameterNullPassingEnabled() {
|
||||||
|
return procedureParameterNullPassingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecondLevelCacheEnabled() {
|
public boolean isSecondLevelCacheEnabled() {
|
||||||
return secondLevelCacheEnabled;
|
return secondLevelCacheEnabled;
|
||||||
|
|
|
@ -37,97 +37,99 @@ import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface SessionFactoryOptionsState {
|
public interface SessionFactoryOptionsState {
|
||||||
public StandardServiceRegistry getServiceRegistry();
|
StandardServiceRegistry getServiceRegistry();
|
||||||
|
|
||||||
public Object getBeanManagerReference();
|
Object getBeanManagerReference();
|
||||||
|
|
||||||
public Object getValidatorFactoryReference();
|
Object getValidatorFactoryReference();
|
||||||
|
|
||||||
public String getSessionFactoryName();
|
String getSessionFactoryName();
|
||||||
|
|
||||||
public boolean isSessionFactoryNameAlsoJndiName();
|
boolean isSessionFactoryNameAlsoJndiName();
|
||||||
|
|
||||||
public boolean isFlushBeforeCompletionEnabled();
|
boolean isFlushBeforeCompletionEnabled();
|
||||||
|
|
||||||
public boolean isAutoCloseSessionEnabled();
|
boolean isAutoCloseSessionEnabled();
|
||||||
|
|
||||||
public boolean isStatisticsEnabled();
|
boolean isStatisticsEnabled();
|
||||||
|
|
||||||
public Interceptor getInterceptor();
|
Interceptor getInterceptor();
|
||||||
|
|
||||||
public StatementInspector getStatementInspector();
|
StatementInspector getStatementInspector();
|
||||||
|
|
||||||
public SessionFactoryObserver[] getSessionFactoryObservers();
|
SessionFactoryObserver[] getSessionFactoryObservers();
|
||||||
|
|
||||||
public BaselineSessionEventsListenerBuilder getBaselineSessionEventsListenerBuilder();
|
BaselineSessionEventsListenerBuilder getBaselineSessionEventsListenerBuilder();
|
||||||
|
|
||||||
public boolean isIdentifierRollbackEnabled();
|
boolean isIdentifierRollbackEnabled();
|
||||||
|
|
||||||
public EntityMode getDefaultEntityMode();
|
EntityMode getDefaultEntityMode();
|
||||||
|
|
||||||
public EntityTuplizerFactory getEntityTuplizerFactory();
|
EntityTuplizerFactory getEntityTuplizerFactory();
|
||||||
|
|
||||||
public boolean isCheckNullability();
|
boolean isCheckNullability();
|
||||||
|
|
||||||
public boolean isInitializeLazyStateOutsideTransactionsEnabled();
|
boolean isInitializeLazyStateOutsideTransactionsEnabled();
|
||||||
|
|
||||||
public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy();
|
MultiTableBulkIdStrategy getMultiTableBulkIdStrategy();
|
||||||
|
|
||||||
public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling();
|
TempTableDdlTransactionHandling getTempTableDdlTransactionHandling();
|
||||||
|
|
||||||
public BatchFetchStyle getBatchFetchStyle();
|
BatchFetchStyle getBatchFetchStyle();
|
||||||
|
|
||||||
public int getDefaultBatchFetchSize();
|
int getDefaultBatchFetchSize();
|
||||||
|
|
||||||
public Integer getMaximumFetchDepth();
|
Integer getMaximumFetchDepth();
|
||||||
|
|
||||||
public NullPrecedence getDefaultNullPrecedence();
|
NullPrecedence getDefaultNullPrecedence();
|
||||||
|
|
||||||
public boolean isOrderUpdatesEnabled();
|
boolean isOrderUpdatesEnabled();
|
||||||
|
|
||||||
public boolean isOrderInsertsEnabled();
|
boolean isOrderInsertsEnabled();
|
||||||
|
|
||||||
public MultiTenancyStrategy getMultiTenancyStrategy();
|
MultiTenancyStrategy getMultiTenancyStrategy();
|
||||||
|
|
||||||
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
|
CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
|
||||||
|
|
||||||
public boolean isJtaTrackByThread();
|
boolean isJtaTrackByThread();
|
||||||
|
|
||||||
public Map getQuerySubstitutions();
|
Map getQuerySubstitutions();
|
||||||
|
|
||||||
public boolean isStrictJpaQueryLanguageCompliance();
|
boolean isStrictJpaQueryLanguageCompliance();
|
||||||
|
|
||||||
public boolean isNamedQueryStartupCheckingEnabled();
|
boolean isNamedQueryStartupCheckingEnabled();
|
||||||
|
|
||||||
public boolean isSecondLevelCacheEnabled();
|
boolean isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
public boolean isQueryCacheEnabled();
|
boolean isSecondLevelCacheEnabled();
|
||||||
|
|
||||||
public QueryCacheFactory getQueryCacheFactory();
|
boolean isQueryCacheEnabled();
|
||||||
|
|
||||||
public String getCacheRegionPrefix();
|
QueryCacheFactory getQueryCacheFactory();
|
||||||
|
|
||||||
public boolean isMinimalPutsEnabled();
|
String getCacheRegionPrefix();
|
||||||
|
|
||||||
public boolean isStructuredCacheEntriesEnabled();
|
boolean isMinimalPutsEnabled();
|
||||||
|
|
||||||
public boolean isDirectReferenceCacheEntriesEnabled();
|
boolean isStructuredCacheEntriesEnabled();
|
||||||
|
|
||||||
public boolean isAutoEvictCollectionCache();
|
boolean isDirectReferenceCacheEntriesEnabled();
|
||||||
|
|
||||||
public SchemaAutoTooling getSchemaAutoTooling();
|
boolean isAutoEvictCollectionCache();
|
||||||
|
|
||||||
public int getJdbcBatchSize();
|
SchemaAutoTooling getSchemaAutoTooling();
|
||||||
|
|
||||||
public boolean isJdbcBatchVersionedData();
|
int getJdbcBatchSize();
|
||||||
|
|
||||||
public boolean isScrollableResultSetsEnabled();
|
boolean isJdbcBatchVersionedData();
|
||||||
|
|
||||||
public boolean isWrapResultSetsEnabled();
|
boolean isScrollableResultSetsEnabled();
|
||||||
|
|
||||||
public boolean isGetGeneratedKeysEnabled();
|
boolean isWrapResultSetsEnabled();
|
||||||
|
|
||||||
public Integer getJdbcFetchSize();
|
boolean isGetGeneratedKeysEnabled();
|
||||||
|
|
||||||
|
Integer getJdbcFetchSize();
|
||||||
|
|
||||||
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
||||||
|
|
||||||
|
@ -137,15 +139,16 @@ public interface SessionFactoryOptionsState {
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ConnectionReleaseMode getConnectionReleaseMode();
|
ConnectionReleaseMode getConnectionReleaseMode();
|
||||||
|
|
||||||
public boolean isCommentsEnabled();
|
boolean isCommentsEnabled();
|
||||||
|
|
||||||
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
|
CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
|
||||||
|
|
||||||
public EntityNameResolver[] getEntityNameResolvers();
|
EntityNameResolver[] getEntityNameResolvers();
|
||||||
|
|
||||||
public EntityNotFoundDelegate getEntityNotFoundDelegate();
|
EntityNotFoundDelegate getEntityNotFoundDelegate();
|
||||||
|
|
||||||
public Map<String, SQLFunction> getCustomSqlFunctionMap();
|
Map<String, SQLFunction> getCustomSqlFunctionMap();
|
||||||
|
|
||||||
|
boolean isPreferUserTransaction();
|
||||||
|
|
||||||
public boolean isPreferUserTransaction();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,11 @@ public abstract class AbstractDelegatingSessionFactoryOptions implements Session
|
||||||
return delegate.isNamedQueryStartupCheckingEnabled();
|
return delegate.isNamedQueryStartupCheckingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProcedureParameterNullPassingEnabled() {
|
||||||
|
return delegate.isProcedureParameterNullPassingEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecondLevelCacheEnabled() {
|
public boolean isSecondLevelCacheEnabled() {
|
||||||
return delegate.isSecondLevelCacheEnabled();
|
return delegate.isSecondLevelCacheEnabled();
|
||||||
|
|
|
@ -42,11 +42,11 @@ public interface SessionFactoryOptions {
|
||||||
*
|
*
|
||||||
* @return The service registry to use.
|
* @return The service registry to use.
|
||||||
*/
|
*/
|
||||||
public StandardServiceRegistry getServiceRegistry();
|
StandardServiceRegistry getServiceRegistry();
|
||||||
|
|
||||||
public Object getBeanManagerReference();
|
Object getBeanManagerReference();
|
||||||
|
|
||||||
public Object getValidatorFactoryReference();
|
Object getValidatorFactoryReference();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name to be used for the SessionFactory. This is use both in:<ul>
|
* The name to be used for the SessionFactory. This is use both in:<ul>
|
||||||
|
@ -56,7 +56,7 @@ public interface SessionFactoryOptions {
|
||||||
*
|
*
|
||||||
* @return The SessionFactory name
|
* @return The SessionFactory name
|
||||||
*/
|
*/
|
||||||
public String getSessionFactoryName();
|
String getSessionFactoryName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the {@link #getSessionFactoryName SesssionFactory name} also a JNDI name, indicating we
|
* Is the {@link #getSessionFactoryName SesssionFactory name} also a JNDI name, indicating we
|
||||||
|
@ -64,94 +64,94 @@ public interface SessionFactoryOptions {
|
||||||
*
|
*
|
||||||
* @return {@code true} if the SessionFactory name is also a JNDI name; {@code false} otherwise.
|
* @return {@code true} if the SessionFactory name is also a JNDI name; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isSessionFactoryNameAlsoJndiName();
|
boolean isSessionFactoryNameAlsoJndiName();
|
||||||
|
|
||||||
public boolean isFlushBeforeCompletionEnabled();
|
boolean isFlushBeforeCompletionEnabled();
|
||||||
|
|
||||||
public boolean isAutoCloseSessionEnabled();
|
boolean isAutoCloseSessionEnabled();
|
||||||
|
|
||||||
public boolean isStatisticsEnabled();
|
boolean isStatisticsEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the interceptor to use by default for all sessions opened from this factory.
|
* Get the interceptor to use by default for all sessions opened from this factory.
|
||||||
*
|
*
|
||||||
* @return The interceptor to use factory wide. May be {@code null}
|
* @return The interceptor to use factory wide. May be {@code null}
|
||||||
*/
|
*/
|
||||||
public Interceptor getInterceptor();
|
Interceptor getInterceptor();
|
||||||
|
|
||||||
public StatementInspector getStatementInspector();
|
StatementInspector getStatementInspector();
|
||||||
|
|
||||||
public SessionFactoryObserver[] getSessionFactoryObservers();
|
SessionFactoryObserver[] getSessionFactoryObservers();
|
||||||
|
|
||||||
public BaselineSessionEventsListenerBuilder getBaselineSessionEventsListenerBuilder();
|
BaselineSessionEventsListenerBuilder getBaselineSessionEventsListenerBuilder();
|
||||||
|
|
||||||
public boolean isIdentifierRollbackEnabled();
|
boolean isIdentifierRollbackEnabled();
|
||||||
|
|
||||||
public EntityMode getDefaultEntityMode();
|
EntityMode getDefaultEntityMode();
|
||||||
|
|
||||||
public EntityTuplizerFactory getEntityTuplizerFactory();
|
EntityTuplizerFactory getEntityTuplizerFactory();
|
||||||
|
|
||||||
public boolean isCheckNullability();
|
boolean isCheckNullability();
|
||||||
|
|
||||||
public boolean isInitializeLazyStateOutsideTransactionsEnabled();
|
boolean isInitializeLazyStateOutsideTransactionsEnabled();
|
||||||
|
|
||||||
public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy();
|
MultiTableBulkIdStrategy getMultiTableBulkIdStrategy();
|
||||||
|
|
||||||
public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling();
|
TempTableDdlTransactionHandling getTempTableDdlTransactionHandling();
|
||||||
|
|
||||||
public BatchFetchStyle getBatchFetchStyle();
|
BatchFetchStyle getBatchFetchStyle();
|
||||||
|
|
||||||
public int getDefaultBatchFetchSize();
|
int getDefaultBatchFetchSize();
|
||||||
|
|
||||||
public Integer getMaximumFetchDepth();
|
Integer getMaximumFetchDepth();
|
||||||
|
|
||||||
public NullPrecedence getDefaultNullPrecedence();
|
NullPrecedence getDefaultNullPrecedence();
|
||||||
|
|
||||||
public boolean isOrderUpdatesEnabled();
|
boolean isOrderUpdatesEnabled();
|
||||||
|
|
||||||
public boolean isOrderInsertsEnabled();
|
boolean isOrderInsertsEnabled();
|
||||||
|
|
||||||
public MultiTenancyStrategy getMultiTenancyStrategy();
|
MultiTenancyStrategy getMultiTenancyStrategy();
|
||||||
|
|
||||||
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
|
CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
|
||||||
|
|
||||||
public boolean isJtaTrackByThread();
|
boolean isJtaTrackByThread();
|
||||||
|
|
||||||
public Map getQuerySubstitutions();
|
Map getQuerySubstitutions();
|
||||||
|
|
||||||
public boolean isStrictJpaQueryLanguageCompliance();
|
boolean isStrictJpaQueryLanguageCompliance();
|
||||||
|
|
||||||
public boolean isNamedQueryStartupCheckingEnabled();
|
boolean isNamedQueryStartupCheckingEnabled();
|
||||||
|
|
||||||
public boolean isSecondLevelCacheEnabled();
|
boolean isSecondLevelCacheEnabled();
|
||||||
|
|
||||||
public boolean isQueryCacheEnabled();
|
boolean isQueryCacheEnabled();
|
||||||
|
|
||||||
public QueryCacheFactory getQueryCacheFactory();
|
QueryCacheFactory getQueryCacheFactory();
|
||||||
|
|
||||||
public String getCacheRegionPrefix();
|
String getCacheRegionPrefix();
|
||||||
|
|
||||||
public boolean isMinimalPutsEnabled();
|
boolean isMinimalPutsEnabled();
|
||||||
|
|
||||||
public boolean isStructuredCacheEntriesEnabled();
|
boolean isStructuredCacheEntriesEnabled();
|
||||||
|
|
||||||
public boolean isDirectReferenceCacheEntriesEnabled();
|
boolean isDirectReferenceCacheEntriesEnabled();
|
||||||
|
|
||||||
public boolean isAutoEvictCollectionCache();
|
boolean isAutoEvictCollectionCache();
|
||||||
|
|
||||||
public SchemaAutoTooling getSchemaAutoTooling();
|
SchemaAutoTooling getSchemaAutoTooling();
|
||||||
|
|
||||||
public int getJdbcBatchSize();
|
int getJdbcBatchSize();
|
||||||
|
|
||||||
public boolean isJdbcBatchVersionedData();
|
boolean isJdbcBatchVersionedData();
|
||||||
|
|
||||||
public boolean isScrollableResultSetsEnabled();
|
boolean isScrollableResultSetsEnabled();
|
||||||
|
|
||||||
public boolean isWrapResultSetsEnabled();
|
boolean isWrapResultSetsEnabled();
|
||||||
|
|
||||||
public boolean isGetGeneratedKeysEnabled();
|
boolean isGetGeneratedKeysEnabled();
|
||||||
|
|
||||||
public Integer getJdbcFetchSize();
|
Integer getJdbcFetchSize();
|
||||||
|
|
||||||
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
||||||
|
|
||||||
|
@ -161,22 +161,24 @@ public interface SessionFactoryOptions {
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ConnectionReleaseMode getConnectionReleaseMode();
|
ConnectionReleaseMode getConnectionReleaseMode();
|
||||||
|
|
||||||
public boolean isCommentsEnabled();
|
boolean isCommentsEnabled();
|
||||||
|
|
||||||
|
|
||||||
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
|
CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
|
||||||
public EntityNameResolver[] getEntityNameResolvers();
|
EntityNameResolver[] getEntityNameResolvers();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the delegate for handling entity-not-found exception conditions.
|
* Get the delegate for handling entity-not-found exception conditions.
|
||||||
*
|
*
|
||||||
* @return The specific EntityNotFoundDelegate to use, May be {@code null}
|
* @return The specific EntityNotFoundDelegate to use, May be {@code null}
|
||||||
*/
|
*/
|
||||||
public EntityNotFoundDelegate getEntityNotFoundDelegate();
|
EntityNotFoundDelegate getEntityNotFoundDelegate();
|
||||||
|
|
||||||
public Map<String, SQLFunction> getCustomSqlFunctionMap();
|
Map<String, SQLFunction> getCustomSqlFunctionMap();
|
||||||
|
|
||||||
void setCheckNullability(boolean enabled);
|
void setCheckNullability(boolean enabled);
|
||||||
|
|
||||||
public boolean isPreferUserTransaction();
|
boolean isPreferUserTransaction();
|
||||||
|
|
||||||
|
boolean isProcedureParameterNullPassingEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -997,4 +997,16 @@ public interface AvailableSettings {
|
||||||
*/
|
*/
|
||||||
String AUTO_SESSION_EVENTS_LISTENER = "hibernate.session.events.auto";
|
String AUTO_SESSION_EVENTS_LISTENER = "hibernate.session.events.auto";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global setting for whether NULL parameter bindings should be passed to database
|
||||||
|
* procedure/function calls as part of {@link org.hibernate.procedure.ProcedureCall}
|
||||||
|
* handling. Implicitly Hibernate will not pass the NULL, the intention being to allow
|
||||||
|
* any default argumnet values to be applied.
|
||||||
|
* <p/>
|
||||||
|
* This defines a global setting, which can them be controlled per parameter via
|
||||||
|
* {@link org.hibernate.procedure.ParameterRegistration#enablePassingNulls(boolean)}
|
||||||
|
* <p/>
|
||||||
|
* Values are {@code true} (pass the NULLs) or {@code false} (do not pass the NULLs).
|
||||||
|
*/
|
||||||
|
String PROCEDURE_NULL_PARAM_PASSING = "hibernate.proc.param_null_passing";
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.StoredProcedureParameter;
|
import javax.persistence.StoredProcedureParameter;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.engine.ResultSetMappingDefinition;
|
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
@ -48,10 +49,11 @@ public class NamedProcedureCallDefinition {
|
||||||
NamedProcedureCallDefinition(NamedStoredProcedureQuery annotation) {
|
NamedProcedureCallDefinition(NamedStoredProcedureQuery annotation) {
|
||||||
this.registeredName = annotation.name();
|
this.registeredName = annotation.name();
|
||||||
this.procedureName = annotation.procedureName();
|
this.procedureName = annotation.procedureName();
|
||||||
|
this.hints = new QueryHintDefinition( annotation.hints() ).getHintsMap();
|
||||||
this.resultClasses = annotation.resultClasses();
|
this.resultClasses = annotation.resultClasses();
|
||||||
this.resultSetMappings = annotation.resultSetMappings();
|
this.resultSetMappings = annotation.resultSetMappings();
|
||||||
this.parameterDefinitions = new ParameterDefinitions( annotation.parameters() );
|
|
||||||
this.hints = new QueryHintDefinition( annotation.hints() ).getHintsMap();
|
this.parameterDefinitions = new ParameterDefinitions( annotation.parameters(), hints );
|
||||||
|
|
||||||
final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0;
|
final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0;
|
||||||
final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0;
|
final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0;
|
||||||
|
@ -145,7 +147,7 @@ public class NamedProcedureCallDefinition {
|
||||||
private final ParameterStrategy parameterStrategy;
|
private final ParameterStrategy parameterStrategy;
|
||||||
private final ParameterDefinition[] parameterDefinitions;
|
private final ParameterDefinition[] parameterDefinitions;
|
||||||
|
|
||||||
ParameterDefinitions(StoredProcedureParameter[] parameters) {
|
ParameterDefinitions(StoredProcedureParameter[] parameters, Map<String, Object> queryHintMap) {
|
||||||
if ( parameters == null || parameters.length == 0 ) {
|
if ( parameters == null || parameters.length == 0 ) {
|
||||||
parameterStrategy = ParameterStrategy.POSITIONAL;
|
parameterStrategy = ParameterStrategy.POSITIONAL;
|
||||||
parameterDefinitions = new ParameterDefinition[0];
|
parameterDefinitions = new ParameterDefinition[0];
|
||||||
|
@ -155,9 +157,15 @@ public class NamedProcedureCallDefinition {
|
||||||
? ParameterStrategy.NAMED
|
? ParameterStrategy.NAMED
|
||||||
: ParameterStrategy.POSITIONAL;
|
: ParameterStrategy.POSITIONAL;
|
||||||
parameterDefinitions = new ParameterDefinition[ parameters.length ];
|
parameterDefinitions = new ParameterDefinition[ parameters.length ];
|
||||||
|
|
||||||
for ( int i = 0; i < parameters.length; i++ ) {
|
for ( int i = 0; i < parameters.length; i++ ) {
|
||||||
// i+1 for the position because the apis say the numbers are 1-based, not zero
|
parameterDefinitions[i] = ParameterDefinition.from(
|
||||||
parameterDefinitions[i] = new ParameterDefinition( i+1, parameters[i] );
|
parameterStrategy,
|
||||||
|
parameters[i],
|
||||||
|
// i+1 for the position because the apis say the numbers are 1-based, not zero
|
||||||
|
i+1,
|
||||||
|
queryHintMap
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,21 +188,62 @@ public class NamedProcedureCallDefinition {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final ParameterMode parameterMode;
|
private final ParameterMode parameterMode;
|
||||||
private final Class type;
|
private final Class type;
|
||||||
|
private final Boolean explicitPassNullSetting;
|
||||||
|
|
||||||
ParameterDefinition(int position, StoredProcedureParameter annotation) {
|
static ParameterDefinition from(
|
||||||
|
ParameterStrategy parameterStrategy,
|
||||||
|
StoredProcedureParameter parameterAnnotation,
|
||||||
|
int adjustedPosition,
|
||||||
|
Map<String, Object> queryHintMap) {
|
||||||
|
// see if there was an explicit hint for this parameter in regards to NULL passing
|
||||||
|
final Object explicitNullPassingHint;
|
||||||
|
if ( parameterStrategy == ParameterStrategy.NAMED ) {
|
||||||
|
explicitNullPassingHint = queryHintMap.get( AvailableSettings.PROCEDURE_NULL_PARAM_PASSING + '.' + parameterAnnotation.name() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
explicitNullPassingHint = queryHintMap.get( AvailableSettings.PROCEDURE_NULL_PARAM_PASSING + '.' + adjustedPosition );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParameterDefinition(
|
||||||
|
adjustedPosition,
|
||||||
|
parameterAnnotation,
|
||||||
|
interpretBoolean( explicitNullPassingHint )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Boolean interpretBoolean(Object value) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value instanceof Boolean ) {
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean.valueOf( value.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterDefinition(int position, StoredProcedureParameter annotation, Boolean explicitPassNullSetting) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.name = normalize( annotation.name() );
|
this.name = normalize( annotation.name() );
|
||||||
this.parameterMode = annotation.mode();
|
this.parameterMode = annotation.mode();
|
||||||
this.type = annotation.type();
|
this.type = annotation.type();
|
||||||
|
this.explicitPassNullSetting = explicitPassNullSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnnecessaryUnboxing")
|
||||||
public ParameterMemento toMemento(SessionFactoryImpl sessionFactory) {
|
public ParameterMemento toMemento(SessionFactoryImpl sessionFactory) {
|
||||||
|
final boolean initialPassNullSetting = explicitPassNullSetting != null
|
||||||
|
? explicitPassNullSetting.booleanValue()
|
||||||
|
: sessionFactory.getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
return new ParameterMemento(
|
return new ParameterMemento(
|
||||||
position,
|
position,
|
||||||
name,
|
name,
|
||||||
parameterMode,
|
parameterMode,
|
||||||
type,
|
type,
|
||||||
sessionFactory.getTypeResolver().heuristicType( type.getName() )
|
sessionFactory.getTypeResolver().heuristicType( type.getName() ),
|
||||||
|
initialPassNullSetting
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import javax.persistence.TemporalType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Describes a registered procedure/function parameter.
|
||||||
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ParameterRegistration<T> {
|
public interface ParameterRegistration<T> {
|
||||||
|
@ -21,7 +23,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The name;
|
* @return The name;
|
||||||
*/
|
*/
|
||||||
public String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The position at which this parameter was registered. Can be {@code null} which should indicate that
|
* The position at which this parameter was registered. Can be {@code null} which should indicate that
|
||||||
|
@ -29,7 +31,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The name;
|
* @return The name;
|
||||||
*/
|
*/
|
||||||
public Integer getPosition();
|
Integer getPosition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the Java type of parameter. This is used to guess the Hibernate type (unless {@link #setHibernateType}
|
* Obtain the Java type of parameter. This is used to guess the Hibernate type (unless {@link #setHibernateType}
|
||||||
|
@ -37,7 +39,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The parameter Java type.
|
* @return The parameter Java type.
|
||||||
*/
|
*/
|
||||||
public Class<T> getType();
|
Class<T> getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
|
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
|
||||||
|
@ -45,14 +47,32 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The parameter mode.
|
* @return The parameter mode.
|
||||||
*/
|
*/
|
||||||
public ParameterMode getMode();
|
ParameterMode getMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls how unbound values for this IN/INOUT parameter registration will be handled prior to
|
||||||
|
* execution. There are 2 possible options to handle it:<ul>
|
||||||
|
* <li>bind the NULL to the parameter</li>
|
||||||
|
* <li>do not bind the NULL to the parameter</li>
|
||||||
|
* </ul>
|
||||||
|
* <p/>
|
||||||
|
* The reason for the distinction comes from default values defined on the corresponding
|
||||||
|
* database procedure/function argument. Any time a value (including NULL) is bound to the
|
||||||
|
* argument, its default value will not be used. So effectively this setting controls
|
||||||
|
* whether the NULL should be interpreted as "pass the NULL" or as "apply the argument default".
|
||||||
|
* <p/>
|
||||||
|
* The (global) default this setting is defined by {@link org.hibernate.cfg.AvailableSettings#PROCEDURE_NULL_PARAM_PASSING}
|
||||||
|
*
|
||||||
|
* @param enabled {@code true} indicates that the NULL should be passed; {@code false} indicates it should not.
|
||||||
|
*/
|
||||||
|
void enablePassingNulls(boolean enabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Hibernate mapping type for this parameter.
|
* Set the Hibernate mapping type for this parameter.
|
||||||
*
|
*
|
||||||
* @param type The Hibernate mapping type.
|
* @param type The Hibernate mapping type.
|
||||||
*/
|
*/
|
||||||
public void setHibernateType(Type type);
|
void setHibernateType(Type type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the binding associated with this parameter. The binding is only relevant for INPUT parameters. Can
|
* Retrieve the binding associated with this parameter. The binding is only relevant for INPUT parameters. Can
|
||||||
|
@ -61,7 +81,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The parameter binding
|
* @return The parameter binding
|
||||||
*/
|
*/
|
||||||
public ParameterBind<T> getBind();
|
ParameterBind<T> getBind();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
|
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
|
||||||
|
@ -69,7 +89,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @param value The value to bind.
|
* @param value The value to bind.
|
||||||
*/
|
*/
|
||||||
public void bindValue(T value);
|
void bindValue(T value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a value to the parameter, using just a specified portion of the DATE/TIME value. It is illegal to call
|
* Bind a value to the parameter, using just a specified portion of the DATE/TIME value. It is illegal to call
|
||||||
|
@ -79,5 +99,5 @@ public interface ParameterRegistration<T> {
|
||||||
* @param value The value to bind
|
* @param value The value to bind
|
||||||
* @param explicitTemporalType An explicitly supplied TemporalType.
|
* @param explicitTemporalType An explicitly supplied TemporalType.
|
||||||
*/
|
*/
|
||||||
public void bindValue(T value, TemporalType explicitTemporalType);
|
void bindValue(T value, TemporalType explicitTemporalType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
private final Class<T> type;
|
private final Class<T> type;
|
||||||
|
|
||||||
private ParameterBindImpl bind;
|
private ParameterBindImpl bind;
|
||||||
|
private boolean passNulls;
|
||||||
|
|
||||||
private int startIndex;
|
private int startIndex;
|
||||||
private Type hibernateType;
|
private Type hibernateType;
|
||||||
|
@ -56,8 +57,9 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
ProcedureCallImpl procedureCall,
|
ProcedureCallImpl procedureCall,
|
||||||
Integer position,
|
Integer position,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type) {
|
Class<T> type,
|
||||||
this( procedureCall, position, null, mode, type );
|
boolean initialPassNullsSetting) {
|
||||||
|
this( procedureCall, position, null, mode, type, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
protected AbstractParameterRegistrationImpl(
|
||||||
|
@ -65,8 +67,9 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
Integer position,
|
Integer position,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type,
|
Class<T> type,
|
||||||
Type hibernateType) {
|
Type hibernateType,
|
||||||
this( procedureCall, position, null, mode, type, hibernateType );
|
boolean initialPassNullsSetting) {
|
||||||
|
this( procedureCall, position, null, mode, type, hibernateType, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,8 +79,9 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
ProcedureCallImpl procedureCall,
|
ProcedureCallImpl procedureCall,
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type) {
|
Class<T> type,
|
||||||
this( procedureCall, null, name, mode, type );
|
boolean initialPassNullsSetting) {
|
||||||
|
this( procedureCall, null, name, mode, type, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
protected AbstractParameterRegistrationImpl(
|
||||||
|
@ -85,8 +89,9 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type,
|
Class<T> type,
|
||||||
Type hibernateType) {
|
Type hibernateType,
|
||||||
this( procedureCall, null, name, mode, type, hibernateType );
|
boolean initialPassNullsSetting) {
|
||||||
|
this( procedureCall, null, name, mode, type, hibernateType, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +103,8 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type,
|
Class<T> type,
|
||||||
Type hibernateType) {
|
Type hibernateType,
|
||||||
|
boolean initialPassNullsSetting) {
|
||||||
this.procedureCall = procedureCall;
|
this.procedureCall = procedureCall;
|
||||||
|
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
@ -111,6 +117,7 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.passNulls = initialPassNullsSetting;
|
||||||
setHibernateType( hibernateType );
|
setHibernateType( hibernateType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,14 +126,16 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
Integer position,
|
Integer position,
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type) {
|
Class<T> type,
|
||||||
|
boolean initialPassNullsSetting) {
|
||||||
this(
|
this(
|
||||||
procedureCall,
|
procedureCall,
|
||||||
position,
|
position,
|
||||||
name,
|
name,
|
||||||
mode,
|
mode,
|
||||||
type,
|
type,
|
||||||
procedureCall.getSession().getFactory().getTypeResolver().heuristicType( type.getName() )
|
procedureCall.getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
|
||||||
|
initialPassNullsSetting
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +163,16 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPassNullsEnabled() {
|
||||||
|
return passNulls;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enablePassingNulls(boolean enabled) {
|
||||||
|
this.passNulls = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getHibernateType() {
|
public Type getHibernateType() {
|
||||||
return hibernateType;
|
return hibernateType;
|
||||||
|
@ -258,17 +277,28 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
|
|
||||||
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
|
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
|
||||||
if ( bind == null || bind.getValue() == null ) {
|
if ( bind == null || bind.getValue() == null ) {
|
||||||
// the user did not bind a value to the parameter being processed. That might be ok *if* the
|
// the user did not bind a value to the parameter being processed. This is the condition
|
||||||
// procedure as defined in the database defines a default value for that parameter.
|
// defined by `passNulls` and that value controls what happens here. If `passNulls` is
|
||||||
|
// {@code true} we will bind the NULL value into the statement; if `passNulls` is
|
||||||
|
// {@code false} we will not.
|
||||||
|
//
|
||||||
// Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure
|
// 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
|
// parameter defines a default value. Deferring to that information would be the best option
|
||||||
// assuming that the database will complain appropriately if not setting the given parameter
|
if ( passNulls ) {
|
||||||
// bind value is an error.
|
log.debugf(
|
||||||
log.debugf(
|
"Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to true; binding NULL",
|
||||||
"Stored procedure [%s] IN/INOUT parameter [%s] not bound; assuming procedure defines default value",
|
procedureCall.getProcedureName(),
|
||||||
procedureCall.getProcedureName(),
|
this
|
||||||
this
|
);
|
||||||
);
|
typeToUse.nullSafeSet( statement, null, startIndex, session() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.debugf(
|
||||||
|
"Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to false; assuming procedure defines default value",
|
||||||
|
procedureCall.getProcedureName(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, session() );
|
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, session() );
|
||||||
|
|
|
@ -20,8 +20,9 @@ public class NamedParameterRegistration<T> extends AbstractParameterRegistration
|
||||||
ProcedureCallImpl procedureCall,
|
ProcedureCallImpl procedureCall,
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type) {
|
Class<T> type,
|
||||||
super( procedureCall, name, mode, type );
|
boolean initialPassNullsSetting) {
|
||||||
|
super( procedureCall, name, mode, type, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedParameterRegistration(
|
NamedParameterRegistration(
|
||||||
|
@ -29,7 +30,8 @@ public class NamedParameterRegistration<T> extends AbstractParameterRegistration
|
||||||
String name,
|
String name,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type,
|
Class<T> type,
|
||||||
Type hibernateType) {
|
Type hibernateType,
|
||||||
super( procedureCall, name, mode, type, hibernateType );
|
boolean initialPassNullsSetting) {
|
||||||
|
super( procedureCall, name, mode, type, hibernateType, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,9 @@ public class PositionalParameterRegistration<T> extends AbstractParameterRegistr
|
||||||
ProcedureCallImpl procedureCall,
|
ProcedureCallImpl procedureCall,
|
||||||
Integer position,
|
Integer position,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type) {
|
Class<T> type,
|
||||||
super( procedureCall, position, mode, type );
|
boolean initialPassNullsSetting) {
|
||||||
|
super( procedureCall, position, mode, type, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionalParameterRegistration(
|
PositionalParameterRegistration(
|
||||||
|
@ -29,7 +30,8 @@ public class PositionalParameterRegistration<T> extends AbstractParameterRegistr
|
||||||
Integer position,
|
Integer position,
|
||||||
ParameterMode mode,
|
ParameterMode mode,
|
||||||
Class<T> type,
|
Class<T> type,
|
||||||
Type hibernateType) {
|
Type hibernateType,
|
||||||
super( procedureCall, position, mode, type, hibernateType );
|
boolean initialPassNullsSetting) {
|
||||||
|
super( procedureCall, position, mode, type, hibernateType, initialPassNullsSetting );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
private final String procedureName;
|
private final String procedureName;
|
||||||
private final NativeSQLQueryReturn[] queryReturns;
|
private final NativeSQLQueryReturn[] queryReturns;
|
||||||
|
|
||||||
|
private final boolean globalParameterPassNullsSetting;
|
||||||
|
|
||||||
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
|
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
|
||||||
private List<ParameterRegistrationImplementor<?>> registeredParameters = new ArrayList<ParameterRegistrationImplementor<?>>();
|
private List<ParameterRegistrationImplementor<?>> registeredParameters = new ArrayList<ParameterRegistrationImplementor<?>>();
|
||||||
|
|
||||||
|
@ -77,6 +79,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
public ProcedureCallImpl(SessionImplementor session, String procedureName) {
|
public ProcedureCallImpl(SessionImplementor session, String procedureName) {
|
||||||
super( session );
|
super( session );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
this.queryReturns = NO_RETURNS;
|
this.queryReturns = NO_RETURNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +94,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
public ProcedureCallImpl(final SessionImplementor session, String procedureName, Class... resultClasses) {
|
public ProcedureCallImpl(final SessionImplementor session, String procedureName, Class... resultClasses) {
|
||||||
super( session );
|
super( session );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
|
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
|
||||||
final Set<String> collectedQuerySpaces = new HashSet<String>();
|
final Set<String> collectedQuerySpaces = new HashSet<String>();
|
||||||
|
@ -128,6 +133,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
public ProcedureCallImpl(final SessionImplementor session, String procedureName, String... resultSetMappings) {
|
public ProcedureCallImpl(final SessionImplementor session, String procedureName, String... resultSetMappings) {
|
||||||
super( session );
|
super( session );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
|
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
|
||||||
final Set<String> collectedQuerySpaces = new HashSet<String>();
|
final Set<String> collectedQuerySpaces = new HashSet<String>();
|
||||||
|
@ -171,6 +177,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
ProcedureCallImpl(SessionImplementor session, ProcedureCallMementoImpl memento) {
|
ProcedureCallImpl(SessionImplementor session, ProcedureCallMementoImpl memento) {
|
||||||
super( session );
|
super( session );
|
||||||
this.procedureName = memento.getProcedureName();
|
this.procedureName = memento.getProcedureName();
|
||||||
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
this.queryReturns = memento.getQueryReturns();
|
this.queryReturns = memento.getQueryReturns();
|
||||||
this.synchronizedQuerySpaces = Util.copy( memento.getSynchronizedQuerySpaces() );
|
this.synchronizedQuerySpaces = Util.copy( memento.getSynchronizedQuerySpaces() );
|
||||||
|
@ -207,7 +214,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
storedRegistration.getName(),
|
storedRegistration.getName(),
|
||||||
storedRegistration.getMode(),
|
storedRegistration.getMode(),
|
||||||
storedRegistration.getType(),
|
storedRegistration.getType(),
|
||||||
storedRegistration.getHibernateType()
|
storedRegistration.getHibernateType(),
|
||||||
|
storedRegistration.isPassNullsEnabled()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -221,7 +229,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
storedRegistration.getPosition(),
|
storedRegistration.getPosition(),
|
||||||
storedRegistration.getMode(),
|
storedRegistration.getMode(),
|
||||||
storedRegistration.getType(),
|
storedRegistration.getType(),
|
||||||
storedRegistration.getHibernateType()
|
storedRegistration.getHibernateType(),
|
||||||
|
storedRegistration.isPassNullsEnabled()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
parameterRegistrations.add( registration );
|
parameterRegistrations.add( registration );
|
||||||
|
@ -257,7 +266,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) {
|
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) {
|
||||||
final PositionalParameterRegistration parameterRegistration =
|
final PositionalParameterRegistration parameterRegistration =
|
||||||
new PositionalParameterRegistration( this, position, mode, type );
|
new PositionalParameterRegistration( this, position, mode, type, globalParameterPassNullsSetting );
|
||||||
registerParameter( parameterRegistration );
|
registerParameter( parameterRegistration );
|
||||||
return parameterRegistration;
|
return parameterRegistration;
|
||||||
}
|
}
|
||||||
|
@ -326,7 +335,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
|
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
|
||||||
final NamedParameterRegistration parameterRegistration = new NamedParameterRegistration( this, name, mode, type );
|
final NamedParameterRegistration parameterRegistration = new NamedParameterRegistration( this, name, mode, type, globalParameterPassNullsSetting );
|
||||||
registerParameter( parameterRegistration );
|
registerParameter( parameterRegistration );
|
||||||
return parameterRegistration;
|
return parameterRegistration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ public class ProcedureCallMementoImpl implements ProcedureCallMemento {
|
||||||
private final ParameterMode mode;
|
private final ParameterMode mode;
|
||||||
private final Class type;
|
private final Class type;
|
||||||
private final Type hibernateType;
|
private final Type hibernateType;
|
||||||
|
private final boolean passNulls;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the memento
|
* Create the memento
|
||||||
|
@ -114,13 +115,21 @@ public class ProcedureCallMementoImpl implements ProcedureCallMemento {
|
||||||
* @param mode The parameter mode
|
* @param mode The parameter mode
|
||||||
* @param type The Java type of the parameter
|
* @param type The Java type of the parameter
|
||||||
* @param hibernateType The Hibernate Type.
|
* @param hibernateType The Hibernate Type.
|
||||||
|
* @param passNulls Should NULL values to passed to the database?
|
||||||
*/
|
*/
|
||||||
public ParameterMemento(int position, String name, ParameterMode mode, Class type, Type hibernateType) {
|
public ParameterMemento(
|
||||||
|
int position,
|
||||||
|
String name,
|
||||||
|
ParameterMode mode,
|
||||||
|
Class type,
|
||||||
|
Type hibernateType,
|
||||||
|
boolean passNulls) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.hibernateType = hibernateType;
|
this.hibernateType = hibernateType;
|
||||||
|
this.passNulls = passNulls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getPosition() {
|
public Integer getPosition() {
|
||||||
|
@ -143,6 +152,10 @@ public class ProcedureCallMementoImpl implements ProcedureCallMemento {
|
||||||
return hibernateType;
|
return hibernateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPassNullsEnabled() {
|
||||||
|
return passNulls;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a ParameterMemento from the given parameter registration
|
* Build a ParameterMemento from the given parameter registration
|
||||||
*
|
*
|
||||||
|
@ -156,7 +169,8 @@ public class ProcedureCallMementoImpl implements ProcedureCallMemento {
|
||||||
registration.getName(),
|
registration.getName(),
|
||||||
registration.getMode(),
|
registration.getMode(),
|
||||||
registration.getType(),
|
registration.getType(),
|
||||||
registration.getHibernateType()
|
registration.getHibernateType(),
|
||||||
|
registration.isPassNullsEnabled()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,21 +26,23 @@ public interface ParameterRegistrationImplementor<T> extends ParameterRegistrati
|
||||||
*
|
*
|
||||||
* @throws SQLException Indicates a problem accessing the statement object
|
* @throws SQLException Indicates a problem accessing the statement object
|
||||||
*/
|
*/
|
||||||
public void prepare(CallableStatement statement, int i) throws SQLException;
|
void prepare(CallableStatement statement, int i) throws SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to the Hibernate type for this parameter registration
|
* Access to the Hibernate type for this parameter registration
|
||||||
*
|
*
|
||||||
* @return The Hibernate Type
|
* @return The Hibernate Type
|
||||||
*/
|
*/
|
||||||
public Type getHibernateType();
|
Type getHibernateType();
|
||||||
|
|
||||||
|
boolean isPassNullsEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to the SQL type(s) for this parameter
|
* Access to the SQL type(s) for this parameter
|
||||||
*
|
*
|
||||||
* @return The SQL types (JDBC type codes)
|
* @return The SQL types (JDBC type codes)
|
||||||
*/
|
*/
|
||||||
public int[] getSqlTypes();
|
int[] getSqlTypes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract value from the statement after execution (used for OUT/INOUT parameters).
|
* Extract value from the statement after execution (used for OUT/INOUT parameters).
|
||||||
|
@ -49,6 +51,6 @@ public interface ParameterRegistrationImplementor<T> extends ParameterRegistrati
|
||||||
*
|
*
|
||||||
* @return The extracted value
|
* @return The extracted value
|
||||||
*/
|
*/
|
||||||
public T extract(CallableStatement statement);
|
T extract(CallableStatement statement);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,13 @@
|
||||||
package org.hibernate.test.sql.storedproc;
|
package org.hibernate.test.sql.storedproc;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.NamedStoredProcedureQueries;
|
||||||
|
import javax.persistence.NamedStoredProcedureQuery;
|
||||||
import javax.persistence.ParameterMode;
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.QueryHint;
|
||||||
|
import javax.persistence.StoredProcedureParameter;
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
import org.hibernate.JDBCException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
@ -34,6 +40,11 @@ import static org.junit.Assert.fail;
|
||||||
*/
|
*/
|
||||||
@RequiresDialect( H2Dialect.class )
|
@RequiresDialect( H2Dialect.class )
|
||||||
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { MyEntity.class };
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(Configuration configuration) {
|
protected void configure(Configuration configuration) {
|
||||||
super.configure( configuration );
|
super.configure( configuration );
|
||||||
|
@ -328,4 +339,109 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInParametersNotSetPass() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
// unlike #testInParametersNotSet here we are asking that the NULL be passed
|
||||||
|
// so these executions should succeed
|
||||||
|
|
||||||
|
|
||||||
|
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
query.registerParameter( 1, Integer.class, ParameterMode.IN ).enablePassingNulls( true );
|
||||||
|
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
query.getOutputs();
|
||||||
|
|
||||||
|
// H2 does not support named parameters
|
||||||
|
// {
|
||||||
|
// ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
// query.registerParameter( "start", Integer.class, ParameterMode.IN );
|
||||||
|
// query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
// try {
|
||||||
|
// query.getOutputs();
|
||||||
|
// fail( "Expecting failure due to missing parameter bind" );
|
||||||
|
// }
|
||||||
|
// catch (JDBCException expected) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void testInParametersNullnessPassingInNamedQueriesViaHints() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
// similar to #testInParametersNotSet and #testInParametersNotSetPass in terms of testing
|
||||||
|
// support for specifying whether to pass NULL argument values or not. This version tests
|
||||||
|
// named procedure support via hints.
|
||||||
|
|
||||||
|
// first a fixture - this execution should fail
|
||||||
|
{
|
||||||
|
ProcedureCall query = session.getNamedProcedureCall( "findUserRangeNoNullPassing" );
|
||||||
|
query.getParameterRegistration( 2 ).bindValue( 2 );
|
||||||
|
try {
|
||||||
|
query.getOutputs();
|
||||||
|
fail( "Expecting failure due to missing parameter bind" );
|
||||||
|
}
|
||||||
|
catch (JDBCException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we enable NULL passing via hint through a named parameter
|
||||||
|
{
|
||||||
|
ProcedureCall query = session.getNamedProcedureCall( "findUserRangeNamedNullPassing" );
|
||||||
|
query.getParameterRegistration( "secondArg" ).bindValue( 2 );
|
||||||
|
query.getOutputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we enable NULL passing via hint through a named parameter
|
||||||
|
{
|
||||||
|
ProcedureCall query = session.getNamedProcedureCall( "findUserRangeOrdinalNullPassing" );
|
||||||
|
query.getParameterRegistration( 2 ).bindValue( 2 );
|
||||||
|
query.getOutputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@NamedStoredProcedureQueries( {
|
||||||
|
@NamedStoredProcedureQuery(
|
||||||
|
name = "findUserRangeNoNullPassing",
|
||||||
|
procedureName = "findUserRange",
|
||||||
|
parameters = {
|
||||||
|
@StoredProcedureParameter( type = Integer.class ),
|
||||||
|
@StoredProcedureParameter( type = Integer.class ),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
@NamedStoredProcedureQuery(
|
||||||
|
name = "findUserRangeNamedNullPassing",
|
||||||
|
procedureName = "findUserRange",
|
||||||
|
hints = @QueryHint( name = "hibernate.proc.param_null_passing.firstArg", value = "true" ),
|
||||||
|
parameters = {
|
||||||
|
@StoredProcedureParameter( name = "firstArg", type = Integer.class ),
|
||||||
|
@StoredProcedureParameter( name = "secondArg", type = Integer.class ),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
@NamedStoredProcedureQuery(
|
||||||
|
name = "findUserRangeOrdinalNullPassing",
|
||||||
|
procedureName = "findUserRange",
|
||||||
|
hints = @QueryHint( name = "hibernate.proc.param_null_passing.1", value = "true" ),
|
||||||
|
parameters = {
|
||||||
|
@StoredProcedureParameter( type = Integer.class ),
|
||||||
|
@StoredProcedureParameter( type = Integer.class ),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} )
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue