HHH-8129 - Unify BaseQueryImpl and AbstractQueryImpl hierarchies
This commit is contained in:
parent
e17819ed61
commit
2f40949719
|
@ -78,7 +78,7 @@ public interface ParameterRegistration<T> {
|
||||||
*
|
*
|
||||||
* @return The parameter binding
|
* @return The parameter binding
|
||||||
*/
|
*/
|
||||||
public ParameterBind getParameterBind();
|
public ParameterBind<T> getBind();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
|
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
|
||||||
|
|
|
@ -129,7 +129,7 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParameterBind getParameterBind() {
|
public ParameterBind<T> getBind() {
|
||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,10 @@ package org.hibernate.jpa.internal;
|
||||||
|
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.NonUniqueResultException;
|
import javax.persistence.NonUniqueResultException;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.PersistenceException;
|
import javax.persistence.PersistenceException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.TransactionRequiredException;
|
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -46,10 +45,10 @@ import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.QueryParameterException;
|
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||||
|
import org.hibernate.engine.query.spi.ParameterMetadata;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
||||||
import org.hibernate.internal.SQLQueryImpl;
|
import org.hibernate.internal.SQLQueryImpl;
|
||||||
|
@ -77,7 +76,6 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
|
|
||||||
private org.hibernate.Query query;
|
private org.hibernate.Query query;
|
||||||
private Set<Integer> jpaPositionalIndices;
|
private Set<Integer> jpaPositionalIndices;
|
||||||
private Set<Parameter<?>> parameters;
|
|
||||||
|
|
||||||
public QueryImpl(org.hibernate.Query query, AbstractEntityManagerImpl em) {
|
public QueryImpl(org.hibernate.Query query, AbstractEntityManagerImpl em) {
|
||||||
this( query, em, Collections.<String, Class>emptyMap() );
|
this( query, em, Collections.<String, Class>emptyMap() );
|
||||||
|
@ -98,13 +96,11 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
throw new IllegalStateException( "Unknown query type for parameter extraction" );
|
throw new IllegalStateException( "Unknown query type for parameter extraction" );
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<Parameter<?>> parameters = new HashSet<Parameter<?>>();
|
final ParameterMetadata parameterMetadata = org.hibernate.internal.AbstractQueryImpl.class.cast( query ).getParameterMetadata();
|
||||||
org.hibernate.internal.AbstractQueryImpl queryImpl = org.hibernate.internal.AbstractQueryImpl.class.cast( query );
|
|
||||||
|
|
||||||
// extract named params
|
// extract named params
|
||||||
for ( String name : (Set<String>) queryImpl.getParameterMetadata().getNamedParameterNames() ) {
|
for ( String name : (Set<String>) parameterMetadata.getNamedParameterNames() ) {
|
||||||
final NamedParameterDescriptor descriptor =
|
final NamedParameterDescriptor descriptor = parameterMetadata.getNamedParameterDescriptor( name );
|
||||||
queryImpl.getParameterMetadata().getNamedParameterDescriptor( name );
|
|
||||||
Class javaType = namedParameterTypeRedefinition.get( name );
|
Class javaType = namedParameterTypeRedefinition.get( name );
|
||||||
if ( javaType != null && mightNeedRedefinition( javaType ) ) {
|
if ( javaType != null && mightNeedRedefinition( javaType ) ) {
|
||||||
descriptor.resetExpectedType(
|
descriptor.resetExpectedType(
|
||||||
|
@ -114,8 +110,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
else if ( descriptor.getExpectedType() != null ) {
|
else if ( descriptor.getExpectedType() != null ) {
|
||||||
javaType = descriptor.getExpectedType().getReturnedClass();
|
javaType = descriptor.getExpectedType().getReturnedClass();
|
||||||
}
|
}
|
||||||
final ParameterImpl parameter = new ParameterImpl( name, javaType );
|
registerParameter( new ParameterRegistrationImpl( query, name, javaType ) );
|
||||||
parameters.add( parameter );
|
|
||||||
if ( descriptor.isJpaStyle() ) {
|
if ( descriptor.isJpaStyle() ) {
|
||||||
if ( jpaPositionalIndices == null ) {
|
if ( jpaPositionalIndices == null ) {
|
||||||
jpaPositionalIndices = new HashSet<Integer>();
|
jpaPositionalIndices = new HashSet<Integer>();
|
||||||
|
@ -125,21 +120,15 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract positional parameters
|
// extract positional parameters
|
||||||
for ( int i = 0, max = queryImpl.getParameterMetadata().getOrdinalParameterCount(); i < max; i++ ) {
|
for ( int i = 0, max = parameterMetadata.getOrdinalParameterCount(); i < max; i++ ) {
|
||||||
final OrdinalParameterDescriptor descriptor =
|
final OrdinalParameterDescriptor descriptor = parameterMetadata.getOrdinalParameterDescriptor( i + 1 );
|
||||||
queryImpl.getParameterMetadata().getOrdinalParameterDescriptor( i+1 );
|
Class javaType = descriptor.getExpectedType() == null ? null : descriptor.getExpectedType().getReturnedClass();
|
||||||
ParameterImpl parameter = new ParameterImpl(
|
registerParameter( new ParameterRegistrationImpl( query, i+1, javaType ) );
|
||||||
i + 1,
|
|
||||||
descriptor.getExpectedType() == null
|
|
||||||
? null
|
|
||||||
: descriptor.getExpectedType().getReturnedClass()
|
|
||||||
);
|
|
||||||
parameters.add( parameter );
|
|
||||||
Integer position = descriptor.getOrdinalPosition();
|
Integer position = descriptor.getOrdinalPosition();
|
||||||
if (jpaPositionalIndices != null && jpaPositionalIndices.contains(position)) LOG.parameterPositionOccurredAsBothJpaAndHibernatePositionalParameter(position);
|
if ( jpaPositionalIndices != null && jpaPositionalIndices.contains(position) ) {
|
||||||
|
LOG.parameterPositionOccurredAsBothJpaAndHibernatePositionalParameter(position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parameters = java.util.Collections.unmodifiableSet( parameters );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SessionFactoryImplementor sfi() {
|
private SessionFactoryImplementor sfi() {
|
||||||
|
@ -151,149 +140,142 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
return java.util.Date.class.isAssignableFrom( javaType );
|
return java.util.Date.class.isAssignableFrom( javaType );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ParameterImpl implements ParameterImplementor {
|
|
||||||
|
|
||||||
|
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
|
||||||
|
private final org.hibernate.Query query;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Integer position;
|
private final Integer position;
|
||||||
private final Class javaType;
|
private final Class<T> javaType;
|
||||||
|
|
||||||
private ParameterImpl(String name, Class javaType) {
|
private ParameterBind<T> bind;
|
||||||
|
|
||||||
|
private ParameterRegistrationImpl(org.hibernate.Query query, String name, Class<T> javaType) {
|
||||||
|
this.query = query;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.javaType = javaType;
|
this.javaType = javaType;
|
||||||
this.position = null;
|
this.position = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterImpl(Integer position, Class javaType) {
|
private ParameterRegistrationImpl(org.hibernate.Query query, Integer position, Class<T> javaType) {
|
||||||
|
this.query = query;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.javaType = javaType;
|
this.javaType = javaType;
|
||||||
this.name = null;
|
this.name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Integer getPosition() {
|
public Integer getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getParameterType() {
|
@Override
|
||||||
|
public Class<T> getParameterType() {
|
||||||
return javaType;
|
return javaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateBinding(Object bind, TemporalType temporalType) {
|
public ParameterMode getMode() {
|
||||||
if ( bind == null || getParameterType() == null ) {
|
// implicitly
|
||||||
// nothing we can check
|
return ParameterMode.IN;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Collection.class.isInstance( bind ) && ! Collection.class.isAssignableFrom( getParameterType() ) ) {
|
@Override
|
||||||
// we have a collection passed in where we are expecting a non-collection.
|
public boolean isBindable() {
|
||||||
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
|
// again, implicitly
|
||||||
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
|
||||||
// will fall through to the main check.
|
|
||||||
validateCollectionValuedParameterBinding( (Collection) bind, temporalType );
|
|
||||||
}
|
|
||||||
else if ( bind.getClass().isArray() ) {
|
|
||||||
validateArrayValuedParameterBinding( bind, temporalType );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( ! isValidBindValue( getParameterType(), bind, temporalType ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Parameter value [%s] did not match expected type [%s (%s)]",
|
|
||||||
bind,
|
|
||||||
getParameterType().getName(),
|
|
||||||
extractName( temporalType )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractName(TemporalType temporalType) {
|
|
||||||
return temporalType == null ? "n/a" : temporalType.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateCollectionValuedParameterBinding(Collection value, TemporalType temporalType) {
|
|
||||||
// validate the elements...
|
|
||||||
for ( Object element : value ) {
|
|
||||||
if ( ! isValidBindValue( getParameterType(), element, temporalType ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Parameter value element [%s] did not match expected type [%s (%s)]",
|
|
||||||
element,
|
|
||||||
getParameterType().getName(),
|
|
||||||
extractName( temporalType )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateArrayValuedParameterBinding(Object value, TemporalType temporalType) {
|
|
||||||
if ( ! getParameterType().isArray() ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
|
|
||||||
getParameterType().getName(),
|
|
||||||
extractName( temporalType )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( value.getClass().getComponentType().isPrimitive() ) {
|
|
||||||
// we have a primitive array. we validate that the actual array has the component type (type of elements)
|
|
||||||
// we expect based on the component type of the parameter specification
|
|
||||||
if ( ! getParameterType().getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s (%s)]",
|
|
||||||
value.getClass().getComponentType().getName(),
|
|
||||||
getParameterType().getName(),
|
|
||||||
extractName( temporalType )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we have an object array. Here we loop over the array and physically check each element against
|
|
||||||
// the type we expect based on the component type of the parameter specification
|
|
||||||
final Object[] array = (Object[]) value;
|
|
||||||
for ( Object element : array ) {
|
|
||||||
if ( ! isValidBindValue( getParameterType().getComponentType(), element, temporalType ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
|
|
||||||
element,
|
|
||||||
getParameterType().getName(),
|
|
||||||
extractName( temporalType )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
|
|
||||||
if ( expectedType.isInstance( value ) ) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( temporalType != null ) {
|
@Override
|
||||||
final boolean parameterDeclarationIsTemporal = Date.class.isAssignableFrom( expectedType )
|
public void bindValue(T value) {
|
||||||
|| Calendar.class.isAssignableFrom( expectedType );
|
validateBinding( getParameterType(), value, null );
|
||||||
final boolean bindIsTemporal = Date.class.isInstance( value )
|
|
||||||
|| Calendar.class.isInstance( value );
|
|
||||||
|
|
||||||
if ( parameterDeclarationIsTemporal && bindIsTemporal ) {
|
if ( name != null ) {
|
||||||
return true;
|
if ( value instanceof Collection ) {
|
||||||
|
query.setParameterList( name, (Collection) value );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
query.setParameter( name, value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
query.setParameter( position-1, value );
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
bind = new ParameterBindImpl<T>( value, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindValue(T value, TemporalType specifiedTemporalType) {
|
||||||
|
validateBinding( getParameterType(), value, specifiedTemporalType );
|
||||||
|
|
||||||
|
if ( Date.class.isInstance( value ) ) {
|
||||||
|
if ( name != null ) {
|
||||||
|
if ( specifiedTemporalType == DATE ) {
|
||||||
|
query.setDate( name, (Date) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIME ) {
|
||||||
|
query.setTime( name, (Date) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIMESTAMP ) {
|
||||||
|
query.setTimestamp( name, (Date) value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( specifiedTemporalType == DATE ) {
|
||||||
|
query.setDate( position-1, (Date) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIME ) {
|
||||||
|
query.setTime( position-1, (Date) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIMESTAMP ) {
|
||||||
|
query.setTimestamp( position-1, (Date) value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Calendar.class.isInstance( value ) ) {
|
||||||
|
if ( name != null ) {
|
||||||
|
if ( specifiedTemporalType == DATE ) {
|
||||||
|
query.setCalendarDate( name, (Calendar) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIME ) {
|
||||||
|
throw new IllegalArgumentException( "not yet implemented" );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIMESTAMP ) {
|
||||||
|
query.setCalendar( name, (Calendar) value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( specifiedTemporalType == DATE ) {
|
||||||
|
query.setCalendarDate( position-1, (Calendar) value );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIME ) {
|
||||||
|
throw new IllegalArgumentException( "not yet implemented" );
|
||||||
|
}
|
||||||
|
else if ( specifiedTemporalType == TIMESTAMP ) {
|
||||||
|
query.setCalendar( position-1, (Calendar) value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unexpected type [" + value + "] passed with TemporalType; expecting Date or Calendar"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind = new ParameterBindImpl<T>( value, specifiedTemporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterBind<T> getBind() {
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public org.hibernate.Query getHibernateQuery() {
|
public org.hibernate.Query getHibernateQuery() {
|
||||||
|
@ -316,53 +298,60 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyTimeout(int timeout) {
|
protected boolean applyTimeoutHint(int timeout) {
|
||||||
query.setTimeout( timeout );
|
query.setTimeout( timeout );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyComment(String comment) {
|
protected boolean applyCommentHint(String comment) {
|
||||||
query.setComment( comment );
|
query.setComment( comment );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyFetchSize(int fetchSize) {
|
protected boolean applyFetchSizeHint(int fetchSize) {
|
||||||
query.setFetchSize( fetchSize );
|
query.setFetchSize( fetchSize );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyCacheable(boolean isCacheable) {
|
protected boolean applyCacheableHint(boolean isCacheable) {
|
||||||
query.setCacheable( isCacheable );
|
query.setCacheable( isCacheable );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyCacheRegion(String regionName) {
|
protected boolean applyCacheRegionHint(String regionName) {
|
||||||
query.setCacheRegion( regionName );
|
query.setCacheRegion( regionName );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyReadOnly(boolean isReadOnly) {
|
protected boolean applyReadOnlyHint(boolean isReadOnly) {
|
||||||
query.setReadOnly( isReadOnly );
|
query.setReadOnly( isReadOnly );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyCacheMode(CacheMode cacheMode) {
|
protected boolean applyCacheModeHint(CacheMode cacheMode) {
|
||||||
query.setCacheMode( cacheMode );
|
query.setCacheMode( cacheMode );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyFlushMode(FlushMode flushMode) {
|
protected boolean applyFlushModeHint(FlushMode flushMode) {
|
||||||
query.setFlushMode( flushMode );
|
query.setFlushMode( flushMode );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canApplyLockModes() {
|
protected boolean canApplyAliasSpecificLockModeHints() {
|
||||||
return org.hibernate.internal.QueryImpl.class.isInstance( query )
|
return org.hibernate.internal.QueryImpl.class.isInstance( query ) || SQLQueryImpl.class.isInstance( query );
|
||||||
|| SQLQueryImpl.class.isInstance( query );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyAliasSpecificLockMode(String alias, LockMode lockMode) {
|
protected void applyAliasSpecificLockModeHint(String alias, LockMode lockMode) {
|
||||||
query.getLockOptions().setAliasSpecificLockMode( alias, lockMode );
|
query.getLockOptions().setAliasSpecificLockMode( alias, lockMode );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,285 +412,10 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> TypedQuery<X> setParameter(Parameter<T> param, T value) {
|
protected boolean isJpaPositionalParameter(int position) {
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
if ( ! parameters.contains( param ) ) {
|
|
||||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
|
||||||
}
|
|
||||||
if ( param.getName() != null ) {
|
|
||||||
// a named param, for not delegate out. Eventually delegate *into* this method...
|
|
||||||
setParameter( param.getName(), value );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setParameter( param.getPosition(), value );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
if ( ! parameters.contains( param ) ) {
|
|
||||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
|
||||||
}
|
|
||||||
if ( param.getName() != null ) {
|
|
||||||
// a named param, for not delegate out. Eventually delegate *into* this method...
|
|
||||||
setParameter( param.getName(), value, temporalType );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setParameter( param.getPosition(), value, temporalType );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
if ( ! parameters.contains( param ) ) {
|
|
||||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
|
||||||
}
|
|
||||||
if ( param.getName() != null ) {
|
|
||||||
// a named param, for not delegate out. Eventually delegate *into* this method...
|
|
||||||
setParameter( param.getName(), value, temporalType );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setParameter( param.getPosition(), value, temporalType );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(String name, Object value) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( value instanceof Collection ) {
|
|
||||||
query.setParameterList( name, (Collection) value );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
query.setParameter( name, value );
|
|
||||||
}
|
|
||||||
registerParameterBinding( getParameter( name ), value, null );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(String name, Date value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( temporalType == DATE ) {
|
|
||||||
query.setDate( name, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIME ) {
|
|
||||||
query.setTime( name, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
|
||||||
query.setTimestamp( name, value );
|
|
||||||
}
|
|
||||||
registerParameterBinding( getParameter( name ), value, temporalType );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(String name, Calendar value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( temporalType == DATE ) {
|
|
||||||
query.setCalendarDate( name, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIME ) {
|
|
||||||
throw new IllegalArgumentException( "not yet implemented" );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
|
||||||
query.setCalendar( name, value );
|
|
||||||
}
|
|
||||||
registerParameterBinding( getParameter(name), value, temporalType );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(int position, Object value) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( isJpaPositionalParameter( position ) ) {
|
|
||||||
this.setParameter( Integer.toString( position ), value );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
query.setParameter( position - 1, value );
|
|
||||||
registerParameterBinding( getParameter( position ), value, null );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isJpaPositionalParameter(int position) {
|
|
||||||
return jpaPositionalIndices != null && jpaPositionalIndices.contains( position );
|
return jpaPositionalIndices != null && jpaPositionalIndices.contains( position );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(int position, Date value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( isJpaPositionalParameter( position ) ) {
|
|
||||||
String name = Integer.toString( position );
|
|
||||||
this.setParameter( name, value, temporalType );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( temporalType == DATE ) {
|
|
||||||
query.setDate( position - 1, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIME ) {
|
|
||||||
query.setTime( position - 1, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
|
||||||
query.setTimestamp( position - 1, value );
|
|
||||||
}
|
|
||||||
registerParameterBinding( getParameter( position ), value, temporalType );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setParameter(int position, Calendar value, TemporalType temporalType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
try {
|
|
||||||
if ( isJpaPositionalParameter( position ) ) {
|
|
||||||
String name = Integer.toString( position );
|
|
||||||
this.setParameter( name, value, temporalType );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( temporalType == DATE ) {
|
|
||||||
query.setCalendarDate( position - 1, value );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIME ) {
|
|
||||||
throw new IllegalArgumentException( "not yet implemented" );
|
|
||||||
}
|
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
|
||||||
query.setCalendar( position - 1, value );
|
|
||||||
}
|
|
||||||
registerParameterBinding( getParameter( position ), value, temporalType );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
catch (QueryParameterException e) {
|
|
||||||
throw new IllegalArgumentException( e );
|
|
||||||
}
|
|
||||||
catch (HibernateException he) {
|
|
||||||
throw getEntityManager().convert( he );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Parameter<?>> getParameters() {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Parameter<?> getParameter(String name) {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
if ( name == null ) {
|
|
||||||
throw new IllegalArgumentException( "Name of parameter to locate cannot be null" );
|
|
||||||
}
|
|
||||||
for ( Parameter parameter : parameters ) {
|
|
||||||
if ( name.equals( parameter.getName() ) ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException( "Unable to locate parameter named [" + name + "]" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Parameter<?> getParameter(int position) {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
if ( isJpaPositionalParameter( position ) ) {
|
|
||||||
return getParameter( Integer.toString( position ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for ( Parameter parameter : parameters ) {
|
|
||||||
if ( parameter.getPosition() != null && position == parameter.getPosition() ) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException( "Unable to locate parameter with position [" + position + "]" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
|
||||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
Parameter param = getParameter( name );
|
|
||||||
if ( param.getParameterType() != null ) {
|
|
||||||
// we were able to determine the expected type during analysis, so validate it here
|
|
||||||
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter named [%s]",
|
|
||||||
param.getParameterType().getName(),
|
|
||||||
type.getName(),
|
|
||||||
name
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
|
||||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
Parameter param = getParameter( position );
|
|
||||||
if ( param.getParameterType() != null ) {
|
|
||||||
// we were able to determine the expected type during analysis, so validate it here
|
|
||||||
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter position [%s]",
|
|
||||||
param.getParameterType().getName(),
|
|
||||||
type.getName(),
|
|
||||||
position
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public <T> T unwrap(Class<T> tClass) {
|
public <T> T unwrap(Class<T> tClass) {
|
||||||
|
@ -723,35 +437,19 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private javax.persistence.LockModeType jpaLockMode = javax.persistence.LockModeType.NONE;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
protected void internalApplyLockMode(javax.persistence.LockModeType lockModeType) {
|
||||||
public TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType) {
|
|
||||||
getEntityManager().checkOpen( true );
|
|
||||||
if (! getEntityManager().isTransactionInProgress()) {
|
|
||||||
throw new TransactionRequiredException( "no transaction is in progress" );
|
|
||||||
}
|
|
||||||
if ( ! canApplyLockModes() ) {
|
|
||||||
throw new IllegalStateException( "Not a JPAQL/Criteria query" );
|
|
||||||
}
|
|
||||||
this.jpaLockMode = lockModeType;
|
|
||||||
query.getLockOptions().setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
query.getLockOptions().setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
||||||
if ( getHints() != null && getHints().containsKey( AvailableSettings.LOCK_TIMEOUT ) ) {
|
if ( getHints() != null && getHints().containsKey( AvailableSettings.LOCK_TIMEOUT ) ) {
|
||||||
applyLockTimeout( ConfigurationHelper.getInteger( getHints().get( AvailableSettings.LOCK_TIMEOUT ) ) );
|
applyLockTimeoutHint( ConfigurationHelper.getInteger( getHints().get( AvailableSettings.LOCK_TIMEOUT ) ) );
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyLockTimeout(int timeout) {
|
protected boolean applyLockTimeoutHint(int timeout) {
|
||||||
query.getLockOptions().setTimeOut( timeout );
|
query.getLockOptions().setTimeOut( timeout );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public javax.persistence.LockModeType getLockMode() {
|
|
||||||
getEntityManager().checkOpen( false );
|
|
||||||
return jpaLockMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,11 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||||
entityManager().checkOpen( true );
|
entityManager().checkOpen( true );
|
||||||
procedureCall.registerParameter( position, type, mode );
|
registerParameter(
|
||||||
|
new ParameterRegistrationImpl(
|
||||||
|
procedureCall.registerParameter( position, type, mode )
|
||||||
|
)
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,27 +109,14 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
||||||
entityManager().checkOpen( true );
|
entityManager().checkOpen( true );
|
||||||
procedureCall.registerParameter( parameterName, type, mode );
|
registerParameter(
|
||||||
|
new ParameterRegistrationImpl(
|
||||||
|
procedureCall.registerParameter( parameterName, type, mode )
|
||||||
|
)
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void validateParameterBindingTypes(ParameterImplementor parameter, ParameterValue bindValue) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// covariant returns ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StoredProcedureQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
|
||||||
return (StoredProcedureQueryImpl) super.setFlushMode( jpaFlushMode );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StoredProcedureQueryImpl setHint(String hintName, Object value) {
|
|
||||||
return (StoredProcedureQueryImpl) super.setHint( hintName, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> StoredProcedureQueryImpl setParameter(Parameter<T> param, T value) {
|
public <T> StoredProcedureQueryImpl setParameter(Parameter<T> param, T value) {
|
||||||
return (StoredProcedureQueryImpl) super.setParameter( param, value );
|
return (StoredProcedureQueryImpl) super.setParameter( param, value );
|
||||||
|
@ -172,6 +163,19 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// covariant returns ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StoredProcedureQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
||||||
|
return (StoredProcedureQueryImpl) super.setFlushMode( jpaFlushMode );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StoredProcedureQueryImpl setHint(String hintName, Object value) {
|
||||||
|
return (StoredProcedureQueryImpl) super.setHint( hintName, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
private ProcedureResult outputs() {
|
private ProcedureResult outputs() {
|
||||||
|
@ -263,7 +267,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canApplyLockModesHints() {
|
protected boolean canApplyAliasSpecificLockModeHints() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +286,81 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyFetchSize(int fetchSize) {
|
protected boolean applyFetchSizeHint(int fetchSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isJpaPositionalParameter(int position) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
|
||||||
|
private final org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration;
|
||||||
|
|
||||||
|
private ParameterBind<T> bind;
|
||||||
|
|
||||||
|
private ParameterRegistrationImpl(org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration) {
|
||||||
|
this.nativeParamRegistration = nativeParamRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return nativeParamRegistration.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPosition() {
|
||||||
|
return nativeParamRegistration.getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getParameterType() {
|
||||||
|
return nativeParamRegistration.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterMode getMode() {
|
||||||
|
return nativeParamRegistration.getMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBindable() {
|
||||||
|
return getMode() == ParameterMode.IN || getMode() == ParameterMode.INOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindValue(T value) {
|
||||||
|
bindValue( value, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindValue(T value, TemporalType specifiedTemporalType) {
|
||||||
|
validateBinding( getParameterType(), value, specifiedTemporalType );
|
||||||
|
|
||||||
|
nativeParamRegistration.bindValue( value,specifiedTemporalType );
|
||||||
|
|
||||||
|
if ( bind == null ) {
|
||||||
|
bind = new ParameterBind<T>() {
|
||||||
|
@Override
|
||||||
|
public T getValue() {
|
||||||
|
return nativeParamRegistration.getBind().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemporalType getSpecifiedTemporalType() {
|
||||||
|
return nativeParamRegistration.getBind().getExplicitTemporalType();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterBind<T> getBind() {
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,65 +23,35 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.jpa.spi;
|
package org.hibernate.jpa.spi;
|
||||||
|
|
||||||
import javax.persistence.CacheRetrieveMode;
|
|
||||||
import javax.persistence.CacheStoreMode;
|
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.TransactionRequiredException;
|
import javax.persistence.TransactionRequiredException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import java.util.Collection;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
||||||
import org.hibernate.jpa.AvailableSettings;
|
|
||||||
import org.hibernate.jpa.QueryHints;
|
import org.hibernate.jpa.QueryHints;
|
||||||
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
|
|
||||||
import org.hibernate.jpa.internal.util.CacheModeHelper;
|
|
||||||
import org.hibernate.jpa.internal.util.ConfigurationHelper;
|
|
||||||
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
|
|
||||||
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_CACHEABLE;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_CACHE_MODE;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_CACHE_REGION;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_COMMENT;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_FLUSH_MODE;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_READONLY;
|
|
||||||
import static org.hibernate.jpa.QueryHints.HINT_TIMEOUT;
|
|
||||||
import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intended as a base class providing convenience in implementing both {@link javax.persistence.Query} and
|
* Base class for implementing both {@link javax.persistence.Query} and {@link javax.persistence.TypedQuery}, including
|
||||||
* {@link javax.persistence.TypedQuery}.
|
* query references built from criteria queries.
|
||||||
* <p/>
|
* <p/>
|
||||||
* IMPL NOTE : This issue, and the reason for this distinction, is that criteria and hl.sql queries share no
|
* Not intended as base for {@link javax.persistence.StoredProcedureQuery}
|
||||||
* commonality currently in Hibernate internals.
|
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
public abstract class AbstractQueryImpl<X> extends BaseQueryImpl implements TypedQuery<X> {
|
||||||
|
|
||||||
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
|
|
||||||
AbstractQueryImpl.class.getName());
|
|
||||||
|
|
||||||
private final HibernateEntityManagerImplementor entityManager;
|
|
||||||
|
|
||||||
public AbstractQueryImpl(HibernateEntityManagerImplementor entityManager) {
|
public AbstractQueryImpl(HibernateEntityManagerImplementor entityManager) {
|
||||||
this.entityManager = entityManager;
|
super( entityManager );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HibernateEntityManagerImplementor getEntityManager() {
|
protected HibernateEntityManagerImplementor getEntityManager() {
|
||||||
return entityManager;
|
return entityManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,10 +64,14 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "ThrowableInstanceNeverThrown" })
|
@SuppressWarnings({ "ThrowableInstanceNeverThrown" })
|
||||||
public int executeUpdate() {
|
public int executeUpdate() {
|
||||||
entityManager.checkOpen( true );
|
checkOpen( true );
|
||||||
try {
|
try {
|
||||||
if ( ! entityManager.isTransactionInProgress() ) {
|
if ( ! entityManager().isTransactionInProgress() ) {
|
||||||
entityManager.throwPersistenceException( new TransactionRequiredException( "Executing an update/delete query" ) );
|
entityManager().throwPersistenceException(
|
||||||
|
new TransactionRequiredException(
|
||||||
|
"Executing an update/delete query"
|
||||||
|
)
|
||||||
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return internalExecuteUpdate();
|
return internalExecuteUpdate();
|
||||||
|
@ -109,203 +83,27 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
catch ( HibernateException he) {
|
catch ( HibernateException he) {
|
||||||
entityManager.throwPersistenceException( he );
|
entityManager().throwPersistenceException( he );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int maxResults = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the given max results value.
|
|
||||||
*
|
|
||||||
* @param maxResults The specified max results
|
|
||||||
*/
|
|
||||||
protected abstract void applyMaxResults(int maxResults);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypedQuery<X> setMaxResults(int maxResult) {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( true );
|
public AbstractQueryImpl<X> setMaxResults(int maxResults) {
|
||||||
if ( maxResult < 0 ) {
|
return (AbstractQueryImpl<X>) super.setMaxResults( maxResults );
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Negative value (" + maxResult + ") passed to setMaxResults"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.maxResults = maxResult;
|
|
||||||
applyMaxResults( maxResult );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSpecifiedMaxResults() {
|
|
||||||
return maxResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxResults() {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
public AbstractQueryImpl<X> setFirstResult(int firstResult) {
|
||||||
return maxResults == -1
|
return (AbstractQueryImpl<X>) super.setFirstResult( firstResult );
|
||||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
|
||||||
: maxResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int firstResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the given first-result value.
|
|
||||||
*
|
|
||||||
* @param firstResult The specified first-result value.
|
|
||||||
*/
|
|
||||||
protected abstract void applyFirstResult(int firstResult);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedQuery<X> setFirstResult(int firstResult) {
|
|
||||||
entityManager.checkOpen( true );
|
|
||||||
if ( firstResult < 0 ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Negative value (" + firstResult + ") passed to setFirstResult"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.firstResult = firstResult;
|
|
||||||
applyFirstResult( firstResult );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getFirstResult() {
|
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
|
||||||
return firstResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> hints;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> getHints() {
|
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
|
||||||
return hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void applyTimeout(int timeout);
|
|
||||||
|
|
||||||
protected abstract void applyLockTimeout(int timeout);
|
|
||||||
|
|
||||||
protected abstract void applyComment(String comment);
|
|
||||||
|
|
||||||
protected abstract void applyFetchSize(int fetchSize);
|
|
||||||
|
|
||||||
protected abstract void applyCacheable(boolean isCacheable);
|
|
||||||
|
|
||||||
protected abstract void applyCacheRegion(String regionName);
|
|
||||||
|
|
||||||
protected abstract void applyReadOnly(boolean isReadOnly);
|
|
||||||
|
|
||||||
protected abstract void applyCacheMode(CacheMode cacheMode);
|
|
||||||
|
|
||||||
protected abstract void applyFlushMode(FlushMode flushMode);
|
|
||||||
|
|
||||||
protected abstract boolean canApplyLockModes();
|
|
||||||
|
|
||||||
protected abstract void applyAliasSpecificLockMode(String alias, LockMode lockMode);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( {"deprecation"})
|
@SuppressWarnings( {"deprecation"})
|
||||||
public TypedQuery<X> setHint(String hintName, Object value) {
|
public AbstractQueryImpl<X> setHint(String hintName, Object value) {
|
||||||
entityManager.checkOpen( true );
|
super.setHint( hintName, value );
|
||||||
boolean skipped = false;
|
|
||||||
try {
|
|
||||||
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
|
||||||
applyTimeout( ConfigurationHelper.getInteger( value ) );
|
|
||||||
}
|
|
||||||
else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) {
|
|
||||||
// convert milliseconds to seconds
|
|
||||||
int timeout = (int)Math.round(ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 );
|
|
||||||
applyTimeout( timeout );
|
|
||||||
}
|
|
||||||
else if ( AvailableSettings.LOCK_TIMEOUT.equals( hintName ) ) {
|
|
||||||
applyLockTimeout( ConfigurationHelper.getInteger( value ) );
|
|
||||||
}
|
|
||||||
else if ( HINT_COMMENT.equals( hintName ) ) {
|
|
||||||
applyComment( (String) value );
|
|
||||||
}
|
|
||||||
else if ( HINT_FETCH_SIZE.equals( hintName ) ) {
|
|
||||||
applyFetchSize( ConfigurationHelper.getInteger( value ) );
|
|
||||||
}
|
|
||||||
else if ( HINT_CACHEABLE.equals( hintName ) ) {
|
|
||||||
applyCacheable( ConfigurationHelper.getBoolean( value ) );
|
|
||||||
}
|
|
||||||
else if ( HINT_CACHE_REGION.equals( hintName ) ) {
|
|
||||||
applyCacheRegion( (String) value );
|
|
||||||
}
|
|
||||||
else if ( HINT_READONLY.equals( hintName ) ) {
|
|
||||||
applyReadOnly( ConfigurationHelper.getBoolean( value ) );
|
|
||||||
}
|
|
||||||
else if ( HINT_CACHE_MODE.equals( hintName ) ) {
|
|
||||||
applyCacheMode( ConfigurationHelper.getCacheMode( value ) );
|
|
||||||
}
|
|
||||||
else if ( HINT_FLUSH_MODE.equals( hintName ) ) {
|
|
||||||
applyFlushMode( ConfigurationHelper.getFlushMode( value ) );
|
|
||||||
}
|
|
||||||
else if ( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) ) {
|
|
||||||
final CacheRetrieveMode retrieveMode = (CacheRetrieveMode) value;
|
|
||||||
|
|
||||||
CacheStoreMode storeMode = hints != null
|
|
||||||
? (CacheStoreMode) hints.get( AvailableSettings.SHARED_CACHE_STORE_MODE )
|
|
||||||
: null;
|
|
||||||
if ( storeMode == null ) {
|
|
||||||
storeMode = (CacheStoreMode) entityManager.getProperties()
|
|
||||||
.get( AvailableSettings.SHARED_CACHE_STORE_MODE );
|
|
||||||
}
|
|
||||||
applyCacheMode(
|
|
||||||
CacheModeHelper.interpretCacheMode( storeMode, retrieveMode )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ( AvailableSettings.SHARED_CACHE_STORE_MODE.equals( hintName ) ) {
|
|
||||||
final CacheStoreMode storeMode = (CacheStoreMode) value;
|
|
||||||
|
|
||||||
CacheRetrieveMode retrieveMode = hints != null
|
|
||||||
? (CacheRetrieveMode) hints.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE )
|
|
||||||
: null;
|
|
||||||
if ( retrieveMode == null ) {
|
|
||||||
retrieveMode = (CacheRetrieveMode) entityManager.getProperties()
|
|
||||||
.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
|
|
||||||
}
|
|
||||||
applyCacheMode(
|
|
||||||
CacheModeHelper.interpretCacheMode( storeMode, retrieveMode )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ( hintName.startsWith( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE ) ) {
|
|
||||||
if ( ! canApplyLockModes() ) {
|
|
||||||
skipped = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// extract the alias
|
|
||||||
final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
|
|
||||||
// determine the LockMode
|
|
||||||
try {
|
|
||||||
final LockMode lockMode = LockModeTypeHelper.interpretLockMode( value );
|
|
||||||
applyAliasSpecificLockMode( alias, lockMode );
|
|
||||||
}
|
|
||||||
catch ( Exception e ) {
|
|
||||||
LOG.unableToDetermineLockModeValue(hintName, value);
|
|
||||||
skipped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
skipped = true;
|
|
||||||
LOG.ignoringUnrecognizedQueryHint(hintName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( ClassCastException e ) {
|
|
||||||
throw new IllegalArgumentException( "Value for hint" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !skipped ) {
|
|
||||||
if ( hints == null ) {
|
|
||||||
hints = new HashMap<String,Object>();
|
|
||||||
}
|
|
||||||
hints.put( hintName, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,137 +112,91 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return QueryHints.getDefinedHints();
|
return QueryHints.getDefinedHints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private javax.persistence.LockModeType jpaLockMode = javax.persistence.LockModeType.NONE;
|
||||||
public abstract TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract javax.persistence.LockModeType getLockMode();
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType) {
|
||||||
private FlushModeType jpaFlushMode;
|
checkOpen( true );
|
||||||
|
if (! getEntityManager().isTransactionInProgress()) {
|
||||||
@Override
|
throw new TransactionRequiredException( "no transaction is in progress" );
|
||||||
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
|
||||||
entityManager.checkOpen( true );
|
|
||||||
this.jpaFlushMode = jpaFlushMode;
|
|
||||||
// TODO : treat as hint?
|
|
||||||
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
|
||||||
applyFlushMode( FlushMode.AUTO );
|
|
||||||
}
|
}
|
||||||
else if ( jpaFlushMode == FlushModeType.COMMIT ) {
|
if ( ! canApplyAliasSpecificLockModeHints() ) {
|
||||||
applyFlushMode( FlushMode.COMMIT );
|
throw new IllegalStateException( "Not a JPAQL/Criteria query" );
|
||||||
}
|
}
|
||||||
|
this.jpaLockMode = lockModeType;
|
||||||
|
internalApplyLockMode( lockModeType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
protected abstract void internalApplyLockMode(javax.persistence.LockModeType lockModeType);
|
||||||
protected FlushModeType getSpecifiedFlushMode() {
|
|
||||||
return jpaFlushMode;
|
@Override
|
||||||
|
public javax.persistence.LockModeType getLockMode() {
|
||||||
|
getEntityManager().checkOpen( false );
|
||||||
|
return jpaLockMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// convariant return handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> AbstractQueryImpl<X> setParameter(Parameter<T> param, T value) {
|
||||||
|
return (AbstractQueryImpl<X>) super.setParameter( param, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlushModeType getFlushMode() {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
public AbstractQueryImpl<X> setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||||
return jpaFlushMode != null
|
return (AbstractQueryImpl<X>) super.setParameter( param, value, temporalType );
|
||||||
? jpaFlushMode
|
|
||||||
: entityManager.getFlushMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Map parameterBindings;
|
|
||||||
|
|
||||||
protected static interface ParameterImplementor<T> extends Parameter<T> {
|
|
||||||
public void validateBinding(Object bind, TemporalType temporalType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
|
||||||
protected void registerParameterBinding(Parameter parameter, Object value, TemporalType temporalType) {
|
|
||||||
if ( parameter == null ) {
|
|
||||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
|
||||||
}
|
|
||||||
|
|
||||||
( (ParameterImplementor) parameter ).validateBinding( value, temporalType );
|
|
||||||
|
|
||||||
if ( parameterBindings == null ) {
|
|
||||||
parameterBindings = new HashMap();
|
|
||||||
}
|
|
||||||
parameterBindings.put( parameter, value );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateArrayValuedParameterBinding(ParameterImplementor parameter, Object value) {
|
|
||||||
if ( ! parameter.getParameterType().isArray() ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Encountered array-valued parameter binding, but was expecting [%s]",
|
|
||||||
parameter.getParameterType().getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( value.getClass().getComponentType().isPrimitive() ) {
|
|
||||||
// we have a primitive array. we validate that the actual array has the component type (type odf elements)
|
|
||||||
// we expect based on the component type of the parameter specification
|
|
||||||
if ( ! parameter.getParameterType().getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s]",
|
|
||||||
value.getClass().getComponentType().getName(),
|
|
||||||
parameter.getParameterType().getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we have an object array. Here we loop over the array and physically check each element against
|
|
||||||
// the type we expect based on the component type of the parameter specification
|
|
||||||
final Object[] array = (Object[]) value;
|
|
||||||
for ( Object element : array ) {
|
|
||||||
if ( ! parameter.getParameterType().getComponentType().isInstance( element ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Array-valued parameter value element [%s] did not match expected type [%s]",
|
|
||||||
element,
|
|
||||||
parameter.getParameterType().getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBound(Parameter<?> param) {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
public AbstractQueryImpl<X> setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||||
return parameterBindings != null && parameterBindings.containsKey( param );
|
return (AbstractQueryImpl<X>) super.setParameter( param, value, temporalType );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getParameterValue(Parameter<T> param) {
|
public AbstractQueryImpl<X> setParameter(String name, Object value) {
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
return (AbstractQueryImpl<X>) super.setParameter( name, value );
|
||||||
if ( parameterBindings == null ) {
|
|
||||||
throw new IllegalStateException( "No parameters have been bound" );
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
T value = (T) parameterBindings.get( param );
|
|
||||||
if ( value == null ) {
|
|
||||||
throw new IllegalStateException( "Parameter has not been bound" );
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
catch ( ClassCastException cce ) {
|
|
||||||
throw new IllegalStateException( "Encountered a parameter value type exception" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParameterValue(String name) {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
public AbstractQueryImpl<X> setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||||
return getParameterValue( getParameter( name ) );
|
return (AbstractQueryImpl<X>) super.setParameter( name, value, temporalType );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParameterValue(int position) {
|
@SuppressWarnings("unchecked")
|
||||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
public AbstractQueryImpl<X> setParameter(String name, Date value, TemporalType temporalType) {
|
||||||
return getParameterValue( getParameter( position ) );
|
return (AbstractQueryImpl<X>) super.setParameter( name, value, temporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public AbstractQueryImpl<X> setParameter(int position, Object value) {
|
||||||
|
return (AbstractQueryImpl<X>) super.setParameter( position, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public AbstractQueryImpl<X> setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||||
|
return (AbstractQueryImpl<X>) super.setParameter( position, value, temporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public AbstractQueryImpl<X> setParameter(int position, Date value, TemporalType temporalType) {
|
||||||
|
return (AbstractQueryImpl<X>) super.setParameter( position, value, temporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public AbstractQueryImpl<X> setFlushMode(FlushModeType jpaFlushMode) {
|
||||||
|
return (AbstractQueryImpl<X>) super.setFlushMode( jpaFlushMode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,14 @@ import javax.persistence.CacheRetrieveMode;
|
||||||
import javax.persistence.CacheStoreMode;
|
import javax.persistence.CacheStoreMode;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -40,7 +42,9 @@ import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.QueryParameterException;
|
||||||
import org.hibernate.jpa.AvailableSettings;
|
import org.hibernate.jpa.AvailableSettings;
|
||||||
import org.hibernate.jpa.QueryHints;
|
import org.hibernate.jpa.QueryHints;
|
||||||
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
|
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
|
||||||
|
@ -59,9 +63,9 @@ import static org.hibernate.jpa.QueryHints.HINT_TIMEOUT;
|
||||||
import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
|
import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intended as the base class for all {@link javax.persistence.Query} implementations, including {@link javax.persistence.TypedQuery} and
|
* Intended as the base class for all {@link javax.persistence.Query} implementations, including
|
||||||
* {@link javax.persistence.StoredProcedureQuery}. Care should be taken that all changes here fit with all
|
* {@link javax.persistence.TypedQuery} and {@link javax.persistence.StoredProcedureQuery}. Care should be taken
|
||||||
* those usages.
|
* that all changes here fit with all those usages.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -86,6 +90,10 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
return entityManager;
|
return entityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkOpen(boolean markForRollbackIfClosed) {
|
||||||
|
entityManager.checkOpen( markForRollbackIfClosed );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Limits (first and max results) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// Limits (first and max results) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -98,7 +106,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setFirstResult(int firstResult) {
|
public BaseQueryImpl setFirstResult(int firstResult) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
|
|
||||||
if ( firstResult < 0 ) {
|
if ( firstResult < 0 ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -112,7 +120,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFirstResult() {
|
public int getFirstResult() {
|
||||||
entityManager().checkOpen( false ); // technically should rollback
|
checkOpen( false ); // technically should rollback
|
||||||
return firstResult;
|
return firstResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +133,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setMaxResults(int maxResult) {
|
public BaseQueryImpl setMaxResults(int maxResult) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
if ( maxResult < 0 ) {
|
if ( maxResult < 0 ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Negative value (" + maxResult + ") passed to setMaxResults"
|
"Negative value (" + maxResult + ") passed to setMaxResults"
|
||||||
|
@ -142,7 +150,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxResults() {
|
public int getMaxResults() {
|
||||||
entityManager().checkOpen( false ); // technically should rollback
|
checkOpen( false ); // technically should rollback
|
||||||
return maxResults == -1
|
return maxResults == -1
|
||||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
||||||
: maxResults;
|
: maxResults;
|
||||||
|
@ -158,7 +166,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getHints() {
|
public Map<String, Object> getHints() {
|
||||||
entityManager().checkOpen( false ); // technically should rollback
|
checkOpen( false ); // technically should rollback
|
||||||
return hints;
|
return hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +204,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
*
|
*
|
||||||
* @return {@code true} if the hint was "applied"
|
* @return {@code true} if the hint was "applied"
|
||||||
*/
|
*/
|
||||||
protected abstract boolean applyFetchSize(int fetchSize);
|
protected abstract boolean applyFetchSizeHint(int fetchSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the cacheable (true/false) hint.
|
* Apply the cacheable (true/false) hint.
|
||||||
|
@ -248,11 +256,11 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
*
|
*
|
||||||
* @return {@code true} indicates they can be applied, {@code false} otherwise.
|
* @return {@code true} indicates they can be applied, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
protected abstract boolean canApplyLockModesHints();
|
protected abstract boolean canApplyAliasSpecificLockModeHints();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the alias specific lock modes. Assumes {@link #canApplyLockModesHints()} has already been called and
|
* Apply the alias specific lock modes. Assumes {@link #canApplyAliasSpecificLockModeHints()} has already been
|
||||||
* returned {@code true}.
|
* called and returned {@code true}.
|
||||||
*
|
*
|
||||||
* @param alias The alias to apply the 'lockMode' to.
|
* @param alias The alias to apply the 'lockMode' to.
|
||||||
* @param lockMode The LockMode to apply.
|
* @param lockMode The LockMode to apply.
|
||||||
|
@ -262,7 +270,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( {"deprecation"})
|
@SuppressWarnings( {"deprecation"})
|
||||||
public BaseQueryImpl setHint(String hintName, Object value) {
|
public BaseQueryImpl setHint(String hintName, Object value) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
boolean applied = false;
|
boolean applied = false;
|
||||||
try {
|
try {
|
||||||
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
||||||
|
@ -280,7 +288,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
applied = applyCommentHint( (String) value );
|
applied = applyCommentHint( (String) value );
|
||||||
}
|
}
|
||||||
else if ( HINT_FETCH_SIZE.equals( hintName ) ) {
|
else if ( HINT_FETCH_SIZE.equals( hintName ) ) {
|
||||||
applied = applyFetchSize( ConfigurationHelper.getInteger( value ) );
|
applied = applyFetchSizeHint( ConfigurationHelper.getInteger( value ) );
|
||||||
}
|
}
|
||||||
else if ( HINT_CACHEABLE.equals( hintName ) ) {
|
else if ( HINT_CACHEABLE.equals( hintName ) ) {
|
||||||
applied = applyCacheableHint( ConfigurationHelper.getBoolean( value ) );
|
applied = applyCacheableHint( ConfigurationHelper.getBoolean( value ) );
|
||||||
|
@ -322,7 +330,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ( hintName.startsWith( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE ) ) {
|
else if ( hintName.startsWith( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE ) ) {
|
||||||
if ( canApplyLockModesHints() ) {
|
if ( canApplyAliasSpecificLockModeHints() ) {
|
||||||
// extract the alias
|
// extract the alias
|
||||||
final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
|
final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
|
||||||
// determine the LockMode
|
// determine the LockMode
|
||||||
|
@ -367,7 +375,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
public BaseQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
this.jpaFlushMode = jpaFlushMode;
|
this.jpaFlushMode = jpaFlushMode;
|
||||||
// TODO : treat as hint?
|
// TODO : treat as hint?
|
||||||
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
||||||
|
@ -386,7 +394,7 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlushModeType getFlushMode() {
|
public FlushModeType getFlushMode() {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return jpaFlushMode != null
|
return jpaFlushMode != null
|
||||||
? jpaFlushMode
|
? jpaFlushMode
|
||||||
: entityManager.getFlushMode();
|
: entityManager.getFlushMode();
|
||||||
|
@ -395,27 +403,78 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
// Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
private List<ParameterImplementor> parameters;
|
private Set<ParameterRegistration<?>> parameterRegistrations;
|
||||||
|
|
||||||
|
protected <X> ParameterRegistration<X> findParameterRegistration(Parameter<X> parameter) {
|
||||||
|
if ( ParameterRegistration.class.isInstance( parameter ) ) {
|
||||||
|
return (ParameterRegistration<X>) parameter;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( parameter.getName() != null ) {
|
||||||
|
return findParameterRegistration( parameter.getName() );
|
||||||
|
}
|
||||||
|
else if ( parameter.getPosition() != null ) {
|
||||||
|
return findParameterRegistration( parameter.getPosition() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "Unable to resolve incoming parameter [" + parameter + "] to registration" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <X> ParameterRegistration<X> findParameterRegistration(String parameterName) {
|
||||||
|
return (ParameterRegistration<X>) getParameter( parameterName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <X> ParameterRegistration<X> findParameterRegistration(int parameterPosition) {
|
||||||
|
if ( isJpaPositionalParameter( parameterPosition ) ) {
|
||||||
|
return findParameterRegistration( Integer.toString( parameterPosition ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (ParameterRegistration<X>) getParameter( parameterPosition );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean isJpaPositionalParameter(int position);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract.
|
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract.
|
||||||
*/
|
*/
|
||||||
protected static interface ParameterImplementor<T> extends Parameter<T> {
|
protected static interface ParameterRegistration<T> extends Parameter<T> {
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
* @return The parameter mode.
|
||||||
|
*/
|
||||||
|
public ParameterMode getMode();
|
||||||
|
|
||||||
public boolean isBindable();
|
public boolean isBindable();
|
||||||
|
|
||||||
public ParameterValue getBoundValue();
|
public void bindValue(T value);
|
||||||
|
|
||||||
|
public void bindValue(T value, TemporalType specifiedTemporalType);
|
||||||
|
|
||||||
|
public ParameterBind<T> getBind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ParameterValue {
|
protected static interface ParameterBind<T> {
|
||||||
private final Object value;
|
public T getValue();
|
||||||
|
|
||||||
|
public TemporalType getSpecifiedTemporalType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class ParameterBindImpl<T> implements ParameterBind<T> {
|
||||||
|
private final T value;
|
||||||
private final TemporalType specifiedTemporalType;
|
private final TemporalType specifiedTemporalType;
|
||||||
|
|
||||||
public ParameterValue(Object value, TemporalType specifiedTemporalType) {
|
public ParameterBindImpl(T value, TemporalType specifiedTemporalType) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.specifiedTemporalType = specifiedTemporalType;
|
this.specifiedTemporalType = specifiedTemporalType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getValue() {
|
public T getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,142 +483,193 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ParameterImplementor<?>,ParameterValue> parameterBindingMap;
|
private Set<ParameterRegistration<?>> parameterRegistrations() {
|
||||||
|
if ( parameterRegistrations == null ) {
|
||||||
private Map<ParameterImplementor<?>,ParameterValue> parameterBindingMap() {
|
// todo : could se use an identity set here?
|
||||||
if ( parameterBindingMap == null ) {
|
parameterRegistrations = new HashSet<ParameterRegistration<?>>();
|
||||||
parameterBindingMap = new HashMap<ParameterImplementor<?>, ParameterValue>();
|
|
||||||
}
|
}
|
||||||
return parameterBindingMap;
|
return parameterRegistrations;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerParameter(ParameterImplementor parameter) {
|
protected void registerParameter(ParameterRegistration parameter) {
|
||||||
if ( parameter == null ) {
|
if ( parameter == null ) {
|
||||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( parameterBindingMap().containsKey( parameter ) ) {
|
if ( parameterRegistrations().contains( parameter ) ) {
|
||||||
|
LOG.debug( "Parameter registered multiple times : " + parameter );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterBindingMap().put( parameter, null );
|
parameterRegistrations().add( parameter );
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void registerParameterBinding(Parameter parameter, ParameterValue bindValue) {
|
|
||||||
validateParameterBinding( (ParameterImplementor) parameter, bindValue );
|
|
||||||
parameterBindingMap().put( (ParameterImplementor) parameter, bindValue );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void validateParameterBinding(ParameterImplementor parameter, ParameterValue bindValue) {
|
|
||||||
if ( parameter == null ) {
|
|
||||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! parameter.isBindable() ) {
|
|
||||||
throw new IllegalArgumentException( "Parameter [" + parameter + "] not valid for binding" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! parameterBindingMap().containsKey( parameter ) ) {
|
|
||||||
throw new IllegalArgumentException( "Unknown parameter [" + parameter + "] specified for value binding" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isBound( parameter ) ) {
|
|
||||||
throw new IllegalArgumentException( "Parameter [" + parameter + "] already had bound value" );
|
|
||||||
}
|
|
||||||
|
|
||||||
validateParameterBindingTypes( parameter, bindValue );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void validateParameterBindingTypes(ParameterImplementor parameter, ParameterValue bindValue);
|
|
||||||
|
|
||||||
protected ParameterValue makeBindValue(Object value) {
|
|
||||||
return new ParameterValue( value, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ParameterValue makeBindValue(Calendar value, TemporalType temporalType) {
|
|
||||||
return new ParameterValue( value, temporalType );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ParameterValue makeBindValue(Date value, TemporalType temporalType) {
|
|
||||||
return new ParameterValue( value, temporalType );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> BaseQueryImpl setParameter(Parameter<T> param, T value) {
|
public <T> BaseQueryImpl setParameter(Parameter<T> param, T value) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( param, makeBindValue( value ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( param ).bindValue( value );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( param ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( param ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public BaseQueryImpl setParameter(String name, Object value) {
|
public BaseQueryImpl setParameter(String name, Object value) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( name ), makeBindValue( value ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( name ).bindValue( value );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(String name, Calendar value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( name ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(String name, Date value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(String name, Date value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( name ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(int position, Object value) {
|
public BaseQueryImpl setParameter(int position, Object value) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( position ), makeBindValue( value ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( position ).bindValue( value );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(int position, Calendar value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( position ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseQueryImpl setParameter(int position, Date value, TemporalType temporalType) {
|
public BaseQueryImpl setParameter(int position, Date value, TemporalType temporalType) {
|
||||||
entityManager().checkOpen( true );
|
checkOpen( true );
|
||||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
|
||||||
|
try {
|
||||||
|
findParameterRegistration( position ).bindValue( value, temporalType );
|
||||||
|
}
|
||||||
|
catch (QueryParameterException e) {
|
||||||
|
throw new IllegalArgumentException( e );
|
||||||
|
}
|
||||||
|
catch (HibernateException he) {
|
||||||
|
throw entityManager.convert( he );
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Set getParameters() {
|
public Set getParameters() {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return parameterBindingMap().keySet();
|
return parameterRegistrations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter<?> getParameter(String name) {
|
public Parameter<?> getParameter(String name) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
if ( parameterBindingMap() != null ) {
|
if ( parameterRegistrations != null ) {
|
||||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
for ( ParameterRegistration<?> param : parameterRegistrations ) {
|
||||||
if ( name.equals( param.getName() ) ) {
|
if ( name.equals( param.getName() ) ) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
@ -571,15 +681,36 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return (Parameter<T>) getParameter( name );
|
Parameter param = getParameter( name );
|
||||||
|
|
||||||
|
if ( param.getParameterType() != null ) {
|
||||||
|
// we were able to determine the expected type during analysis, so validate it here
|
||||||
|
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter named [%s]",
|
||||||
|
param.getParameterType().getName(),
|
||||||
|
type.getName(),
|
||||||
|
name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Parameter<T>) param;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter<?> getParameter(int position) {
|
public Parameter<?> getParameter(int position) {
|
||||||
entityManager().checkOpen( false );
|
if ( isJpaPositionalParameter( position ) ) {
|
||||||
if ( parameterBindingMap() != null ) {
|
return getParameter( Integer.toString( position ) );
|
||||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
}
|
||||||
|
checkOpen( false );
|
||||||
|
if ( parameterRegistrations != null ) {
|
||||||
|
for ( ParameterRegistration<?> param : parameterRegistrations ) {
|
||||||
|
if ( param.getPosition() == null ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if ( position == param.getPosition() ) {
|
if ( position == param.getPosition() ) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
@ -591,25 +722,46 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return (Parameter<T>) getParameter( position );
|
|
||||||
|
Parameter param = getParameter( position );
|
||||||
|
|
||||||
|
if ( param.getParameterType() != null ) {
|
||||||
|
// we were able to determine the expected type during analysis, so validate it here
|
||||||
|
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter at position [%s]",
|
||||||
|
param.getParameterType().getName(),
|
||||||
|
type.getName(),
|
||||||
|
position
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Parameter<T>) param;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBound(Parameter<?> param) {
|
public boolean isBound(Parameter<?> param) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return parameterBindingMap() != null
|
final ParameterRegistration registration = findParameterRegistration( param );
|
||||||
&& parameterBindingMap.get( (ParameterImplementor) param ) != null;
|
return registration != null && registration.isBindable() && registration.getBind() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getParameterValue(Parameter<T> param) {
|
public <T> T getParameterValue(Parameter<T> param) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
if ( parameterBindingMap != null ) {
|
|
||||||
final ParameterValue boundValue = parameterBindingMap.get( (ParameterImplementor) param );
|
final ParameterRegistration<T> registration = findParameterRegistration( param );
|
||||||
if ( boundValue != null ) {
|
if ( registration != null ) {
|
||||||
return (T) boundValue.getValue();
|
if ( ! registration.isBindable() ) {
|
||||||
|
throw new IllegalArgumentException( "Passed parameter [" + param + "] is not bindable" );
|
||||||
|
}
|
||||||
|
final ParameterBind<T> bind = registration.getBind();
|
||||||
|
if ( bind != null ) {
|
||||||
|
return bind.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException( "Parameter [" + param + "] has not yet been bound" );
|
throw new IllegalStateException( "Parameter [" + param + "] has not yet been bound" );
|
||||||
|
@ -617,13 +769,153 @@ public abstract class BaseQueryImpl implements Query {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParameterValue(String name) {
|
public Object getParameterValue(String name) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return getParameterValue( getParameter( name ) );
|
return getParameterValue( getParameter( name ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParameterValue(int position) {
|
public Object getParameterValue(int position) {
|
||||||
entityManager().checkOpen( false );
|
checkOpen( false );
|
||||||
return getParameterValue( getParameter( position ) );
|
return getParameterValue( getParameter( position ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static void validateBinding(Class parameterType, Object bind, TemporalType temporalType) {
|
||||||
|
if ( bind == null || parameterType == null ) {
|
||||||
|
// nothing we can check
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Collection.class.isInstance( bind ) && ! Collection.class.isAssignableFrom( parameterType ) ) {
|
||||||
|
// we have a collection passed in where we are expecting a non-collection.
|
||||||
|
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
|
||||||
|
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
||||||
|
// will fall through to the main check.
|
||||||
|
validateCollectionValuedParameterBinding( parameterType, (Collection) bind, temporalType );
|
||||||
|
}
|
||||||
|
else if ( bind.getClass().isArray() ) {
|
||||||
|
validateArrayValuedParameterBinding( parameterType, bind, temporalType );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( ! isValidBindValue( parameterType, bind, temporalType ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter value [%s] did not match expected type [%s (%s)]",
|
||||||
|
bind,
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extractName(TemporalType temporalType) {
|
||||||
|
return temporalType == null ? "n/a" : temporalType.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateCollectionValuedParameterBinding(
|
||||||
|
Class parameterType,
|
||||||
|
Collection value,
|
||||||
|
TemporalType temporalType) {
|
||||||
|
// validate the elements...
|
||||||
|
for ( Object element : value ) {
|
||||||
|
if ( ! isValidBindValue( parameterType, element, temporalType ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter value element [%s] did not match expected type [%s (%s)]",
|
||||||
|
element,
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateArrayValuedParameterBinding(
|
||||||
|
Class parameterType,
|
||||||
|
Object value,
|
||||||
|
TemporalType temporalType) {
|
||||||
|
if ( ! parameterType.isArray() ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value.getClass().getComponentType().isPrimitive() ) {
|
||||||
|
// we have a primitive array. we validate that the actual array has the component type (type of elements)
|
||||||
|
// we expect based on the component type of the parameter specification
|
||||||
|
if ( ! parameterType.getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s (%s)]",
|
||||||
|
value.getClass().getComponentType().getName(),
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have an object array. Here we loop over the array and physically check each element against
|
||||||
|
// the type we expect based on the component type of the parameter specification
|
||||||
|
final Object[] array = (Object[]) value;
|
||||||
|
for ( Object element : array ) {
|
||||||
|
if ( ! isValidBindValue( parameterType.getComponentType(), element, temporalType ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
|
||||||
|
element,
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
|
||||||
|
if ( expectedType.isInstance( value ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( temporalType != null ) {
|
||||||
|
final boolean parameterDeclarationIsTemporal = Date.class.isAssignableFrom( expectedType )
|
||||||
|
|| Calendar.class.isAssignableFrom( expectedType );
|
||||||
|
final boolean bindIsTemporal = Date.class.isInstance( value )
|
||||||
|
|| Calendar.class.isInstance( value );
|
||||||
|
|
||||||
|
if ( parameterDeclarationIsTemporal && bindIsTemporal ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,12 +423,11 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
em.flush();
|
em.flush();
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
Query query = em.createQuery( "select w from Wallet w where w.brand = ?1 and w.model = ?3" );
|
Query query = em.createQuery( "select w from Wallet w where w.brand = ?1 and w.model = ?3" );
|
||||||
query.setParameter( 1, "Lacoste" );
|
query.setParameter( 1, "Lacoste" );
|
||||||
|
try {
|
||||||
query.setParameter( 2, "Expensive" );
|
query.setParameter( 2, "Expensive" );
|
||||||
query.getResultList();
|
fail( "Should fail due to a user error in parameters" );
|
||||||
fail("The query should fail due to a user error in parameters");
|
|
||||||
}
|
}
|
||||||
catch ( IllegalArgumentException e ) {
|
catch ( IllegalArgumentException e ) {
|
||||||
//success
|
//success
|
||||||
|
|
Loading…
Reference in New Issue