public QuerySelect copy() {
   QuerySelect copy = new QuerySelect(dialect);
   copy.joins = this.joins.copy();
   copy.select.append(this.select.toString());
   copy.where.append(this.where.toString());
   copy.groupBy.append(this.groupBy.toString());
   copy.orderBy.append(this.orderBy.toString());
   copy.having.append(this.having.toString());
   copy.comment = this.comment;
   copy.distinct = this.distinct;
   return copy;
 }
 private void renderPropertiesSelect(QuerySelect sql) {
   int size = returnedTypes.size();
   for (int k = 0; k < size; k++) {
     String suffix = size == 1 ? "" : Integer.toString(k) + '_';
     String name = (String) returnedTypes.get(k);
     sql.addSelectFragmentString(persisters[k].propertySelectFragment(name, suffix, false));
   }
 }
  private void renderSQL() throws QueryException, MappingException {

    final int rtsize;
    if (returnedTypes.size() == 0 && scalarTypes.size() == 0) {
      // ie no select clause in HQL
      returnedTypes = fromTypes;
      rtsize = returnedTypes.size();
    } else {
      rtsize = returnedTypes.size();
      Iterator iter = entitiesToFetch.iterator();
      while (iter.hasNext()) {
        returnedTypes.add(iter.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(i);
      // if ( !isName(name) ) throw new QueryException("unknown type: " + name);
      persisters[i] = getEntityPersisterForName(name);
      // TODO: cannot use generateSuffixes() - it handles the initial suffix differently.
      suffixes[i] = (size == 1) ? "" : Integer.toString(i) + '_';
      names[i] = name;
      includeInSelect[i] = !entitiesToFetch.contains(name);
      if (includeInSelect[i]) selectLength++;
      if (name.equals(collectionOwnerName)) collectionOwnerColumn = i;
      String oneToOneOwner = (String) oneToOneOwnerNames.get(name);
      owners[i] = (oneToOneOwner == null) ? -1 : returnedTypes.indexOf(oneToOneOwner);
      ownerAssociationTypes[i] = (EntityType) uniqueKeyOwnerReferences.get(name);
    }

    if (ArrayHelper.isAllNegative(owners)) 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[i] = (Type) scalarTypes.get(i);
    }

    QuerySelect sql = new QuerySelect(getFactory().getDialect());
    sql.setDistinct(distinct);

    if (!shallowQuery) {
      renderIdentifierSelect(sql);
      renderPropertiesSelect(sql);
    }

    if (collectionPersister != null) {
      sql.addSelectFragmentString(collectionPersister.selectFragment(fetchName, "__"));
    }

    if (hasScalars || shallowQuery) sql.addSelectFragmentString(scalarSelect);

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

    sql.setWhereTokens(whereTokens.iterator());

    sql.setGroupByTokens(groupByTokens.iterator());
    sql.setHavingTokens(havingTokens.iterator());
    sql.setOrderByTokens(orderByTokens.iterator());

    if (collectionPersister != null && collectionPersister.hasOrdering()) {
      sql.addOrderBy(collectionPersister.getSQLOrderByString(fetchName));
    }

    scalarColumnNames = NameGenerator.generateColumnNames(returnTypes, getFactory());

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

    sqlString = sql.toQueryString();

    if (holderClass != null)
      holderConstructor = ReflectHelper.getConstructor(holderClass, 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++] =
              getFactory()
                  .getTypeResolver()
                  .getTypeFactory()
                  .manyToOne(persisters[i].getEntityName(), shallowQuery);
        }
      }
    }
  }