Beispiel #1
0
        public async Task <object> PerformInsertAsync(SqlCommandInfo insertSql, ISessionImplementor session, IBinder binder, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            // NH-2145: Prevent connection releases between insert and select when we cannot perform
            // them as a single statement. Retrieving id most of the time relies on using the same connection.
            session.ConnectionManager.FlushBeginning();
            try
            {
                try
                {
                    // prepare and execute the insert
                    var insert = await(session.Batcher.PrepareCommandAsync(insertSql.CommandType, insertSql.Text, insertSql.ParameterTypes, cancellationToken)).ConfigureAwait(false);
                    try
                    {
                        await(binder.BindValuesAsync(insert, cancellationToken)).ConfigureAwait(false);
                        await(session.Batcher.ExecuteNonQueryAsync(insert, cancellationToken)).ConfigureAwait(false);
                    }
                    finally
                    {
                        session.Batcher.CloseCommand(insert, null);
                    }
                }
                catch (DbException sqle)
                {
                    throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle,
                                                     "could not insert: " + persister.GetInfoString(), insertSql.Text);
                }

                var selectSql = SelectSQL;
                using (session.BeginProcess())
                {
                    try
                    {
                        //fetch the generated id in a separate query
                        var idSelect = await(session.Batcher.PrepareCommandAsync(CommandType.Text, selectSql, ParametersTypes, cancellationToken)).ConfigureAwait(false);
                        try
                        {
                            await(BindParametersAsync(session, idSelect, binder, cancellationToken)).ConfigureAwait(false);
                            var rs = await(session.Batcher.ExecuteReaderAsync(idSelect, cancellationToken)).ConfigureAwait(false);
                            try
                            {
                                return(await(GetResultAsync(session, rs, binder.Entity, cancellationToken)).ConfigureAwait(false));
                            }
                            finally
                            {
                                session.Batcher.CloseReader(rs);
                            }
                        }
                        finally
                        {
                            session.Batcher.CloseCommand(idSelect, null);
                        }
                    }
                    catch (DbException sqle)
                    {
                        throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle,
                                                         "could not retrieve generated id after insert: " + persister.GetInfoString(),
                                                         insertSql.Text);
                    }
                }
            }
            finally
            {
                session.ConnectionManager.FlushEnding();
            }
        }
        protected async Task <List <object> > DoListAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled;
            var  stopWatch    = new Stopwatch();

            if (statsEnabled)
            {
                stopWatch.Start();
            }
            int rowCount = 0;

            var results = new List <object>();

            var hydratedObjects = new List <object> [Translators.Count];

            List <EntityKey[]>[] subselectResultKeys = new List <EntityKey[]> [Translators.Count];
            bool[] createSubselects = new bool[Translators.Count];

            try
            {
                using (var reader = await(resultSetsCommand.GetReaderAsync(_timeout, cancellationToken)).ConfigureAwait(false))
                {
                    if (log.IsDebugEnabled())
                    {
                        log.Debug("Executing {0} queries", translators.Count);
                    }
                    for (int i = 0; i < translators.Count; i++)
                    {
                        ITranslator     translator = Translators[i];
                        QueryParameters parameter  = Parameters[i];

                        int entitySpan = translator.Loader.EntityPersisters.Length;
                        hydratedObjects[i] = entitySpan > 0 ? new List <object>() : null;
                        RowSelection selection = parameter.RowSelection;
                        int          maxRows   = Loader.Loader.HasMaxRows(selection) ? selection.MaxRows : int.MaxValue;
                        if (!dialect.SupportsLimitOffset || !translator.Loader.UseLimit(selection, dialect))
                        {
                            await(Loader.Loader.AdvanceAsync(reader, selection, cancellationToken)).ConfigureAwait(false);
                        }

                        if (parameter.HasAutoDiscoverScalarTypes)
                        {
                            translator.Loader.AutoDiscoverTypes(reader);
                        }

                        LockMode[] lockModeArray     = translator.Loader.GetLockModes(parameter.LockModes);
                        EntityKey  optionalObjectKey = Loader.Loader.GetOptionalObjectKey(parameter, session);

                        createSubselects[i]    = translator.Loader.IsSubselectLoadingEnabled;
                        subselectResultKeys[i] = createSubselects[i] ? new List <EntityKey[]>() : null;

                        translator.Loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session);
                        EntityKey[] keys = new EntityKey[entitySpan];                         // we can reuse it each time

                        if (log.IsDebugEnabled())
                        {
                            log.Debug("processing result set");
                        }

                        IList tempResults = new List <object>();
                        int   count;
                        for (count = 0; count < maxRows && await(reader.ReadAsync(cancellationToken)).ConfigureAwait(false); count++)
                        {
                            if (log.IsDebugEnabled())
                            {
                                log.Debug("result set row: {0}", count);
                            }

                            rowCount++;
                            object result = await(translator.Loader.GetRowFromResultSetAsync(
                                                      reader, session, parameter, lockModeArray, optionalObjectKey, hydratedObjects[i], keys, true, cancellationToken)).ConfigureAwait(false);
                            tempResults.Add(result);

                            if (createSubselects[i])
                            {
                                subselectResultKeys[i].Add(keys);
                                keys = new EntityKey[entitySpan];                                 //can't reuse in this case
                            }
                        }

                        if (log.IsDebugEnabled())
                        {
                            log.Debug("done processing result set ({0} rows)", count);
                        }

                        results.Add(tempResults);

                        if (log.IsDebugEnabled())
                        {
                            log.Debug("Query {0} returned {1} results", i, tempResults.Count);
                        }

                        await(reader.NextResultAsync(cancellationToken)).ConfigureAwait(false);
                    }

                    for (int i = 0; i < translators.Count; i++)
                    {
                        ITranslator     translator = translators[i];
                        QueryParameters parameter  = parameters[i];

                        await(translator.Loader.InitializeEntitiesAndCollectionsAsync(hydratedObjects[i], reader, session, false, cancellationToken)).ConfigureAwait(false);

                        if (createSubselects[i])
                        {
                            translator.Loader.CreateSubselects(subselectResultKeys[i], parameter, session);
                        }
                    }
                }
            }
            catch (Exception sqle)
            {
                log.Error(sqle, "Failed to execute multi query: [{0}]", resultSetsCommand.Sql);
                throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "Failed to execute multi query", resultSetsCommand.Sql);
            }

            if (statsEnabled)
            {
                stopWatch.Stop();
                session.Factory.StatisticsImplementor.QueryExecuted(string.Format("{0} queries (MultiQuery)", translators.Count), rowCount, stopWatch.Elapsed);
            }
            return(results);
        }
Beispiel #3
0
        public override async Task <int> ExecuteAsync(QueryParameters parameters, ISessionImplementor session, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            CoordinateSharedCacheCleanup(session);

            await(CreateTemporaryTableIfNecessaryAsync(persister, session, cancellationToken)).ConfigureAwait(false);

            try
            {
                // First, save off the pertinent ids, saving the number of pertinent ids for return
                DbCommand ps = null;
                int       resultCount;
                try
                {
                    try
                    {
                        var       paramsSpec             = Walker.Parameters;
                        var       sqlString              = FilterHelper.ExpandDynamicFilterParameters(idInsertSelect, paramsSpec, session);
                        var       sqlQueryParametersList = sqlString.GetParameters().ToList();
                        SqlType[] parameterTypes         = paramsSpec.GetQueryParameterTypes(sqlQueryParametersList, session.Factory);

                        ps = await(session.Batcher.PrepareCommandAsync(CommandType.Text, sqlString, parameterTypes, cancellationToken)).ConfigureAwait(false);
                        foreach (var parameterSpecification in paramsSpec)
                        {
                            await(parameterSpecification.BindAsync(ps, sqlQueryParametersList, parameters, session, cancellationToken)).ConfigureAwait(false);
                        }

                        resultCount = await(session.Batcher.ExecuteNonQueryAsync(ps, cancellationToken)).ConfigureAwait(false);
                    }
                    finally
                    {
                        if (ps != null)
                        {
                            session.Batcher.CloseCommand(ps, null);
                        }
                    }
                }
                catch (DbException e)
                {
                    throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not insert/select ids for bulk delete", idInsertSelect);
                }

                // Start performing the deletes
                for (int i = 0; i < deletes.Length; i++)
                {
                    try
                    {
                        try
                        {
                            ps = await(session.Batcher.PrepareCommandAsync(CommandType.Text, deletes[i], Array.Empty <SqlType>(), cancellationToken)).ConfigureAwait(false);
                            await(session.Batcher.ExecuteNonQueryAsync(ps, cancellationToken)).ConfigureAwait(false);
                        }
                        finally
                        {
                            if (ps != null)
                            {
                                session.Batcher.CloseCommand(ps, null);
                            }
                        }
                    }
                    catch (DbException e)
                    {
                        throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "error performing bulk delete", deletes[i]);
                    }
                }

                return(resultCount);
            }
            finally
            {
                await(DropTemporaryTableIfNecessaryAsync(persister, session, cancellationToken)).ConfigureAwait(false);
            }
        }
        public object PerformInsert(SqlCommandInfo insertSql, ISessionImplementor session, IBinder binder)
        {
            // NH-2145: Prevent connection releases between insert and select when we cannot perform
            // them as a single statement. Retrieving id most of the time relies on using the same connection.
            session.ConnectionManager.FlushBeginning();
            try
            {
                try
                {
                    // prepare and execute the insert
                    var insert = session.Batcher.PrepareCommand(insertSql.CommandType, insertSql.Text, insertSql.ParameterTypes);
                    try
                    {
                        binder.BindValues(insert);
                        session.Batcher.ExecuteNonQuery(insert);
                    }
                    finally
                    {
                        session.Batcher.CloseCommand(insert, null);
                    }
                }
                catch (DbException sqle)
                {
                    throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle,
                                                     "could not insert: " + persister.GetInfoString(), insertSql.Text);
                }

                var selectSql = SelectSQL;
                using (new SessionIdLoggingContext(session.SessionId))
                {
                    try
                    {
                        //fetch the generated id in a separate query
                        var idSelect = session.Batcher.PrepareCommand(CommandType.Text, selectSql, ParametersTypes);
                        try
                        {
                            BindParameters(session, idSelect, binder.Entity);
                            var rs = session.Batcher.ExecuteReader(idSelect);
                            try
                            {
                                return(GetResult(session, rs, binder.Entity));
                            }
                            finally
                            {
                                session.Batcher.CloseReader(rs);
                            }
                        }
                        finally
                        {
                            session.Batcher.CloseCommand(idSelect, null);
                        }
                    }
                    catch (DbException sqle)
                    {
                        throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle,
                                                         "could not retrieve generated id after insert: " + persister.GetInfoString(),
                                                         insertSql.Text);
                    }
                }
            }
            finally
            {
                session.ConnectionManager.FlushEnding();
            }
        }
        protected override int DoUpdateRows(object id, IPersistentCollection collection, ISessionImplementor session)
        {
            // we finish all the "removes" first to take care of possible unique
            // constraints and so that we can take better advantage of batching
            try
            {
                const int offset = 0;
                int       count  = 0;

                if (RowDeleteEnabled)
                {
                    IExpectation   deleteExpectation = Expectations.AppropriateExpectation(DeleteCheckStyle);
                    bool           useBatch          = deleteExpectation.CanBeBatched;
                    SqlCommandInfo sql = SqlDeleteRowString;
                    IDbCommand     st  = null;
                    // update removed rows fks to null
                    try
                    {
                        int         i       = 0;
                        IEnumerable entries = collection.Entries(this);

                        foreach (object entry in entries)
                        {
                            if (collection.NeedsUpdating(entry, i, ElementType))
                            {
                                // will still be issued when it used to be null
                                if (useBatch)
                                {
                                    st = session.Batcher.PrepareBatchCommand(SqlDeleteRowString.CommandType, sql.Text,
                                                                             SqlDeleteRowString.ParameterTypes);
                                }
                                else
                                {
                                    st = session.Batcher.PrepareCommand(SqlDeleteRowString.CommandType, sql.Text,
                                                                        SqlDeleteRowString.ParameterTypes);
                                }

                                int loc = WriteKey(st, id, offset, session);
                                WriteElementToWhere(st, collection.GetSnapshotElement(entry, i), loc, session);
                                if (useBatch)
                                {
                                    session.Batcher.AddToBatch(deleteExpectation);
                                }
                                else
                                {
                                    deleteExpectation.VerifyOutcomeNonBatched(session.Batcher.ExecuteNonQuery(st), st);
                                }
                                count++;
                            }
                            i++;
                        }
                    }
                    catch (Exception e)
                    {
                        if (useBatch)
                        {
                            session.Batcher.AbortBatch(e);
                        }
                        throw;
                    }
                    finally
                    {
                        if (!useBatch && st != null)
                        {
                            session.Batcher.CloseCommand(st, null);
                        }
                    }
                }

                if (RowInsertEnabled)
                {
                    IExpectation insertExpectation = Expectations.AppropriateExpectation(InsertCheckStyle);
                    //bool callable = InsertCallable;
                    bool           useBatch = insertExpectation.CanBeBatched;
                    SqlCommandInfo sql      = SqlInsertRowString;
                    IDbCommand     st       = null;

                    // now update all changed or added rows fks
                    try
                    {
                        int         i       = 0;
                        IEnumerable entries = collection.Entries(this);
                        foreach (object entry in entries)
                        {
                            if (collection.NeedsUpdating(entry, i, ElementType))
                            {
                                if (useBatch)
                                {
                                    st = session.Batcher.PrepareBatchCommand(SqlInsertRowString.CommandType, sql.Text,
                                                                             SqlInsertRowString.ParameterTypes);
                                }
                                else
                                {
                                    st = session.Batcher.PrepareCommand(SqlInsertRowString.CommandType, sql.Text,
                                                                        SqlInsertRowString.ParameterTypes);
                                }

                                //offset += insertExpectation.Prepare(st, Factory.ConnectionProvider.Driver);
                                int loc = WriteKey(st, id, offset, session);
                                if (HasIndex && !indexContainsFormula)
                                {
                                    loc = WriteIndexToWhere(st, collection.GetIndex(entry, i, this), loc, session);
                                }
                                WriteElementToWhere(st, collection.GetElement(entry), loc, session);
                                if (useBatch)
                                {
                                    session.Batcher.AddToBatch(insertExpectation);
                                }
                                else
                                {
                                    insertExpectation.VerifyOutcomeNonBatched(session.Batcher.ExecuteNonQuery(st), st);
                                }
                                count++;
                            }
                            i++;
                        }
                    }
                    catch (Exception e)
                    {
                        if (useBatch)
                        {
                            session.Batcher.AbortBatch(e);
                        }
                        throw;
                    }
                    finally
                    {
                        if (!useBatch && st != null)
                        {
                            session.Batcher.CloseCommand(st, null);
                        }
                    }
                }
                return(count);
            }
            catch (DbException sqle)
            {
                throw ADOExceptionHelper.Convert(SQLExceptionConverter, sqle, "could not update collection rows: " + MessageHelper.InfoString(this, id));
            }
        }
Beispiel #6
0
        public void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted)
        {
            DbConnection  connection = null;
            DbTransaction trans      = null;

            // bool wasAutoCommit = false;
            try
            {
                // We make an exception for SQLite and use the session's connection,
                // since SQLite only allows one connection to the database.
                if (session.Factory.Dialect is SQLiteDialect)
                {
                    connection = session.Connection;
                }
                else
                {
                    connection = session.Factory.ConnectionProvider.GetConnection();
                }

                if (transacted)
                {
                    trans = connection.BeginTransaction();
                    // TODO NH: a way to read the autocommit state is needed
                    //if (TransactionManager.GetAutoCommit(connection))
                    //{
                    //  wasAutoCommit = true;
                    //  TransactionManager.SetAutoCommit(connection, false);
                    //}
                }

                work.DoWork(connection, trans);

                if (transacted)
                {
                    trans.Commit();
                    //TransactionManager.Commit(connection);
                }
            }
            catch (Exception t)
            {
                using (new SessionIdLoggingContext(session.SessionId))
                {
                    try
                    {
                        if (trans != null && connection.State != ConnectionState.Closed)
                        {
                            trans.Rollback();
                        }
                    }
                    catch (Exception ignore)
                    {
                        isolaterLog.Debug("unable to release connection on exception [" + ignore + "]");
                    }

                    if (t is HibernateException)
                    {
                        throw;
                    }
                    else if (t is DbException)
                    {
                        throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t,
                                                         "error performing isolated work");
                    }
                    else
                    {
                        throw new HibernateException("error performing isolated work", t);
                    }
                }
            }
            finally
            {
                //if (transacted && wasAutoCommit)
                //{
                //  try
                //  {
                //    // TODO NH: reset autocommit
                //    // TransactionManager.SetAutoCommit(connection, true);
                //  }
                //  catch (Exception)
                //  {
                //    log.Debug("was unable to reset connection back to auto-commit");
                //  }
                //}
                if (session.Factory.Dialect is SQLiteDialect == false)
                {
                    session.Factory.ConnectionProvider.CloseConnection(connection);
                }
            }
        }
Beispiel #7
0
        public override int Execute(QueryParameters parameters, ISessionImplementor session)
        {
            CoordinateSharedCacheCleanup(session);

            CreateTemporaryTableIfNecessary(persister, session);

            try
            {
                // First, save off the pertinent ids, saving the number of pertinent ids for return
                DbCommand ps = null;
                int       resultCount;
                try
                {
                    try
                    {
                        var       paramsSpec             = Walker.Parameters;
                        var       sqlQueryParametersList = idInsertSelect.GetParameters().ToList();
                        SqlType[] parameterTypes         = paramsSpec.GetQueryParameterTypes(sqlQueryParametersList, session.Factory);

                        ps = session.Batcher.PrepareCommand(CommandType.Text, idInsertSelect, parameterTypes);
                        foreach (var parameterSpecification in paramsSpec)
                        {
                            parameterSpecification.Bind(ps, sqlQueryParametersList, parameters, session);
                        }

                        resultCount = session.Batcher.ExecuteNonQuery(ps);
                    }
                    finally
                    {
                        if (ps != null)
                        {
                            session.Batcher.CloseCommand(ps, null);
                        }
                    }
                }
                catch (DbException e)
                {
                    throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not insert/select ids for bulk delete", idInsertSelect);
                }

                // Start performing the deletes
                for (int i = 0; i < deletes.Length; i++)
                {
                    try
                    {
                        try
                        {
                            ps = session.Batcher.PrepareCommand(CommandType.Text, deletes[i], new SqlType[0]);
                            session.Batcher.ExecuteNonQuery(ps);
                        }
                        finally
                        {
                            if (ps != null)
                            {
                                session.Batcher.CloseCommand(ps, null);
                            }
                        }
                    }
                    catch (DbException e)
                    {
                        throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "error performing bulk delete", deletes[i]);
                    }
                }

                return(resultCount);
            }
            finally
            {
                DropTemporaryTableIfNecessary(persister, session);
            }
        }
Beispiel #8
0
        public override int Execute(QueryParameters parameters, ISessionImplementor session)
        {
            CoordinateSharedCacheCleanup(session);

            CreateTemporaryTableIfNecessary(persister, session);

            try
            {
                // First, save off the pertinent ids, as the return value
                DbCommand ps = null;
                int       resultCount;
                try
                {
                    try
                    {
                        int parameterStart = Walker.NumberOfParametersInSetClause;

                        IList <IParameterSpecification> allParams = Walker.Parameters;

                        List <IParameterSpecification> whereParams = (new List <IParameterSpecification>(allParams)).GetRange(
                            parameterStart, allParams.Count - parameterStart);

                        var       sqlQueryParametersList = idInsertSelect.GetParameters().ToList();
                        SqlType[] parameterTypes         = whereParams.GetQueryParameterTypes(sqlQueryParametersList, session.Factory);

                        ps = session.Batcher.PrepareCommand(CommandType.Text, idInsertSelect, parameterTypes);
                        foreach (var parameterSpecification in whereParams)
                        {
                            parameterSpecification.Bind(ps, sqlQueryParametersList, parameters, session);
                        }

                        resultCount = session.Batcher.ExecuteNonQuery(ps);
                    }
                    finally
                    {
                        if (ps != null)
                        {
                            session.Batcher.CloseCommand(ps, null);
                        }
                    }
                }
                catch (DbException e)
                {
                    throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not insert/select ids for bulk update",
                                                     idInsertSelect);
                }

                // Start performing the updates
                for (int i = 0; i < updates.Length; i++)
                {
                    if (updates[i] == null)
                    {
                        continue;
                    }
                    try
                    {
                        try
                        {
                            var       sqlQueryParametersList = updates[i].GetParameters().ToList();
                            var       paramsSpec             = hqlParameters[i];
                            SqlType[] parameterTypes         = paramsSpec.GetQueryParameterTypes(sqlQueryParametersList, session.Factory);

                            ps = session.Batcher.PrepareCommand(CommandType.Text, updates[i], parameterTypes);
                            foreach (var parameterSpecification in paramsSpec)
                            {
                                parameterSpecification.Bind(ps, sqlQueryParametersList, parameters, session);
                            }

                            session.Batcher.ExecuteNonQuery(ps);
                        }
                        finally
                        {
                            if (ps != null)
                            {
                                session.Batcher.CloseCommand(ps, null);
                            }
                        }
                    }
                    catch (DbException e)
                    {
                        throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "error performing bulk update", updates[i]);
                    }
                }

                return(resultCount);
            }
            finally
            {
                DropTemporaryTableIfNecessary(persister, session);
            }
        }
Beispiel #9
0
        protected ArrayList DoList()
        {
            bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled;
            var  stopWatch    = new Stopwatch();

            if (statsEnabled)
            {
                stopWatch.Start();
            }
            int rowCount = 0;

            ArrayList results = new ArrayList();

            ArrayList[]          hydratedObjects     = new ArrayList[Translators.Count];
            List <EntityKey[]>[] subselectResultKeys = new List <EntityKey[]> [Translators.Count];
            bool[] createSubselects = new bool[Translators.Count];

            try
            {
                using (var reader = resultSetsCommand.GetReader(commandTimeout != RowSelection.NoValue ? commandTimeout : (int?)null))
                {
                    if (log.IsDebugEnabled)
                    {
                        log.DebugFormat("Executing {0} queries", translators.Count);
                    }
                    for (int i = 0; i < translators.Count; i++)
                    {
                        ITranslator     translator = Translators[i];
                        QueryParameters parameter  = Parameters[i];

                        int entitySpan = translator.Loader.EntityPersisters.Length;
                        hydratedObjects[i] = entitySpan > 0 ? new ArrayList() : null;
                        RowSelection selection = parameter.RowSelection;
                        int          maxRows   = Loader.Loader.HasMaxRows(selection) ? selection.MaxRows : int.MaxValue;
                        if (!dialect.SupportsLimitOffset || !translator.Loader.UseLimit(selection, dialect))
                        {
                            Loader.Loader.Advance(reader, selection);
                        }

                        LockMode[] lockModeArray     = translator.Loader.GetLockModes(parameter.LockModes);
                        EntityKey  optionalObjectKey = Loader.Loader.GetOptionalObjectKey(parameter, session);

                        createSubselects[i]    = translator.Loader.IsSubselectLoadingEnabled;
                        subselectResultKeys[i] = createSubselects[i] ? new List <EntityKey[]>() : null;

                        translator.Loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session);
                        EntityKey[] keys = new EntityKey[entitySpan];                         // we can reuse it each time

                        if (log.IsDebugEnabled)
                        {
                            log.Debug("processing result set");
                        }

                        IList tempResults = new ArrayList();
                        int   count;
                        for (count = 0; count < maxRows && reader.Read(); count++)
                        {
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("result set row: " + count);
                            }

                            rowCount++;
                            object result = translator.Loader.GetRowFromResultSet(
                                reader, session, parameter, lockModeArray, optionalObjectKey, hydratedObjects[i], keys, true);
                            tempResults.Add(result);

                            if (createSubselects[i])
                            {
                                subselectResultKeys[i].Add(keys);
                                keys = new EntityKey[entitySpan];                                 //can't reuse in this case
                            }
                        }

                        if (log.IsDebugEnabled)
                        {
                            log.Debug(string.Format("done processing result set ({0} rows)", count));
                        }

                        results.Add(tempResults);

                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat("Query {0} returned {1} results", i, tempResults.Count);
                        }

                        reader.NextResult();
                    }

                    for (int i = 0; i < translators.Count; i++)
                    {
                        ITranslator     translator = translators[i];
                        QueryParameters parameter  = parameters[i];

                        translator.Loader.InitializeEntitiesAndCollections(hydratedObjects[i], reader, session, false);

                        if (createSubselects[i])
                        {
                            translator.Loader.CreateSubselects(subselectResultKeys[i], parameter, session);
                        }
                    }
                }
            }
            catch (Exception sqle)
            {
                var message = string.Format("Failed to execute multi query: [{0}]", resultSetsCommand.Sql);
                log.Error(message, sqle);
                throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "Failed to execute multi query", resultSetsCommand.Sql);
            }

            if (statsEnabled)
            {
                stopWatch.Stop();
                session.Factory.StatisticsImplementor.QueryExecuted(string.Format("{0} queries (MultiQuery)", translators.Count), rowCount, stopWatch.Elapsed);
            }
            return(results);
        }