Open Source Repository

Home /hibernate/hibernate-3.2.7.ga | Repository Home



org/hibernate/hql/classic/QueryTranslatorImpl.java
//$Id: QueryTranslatorImpl.java 11081 2007-01-23 16:31:13Z [email protected] $
package org.hibernate.hql.classic;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.SequencedHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.ScrollableResults;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.JoinSequence;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.event.EventSource;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.hql.FilterTranslator;
import org.hibernate.hql.HolderInstantiator;
import org.hibernate.hql.NameGenerator;
import org.hibernate.hql.ParameterTranslations;
import org.hibernate.impl.IteratorImpl;
import org.hibernate.loader.BasicLoader;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.QuerySelect;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;

/**
 * An instance of <tt>QueryTranslator</tt> translates a Hibernate
 * query string to SQL.
 */
public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator {

  private static final String[] NO_RETURN_ALIASES = new String[] {};

  private final String queryIdentifier;
  private final String queryString;

  private final Map typeMap = new SequencedHashMap();
  private final Map collections = new SequencedHashMap();
  private List returnedTypes = new ArrayList();
  private final List fromTypes = new ArrayList();
  private final List scalarTypes = new ArrayList();
  private final Map namedParameters = new HashMap();
  private final Map aliasNames = new HashMap();
  private final Map oneToOneOwnerNames = new HashMap();
  private final Map uniqueKeyOwnerReferences = new HashMap();
  private final Map decoratedPropertyMappings = new HashMap();

  private final List scalarSelectTokens = new ArrayList();
  private final List whereTokens = new ArrayList();
  private final List havingTokens = new ArrayList();
  private final Map joins = new SequencedHashMap();
  private final List orderByTokens = new ArrayList();
  private final List groupByTokens = new ArrayList();
  private final Set querySpaces = new HashSet();
  private final Set entitiesToFetch = new HashSet();

  private final Map pathAliases = new HashMap();
  private final Map pathJoins = new HashMap();

  private Queryable[] persisters;
  private int[] owners;
  private EntityType[] ownerAssociationTypes;
  private String[] names;
  private boolean[] includeInSelect;
  private int selectLength;
  private Type[] returnTypes;
  private Type[] actualReturnTypes;
  private String[][] scalarColumnNames;
  private Map tokenReplacements;
  private int nameCount = 0;
  private int parameterCount = 0;
  private boolean distinct = false;
  private boolean compiled;
  private String sqlString;
  private Class holderClass;
  private Constructor holderConstructor;
  private boolean hasScalars;
  private boolean shallowQuery;
  private QueryTranslatorImpl superQuery;

  private QueryableCollection collectionPersister;
  private int collectionOwnerColumn = -1;
  private String collectionOwnerName;
  private String fetchName;

  private String[] suffixes;

  private Map enabledFilters;

  private static final Log log = LogFactory.getLogQueryTranslatorImpl.class );

  /**
   * Construct a query translator
   *
   @param queryIdentifier A unique identifier for the query of which this
   * translation is part; typically this is the original, user-supplied query string.
   @param queryString The "preprocessed" query string; at the very least
   * already processed by {@link org.hibernate.hql.QuerySplitter}.
   @param enabledFilters Any enabled filters.
   @param factory The session factory.
   */
  public QueryTranslatorImpl(
      String queryIdentifier,
          String queryString,
          Map enabledFilters,
          SessionFactoryImplementor factory) {
    superfactory );
    this.queryIdentifier = queryIdentifier;
    this.queryString = queryString;
    this.enabledFilters = enabledFilters;
  }

  /**
   * Construct a query translator; this form used internally.
   *
   @param queryString The query string to process.
   @param enabledFilters Any enabled filters.
   @param factory The session factory.
   */
  public QueryTranslatorImpl(
          String queryString,
          Map enabledFilters,
          SessionFactoryImplementor factory) {
    thisqueryString, queryString, enabledFilters, factory );
  }

  /**
   * Compile a subquery.
   *
   @param superquery The containing query of the query to be compiled.
   *
   @throws org.hibernate.MappingException Indicates problems resolving
   * things referenced in the query.
   @throws org.hibernate.QueryException Generally some form of syntatic
   * failure.
   */
  void compile(QueryTranslatorImpl superquerythrows QueryException, MappingException {
    this.tokenReplacements = superquery.tokenReplacements;
    this.superQuery = superquery;
    this.shallowQuery = true;
    this.enabledFilters = superquery.getEnabledFilters();
    compile();
  }


  /**
   * Compile a "normal" query. This method may be called multiple
   * times. Subsequent invocations are no-ops.
   */
  public synchronized void compile(
      Map replacements,
      boolean scalarthrows QueryException, MappingException {
    if !compiled ) {
      this.tokenReplacements = replacements;
      this.shallowQuery = scalar;
      compile();
    }
  }

  /**
   * Compile a filter. This method may be called multiple
   * times. Subsequent invocations are no-ops.
   */
  public synchronized void compile(
      String collectionRole,
      Map replacements,
      boolean scalarthrows QueryException, MappingException {

    if !isCompiled() ) {
      addFromAssociation"this", collectionRole );
      compilereplacements, scalar );
    }
  }

  /**
   * Compile the query (generate the SQL).
   *
   @throws org.hibernate.MappingException Indicates problems resolving
   * things referenced in the query.
   @throws org.hibernate.QueryException Generally some form of syntatic
   * failure.
   */
  private void compile() throws QueryException, MappingException {

    log.trace"compiling query" );
    try {
      ParserHelper.parsenew PreprocessingParsertokenReplacements ),
          queryString,
          ParserHelper.HQL_SEPARATORS,
          this );
      renderSQL();
    }
    catch QueryException qe ) {
      qe.setQueryStringqueryString );
      throw qe;
    }
    catch MappingException me ) {
      throw me;
    }
    catch Exception e ) {
      log.debug"unexpected query compilation problem", e );
      e.printStackTrace();
      QueryException qe = new QueryException"Incorrect query syntax", e );
      qe.setQueryStringqueryString );
      throw qe;
    }

    postInstantiate();

    compiled = true;

  }

  public String getSQLString() {
    return sqlString;
  }

  public List collectSqlStrings() {
    return ArrayHelper.toListnew String[] { sqlString } );
  }

  public String getQueryString() {
    return queryString;
  }

  /**
   * Persisters for the return values of a <tt>find()</tt> style query.
   *
   @return an array of <tt>EntityPersister</tt>s.
   */
  protected Loadable[] getEntityPersisters() {
    return persisters;
  }

  /**
   * Types of the return values of an <tt>iterate()</tt> style query.
   *
   @return an array of <tt>Type</tt>s.
   */
  public Type[] getReturnTypes() {
    return actualReturnTypes;
  }

  public String[] getReturnAliases() {
    // return aliases not supported in classic translator!
    return NO_RETURN_ALIASES;
  }

  public String[][] getColumnNames() {
    return scalarColumnNames;
  }

  private static void logQuery(String hql, String sql) {
    if log.isDebugEnabled() ) {
      log.debug"HQL: " + hql );
      log.debug"SQL: " + sql );
    }
  }

  void setAliasName(String alias, String name) {
    aliasNames.putalias, name );
  }

  public String getAliasName(String alias) {
    String name = String aliasNames.getalias );
    if name == null ) {
      if superQuery != null ) {
        name = superQuery.getAliasNamealias );
      }
      else {
        name = alias;
      }
    }
    return name;
  }

  String unalias(String path) {
    String alias = StringHelper.rootpath );
    String name = getAliasNamealias );
    if name != null ) {
      return name + path.substringalias.length() );
    }
    else {
      return path;
    }
  }

  void addEntityToFetch(String name, String oneToOneOwnerName, AssociationType ownerAssociationType) {
    addEntityToFetchname );
    if oneToOneOwnerName != null oneToOneOwnerNames.putname, oneToOneOwnerName );
    if ownerAssociationType != null uniqueKeyOwnerReferences.putname, ownerAssociationType );
  }

  private void addEntityToFetch(String name) {
    entitiesToFetch.addname );
  }

  private int nextCount() {
    return superQuery == null ? nameCount++ : superQuery.nameCount++;
  }

  String createNameFor(String type) {
    return StringHelper.generateAliastype, nextCount() );
  }

  String createNameForCollection(String role) {
    return StringHelper.generateAliasrole, nextCount() );
  }

  private String getType(String name) {
    String type = String typeMap.getname );
    if type == null && superQuery != null ) {
      type = superQuery.getTypename );
    }
    return type;
  }

  private String getRole(String name) {
    String role = String collections.getname );
    if role == null && superQuery != null ) {
      role = superQuery.getRolename );
    }
    return role;
  }

  boolean isName(String name) {
    return aliasNames.containsKeyname ||
        typeMap.containsKeyname ||
        collections.containsKeyname || (
        superQuery != null && superQuery.isNamename )
        );
  }

  PropertyMapping getPropertyMapping(String namethrows QueryException {
    PropertyMapping decorator = getDecoratedPropertyMappingname );
    if decorator != null return decorator;

    String type = getTypename );
    if type == null ) {
      String role = getRolename );
      if role == null ) {
        throw new QueryException"alias not found: " + name );
      }
      return getCollectionPersisterrole )//.getElementPropertyMapping();
    }
    else {
      Queryable persister = getEntityPersistertype );
      if persister == null throw new QueryException"persistent class not found: " + type );
      return persister;
    }
  }

  private PropertyMapping getDecoratedPropertyMapping(String name) {
    return PropertyMapping decoratedPropertyMappings.getname );
  }

  void decoratePropertyMapping(String name, PropertyMapping mapping) {
    decoratedPropertyMappings.putname, mapping );
  }

  private Queryable getEntityPersisterForName(String namethrows QueryException {
    String type = getTypename );
    Queryable persister = getEntityPersistertype );
    if persister == null throw new QueryException"persistent class not found: " + type );
    return persister;
  }

  Queryable getEntityPersisterUsingImports(String className) {
    final String importedClassName = getFactory().getImportedClassNameclassName );
    if importedClassName == null ) {
      return null;
    }
    try {
      return Queryable getFactory().getEntityPersisterimportedClassName );
    }
    catch MappingException me ) {
      return null;
    }
  }

  Queryable getEntityPersister(String entityNamethrows QueryException {
    try {
      return Queryable getFactory().getEntityPersisterentityName );
    }
    catch Exception e ) {
      throw new QueryException"persistent class not found: " + entityName );
    }
  }

  QueryableCollection getCollectionPersister(String rolethrows QueryException {
    try {
      return QueryableCollection getFactory().getCollectionPersisterrole );
    }
    catch ClassCastException cce ) {
      throw new QueryException"collection role is not queryable: " + role );
    }
    catch Exception e ) {
      throw new QueryException"collection role not found: " + role );
    }
  }

  void addType(String name, String type) {
    typeMap.putname, type );
  }

  void addCollection(String name, String role) {
    collections.putname, role );
  }

  void addFrom(String name, String type, JoinSequence joinSequence)
      throws QueryException {
    addTypename, type );
    addFromname, joinSequence );
  }

  void addFromCollection(String name, String collectionRole, JoinSequence joinSequence)
      throws QueryException {
    //register collection role
    addCollectionname, collectionRole );
    addJoinname, joinSequence );
  }

  void addFrom(String name, JoinSequence joinSequence)
      throws QueryException {
    fromTypes.addname );
    addJoinname, joinSequence );
  }

  void addFromClass(String name, Queryable classPersister)
      throws QueryException {
    JoinSequence joinSequence = new JoinSequencegetFactory() )
        .setRootclassPersister, name );
    //crossJoins.add(name);
    addFromname, classPersister.getEntityName(), joinSequence );
  }

  void addSelectClass(String name) {
    returnedTypes.addname );
  }

  void addSelectScalar(Type type) {
    scalarTypes.addtype );
  }

  void appendWhereToken(String token) {
    whereTokens.addtoken );
  }

  void appendHavingToken(String token) {
    havingTokens.addtoken );
  }

  void appendOrderByToken(String token) {
    orderByTokens.addtoken );
  }

  void appendGroupByToken(String token) {
    groupByTokens.addtoken );
  }

  void appendScalarSelectToken(String token) {
    scalarSelectTokens.addtoken );
  }

  void appendScalarSelectTokens(String[] tokens) {
    scalarSelectTokens.addtokens );
  }

  void addFromJoinOnly(String name, JoinSequence joinSequencethrows QueryException {
    addJoinname, joinSequence.getFromPart() );
  }

  void addJoin(String name, JoinSequence joinSequencethrows QueryException {
    if !joins.containsKeyname ) ) joins.putname, joinSequence );
  }

  void addNamedParameter(String name) {
    if superQuery != null superQuery.addNamedParametername );
    Integer loc = new IntegerparameterCount++ );
    Object o = namedParameters.getname );
    if o == null ) {
      namedParameters.putname, loc );
    }
    else if instanceof Integer ) {
      ArrayList list = new ArrayList);
      list.add);
      list.addloc );
      namedParameters.putname, list );
    }
    else {
      ( ( ArrayList ).addloc );
    }
  }

  public int[] getNamedParameterLocs(String namethrows QueryException {
    Object o = namedParameters.getname );
    if o == null ) {
      QueryException qe = new QueryExceptionERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
      qe.setQueryStringqueryString );
      throw qe;
    }
    if instanceof Integer ) {
      return new int[]{ ( ( Integer ).intValue() };
    }
    else {
      return ArrayHelper.toIntArray( ( ArrayList );
    }
  }

  private void renderSQL() throws QueryException, MappingException {

    final int rtsize;
    if returnedTypes.size() == && scalarTypes.size() == ) {
      //ie no select clause in HQL
      returnedTypes = fromTypes;
      rtsize = returnedTypes.size();
    }
    else {
      rtsize = returnedTypes.size();
      Iterator iter = entitiesToFetch.iterator();
      while iter.hasNext() ) {
        returnedTypes.additer.next() );
      }
    }
    int size = returnedTypes.size();
    persisters = new Queryable[size];
    names = new String[size];
    owners = new int[size];
    ownerAssociationTypes = new EntityType[size];
    suffixes = new String[size];
    includeInSelect = new boolean[size];
    for int i = 0; i < size; i++ ) {
      String name = String returnedTypes.get);
      //if ( !isName(name) ) throw new QueryException("unknown type: " + name);
      persisters[i= getEntityPersisterForNamename );
      // TODO: cannot use generateSuffixes() - it handles the initial suffix differently.
      suffixes[isize == "" : Integer.toString'_';
      names[i= name;
      includeInSelect[i= !entitiesToFetch.containsname );
      if includeInSelect[i] ) selectLength++;
      if name.equalscollectionOwnerName ) ) collectionOwnerColumn = i;
      String oneToOneOwner = String oneToOneOwnerNames.getname );
      owners[ioneToOneOwner == null ? -: returnedTypes.indexOfoneToOneOwner );
      ownerAssociationTypes[i(EntityTypeuniqueKeyOwnerReferences.getname );
    }

    if ArrayHelper.isAllNegativeowners ) ) owners = null;

    String scalarSelect = renderScalarSelect()//Must be done here because of side-effect! yuck...

    int scalarSize = scalarTypes.size();
    hasScalars = scalarTypes.size() != rtsize;

    returnTypes = new Type[scalarSize];
    for int i = 0; i < scalarSize; i++ ) {
      returnTypes[iType scalarTypes.get);
    }

    QuerySelect sql = new QuerySelectgetFactory().getDialect() );
    sql.setDistinctdistinct );

    if !shallowQuery ) {
      renderIdentifierSelectsql );
      renderPropertiesSelectsql );
    }

    if collectionPersister != null ) {
      sql.addSelectFragmentStringcollectionPersister.selectFragmentfetchName, "__" ) );
    }

    if hasScalars || shallowQuery sql.addSelectFragmentStringscalarSelect );

    //TODO: for some dialects it would be appropriate to add the renderOrderByPropertiesSelect() to other select strings
    mergeJoinssql.getJoinFragment() );

    sql.setWhereTokenswhereTokens.iterator() );

    sql.setGroupByTokensgroupByTokens.iterator() );
    sql.setHavingTokenshavingTokens.iterator() );
    sql.setOrderByTokensorderByTokens.iterator() );

    if collectionPersister != null && collectionPersister.hasOrdering() ) {
      sql.addOrderBycollectionPersister.getSQLOrderByStringfetchName ) );
    }

    scalarColumnNames = NameGenerator.generateColumnNamesreturnTypes, getFactory() );

    // initialize the Set of queried identifier spaces (ie. tables)
    Iterator iter = collections.values().iterator();
    while iter.hasNext() ) {
      CollectionPersister p = getCollectionPersister( ( String iter.next() );
      addQuerySpacesp.getCollectionSpaces() );
    }
    iter = typeMap.keySet().iterator();
    while iter.hasNext() ) {
      Queryable p = getEntityPersisterForName( ( String iter.next() );
      addQuerySpacesp.getQuerySpaces() );
    }

    sqlString = sql.toQueryString();

    if holderClass != null holderConstructor = ReflectHelper.getConstructorholderClass, returnTypes );

    if hasScalars ) {
      actualReturnTypes = returnTypes;
    }
    else {
      actualReturnTypes = new Type[selectLength];
      int j = 0;
      for int i = 0; i < persisters.length; i++ ) {
        if includeInSelect[i] ) {
          actualReturnTypes[j++= TypeFactory.manyToOnepersisters[i].getEntityName(), shallowQuery );
        }
      }
    }

  }

  private void renderIdentifierSelect(QuerySelect sql) {
    int size = returnedTypes.size();

    for int k = 0; k < size; k++ ) {
      String name = String returnedTypes.get);
      String suffix = size == "" : Integer.toString'_';
      sql.addSelectFragmentStringpersisters[k].identifierSelectFragmentname, suffix ) );
    }

  }

  /*private String renderOrderByPropertiesSelect() {
    StringBuffer buf = new StringBuffer(10);

    //add the columns we are ordering by to the select ID select clause
    Iterator iter = orderByTokens.iterator();
    while ( iter.hasNext() ) {
      String token = (String) iter.next();
      if ( token.lastIndexOf(".") > 0 ) {
        //ie. it is of form "foo.bar", not of form "asc" or "desc"
        buf.append(StringHelper.COMMA_SPACE).append(token);
      }
    }

    return buf.toString();
  }*/

  private void renderPropertiesSelect(QuerySelect sql) {
    int size = returnedTypes.size();
    for int k = 0; k < size; k++ ) {
      String suffix = size == "" : Integer.toString'_';
      String name = String returnedTypes.get);
      sql.addSelectFragmentStringpersisters[k].propertySelectFragmentname, suffix, false ) );
    }
  }

  /**
   * WARNING: side-effecty
   */
  private String renderScalarSelect() {

    boolean isSubselect = superQuery != null;

    StringBuffer buf = new StringBuffer20 );

    if scalarTypes.size() == ) {
      //ie. no select clause
      int size = returnedTypes.size();
      for int k = 0; k < size; k++ ) {

        scalarTypes.addTypeFactory.manyToOnepersisters[k].getEntityName(), shallowQuery ) );

        String[] idColumnNames = persisters[k].getIdentifierColumnNames();
        for int i = 0; i < idColumnNames.length; i++ ) {
          buf.appendreturnedTypes.get) ).append'.' ).appendidColumnNames[i] );
          if !isSubselect buf.append" as " ).appendNameGenerator.scalarNamek, i ) );
          if i != idColumnNames.length - || k != size - buf.append", " );
        }

      }

    }
    else {
      //there _was_ a select clause
      Iterator iter = scalarSelectTokens.iterator();
      int c = 0;
      boolean nolast = false//real hacky...
      int parenCount = 0// used to count the nesting of parentheses
      while iter.hasNext() ) {
        Object next = iter.next();
        if next instanceof String ) {
          String token = String next;

          if "(".equalstoken ) ) {
            parenCount++;
          }
          else if ")".equalstoken ) ) {
            parenCount--;
          }

          String lc = token.toLowerCase();
          if lc.equals", " ) ) {
            if nolast ) {
              nolast = false;
            }
            else {
              if !isSubselect && parenCount == ) {
                int x = c++;
                buf.append" as " )
                    .appendNameGenerator.scalarNamex, ) );
              }
            }
          }
          buf.appendtoken );
          if lc.equals"distinct" || lc.equals"all" ) ) {
            buf.append' ' );
          }
        }
        else {
          nolast = true;
          String[] tokens = String[] ) next;
          for int i = 0; i < tokens.length; i++ ) {
            buf.appendtokens[i] );
            if !isSubselect ) {
              buf.append" as " )
                  .appendNameGenerator.scalarNamec, i ) );
            }
            if i != tokens.length - buf.append", " );
          }
          c++;
        }
      }
      if !isSubselect && !nolast ) {
        int x = c++;
        buf.append" as " )
            .appendNameGenerator.scalarNamex, ) );
      }

    }

    return buf.toString();
  }

  private void mergeJoins(JoinFragment ojfthrows MappingException, QueryException {

    Iterator iter = joins.entrySet().iterator();
    while iter.hasNext() ) {
      Map.Entry me = Map.Entry iter.next();
      String name = String me.getKey();
      JoinSequence join = JoinSequence me.getValue();
      join.setSelectornew JoinSequence.Selector() {
        public boolean includeSubclasses(String alias) {
          boolean include = returnedTypes.containsalias && !isShallowQuery();
          return include;
        }
      } );

      if typeMap.containsKeyname ) ) {
        ojf.addFragmentjoin.toJoinFragmentenabledFilters, true ) );
      }
      else if collections.containsKeyname ) ) {
        ojf.addFragmentjoin.toJoinFragmentenabledFilters, true ) );
      }
      else {
        //name from a super query (a bit inelegant that it shows up here)
      }

    }

  }

  public final Set getQuerySpaces() {
    return querySpaces;
  }

  /**
   * Is this query called by scroll() or iterate()?
   *
   @return true if it is, false if it is called by find() or list()
   */
  boolean isShallowQuery() {
    return shallowQuery;
  }

  void addQuerySpaces(Serializable[] spaces) {
    for int i = 0; i < spaces.length; i++ ) {
      querySpaces.addspaces[i] );
    }
    if superQuery != null superQuery.addQuerySpacesspaces );
  }

  void setDistinct(boolean distinct) {
    this.distinct = distinct;
  }

  boolean isSubquery() {
    return superQuery != null;
  }

  /**
   * Overrides method from Loader
   */
  public CollectionPersister[] getCollectionPersisters() {
    return collectionPersister == null null new CollectionPersister[] { collectionPersister };
  }

  protected String[] getCollectionSuffixes() {
    return collectionPersister == null null new String[] { "__" };
  }

  void setCollectionToFetch(String role, String name, String ownerName, String entityName)
      throws QueryException {
    fetchName = name;
    collectionPersister = getCollectionPersisterrole );
    collectionOwnerName = ownerName;
    if collectionPersister.getElementType().isEntityType() ) {
      addEntityToFetchentityName );
    }
  }

  protected String[] getSuffixes() {
    return suffixes;
  }

  protected String[] getAliases() {
    return names;
  }

  /**
   * Used for collection filters
   */
  private void addFromAssociation(final String elementName, final String collectionRole)
      throws QueryException {
    //q.addCollection(collectionName, collectionRole);
    QueryableCollection persister = getCollectionPersistercollectionRole );
    Type collectionElementType = persister.getElementType();
    if !collectionElementType.isEntityType() ) {
      throw new QueryException"collection of values in filter: " + elementName );
    }

    String[] keyColumnNames = persister.getKeyColumnNames();
    //if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " + collectionRole);

    String collectionName;
    JoinSequence join = new JoinSequencegetFactory() );
    collectionName = persister.isOneToMany() ?
        elementName :
        createNameForCollectioncollectionRole );
    join.setRootpersister, collectionName );
    if !persister.isOneToMany() ) {
      //many-to-many
      addCollectioncollectionName, collectionRole );
      try {
        join.addJoin( ( AssociationType persister.getElementType(),
            elementName,
            JoinFragment.INNER_JOIN,
            persister.getElementColumnNames(collectionName) );
      }
      catch MappingException me ) {
        throw new QueryExceptionme );
      }
    }
    join.addConditioncollectionName, keyColumnNames, " = ?" );
    //if ( persister.hasWhere() ) join.addCondition( persister.getSQLWhereString(collectionName) );
    EntityType elemType = EntityType collectionElementType;
    addFromelementName, elemType.getAssociatedEntityName(), join );

  }

  String getPathAlias(String path) {
    return String pathAliases.getpath );
  }

  JoinSequence getPathJoin(String path) {
    return JoinSequence pathJoins.getpath );
  }

  void addPathAliasAndJoin(String path, String alias, JoinSequence joinSequence) {
    pathAliases.putpath, alias );
    pathJoins.putpath, joinSequence );
  }

  public List list(SessionImplementor session, QueryParameters queryParameters)
      throws HibernateException {
    return listsession, queryParameters, getQuerySpaces(), actualReturnTypes );
  }

  /**
   * Return the query results as an iterator
   */
  public Iterator iterate(QueryParameters queryParameters, EventSource session)
      throws HibernateException {

    boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
    long startTime = 0;
    if stats startTime = System.currentTimeMillis();

    try {

      PreparedStatement st = prepareQueryStatementqueryParameters, false, session );
      ResultSet rs = getResultSetst, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session );
      HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
      Iterator result = new IteratorImplrs, st, session, returnTypes, getColumnNames(), hi );

      if stats ) {
        session.getFactory().getStatisticsImplementor().queryExecuted(
            "HQL: " + queryString,
            0,
            System.currentTimeMillis() - startTime
          );
      }

      return result;

    }
    catch SQLException sqle ) {
      throw JDBCExceptionHelper.convert(
          getFactory().getSQLExceptionConverter(),
          sqle,
          "could not execute query using iterate",
          getSQLString()
        );
    }

  }

  public int executeUpdate(QueryParameters queryParameters, SessionImplementor sessionthrows HibernateException {
    throw new UnsupportedOperationException"Not supported!  Use the AST translator...");
  }

  protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
      throws SQLException, HibernateException {
    row = toResultRowrow );
    if hasScalars ) {
      String[][] scalarColumns = getColumnNames();
      int queryCols = returnTypes.length;
      if holderClass == null && queryCols == ) {
        return returnTypes[0].nullSafeGetrs, scalarColumns[0], session, null );
      }
      else {
        row = new Object[queryCols];
        for int i = 0; i < queryCols; i++ )
          row[i= returnTypes[i].nullSafeGetrs, scalarColumns[i], session, null );
        return row;
      }
    }
    else if holderClass == null ) {
      return row.length == ? row[0: row;
    }
    else {
      return row;
    }

  }

  protected List getResultList(List results, ResultTransformer resultTransformerthrows QueryException {
    if holderClass != null ) {
      for int i = 0; i < results.size(); i++ ) {
        Object[] row = Object[] ) results.get);
        try {
          results.seti, holderConstructor.newInstancerow ) );
        }
        catch Exception e ) {
          throw new QueryException"could not instantiate: " + holderClass, e );
        }
      }
    }
    return results;
  }

  private Object[] toResultRow(Object[] row) {
    if selectLength == row.length ) {
      return row;
    }
    else {
      Object[] result = new Object[selectLength];
      int j = 0;
      for int i = 0; i < row.length; i++ ) {
        if includeInSelect[i] ) result[j++= row[i];
      }
      return result;
    }
  }

  void setHolderClass(Class clazz) {
    holderClass = clazz;
  }

  protected LockMode[] getLockModes(Map lockModes) {
    // unfortunately this stuff can't be cached because
    // it is per-invocation, not constant for the
    // QueryTranslator instance
    HashMap nameLockModes = new HashMap();
    if lockModes != null ) {
      Iterator iter = lockModes.entrySet().iterator();
      while iter.hasNext() ) {
        Map.Entry me = Map.Entry iter.next();
        nameLockModes.putgetAliasName( ( String me.getKey() ),
            me.getValue() );
      }
    }
    LockMode[] lockModeArray = new LockMode[names.length];
    for int i = 0; i < names.length; i++ ) {
      LockMode lm = LockMode nameLockModes.getnames[i] );
      if lm == null lm = LockMode.NONE;
      lockModeArray[i= lm;
    }
    return lockModeArray;
  }

  protected String applyLocks(String sql, Map lockModes, Dialect dialectthrows QueryException {
    // can't cache this stuff either (per-invocation)
    final String result;
    if lockModes == null || lockModes.size() == ) {
      result = sql;
    }
    else {
      Map aliasedLockModes = new HashMap();
      Iterator iter = lockModes.entrySet().iterator();
      while iter.hasNext() ) {
        Map.Entry me = Map.Entry iter.next();
        aliasedLockModes.putgetAliasName( ( String me.getKey() ), me.getValue() );
      }
      Map keyColumnNames = null;
      if dialect.forUpdateOfColumns() ) {
        keyColumnNames = new HashMap();
        for int i = 0; i < names.length; i++ ) {
          keyColumnNames.putnames[i], persisters[i].getIdentifierColumnNames() );
        }
      }
      result = dialect.applyLocksToSqlsql, aliasedLockModes, keyColumnNames );
    }
    logQueryqueryString, result );
    return result;
  }

  protected boolean upgradeLocks() {
    return true;
  }

  protected int[] getCollectionOwners() {
    return new int[] { collectionOwnerColumn };
  }

  protected boolean isCompiled() {
    return compiled;
  }

  public String toString() {
    return queryString;
  }

  protected int[] getOwners() {
    return owners;
  }

  protected EntityType[] getOwnerAssociationTypes() {
    return ownerAssociationTypes;
  }

  public Class getHolderClass() {
    return holderClass;
  }

  public Map getEnabledFilters() {
    return enabledFilters;
  }

  public ScrollableResults scroll(final QueryParameters queryParameters,
                  final SessionImplementor session)
      throws HibernateException {
    HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
    return scrollqueryParameters, returnTypes, hi, session );
  }

  public String getQueryIdentifier() {
    return queryIdentifier;
  }

  protected boolean isSubselectLoadingEnabled() {
    return hasSubselectLoadableCollections();
  }

  public void validateScrollability() throws HibernateException {
    // This is the legacy behaviour for HQL queries...
    if getCollectionPersisters() != null ) {
      throw new HibernateException"Cannot scroll queries which initialize collections" );
    }
  }

  public boolean containsCollectionFetches() {
    return false;
  }

  public boolean isManipulationStatement() {
    // classic parser does not support bulk manipulation statements
    return false;
  }

  public ParameterTranslations getParameterTranslations() {
    return new ParameterTranslations() {

      public boolean supportsOrdinalParameterMetadata() {
        // classic translator does not support collection of ordinal
        // param metadata
        return false;
      }

      public int getOrdinalParameterCount() {
        return 0// not known!
      }

      public int getOrdinalParameterSqlLocation(int ordinalPosition) {
        return 0// not known!
      }

      public Type getOrdinalParameterExpectedType(int ordinalPosition) {
        return null// not known!
      }

      public Set getNamedParameterNames() {
        return namedParameters.keySet();
      }

      public int[] getNamedParameterSqlLocations(String name) {
        return getNamedParameterLocsname );
      }

      public Type getNamedParameterExpectedType(String name) {
        return null// not known!
      }
    };
  }
}