HHH-18280 add hibernate.query.pass_procedure_paramater_names setting
This commit is contained in:
parent
8740a832d2
commit
03e48d8355
|
@ -1136,12 +1136,6 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
|
||||
// Not sure if it's a JDBC driver issue, but it doesn't work
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generatedAs(String generatedAs) {
|
||||
return " as (" + generatedAs + ") persisted";
|
||||
|
|
|
@ -208,6 +208,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private boolean orderInsertsEnabled;
|
||||
private boolean collectionsInDefaultFetchGroupEnabled = true;
|
||||
private boolean UnownedAssociationTransientCheck;
|
||||
private boolean passProcedureParameterNames;
|
||||
|
||||
// JPA callbacks
|
||||
private final boolean callbacksEnabled;
|
||||
|
@ -627,6 +628,12 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
configurationSettings,
|
||||
isJpaBootstrap()
|
||||
);
|
||||
|
||||
this.passProcedureParameterNames = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES,
|
||||
configurationSettings,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private boolean disallowBatchUpdates(Dialect dialect, ExtractedDatabaseMetaData meta) {
|
||||
|
@ -1318,6 +1325,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return xmlFormatMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassProcedureParameterNames() {
|
||||
return passProcedureParameterNames;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// In-flight mutation access
|
||||
|
||||
|
|
|
@ -512,4 +512,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public FormatMapper getXmlFormatMapper() {
|
||||
return delegate.getXmlFormatMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassProcedureParameterNames() {
|
||||
return delegate.isPassProcedureParameterNames();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -374,4 +374,6 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
|||
default JavaType<Object> getDefaultTenantIdentifierJavaType() {
|
||||
return ObjectJavaType.INSTANCE;
|
||||
}
|
||||
|
||||
boolean isPassProcedureParameterNames();
|
||||
}
|
||||
|
|
|
@ -242,4 +242,11 @@ public interface QuerySettings {
|
|||
*/
|
||||
@Deprecated(since="6.0")
|
||||
String QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE = "hibernate.query.plan_parameter_metadata_max_size";
|
||||
|
||||
/**
|
||||
* For database supporting name parameters this setting allows to use named parameter is the procedure call.
|
||||
*
|
||||
* By default, this is set to false
|
||||
*/
|
||||
String QUERY_PASS_PROCEDURE_PARAMETER_NAMES = "hibernate.query.pass_procedure_paramater_names";
|
||||
}
|
||||
|
|
|
@ -857,11 +857,6 @@ public class DB2Dialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
|
||||
statement.registerOutParameter( col++, Types.REF_CURSOR );
|
||||
|
|
|
@ -1582,12 +1582,6 @@ public class OracleDialect extends Dialect {
|
|||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
|
||||
// Not sure if it's a JDBC driver issue, but it doesn't work
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
|
||||
return (ResultSet) statement.getObject( name );
|
||||
|
|
|
@ -1122,11 +1122,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generatedAs(String generatedAs) {
|
||||
return " as (" + generatedAs + ") persisted";
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.procedure.internal;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||
import org.hibernate.procedure.spi.ParameterStrategy;
|
||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||
|
@ -84,7 +85,10 @@ public class DB2CallableStatementSupport extends AbstractStandardCallableStateme
|
|||
i + offset,
|
||||
procedureCall
|
||||
);
|
||||
if ( parameter.getName() != null ) {
|
||||
final SharedSessionContractImplementor session = procedureCall.getSession();
|
||||
if ( parameter.getName() != null
|
||||
&& session.getJdbcServices().getExtractedMetaDataSupport().supportsNamedParameters()
|
||||
&& session.getFactory().getSessionFactoryOptions().isPassProcedureParameterNames() ) {
|
||||
buffer.append( parameter.getName() ).append( " => ?" );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -52,7 +52,7 @@ public class FunctionReturnImpl<T> implements FunctionReturnImplementor<T> {
|
|||
final JdbcCallParameterExtractorImpl<T> parameterExtractor;
|
||||
|
||||
if ( getJdbcTypeCode() == Types.REF_CURSOR ) {
|
||||
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( null, 1 );
|
||||
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( 1 );
|
||||
ormType = null;
|
||||
parameterExtractor = null;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ public class OracleCallableStatementSupport extends StandardCallableStatementSup
|
|||
super( supportsRefCursors );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendNameParameter(
|
||||
StringBuilder buffer,
|
||||
ProcedureParameterImplementor parameter,
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.procedure.internal;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.procedure.ParameterTypeException;
|
||||
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
|
||||
import org.hibernate.procedure.spi.ParameterStrategy;
|
||||
|
@ -29,7 +25,6 @@ import org.hibernate.sql.exec.internal.JdbcCallParameterExtractorImpl;
|
|||
import org.hibernate.sql.exec.internal.JdbcCallParameterRegistrationImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcCallRefCursorExtractorImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
@ -138,45 +133,49 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
|
|||
bindableType = null;
|
||||
}
|
||||
|
||||
final SharedSessionContractImplementor session = procedureCall.getSession();
|
||||
|
||||
final OutputableType<T> typeToUse = (OutputableType<T>) BindingTypeHelper.INSTANCE.resolveTemporalPrecision(
|
||||
binding == null ? null : binding.getExplicitTemporalPrecision(),
|
||||
bindableType,
|
||||
procedureCall.getSession().getFactory()
|
||||
session.getFactory()
|
||||
);
|
||||
|
||||
final String jdbcParamName;
|
||||
final JdbcParameterBinder parameterBinder;
|
||||
final JdbcCallRefCursorExtractorImpl refCursorExtractor;
|
||||
final JdbcCallParameterExtractorImpl<T> parameterExtractor;
|
||||
final ExtractedDatabaseMetaData databaseMetaData = procedureCall.getSession()
|
||||
final ExtractedDatabaseMetaData databaseMetaData = session
|
||||
.getFactory()
|
||||
.getJdbcServices()
|
||||
.getJdbcEnvironment()
|
||||
.getExtractedDatabaseMetaData();
|
||||
|
||||
final boolean passProcedureParameterNames = session.getFactory()
|
||||
.getSessionFactoryOptions()
|
||||
.isPassProcedureParameterNames();
|
||||
switch ( mode ) {
|
||||
case REF_CURSOR:
|
||||
jdbcParamName = this.name != null && databaseMetaData.supportsNamedParameters() ? this.name : null;
|
||||
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( jdbcParamName, startIndex );
|
||||
jdbcParamName = this.name != null && databaseMetaData.supportsNamedParameters() && passProcedureParameterNames ? this.name : null;
|
||||
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( startIndex );
|
||||
parameterBinder = null;
|
||||
parameterExtractor = null;
|
||||
break;
|
||||
case IN:
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, passProcedureParameterNames, typeToUse, databaseMetaData );
|
||||
validateBindableType( typeToUse, startIndex );
|
||||
parameterBinder = getParameterBinder( typeToUse, jdbcParamName );
|
||||
parameterExtractor = null;
|
||||
refCursorExtractor = null;
|
||||
break;
|
||||
case INOUT:
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, passProcedureParameterNames, typeToUse, databaseMetaData );
|
||||
validateBindableType( typeToUse, startIndex );
|
||||
parameterBinder = getParameterBinder( typeToUse, jdbcParamName );
|
||||
parameterExtractor = new JdbcCallParameterExtractorImpl<>( procedureCall.getProcedureName(), jdbcParamName, startIndex, typeToUse );
|
||||
refCursorExtractor = null;
|
||||
break;
|
||||
default:
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
|
||||
jdbcParamName = getJdbcParamName( procedureCall, isNamed, passProcedureParameterNames, typeToUse, databaseMetaData );
|
||||
validateBindableType( typeToUse, startIndex );
|
||||
parameterBinder = null;
|
||||
parameterExtractor = new JdbcCallParameterExtractorImpl<>( procedureCall.getProcedureName(), jdbcParamName, startIndex, typeToUse );
|
||||
|
@ -190,9 +189,10 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
|
|||
private String getJdbcParamName(
|
||||
ProcedureCallImplementor<?> procedureCall,
|
||||
boolean isNamed,
|
||||
boolean passProcedureParameterNames,
|
||||
OutputableType<T> typeToUse,
|
||||
ExtractedDatabaseMetaData databaseMetaData) {
|
||||
return isNamed && canDoNameParameterBinding( typeToUse, procedureCall, databaseMetaData ) ? this.name : null;
|
||||
return isNamed && passProcedureParameterNames && canDoNameParameterBinding( typeToUse, procedureCall, databaseMetaData ) ? this.name : null;
|
||||
}
|
||||
|
||||
private void validateBindableType(BindableType<T> bindableType, int startIndex) {
|
||||
|
@ -221,31 +221,7 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
|
|||
}
|
||||
|
||||
if ( typeToUse instanceof BasicType<?> ) {
|
||||
if ( name == null ) {
|
||||
return new JdbcParameterImpl( (BasicType<T>) typeToUse );
|
||||
}
|
||||
else {
|
||||
return new JdbcParameterImpl( (BasicType<T>) typeToUse ) {
|
||||
@Override
|
||||
protected void bindParameterValue(
|
||||
JdbcMapping jdbcMapping,
|
||||
PreparedStatement statement,
|
||||
Object bindValue,
|
||||
int startPosition,
|
||||
ExecutionContext executionContext) throws SQLException {
|
||||
jdbcMapping.getJdbcValueBinder().bind(
|
||||
(CallableStatement) statement,
|
||||
bindValue,
|
||||
name,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JdbcParameter(" + name + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
return new JdbcParameterImpl( (BasicType<T>) typeToUse );
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -18,6 +18,7 @@ public class SQLServerCallableStatementSupport extends StandardCallableStatement
|
|||
super( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendNameParameter(StringBuilder buffer, ProcedureParameterImplementor parameter, JdbcCallParameterRegistration registration) {
|
||||
buffer.append( '@' ).append( parameter.getName() ).append( " = ?" );
|
||||
}
|
||||
|
|
|
@ -91,7 +91,9 @@ public class StandardCallableStatementSupport extends AbstractStandardCallableSt
|
|||
i + offset,
|
||||
procedureCall
|
||||
);
|
||||
if ( parameter.getName() != null ) {
|
||||
if ( parameter.getName() != null
|
||||
&& session.getJdbcServices().getExtractedMetaDataSupport().supportsNamedParameters()
|
||||
&& session.getFactory().getSessionFactoryOptions().isPassProcedureParameterNames() ) {
|
||||
appendNameParameter( buffer, parameter, registration );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.procedure.internal;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
||||
|
@ -80,7 +81,10 @@ public class SybaseCallableStatementSupport extends AbstractStandardCallableStat
|
|||
i + offset,
|
||||
procedureCall
|
||||
);
|
||||
if ( parameter.getName() != null ) {
|
||||
final SharedSessionContractImplementor session = procedureCall.getSession();
|
||||
if ( parameter.getName() != null
|
||||
&& session.getJdbcServices().getExtractedMetaDataSupport().supportsNamedParameters()
|
||||
&& session.getFactory().getSessionFactoryOptions().isPassProcedureParameterNames() ) {
|
||||
buffer.append("@").append( parameter.getName() ).append( " = ?" );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -50,20 +50,8 @@ public class JdbcCallParameterExtractorImpl<T> implements JdbcCallParameterExtra
|
|||
CallableStatement callableStatement,
|
||||
boolean shouldUseJdbcNamedParameters,
|
||||
SharedSessionContractImplementor session) {
|
||||
|
||||
final boolean useNamed = shouldUseJdbcNamedParameters
|
||||
&& parameterName != null;
|
||||
|
||||
// todo (6.0) : we should just ask BasicValuedExpressibleType for the JdbcValueExtractor...
|
||||
|
||||
|
||||
try {
|
||||
if ( useNamed ) {
|
||||
return ormType.extract( callableStatement, parameterName, session );
|
||||
}
|
||||
else {
|
||||
return ormType.extract( callableStatement, parameterPosition, session );
|
||||
}
|
||||
return ormType.extract( callableStatement, parameterPosition, session );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||
|
|
|
@ -101,16 +101,9 @@ public class JdbcCallParameterRegistrationImpl implements JdbcCallParameterRegis
|
|||
private void registerRefCursorParameter(
|
||||
CallableStatement callableStatement,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( name != null ) {
|
||||
session.getFactory().getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.registerRefCursorParameter( callableStatement, name );
|
||||
}
|
||||
else {
|
||||
session.getFactory().getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.registerRefCursorParameter( callableStatement, jdbcParameterPositionStart );
|
||||
}
|
||||
session.getFactory().getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.registerRefCursorParameter( callableStatement, jdbcParameterPositionStart );
|
||||
|
||||
}
|
||||
|
||||
|
@ -119,12 +112,7 @@ public class JdbcCallParameterRegistrationImpl implements JdbcCallParameterRegis
|
|||
SharedSessionContractImplementor session) {
|
||||
final JdbcType sqlTypeDescriptor = ormType.getJdbcType();
|
||||
try {
|
||||
if ( name != null ) {
|
||||
sqlTypeDescriptor.registerOutParameter( callableStatement, name );
|
||||
}
|
||||
else {
|
||||
sqlTypeDescriptor.registerOutParameter( callableStatement, jdbcParameterPositionStart );
|
||||
}
|
||||
sqlTypeDescriptor.registerOutParameter( callableStatement, jdbcParameterPositionStart );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||
|
|
|
@ -21,13 +21,10 @@ import org.hibernate.sql.exec.spi.JdbcCallRefCursorExtractor;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcCallRefCursorExtractorImpl implements JdbcCallRefCursorExtractor {
|
||||
private final String jdbcParameterName;
|
||||
private final int jdbcParameterPosition;
|
||||
|
||||
public JdbcCallRefCursorExtractorImpl(
|
||||
String jdbcParameterName,
|
||||
int jdbcParameterPosition) {
|
||||
this.jdbcParameterName = jdbcParameterName;
|
||||
this.jdbcParameterPosition = jdbcParameterPosition;
|
||||
}
|
||||
|
||||
|
@ -39,19 +36,9 @@ public class JdbcCallRefCursorExtractorImpl implements JdbcCallRefCursorExtracto
|
|||
.getJdbcEnvironment()
|
||||
.getExtractedDatabaseMetaData()
|
||||
.supportsNamedParameters();
|
||||
final boolean useNamed = supportsNamedParameters && jdbcParameterName != null;
|
||||
|
||||
if ( useNamed ) {
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.getResultSet( callableStatement, jdbcParameterName );
|
||||
}
|
||||
else {
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.getResultSet( callableStatement, jdbcParameterPosition );
|
||||
}
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.requireService( RefCursorSupport.class )
|
||||
.getResultSet( callableStatement, jdbcParameterPosition );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.time.ZoneOffset;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.query.procedure.ProcedureParameter;
|
||||
|
@ -29,6 +30,7 @@ import org.hibernate.testing.orm.junit.Jira;
|
|||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
@ -58,13 +60,16 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
/**
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
@Jpa( annotatedClasses = {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
Vote.class,
|
||||
DB2StoredProcedureTest.IdHolder.class,
|
||||
DB2StoredProcedureTest.Address.class,
|
||||
} )
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
Vote.class,
|
||||
DB2StoredProcedureTest.IdHolder.class,
|
||||
DB2StoredProcedureTest.Address.class,
|
||||
},
|
||||
properties = @Setting(name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "true")
|
||||
)
|
||||
@RequiresDialect( value = DB2Dialect.class )
|
||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-18332" )
|
||||
public class DB2StoredProcedureTest {
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.QueryHints;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.query.procedure.ProcedureParameter;
|
||||
|
@ -31,6 +32,7 @@ import org.hibernate.testing.TestForIssue;
|
|||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -65,7 +67,8 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
OracleStoredProcedureTest.IdHolder.class,
|
||||
Vote.class,
|
||||
OracleStoredProcedureTest.Address.class
|
||||
}
|
||||
},
|
||||
properties = @Setting( name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "true")
|
||||
)
|
||||
@RequiresDialect(value = OracleDialect.class)
|
||||
public class OracleStoredProcedureTest {
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.time.ZoneOffset;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
@ -26,6 +27,7 @@ import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
|||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -53,7 +55,8 @@ import static org.junit.Assert.fail;
|
|||
Person.class,
|
||||
Phone.class,
|
||||
PostgreSQLStoredProcedureTest.Address.class
|
||||
}
|
||||
},
|
||||
properties = @Setting( name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "true")
|
||||
)
|
||||
@RequiresDialect(value = PostgreSQLDialect.class)
|
||||
public class PostgreSQLStoredProcedureTest {
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.orm.test.procedure;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ParameterMode;
|
||||
import jakarta.persistence.StoredProcedureQuery;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInAutoCommit;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(value = SQLServerDialect.class, majorVersion = 11)
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
SQLServerStoredProcedureForcePositionalTest.Address.class
|
||||
},
|
||||
properties = @Setting( name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "false")
|
||||
)
|
||||
public class SQLServerStoredProcedureForcePositionalTest {
|
||||
|
||||
private static final String CITY = "London";
|
||||
private static final String STREET = "Lollard Street";
|
||||
private static final String ZIP = "SE116UG";
|
||||
|
||||
@BeforeEach
|
||||
public void init(EntityManagerFactoryScope scope) {
|
||||
doInAutoCommit(
|
||||
"DROP PROCEDURE sp_count_phones",
|
||||
"CREATE PROCEDURE sp_count_phones " +
|
||||
" @personId INT, " +
|
||||
" @phoneCount INT OUTPUT " +
|
||||
"AS " +
|
||||
"BEGIN " +
|
||||
" SELECT @phoneCount = COUNT(*) " +
|
||||
" FROM Phone " +
|
||||
" WHERE person_id = @personId " +
|
||||
"END"
|
||||
);
|
||||
|
||||
scope.inTransaction( entityManager -> {
|
||||
Person person1 = new Person( 1L, "John Doe" );
|
||||
person1.setNickName( "JD" );
|
||||
person1.setAddress( "Earth" );
|
||||
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )
|
||||
.toInstant( ZoneOffset.UTC ) ) );
|
||||
|
||||
entityManager.persist( person1 );
|
||||
|
||||
Phone phone1 = new Phone( "123-456-7890" );
|
||||
phone1.setId( 1L );
|
||||
|
||||
person1.addPhone( phone1 );
|
||||
|
||||
Phone phone2 = new Phone( "098_765-4321" );
|
||||
phone2.setId( 2L );
|
||||
|
||||
person1.addPhone( phone2 );
|
||||
|
||||
Address address = new Address( 1l, STREET, CITY, ZIP );
|
||||
entityManager.persist( address );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(EntityManagerFactoryScope scope) {
|
||||
scope.releaseEntityManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredProcedure(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_count_phones" );
|
||||
query.registerStoredProcedureParameter( "personId2", Long.class, ParameterMode.IN );
|
||||
query.registerStoredProcedureParameter( "phoneCount", Long.class, ParameterMode.OUT );
|
||||
|
||||
query.setParameter( "personId2", 1L );
|
||||
|
||||
query.execute();
|
||||
Long phoneCount = (Long) query.getOutputParameterValue( "phoneCount" );
|
||||
assertEquals( Long.valueOf( 2 ), phoneCount );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Address")
|
||||
@Table(name = "ADDRESS_TABLE")
|
||||
public static class Address {
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private long id;
|
||||
@Column(name = "STREET")
|
||||
private String street;
|
||||
@Column(name = "CITY")
|
||||
private String city;
|
||||
@Column(name = "ZIP")
|
||||
private String zip;
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(long id, String street, String city, String zip) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,12 +15,14 @@ import java.util.List;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -48,7 +50,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
Person.class,
|
||||
Phone.class,
|
||||
SQLServerStoredProcedureTest.Address.class
|
||||
}
|
||||
},
|
||||
properties = @Setting( name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "true")
|
||||
)
|
||||
public class SQLServerStoredProcedureTest {
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.sql.Timestamp;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.jpa.HibernateHints;
|
||||
|
||||
|
@ -18,6 +19,7 @@ import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
|||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -39,7 +41,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
annotatedClasses = {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
}
|
||||
},
|
||||
properties = @Setting( name = AvailableSettings.QUERY_PASS_PROCEDURE_PARAMETER_NAMES, value = "true")
|
||||
)
|
||||
public class SybaseStoredProcedureTest {
|
||||
|
||||
|
|
Loading…
Reference in New Issue