package org.hibernate.engine.spi;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.hql.internal.classic.ParserHelper;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.FilterImpl;
import org.hibernate.internal.util.EntityPrinter;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.query.internal.QueryParameterBindingsImpl;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
public final class QueryParameters {
private static final Logger LOG = CoreLogging.logger( QueryParameters.class );
private static final String SYMBOLS = ParserHelper.HQL_SEPARATORS.replace( "'", "" );
private Type[] positionalParameterTypes;
private Object[] positionalParameterValues;
private Map<String,TypedValue> namedParameters;
private LockOptions lockOptions;
private RowSelection rowSelection;
private boolean cacheable;
private String cacheRegion;
private String ;
private List<String> queryHints;
private ScrollMode scrollMode;
private Serializable[] collectionKeys;
private Object optionalObject;
private String optionalEntityName;
private Serializable optionalId;
private boolean isReadOnlyInitialized;
private boolean readOnly;
private boolean callable;
private boolean autodiscovertypes;
private boolean isNaturalKeyLookup;
private boolean passDistinctThrough = true;
private final ResultTransformer resultTransformer;
private String processedSQL;
private Type[] processedPositionalParameterTypes;
private Object[] processedPositionalParameterValues;
private HQLQueryPlan queryPlan;
public QueryParameters() {
this( ArrayHelper.EMPTY_TYPE_ARRAY, ArrayHelper.EMPTY_OBJECT_ARRAY );
}
public QueryParameters(Type type, Object value) {
this( new Type[] { type }, new Object[] { value } );
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalObjectId) {
this( positionalParameterTypes, positionalParameterValues );
this.optionalObject = optionalObject;
this.optionalId = optionalObjectId;
this.optionalEntityName = optionalEntityName;
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues) {
this( positionalParameterTypes, positionalParameterValues, null, null, false, false, false, null, null, null, false, null );
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final Serializable[] collectionKeys) {
this( positionalParameterTypes, positionalParameterValues, null, collectionKeys );
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final Map<String,TypedValue> namedParameters,
final Serializable[] collectionKeys) {
this(
positionalParameterTypes,
positionalParameterValues,
namedParameters,
null,
null,
false,
false,
false,
null,
null,
null,
collectionKeys,
null
);
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final LockOptions lockOptions,
final RowSelection rowSelection,
final boolean isReadOnlyInitialized,
final boolean readOnly,
final boolean cacheable,
final String cacheRegion,
final String comment,
final List<String> queryHints,
final boolean isLookupByNaturalKey,
final ResultTransformer transformer) {
this(
positionalParameterTypes,
positionalParameterValues,
null,
lockOptions,
rowSelection,
isReadOnlyInitialized,
readOnly,
cacheable,
cacheRegion,
comment,
queryHints,
null,
transformer
);
isNaturalKeyLookup = isLookupByNaturalKey;
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final Map<String,TypedValue> namedParameters,
final LockOptions lockOptions,
final RowSelection rowSelection,
final boolean isReadOnlyInitialized,
final boolean readOnly,
final boolean cacheable,
final String cacheRegion,
final String comment,
final List<String> queryHints,
final Serializable[] collectionKeys,
ResultTransformer transformer) {
this.positionalParameterTypes = positionalParameterTypes;
this.positionalParameterValues = positionalParameterValues;
this.namedParameters = namedParameters;
this.lockOptions = lockOptions;
this.rowSelection = rowSelection;
this.cacheable = cacheable;
this.cacheRegion = cacheRegion;
this.comment = comment;
this.queryHints = queryHints;
this.collectionKeys = collectionKeys;
this.isReadOnlyInitialized = isReadOnlyInitialized;
this.readOnly = readOnly;
this.resultTransformer = transformer;
}
public QueryParameters(
final Type[] positionalParameterTypes,
final Object[] positionalParameterValues,
final Map<String,TypedValue> namedParameters,
final LockOptions lockOptions,
final RowSelection rowSelection,
final boolean isReadOnlyInitialized,
final boolean readOnly,
final boolean cacheable,
final String cacheRegion,
final String comment,
final List<String> queryHints,
final Serializable[] collectionKeys,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalId,
final ResultTransformer transformer) {
this(
positionalParameterTypes,
positionalParameterValues,
namedParameters,
lockOptions,
rowSelection,
isReadOnlyInitialized,
readOnly,
cacheable,
cacheRegion,
comment,
queryHints,
collectionKeys,
transformer
);
this.optionalEntityName = optionalEntityName;
this.optionalId = optionalId;
this.optionalObject = optionalObject;
}
public QueryParameters(
QueryParameterBindings queryParameterBindings,
LockOptions lockOptions,
RowSelection selection,
final boolean isReadOnlyInitialized,
boolean readOnly,
boolean cacheable,
String cacheRegion,
String comment,
List<String> dbHints,
final Serializable[] collectionKeys,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalId,
ResultTransformer resultTransformer) {
this(
queryParameterBindings.collectPositionalBindTypes(),
queryParameterBindings.collectPositionalBindValues(),
queryParameterBindings.collectNamedParameterBindings(),
lockOptions,
selection,
isReadOnlyInitialized,
readOnly,
cacheable,
cacheRegion,
comment,
dbHints,
collectionKeys,
optionalObject,
optionalEntityName,
optionalId,
resultTransformer
);
}
@SuppressWarnings( {"UnusedDeclaration"})
public boolean hasRowSelection() {
return rowSelection != null;
}
public Map<String,TypedValue> getNamedParameters() {
return namedParameters;
}
public Type[] getPositionalParameterTypes() {
return positionalParameterTypes;
}
public Object[] getPositionalParameterValues() {
return positionalParameterValues;
}
public RowSelection getRowSelection() {
return rowSelection;
}
public ResultTransformer getResultTransformer() {
return resultTransformer;
}
@SuppressWarnings( {"UnusedDeclaration"})
public void setNamedParameters(Map<String,TypedValue> map) {
namedParameters = map;
}
public void setPositionalParameterTypes(Type[] types) {
positionalParameterTypes = types;
}
public void setPositionalParameterValues(Object[] objects) {
positionalParameterValues = objects;
}
@SuppressWarnings( {"UnusedDeclaration"})
public void setRowSelection(RowSelection selection) {
rowSelection = selection;
}
public LockOptions getLockOptions() {
return lockOptions;
}
public void setLockOptions(LockOptions lockOptions) {
this.lockOptions = lockOptions;
}
public void traceParameters(SessionFactoryImplementor factory) throws HibernateException {
EntityPrinter print = new EntityPrinter( factory );
if ( positionalParameterValues.length != 0 ) {
LOG.tracev( "Parameters: {0}", print.toString( positionalParameterTypes, positionalParameterValues ) );
}
if ( namedParameters != null ) {
LOG.tracev( "Named parameters: {0}", print.toString( namedParameters ) );
}
}
public boolean isCacheable() {
return cacheable;
}
public void setCacheable(boolean b) {
cacheable = b;
}
public String getCacheRegion() {
return cacheRegion;
}
public void setCacheRegion(String cacheRegion) {
this.cacheRegion = cacheRegion;
}
public void validateParameters() throws QueryException {
final int types = positionalParameterTypes == null ? 0 : positionalParameterTypes.length;
final int values = positionalParameterValues == null ? 0 : positionalParameterValues.length;
if ( types != values ) {
throw new QueryException(
"Number of positional parameter types:" + types +
" does not match number of positional parameters: " + values
);
}
}
public String () {
return comment;
}
public void (String comment) {
this.comment = comment;
}
public List<String> getQueryHints() {
return queryHints;
}
public void setQueryHints(List<String> queryHints) {
this.queryHints = queryHints;
}
public ScrollMode getScrollMode() {
return scrollMode;
}
public void setScrollMode(ScrollMode scrollMode) {
this.scrollMode = scrollMode;
}
public Serializable[] getCollectionKeys() {
return collectionKeys;
}
@SuppressWarnings( {"UnusedDeclaration"})
public void setCollectionKeys(Serializable[] collectionKeys) {
this.collectionKeys = collectionKeys;
}
public String getOptionalEntityName() {
return optionalEntityName;
}
public void setOptionalEntityName(String optionalEntityName) {
this.optionalEntityName = optionalEntityName;
}
public Serializable getOptionalId() {
return optionalId;
}
public void setOptionalId(Serializable optionalId) {
this.optionalId = optionalId;
}
public Object getOptionalObject() {
return optionalObject;
}
public void setOptionalObject(Object optionalObject) {
this.optionalObject = optionalObject;
}
public boolean isReadOnlyInitialized() {
return isReadOnlyInitialized;
}
public boolean isReadOnly() {
if ( !isReadOnlyInitialized() ) {
throw new IllegalStateException( "cannot call isReadOnly() when isReadOnlyInitialized() returns false" );
}
return readOnly;
}
public boolean isReadOnly(SharedSessionContractImplementor session) {
return isReadOnlyInitialized
? isReadOnly()
: session.getPersistenceContext().isDefaultReadOnly();
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
this.isReadOnlyInitialized = true;
}
public void setCallable(boolean callable) {
this.callable = callable;
}
public boolean isCallable() {
return callable;
}
public boolean hasAutoDiscoverScalarTypes() {
return autodiscovertypes;
}
public boolean isPassDistinctThrough() {
return passDistinctThrough;
}
public void setPassDistinctThrough(boolean passDistinctThrough) {
this.passDistinctThrough = passDistinctThrough;
}
public void processFilters(String sql, SharedSessionContractImplementor session) {
processFilters( sql, session.getLoadQueryInfluencers().getEnabledFilters(), session.getFactory() );
}
@SuppressWarnings( {"unchecked"})
public void processFilters(String sql, Map filters, SessionFactoryImplementor factory) {
if ( filters.size() == 0 || !sql.contains( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
processedPositionalParameterValues = getPositionalParameterValues();
processedPositionalParameterTypes = getPositionalParameterTypes();
processedSQL = sql;
}
else {
final StringTokenizer tokens = new StringTokenizer( sql, SYMBOLS, true );
StringBuilder result = new StringBuilder();
List parameters = new ArrayList();
List parameterTypes = new ArrayList();
int positionalIndex = 0;
while ( tokens.hasMoreTokens() ) {
final String token = tokens.nextToken();
if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
final String filterParameterName = token.substring( 1 );
final String[] parts = LoadQueryInfluencers.parseFilterParameterName( filterParameterName );
final FilterImpl filter = (FilterImpl) filters.get( parts[0] );
final Object value = filter.getParameter( parts[1] );
final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) {
Iterator itr = ( (Collection) value ).iterator();
while ( itr.hasNext() ) {
final Object elementValue = itr.next();
result.append( '?' );
parameters.add( elementValue );
parameterTypes.add( type );
if ( itr.hasNext() ) {
result.append( ", " );
}
}
}
else {
result.append( '?' );
parameters.add( value );
parameterTypes.add( type );
}
}
else {
result.append( token );
if ( "?".equals( token ) && positionalIndex < getPositionalParameterValues().length ) {
final Type type = getPositionalParameterTypes()[positionalIndex];
if ( type.isComponentType() ) {
int paramIndex = 1;
final int numberOfParametersCoveredBy = getNumberOfParametersCoveredBy( ((ComponentType) type).getSubtypes() );
while ( paramIndex < numberOfParametersCoveredBy ) {
final String nextToken = tokens.nextToken();
if ( "?".equals( nextToken ) ) {
paramIndex++;
}
result.append( nextToken );
}
}
parameters.add( getPositionalParameterValues()[positionalIndex] );
parameterTypes.add( type );
positionalIndex++;
}
}
}
processedPositionalParameterValues = parameters.toArray();
processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[parameterTypes.size()] );
processedSQL = result.toString();
}
}
private int getNumberOfParametersCoveredBy(Type[] subtypes) {
int numberOfParameters = 0;
for ( Type type : subtypes ) {
if ( type.isComponentType() ) {
numberOfParameters = numberOfParameters + getNumberOfParametersCoveredBy( ((ComponentType) type).getSubtypes() );
}
else {
numberOfParameters++;
}
}
return numberOfParameters;
}
public String getFilteredSQL() {
return processedSQL;
}
public Object[] getFilteredPositionalParameterValues() {
return processedPositionalParameterValues;
}
public Type[] getFilteredPositionalParameterTypes() {
return processedPositionalParameterTypes;
}
public boolean isNaturalKeyLookup() {
return isNaturalKeyLookup;
}
@SuppressWarnings( {"UnusedDeclaration"})
public void setNaturalKeyLookup(boolean isNaturalKeyLookup) {
this.isNaturalKeyLookup = isNaturalKeyLookup;
}
public void setAutoDiscoverScalarTypes(boolean autodiscovertypes) {
this.autodiscovertypes = autodiscovertypes;
}
public QueryParameters createCopyUsing(RowSelection selection) {
QueryParameters copy = new QueryParameters(
this.positionalParameterTypes,
this.positionalParameterValues,
this.namedParameters,
this.lockOptions,
selection,
this.isReadOnlyInitialized,
this.readOnly,
this.cacheable,
this.cacheRegion,
this.comment,
this.queryHints,
this.collectionKeys,
this.optionalObject,
this.optionalEntityName,
this.optionalId,
this.resultTransformer
);
copy.processedSQL = this.processedSQL;
copy.processedPositionalParameterTypes = this.processedPositionalParameterTypes;
copy.processedPositionalParameterValues = this.processedPositionalParameterValues;
copy.passDistinctThrough = this.passDistinctThrough;
return copy;
}
public HQLQueryPlan getQueryPlan() {
return queryPlan;
}
public void setQueryPlan(HQLQueryPlan queryPlan) {
this.queryPlan = queryPlan;
}
public void bindDynamicParameter(Type paramType, Object paramValue) {
if(processedPositionalParameterTypes != null) {
int length = processedPositionalParameterTypes.length;
Type[] types = new Type[length + 1];
Object[] values = new Object[length + 1];
for ( int i = 0; i < length; i++ ) {
types[i] = processedPositionalParameterTypes[i];
values[i] = processedPositionalParameterValues[i];
}
types[length] = paramType;
values[length] = paramValue;
processedPositionalParameterTypes = types;
processedPositionalParameterValues = values;
}
}
}