From: <fab...@us...> - 2011-06-15 23:31:24
|
Revision: 5932 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5932&view=rev Author: fabiomaulo Date: 2011-06-15 23:31:17 +0000 (Wed, 15 Jun 2011) Log Message: ----------- Refactoring to have common PrepareQueryCommand (as before) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaLoader.cs trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs trunk/nhibernate/src/NHibernate/Loader/Custom/ICustomQuery.cs trunk/nhibernate/src/NHibernate/Loader/Loader.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -454,51 +454,5 @@ return new SqlCommandImpl(sqlString, parameterSpecs, queryParameters, session.Factory); } - - /// <summary> - /// Obtain an <c>IDbCommand</c> with all parameters pre-bound. Bind positional parameters, - /// named parameters, and limit parameters. - /// </summary> - /// <remarks> - /// Creates an IDbCommand object and populates it with the values necessary to execute it against the - /// database to Load an Entity. - /// </remarks> - /// <param name="queryParameters">The <see cref="QueryParameters"/> to use for the IDbCommand.</param> - /// <param name="scroll">TODO: find out where this is used...</param> - /// <param name="session">The SessionImpl this Command is being prepared in.</param> - /// <returns>A CommandWrapper wrapping an IDbCommand that is ready to be executed.</returns> - protected internal override IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, ISessionImplementor session) - { - var sqlCommand = CreateSqlCommand(queryParameters, session); - var sqlString = sqlCommand.Query; - - sqlCommand.ResetParametersIndexesForTheCommand(0); - IDbCommand command = session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, sqlCommand.ParameterTypes); - - try - { - RowSelection selection = queryParameters.RowSelection; - if (selection != null && selection.Timeout != RowSelection.NoValue) - { - command.CommandTimeout = selection.Timeout; - } - - sqlCommand.Bind(command, session); - - session.Batcher.ExpandQueryParameters(command, sqlString); - } - catch (HibernateException) - { - session.Batcher.CloseCommand(command, null); - throw; - } - catch (Exception sqle) - { - session.Batcher.CloseCommand(command, null); - ADOExceptionReporter.LogExceptions(sqle); - throw; - } - return command; - } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -324,52 +324,6 @@ } /// <summary> - /// Obtain an <c>IDbCommand</c> with all parameters pre-bound. Bind positional parameters, - /// named parameters, and limit parameters. - /// </summary> - /// <remarks> - /// Creates an IDbCommand object and populates it with the values necessary to execute it against the - /// database to Load an Entity. - /// </remarks> - /// <param name="queryParameters">The <see cref="QueryParameters"/> to use for the IDbCommand.</param> - /// <param name="scroll">TODO: find out where this is used...</param> - /// <param name="session">The SessionImpl this Command is being prepared in.</param> - /// <returns>A CommandWrapper wrapping an IDbCommand that is ready to be executed.</returns> - protected internal override IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, ISessionImplementor session) - { - var sqlCommand = CreateSqlCommand(queryParameters, session); - var query = sqlCommand.Query; - - sqlCommand.ResetParametersIndexesForTheCommand(0); - IDbCommand command = session.Batcher.PrepareQueryCommand(CommandType.Text, query, sqlCommand.ParameterTypes); - - try - { - RowSelection selection = queryParameters.RowSelection; - if (selection != null && selection.Timeout != RowSelection.NoValue) - { - command.CommandTimeout = selection.Timeout; - } - - sqlCommand.Bind(command, session); - - session.Batcher.ExpandQueryParameters(command, query); - } - catch (HibernateException) - { - session.Batcher.CloseCommand(command, null); - throw; - } - catch (Exception sqle) - { - session.Batcher.CloseCommand(command, null); - ADOExceptionReporter.LogExceptions(sqle); - throw; - } - return command; - } - - /// <summary> /// Compile a "normal" query. This method may be called multiple /// times. Subsequent invocations are no-ops. /// </summary> Modified: trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -865,7 +865,7 @@ var sqlQueryImpl = (SqlQueryImpl) sqlQuery; NativeSQLQuerySpecification sqlQuerySpec = sqlQueryImpl.GenerateQuerySpecification(sqlQueryImpl.NamedParams); var sqlCustomQuery = new SQLCustomQuery(sqlQuerySpec.SqlQueryReturns, sqlQuerySpec.QueryString, sqlQuerySpec.QuerySpaces, sessionFactory); - loader = new CustomLoader(sqlCustomQuery, sqlCustomQuery.CollectedParametersSpecifications, sessionFactory); + loader = new CustomLoader(sqlCustomQuery, sessionFactory); } public IType[] ReturnTypes Modified: trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaLoader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaLoader.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaLoader.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -201,52 +201,6 @@ return new SqlCommandImpl(sqlString, parameterSpecs, queryParameters, session.Factory); } - /// <summary> - /// Obtain an <c>IDbCommand</c> with all parameters pre-bound. Bind positional parameters, - /// named parameters, and limit parameters. - /// </summary> - /// <remarks> - /// Creates an IDbCommand object and populates it with the values necessary to execute it against the - /// database to Load an Entity. - /// </remarks> - /// <param name="queryParameters">The <see cref="QueryParameters"/> to use for the IDbCommand.</param> - /// <param name="scroll">TODO: find out where this is used...</param> - /// <param name="session">The SessionImpl this Command is being prepared in.</param> - /// <returns>A CommandWrapper wrapping an IDbCommand that is ready to be executed.</returns> - protected internal override IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, ISessionImplementor session) - { - var sqlCommand = CreateSqlCommand(queryParameters, session); - var sqlString = sqlCommand.Query; - - sqlCommand.ResetParametersIndexesForTheCommand(0); - IDbCommand command = session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, sqlCommand.ParameterTypes); - - try - { - RowSelection selection = queryParameters.RowSelection; - if (selection != null && selection.Timeout != RowSelection.NoValue) - { - command.CommandTimeout = selection.Timeout; - } - - sqlCommand.Bind(command, session); - - session.Batcher.ExpandQueryParameters(command, sqlString); - } - catch (HibernateException) - { - session.Batcher.CloseCommand(command, null); - throw; - } - catch (Exception sqle) - { - session.Batcher.CloseCommand(command, null); - ADOExceptionReporter.LogExceptions(sqle); - throw; - } - return command; - } - public override int[] GetNamedParameterLocs(string name) { return new int[0]; Modified: trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -43,17 +43,12 @@ private IType[] resultTypes; private string[] transformerAliases; - public CustomLoader(ICustomQuery customQuery, IEnumerable<IParameterSpecification> parametersSpecifications, ISessionFactoryImplementor factory) - : this(customQuery, factory) - { - this.parametersSpecifications = parametersSpecifications.ToList(); - } - public CustomLoader(ICustomQuery customQuery, ISessionFactoryImplementor factory) : base(factory) { sql = customQuery.SQL; querySpaces.AddAll(customQuery.QuerySpaces); namedParameterBindPoints = customQuery.NamedParameterBindPoints; + this.parametersSpecifications = customQuery.CollectedParametersSpecifications.ToList(); List<IQueryable> entitypersisters = new List<IQueryable>(); List<int> entityowners = new List<int>(); @@ -350,10 +345,6 @@ public override ISqlCommand CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session) { - if(parametersSpecifications == null) - { - throw new InvalidOperationException("The custom SQL loader was not initialized with Parameters Specifications."); - } // A distinct-copy of parameter specifications collected during query construction var parameterSpecs = new HashSet<IParameterSpecification>(parametersSpecifications); SqlString sqlString = SqlString.Copy(); Modified: trunk/nhibernate/src/NHibernate/Loader/Custom/ICustomQuery.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Custom/ICustomQuery.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Loader/Custom/ICustomQuery.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -1,5 +1,6 @@ using System.Collections.Generic; using Iesi.Collections.Generic; +using NHibernate.Param; using NHibernate.SqlCommand; namespace NHibernate.Loader.Custom @@ -42,5 +43,7 @@ /// ADO result set to be expected and how to map this result set. /// </summary> IList<IReturn> CustomQueryReturns { get; } + + IEnumerable<IParameterSpecification> CollectedParametersSpecifications { get; } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-06-15 20:04:47 UTC (rev 5931) +++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-06-15 23:31:17 UTC (rev 5932) @@ -1136,83 +1136,25 @@ /// <param name="scroll">TODO: find out where this is used...</param> /// <param name="session">The SessionImpl this Command is being prepared in.</param> /// <returns>A CommandWrapper wrapping an IDbCommand that is ready to be executed.</returns> - protected internal virtual IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, - ISessionImplementor session) + protected internal virtual IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, ISessionImplementor session) { - SqlString sqlString = ProcessFilters(queryParameters, session); - Dialect.Dialect dialect = session.Factory.Dialect; + ISqlCommand sqlCommand = CreateSqlCommand(queryParameters, session); + SqlString sqlString = sqlCommand.Query; - RowSelection selection = queryParameters.RowSelection; - bool useLimit = UseLimit(selection, dialect); - bool hasFirstRow = GetFirstRow(selection) > 0; - bool useOffset = hasFirstRow && useLimit && dialect.SupportsLimitOffset; - int startIndex = GetFirstLimitParameterCount(dialect, useLimit, hasFirstRow, useOffset); - // TODO NH bool callable = queryParameters.Callable; + sqlCommand.ResetParametersIndexesForTheCommand(0); + IDbCommand command = session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, sqlCommand.ParameterTypes); - SqlType[] parameterTypes = queryParameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, startIndex, useLimit, useOffset); - - if (useLimit) - { - int? offset = GetOffsetUsingDialect(selection, dialect); - int? limit = GetLimitUsingDialect(selection, dialect); - Parameter offsetParameter = queryParameters.OffsetParameterIndex.HasValue ? Parameter.WithIndex(queryParameters.OffsetParameterIndex.Value) : null; - Parameter limitParameter = queryParameters.LimitParameterIndex.HasValue ? Parameter.WithIndex(queryParameters.LimitParameterIndex.Value) : null; - sqlString = - dialect.GetLimitString( - sqlString.Trim(), - useOffset ? offset : null, - limit, - useOffset ? offsetParameter : null, - limitParameter); - } - - sqlString = PreprocessSQL(sqlString, queryParameters, dialect); - - // TODO NH: Callable for SP -> PrepareCallableQueryCommand - IDbCommand command = - session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, parameterTypes); - try { - // Added in NH - not in H2.1 + RowSelection selection = queryParameters.RowSelection; if (selection != null && selection.Timeout != RowSelection.NoValue) { command.CommandTimeout = selection.Timeout; } - int colIndex = 0; + sqlCommand.Bind(command, session); - if (useLimit && dialect.BindLimitParametersFirst) - { - colIndex += BindLimitParameters(command, colIndex, selection, session); - } - // TODO NH - //if (callable) - //{ - // colIndex = dialect.RegisterResultSetOutParameter(command, col); - //} - - colIndex += BindParameterValues(command, queryParameters, colIndex, session); - - if (useLimit && !dialect.BindLimitParametersFirst) - { - BindLimitParameters(command, colIndex, selection, session); - } - session.Batcher.ExpandQueryParameters(command, sqlString); - - if (!useLimit) - { - SetMaxRows(command, selection); - } - if (selection != null) - { - if (selection.Timeout != RowSelection.NoValue) - { - command.CommandTimeout = selection.Timeout; - } - // H2.1 handles FetchSize here - not ported - } } catch (HibernateException) { @@ -1225,7 +1167,6 @@ ADOExceptionReporter.LogExceptions(sqle); throw; } - return command; } @@ -1758,9 +1699,43 @@ public virtual ISqlCommand CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session) { - throw new NotSupportedException("This loader does not support extraction of single command."); + // The implementation of this method is itended to be used just for "internal" command (not for queries coming from users) + // Internally NH creates various commands, all using just positional-parameters, to then potentially apply dynamic-filters and pagination. + // In practice this method should be overriden by those loaders representing a user-query as CriteriaLoader, QueryLoader, classic QueryTraslator, CustomLoader (for custmon SQL queries). + + // A distinct-copy of parameter specifications collected during query construction + var parameterSpecs = new HashSet<IParameterSpecification>(GetParameterSpecifications(queryParameters, session.Factory)); + SqlString sqlString = SqlString.Copy(); + + // dynamic-filter parameters: during the HQL->SQL parsing, filters can be added as SQL_TOKEN/string and the SqlGenerator will not find it + sqlString = ExpandDynamicFilterParameters(sqlString, parameterSpecs, session); + AdjustQueryParametersForSubSelectFetching(sqlString, parameterSpecs, session, queryParameters); // NOTE: see TODO below + + sqlString = AddLimitsParametersIfNeeded(sqlString, parameterSpecs, queryParameters, session); + // TODO: for sub-select fetching we have to try to assign the QueryParameter.ProcessedSQL here (with limits) but only after use IParameterSpecification for any kind of queries + + // The PreprocessSQL method can modify the SqlString but should never add parameters (or we have to override it) + sqlString = PreprocessSQL(sqlString, queryParameters, session.Factory.Dialect); + + return new SqlCommandImpl(sqlString, parameterSpecs, queryParameters, session.Factory); } + protected IEnumerable<IParameterSpecification> GetParameterSpecifications(QueryParameters queryParameters, ISessionFactoryImplementor sessionFactory) + { + // TODO FM: remove this implementation and put an abstract ParameterSpecifications in the Loader (each concrete implementation have to expose it) => NH1990, SubselectFetchFixture + var positionalSpecifications = queryParameters.PositionalParameterTypes.Select((t, i) => (IParameterSpecification)new PositionalParameterSpecification(1, 0, i) { ExpectedType = t }); + var namedSpecifications = queryParameters.NamedParameters != null ? queryParameters.NamedParameters.Select(np => (IParameterSpecification)new NamedParameterSpecification(1, 0, np.Key) { ExpectedType = np.Value.Type }): Enumerable.Empty<IParameterSpecification>(); + var specifications= positionalSpecifications.Concat(namedSpecifications).ToList(); + var parameters = SqlString.GetParameters().ToArray(); + var sqlParameterPos = 0; + var paramTrackers = specifications.SelectMany(specification => specification.GetIdsForBackTrack(sessionFactory)); + foreach (var paramTracker in paramTrackers) + { + parameters[sqlParameterPos++].BackTrack = paramTracker; + } + return specifications; + } + protected void AdjustQueryParametersForSubSelectFetching(SqlString sqlString, IEnumerable<IParameterSpecification> parameterSpecs, ISessionImplementor session, QueryParameters queryParameters) { // TODO: Remove this when all parameters are managed using IParameterSpecification (QueryParameters does not need to have decomposed values for filters) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |