All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.query.internal.QueryParameterBindingsImpl Maven / Gradle / Ivy
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.query.internal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.QueryException;
import org.hibernate.QueryParameterException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.hql.internal.classic.ParserHelper;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterListBinding;
import org.hibernate.type.SerializableType;
import org.hibernate.type.Type;
/**
* Manages the group of QueryParameterBinding for a particular query.
*
* @author Steve Ebersole
* @author Chris Cranford
*/
@Incubating
public class QueryParameterBindingsImpl implements QueryParameterBindings {
private static final CoreMessageLogger log = CoreLogging.messageLogger( QueryParameterBindingsImpl.class );
private final SessionFactoryImplementor sessionFactory;
private final ParameterMetadata parameterMetadata;
private final boolean queryParametersValidationEnabled;
private Map parameterBindingMap;
private Map parameterListBindingMap;
private Map positionalParameterBindings;
public static QueryParameterBindingsImpl from(
ParameterMetadata parameterMetadata,
SessionFactoryImplementor sessionFactory,
boolean queryParametersValidationEnabled) {
if ( parameterMetadata == null ) {
return new QueryParameterBindingsImpl(
sessionFactory,
parameterMetadata,
queryParametersValidationEnabled
);
}
else {
return new QueryParameterBindingsImpl(
sessionFactory,
parameterMetadata.collectAllParameters(),
parameterMetadata, queryParametersValidationEnabled
);
}
}
private QueryParameterBindingsImpl(
SessionFactoryImplementor sessionFactory,
ParameterMetadata parameterMetadata,
boolean queryParametersValidationEnabled) {
this( sessionFactory, Collections.emptySet(), parameterMetadata, queryParametersValidationEnabled );
}
private QueryParameterBindingsImpl(
SessionFactoryImplementor sessionFactory,
Set> queryParameters,
ParameterMetadata parameterMetadata,
boolean queryParametersValidationEnabled) {
this.sessionFactory = sessionFactory;
this.parameterMetadata = parameterMetadata;
this.queryParametersValidationEnabled = queryParametersValidationEnabled;
this.positionalParameterBindings = new TreeMap<>( );
if ( queryParameters == null || queryParameters.isEmpty() ) {
parameterBindingMap = Collections.emptyMap();
}
else {
parameterBindingMap = new HashMap<>();
for ( QueryParameter queryParameter : queryParameters ) {
if ( queryParameter.getPosition() == null ) {
// only cache the non-positional parameters in this map
// positional parameters will be bound dynamically with getBinding(int)
parameterBindingMap.put( queryParameter, makeBinding( queryParameter ) );
}
}
}
parameterListBindingMap = new HashMap<>();
}
protected QueryParameterBinding makeBinding(QueryParameter queryParameter) {
return makeBinding( queryParameter.getType() );
}
protected QueryParameterBinding makeBinding(Type bindType) {
return new QueryParameterBindingImpl( bindType, sessionFactory, shouldValidateBindingValue() );
}
public boolean isBound(QueryParameter parameter) {
final QueryParameterBinding binding = locateBinding( parameter );
if ( binding != null ) {
return binding.getBindValue() != null;
}
final QueryParameterListBinding listBinding = locateQueryParameterListBinding( parameter );
if ( listBinding != null ) {
return listBinding.getBindValues() != null;
}
return false;
}
@SuppressWarnings("unchecked")
public QueryParameterBinding getBinding(QueryParameter parameter) {
final QueryParameterBinding binding = locateBinding( parameter );
if ( binding == null ) {
throw new IllegalArgumentException(
"Could not resolve QueryParameter reference [" + parameter + "] to QueryParameterBinding"
);
}
return binding;
}
@SuppressWarnings("unchecked")
public QueryParameterBinding locateBinding(QueryParameter parameter) {
// see if this exact instance is known as a key
if ( parameterBindingMap.containsKey( parameter ) ) {
return parameterBindingMap.get( parameter );
}
// if the incoming parameter has a name, try to find it by name
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
final QueryParameterBinding binding = locateBinding( parameter.getName() );
if ( binding != null ) {
return binding;
}
}
// if the incoming parameter has a position, try to find it by position
if ( parameter.getPosition() != null ) {
final QueryParameterBinding binding = locateBinding( parameter.getPosition() );
if ( binding != null ) {
return binding;
}
}
return null;
}
protected QueryParameterBinding locateBinding(String name) {
for ( Map.Entry entry : parameterBindingMap.entrySet() ) {
if ( name.equals( entry.getKey().getName() ) ) {
return entry.getValue();
}
}
return null;
}
protected QueryParameterBinding locateAndRemoveBinding(String name) {
final Iterator> entryIterator = parameterBindingMap.entrySet().iterator();
while ( entryIterator.hasNext() ) {
final Map.Entry entry = entryIterator.next();
if ( name.equals( entry.getKey().getName() ) ) {
entryIterator.remove();
return entry.getValue();
}
}
return null;
}
protected QueryParameterBinding locateBinding(int position) {
if ( position < positionalParameterBindings.size() ) {
return positionalParameterBindings.get( position );
}
return null;
}
public QueryParameterBinding getBinding(String name) {
final QueryParameterBinding binding = locateBinding( name );
if ( binding == null ) {
throw new IllegalArgumentException( "Unknown parameter name : " + name );
}
return binding;
}
public QueryParameterBinding getBinding(int position) {
int positionAdjustment = 0;
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
positionAdjustment = -1;
}
QueryParameterBinding binding = null;
if ( parameterMetadata != null ) {
if ( !parameterMetadata.hasPositionalParameters() ) {
// no positional parameters, assume jpa named.
binding = locateBinding( Integer.toString( position ) );
}
else {
try {
binding = positionalParameterBindings.get( position + positionAdjustment );
if ( binding == null ) {
binding = makeBinding( parameterMetadata.getQueryParameter( position ) );
positionalParameterBindings.put( position + positionAdjustment, binding );
}
}
catch (QueryParameterException e) {
// treat this as null binding
}
}
}
if ( binding == null ) {
throw new IllegalArgumentException( "Unknown parameter position: " + position );
}
return binding;
}
public void verifyParametersBound(boolean reserveFirstParameter) {
// verify named parameters bound
for ( Map.Entry bindEntry : parameterBindingMap.entrySet() ) {
if ( !bindEntry.getValue().isBound() ) {
if ( bindEntry.getKey().getName() != null ) {
throw new QueryException( "Named parameter [" + bindEntry.getKey().getName() + "] not set" );
}
else {
throw new QueryException( "Parameter memento [" + bindEntry.getKey() + "] not set" );
}
}
}
// verify position parameters bound
int startIndex = 0;
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
startIndex = 1;
}
for ( int i = startIndex; i < positionalParameterBindings.size(); i++ ) {
QueryParameterBinding binding = null;
if ( parameterMetadata.isOrdinalParametersZeroBased() ) {
binding = positionalParameterBindings.get( i );
}
else {
binding = positionalParameterBindings.get( i - 1 );
}
if ( binding == null || !binding.isBound() ) {
throw new QueryException( "Positional parameter [" + i + "] not set" );
}
}
// verify position parameter count is correct
final int positionalValueSpan = calculatePositionalValueSpan( reserveFirstParameter );
final int positionCounts = parameterMetadata.getPositionalParameterCount();
if ( positionCounts != positionalValueSpan ) {
if ( reserveFirstParameter && positionCounts - 1 != positionalValueSpan ) {
throw new QueryException(
"Expected positional parameter count: " +
( positionCounts - 1 ) +
", actually detected " + positionalValueSpan
);
}
else if ( !reserveFirstParameter ) {
throw new QueryException(
"Expected positional parameter count: " +
( positionCounts ) +
", actually detected " + positionalValueSpan
);
}
}
}
private int calculatePositionalValueSpan(boolean reserveFirstParameter) {
int positionalValueSpan = 0;
for ( QueryParameterBinding binding : positionalParameterBindings.values() ) {
if ( binding.isBound() ) {
Type bindType = binding.getBindType();
if ( bindType == null ) {
bindType = SerializableType.INSTANCE;
}
positionalValueSpan += bindType.getColumnSpan( sessionFactory );
}
}
return positionalValueSpan;
}
/**
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
*/
@Deprecated
public Collection collectBindTypes() {
return parameterBindingMap.values()
.stream()
.map( QueryParameterBinding::getBindType )
.collect( Collectors.toList() );
}
/**
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
*/
@Deprecated
public Collection collectBindValues() {
return parameterBindingMap.values()
.stream()
.map( QueryParameterBinding::getBindValue )
.collect( Collectors.toList() );
}
/**
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
*/
@Deprecated
public Type[] collectPositionalBindTypes() {
Type[] types = new Type[ positionalParameterBindings.size() ];
// NOTE : bindings should be ordered by position by nature of a TreeMap...
// NOTE : we also assume the contiguity of the positions
for ( Map.Entry entry : positionalParameterBindings.entrySet() ) {
final int position = entry.getKey();
Type type = entry.getValue().getBindType();
if ( type == null ) {
log.debugf( "Binding for positional-parameter [%s] did not define type, using SerializableType", position );
type = SerializableType.INSTANCE;
}
types[ position ] = type;
}
return types;
}
/**
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
*/
@Deprecated
public Object[] collectPositionalBindValues() {
Object[] values = new Object[ positionalParameterBindings.size() ];
// NOTE : bindings should be ordered by position by nature of a TreeMap...
// NOTE : we also assume the contiguity of the positions
for ( Map.Entry entry : positionalParameterBindings.entrySet() ) {
final int position = entry.getKey();
values[ position ] = entry.getValue().getBindValue();
}
return values;
}
/**
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
*/
@Deprecated
public Map collectNamedParameterBindings() {
Map collectedBindings = new HashMap<>();
for ( Map.Entry entry : parameterBindingMap.entrySet() ) {
if ( entry.getKey().getName() == null ) {
continue;
}
Type bindType = entry.getValue().getBindType();
if ( bindType == null ) {
log.debugf( "Binding for named-parameter [%s] did not define type", entry.getKey().getName() );
bindType = SerializableType.INSTANCE;
}
collectedBindings.put(
entry.getKey().getName(),
new TypedValue( bindType, entry.getValue().getBindValue() )
);
}
return collectedBindings;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parameter list binding - expect changes in 6.0
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
@SuppressWarnings("unchecked")
public QueryParameterListBinding getQueryParameterListBinding(QueryParameter queryParameter) {
QueryParameterListBinding result = parameterListBindingMap.get( queryParameter );
if ( result == null ) {
result = transformQueryParameterBindingToQueryParameterListBinding( queryParameter );
}
return result;
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
private QueryParameterListBinding locateQueryParameterListBinding(QueryParameter queryParameter) {
QueryParameterListBinding result = parameterListBindingMap.get( queryParameter );
if ( result == null && queryParameter.getName() != null ) {
for ( Map.Entry entry : parameterListBindingMap.entrySet() ) {
if ( queryParameter.getName().equals( entry.getKey().getName() ) ) {
result = entry.getValue();
break;
}
}
}
return result;
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
private QueryParameterListBinding transformQueryParameterBindingToQueryParameterListBinding(QueryParameter queryParameter) {
log.debugf( "Converting QueryParameterBinding to QueryParameterListBinding for given QueryParameter : %s", queryParameter );
final QueryParameterBinding binding = getAndRemoveBinding( queryParameter );
if ( binding == null ) {
throw new IllegalArgumentException(
"Could not locate QueryParameterBinding for given QueryParameter : " + queryParameter +
"; parameter list must be defined using named parameter"
);
}
final QueryParameterListBinding convertedBinding = new QueryParameterListBindingImpl<>(
binding.getBindType(),
shouldValidateBindingValue()
);
parameterListBindingMap.put( queryParameter, convertedBinding );
return convertedBinding;
}
private boolean shouldValidateBindingValue() {
return sessionFactory.getSessionFactoryOptions().isJpaBootstrap() && queryParametersValidationEnabled;
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
@SuppressWarnings("unchecked")
private QueryParameterBinding getAndRemoveBinding(QueryParameter parameter) {
// see if this exact instance is known as a key
if ( parameterBindingMap.containsKey( parameter ) ) {
return parameterBindingMap.remove( parameter );
}
// if the incoming parameter has a name, try to find it by name
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
final QueryParameterBinding binding = locateAndRemoveBinding( parameter.getName() );
if ( binding != null ) {
return binding;
}
}
// NOTE : getAndRemoveBinding is only intended for usage from #transformQueryParameterBindingToQueryParameterListBinding
// which only supports named parameters, so there is no need to look into legacy positional parameters
throw new IllegalArgumentException(
"Could not resolve QueryParameter reference [" + parameter + "] to QueryParameterBinding"
);
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
@SuppressWarnings("unchecked")
public QueryParameterListBinding getQueryParameterListBinding(String name) {
// find the QueryParameter instance for the given name
final QueryParameter queryParameter = resolveQueryParameter( name );
return getQueryParameterListBinding( queryParameter );
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
@SuppressWarnings("unchecked")
private QueryParameter resolveQueryParameter(String name) {
for ( QueryParameter queryParameter : parameterListBindingMap.keySet() ) {
if ( name.equals( queryParameter.getName() ) ) {
return queryParameter;
}
}
for ( QueryParameter queryParameter : parameterBindingMap.keySet() ) {
if ( name.equals( queryParameter.getName() ) ) {
return queryParameter;
}
}
throw new IllegalArgumentException(
"Unable to resolve given parameter name [" + name + "] to QueryParameter reference"
);
}
/**
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
*/
@Deprecated
@SuppressWarnings("unchecked")
public String expandListValuedParameters(String queryString, SharedSessionContractImplementor session) {
if ( queryString == null ) {
return null;
}
// more-or-less... for each entry in parameterListBindingMap we will create an
// entry in parameterBindingMap for each of the values in the bound value list. afterwards
// we will clear the parameterListBindingMap.
//
// NOTE that this is essentially the legacy logical prior to modeling QueryParameterBinding/QueryParameterListBinding.
// Fully expect the details of how this is handled in 6.0
// HHH-1123
// Some DBs limit number of IN expressions. For now, warn...
final Dialect dialect = session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getJdbcEnvironment().getDialect();
final int inExprLimit = dialect.getInExpressionCountLimit();
for ( Map.Entry entry : parameterListBindingMap.entrySet() ) {
final NamedParameterDescriptor sourceParam = (NamedParameterDescriptor) entry.getKey();
final Collection bindValues = entry.getValue().getBindValues();
if ( inExprLimit > 0 && bindValues.size() > inExprLimit ) {
log.tooManyInExpressions( dialect.getClass().getName(), inExprLimit, sourceParam.getName(), bindValues.size() );
}
final boolean isJpaPositionalParam = sourceParam.isJpaPositionalParameter();
final String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
final String placeholder = paramPrefix + sourceParam.getName();
final int loc = queryString.indexOf( placeholder );
if ( loc < 0 ) {
continue;
}
final String beforePlaceholder = queryString.substring( 0, loc );
final String afterPlaceholder = queryString.substring( loc + placeholder.length() );
// check if placeholder is already immediately enclosed in parentheses
// (ignoring whitespace)
boolean isEnclosedInParens =
StringHelper.getLastNonWhitespaceCharacter( beforePlaceholder ) == '(' &&
StringHelper.getFirstNonWhitespaceCharacter( afterPlaceholder ) == ')';
if ( bindValues.size() == 1 && isEnclosedInParens ) {
// short-circuit for performance when only 1 value and the
// placeholder is already enclosed in parentheses...
final QueryParameterBinding syntheticBinding = makeBinding( entry.getValue().getBindType() );
syntheticBinding.setBindValue( bindValues.iterator().next() );
parameterBindingMap.put( sourceParam, syntheticBinding );
continue;
}
StringBuilder expansionList = new StringBuilder();
int i = 0;
for ( Object bindValue : entry.getValue().getBindValues() ) {
// for each value in the bound list-of-values we:
// 1) create a synthetic named parameter
// 2) expand the queryString to include each synthetic named param in place of the original
// 3) create a new synthetic binding for just that single value under the synthetic name
final String syntheticName = ( isJpaPositionalParam ? 'x' : "" ) + sourceParam.getName() + '_' + i;
if ( i > 0 ) {
expansionList.append( ", " );
}
expansionList.append( ParserHelper.HQL_VARIABLE_PREFIX ).append( syntheticName );
final QueryParameter syntheticParam = new QueryParameterNamedImpl<>(
syntheticName,
sourceParam.getSourceLocations(),
sourceParam.isJpaPositionalParameter(),
sourceParam.getType()
);
final QueryParameterBinding syntheticBinding = makeBinding( entry.getValue().getBindType() );
syntheticBinding.setBindValue( bindValue );
parameterBindingMap.put( syntheticParam, syntheticBinding );
i++;
}
queryString = StringHelper.replace(
beforePlaceholder,
afterPlaceholder,
placeholder,
expansionList.toString(),
true,
true
);
}
return queryString;
}
}