/** 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 = prepareQueryStatement(queryParameters, false, session);
      ResultSet rs =
          getResultSet(
              st,
              queryParameters.hasAutoDiscoverScalarTypes(),
              false,
              queryParameters.getRowSelection(),
              session);
      HolderInstantiator hi =
          HolderInstantiator.createClassicHolderInstantiator(
              holderConstructor, queryParameters.getResultTransformer());
      Iterator result = new IteratorImpl(rs, 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());
    }
  }
  /** @see LockingStrategy#lock */
  public void lock(Serializable id, Object version, Object object, SessionImplementor session)
      throws StaleObjectStateException, JDBCException {

    SessionFactoryImplementor factory = session.getFactory();
    try {
      PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
      try {
        lockable.getIdentifierType().nullSafeSet(st, id, 1, session);
        if (lockable.isVersioned()) {
          lockable
              .getVersionType()
              .nullSafeSet(
                  st, version, lockable.getIdentifierType().getColumnSpan(factory) + 1, session);
        }

        ResultSet rs = st.executeQuery();
        try {
          if (!rs.next()) {
            if (factory.getStatistics().isStatisticsEnabled()) {
              factory.getStatisticsImplementor().optimisticFailure(lockable.getEntityName());
            }
            throw new StaleObjectStateException(lockable.getEntityName(), id);
          }
        } finally {
          rs.close();
        }
      } finally {
        session.getBatcher().closeStatement(st);
      }

    } catch (SQLException sqle) {
      throw JDBCExceptionHelper.convert(
          session.getFactory().getSQLExceptionConverter(),
          sqle,
          "could not lock: " + MessageHelper.infoString(lockable, id, session.getFactory()),
          sql);
    }
  }
  protected int doUpdateRows(
      Serializable id, PersistentCollection collection, SessionImplementor session)
      throws HibernateException {

    if (ArrayHelper.isAllFalse(elementColumnIsSettable)) return 0;

    try {
      PreparedStatement st = null;
      boolean callable = isUpdateCallable();
      Iterator entries = collection.entries(this);
      try {
        int i = 0;
        int count = 0;
        while (entries.hasNext()) {
          int offset = 1;
          Object entry = entries.next();
          if (collection.needsUpdating(entry, i, elementType)) {
            if (st == null) {
              if (callable) {
                CallableStatement callstatement =
                    session.getBatcher().prepareBatchCallableStatement(getSQLUpdateRowString());
                callstatement.registerOutParameter(
                    offset++,
                    Types
                        .NUMERIC); // TODO: should we require users to return number of update rows
                                   // ? (we cant make it return this without changing
                                   // collectionpersister interface)
                st = callstatement;
              } else {
                st = session.getBatcher().prepareBatchStatement(getSQLUpdateRowString());
              }
            }

            int loc = writeElement(st, collection.getElement(entry), offset, session);
            if (hasIdentifier) {
              loc = writeIdentifier(st, collection.getIdentifier(entry, i), loc, session);
            } else {
              loc = writeKey(st, id, loc, session);
              if (hasIndex && !indexContainsFormula) {
                loc = writeIndexToWhere(st, collection.getIndex(entry, i, this), loc, session);
              } else {
                loc =
                    writeElementToWhere(st, collection.getSnapshotElement(entry, i), loc, session);
              }
            }
            session.getBatcher().addToBatch(1);
            count++;
          }
          i++;
        }
        return count;
      } catch (SQLException sqle) {
        session.getBatcher().abortBatch(sqle);
        throw sqle;
      }
    } catch (SQLException sqle) {
      throw JDBCExceptionHelper.convert(
          getSQLExceptionConverter(),
          sqle,
          "could not update collection rows: "
              + MessageHelper.collectionInfoString(this, id, getFactory()),
          getSQLUpdateRowString());
    }
  }