From: <ric...@us...> - 2010-08-06 19:57:17
|
Revision: 5118 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5118&view=rev Author: ricbrown Date: 2010-08-06 19:57:08 +0000 (Fri, 06 Aug 2010) Log Message: ----------- Fix NH-2251 (System.FormatException mixing Future and Skip/Take) Fixed naming and position of parameters for dialects supporting parameters for limits. Modified Paths: -------------- trunk/nhibernate/releasenotes.txt trunk/nhibernate/src/NHibernate/Criterion/ICriteriaQuery.cs trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs trunk/nhibernate/src/NHibernate/Dialect/DB2Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs trunk/nhibernate/src/NHibernate/Loader/Loader.cs trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs trunk/nhibernate/src/NHibernate.Test/DialectTest/DB2DialectFixture.cs trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Domain.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Mappings.hbm.xml Modified: trunk/nhibernate/releasenotes.txt =================================================================== --- trunk/nhibernate/releasenotes.txt 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/releasenotes.txt 2010-08-06 19:57:08 UTC (rev 5118) @@ -1,9 +1,13 @@ -Build 3.0.0.Alpha1 +Build 3.0.0.Alpha2 ============================= -** Known BREAKING CHANGES from NH2.1.1.GA to NH3.0.0.Alpha1 +** Known BREAKING CHANGES from NH2.1.1.GA to NH3.0.0.Alpha2 ##### Run time ##### * (NH-2199) - null values in maps/dictionaries are no longer silenty ignored/deleted + ##### Possible Breaking Changes ##### + * (NH-2251) - Signature change for GetLimitString in Dialect + + Build 3.0.0.Alpha1 (rev5056) ============================= Modified: trunk/nhibernate/src/NHibernate/Criterion/ICriteriaQuery.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/ICriteriaQuery.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Criterion/ICriteriaQuery.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -68,5 +68,11 @@ /// Do not report the same item multiple times as it will be assumed to be a separate parameter. /// </summary> void AddUsedTypedValues(TypedValue [] values); + + /// <summary> + /// Creates a dummy parameter index for the supplied paged value. + /// Returns null if the Dialect does not support limit parameters + /// </summary> + int? CreatePagingParameter(int value); } } Modified: trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -68,7 +68,9 @@ if (criteriaImpl.FirstResult != 0 || criteriaImpl.MaxResults != RowSelection.NoValue) { - sql = factory.Dialect.GetLimitString(sql, criteriaImpl.FirstResult, criteriaImpl.MaxResults); + int? offsetParameterIndex = criteriaQuery.CreatePagingParameter(criteriaImpl.FirstResult); + int? limitParameterIndex = criteriaQuery.CreatePagingParameter(criteriaImpl.MaxResults); + sql = factory.Dialect.GetLimitString(sql, criteriaImpl.FirstResult, criteriaImpl.MaxResults, offsetParameterIndex, limitParameterIndex); } if (op != null) Modified: trunk/nhibernate/src/NHibernate/Dialect/DB2Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/DB2Dialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/DB2Dialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -212,7 +212,7 @@ /// <param name="querySqlString">A Query in the form of a SqlString.</param> /// <param name="hasOffset">Offset of the first row is not zero</param> /// <returns>A new SqlString that contains the <c>LIMIT</c> clause.</returns> - public override SqlString GetLimitString(SqlString querySqlString, bool hasOffset) + public override SqlString GetLimitString(SqlString querySqlString, int offset, int limit, int? offsetParameterIndex, int? limitParameterIndex) { /* * "select * from (select row_number() over(orderby_clause) as rownum, " @@ -228,19 +228,19 @@ .Add(querySqlString.Substring(7)) .Add(") as tempresult where rownum "); - if (hasOffset) + if (offset > 0) { pagingBuilder .Add("between ") - .Add(Parameter.Placeholder) + .Add(Parameter.WithIndex(offsetParameterIndex.Value)) .Add("+1 and ") - .Add(Parameter.Placeholder); + .Add(Parameter.WithIndex(limitParameterIndex.Value)); } else { pagingBuilder .Add("<= ") - .Add(Parameter.Placeholder); + .Add(Parameter.WithIndex(limitParameterIndex.Value)); } return pagingBuilder.ToSqlString(); Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -1409,11 +1409,30 @@ /// <summary> /// Add a <c>LIMIT</c> clause to the given SQL <c>SELECT</c> + /// when the dialect supports variable limits (i.e., parameters for the limit constraints) /// </summary> /// <param name="querySqlString">A Query in the form of a SqlString.</param> /// <param name="offset">Offset of the first row to be returned by the query (zero-based)</param> /// <param name="limit">Maximum number of rows to be returned by the query</param> /// <returns>A new SqlString that contains the <c>LIMIT</c> clause.</returns> + public virtual SqlString GetLimitString(SqlString querySqlString, int offset, int limit, int? offsetParameterIndex, int? limitParameterIndex) + { + if (!SupportsVariableLimit) + return GetLimitString(querySqlString, offset, limit); + + if ((offsetParameterIndex == null) && (limitParameterIndex == null)) + return GetLimitString(querySqlString, offset, limit); + + throw new NotSupportedException("Override to support limits passed as parameters"); + } + + /// <summary> + /// Add a <c>LIMIT</c> clause to the given SQL <c>SELECT</c> + /// </summary> + /// <param name="querySqlString">A Query in the form of a SqlString.</param> + /// <param name="offset">Offset of the first row to be returned by the query (zero-based)</param> + /// <param name="limit">Maximum number of rows to be returned by the query</param> + /// <returns>A new SqlString that contains the <c>LIMIT</c> clause.</returns> public virtual SqlString GetLimitString(SqlString querySqlString, int offset, int limit) { return GetLimitString(querySqlString, offset > 0); Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -42,7 +42,7 @@ /// Note that we need to add explicitly specify the columns, because we need to be able to use them /// in a paged subselect. NH-1155 /// </remarks> - public override SqlString GetLimitString(SqlString querySqlString, int offset, int last) + public override SqlString GetLimitString(SqlString querySqlString, int offset, int last, int? offsetParameterIndex, int? limitParameterIndex) { //dont do this paging code if there is no offset, use the //sql 2000 dialect since it just uses a top statement @@ -76,16 +76,10 @@ sortExpressions = new[] {new SqlString("CURRENT_TIMESTAMP"),}; } - Parameter limitParameter = Parameter.Placeholder; - limitParameter.ParameterPosition = 0; - - Parameter offsetParameter = Parameter.Placeholder; - offsetParameter.ParameterPosition = 1; - SqlStringBuilder result = new SqlStringBuilder() .Add("SELECT TOP (") - .Add(limitParameter) + .Add(Parameter.WithIndex(limitParameterIndex.Value)) .Add(") ") .Add(StringHelper.Join(", ", columnsOrAliases)) .Add(" FROM (") @@ -98,7 +92,7 @@ .Add(") as __hibernate_sort_row ") .Add(from) .Add(") as query WHERE query.__hibernate_sort_row > ") - .Add(offsetParameter) + .Add(Parameter.WithIndex(offsetParameterIndex.Value)) .Add(" ORDER BY query.__hibernate_sort_row"); return result.ToSqlString(); Modified: trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -186,17 +186,17 @@ /// <param name="querySqlString"></param> /// <param name="hasOffset"></param> /// <returns></returns> - public override SqlString GetLimitString(SqlString querySqlString, bool hasOffset) + public override SqlString GetLimitString(SqlString querySqlString, int offset, int limit, int? offsetParameterIndex, int? limitParameterIndex) { var pagingBuilder = new SqlStringBuilder(); pagingBuilder.Add(querySqlString); pagingBuilder.Add(" limit "); - pagingBuilder.Add(Parameter.Placeholder); + pagingBuilder.Add(Parameter.WithIndex(limitParameterIndex.Value)); - if (hasOffset) + if (offset > 0) { pagingBuilder.Add(", "); - pagingBuilder.Add(Parameter.Placeholder); + pagingBuilder.Add(Parameter.WithIndex(offsetParameterIndex.Value)); } return pagingBuilder.ToSqlString(); } Modified: trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -248,9 +248,10 @@ return new DecodeCaseFragment(this); } - public override SqlString GetLimitString(SqlString sql, bool hasOffset) + public override SqlString GetLimitString(SqlString sql, int offset, int limit, int? offsetParameterIndex, int? limitParameterIndex) { sql = sql.Trim(); + bool hasOffset = offset > 0; bool isForUpdate = false; if (sql.EndsWithCaseInsensitive(" for update")) { @@ -270,11 +271,11 @@ pagingSelect.Add(sql); if (hasOffset) { - pagingSelect.Add(" ) row_ where rownum <=").AddParameter().Add(") where rownum_ >").AddParameter(); + pagingSelect.Add(" ) row_ where rownum <=").AddParameter(limitParameterIndex.Value).Add(") where rownum_ >").AddParameter(offsetParameterIndex.Value); } else { - pagingSelect.Add(" ) where rownum <=").AddParameter(); + pagingSelect.Add(" ) where rownum <=").AddParameter(limitParameterIndex.Value); } if (isForUpdate) Modified: trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -133,17 +133,17 @@ /// <param name="querySqlString"></param> /// <param name="hasOffset">Offset of the first row to process in the result set is non-zero</param> /// <returns></returns> - public override SqlString GetLimitString(SqlString querySqlString, bool hasOffset) + public override SqlString GetLimitString(SqlString querySqlString, int offset, int limit, int? offsetParameterIndex, int? limitParameterIndex) { SqlStringBuilder pagingBuilder = new SqlStringBuilder(); pagingBuilder.Add(querySqlString); pagingBuilder.Add(" limit "); - pagingBuilder.Add(Parameter.Placeholder); + pagingBuilder.Add(Parameter.WithIndex(limitParameterIndex.Value)); - if (hasOffset) + if (offset > 0) { pagingBuilder.Add(" offset "); - pagingBuilder.Add(Parameter.Placeholder); + pagingBuilder.Add(Parameter.WithIndex(offsetParameterIndex.Value)); } return pagingBuilder.ToSqlString(); Modified: trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Data; +using System.Linq; using log4net; using NHibernate.Hql.Classic; using NHibernate.Impl; @@ -40,7 +41,12 @@ private object _optionalId; private string _comment; private bool _readOnly; + private int? limitParameterIndex = null; + private int? offsetParameterIndex = null; + private int wildcardSubqueryLimitParameterIndex = -1; private IDictionary<int, int> _adjustedParameterLocations; + private IDictionary<int, int> _tempPagingParameterIndexes; + private IDictionary<int, int> _pagingParameterIndexMap; private SqlString processedSQL; @@ -61,7 +67,7 @@ } public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues) - : this(positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null) {} + : this(positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null, null) {} public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object[] collectionKeys) : this(positionalParameterTypes, postionalParameterValues, null, collectionKeys) {} @@ -74,12 +80,13 @@ public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool cacheable, - string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer) + string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer, IDictionary<int,int> tempPagingParameterIndexes) : this( positionalParameterTypes, positionalParameterValues, null, lockModes, rowSelection, false, cacheable, cacheRegion, comment, null, transformer) { NaturalKeyLookup = isLookupByNaturalKey; + _tempPagingParameterIndexes = tempPagingParameterIndexes; } public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, @@ -125,6 +132,16 @@ get { return _rowSelection != null; } } + public int? LimitParameterIndex + { + get { return limitParameterIndex; } + } + + public int? OffsetParameterIndex + { + get { return offsetParameterIndex; } + } + /// <summary> /// Named parameters. /// </summary> @@ -401,7 +418,11 @@ { if (sqlParameter is Parameter) { - sqlParameters.Add((Parameter)sqlParameter); + var parameter = (Parameter) sqlParameter; + if (!parameter.ParameterPosition.HasValue || (parameter.ParameterPosition >= 0)) + { + sqlParameters.Add(parameter); + } } } @@ -497,25 +518,61 @@ } } + if (_tempPagingParameterIndexes != null) + { + _pagingParameterIndexMap = new Dictionary<int, int>(); + + var pagingParameters = + sqlString.Parts + .Cast<object>() + .Where(p => p is Parameter) + .Cast<Parameter>() + .Where(p => p.ParameterPosition.HasValue && p.ParameterPosition < 0) + .ToList(); + + foreach (Parameter pagingParameter in pagingParameters) + { + int pagingValue = _tempPagingParameterIndexes[pagingParameter.ParameterPosition.Value]; + int position = parameterIndex + startParameterIndex; + _pagingParameterIndexMap.Add(position, pagingValue); + pagingParameter.ParameterPosition = position; + paramTypeList.Add(NHibernateUtil.Int32); + parameterIndex++; + totalSpan++; + } + } + if (addLimit && factory.Dialect.SupportsVariableLimit) { if (factory.Dialect.BindLimitParametersFirst) { paramTypeList.Insert(0, NHibernateUtil.Int32); + limitParameterIndex = startParameterIndex - 1; if (addOffset) { paramTypeList.Insert(0, NHibernateUtil.Int32); + offsetParameterIndex = startParameterIndex - 2; } } else { paramTypeList.Add(NHibernateUtil.Int32); + limitParameterIndex = totalSpan; if (addOffset) { paramTypeList.Add(NHibernateUtil.Int32); + offsetParameterIndex = totalSpan; + limitParameterIndex = totalSpan + 1; } } + if (addOffset && factory.Dialect.BindLimitParametersInReverseOrder) + { + int? temp = limitParameterIndex; + limitParameterIndex = offsetParameterIndex; + offsetParameterIndex = temp; + } + totalSpan += addOffset ? 2 : 1; } @@ -562,6 +619,16 @@ } } + if (_pagingParameterIndexMap != null) + { + foreach (int pagingParameterIndex in _pagingParameterIndexMap.Keys) + { + ArrayHelper.SafeSetValue(values, pagingParameterIndex, _pagingParameterIndexMap[pagingParameterIndex]); + ArrayHelper.SafeSetValue(types, pagingParameterIndex, NHibernateUtil.Int32); + ArrayHelper.SafeSetValue(sources, pagingParameterIndex, "limit_" + pagingParameterIndex); + } + } + int span = 0; for (int i = start; i < values.Count; i++) { Modified: trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -315,47 +315,41 @@ { int colIndex = 0; - colIndex = BindLimitParametersFirstIfNeccesary(command, colIndex); - colIndex = BindQueryParameters(command, colIndex); - - BindLimitParametersLastIfNeccesary(command, colIndex); + for (int queryIndex = 0; queryIndex < loaders.Count; queryIndex++) + { + int limitParameterSpan = BindLimitParametersFirstIfNeccesary(command, queryIndex, colIndex); + colIndex = BindQueryParameters(command, queryIndex, colIndex + limitParameterSpan); + BindLimitParametersLastIfNeccesary(command, queryIndex, colIndex); + } } - private void BindLimitParametersLastIfNeccesary(IDbCommand command, int colIndex) + private void BindLimitParametersLastIfNeccesary(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < loaders.Count; i++) + QueryParameters parameter = parameters[queryIndex]; + RowSelection selection = parameter.RowSelection; + if (Loader.Loader.UseLimit(selection, dialect) && !dialect.BindLimitParametersFirst) { - QueryParameters parameter = parameters[i]; - RowSelection selection = parameter.RowSelection; - if (Loader.Loader.UseLimit(selection, dialect) && !dialect.BindLimitParametersFirst) - { - colIndex += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); - } + Loader.Loader.BindLimitParameters(command, colIndex, selection, session); } } - private int BindQueryParameters(IDbCommand command, int colIndex) + private int BindQueryParameters(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < loaders.Count; i++) - { - QueryParameters parameter = parameters[i]; - colIndex += parameter.BindParameters(command, colIndex, session); - } + QueryParameters parameter = parameters[queryIndex]; + colIndex += parameter.BindParameters(command, colIndex, session); return colIndex; } - private int BindLimitParametersFirstIfNeccesary(IDbCommand command, int colIndex) + private int BindLimitParametersFirstIfNeccesary(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < loaders.Count; i++) + int limitParametersSpan = 0; + QueryParameters parameter = parameters[queryIndex]; + RowSelection selection = parameter.RowSelection; + if (Loader.Loader.UseLimit(selection, dialect) && dialect.BindLimitParametersFirst) { - QueryParameters parameter = parameters[i]; - RowSelection selection = parameter.RowSelection; - if (Loader.Loader.UseLimit(selection, dialect) && dialect.BindLimitParametersFirst) - { - colIndex += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); - } + limitParametersSpan += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); } - return colIndex; + return limitParametersSpan; } public IMultiCriteria Add(System.Type resultGenericListType, ICriteria criteria) Modified: trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -643,33 +643,29 @@ { int colIndex = 0; - colIndex = BindLimitParametersFirstIfNeccesary(command, colIndex); - colIndex = BindQueryParameters(command, colIndex); - - BindLimitParametersLastIfNeccesary(command, colIndex); + for (int queryIndex = 0; queryIndex < queries.Count; queryIndex++) + { + int limitParameterSpan = BindLimitParametersFirstIfNeccesary(command, queryIndex, colIndex); + colIndex = BindQueryParameters(command, queryIndex, colIndex + limitParameterSpan); + BindLimitParametersLastIfNeccesary(command, queryIndex, colIndex); + } } - private void BindLimitParametersLastIfNeccesary(IDbCommand command, int colIndex) + private void BindLimitParametersLastIfNeccesary(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < queries.Count; i++) + QueryParameters parameter = parameters[queryIndex]; + RowSelection selection = parameter.RowSelection; + if (Loader.Loader.UseLimit(selection, dialect) && !dialect.BindLimitParametersFirst) { - QueryParameters parameter = parameters[i]; - RowSelection selection = parameter.RowSelection; - if (Loader.Loader.UseLimit(selection, dialect) && !dialect.BindLimitParametersFirst) - { - colIndex += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); - } + Loader.Loader.BindLimitParameters(command, colIndex, selection, session); } } - private int BindQueryParameters(IDbCommand command, int colIndex) + private int BindQueryParameters(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < queries.Count; i++) - { - IQueryTranslator translator = Translators[i]; - QueryParameters parameter = Parameters[i]; - colIndex += parameter.BindParameters(command, colIndex, session); - } + IQueryTranslator translator = Translators[queryIndex]; + QueryParameters parameter = Parameters[queryIndex]; + colIndex += parameter.BindParameters(command, colIndex, session); return colIndex; } @@ -688,18 +684,16 @@ return queryResults[criteriaResultPositions[key]]; } - private int BindLimitParametersFirstIfNeccesary(IDbCommand command, int colIndex) + private int BindLimitParametersFirstIfNeccesary(IDbCommand command, int queryIndex, int colIndex) { - for (int i = 0; i < queries.Count; i++) + int limitParameterSpan = 0; + QueryParameters parameter = Parameters[queryIndex]; + RowSelection selection = parameter.RowSelection; + if (Loader.Loader.UseLimit(selection, dialect) && dialect.BindLimitParametersFirst) { - QueryParameters parameter = Parameters[i]; - RowSelection selection = parameter.RowSelection; - if (Loader.Loader.UseLimit(selection, dialect) && dialect.BindLimitParametersFirst) - { - colIndex += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); - } + limitParameterSpan += Loader.Loader.BindLimitParameters(command, colIndex, selection, session); } - return colIndex; + return limitParameterSpan; } public override string ToString() Modified: trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -26,6 +26,8 @@ private readonly string rootEntityName; private readonly string rootSQLAlias; private const int aliasCount = 0; + private int _tempPagingParameterIndex = -1; + private IDictionary<int, int> _tempPagingParameterIndexes = new Dictionary<int, int>(); private readonly IDictionary<ICriteria, ICriteriaInfoProvider> criteriaInfoMap = new Dictionary<ICriteria, ICriteriaInfoProvider>(); @@ -141,7 +143,7 @@ return new QueryParameters(typeArray, valueArray, lockModes, selection, rootCriteria.Cacheable, rootCriteria.CacheRegion, - rootCriteria.Comment, rootCriteria.LookupByNaturalKey, rootCriteria.ResultTransformer); + rootCriteria.Comment, rootCriteria.LookupByNaturalKey, rootCriteria.ResultTransformer, _tempPagingParameterIndexes); } public SqlString GetGroupBy() @@ -730,7 +732,15 @@ } } + public int? CreatePagingParameter(int value) + { + if (!Factory.Dialect.SupportsVariableLimit) + return null; + _tempPagingParameterIndexes.Add(_tempPagingParameterIndex, value); + return _tempPagingParameterIndex--; + } + public SqlString GetHavingCondition(IDictionary<string, IFilter> enabledFilters) { SqlStringBuilder condition = new SqlStringBuilder(30); Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -1112,7 +1112,12 @@ if (useLimit) { sqlString = - dialect.GetLimitString(sqlString.Trim(), useOffset ? GetFirstRow(selection) : 0, GetMaxOrLimit(dialect, selection)); + dialect.GetLimitString( + sqlString.Trim(), + useOffset ? GetFirstRow(selection) : 0, + GetMaxOrLimit(dialect, selection), + queryParameters.OffsetParameterIndex, + queryParameters.LimitParameterIndex); } sqlString = PreprocessSQL(sqlString, queryParameters, dialect); @@ -1710,7 +1715,12 @@ if (useLimit) { sqlString = - dialect.GetLimitString(sqlString.Trim(), useOffset ? GetFirstRow(selection) : 0, GetMaxOrLimit(dialect, selection)); + dialect.GetLimitString( + sqlString.Trim(), + useOffset ? GetFirstRow(selection) : 0, + GetMaxOrLimit(dialect, selection), + parameters.OffsetParameterIndex, + parameters.LimitParameterIndex); } sqlString = PreprocessSQL(sqlString, parameters, dialect); Modified: trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -26,6 +26,14 @@ get { return new Parameter(); } } + /// <summary> + /// Create a parameter with the specified position + /// </summary> + public static Parameter WithIndex(int position) + { + return new Parameter() { ParameterPosition = position }; + } + private Parameter() { } Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -581,7 +581,18 @@ for (int i=0; i<clone.sqlParts.Length; i++) { if (clone.sqlParts[i] is Parameter) - clone.sqlParts[i] = SqlCommand.Parameter.Placeholder; + { + var originalParameter = (Parameter)clone.sqlParts[i]; + var copyParameter = SqlCommand.Parameter.Placeholder; + + if (originalParameter.ParameterPosition < 0) + { + // placeholder for sub-query parameter + copyParameter.ParameterPosition = originalParameter.ParameterPosition; + } + + clone.sqlParts[i] = copyParameter; + } } return clone; Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -110,6 +110,11 @@ return Add(Parameter.Placeholder); } + public SqlStringBuilder AddParameter(int position) + { + return Add(Parameter.WithIndex(position)); + } + /// <summary> /// Attempts to discover what type of object this is and calls the appropriate /// method. Modified: trunk/nhibernate/src/NHibernate.Test/DialectTest/DB2DialectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DialectTest/DB2DialectFixture.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate.Test/DialectTest/DB2DialectFixture.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -24,7 +24,7 @@ " order by a, x" }); - SqlString limited = dialect.GetLimitString(sql, true); + SqlString limited = dialect.GetLimitString(sql, 1, 2, -1, -2); Assert.AreEqual( "select * from (select rownumber() over(order by a, x) as rownum, a, b, c from d where X = ? and Z = ? order by a, x) as tempresult where rownum between ?+1 and ?", limited.ToString()); Modified: trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -16,37 +16,37 @@ { MsSql2005Dialect d = new MsSql2005Dialect(); - SqlString str = d.GetLimitString(new SqlString("select distinct c.Contact_Id as Contact1_19_0_, c._Rating as Rating2_19_0_ from dbo.Contact c where COALESCE(c.Rating, 0) > 0 order by c.Rating desc , c.Last_Name , c.First_Name"), 1, 10); + SqlString str = d.GetLimitString(new SqlString("select distinct c.Contact_Id as Contact1_19_0_, c._Rating as Rating2_19_0_ from dbo.Contact c where COALESCE(c.Rating, 0) > 0 order by c.Rating desc , c.Last_Name , c.First_Name"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) Contact1_19_0_, Rating2_19_0_ FROM (select distinct c.Contact_Id as Contact1_19_0_, c._Rating as Rating2_19_0_, ROW_NUMBER() OVER(ORDER BY c.Rating DESC, c.Last_Name, c.First_Name) as __hibernate_sort_row from dbo.Contact c where COALESCE(c.Rating, 0) > 0) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT fish.id FROM fish"), 1, 10); + str = d.GetLimitString(new SqlString("SELECT fish.id FROM fish"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) id FROM (SELECT fish.id, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id FROM fish fish_"), 1, 10); + str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id FROM fish fish_"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) id FROM (SELECT DISTINCT fish_.id, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish fish_) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id as ixx9_ FROM fish fish_"), 1, 10); + str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id as ixx9_ FROM fish fish_"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) ixx9_ FROM (SELECT DISTINCT fish_.id as ixx9_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish fish_) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT * FROM fish ORDER BY name"), 5, 15); + str = d.GetLimitString(new SqlString("SELECT * FROM fish ORDER BY name"), 5, 15, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY name) as __hibernate_sort_row FROM fish) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT fish.id, fish.name FROM fish ORDER BY name DESC"), 7, 28); + str = d.GetLimitString(new SqlString("SELECT fish.id, fish.name FROM fish ORDER BY name DESC"), 7, 28, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) id, name FROM (SELECT fish.id, fish.name, ROW_NUMBER() OVER(ORDER BY fish.name DESC) as __hibernate_sort_row FROM fish) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", @@ -54,25 +54,25 @@ str = d.GetLimitString( - new SqlString("SELECT * FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t ORDER BY name DESC"), 10, 20); + new SqlString("SELECT * FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t ORDER BY name DESC"), 10, 20, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY name DESC) as __hibernate_sort_row FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count FROM fish"), 1, 10); + str = d.GetLimitString(new SqlString("SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count FROM fish"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) *, some_count FROM (SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT * FROM fish WHERE scales = ", Parameter.Placeholder), 1, 10); + str = d.GetLimitString(new SqlString("SELECT * FROM fish WHERE scales = ", Parameter.Placeholder), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) * FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish WHERE scales = ?) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", str.ToString()); - str = d.GetLimitString(new SqlString("SELECT f.Type, COUNT(DISTINCT f.Name) AS Name FROM Fish f GROUP BY f.Type ORDER BY COUNT(DISTINCT f.Name)"), 1, 10); + str = d.GetLimitString(new SqlString("SELECT f.Type, COUNT(DISTINCT f.Name) AS Name FROM Fish f GROUP BY f.Type ORDER BY COUNT(DISTINCT f.Name)"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) Type, Name FROM (SELECT f.Type, COUNT(DISTINCT f.Name) AS Name, ROW_NUMBER() OVER(ORDER BY COUNT(DISTINCT f.Name)) as __hibernate_sort_row FROM Fish f GROUP BY f.Type) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", @@ -95,13 +95,13 @@ { MsSql2005Dialect d = new MsSql2005Dialect(); SqlString result = - d.GetLimitString(new SqlString("select concat(a.Description,', ', a.Description) as desc from Animal a"), 1, 10); + d.GetLimitString(new SqlString("select concat(a.Description,', ', a.Description) as desc from Animal a"), 1, 10, -1, -2); System.Console.WriteLine(result); Assert.AreEqual("SELECT TOP (?) desc FROM (select concat(a.Description,', ', a.Description) as desc, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row from Animal a) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", result.ToString()); // The test use the function "cast" because cast need the keyWork "as" too SqlString str = - d.GetLimitString(new SqlString("SELECT fish.id, cast('astring, with,comma' as string) as bar FROM fish"), 1, 10); + d.GetLimitString(new SqlString("SELECT fish.id, cast('astring, with,comma' as string) as bar FROM fish"), 1, 10, -1, -2); System.Console.WriteLine(str); Assert.AreEqual( "SELECT TOP (?) id, bar FROM (SELECT fish.id, cast('astring, with,comma' as string) as bar, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM fish) as query WHERE query.__hibernate_sort_row > ? ORDER BY query.__hibernate_sort_row", Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Domain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Domain.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Domain.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -6,5 +6,6 @@ { public virtual Guid Id { get; set; } public virtual string Name { get; set; } + public virtual int Ord { get; set; } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Fixture.cs 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Fixture.cs 2010-08-06 19:57:08 UTC (rev 5118) @@ -1,12 +1,13 @@ using System.Linq; using NUnit.Framework; using SharpTestsEx; +using NHibernate.Criterion; namespace NHibernate.Test.NHSpecificTest.NH2251 { public class Fixture : BugTestCase { - [Test, Ignore("Executing FutureValue before Future cause the mix of parameters in SQL.")] + [Test] public void WhenUseFutureSkipTakeThenNotThrow() { using (var session = OpenSession()) @@ -47,5 +48,109 @@ ).Should().NotThrow(); } } + + [Test] + public void HqlWithOffsetAndLimit() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Save(new Foo() { Name = "name1" }); + session.Save(new Foo() { Name = "name2" }); + session.Save(new Foo() { Name = "name3" }); + session.Save(new Foo() { Name = "name4" }); + + string stringParam = "name%"; + var list = + session.CreateQuery("from Foo f where f.Name like :stringParam order by f.Name") + .SetParameter("stringParam", stringParam) + .SetFirstResult(1) + .SetMaxResults(2) + .List<Foo>(); + + Assert.That(list.Count(), Is.EqualTo(2)); + Assert.That(list[0].Name, Is.EqualTo("name2")); + Assert.That(list[1].Name, Is.EqualTo("name3")); + } + } + + [Test] + public void FuturePagedHql() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Save(new Foo() { Name = "name1" }); + session.Save(new Foo() { Name = "name2" }); + session.Save(new Foo() { Name = "name3" }); + session.Save(new Foo() { Name = "name4" }); + + string stringParam = "name%"; + var list1 = + session.CreateQuery("from Foo f where f.Name like :stringParam order by f.Name") + .SetParameter("stringParam", stringParam) + .SetFirstResult(1) + .SetMaxResults(2) + .Future<Foo>(); + + var list2 = + session.CreateQuery("from Foo f where f.Name like :stringParam order by f.Name") + .SetParameter("stringParam", stringParam) + .SetFirstResult(1) + .SetMaxResults(2) + .Future<Foo>(); + + Assert.That(list1.Count(), Is.EqualTo(2)); + Assert.That(list1.ElementAt(0).Name, Is.EqualTo("name2")); + Assert.That(list1.ElementAt(1).Name, Is.EqualTo("name3")); + + Assert.That(list2.Count(), Is.EqualTo(2)); + Assert.That(list2.ElementAt(0).Name, Is.EqualTo("name2")); + Assert.That(list2.ElementAt(1).Name, Is.EqualTo("name3")); + } + } + + [Test] + public void MultiplePagingParametersInSingleQuery() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Save(new Foo() { Ord = 0, Name = "00" }); + session.Save(new Foo() { Ord = 1, Name = "10" }); + session.Save(new Foo() { Ord = 2, Name = "10" }); + session.Save(new Foo() { Ord = 3, Name = "11" }); + session.Save(new Foo() { Ord = 4, Name = "10" }); + session.Save(new Foo() { Ord = 5, Name = "10" }); + session.Save(new Foo() { Ord = 6, Name = "10" }); + session.Save(new Foo() { Ord = 7, Name = "10" }); + session.Save(new Foo() { Ord = 8, Name = "10" }); + session.Save(new Foo() { Ord = 9, Name = "10" }); + + // returns 2, 3, 4, 5, 6, 7, 8 + DetachedCriteria pagedSubquery = + DetachedCriteria.For<Foo>() + .Add(Restrictions.Like("Name", "1%")) + .AddOrder(Order.Asc("Ord")) + .SetFirstResult(1) + .SetMaxResults(7) + .SetProjection(Projections.Property("Id")); + + var query = + session.CreateCriteria<Foo>() + .Add(Subqueries.PropertyIn("Id", pagedSubquery)) + .Add(Restrictions.Like("Name", "%0")) // excludes 3 + .AddOrder(Order.Asc("Ord")) + .SetFirstResult(2) + .SetMaxResults(3); + + var list = query.List<Foo>(); + + Assert.That(list.Count, Is.EqualTo(3)); + Assert.That(list[0].Ord, Is.EqualTo(5)); + Assert.That(list[1].Ord, Is.EqualTo(6)); + Assert.That(list[2].Ord, Is.EqualTo(7)); + } + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Mappings.hbm.xml 2010-08-06 13:56:15 UTC (rev 5117) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2251/Mappings.hbm.xml 2010-08-06 19:57:08 UTC (rev 5118) @@ -7,6 +7,7 @@ <id name="Id"> <generator class="guid" /> </id> - <property name="Name"/> - </class> + <property name="Name"/> + <property name="Ord"/> + </class> </hibernate-mapping> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |