HHH-12136 - Various improvements for ProcedureCall/StoredProcedureQuery
This commit is contained in:
parent
15bf44e4e9
commit
6ba328e7a0
|
@ -813,7 +813,7 @@ identPrimaryBase
|
||||||
;
|
;
|
||||||
|
|
||||||
castedIdentPrimaryBase
|
castedIdentPrimaryBase
|
||||||
: i:IDENT! OPEN! p:path AS! a:path! CLOSE! { i.getText().equals("treat") }? {
|
: i:IDENT! OPEN! p:path AS! a:path! CLOSE! { i.getText().equalsIgnoreCase("treat") }? {
|
||||||
registerTreat( #p, #a );
|
registerTreat( #p, #a );
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.internal.FilterImpl;
|
||||||
import org.hibernate.internal.util.EntityPrinter;
|
import org.hibernate.internal.util.EntityPrinter;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
import org.hibernate.type.ComponentType;
|
import org.hibernate.type.ComponentType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -230,7 +231,7 @@ public final class QueryParameters {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryParameters(
|
public QueryParameters(
|
||||||
QueryParameterBindingsImpl queryParameterBindings,
|
QueryParameterBindings queryParameterBindings,
|
||||||
LockOptions lockOptions,
|
LockOptions lockOptions,
|
||||||
RowSelection selection,
|
RowSelection selection,
|
||||||
final boolean isReadOnlyInitialized,
|
final boolean isReadOnlyInitialized,
|
||||||
|
|
|
@ -8,10 +8,12 @@ package org.hibernate.procedure;
|
||||||
|
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes an input value binding for any IN/INOUT parameters.
|
* Describes an input value binding for any IN/INOUT parameters.
|
||||||
*/
|
*/
|
||||||
public interface ParameterBind<T> {
|
public interface ParameterBind<T> extends QueryParameterBinding<T> {
|
||||||
/**
|
/**
|
||||||
* Retrieves the bound value.
|
* Retrieves the bound value.
|
||||||
*
|
*
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.procedure;
|
||||||
import javax.persistence.ParameterMode;
|
import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.query.QueryParameter;
|
||||||
|
import org.hibernate.query.procedure.ProcedureParameter;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +18,7 @@ import org.hibernate.type.Type;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ParameterRegistration<T> {
|
public interface ParameterRegistration<T> extends ProcedureParameter<T> {
|
||||||
/**
|
/**
|
||||||
* The name under which this parameter was registered. Can be {@code null} which should indicate that
|
* The name under which this parameter was registered. Can be {@code null} which should indicate that
|
||||||
* positional registration was used (and therefore {@link #getPosition()} should return non-null.
|
* positional registration was used (and therefore {@link #getPosition()} should return non-null.
|
||||||
|
@ -33,14 +35,6 @@ public interface ParameterRegistration<T> {
|
||||||
*/
|
*/
|
||||||
Integer getPosition();
|
Integer getPosition();
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the Java type of parameter. This is used to guess the Hibernate type (unless {@link #setHibernateType}
|
|
||||||
* is called explicitly).
|
|
||||||
*
|
|
||||||
* @return The parameter Java type.
|
|
||||||
*/
|
|
||||||
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
|
||||||
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
|
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
|
||||||
|
|
|
@ -1,431 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.procedure.internal;
|
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import javax.persistence.ParameterMode;
|
|
||||||
import javax.persistence.TemporalType;
|
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
|
||||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
|
||||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
||||||
import org.hibernate.procedure.ParameterBind;
|
|
||||||
import org.hibernate.procedure.ParameterMisuseException;
|
|
||||||
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
|
|
||||||
import org.hibernate.procedure.spi.ParameterStrategy;
|
|
||||||
import org.hibernate.type.CalendarDateType;
|
|
||||||
import org.hibernate.type.CalendarTimeType;
|
|
||||||
import org.hibernate.type.CalendarType;
|
|
||||||
import org.hibernate.type.ProcedureParameterExtractionAware;
|
|
||||||
import org.hibernate.type.ProcedureParameterNamedBinder;
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract implementation of ParameterRegistration/ParameterRegistrationImplementor
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public abstract class AbstractParameterRegistrationImpl<T> implements ParameterRegistrationImplementor<T> {
|
|
||||||
private static final Logger log = Logger.getLogger( AbstractParameterRegistrationImpl.class );
|
|
||||||
|
|
||||||
private final ProcedureCallImpl procedureCall;
|
|
||||||
|
|
||||||
private final Integer position;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final ParameterMode mode;
|
|
||||||
private final Class<T> type;
|
|
||||||
|
|
||||||
private ParameterBindImpl bind;
|
|
||||||
private boolean passNulls;
|
|
||||||
|
|
||||||
private int startIndex;
|
|
||||||
private Type hibernateType;
|
|
||||||
private int[] sqlTypes;
|
|
||||||
|
|
||||||
|
|
||||||
// positional constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this( procedureCall, position, null, mode, type, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
Type hibernateType,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this( procedureCall, position, null, mode, type, hibernateType, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// named constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this( procedureCall, null, name, mode, type, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
Type hibernateType,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this( procedureCall, null, name, mode, type, hibernateType, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// full constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
private AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
Type hibernateType,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this.procedureCall = procedureCall;
|
|
||||||
|
|
||||||
this.position = position;
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
this.mode = mode;
|
|
||||||
this.type = type;
|
|
||||||
|
|
||||||
if ( mode == ParameterMode.REF_CURSOR ) {
|
|
||||||
this.sqlTypes = new int[]{ Types.REF_CURSOR };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.passNulls = initialPassNullsSetting;
|
|
||||||
setHibernateType( hibernateType );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AbstractParameterRegistrationImpl(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
this(
|
|
||||||
procedureCall,
|
|
||||||
position,
|
|
||||||
name,
|
|
||||||
mode,
|
|
||||||
type,
|
|
||||||
procedureCall.getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
|
|
||||||
initialPassNullsSetting
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SharedSessionContractImplementor session() {
|
|
||||||
return procedureCall.getSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<T> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParameterMode getMode() {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPassNullsEnabled() {
|
|
||||||
return passNulls;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enablePassingNulls(boolean enabled) {
|
|
||||||
this.passNulls = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type getHibernateType() {
|
|
||||||
return hibernateType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHibernateType(Type type) {
|
|
||||||
if ( type == null ) {
|
|
||||||
throw new IllegalArgumentException( "Type cannot be null" );
|
|
||||||
}
|
|
||||||
this.hibernateType = type;
|
|
||||||
this.sqlTypes = hibernateType.sqlTypes( session().getFactory() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public ParameterBind<T> getBind() {
|
|
||||||
return bind;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindValue(T value) {
|
|
||||||
validateBindability();
|
|
||||||
this.bind = new ParameterBindImpl<T>( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateBindability() {
|
|
||||||
if ( ! canBind() ) {
|
|
||||||
throw new ParameterMisuseException( "Cannot bind value to non-input parameter : " + this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canBind() {
|
|
||||||
return mode == ParameterMode.IN || mode == ParameterMode.INOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindValue(T value, TemporalType explicitTemporalType) {
|
|
||||||
validateBindability();
|
|
||||||
if ( explicitTemporalType != null ) {
|
|
||||||
if ( ! isDateTimeType() ) {
|
|
||||||
throw new IllegalArgumentException( "TemporalType should not be specified for non date/time type" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.bind = new ParameterBindImpl<T>( value, explicitTemporalType );
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDateTimeType() {
|
|
||||||
return Date.class.isAssignableFrom( type )
|
|
||||||
|| Calendar.class.isAssignableFrom( type );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepare(CallableStatement statement, int startIndex) throws SQLException {
|
|
||||||
// initially set up the Type we will use for binding as the explicit type.
|
|
||||||
Type typeToUse = hibernateType;
|
|
||||||
int[] sqlTypesToUse = sqlTypes;
|
|
||||||
|
|
||||||
// however, for Calendar binding with an explicit TemporalType we may need to adjust this...
|
|
||||||
if ( bind != null && bind.getExplicitTemporalType() != null ) {
|
|
||||||
if ( Calendar.class.isInstance( bind.getValue() ) ) {
|
|
||||||
switch ( bind.getExplicitTemporalType() ) {
|
|
||||||
case TIMESTAMP: {
|
|
||||||
typeToUse = CalendarType.INSTANCE;
|
|
||||||
sqlTypesToUse = typeToUse.sqlTypes( session().getFactory() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DATE: {
|
|
||||||
typeToUse = CalendarDateType.INSTANCE;
|
|
||||||
sqlTypesToUse = typeToUse.sqlTypes( session().getFactory() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TIME: {
|
|
||||||
typeToUse = CalendarTimeType.INSTANCE;
|
|
||||||
sqlTypesToUse = typeToUse.sqlTypes( session().getFactory() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startIndex = startIndex;
|
|
||||||
if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
|
||||||
if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
|
||||||
if ( sqlTypesToUse.length > 1 ) {
|
|
||||||
// there is more than one column involved; see if the Hibernate Type can handle
|
|
||||||
// multi-param extraction...
|
|
||||||
final boolean canHandleMultiParamExtraction =
|
|
||||||
ProcedureParameterExtractionAware.class.isInstance( hibernateType )
|
|
||||||
&& ( (ProcedureParameterExtractionAware) hibernateType ).canDoExtraction();
|
|
||||||
if ( ! canHandleMultiParamExtraction ) {
|
|
||||||
// it cannot...
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"Type [" + hibernateType + "] does support multi-parameter value extraction"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769).
|
|
||||||
// The idea is that an embeddable/custom type can have more than one column values
|
|
||||||
// that correspond with embeddable/custom attribute value. This does not seem to
|
|
||||||
// be working yet. For now, if sqlTypesToUse.length > 1, then register
|
|
||||||
// the out parameters by position (since we only have one name).
|
|
||||||
// This will cause a failure if there are other parameters bound by
|
|
||||||
// name and the dialect does not support "mixed" named/positional parameters;
|
|
||||||
// e.g., Oracle.
|
|
||||||
if ( sqlTypesToUse.length == 1 &&
|
|
||||||
procedureCall.getParameterStrategy() == ParameterStrategy.NAMED &&
|
|
||||||
canDoNameParameterBinding() ) {
|
|
||||||
statement.registerOutParameter( getName(), sqlTypesToUse[0] );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for ( int i = 0; i < sqlTypesToUse.length; i++ ) {
|
|
||||||
statement.registerOutParameter( startIndex + i, sqlTypesToUse[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
|
|
||||||
if ( bind == null || bind.getValue() == null ) {
|
|
||||||
// the user did not bind a value to the parameter being processed. This is the condition
|
|
||||||
// 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
|
|
||||||
// parameter defines a default value. Deferring to that information would be the best option
|
|
||||||
if ( passNulls ) {
|
|
||||||
log.debugf(
|
|
||||||
"Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to true; binding NULL",
|
|
||||||
procedureCall.getProcedureName(),
|
|
||||||
this
|
|
||||||
);
|
|
||||||
if ( this.procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding() ) {
|
|
||||||
((ProcedureParameterNamedBinder) typeToUse).nullSafeSet(
|
|
||||||
statement,
|
|
||||||
null,
|
|
||||||
this.getName(),
|
|
||||||
session()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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 {
|
|
||||||
if ( this.procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding()) {
|
|
||||||
((ProcedureParameterNamedBinder) typeToUse).nullSafeSet(
|
|
||||||
statement,
|
|
||||||
bind.getValue(),
|
|
||||||
this.getName(),
|
|
||||||
session()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, session() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we have a REF_CURSOR type param
|
|
||||||
if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED ) {
|
|
||||||
session().getFactory().getServiceRegistry()
|
|
||||||
.getService( RefCursorSupport.class )
|
|
||||||
.registerRefCursorParameter( statement, getName() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session().getFactory().getServiceRegistry()
|
|
||||||
.getService( RefCursorSupport.class )
|
|
||||||
.registerRefCursorParameter( statement, startIndex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canDoNameParameterBinding() {
|
|
||||||
final ExtractedDatabaseMetaData databaseMetaData = session()
|
|
||||||
.getJdbcCoordinator()
|
|
||||||
.getJdbcSessionOwner()
|
|
||||||
.getJdbcSessionContext()
|
|
||||||
.getServiceRegistry().getService( JdbcEnvironment.class )
|
|
||||||
.getExtractedDatabaseMetaData();
|
|
||||||
return
|
|
||||||
databaseMetaData.supportsNamedParameters() &&
|
|
||||||
ProcedureParameterNamedBinder.class.isInstance( hibernateType )
|
|
||||||
&& ((ProcedureParameterNamedBinder) hibernateType).canDoSetting();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getSqlTypes() {
|
|
||||||
if ( mode == ParameterMode.REF_CURSOR ) {
|
|
||||||
// we could use the Types#REF_CURSOR added in Java 8, but that would require requiring Java 8...
|
|
||||||
throw new IllegalStateException( "REF_CURSOR parameters do not have a SQL/JDBC type" );
|
|
||||||
}
|
|
||||||
return sqlTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T extract(CallableStatement statement) {
|
|
||||||
if ( mode == ParameterMode.IN ) {
|
|
||||||
throw new ParameterMisuseException( "IN parameter not valid for output extraction" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769).
|
|
||||||
// For now, if sqlTypes.length > 1 with a named parameter, then extract
|
|
||||||
// parameter values by position (since we only have one name).
|
|
||||||
final boolean useNamed = sqlTypes.length == 1 &&
|
|
||||||
procedureCall.getParameterStrategy() == ParameterStrategy.NAMED &&
|
|
||||||
canDoNameParameterBinding();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ( ProcedureParameterExtractionAware.class.isInstance( hibernateType ) ) {
|
|
||||||
if ( useNamed ) {
|
|
||||||
return (T) ( (ProcedureParameterExtractionAware) hibernateType ).extract(
|
|
||||||
statement,
|
|
||||||
new String[] { getName() },
|
|
||||||
session()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (T) ( (ProcedureParameterExtractionAware) hibernateType ).extract(
|
|
||||||
statement,
|
|
||||||
startIndex,
|
|
||||||
session()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( useNamed ) {
|
|
||||||
return (T) statement.getObject( name );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (T) statement.getObject( startIndex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
throw procedureCall.getSession().getFactory().getSQLExceptionHelper().convert(
|
|
||||||
e,
|
|
||||||
"Unable to extract OUT/INOUT parameter value"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.procedure.internal;
|
|
||||||
|
|
||||||
import javax.persistence.ParameterMode;
|
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a registered named parameter
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class NamedParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
|
|
||||||
NamedParameterRegistration(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
super( procedureCall, name, mode, type, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
NamedParameterRegistration(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
String name,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
Type hibernateType,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
super( procedureCall, name, mode, type, hibernateType, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,9 +6,16 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.procedure.internal;
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.hibernate.procedure.ParameterBind;
|
import org.hibernate.procedure.ParameterBind;
|
||||||
|
import org.hibernate.query.internal.BindingTypeHelper;
|
||||||
|
import org.hibernate.query.procedure.internal.ProcedureParamBindings;
|
||||||
|
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the {@link ParameterBind} contract.
|
* Implementation of the {@link ParameterBind} contract.
|
||||||
|
@ -16,16 +23,25 @@ import org.hibernate.procedure.ParameterBind;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ParameterBindImpl<T> implements ParameterBind<T> {
|
public class ParameterBindImpl<T> implements ParameterBind<T> {
|
||||||
private final T value;
|
private static final Logger log = Logger.getLogger( ParameterBindImpl.class );
|
||||||
private final TemporalType explicitTemporalType;
|
|
||||||
|
|
||||||
ParameterBindImpl(T value) {
|
private final ProcedureParameterImplementor procedureParameter;
|
||||||
this( value, null );
|
private final ProcedureParamBindings procedureParamBindings;
|
||||||
}
|
|
||||||
|
|
||||||
ParameterBindImpl(T value, TemporalType explicitTemporalType) {
|
private boolean isBound;
|
||||||
this.value = value;
|
|
||||||
this.explicitTemporalType = explicitTemporalType;
|
private T value;
|
||||||
|
private Type hibernateType;
|
||||||
|
|
||||||
|
private TemporalType explicitTemporalType;
|
||||||
|
|
||||||
|
public ParameterBindImpl(
|
||||||
|
ProcedureParameterImplementor procedureParameter,
|
||||||
|
ProcedureParamBindings procedureParamBindings) {
|
||||||
|
this.procedureParameter = procedureParameter;
|
||||||
|
this.procedureParamBindings = procedureParamBindings;
|
||||||
|
|
||||||
|
this.hibernateType = procedureParameter.getHibernateType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -37,4 +53,66 @@ public class ParameterBindImpl<T> implements ParameterBind<T> {
|
||||||
public TemporalType getExplicitTemporalType() {
|
public TemporalType getExplicitTemporalType() {
|
||||||
return explicitTemporalType;
|
return explicitTemporalType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBound() {
|
||||||
|
return isBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBindValue(T value) {
|
||||||
|
internalSetValue( value );
|
||||||
|
|
||||||
|
if ( value != null && hibernateType == null ) {
|
||||||
|
hibernateType = procedureParamBindings.getProcedureCall()
|
||||||
|
.getSession()
|
||||||
|
.getFactory()
|
||||||
|
.getTypeResolver()
|
||||||
|
.heuristicType( value.getClass().getName() );
|
||||||
|
log.debugf( "Using heuristic type [%s] based on bind value [%s] as `bindType`", hibernateType, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalSetValue(T value) {
|
||||||
|
if ( procedureParameter.getMode() != ParameterMode.IN && procedureParameter.getMode() != ParameterMode.INOUT ) {
|
||||||
|
throw new IllegalStateException( "Can only bind values for IN/INOUT parameters : " + procedureParameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( procedureParameter.getParameterType() != null ) {
|
||||||
|
if ( !procedureParameter.getParameterType().isInstance( value ) ) {
|
||||||
|
throw new IllegalArgumentException( "Bind value [" + value + "] was not of specified type [" + procedureParameter.getParameterType() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.value = value;
|
||||||
|
this.isBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBindValue(T value, Type clarifiedType) {
|
||||||
|
internalSetValue( value );
|
||||||
|
this.hibernateType = clarifiedType;
|
||||||
|
log.debugf( "Using explicit type [%s] as `bindType`", hibernateType, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBindValue(T value, TemporalType clarifiedTemporalType) {
|
||||||
|
internalSetValue( value );
|
||||||
|
this.hibernateType = BindingTypeHelper.INSTANCE.determineTypeForTemporalType( clarifiedTemporalType, hibernateType, value );
|
||||||
|
this.explicitTemporalType = clarifiedTemporalType;
|
||||||
|
log.debugf( "Using type [%s] (based on TemporalType [%s] as `bindType`", hibernateType, clarifiedTemporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getBindValue() {
|
||||||
|
if ( !isBound ) {
|
||||||
|
throw new IllegalStateException( "Value not yet bound" );
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getBindType() {
|
||||||
|
return hibernateType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.procedure.internal;
|
|
||||||
|
|
||||||
import javax.persistence.ParameterMode;
|
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a registered positional parameter
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class PositionalParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
|
|
||||||
PositionalParameterRegistration(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
super( procedureCall, position, mode, type, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
|
|
||||||
PositionalParameterRegistration(
|
|
||||||
ProcedureCallImpl procedureCall,
|
|
||||||
Integer position,
|
|
||||||
ParameterMode mode,
|
|
||||||
Class<T> type,
|
|
||||||
Type hibernateType,
|
|
||||||
boolean initialPassNullsSetting) {
|
|
||||||
super( procedureCall, position, mode, type, hibernateType, initialPassNullsSetting );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,13 +11,13 @@ import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
|
@ -28,17 +28,13 @@ import javax.persistence.TemporalType;
|
||||||
import javax.persistence.TransactionRequiredException;
|
import javax.persistence.TransactionRequiredException;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.engine.ResultSetMappingDefinition;
|
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
|
||||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|
||||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.procedure.NoSuchParameterException;
|
import org.hibernate.procedure.NoSuchParameterException;
|
||||||
import org.hibernate.procedure.ParameterRegistration;
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
|
@ -51,8 +47,12 @@ import org.hibernate.procedure.spi.ParameterStrategy;
|
||||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.internal.AbstractProducedQuery;
|
import org.hibernate.query.internal.AbstractProducedQuery;
|
||||||
|
import org.hibernate.query.procedure.internal.ProcedureParamBindings;
|
||||||
import org.hibernate.query.procedure.internal.ProcedureParameterImpl;
|
import org.hibernate.query.procedure.internal.ProcedureParameterImpl;
|
||||||
import org.hibernate.query.procedure.internal.ProcedureParameterMetadata;
|
import org.hibernate.query.procedure.internal.ProcedureParameterMetadata;
|
||||||
|
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.result.NoMoreReturnsException;
|
import org.hibernate.result.NoMoreReturnsException;
|
||||||
import org.hibernate.result.Output;
|
import org.hibernate.result.Output;
|
||||||
import org.hibernate.result.ResultSetOutput;
|
import org.hibernate.result.ResultSetOutput;
|
||||||
|
@ -82,8 +82,8 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
private final boolean globalParameterPassNullsSetting;
|
private final boolean globalParameterPassNullsSetting;
|
||||||
|
|
||||||
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
|
private final ProcedureParameterMetadata parameterMetadata;
|
||||||
private List<ParameterRegistrationImplementor<?>> registeredParameters = new ArrayList<>();
|
private final ProcedureParamBindings paramBindings;
|
||||||
|
|
||||||
private Set<String> synchronizedQuerySpaces;
|
private Set<String> synchronizedQuerySpaces;
|
||||||
|
|
||||||
|
@ -96,11 +96,14 @@ public class ProcedureCallImpl<R>
|
||||||
* @param procedureName The name of the procedure to call
|
* @param procedureName The name of the procedure to call
|
||||||
*/
|
*/
|
||||||
public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName) {
|
public ProcedureCallImpl(SharedSessionContractImplementor session, String procedureName) {
|
||||||
super( session, new ProcedureParameterMetadata() );
|
super( session, null );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
this.queryReturns = NO_RETURNS;
|
this.queryReturns = NO_RETURNS;
|
||||||
|
|
||||||
|
this.parameterMetadata = new ProcedureParameterMetadata( this );
|
||||||
|
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,7 +114,7 @@ public class ProcedureCallImpl<R>
|
||||||
* @param resultClasses The classes making up the result
|
* @param resultClasses The classes making up the result
|
||||||
*/
|
*/
|
||||||
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, Class... resultClasses) {
|
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, Class... resultClasses) {
|
||||||
super( session, new ProcedureParameterMetadata() );
|
super( session, null );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
|
@ -140,6 +143,9 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
|
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
|
||||||
this.synchronizedQuerySpaces = collectedQuerySpaces;
|
this.synchronizedQuerySpaces = collectedQuerySpaces;
|
||||||
|
|
||||||
|
this.parameterMetadata = new ProcedureParameterMetadata( this );
|
||||||
|
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +156,7 @@ public class ProcedureCallImpl<R>
|
||||||
* @param resultSetMappings The names of the result set mappings making up the result
|
* @param resultSetMappings The names of the result set mappings making up the result
|
||||||
*/
|
*/
|
||||||
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, String... resultSetMappings) {
|
public ProcedureCallImpl(final SharedSessionContractImplementor session, String procedureName, String... resultSetMappings) {
|
||||||
super( session, new ProcedureParameterMetadata() );
|
super( session, null );
|
||||||
this.procedureName = procedureName;
|
this.procedureName = procedureName;
|
||||||
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||||
|
|
||||||
|
@ -184,6 +190,9 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
|
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
|
||||||
this.synchronizedQuerySpaces = collectedQuerySpaces;
|
this.synchronizedQuerySpaces = collectedQuerySpaces;
|
||||||
|
|
||||||
|
this.parameterMetadata = new ProcedureParameterMetadata( this );
|
||||||
|
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,41 +203,21 @@ public class ProcedureCallImpl<R>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ProcedureCallImpl(SharedSessionContractImplementor session, ProcedureCallMementoImpl memento) {
|
ProcedureCallImpl(SharedSessionContractImplementor session, ProcedureCallMementoImpl memento) {
|
||||||
super( session, new ProcedureParameterMetadata() );
|
super( session, null );
|
||||||
this.procedureName = memento.getProcedureName();
|
this.procedureName = memento.getProcedureName();
|
||||||
this.globalParameterPassNullsSetting = session.getFactory().getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
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() );
|
||||||
this.parameterStrategy = memento.getParameterStrategy();
|
|
||||||
if ( parameterStrategy == ParameterStrategy.UNKNOWN ) {
|
|
||||||
// nothing else to do in this case
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<ProcedureCallMementoImpl.ParameterMemento> storedRegistrations = memento.getParameterDeclarations();
|
this.parameterMetadata = new ProcedureParameterMetadata( this );
|
||||||
if ( storedRegistrations == null ) {
|
this.paramBindings = new ProcedureParamBindings( parameterMetadata, this );
|
||||||
// most likely a problem if ParameterStrategy is not UNKNOWN...
|
|
||||||
LOG.debugf(
|
|
||||||
"ParameterStrategy was [%s] on named copy [%s], but no parameters stored",
|
|
||||||
parameterStrategy,
|
|
||||||
procedureName
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<ParameterRegistrationImplementor<?>> parameterRegistrations =
|
for ( ProcedureCallMementoImpl.ParameterMemento storedRegistration : memento.getParameterDeclarations() ) {
|
||||||
CollectionHelper.arrayList( storedRegistrations.size() );
|
final ProcedureParameterImplementor<?> registration;
|
||||||
|
|
||||||
for ( ProcedureCallMementoImpl.ParameterMemento storedRegistration : storedRegistrations ) {
|
|
||||||
final ParameterRegistrationImplementor<?> registration;
|
|
||||||
if ( StringHelper.isNotEmpty( storedRegistration.getName() ) ) {
|
if ( StringHelper.isNotEmpty( storedRegistration.getName() ) ) {
|
||||||
if ( parameterStrategy != ParameterStrategy.NAMED ) {
|
registration = new ProcedureParameterImpl(
|
||||||
throw new IllegalStateException(
|
|
||||||
"Found named stored procedure parameter associated with positional parameters"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
registration = new NamedParameterRegistration(
|
|
||||||
this,
|
this,
|
||||||
storedRegistration.getName(),
|
storedRegistration.getName(),
|
||||||
storedRegistration.getMode(),
|
storedRegistration.getMode(),
|
||||||
|
@ -238,12 +227,7 @@ public class ProcedureCallImpl<R>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( parameterStrategy != ParameterStrategy.POSITIONAL ) {
|
registration = new ProcedureParameterImpl(
|
||||||
throw new IllegalStateException(
|
|
||||||
"Found named stored procedure parameter associated with positional parameters"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
registration = new PositionalParameterRegistration(
|
|
||||||
this,
|
this,
|
||||||
storedRegistration.getPosition(),
|
storedRegistration.getPosition(),
|
||||||
storedRegistration.getMode(),
|
storedRegistration.getMode(),
|
||||||
|
@ -252,10 +236,9 @@ public class ProcedureCallImpl<R>
|
||||||
storedRegistration.isPassNullsEnabled()
|
storedRegistration.isPassNullsEnabled()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
getParameterMetadata().registerParameter( new ProcedureParameterImpl( registration ) );
|
|
||||||
parameterRegistrations.add( registration );
|
getParameterMetadata().registerParameter( registration );
|
||||||
}
|
}
|
||||||
this.registeredParameters = parameterRegistrations;
|
|
||||||
|
|
||||||
for ( Map.Entry<String, Object> entry : memento.getHintsMap().entrySet() ) {
|
for ( Map.Entry<String, Object> entry : memento.getHintsMap().entrySet() ) {
|
||||||
setHint( entry.getKey(), entry.getValue() );
|
setHint( entry.getKey(), entry.getValue() );
|
||||||
|
@ -264,7 +247,12 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcedureParameterMetadata getParameterMetadata() {
|
public ProcedureParameterMetadata getParameterMetadata() {
|
||||||
return (ProcedureParameterMetadata) super.getParameterMetadata();
|
return parameterMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return paramBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -273,7 +261,7 @@ public class ProcedureCallImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParameterStrategy getParameterStrategy() {
|
public ParameterStrategy getParameterStrategy() {
|
||||||
return parameterStrategy;
|
return getParameterMetadata().getParameterStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -294,11 +282,17 @@ public class ProcedureCallImpl<R>
|
||||||
@Override
|
@Override
|
||||||
@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 ProcedureParameterImpl procedureParameter = new ProcedureParameterImpl(
|
||||||
|
this,
|
||||||
|
position,
|
||||||
|
mode,
|
||||||
|
type,
|
||||||
|
getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
|
||||||
|
globalParameterPassNullsSetting
|
||||||
|
);
|
||||||
|
|
||||||
final PositionalParameterRegistration parameterRegistration =
|
registerParameter( procedureParameter );
|
||||||
new PositionalParameterRegistration( this, position, mode, type, globalParameterPassNullsSetting );
|
return procedureParameter;
|
||||||
registerParameter( parameterRegistration );
|
|
||||||
return parameterRegistration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -308,68 +302,30 @@ public class ProcedureCallImpl<R>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerParameter(ParameterRegistrationImplementor parameter) {
|
private void registerParameter(ProcedureParameterImplementor parameter) {
|
||||||
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
|
getParameterMetadata().registerParameter( parameter );
|
||||||
prepareForNamedParameters();
|
|
||||||
}
|
|
||||||
else if ( parameter.getPosition() != null ) {
|
|
||||||
prepareForPositionalParameters();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "Given parameter did not define name or position [" + parameter + "]" );
|
|
||||||
}
|
|
||||||
((ProcedureParameterMetadata)getParameterMetadata()).registerParameter( new ProcedureParameterImpl( parameter ) );
|
|
||||||
|
|
||||||
registeredParameters.add( parameter );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareForPositionalParameters() {
|
|
||||||
if ( parameterStrategy == ParameterStrategy.NAMED ) {
|
|
||||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
|
||||||
}
|
|
||||||
parameterStrategy = ParameterStrategy.POSITIONAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareForNamedParameters() {
|
|
||||||
if ( parameterStrategy == ParameterStrategy.POSITIONAL ) {
|
|
||||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
|
||||||
}
|
|
||||||
if ( parameterStrategy == ParameterStrategy.UNKNOWN ) {
|
|
||||||
// protect to only do this check once
|
|
||||||
final ExtractedDatabaseMetaData databaseMetaData = getSession()
|
|
||||||
.getJdbcCoordinator()
|
|
||||||
.getJdbcSessionOwner()
|
|
||||||
.getJdbcSessionContext()
|
|
||||||
.getServiceRegistry().getService( JdbcEnvironment.class )
|
|
||||||
.getExtractedDatabaseMetaData();
|
|
||||||
if ( ! databaseMetaData.supportsNamedParameters() ) {
|
|
||||||
LOG.unsupportedNamedParameters();
|
|
||||||
}
|
|
||||||
parameterStrategy = ParameterStrategy.NAMED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParameterRegistrationImplementor getParameterRegistration(int position) {
|
public ParameterRegistrationImplementor getParameterRegistration(int position) {
|
||||||
if ( parameterStrategy != ParameterStrategy.POSITIONAL ) {
|
return getParameterMetadata().getQueryParameter( position );
|
||||||
throw new ParameterStrategyException(
|
|
||||||
"Attempt to access positional parameter [" + position + "] but ProcedureCall using named parameters"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
|
||||||
if ( position == parameter.getPosition() ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new NoSuchParameterException( "Could not locate parameter registered using that position [" + position + "]" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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, globalParameterPassNullsSetting );
|
final ProcedureParameterImpl parameter = new ProcedureParameterImpl(
|
||||||
registerParameter( parameterRegistration );
|
this,
|
||||||
return parameterRegistration;
|
name,
|
||||||
|
mode,
|
||||||
|
type,
|
||||||
|
getSession().getFactory().getTypeResolver().heuristicType( type.getName() ),
|
||||||
|
globalParameterPassNullsSetting
|
||||||
|
);
|
||||||
|
|
||||||
|
registerParameter( parameter );
|
||||||
|
|
||||||
|
return parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -381,21 +337,13 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParameterRegistrationImplementor getParameterRegistration(String name) {
|
public ParameterRegistrationImplementor getParameterRegistration(String name) {
|
||||||
if ( parameterStrategy != ParameterStrategy.NAMED ) {
|
return getParameterMetadata().getQueryParameter( name );
|
||||||
throw new ParameterStrategyException( "Names were not used to register parameters with this stored procedure call" );
|
|
||||||
}
|
|
||||||
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
|
||||||
if ( name.equals( parameter.getName() ) ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new NoSuchParameterException( "Could not locate parameter registered under that name [" + name + "]" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<ParameterRegistration> getRegisteredParameters() {
|
public List getRegisteredParameters() {
|
||||||
return new ArrayList<>( registeredParameters );
|
return new ArrayList( getParameterMetadata().collectAllParameters() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -424,12 +372,11 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
final String call = getProducer().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().renderCallableStatement(
|
final String call = getProducer().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().renderCallableStatement(
|
||||||
procedureName,
|
procedureName,
|
||||||
parameterStrategy,
|
getParameterMetadata(),
|
||||||
registeredParameters,
|
paramBindings,
|
||||||
getProducer()
|
getProducer()
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
|
||||||
LOG.debugf( "Preparing procedure call : %s", call );
|
LOG.debugf( "Preparing procedure call : %s", call );
|
||||||
final CallableStatement statement = (CallableStatement) getSession()
|
final CallableStatement statement = (CallableStatement) getSession()
|
||||||
.getJdbcCoordinator()
|
.getJdbcCoordinator()
|
||||||
|
@ -438,28 +385,36 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
|
|
||||||
// prepare parameters
|
// prepare parameters
|
||||||
|
|
||||||
|
getParameterMetadata().visitRegistrations(
|
||||||
|
new Consumer<QueryParameter>() {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
@Override
|
||||||
parameter.prepare( statement, i );
|
public void accept(QueryParameter queryParameter) {
|
||||||
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
|
try {
|
||||||
|
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
|
||||||
|
registration.prepare( statement, i );
|
||||||
|
if ( registration.getMode() == ParameterMode.REF_CURSOR ) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
i += parameter.getSqlTypes().length;
|
i += registration.getSqlTypes().length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProcedureOutputsImpl( this, statement );
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
catch (SQLException e) {
|
||||||
throw getSession().getJdbcServices().getSqlExceptionHelper().convert(
|
throw getSession().getJdbcServices().getSqlExceptionHelper().convert(
|
||||||
e,
|
e,
|
||||||
"Error preparing CallableStatement",
|
"Error preparing registered callable parameter",
|
||||||
getProcedureName()
|
getProcedureName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return new ProcedureOutputsImpl( this, statement );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQueryString() {
|
public String getQueryString() {
|
||||||
|
@ -492,6 +447,7 @@ public class ProcedureCallImpl<R>
|
||||||
*
|
*
|
||||||
* @return The spaces
|
* @return The spaces
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected Set<String> synchronizedQuerySpaces() {
|
protected Set<String> synchronizedQuerySpaces() {
|
||||||
if ( synchronizedQuerySpaces == null ) {
|
if ( synchronizedQuerySpaces == null ) {
|
||||||
synchronizedQuerySpaces = new HashSet<>();
|
synchronizedQuerySpaces = new HashSet<>();
|
||||||
|
@ -522,6 +478,7 @@ public class ProcedureCallImpl<R>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected void addSynchronizedQuerySpaces(EntityPersister persister) {
|
protected void addSynchronizedQuerySpaces(EntityPersister persister) {
|
||||||
synchronizedQuerySpaces().addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
|
synchronizedQuerySpaces().addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
|
||||||
}
|
}
|
||||||
|
@ -553,11 +510,15 @@ public class ProcedureCallImpl<R>
|
||||||
*/
|
*/
|
||||||
public ParameterRegistrationImplementor[] collectRefCursorParameters() {
|
public ParameterRegistrationImplementor[] collectRefCursorParameters() {
|
||||||
final List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<>();
|
final List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<>();
|
||||||
for ( ParameterRegistrationImplementor param : registeredParameters ) {
|
|
||||||
if ( param.getMode() == ParameterMode.REF_CURSOR ) {
|
getParameterMetadata().visitRegistrations(
|
||||||
refCursorParams.add( param );
|
queryParameter -> {
|
||||||
|
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
|
||||||
|
if ( registration.getMode() == ParameterMode.REF_CURSOR ) {
|
||||||
|
refCursorParams.add( registration );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] );
|
return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,8 +527,8 @@ public class ProcedureCallImpl<R>
|
||||||
return new ProcedureCallMementoImpl(
|
return new ProcedureCallMementoImpl(
|
||||||
procedureName,
|
procedureName,
|
||||||
Util.copy( queryReturns ),
|
Util.copy( queryReturns ),
|
||||||
parameterStrategy,
|
getParameterMetadata().getParameterStrategy(),
|
||||||
toParameterMementos( registeredParameters ),
|
toParameterMementos( getParameterMetadata() ),
|
||||||
Util.copy( synchronizedQuerySpaces ),
|
Util.copy( synchronizedQuerySpaces ),
|
||||||
Util.copy( hints )
|
Util.copy( hints )
|
||||||
);
|
);
|
||||||
|
@ -578,22 +539,28 @@ public class ProcedureCallImpl<R>
|
||||||
return new ProcedureCallMementoImpl(
|
return new ProcedureCallMementoImpl(
|
||||||
procedureName,
|
procedureName,
|
||||||
Util.copy( queryReturns ),
|
Util.copy( queryReturns ),
|
||||||
parameterStrategy,
|
getParameterMetadata().getParameterStrategy(),
|
||||||
toParameterMementos( registeredParameters ),
|
toParameterMementos( getParameterMetadata() ),
|
||||||
Util.copy( synchronizedQuerySpaces ),
|
Util.copy( synchronizedQuerySpaces ),
|
||||||
Util.copy( getHints() )
|
Util.copy( getHints() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ProcedureCallMementoImpl.ParameterMemento> toParameterMementos(List<ParameterRegistrationImplementor<?>> registeredParameters) {
|
private static List<ProcedureCallMementoImpl.ParameterMemento> toParameterMementos(ProcedureParameterMetadata parameterMetadata) {
|
||||||
if ( registeredParameters == null ) {
|
if ( parameterMetadata.getParameterStrategy() == ParameterStrategy.UNKNOWN ) {
|
||||||
return null;
|
// none...
|
||||||
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ProcedureCallMementoImpl.ParameterMemento> copy = CollectionHelper.arrayList( registeredParameters.size() );
|
final List<ProcedureCallMementoImpl.ParameterMemento> copy = new ArrayList<>();
|
||||||
for ( ParameterRegistrationImplementor registration : registeredParameters ) {
|
|
||||||
|
parameterMetadata.visitRegistrations(
|
||||||
|
queryParameter -> {
|
||||||
|
final ParameterRegistrationImplementor registration = (ParameterRegistrationImplementor) queryParameter;
|
||||||
copy.add( ProcedureCallMementoImpl.ParameterMemento.fromRegistration( registration ) );
|
copy.add( ProcedureCallMementoImpl.ParameterMemento.fromRegistration( registration ) );
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,6 +571,7 @@ public class ProcedureCallImpl<R>
|
||||||
private ProcedureOutputs procedureResult;
|
private ProcedureOutputs procedureResult;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
public ProcedureCallImplementor<R> registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||||
getProducer().checkOpen( true );
|
getProducer().checkOpen( true );
|
||||||
|
|
||||||
|
@ -622,6 +590,7 @@ public class ProcedureCallImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
public ProcedureCallImplementor<R> registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
||||||
getProducer().checkOpen( true );
|
getProducer().checkOpen( true );
|
||||||
try {
|
try {
|
||||||
|
@ -828,182 +797,127 @@ public class ProcedureCallImpl<R>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo (5.3) : all of the parameter stuff here can be done in AbstractProducedQuery
|
||||||
|
// using #getParameterMetadata and #getQueryParameterBindings for abstraction.
|
||||||
|
// this "win" is to define these in one place
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value) {
|
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value) {
|
||||||
locateParameterRegistration( parameter ).bindValue( value );
|
paramBindings.getBinding( getParameterMetadata().resolve( parameter ) ).setBindValue( value );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <P> ParameterRegistrationImplementor<P> locateParameterRegistration(Parameter<P> parameter) {
|
|
||||||
if ( parameter.getName() != null ) {
|
|
||||||
return locateParameterRegistration( parameter.getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( parameter.getPosition() != null ) {
|
|
||||||
return locateParameterRegistration( parameter.getPosition() );
|
|
||||||
}
|
|
||||||
|
|
||||||
throw getExceptionConverter().convert(
|
|
||||||
new IllegalArgumentException( "Could not resolve registration for given parameter reference [" + parameter + "]" )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <P> ParameterRegistrationImplementor<P> locateParameterRegistration(String name) {
|
|
||||||
assert name != null;
|
|
||||||
|
|
||||||
if ( parameterStrategy == ParameterStrategy.POSITIONAL ) {
|
|
||||||
throw new IllegalArgumentException( "Expecting positional parameter" );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( ParameterRegistrationImplementor<?> registeredParameter : registeredParameters ) {
|
|
||||||
if ( name.equals( registeredParameter.getName() ) ) {
|
|
||||||
return (ParameterRegistrationImplementor<P>) registeredParameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException( "Unknown parameter registration name [" + name + "]" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <P> ParameterRegistrationImplementor<P> locateParameterRegistration(int position) {
|
|
||||||
if ( parameterStrategy == ParameterStrategy.NAMED ) {
|
|
||||||
throw new IllegalArgumentException( "Expecting named parameter" );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( ParameterRegistrationImplementor<?> registeredParameter : registeredParameters ) {
|
|
||||||
if ( registeredParameter.getPosition() != null && registeredParameter.getPosition() == position ) {
|
|
||||||
return (ParameterRegistrationImplementor<P>) registeredParameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException( "Unknown parameter registration position [" + position + "]" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <P> ProcedureCallImplementor<R> setParameter(Parameter<P> parameter, P value) {
|
public <P> ProcedureCallImplementor<R> setParameter(Parameter<P> parameter, P value) {
|
||||||
locateParameterRegistration( parameter ).bindValue( value );
|
paramBindings.getBinding( getParameterMetadata().resolve( parameter ) ).setBindValue( value );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcedureCallImplementor<R> setParameter(String name, Object value) {
|
public ProcedureCallImplementor<R> setParameter(String name, Object value) {
|
||||||
locateParameterRegistration( name ).bindValue( value );
|
paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) ).setBindValue( value );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcedureCallImplementor<R> setParameter(int position, Object value) {
|
public ProcedureCallImplementor<R> setParameter(int position, Object value) {
|
||||||
locateParameterRegistration( position ).bindValue( value );
|
paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) ).setBindValue( value );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, Type type) {
|
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, Type type) {
|
||||||
final ParameterRegistrationImplementor<P> reg = locateParameterRegistration( parameter );
|
final QueryParameterBinding<P> binding = paramBindings.getBinding( parameter );
|
||||||
reg.bindValue( value );
|
binding.setBindValue( value, type );
|
||||||
reg.setHibernateType( type );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(String name, Object value, Type type) {
|
public ProcedureCallImplementor<R> setParameter(String name, Object value, Type type) {
|
||||||
final ParameterRegistrationImplementor reg = locateParameterRegistration( name );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) );
|
||||||
reg.bindValue( value );
|
binding.setBindValue( value, type );
|
||||||
reg.setHibernateType( type );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(int position, Object value, Type type) {
|
public ProcedureCallImplementor<R> setParameter(int position, Object value, Type type) {
|
||||||
final ParameterRegistrationImplementor reg = locateParameterRegistration( position );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) );
|
||||||
reg.bindValue( value );
|
binding.setBindValue( value, type );
|
||||||
reg.setHibernateType( type );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, TemporalType temporalType) {
|
public <P> ProcedureCallImplementor<R> setParameter(QueryParameter<P> parameter, P value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( parameter ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( parameter );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(String name, Object value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(String name, Object value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( name ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( name ) );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(int position, Object value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(int position, Object value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( position ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().getQueryParameter( position ) );
|
||||||
return this;
|
binding.setBindValue( value, temporalType );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcedureCallImplementor<R> setParameterList(QueryParameter parameter, Collection values) {
|
|
||||||
super.setParameterList( parameter, values );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcedureCallImplementor<R> setParameterList(String name, Collection values) {
|
|
||||||
super.setParameterList( name, values );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcedureCallImplementor<R> setParameterList(String name, Collection values, Type type) {
|
|
||||||
super.setParameterList( name, values, type );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcedureCallImplementor<R> setParameterList(String name, Object[] values, Type type) {
|
|
||||||
super.setParameterList( name, values, type );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcedureCallImplementor<R> setParameterList(String name, Object[] values) {
|
|
||||||
super.setParameterList( name, values );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Calendar value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Calendar value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( parameter ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().resolve( parameter ) );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Date value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(Parameter parameter, Date value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( parameter ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( getParameterMetadata().resolve( parameter ) );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(String name, Calendar value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( name ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( name );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(String name, Date value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(String name, Date value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( name ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( name );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(int position, Calendar value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( position ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( position );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ProcedureCallImplementor<R> setParameter(int position, Date value, TemporalType temporalType) {
|
public ProcedureCallImplementor<R> setParameter(int position, Date value, TemporalType temporalType) {
|
||||||
locateParameterRegistration( position ).bindValue( value, temporalType );
|
final QueryParameterBinding binding = paramBindings.getBinding( position );
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ public class ProcedureCallMementoImpl implements ProcedureCallMemento {
|
||||||
registration.getPosition(),
|
registration.getPosition(),
|
||||||
registration.getName(),
|
registration.getName(),
|
||||||
registration.getMode(),
|
registration.getMode(),
|
||||||
registration.getType(),
|
registration.getParameterType(),
|
||||||
registration.getHibernateType(),
|
registration.getHibernateType(),
|
||||||
registration.isPassNullsEnabled()
|
registration.isPassNullsEnabled()
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,24 +7,44 @@
|
||||||
package org.hibernate.procedure.spi;
|
package org.hibernate.procedure.spi;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.query.procedure.internal.ProcedureParamBindings;
|
||||||
|
import org.hibernate.query.procedure.internal.ProcedureParameterMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface CallableStatementSupport {
|
public interface CallableStatementSupport {
|
||||||
String renderCallableStatement(
|
default String renderCallableStatement(
|
||||||
String name,
|
String name,
|
||||||
ParameterStrategy parameterStrategy,
|
ParameterStrategy parameterStrategy,
|
||||||
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
|
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
|
||||||
SharedSessionContractImplementor session);
|
SharedSessionContractImplementor session) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Legacy #renderCallableStatement called but implementation does not support that call."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
default String renderCallableStatement(
|
||||||
|
String procedureName,
|
||||||
|
ProcedureParameterMetadata parameterMetadata,
|
||||||
|
ProcedureParamBindings paramBindings,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return renderCallableStatement(
|
||||||
|
procedureName,
|
||||||
|
parameterMetadata.getParameterStrategy(),
|
||||||
|
new ArrayList( parameterMetadata.collectAllParameters() ),
|
||||||
|
session
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void registerParameters(
|
void registerParameters(
|
||||||
String procedureName,
|
String procedureName,
|
||||||
CallableStatement statement,
|
CallableStatement statement,
|
||||||
ParameterStrategy parameterStrategy,
|
ParameterStrategy parameterStrategy,
|
||||||
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
|
List<ParameterRegistrationImplementor<?>> parameterRegistrations,
|
||||||
SharedSessionContractImplementor session);
|
SharedSessionContractImplementor session);;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.sql.CallableStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.procedure.ParameterRegistration;
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.query;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,4 +63,6 @@ public interface ParameterMetadata {
|
||||||
int getParameterCount();
|
int getParameterCount();
|
||||||
|
|
||||||
boolean containsReference(QueryParameter parameter);
|
boolean containsReference(QueryParameter parameter);
|
||||||
|
|
||||||
|
void visitRegistrations(Consumer<QueryParameter> action);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.NonUniqueResultException;
|
import org.hibernate.NonUniqueResultException;
|
||||||
import org.hibernate.PropertyNotFoundException;
|
import org.hibernate.PropertyNotFoundException;
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.QueryParameterException;
|
import org.hibernate.QueryParameterException;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
|
@ -75,6 +74,7 @@ import org.hibernate.query.ParameterMetadata;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.spi.QueryImplementor;
|
import org.hibernate.query.spi.QueryImplementor;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterListBinding;
|
import org.hibernate.query.spi.QueryParameterListBinding;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
@ -110,7 +110,6 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
private final SharedSessionContractImplementor producer;
|
private final SharedSessionContractImplementor producer;
|
||||||
private final ParameterMetadata parameterMetadata;
|
private final ParameterMetadata parameterMetadata;
|
||||||
private final QueryParameterBindingsImpl queryParameterBindings;
|
|
||||||
|
|
||||||
private FlushMode flushMode;
|
private FlushMode flushMode;
|
||||||
private CacheStoreMode cacheStoreMode;
|
private CacheStoreMode cacheStoreMode;
|
||||||
|
@ -140,11 +139,6 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
ParameterMetadata parameterMetadata) {
|
ParameterMetadata parameterMetadata) {
|
||||||
this.producer = producer;
|
this.producer = producer;
|
||||||
this.parameterMetadata = parameterMetadata;
|
this.parameterMetadata = parameterMetadata;
|
||||||
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
|
||||||
parameterMetadata,
|
|
||||||
producer.getFactory(),
|
|
||||||
producer.isQueryParametersValidationEnabled()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -394,28 +388,32 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryImplementor<R> setParameter(int position, OffsetDateTime value, TemporalType temporalType) {
|
public QueryImplementor<R> setParameter(int position, OffsetDateTime value, TemporalType temporalType) {
|
||||||
locateBinding( position ).setBindValue( value, temporalType );
|
final QueryParameterBinding<Object> binding = getQueryParameterBindings().getBinding(
|
||||||
|
getParameterMetadata().getQueryParameter( position )
|
||||||
|
);
|
||||||
|
|
||||||
|
binding.setBindValue( value, temporalType );
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value) {
|
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value) {
|
||||||
queryParameterBindings.getBinding( (QueryParameter) parameter );
|
getQueryParameterBindings().getBinding( (QueryParameter) parameter ).setBindValue( value );
|
||||||
locateBinding( parameter ).setBindValue( value );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <P> QueryParameterBinding<P> locateBinding(Parameter<P> parameter) {
|
private <P> QueryParameterBinding<P> locateBinding(Parameter<P> parameter) {
|
||||||
if ( parameter instanceof QueryParameter ) {
|
if ( parameter instanceof QueryParameter ) {
|
||||||
return queryParameterBindings.getBinding( (QueryParameter) parameter );
|
return getQueryParameterBindings().getBinding( (QueryParameter) parameter );
|
||||||
}
|
}
|
||||||
else if ( parameter.getName() != null ) {
|
else if ( parameter.getName() != null ) {
|
||||||
return queryParameterBindings.getBinding( parameter.getName() );
|
return getQueryParameterBindings().getBinding( parameter.getName() );
|
||||||
}
|
}
|
||||||
else if ( parameter.getPosition() != null ) {
|
else if ( parameter.getPosition() != null ) {
|
||||||
return queryParameterBindings.getBinding( parameter.getPosition() );
|
return getQueryParameterBindings().getBinding( parameter.getPosition() );
|
||||||
}
|
}
|
||||||
|
|
||||||
throw getExceptionConverter().convert(
|
throw getExceptionConverter().convert(
|
||||||
|
@ -424,15 +422,15 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private <P> QueryParameterBinding<P> locateBinding(QueryParameter<P> parameter) {
|
private <P> QueryParameterBinding<P> locateBinding(QueryParameter<P> parameter) {
|
||||||
return queryParameterBindings.getBinding( parameter );
|
return getQueryParameterBindings().getBinding( parameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
private <P> QueryParameterBinding<P> locateBinding(String name) {
|
private <P> QueryParameterBinding<P> locateBinding(String name) {
|
||||||
return queryParameterBindings.getBinding( name );
|
return getQueryParameterBindings().getBinding( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
private <P> QueryParameterBinding<P> locateBinding(int position) {
|
private <P> QueryParameterBinding<P> locateBinding(int position) {
|
||||||
return queryParameterBindings.getBinding( position );
|
return getQueryParameterBindings().getBinding( position );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -470,15 +468,15 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
private QueryParameterListBinding locateListBinding(Parameter parameter) {
|
private QueryParameterListBinding locateListBinding(Parameter parameter) {
|
||||||
if ( parameter instanceof QueryParameter ) {
|
if ( parameter instanceof QueryParameter ) {
|
||||||
return queryParameterBindings.getQueryParameterListBinding( (QueryParameter) parameter );
|
return getQueryParameterBindings().getQueryParameterListBinding( (QueryParameter) parameter );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return queryParameterBindings.getQueryParameterListBinding( parameter.getName() );
|
return getQueryParameterBindings().getQueryParameterListBinding( parameter.getName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryParameterListBinding locateListBinding(String name) {
|
private QueryParameterListBinding locateListBinding(String name) {
|
||||||
return queryParameterBindings.getQueryParameterListBinding( name );
|
return getQueryParameterBindings().getQueryParameterListBinding( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -493,7 +491,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
setParameterList( name, (Collection) value );
|
setParameterList( name, (Collection) value );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
queryParameterBindings.getBinding( name ).setBindValue( value );
|
getQueryParameterBindings().getBinding( name ).setBindValue( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -508,10 +506,10 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() );
|
setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() );
|
||||||
}
|
}
|
||||||
else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
|
else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
|
||||||
setParameterList( parameterMetadata.getQueryParameter( position ), (Collection) value );
|
setParameterList( getParameterMetadata().getQueryParameter( position ), (Collection) value );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
queryParameterBindings.getBinding( position ).setBindValue( value );
|
getQueryParameterBindings().getBinding( position ).setBindValue( value );
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -519,105 +517,105 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value, Type type) {
|
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value, Type type) {
|
||||||
queryParameterBindings.getBinding( parameter ).setBindValue( value, type );
|
getQueryParameterBindings().getBinding( parameter ).setBindValue( value, type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(String name, Object value, Type type) {
|
public QueryImplementor setParameter(String name, Object value, Type type) {
|
||||||
queryParameterBindings.getBinding( name ).setBindValue( value, type );
|
getQueryParameterBindings().getBinding( name ).setBindValue( value, type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(int position, Object value, Type type) {
|
public QueryImplementor setParameter(int position, Object value, Type type) {
|
||||||
queryParameterBindings.getBinding( position ).setBindValue( value, type );
|
getQueryParameterBindings().getBinding( position ).setBindValue( value, type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value, TemporalType temporalType) {
|
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value, TemporalType temporalType) {
|
||||||
queryParameterBindings.getBinding( parameter ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( parameter ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(String name, Object value, TemporalType temporalType) {
|
public QueryImplementor setParameter(String name, Object value, TemporalType temporalType) {
|
||||||
queryParameterBindings.getBinding( name ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( name ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(int position, Object value, TemporalType temporalType) {
|
public QueryImplementor setParameter(int position, Object value, TemporalType temporalType) {
|
||||||
queryParameterBindings.getBinding( position ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( position ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P> QueryImplementor<R> setParameterList(QueryParameter<P> parameter, Collection<P> values) {
|
public <P> QueryImplementor<R> setParameterList(QueryParameter<P> parameter, Collection<P> values) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( parameter ).setBindValues( values );
|
getQueryParameterBindings().getQueryParameterListBinding( parameter ).setBindValues( values );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(String name, Collection values) {
|
public QueryImplementor setParameterList(String name, Collection values) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( name ).setBindValues( values );
|
getQueryParameterBindings().getQueryParameterListBinding( name ).setBindValues( values );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(int position, Collection values) {
|
public QueryImplementor setParameterList(int position, Collection values) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( values );
|
getQueryParameterBindings().getQueryParameterListBinding( position ).setBindValues( values );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(String name, Collection values, Type type) {
|
public QueryImplementor setParameterList(String name, Collection values, Type type) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( name ).setBindValues( values, type );
|
getQueryParameterBindings().getQueryParameterListBinding( name ).setBindValues( values, type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(int position, Collection values, Type type) {
|
public QueryImplementor setParameterList(int position, Collection values, Type type) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( values, type );
|
getQueryParameterBindings().getQueryParameterListBinding( position ).setBindValues( values, type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(String name, Object[] values, Type type) {
|
public QueryImplementor setParameterList(String name, Object[] values, Type type) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( name ).setBindValues( Arrays.asList( values ), type );
|
getQueryParameterBindings().getQueryParameterListBinding( name ).setBindValues( Arrays.asList( values ), type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(int position, Object[] values, Type type) {
|
public QueryImplementor setParameterList(int position, Object[] values, Type type) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ), type );
|
getQueryParameterBindings().getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ), type );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(String name, Object[] values) {
|
public QueryImplementor setParameterList(String name, Object[] values) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( name ).setBindValues( Arrays.asList( values ) );
|
getQueryParameterBindings().getQueryParameterListBinding( name ).setBindValues( Arrays.asList( values ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameterList(int position, Object[] values) {
|
public QueryImplementor setParameterList(int position, Object[] values) {
|
||||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ) );
|
getQueryParameterBindings().getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +623,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
public QueryImplementor setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( (QueryParameter) param ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( (QueryParameter) param ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +631,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
public QueryImplementor setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( (QueryParameter) param ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( (QueryParameter) param ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,7 +639,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(String name, Calendar value, TemporalType temporalType) {
|
public QueryImplementor setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( name ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( name ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +647,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(String name, Date value, TemporalType temporalType) {
|
public QueryImplementor setParameter(String name, Date value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( name ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( name ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +655,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(int position, Calendar value, TemporalType temporalType) {
|
public QueryImplementor setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( position ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( position ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,7 +663,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public QueryImplementor setParameter(int position, Date value, TemporalType temporalType) {
|
public QueryImplementor setParameter(int position, Date value, TemporalType temporalType) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
queryParameterBindings.getBinding( position ).setBindValue( value, temporalType );
|
getQueryParameterBindings().getBinding( position ).setBindValue( value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +674,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter<?> getParameter(String name) {
|
public QueryParameter<?> getParameter(String name) {
|
||||||
getProducer().checkOpen( false );
|
getProducer().checkOpen( false );
|
||||||
try {
|
try {
|
||||||
return getParameterMetadata().getQueryParameter( name );
|
return getParameterMetadata().getQueryParameter( name );
|
||||||
|
@ -688,7 +686,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
public <T> QueryParameter<T> getParameter(String name, Class<T> type) {
|
||||||
try {
|
try {
|
||||||
final QueryParameter parameter = getParameterMetadata().getQueryParameter( name );
|
final QueryParameter parameter = getParameterMetadata().getQueryParameter( name );
|
||||||
if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
|
if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
|
||||||
|
@ -706,7 +704,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter<?> getParameter(int position) {
|
public QueryParameter<?> getParameter(int position) {
|
||||||
// It is important to understand that there are 2 completely distinct conceptualization of
|
// It is important to understand that there are 2 completely distinct conceptualization of
|
||||||
// "positional parameters" in play here:
|
// "positional parameters" in play here:
|
||||||
// 1) The legacy Hibernate concept is akin to JDBC PreparedStatement parameters. Very limited and
|
// 1) The legacy Hibernate concept is akin to JDBC PreparedStatement parameters. Very limited and
|
||||||
|
@ -739,7 +737,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
public <T> QueryParameter<T> getParameter(int position, Class<T> type) {
|
||||||
try {
|
try {
|
||||||
final QueryParameter parameter = getParameterMetadata().getQueryParameter( position );
|
final QueryParameter parameter = getParameterMetadata().getQueryParameter( position );
|
||||||
if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
|
if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
|
||||||
|
@ -759,18 +757,20 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
@Override
|
@Override
|
||||||
public boolean isBound(Parameter<?> parameter) {
|
public boolean isBound(Parameter<?> parameter) {
|
||||||
getProducer().checkOpen();
|
getProducer().checkOpen();
|
||||||
return queryParameterBindings.isBound( (QueryParameter) parameter );
|
return getQueryParameterBindings().isBound( (QueryParameter) parameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T getParameterValue(Parameter<T> parameter) {
|
public <T> T getParameterValue(Parameter<T> parameter) {
|
||||||
|
LOGGER.tracef( "#getParameterValue(%s)", parameter );
|
||||||
|
|
||||||
getProducer().checkOpen( false );
|
getProducer().checkOpen( false );
|
||||||
|
|
||||||
if ( !parameterMetadata.containsReference( (QueryParameter) parameter ) ) {
|
if ( !getParameterMetadata().containsReference( (QueryParameter) parameter ) ) {
|
||||||
throw new IllegalArgumentException( "Parameter reference [" + parameter + "] did not come from this query" );
|
throw new IllegalArgumentException( "Parameter reference [" + parameter + "] did not come from this query" );
|
||||||
}
|
}
|
||||||
|
|
||||||
final QueryParameterBinding<T> binding = queryParameterBindings.getBinding( (QueryParameter<T>) parameter );
|
final QueryParameterBinding<T> binding = getQueryParameterBindings().getBinding( (QueryParameter<T>) parameter );
|
||||||
LOGGER.debugf( "Checking whether parameter reference [%s] is bound : %s", parameter, binding.isBound() );
|
LOGGER.debugf( "Checking whether parameter reference [%s] is bound : %s", parameter, binding.isBound() );
|
||||||
if ( !binding.isBound() ) {
|
if ( !binding.isBound() ) {
|
||||||
throw new IllegalStateException( "Parameter value not yet bound : " + parameter.toString() );
|
throw new IllegalStateException( "Parameter value not yet bound : " + parameter.toString() );
|
||||||
|
@ -784,7 +784,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
final QueryParameterBinding binding;
|
final QueryParameterBinding binding;
|
||||||
try {
|
try {
|
||||||
binding = queryParameterBindings.getBinding( name );
|
binding = getQueryParameterBindings().getBinding( name );
|
||||||
}
|
}
|
||||||
catch (QueryParameterException e) {
|
catch (QueryParameterException e) {
|
||||||
throw new IllegalArgumentException( "Could not resolve parameter by name - " + name, e );
|
throw new IllegalArgumentException( "Could not resolve parameter by name - " + name, e );
|
||||||
|
@ -803,7 +803,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
final QueryParameterBinding binding;
|
final QueryParameterBinding binding;
|
||||||
try {
|
try {
|
||||||
binding = queryParameterBindings.getBinding( position );
|
binding = getQueryParameterBindings().getBinding( position );
|
||||||
}
|
}
|
||||||
catch (QueryParameterException e) {
|
catch (QueryParameterException e) {
|
||||||
throw new IllegalArgumentException( "Could not resolve parameter by position - " + position, e );
|
throw new IllegalArgumentException( "Could not resolve parameter by position - " + position, e );
|
||||||
|
@ -849,7 +849,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Type determineType(String namedParam, Class retType) {
|
protected Type determineType(String namedParam, Class retType) {
|
||||||
Type type = queryParameterBindings.getBinding( namedParam ).getBindType();
|
Type type = getQueryParameterBindings().getBinding( namedParam ).getBindType();
|
||||||
if ( type == null ) {
|
if ( type == null ) {
|
||||||
type = getParameterMetadata().getQueryParameter( namedParam ).getType();
|
type = getParameterMetadata().getQueryParameter( namedParam ).getType();
|
||||||
}
|
}
|
||||||
|
@ -1331,8 +1331,8 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
if ( cls.isInstance( getParameterMetadata() ) ) {
|
if ( cls.isInstance( getParameterMetadata() ) ) {
|
||||||
return (T) getParameterMetadata();
|
return (T) getParameterMetadata();
|
||||||
}
|
}
|
||||||
if ( cls.isInstance( queryParameterBindings ) ) {
|
if ( cls.isInstance( getQueryParameterBindings() ) ) {
|
||||||
return (T) queryParameterBindings;
|
return (T) getQueryParameterBindings();
|
||||||
}
|
}
|
||||||
if ( cls.isInstance( this ) ) {
|
if ( cls.isInstance( this ) ) {
|
||||||
return (T) this;
|
return (T) this;
|
||||||
|
@ -1358,7 +1358,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryParameters queryParameters = new QueryParameters(
|
QueryParameters queryParameters = new QueryParameters(
|
||||||
queryParameterBindings,
|
getQueryParameterBindings(),
|
||||||
getLockOptions(),
|
getLockOptions(),
|
||||||
queryOptions,
|
queryOptions,
|
||||||
true,
|
true,
|
||||||
|
@ -1381,23 +1381,23 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryParameters getQueryParameters() {
|
public QueryParameters getQueryParameters() {
|
||||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||||
return makeQueryParametersForExecution( expandedQuery );
|
return makeQueryParametersForExecution( expandedQuery );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
protected Type[] getPositionalParameterTypes() {
|
protected Type[] getPositionalParameterTypes() {
|
||||||
return queryParameterBindings.collectPositionalBindTypes();
|
return getQueryParameterBindings().collectPositionalBindTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
protected Object[] getPositionalParameterValues() {
|
protected Object[] getPositionalParameterValues() {
|
||||||
return queryParameterBindings.collectPositionalBindValues();
|
return getQueryParameterBindings().collectPositionalBindValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
protected Map<String, TypedValue> getNamedParameterMap() {
|
protected Map<String, TypedValue> getNamedParameterMap() {
|
||||||
return queryParameterBindings.collectNamedParameterBindings();
|
return getQueryParameterBindings().collectNamedParameterBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlushMode sessionFlushMode;
|
private FlushMode sessionFlushMode;
|
||||||
|
@ -1405,7 +1405,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
|
|
||||||
protected void beforeQuery() {
|
protected void beforeQuery() {
|
||||||
if ( optionalId == null ) {
|
if ( optionalId == null ) {
|
||||||
queryParameterBindings.verifyParametersBound( isCallable() );
|
getQueryParameterBindings().verifyParametersBound( isCallable() );
|
||||||
}
|
}
|
||||||
|
|
||||||
assert sessionFlushMode == null;
|
assert sessionFlushMode == null;
|
||||||
|
@ -1450,7 +1450,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
return EmptyIterator.INSTANCE;
|
return EmptyIterator.INSTANCE;
|
||||||
}
|
}
|
||||||
return getProducer().iterate(
|
return getProducer().iterate(
|
||||||
queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() ),
|
getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() ),
|
||||||
getQueryParameters()
|
getQueryParameters()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1475,7 +1475,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
if (getMaxResults() == 0){
|
if (getMaxResults() == 0){
|
||||||
return EmptyScrollableResults.INSTANCE;
|
return EmptyScrollableResults.INSTANCE;
|
||||||
}
|
}
|
||||||
final String query = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
final String query = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||||
QueryParameters queryParameters = makeQueryParametersForExecution( query );
|
QueryParameters queryParameters = makeQueryParametersForExecution( query );
|
||||||
queryParameters.setScrollMode( scrollMode );
|
queryParameters.setScrollMode( scrollMode );
|
||||||
return getProducer().scroll( query, queryParameters );
|
return getProducer().scroll( query, queryParameters );
|
||||||
|
@ -1538,16 +1538,14 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||||
return getProducer().list(
|
return getProducer().list(
|
||||||
expandedQuery,
|
expandedQuery,
|
||||||
makeQueryParametersForExecution( expandedQuery )
|
makeQueryParametersForExecution( expandedQuery )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryParameterBindingsImpl getQueryParameterBindings() {
|
protected abstract QueryParameterBindings getQueryParameterBindings();
|
||||||
return queryParameterBindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R uniqueResult() {
|
public R uniqueResult() {
|
||||||
|
@ -1620,7 +1618,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int doExecuteUpdate() {
|
protected int doExecuteUpdate() {
|
||||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||||
return getProducer().executeUpdate(
|
return getProducer().executeUpdate(
|
||||||
expandedQuery,
|
expandedQuery,
|
||||||
makeQueryParametersForExecution( expandedQuery )
|
makeQueryParametersForExecution( expandedQuery )
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ import org.hibernate.type.Type;
|
||||||
public class CollectionFilterImpl extends org.hibernate.query.internal.AbstractProducedQuery {
|
public class CollectionFilterImpl extends org.hibernate.query.internal.AbstractProducedQuery {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
private Object collection;
|
private Object collection;
|
||||||
|
private final QueryParameterBindingsImpl queryParameterBindings;
|
||||||
|
|
||||||
public CollectionFilterImpl(
|
public CollectionFilterImpl(
|
||||||
String queryString,
|
String queryString,
|
||||||
|
@ -34,6 +36,16 @@ public class CollectionFilterImpl extends org.hibernate.query.internal.AbstractP
|
||||||
super( session, parameterMetadata );
|
super( session, parameterMetadata );
|
||||||
this.queryString = queryString;
|
this.queryString = queryString;
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
|
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
||||||
|
parameterMetadata,
|
||||||
|
session.getFactory(),
|
||||||
|
session.isQueryParametersValidationEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return queryParameterBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.query.NativeQuery;
|
||||||
import org.hibernate.query.ParameterMetadata;
|
import org.hibernate.query.ParameterMetadata;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.spi.NativeQueryImplementor;
|
import org.hibernate.query.spi.NativeQueryImplementor;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -55,6 +56,7 @@ import static org.hibernate.jpa.QueryHints.HINT_NATIVE_LOCKMODE;
|
||||||
*/
|
*/
|
||||||
public class NativeQueryImpl<T> extends AbstractProducedQuery<T> implements NativeQueryImplementor<T> {
|
public class NativeQueryImpl<T> extends AbstractProducedQuery<T> implements NativeQueryImplementor<T> {
|
||||||
private final String sqlString;
|
private final String sqlString;
|
||||||
|
private final QueryParameterBindingsImpl queryParameterBindings;
|
||||||
private List<NativeSQLQueryReturn> queryReturns;
|
private List<NativeSQLQueryReturn> queryReturns;
|
||||||
private List<NativeQueryReturnBuilder> queryReturnBuilders;
|
private List<NativeQueryReturnBuilder> queryReturnBuilders;
|
||||||
private boolean autoDiscoverTypes;
|
private boolean autoDiscoverTypes;
|
||||||
|
@ -100,6 +102,13 @@ public class NativeQueryImpl<T> extends AbstractProducedQuery<T> implements Nati
|
||||||
else {
|
else {
|
||||||
this.queryReturns = new ArrayList<>();
|
this.queryReturns = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
||||||
|
parameterMetadata,
|
||||||
|
session.getFactory(),
|
||||||
|
session.isQueryParametersValidationEnabled()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeQueryImpl(
|
public NativeQueryImpl(
|
||||||
|
@ -113,6 +122,17 @@ public class NativeQueryImpl<T> extends AbstractProducedQuery<T> implements Nati
|
||||||
this.sqlString = sqlString;
|
this.sqlString = sqlString;
|
||||||
this.callable = callable;
|
this.callable = callable;
|
||||||
this.querySpaces = new ArrayList<>();
|
this.querySpaces = new ArrayList<>();
|
||||||
|
|
||||||
|
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
||||||
|
sqlParameterMetadata,
|
||||||
|
session.getFactory(),
|
||||||
|
session.isQueryParametersValidationEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return queryParameterBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
|
@ -197,14 +198,6 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
||||||
return (QueryParameter<T>) param;
|
return (QueryParameter<T>) param;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( param.getName() != null ) {
|
|
||||||
return getQueryParameter( param.getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( param.getPosition() != null ) {
|
|
||||||
return getQueryParameter( param.getPosition() );
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException( "Could not resolve javax.persistence.Parameter to org.hibernate.query.QueryParameter" );
|
throw new IllegalArgumentException( "Could not resolve javax.persistence.Parameter to org.hibernate.query.QueryParameter" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +225,20 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitRegistrations(Consumer<QueryParameter> action) {
|
||||||
|
if ( hasPositionalParameters() ) {
|
||||||
|
for ( OrdinalParameterDescriptor descriptor : ordinalDescriptorMap.values() ) {
|
||||||
|
action.accept( descriptor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( hasNamedParameters() ) {
|
||||||
|
for ( NamedParameterDescriptor descriptor : namedDescriptorMap.values() ) {
|
||||||
|
action.accept( descriptor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deprecated.
|
* Deprecated.
|
||||||
*
|
*
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.internal;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.query.ParameterMetadata;
|
import org.hibernate.query.ParameterMetadata;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,12 +18,24 @@ import org.hibernate.type.Type;
|
||||||
public class QueryImpl<R> extends AbstractProducedQuery<R> implements Query<R> {
|
public class QueryImpl<R> extends AbstractProducedQuery<R> implements Query<R> {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
|
||||||
|
private final QueryParameterBindingsImpl queryParameterBindings;
|
||||||
|
|
||||||
public QueryImpl(
|
public QueryImpl(
|
||||||
SharedSessionContractImplementor producer,
|
SharedSessionContractImplementor producer,
|
||||||
ParameterMetadata parameterMetadata,
|
ParameterMetadata parameterMetadata,
|
||||||
String queryString) {
|
String queryString) {
|
||||||
super( producer, parameterMetadata );
|
super( producer, parameterMetadata );
|
||||||
this.queryString = queryString;
|
this.queryString = queryString;
|
||||||
|
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
||||||
|
parameterMetadata,
|
||||||
|
producer.getFactory(),
|
||||||
|
producer.isQueryParametersValidationEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return queryParameterBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.type.Type;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class QueryParameterImpl<T> implements QueryParameter<T> {
|
public abstract class QueryParameterImpl<T> implements QueryParameter<T> {
|
||||||
private final Type expectedType;
|
private Type expectedType;
|
||||||
|
|
||||||
public QueryParameterImpl(Type expectedType) {
|
public QueryParameterImpl(Type expectedType) {
|
||||||
this.expectedType = expectedType;
|
this.expectedType = expectedType;
|
||||||
|
@ -29,6 +29,10 @@ public abstract class QueryParameterImpl<T> implements QueryParameter<T> {
|
||||||
return expectedType;
|
return expectedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHibernateType(Type expectedType) {
|
||||||
|
this.expectedType = expectedType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<T> getParameterType() {
|
public Class<T> getParameterType() {
|
||||||
return expectedType == null ? null : expectedType.getReturnedClass();
|
return expectedType == null ? null : expectedType.getReturnedClass();
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* 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.query.procedure.internal;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.engine.spi.TypedValue;
|
||||||
|
import org.hibernate.procedure.ParameterBind;
|
||||||
|
import org.hibernate.procedure.internal.ParameterBindImpl;
|
||||||
|
import org.hibernate.procedure.internal.ProcedureCallImpl;
|
||||||
|
import org.hibernate.query.QueryParameter;
|
||||||
|
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
|
import org.hibernate.query.spi.QueryParameterListBinding;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ProcedureParamBindings implements QueryParameterBindings {
|
||||||
|
private final ProcedureParameterMetadata parameterMetadata;
|
||||||
|
private final ProcedureCallImpl procedureCall;
|
||||||
|
|
||||||
|
private final Map<ProcedureParameterImplementor, ParameterBind> bindingMap = new HashMap<>();
|
||||||
|
|
||||||
|
public ProcedureParamBindings(
|
||||||
|
ProcedureParameterMetadata parameterMetadata,
|
||||||
|
ProcedureCallImpl procedureCall) {
|
||||||
|
this.parameterMetadata = parameterMetadata;
|
||||||
|
this.procedureCall = procedureCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcedureParameterMetadata getParameterMetadata() {
|
||||||
|
return parameterMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcedureCallImpl getProcedureCall() {
|
||||||
|
return procedureCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBound(QueryParameter parameter) {
|
||||||
|
return getBinding( parameter ).isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterBinding<T> getBinding(QueryParameter<T> parameter) {
|
||||||
|
final ProcedureParameterImplementor<T> procParam = parameterMetadata.resolve( parameter );
|
||||||
|
ParameterBind binding = bindingMap.get( procParam );
|
||||||
|
|
||||||
|
if ( binding == null ) {
|
||||||
|
if ( ! parameterMetadata.containsReference( parameter ) ) {
|
||||||
|
throw new IllegalArgumentException( "Passed parameter is not registered with this query" );
|
||||||
|
}
|
||||||
|
|
||||||
|
binding = new ParameterBindImpl( procParam, this );
|
||||||
|
bindingMap.put( procParam, binding );
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterBinding<T> getBinding(String name) {
|
||||||
|
return getBinding( parameterMetadata.getQueryParameter( name ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterBinding<T> getBinding(int position) {
|
||||||
|
return getBinding( parameterMetadata.getQueryParameter( position ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verifyParametersBound(boolean callable) {
|
||||||
|
parameterMetadata.visitRegistrations(
|
||||||
|
queryParameter -> {
|
||||||
|
final ProcedureParameterImplementor procParam = (ProcedureParameterImplementor) queryParameter;
|
||||||
|
if ( procParam.getMode() == ParameterMode.IN
|
||||||
|
|| procParam.getMode() == ParameterMode.INOUT ) {
|
||||||
|
if ( !getBinding( procParam ).isBound() ) {
|
||||||
|
// depending on "pass nulls" this might be ok...
|
||||||
|
// for now, just log a warning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String expandListValuedParameters(String queryString, SharedSessionContractImplementor producer) {
|
||||||
|
return queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(QueryParameter<T> parameter) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(int position) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// I think these are not needed for proc call execution
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type[] collectPositionalBindTypes() {
|
||||||
|
return new Type[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] collectPositionalBindValues() {
|
||||||
|
return new Object[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, TypedValue> collectNamedParameterBindings() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,36 +6,101 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.procedure.internal;
|
package org.hibernate.query.procedure.internal;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.Calendar;
|
||||||
import javax.persistence.ParameterMode;
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
|
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
||||||
|
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
||||||
|
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||||
|
import org.hibernate.procedure.ParameterBind;
|
||||||
|
import org.hibernate.procedure.ParameterMisuseException;
|
||||||
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
|
import org.hibernate.procedure.internal.ProcedureCallImpl;
|
||||||
|
import org.hibernate.procedure.spi.ParameterStrategy;
|
||||||
import org.hibernate.query.internal.QueryParameterImpl;
|
import org.hibernate.query.internal.QueryParameterImpl;
|
||||||
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
||||||
|
import org.hibernate.type.CalendarDateType;
|
||||||
|
import org.hibernate.type.CalendarTimeType;
|
||||||
|
import org.hibernate.type.CalendarType;
|
||||||
|
import org.hibernate.type.ProcedureParameterExtractionAware;
|
||||||
|
import org.hibernate.type.ProcedureParameterNamedBinder;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ProcedureParameterImpl<T> extends QueryParameterImpl<T> implements ProcedureParameterImplementor<T> {
|
public class ProcedureParameterImpl<T>
|
||||||
private ParameterRegistrationImplementor<T> nativeParamRegistration;
|
extends QueryParameterImpl<T>
|
||||||
|
implements ProcedureParameterImplementor<T>, ParameterRegistration<T> {
|
||||||
|
private static final Logger log = Logger.getLogger( ProcedureParameterImpl.class );
|
||||||
|
|
||||||
public ProcedureParameterImpl(ParameterRegistrationImplementor<T> nativeParamRegistration) {
|
private final ProcedureCallImpl procedureCall;
|
||||||
super( nativeParamRegistration.getHibernateType() );
|
private final String name;
|
||||||
this.nativeParamRegistration = nativeParamRegistration;
|
private final Integer position;
|
||||||
|
private final ParameterMode mode;
|
||||||
|
private final Class<T> javaType;
|
||||||
|
|
||||||
|
private int[] sqlTypes;
|
||||||
|
private boolean passNullsEnabled;
|
||||||
|
|
||||||
|
// in-flight state needed between prepare and extract
|
||||||
|
private int startIndex;
|
||||||
|
|
||||||
|
public ProcedureParameterImpl(
|
||||||
|
ProcedureCallImpl procedureCall,
|
||||||
|
String name,
|
||||||
|
ParameterMode mode,
|
||||||
|
Class<T> javaType,
|
||||||
|
Type hibernateType,
|
||||||
|
boolean initialPassNullsSetting) {
|
||||||
|
super( hibernateType );
|
||||||
|
this.procedureCall = procedureCall;
|
||||||
|
this.name = name;
|
||||||
|
this.position = null;
|
||||||
|
this.mode = mode;
|
||||||
|
this.javaType = javaType;
|
||||||
|
this.passNullsEnabled = initialPassNullsSetting;
|
||||||
|
|
||||||
|
setHibernateType( hibernateType );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcedureParameterImpl(
|
||||||
|
ProcedureCallImpl procedureCall,
|
||||||
|
Integer position,
|
||||||
|
ParameterMode mode,
|
||||||
|
Class<T> javaType,
|
||||||
|
Type hibernateType,
|
||||||
|
boolean initialPassNullsSetting) {
|
||||||
|
super( hibernateType );
|
||||||
|
this.procedureCall = procedureCall;
|
||||||
|
this.name = null;
|
||||||
|
this.position = position;
|
||||||
|
this.mode = mode;
|
||||||
|
this.javaType = javaType;
|
||||||
|
this.passNullsEnabled = initialPassNullsSetting;
|
||||||
|
|
||||||
|
setHibernateType( hibernateType );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParameterMode getMode() {
|
public ParameterMode getMode() {
|
||||||
return nativeParamRegistration.getMode();
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPassNullsEnabled() {
|
public boolean isPassNullsEnabled() {
|
||||||
return nativeParamRegistration.isPassNullsEnabled();
|
return passNullsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enablePassingNulls(boolean enabled) {
|
public void enablePassingNulls(boolean enabled) {
|
||||||
nativeParamRegistration.enablePassingNulls( enabled );
|
this.passNullsEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -45,16 +110,287 @@ public class ProcedureParameterImpl<T> extends QueryParameterImpl<T> implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return nativeParamRegistration.getName();
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getPosition() {
|
public Integer getPosition() {
|
||||||
return nativeParamRegistration.getPosition();
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParameterRegistrationImplementor<T> getNativeParameterRegistration() {
|
public Type getHibernateType() {
|
||||||
return nativeParamRegistration;
|
return getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHibernateType(Type expectedType) {
|
||||||
|
super.setHibernateType( expectedType );
|
||||||
|
|
||||||
|
if ( mode == ParameterMode.REF_CURSOR ) {
|
||||||
|
sqlTypes = new int[] { Types.REF_CURSOR };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( expectedType == null ) {
|
||||||
|
throw new IllegalArgumentException( "Type cannot be null" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sqlTypes = expectedType.sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getParameterType() {
|
||||||
|
return javaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterBind<T> getBind() {
|
||||||
|
return (ParameterBind<T>) procedureCall.getQueryParameterBindings().getBinding( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void bindValue(Object value) {
|
||||||
|
getBind().setBindValue( (T) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void bindValue(Object value, TemporalType explicitTemporalType) {
|
||||||
|
getBind().setBindValue( (T) value, explicitTemporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepare(CallableStatement statement, int startIndex) throws SQLException {
|
||||||
|
// initially set up the Type we will use for binding as the explicit type.
|
||||||
|
Type typeToUse = getHibernateType();
|
||||||
|
int[] sqlTypesToUse = sqlTypes;
|
||||||
|
|
||||||
|
final ParameterBind bind = getBind();
|
||||||
|
|
||||||
|
// however, for Calendar binding with an explicit TemporalType we may need to adjust this...
|
||||||
|
if ( bind != null && bind.getExplicitTemporalType() != null ) {
|
||||||
|
if ( Calendar.class.isInstance( bind.getValue() ) ) {
|
||||||
|
switch ( bind.getExplicitTemporalType() ) {
|
||||||
|
case TIMESTAMP: {
|
||||||
|
typeToUse = CalendarType.INSTANCE;
|
||||||
|
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATE: {
|
||||||
|
typeToUse = CalendarDateType.INSTANCE;
|
||||||
|
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TIME: {
|
||||||
|
typeToUse = CalendarTimeType.INSTANCE;
|
||||||
|
sqlTypesToUse = typeToUse.sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startIndex = startIndex;
|
||||||
|
if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
||||||
|
if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
||||||
|
if ( sqlTypesToUse.length > 1 ) {
|
||||||
|
// there is more than one column involved; see if the Hibernate Type can handle
|
||||||
|
// multi-param extraction...
|
||||||
|
final boolean canHandleMultiParamExtraction =
|
||||||
|
ProcedureParameterExtractionAware.class.isInstance( typeToUse )
|
||||||
|
&& ( (ProcedureParameterExtractionAware) typeToUse ).canDoExtraction();
|
||||||
|
if ( ! canHandleMultiParamExtraction ) {
|
||||||
|
// it cannot...
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Type [" + typeToUse + "] does support multi-parameter value extraction"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769).
|
||||||
|
// The idea is that an embeddable/custom type can have more than one column values
|
||||||
|
// that correspond with embeddable/custom attribute value. This does not seem to
|
||||||
|
// be working yet. For now, if sqlTypesToUse.length > 1, then register
|
||||||
|
// the out parameters by position (since we only have one name).
|
||||||
|
// This will cause a failure if there are other parameters bound by
|
||||||
|
// name and the dialect does not support "mixed" named/positional parameters;
|
||||||
|
// e.g., Oracle.
|
||||||
|
if ( sqlTypesToUse.length == 1 &&
|
||||||
|
procedureCall.getParameterStrategy() == ParameterStrategy.NAMED &&
|
||||||
|
canDoNameParameterBinding( typeToUse ) ) {
|
||||||
|
statement.registerOutParameter( getName(), sqlTypesToUse[0] );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for ( int i = 0; i < sqlTypesToUse.length; i++ ) {
|
||||||
|
statement.registerOutParameter( startIndex + i, sqlTypesToUse[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
|
||||||
|
if ( bind == null || bind.getValue() == null ) {
|
||||||
|
// the user did not bind a value to the parameter being processed. This is the condition
|
||||||
|
// 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
|
||||||
|
// parameter defines a default value. Deferring to that information would be the best option
|
||||||
|
if ( isPassNullsEnabled() ) {
|
||||||
|
log.debugf(
|
||||||
|
"Stored procedure [%s] IN/INOUT parameter [%s] not bound and `passNulls` was set to true; binding NULL",
|
||||||
|
procedureCall.getProcedureName(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
if ( this.procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) {
|
||||||
|
((ProcedureParameterNamedBinder) typeToUse).nullSafeSet(
|
||||||
|
statement,
|
||||||
|
null,
|
||||||
|
this.getName(),
|
||||||
|
procedureCall.getSession()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
typeToUse.nullSafeSet( statement, null, startIndex, procedureCall.getSession() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if ( this.procedureCall.getParameterStrategy() == ParameterStrategy.NAMED && canDoNameParameterBinding( typeToUse ) ) {
|
||||||
|
((ProcedureParameterNamedBinder) typeToUse).nullSafeSet(
|
||||||
|
statement,
|
||||||
|
bind.getValue(),
|
||||||
|
this.getName(),
|
||||||
|
procedureCall.getSession()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, procedureCall.getSession() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have a REF_CURSOR type param
|
||||||
|
if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED ) {
|
||||||
|
procedureCall.getSession().getFactory().getServiceRegistry()
|
||||||
|
.getService( RefCursorSupport.class )
|
||||||
|
.registerRefCursorParameter( statement, getName() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
procedureCall.getSession().getFactory().getServiceRegistry()
|
||||||
|
.getService( RefCursorSupport.class )
|
||||||
|
.registerRefCursorParameter( statement, startIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canDoNameParameterBinding(Type hibernateType) {
|
||||||
|
final ExtractedDatabaseMetaData databaseMetaData = procedureCall.getSession()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getJdbcSessionOwner()
|
||||||
|
.getJdbcSessionContext()
|
||||||
|
.getServiceRegistry().getService( JdbcEnvironment.class )
|
||||||
|
.getExtractedDatabaseMetaData();
|
||||||
|
return
|
||||||
|
databaseMetaData.supportsNamedParameters()
|
||||||
|
&& ProcedureParameterNamedBinder.class.isInstance( hibernateType )
|
||||||
|
&& ((ProcedureParameterNamedBinder) hibernateType).canDoSetting();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSqlTypes() {
|
||||||
|
if ( mode == ParameterMode.REF_CURSOR ) {
|
||||||
|
// we could use the Types#REF_CURSOR added in Java 8, but that would require requiring Java 8...
|
||||||
|
throw new IllegalStateException( "REF_CURSOR parameters do not have a SQL/JDBC type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return determineHibernateType().sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type determineHibernateType() {
|
||||||
|
final ParameterBind<T> bind = getBind();
|
||||||
|
|
||||||
|
// if the bind defines a type, that should be the most specific...
|
||||||
|
final Type bindType = bind.getBindType();
|
||||||
|
if ( bindType != null ) {
|
||||||
|
return bindType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, see if the parameter itself has an expected type, and if so use that...
|
||||||
|
final Type paramType = getHibernateType();
|
||||||
|
if ( paramType != null ) {
|
||||||
|
return paramType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we just have guessing games
|
||||||
|
if ( bind.getValue() != null ) {
|
||||||
|
return procedureCall.getSession()
|
||||||
|
.getFactory()
|
||||||
|
.getTypeResolver()
|
||||||
|
.heuristicType( bind.getValue().getClass().getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException( "Unable to determine SQL type(s) - Hibernate Type not known" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T extract(CallableStatement statement) {
|
||||||
|
if ( mode == ParameterMode.IN ) {
|
||||||
|
throw new ParameterMisuseException( "IN parameter not valid for output extraction" );
|
||||||
|
}
|
||||||
|
|
||||||
|
final Type hibernateType = determineHibernateType();
|
||||||
|
final int[] sqlTypes = hibernateType.sqlTypes( procedureCall.getSession().getFactory() );
|
||||||
|
|
||||||
|
// TODO: sqlTypesToUse.length > 1 does not seem to have a working use case (HHH-10769).
|
||||||
|
// For now, if sqlTypes.length > 1 with a named parameter, then extract
|
||||||
|
// parameter values by position (since we only have one name).
|
||||||
|
final boolean useNamed = sqlTypes.length == 1 &&
|
||||||
|
procedureCall.getParameterStrategy() == ParameterStrategy.NAMED &&
|
||||||
|
canDoNameParameterBinding( hibernateType );
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ( ProcedureParameterExtractionAware.class.isInstance( hibernateType ) ) {
|
||||||
|
if ( useNamed ) {
|
||||||
|
return (T) ( (ProcedureParameterExtractionAware) hibernateType ).extract(
|
||||||
|
statement,
|
||||||
|
new String[] { getName() },
|
||||||
|
procedureCall.getSession()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (T) ( (ProcedureParameterExtractionAware) hibernateType ).extract(
|
||||||
|
statement,
|
||||||
|
startIndex,
|
||||||
|
procedureCall.getSession()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( useNamed ) {
|
||||||
|
return (T) statement.getObject( name );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (T) statement.getObject( startIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
throw procedureCall.getSession().getFactory().getSQLExceptionHelper().convert(
|
||||||
|
e,
|
||||||
|
"Unable to extract OUT/INOUT parameter value"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,13 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
|
||||||
import org.hibernate.QueryParameterException;
|
import org.hibernate.procedure.internal.ProcedureCallImpl;
|
||||||
|
import org.hibernate.procedure.spi.ParameterRegistrationImplementor;
|
||||||
|
import org.hibernate.procedure.spi.ParameterStrategy;
|
||||||
import org.hibernate.query.ParameterMetadata;
|
import org.hibernate.query.ParameterMetadata;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.procedure.ProcedureParameter;
|
import org.hibernate.query.procedure.ProcedureParameter;
|
||||||
|
@ -25,35 +28,46 @@ import org.hibernate.query.procedure.spi.ProcedureParameterImplementor;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ProcedureParameterMetadata implements ParameterMetadata {
|
public class ProcedureParameterMetadata implements ParameterMetadata {
|
||||||
private List<ProcedureParameterImplementor> parameters;
|
private final ProcedureCallImpl procedureCall;
|
||||||
|
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
|
||||||
|
private List<ProcedureParameterImplementor> parameters = new ArrayList<>();
|
||||||
|
|
||||||
private boolean hasNamed;
|
public ProcedureParameterMetadata(ProcedureCallImpl procedureCall) {
|
||||||
private int ordinalParamCount;
|
this.procedureCall = procedureCall;
|
||||||
|
|
||||||
public ProcedureParameterMetadata() {
|
|
||||||
parameters = new ArrayList<>( );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerParameter(ProcedureParameterImplementor parameter) {
|
public void registerParameter(ProcedureParameterImplementor parameter) {
|
||||||
|
if ( parameter.getName() != null ) {
|
||||||
|
if ( parameterStrategy == ParameterStrategy.POSITIONAL ) {
|
||||||
|
throw new IllegalArgumentException( "Cannot mix named parameter with positional parameter registrations" );
|
||||||
|
}
|
||||||
|
parameterStrategy = ParameterStrategy.NAMED;
|
||||||
|
}
|
||||||
|
else if ( parameter.getPosition() != null ) {
|
||||||
|
if ( parameterStrategy == ParameterStrategy.NAMED ) {
|
||||||
|
throw new IllegalArgumentException( "Cannot mix positional parameter with named parameter registrations" );
|
||||||
|
}
|
||||||
|
this.parameterStrategy = ParameterStrategy.POSITIONAL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException( "Unrecognized parameter type : " + parameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( parameters == null ) {
|
if ( parameters == null ) {
|
||||||
parameters = new ArrayList<>();
|
parameters = new ArrayList<>();
|
||||||
}
|
}
|
||||||
parameters.add( parameter );
|
parameters.add( parameter );
|
||||||
|
|
||||||
this.hasNamed = hasNamed || parameter.getName() != null;
|
|
||||||
if ( parameter.getPosition() != null ) {
|
|
||||||
ordinalParamCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNamedParameters() {
|
public boolean hasNamedParameters() {
|
||||||
return hasNamed;
|
return parameterStrategy == ParameterStrategy.NAMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPositionalParameters() {
|
public boolean hasPositionalParameters() {
|
||||||
return ordinalParamCount > 0;
|
return parameterStrategy == ParameterStrategy.POSITIONAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,7 +90,7 @@ public class ProcedureParameterMetadata implements ParameterMetadata {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getNamedParameterNames() {
|
public Set<String> getNamedParameterNames() {
|
||||||
if ( !hasNamed ) {
|
if ( !hasNamedParameters() ) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,69 +105,53 @@ public class ProcedureParameterMetadata implements ParameterMetadata {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPositionalParameterCount() {
|
public int getPositionalParameterCount() {
|
||||||
return ordinalParamCount;
|
return hasPositionalParameters() ? parameters.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> QueryParameter<T> getQueryParameter(String name) {
|
public <T> ParameterRegistrationImplementor<T> getQueryParameter(String name) {
|
||||||
assert name != null;
|
assert name != null;
|
||||||
QueryParameter<T> result = null;
|
|
||||||
if ( hasNamed ) {
|
if ( hasNamedParameters() ) {
|
||||||
for ( ProcedureParameter parameter : parameters ) {
|
for ( ParameterRegistrationImplementor parameter : parameters ) {
|
||||||
if ( name.equals( parameter.getName() ) ) {
|
if ( name.equals( parameter.getName() ) ) {
|
||||||
result = parameter;
|
return parameter;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( result != null ) {
|
|
||||||
return result;
|
throw new IllegalArgumentException( "Named parameter [" + name + "] is not registered with this procedure call" );
|
||||||
}
|
|
||||||
throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> QueryParameter<T> getQueryParameter(Integer position) {
|
public <T> ParameterRegistrationImplementor<T> getQueryParameter(Integer position) {
|
||||||
assert position != null;
|
assert position != null;
|
||||||
|
|
||||||
if ( ordinalParamCount > 0 ) {
|
if ( hasPositionalParameters() ) {
|
||||||
for ( ProcedureParameter parameter : parameters ) {
|
for ( ParameterRegistrationImplementor parameter : parameters ) {
|
||||||
if ( parameter.getPosition() != null && position.intValue() == parameter.getPosition() ) {
|
if ( parameter.getPosition() != null && position.intValue() == parameter.getPosition() ) {
|
||||||
return parameter;
|
return parameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new QueryParameterException( "could not locate parameter at position [" + position + "]" );
|
|
||||||
|
throw new IllegalArgumentException( "Positional parameter [" + position + "] is not registered with this procedure call" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> QueryParameter<T> resolve(Parameter<T> param) {
|
public <T> ProcedureParameterImplementor<T> resolve(Parameter<T> param) {
|
||||||
// first see if that instance exists here...
|
if ( ProcedureParameterImplementor.class.isInstance( param ) ) {
|
||||||
for ( ProcedureParameter parameter : parameters ) {
|
for ( ProcedureParameterImplementor parameter : parameters ) {
|
||||||
if ( parameter == param ) {
|
if ( parameter == param ) {
|
||||||
return parameter;
|
return parameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, try name/position from the incoming param
|
|
||||||
if ( param.getPosition() != null || param.getName() != null ) {
|
|
||||||
for ( ProcedureParameter parameter : parameters ) {
|
|
||||||
// name
|
|
||||||
if ( param.getName() != null && param.getName().equals( parameter.getName() ) ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// position
|
throw new IllegalArgumentException( "Could not resolve javax.persistence.Parameter to org.hibernate.query.QueryParameter" );
|
||||||
if ( param.getPosition() != null && param.getPosition().equals( parameter.getPosition() ) ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -176,4 +174,16 @@ public class ProcedureParameterMetadata implements ParameterMetadata {
|
||||||
public boolean containsReference(QueryParameter parameter) {
|
public boolean containsReference(QueryParameter parameter) {
|
||||||
return parameters.contains( parameter );
|
return parameters.contains( parameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParameterStrategy getParameterStrategy() {
|
||||||
|
return parameterStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitRegistrations(Consumer<QueryParameter> action) {
|
||||||
|
for ( ProcedureParameterImplementor parameter : parameters ) {
|
||||||
|
action.accept( parameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,5 @@ import org.hibernate.query.procedure.ProcedureParameter;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ProcedureParameterImplementor<T> extends ProcedureParameter<T> {
|
public interface ProcedureParameterImplementor<T> extends ProcedureParameter<T>, ParameterRegistrationImplementor<T> {
|
||||||
ParameterRegistrationImplementor<T> getNativeParameterRegistration();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.spi;
|
package org.hibernate.query.spi;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.engine.spi.TypedValue;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -19,4 +24,15 @@ public interface QueryParameterBindings {
|
||||||
<T> QueryParameterBinding<T> getBinding(QueryParameter<T> parameter);
|
<T> QueryParameterBinding<T> getBinding(QueryParameter<T> parameter);
|
||||||
<T> QueryParameterBinding<T> getBinding(String name);
|
<T> QueryParameterBinding<T> getBinding(String name);
|
||||||
<T> QueryParameterBinding<T> getBinding(int position);
|
<T> QueryParameterBinding<T> getBinding(int position);
|
||||||
|
|
||||||
|
void verifyParametersBound(boolean callable);
|
||||||
|
String expandListValuedParameters(String queryString, SharedSessionContractImplementor producer);
|
||||||
|
|
||||||
|
<T> QueryParameterListBinding<T> getQueryParameterListBinding(QueryParameter<T> parameter);
|
||||||
|
<T> QueryParameterListBinding<T> getQueryParameterListBinding(String name);
|
||||||
|
<T> QueryParameterListBinding<T> getQueryParameterListBinding(int position);
|
||||||
|
|
||||||
|
Type[] collectPositionalBindTypes();
|
||||||
|
Object[] collectPositionalBindValues();
|
||||||
|
Map<String,TypedValue> collectNamedParameterBindings();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* 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.test.jpa.compliance.tck2_2;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Parameter;
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.boot.Metadata;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.procedure.ProcedureCall;
|
||||||
|
import org.hibernate.query.QueryParameter;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.test.sql.storedproc.StoredProcedureResultSetMappingTest;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@RequiresDialect( H2Dialect.class )
|
||||||
|
public class StoredProcedureApiTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parameterValueAccess() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
final ProcedureCall call = session.createStoredProcedureCall( "test" );
|
||||||
|
|
||||||
|
call.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
|
||||||
|
call.registerStoredProcedureParameter( 2, String.class, ParameterMode.OUT);
|
||||||
|
call.setParameter( 1, 1 );
|
||||||
|
call.getParameterValue( 1 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidParameterReference() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
final ProcedureCall call1 = session.createStoredProcedureCall( "test" );
|
||||||
|
call1.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
|
||||||
|
final Parameter<Integer> p1_1 = (Parameter<Integer>) call1.getParameter( 1 );
|
||||||
|
call1.setParameter( 1, 1 );
|
||||||
|
|
||||||
|
final ProcedureCall call2 = session.createStoredProcedureCall( "test" );
|
||||||
|
call2.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
|
||||||
|
call2.setParameter( 1, 1 );
|
||||||
|
|
||||||
|
try {
|
||||||
|
call2.getParameterValue( p1_1 );
|
||||||
|
fail( "Expecting failure" );
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParameterBindTypeMismatch() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
try {
|
||||||
|
final ProcedureCall call1 = session.createStoredProcedureCall( "test" );
|
||||||
|
call1.registerStoredProcedureParameter( 1, Integer.class, ParameterMode.IN );
|
||||||
|
call1.setParameter( 1, new Date() );
|
||||||
|
|
||||||
|
fail( "expecting failure" );
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
|
||||||
|
sources.addAnnotatedClass( Person.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterMetadataBuilt(Metadata metadata) {
|
||||||
|
super.afterMetadataBuilt( metadata );
|
||||||
|
|
||||||
|
// metadata.getDatabase().addAuxiliaryDatabaseObject(
|
||||||
|
// new StoredProcedureResultSetMappingTest.ProcedureDefinition() {
|
||||||
|
// @Override
|
||||||
|
// public boolean appliesToDialect(Dialect dialect) {
|
||||||
|
// return H2Dialect.class.isInstance( dialect );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public boolean beforeTablesOnCreation() {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getExportIdentifier() {
|
||||||
|
// return "StoredProcedure#test"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String[] sqlCreateStrings(Dialect dialect) {
|
||||||
|
// return super.sqlCreateStrings( dialect );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String[] sqlDropStrings(Dialect dialect) {
|
||||||
|
// return super.sqlDropStrings( dialect );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "Person" )
|
||||||
|
@Table( name = "person" )
|
||||||
|
public static class Person {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
public String name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -284,8 +284,10 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
session.beginTransaction();
|
session.beginTransaction();
|
||||||
|
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
query.registerParameter( 1, Integer.class, ParameterMode.IN ).bindValue( 1 );
|
query.registerParameter( 1, Integer.class, ParameterMode.IN )
|
||||||
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
.bindValue( 1 );
|
||||||
|
query.registerParameter( 2, Integer.class, ParameterMode.IN )
|
||||||
|
.bindValue( 2 );
|
||||||
ProcedureOutputs procedureResult = query.getOutputs();
|
ProcedureOutputs procedureResult = query.getOutputs();
|
||||||
Output currentOutput = procedureResult.getCurrent();
|
Output currentOutput = procedureResult.getCurrent();
|
||||||
assertNotNull( currentOutput );
|
assertNotNull( currentOutput );
|
||||||
|
|
Loading…
Reference in New Issue