package org.hibernate.internal;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.engine.query.spi.ParameterMetadata;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.hql.internal.classic.ParserHelper;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.property.Getter;
import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.SerializableType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
public abstract class AbstractQueryImpl implements Query {
private static final CoreMessageLogger log = Logger.getMessageLogger(
CoreMessageLogger.class,
AbstractQueryImpl.class.getName()
);
private static final Object UNSET_PARAMETER = new MarkerObject("<unset parameter>");
private static final Object UNSET_TYPE = new MarkerObject("<unset type>");
private final String queryString;
protected final SessionImplementor session;
protected final ParameterMetadata parameterMetadata;
private List values = new ArrayList(4);
private List types = new ArrayList(4);
private Map<String,TypedValue> namedParameters = new HashMap<String, TypedValue>(4);
private Map<String, TypedValue> namedParameterLists = new HashMap<String, TypedValue>(4);
private Object optionalObject;
private Serializable optionalId;
private String optionalEntityName;
private RowSelection selection;
private boolean cacheable;
private String cacheRegion;
private String ;
private final List<String> queryHints = new ArrayList<String>();
private FlushMode flushMode;
private CacheMode cacheMode;
private FlushMode sessionFlushMode;
private CacheMode sessionCacheMode;
private Serializable collectionKey;
private Boolean readOnly;
private ResultTransformer resultTransformer;
private HQLQueryPlan queryPlan;
public AbstractQueryImpl(
String queryString,
FlushMode flushMode,
SessionImplementor session,
ParameterMetadata parameterMetadata) {
this.session = session;
this.queryString = queryString;
this.selection = new RowSelection();
this.flushMode = flushMode;
this.cacheMode = null;
this.parameterMetadata = parameterMetadata;
}
public ParameterMetadata getParameterMetadata() {
return parameterMetadata;
}
@Override
public String toString() {
return StringHelper.unqualify( getClass().getName() ) + '(' + queryString + ')';
}
@Override
public final String getQueryString() {
return queryString;
}
@Override
public boolean isCacheable() {
return cacheable;
}
@Override
public Query setCacheable(boolean cacheable) {
this.cacheable = cacheable;
return this;
}
@Override
public String getCacheRegion() {
return cacheRegion;
}
@Override
public Query setCacheRegion(String cacheRegion) {
if (cacheRegion != null) {
this.cacheRegion = cacheRegion.trim();
}
return this;
}
@Override
public FlushMode getFlushMode() {
return flushMode;
}
@Override
public Query setFlushMode(FlushMode flushMode) {
this.flushMode = flushMode;
return this;
}
@Override
public CacheMode getCacheMode() {
return cacheMode;
}
@Override
public Query setCacheMode(CacheMode cacheMode) {
this.cacheMode = cacheMode;
return this;
}
@Override
public String () {
return comment;
}
@Override
public Query (String comment) {
this.comment = comment;
return this;
}
@Override
public Query addQueryHint(String queryHint) {
queryHints.add( queryHint );
return this;
}
@Override
public Integer getFirstResult() {
return selection.getFirstRow();
}
@Override
public Query setFirstResult(int firstResult) {
selection.setFirstRow( firstResult);
return this;
}
@Override
public Integer getMaxResults() {
return selection.getMaxRows();
}
@Override
public Query setMaxResults(int maxResults) {
if ( maxResults <= 0 ) {
selection.setMaxRows( null );
}
else {
selection.setMaxRows( maxResults);
}
return this;
}
@Override
public Integer getTimeout() {
return selection.getTimeout();
}
@Override
public Query setTimeout(int timeout) {
selection.setTimeout( timeout);
return this;
}
@Override
public Integer getFetchSize() {
return selection.getFetchSize();
}
@Override
public Query setFetchSize(int fetchSize) {
selection.setFetchSize( fetchSize);
return this;
}
public Type[] getReturnTypes() throws HibernateException {
return session.getFactory().getReturnTypes( queryString );
}
public String[] getReturnAliases() throws HibernateException {
return session.getFactory().getReturnAliases( queryString );
}
public Query setCollectionKey(Serializable collectionKey) {
this.collectionKey = collectionKey;
return this;
}
@Override
public boolean isReadOnly() {
return ( readOnly == null ?
getSession().getPersistenceContext().isDefaultReadOnly() :
readOnly
);
}
@Override
public Query setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
return this;
}
@Override
public Query setResultTransformer(ResultTransformer transformer) {
this.resultTransformer = transformer;
return this;
}
public void setOptionalEntityName(String optionalEntityName) {
this.optionalEntityName = optionalEntityName;
}
public void setOptionalId(Serializable optionalId) {
this.optionalId = optionalId;
}
public void setOptionalObject(Object optionalObject) {
this.optionalObject = optionalObject;
}
SessionImplementor getSession() {
return session;
}
@Override
public abstract LockOptions getLockOptions();
protected Map<String, TypedValue> getNamedParams() {
return new HashMap<String, TypedValue>( namedParameters );
}
@Override
public String[] getNamedParameters() throws HibernateException {
return ArrayHelper.toStringArray( parameterMetadata.getNamedParameterNames() );
}
public boolean hasNamedParameters() {
return parameterMetadata.getNamedParameterNames().size() > 0;
}
protected Map<String, TypedValue> getNamedParameterLists() {
return namedParameterLists;
}
protected List getValues() {
return values;
}
protected List getTypes() {
return types;
}
protected void verifyParameters() throws QueryException {
verifyParameters(false);
}
protected void verifyParameters(boolean reserveFirstParameter) throws HibernateException {
if ( parameterMetadata.getNamedParameterNames().size() != namedParameters.size() + namedParameterLists.size() ) {
Set<String> missingParams = new HashSet<String>( parameterMetadata.getNamedParameterNames() );
missingParams.removeAll( namedParameterLists.keySet() );
missingParams.removeAll( namedParameters.keySet() );
throw new QueryException( "Not all named parameters have been set: " + missingParams, getQueryString() );
}
int positionalValueSpan = 0;
for ( int i = 0; i < values.size(); i++ ) {
Object object = types.get( i );
if( values.get( i ) == UNSET_PARAMETER || object == UNSET_TYPE ) {
if ( reserveFirstParameter && i==0 ) {
continue;
}
else {
throw new QueryException( "Unset positional parameter at position: " + i, getQueryString() );
}
}
positionalValueSpan += ( (Type) object ).getColumnSpan( session.getFactory() );
}
if ( parameterMetadata.getOrdinalParameterCount() != positionalValueSpan ) {
if ( reserveFirstParameter && parameterMetadata.getOrdinalParameterCount() - 1 != positionalValueSpan ) {
throw new QueryException(
"Expected positional parameter count: " +
(parameterMetadata.getOrdinalParameterCount()-1) +
", actual parameters: " +
values,
getQueryString()
);
}
else if ( !reserveFirstParameter ) {
throw new QueryException(
"Expected positional parameter count: " +
parameterMetadata.getOrdinalParameterCount() +
", actual parameters: " +
values,
getQueryString()
);
}
}
}
public Query setParameter(int position, Object val, Type type) {
if ( parameterMetadata.getOrdinalParameterCount() == 0 ) {
throw new IllegalArgumentException("No positional parameters in query: " + getQueryString() );
}
if ( position < 0 || position > parameterMetadata.getOrdinalParameterCount() - 1 ) {
throw new IllegalArgumentException("Positional parameter does not exist: " + position + " in query: " + getQueryString() );
}
int size = values.size();
if ( position < size ) {
values.set( position, val );
types.set( position, type );
}
else {
for ( int i = 0; i < position - size; i++ ) {
values.add( UNSET_PARAMETER );
types.add( UNSET_TYPE );
}
values.add( val );
types.add( type );
}
return this;
}
public Query setParameter(String name, Object val, Type type) {
if ( !parameterMetadata.getNamedParameterNames().contains( name ) ) {
throw new IllegalArgumentException("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]");
}
else {
namedParameters.put( name, new TypedValue( type, val ) );
return this;
}
}
public Query setParameter(int position, Object val) throws HibernateException {
if (val == null) {
setParameter( position, val, StandardBasicTypes.SERIALIZABLE );
}
else {
setParameter( position, val, determineType( position, val ) );
}
return this;
}
public Query setParameter(String name, Object val) throws HibernateException {
if (val == null) {
Type type = parameterMetadata.getNamedParameterExpectedType( name );
if ( type == null ) {
type = StandardBasicTypes.SERIALIZABLE;
}
setParameter( name, val, type );
}
else {
setParameter( name, val, determineType( name, val ) );
}
return this;
}
protected Type determineType(int paramPosition, Object paramValue, Type defaultType) {
Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
if ( type == null ) {
type = defaultType;
}
return type;
}
protected Type determineType(int paramPosition, Object paramValue) throws HibernateException {
Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
if ( type == null ) {
type = guessType( paramValue );
}
return type;
}
protected Type determineType(String paramName, Object paramValue, Type defaultType) {
Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
if ( type == null ) {
type = defaultType;
}
return type;
}
protected Type determineType(String paramName, Object paramValue) throws HibernateException {
Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
if ( type == null ) {
type = guessType( paramValue );
}
return type;
}
protected Type determineType(String paramName, Class clazz) throws HibernateException {
Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
if ( type == null ) {
type = guessType( clazz );
}
return type;
}
private Type guessType(Object param) throws HibernateException {
Class clazz = HibernateProxyHelper.getClassWithoutInitializingProxy( param );
return guessType( clazz );
}
private Type guessType(Class clazz) throws HibernateException {
String typename = clazz.getName();
Type type = session.getFactory().getTypeResolver().heuristicType(typename);
boolean serializable = type!=null && type instanceof SerializableType;
if (type==null || serializable) {
try {
session.getFactory().getEntityPersister( clazz.getName() );
}
catch (MappingException me) {
if (serializable) {
return type;
}
else {
throw new HibernateException("Could not determine a type for class: " + typename);
}
}
return ( (Session) session ).getTypeHelper().entity( clazz );
}
else {
return type;
}
}
public Query setString(int position, String val) {
setParameter(position, val, StandardBasicTypes.STRING);
return this;
}
public Query setCharacter(int position, char val) {
setParameter( position, Character.valueOf( val ), StandardBasicTypes.CHARACTER );
return this;
}
public Query setBoolean(int position, boolean val) {
Boolean valueToUse = val;
Type typeToUse = determineType( position, valueToUse, StandardBasicTypes.BOOLEAN );
setParameter( position, valueToUse, typeToUse );
return this;
}
public Query setByte(int position, byte val) {
setParameter(position, val, StandardBasicTypes.BYTE);
return this;
}
public Query setShort(int position, short val) {
setParameter(position, val, StandardBasicTypes.SHORT);
return this;
}
public Query setInteger(int position, int val) {
setParameter(position, val, StandardBasicTypes.INTEGER);
return this;
}
public Query setLong(int position, long val) {
setParameter(position, val, StandardBasicTypes.LONG);
return this;
}
public Query setFloat(int position, float val) {
setParameter(position, val, StandardBasicTypes.FLOAT);
return this;
}
public Query setDouble(int position, double val) {
setParameter(position, val, StandardBasicTypes.DOUBLE);
return this;
}
public Query setBinary(int position, byte[] val) {
setParameter(position, val, StandardBasicTypes.BINARY);
return this;
}
public Query setText(int position, String val) {
setParameter(position, val, StandardBasicTypes.TEXT);
return this;
}
public Query setSerializable(int position, Serializable val) {
setParameter(position, val, StandardBasicTypes.SERIALIZABLE);
return this;
}
public Query setDate(int position, Date date) {
setParameter(position, date, StandardBasicTypes.DATE);
return this;
}
public Query setTime(int position, Date date) {
setParameter(position, date, StandardBasicTypes.TIME);
return this;
}
public Query setTimestamp(int position, Date date) {
setParameter(position, date, StandardBasicTypes.TIMESTAMP);
return this;
}
public Query setEntity(int position, Object val) {
setParameter( position, val, ( (Session) session ).getTypeHelper().entity( resolveEntityName( val ) ) );
return this;
}
private String resolveEntityName(Object val) {
if ( val == null ) {
throw new IllegalArgumentException( "entity for parameter binding cannot be null" );
}
return session.bestGuessEntityName( val );
}
public Query setLocale(int position, Locale locale) {
setParameter(position, locale, StandardBasicTypes.LOCALE);
return this;
}
public Query setCalendar(int position, Calendar calendar) {
setParameter(position, calendar, StandardBasicTypes.CALENDAR);
return this;
}
public Query setCalendarDate(int position, Calendar calendar) {
setParameter(position, calendar, StandardBasicTypes.CALENDAR_DATE);
return this;
}
public Query setBinary(String name, byte[] val) {
setParameter(name, val, StandardBasicTypes.BINARY);
return this;
}
public Query setText(String name, String val) {
setParameter(name, val, StandardBasicTypes.TEXT);
return this;
}
public Query setBoolean(String name, boolean val) {
Boolean valueToUse = val;
Type typeToUse = determineType( name, valueToUse, StandardBasicTypes.BOOLEAN );
setParameter( name, valueToUse, typeToUse );
return this;
}
public Query setByte(String name, byte val) {
setParameter(name, val, StandardBasicTypes.BYTE);
return this;
}
public Query setCharacter(String name, char val) {
setParameter(name, val, StandardBasicTypes.CHARACTER);
return this;
}
public Query setDate(String name, Date date) {
setParameter(name, date, StandardBasicTypes.DATE);
return this;
}
public Query setDouble(String name, double val) {
setParameter(name, val, StandardBasicTypes.DOUBLE);
return this;
}
public Query setEntity(String name, Object val) {
setParameter( name, val, ( (Session) session ).getTypeHelper().entity( resolveEntityName( val ) ) );
return this;
}
public Query setFloat(String name, float val) {
setParameter(name, val, StandardBasicTypes.FLOAT);
return this;
}
public Query setInteger(String name, int val) {
setParameter(name, val, StandardBasicTypes.INTEGER);
return this;
}
public Query setLocale(String name, Locale locale) {
setParameter(name, locale, StandardBasicTypes.LOCALE);
return this;
}
public Query setCalendar(String name, Calendar calendar) {
setParameter(name, calendar, StandardBasicTypes.CALENDAR);
return this;
}
public Query setCalendarDate(String name, Calendar calendar) {
setParameter(name, calendar, StandardBasicTypes.CALENDAR_DATE);
return this;
}
public Query setLong(String name, long val) {
setParameter(name, val, StandardBasicTypes.LONG);
return this;
}
public Query setSerializable(String name, Serializable val) {
setParameter(name, val, StandardBasicTypes.SERIALIZABLE);
return this;
}
public Query setShort(String name, short val) {
setParameter(name, val, StandardBasicTypes.SHORT);
return this;
}
public Query setString(String name, String val) {
setParameter(name, val, StandardBasicTypes.STRING);
return this;
}
public Query setTime(String name, Date date) {
setParameter(name, date, StandardBasicTypes.TIME);
return this;
}
public Query setTimestamp(String name, Date date) {
setParameter(name, date, StandardBasicTypes.TIMESTAMP);
return this;
}
public Query setBigDecimal(int position, BigDecimal number) {
setParameter(position, number, StandardBasicTypes.BIG_DECIMAL);
return this;
}
public Query setBigDecimal(String name, BigDecimal number) {
setParameter(name, number, StandardBasicTypes.BIG_DECIMAL);
return this;
}
public Query setBigInteger(int position, BigInteger number) {
setParameter(position, number, StandardBasicTypes.BIG_INTEGER);
return this;
}
public Query setBigInteger(String name, BigInteger number) {
setParameter(name, number, StandardBasicTypes.BIG_INTEGER);
return this;
}
@Override
public Query setParameterList(String name, Collection vals, Type type) throws HibernateException {
if ( !parameterMetadata.getNamedParameterNames().contains( name ) ) {
throw new IllegalArgumentException("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]");
}
namedParameterLists.put( name, new TypedValue( type, vals ) );
return this;
}
protected String expandParameterLists(Map namedParamsCopy) {
String query = this.queryString;
for ( Map.Entry<String, TypedValue> stringTypedValueEntry : namedParameterLists.entrySet() ) {
Map.Entry me = (Map.Entry) stringTypedValueEntry;
query = expandParameterList( query, (String) me.getKey(), (TypedValue) me.getValue(), namedParamsCopy );
}
return query;
}
private String expandParameterList(String query, String name, TypedValue typedList, Map namedParamsCopy) {
Collection vals = (Collection) typedList.getValue();
final Dialect dialect = session.getFactory().getDialect();
final int inExprLimit = dialect.getInExpressionCountLimit();
if ( inExprLimit > 0 && vals.size() > inExprLimit ) {
log.tooManyInExpressions( dialect.getClass().getName(), inExprLimit, name, vals.size() );
}
Type type = typedList.getType();
boolean isJpaPositionalParam = parameterMetadata.getNamedParameterDescriptor( name ).isJpaStyle();
String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
String placeholder =
new StringBuilder( paramPrefix.length() + name.length() )
.append( paramPrefix ).append( name )
.toString();
if ( query == null ) {
return query;
}
int loc = query.indexOf( placeholder );
if ( loc < 0 ) {
return query;
}
String beforePlaceholder = query.substring( 0, loc );
String afterPlaceholder = query.substring( loc + placeholder.length() );
boolean isEnclosedInParens =
StringHelper.getLastNonWhitespaceCharacter( beforePlaceholder ) == '(' &&
StringHelper.getFirstNonWhitespaceCharacter( afterPlaceholder ) == ')';
if ( vals.size() == 1 && isEnclosedInParens ) {
namedParamsCopy.put( name, new TypedValue( type, vals.iterator().next() ) );
return query;
}
StringBuilder list = new StringBuilder( 16 );
Iterator iter = vals.iterator();
int i = 0;
while ( iter.hasNext() ) {
String alias = ( isJpaPositionalParam ? 'x' + name : name ) + '_' + i++ + '_';
if ( namedParamsCopy.put( alias, new TypedValue( type, iter.next() ) ) != null ) {
throw new HibernateException( "Repeated usage of alias '" + alias + "' while expanding list parameter." );
}
list.append( ParserHelper.HQL_VARIABLE_PREFIX ).append( alias );
if ( iter.hasNext() ) {
list.append( ", " );
}
}
return StringHelper.replace(
beforePlaceholder,
afterPlaceholder,
placeholder.toString(),
list.toString(),
true,
true
);
}
public Query setParameterList(String name, Collection vals) throws HibernateException {
if ( vals == null ) {
throw new QueryException( "Collection must be not null!" );
}
if( vals.size() == 0 ) {
setParameterList( name, vals, null );
}
else {
setParameterList(name, vals, determineType( name, vals.iterator().next() ) );
}
return this;
}
public Query setParameterList(String name, Object[] vals, Type type) throws HibernateException {
return setParameterList( name, Arrays.asList(vals), type );
}
public Query setParameterList(String name, Object[] values) throws HibernateException {
return setParameterList( name, Arrays.asList( values ) );
}
public Query setProperties(Map map) throws HibernateException {
String[] params = getNamedParameters();
for (int i = 0; i < params.length; i++) {
String namedParam = params[i];
final Object object = map.get(namedParam);
if(object==null) {
continue;
}
Class retType = object.getClass();
if ( Collection.class.isAssignableFrom( retType ) ) {
setParameterList( namedParam, ( Collection ) object );
}
else if ( retType.isArray() ) {
setParameterList( namedParam, ( Object[] ) object );
}
else {
setParameter( namedParam, object, determineType( namedParam, retType ) );
}
}
return this;
}
public Query setProperties(Object bean) throws HibernateException {
Class clazz = bean.getClass();
String[] params = getNamedParameters();
for (int i = 0; i < params.length; i++) {
String namedParam = params[i];
try {
Getter getter = ReflectHelper.getGetter( clazz, namedParam );
Class retType = getter.getReturnType();
final Object object = getter.get( bean );
if ( Collection.class.isAssignableFrom( retType ) ) {
setParameterList( namedParam, ( Collection ) object );
}
else if ( retType.isArray() ) {
setParameterList( namedParam, ( Object[] ) object );
}
else {
setParameter( namedParam, object, determineType( namedParam, retType ) );
}
}
catch (PropertyNotFoundException pnfe) {
}
}
return this;
}
public Query setParameters(Object[] values, Type[] types) {
this.values = Arrays.asList(values);
this.types = Arrays.asList(types);
return this;
}
public Object uniqueResult() throws HibernateException {
return uniqueElement( list() );
}
static Object uniqueElement(List list) throws NonUniqueResultException {
int size = list.size();
if (size==0) return null;
Object first = list.get(0);
for ( int i=1; i<size; i++ ) {
if ( list.get(i)!=first ) {
throw new NonUniqueResultException( list.size() );
}
}
return first;
}
protected RowSelection getRowSelection() {
return selection;
}
public Type[] typeArray() {
return ArrayHelper.toTypeArray( getTypes() );
}
public Object[] valueArray() {
return getValues().toArray();
}
public QueryParameters getQueryParameters(Map namedParams) {
QueryParameters queryParameters = new QueryParameters(
typeArray(),
valueArray(),
namedParams,
getLockOptions(),
getRowSelection(),
true,
isReadOnly(),
cacheable,
cacheRegion,
comment,
queryHints,
collectionKey == null ? null : new Serializable[] { collectionKey },
optionalObject,
optionalEntityName,
optionalId,
resultTransformer
);
queryParameters.setQueryPlan( queryPlan );
return queryParameters;
}
protected void before() {
if ( flushMode!=null ) {
sessionFlushMode = getSession().getFlushMode();
getSession().setFlushMode(flushMode);
}
if ( cacheMode!=null ) {
sessionCacheMode = getSession().getCacheMode();
getSession().setCacheMode(cacheMode);
}
}
protected void after() {
if (sessionFlushMode!=null) {
getSession().setFlushMode(sessionFlushMode);
sessionFlushMode = null;
}
if (sessionCacheMode!=null) {
getSession().setCacheMode(sessionCacheMode);
sessionCacheMode = null;
}
}
public HQLQueryPlan getQueryPlan() {
return queryPlan;
}
public void setQueryPlan(HQLQueryPlan queryPlan) {
this.queryPlan = queryPlan;
}
}