|
From: <pa...@us...> - 2011-05-29 18:37:03
|
Revision: 5880
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5880&view=rev
Author: patearl
Date: 2011-05-29 18:36:56 +0000 (Sun, 29 May 2011)
Log Message:
-----------
Documentation and consistency improvements in limit support. Includes a fix for a bug recently introduced in the MsSql2005Dialect.
Modified Paths:
--------------
trunk/nhibernate/releasenotes.txt
trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs
trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
Modified: trunk/nhibernate/releasenotes.txt
===================================================================
--- trunk/nhibernate/releasenotes.txt 2011-05-29 18:06:21 UTC (rev 5879)
+++ trunk/nhibernate/releasenotes.txt 2011-05-29 18:36:56 UTC (rev 5880)
@@ -4,6 +4,8 @@
##### Possible Breaking Changes #####
* All Dialect.GetLimitString() methods replaced with a single GetLimitString method with a new signature.
+ For dialects the developers don't perform routine tests on, efforts were made to ensure the new limit string
+ method conforms to the database documentation. Please report any limit-related bugs discovered at runtime.
* [NH-2550] - Allow public access to FieldInterceptor Session (IFieldInterceptor changed)
* [NH-2593] - For Microsoft SQL Server the default batch-size (adonet.batch_size) is set to 20 where not explicit defined in the session-factory configuration
* - ICollectionPersister added property to fix [NH-2489]
Modified: trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2011-05-29 18:06:21 UTC (rev 5879)
+++ trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2011-05-29 18:36:56 UTC (rev 5880)
@@ -66,11 +66,13 @@
if (criteriaImpl.FirstResult != 0 || criteriaImpl.MaxResults != RowSelection.NoValue)
{
- int firstResults = factory.Dialect.GetOffsetValue(Loader.Loader.GetFirstRow(parameters.RowSelection));
- int maxResults = Loader.Loader.GetMaxOrLimit(factory.Dialect, parameters.RowSelection);
- int? offsetParameterIndex = criteriaQuery.CreatePagingParameter(firstResults);
- int? limitParameterIndex = criteriaQuery.CreatePagingParameter(maxResults);
- sql = factory.Dialect.GetLimitString(sql, firstResults, maxResults, offsetParameterIndex, limitParameterIndex);
+ int? offset = Loader.Loader.GetOffsetUsingDialect(parameters.RowSelection, factory.Dialect);
+ int? limit = Loader.Loader.GetLimitUsingDialect(parameters.RowSelection, factory.Dialect);
+ int? offsetParameterIndex = offset.HasValue ? criteriaQuery.CreatePagingParameter(offset.Value) : null;
+ int? limitParameterIndex = limit.HasValue ? criteriaQuery.CreatePagingParameter(limit.Value) : null;
+ Parameter offsetParameter = offsetParameterIndex.HasValue ? Parameter.WithIndex(offsetParameterIndex.Value) : null;
+ Parameter limitParameter = limitParameterIndex.HasValue ? Parameter.WithIndex(limitParameterIndex.Value) : null;
+ sql = factory.Dialect.GetLimitString(sql, offset, limit, offsetParameter, limitParameter);
}
if (op != null)
Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2011-05-29 18:06:21 UTC (rev 5879)
+++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2011-05-29 18:36:56 UTC (rev 5880)
@@ -1702,28 +1702,34 @@
}
/// <summary>
+ /// Generates a string to limit the result set to a number of maximum results with a specified offset into the results.
/// Expects any database-specific offset and limit adjustments to have already been performed (ex. UseMaxForLimit, OffsetStartsAtOne).
+ /// Performs error checking based on the various dialect limit support options. If both parameters and fixed valeus are
+ /// specified, this will use the parameter option if possible. Otherwise, it will fall back to a fixed string.
/// </summary>
- internal SqlString GetLimitString(SqlString queryString, int? offset, int? limit, int? offsetParameterIndex, int? limitParameterIndex)
+ /// <param name="queryString"></param>
+ /// <param name="offset"></param>
+ /// <param name="limit"></param>
+ /// <param name="offsetParameter"></param>
+ /// <param name="limitParameter"></param>
+ /// <returns></returns>
+ public SqlString GetLimitString(SqlString queryString, int? offset, int? limit, Parameter offsetParameter, Parameter limitParameter)
{
- SqlString offsetParameter =
- SupportsVariableLimit && offsetParameterIndex.HasValue ? new SqlString(Parameter.WithIndex(offsetParameterIndex.Value)) :
- offset.HasValue ? new SqlString(offset.ToString()) :
- null;
+ if (offset == null && limit == null && offsetParameter == null && limitParameter == null)
+ return queryString;
- SqlString limitParameter =
- SupportsVariableLimit && limitParameterIndex.HasValue ? new SqlString(Parameter.WithIndex(limitParameterIndex.Value)) :
- limit.HasValue ? new SqlString(limit.ToString()) :
- null;
+ if (!SupportsLimit)
+ throw new NotSupportedException("Dialect does not support limits.");
- return GetLimitString(queryString, offsetParameter, limitParameter);
- }
+ if (!SupportsVariableLimit && offsetParameter != null && offset == null)
+ throw new NotSupportedException("Dialect does not support variable limits.");
- /// <summary>
- /// Expects any database-specific offset and limit adjustments to have already been performed (ex. UseMaxForLimit, OffsetStartsAtOne).
- /// </summary>
- internal SqlString GetLimitString(SqlString queryString, int? offset, int? limit, Parameter offsetParameter, Parameter limitParameter)
- {
+ if (!SupportsVariableLimit && limitParameter != null && limit == null)
+ throw new NotSupportedException("Dialect does not support variable limits.");
+
+ if (!SupportsLimitOffset && (offset != null || offsetParameter != null))
+ throw new NotSupportedException("Dialect does not support limits with offsets.");
+
SqlString o =
SupportsVariableLimit && offsetParameter != null ? new SqlString(offsetParameter) :
offset.HasValue ? new SqlString(offset.ToString()) :
@@ -1737,7 +1743,15 @@
return GetLimitString(queryString, o, l);
}
- internal int GetLimitValue(int offset, int limit)
+ /// <summary>
+ /// Some databases require that a limit statement contain the maximum row number
+ /// instead of the number of rows to retrieve. This method adjusts source
+ /// limit and offset values to account for this.
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <param name="limit"></param>
+ /// <returns></returns>
+ public int GetLimitValue(int offset, int limit)
{
if (limit == int.MaxValue)
return int.MaxValue;
@@ -1748,7 +1762,13 @@
return limit;
}
- internal int GetOffsetValue(int offset)
+ /// <summary>
+ /// Some databases use limit row offsets that start at one instead of zero.
+ /// This method adjusts a desired offset using the OffsetStartsAtOne flag.
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public int GetOffsetValue(int offset)
{
if (OffsetStartsAtOne)
return offset + 1;
Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2011-05-29 18:06:21 UTC (rev 5879)
+++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2011-05-29 18:36:56 UTC (rev 5880)
@@ -76,6 +76,9 @@
if (limit != null)
result.Add("TOP (").Add(limit).Add(") ");
+ else
+ // ORDER BY can only be used in subqueries if TOP is also specified.
+ result.Add("TOP (" + int.MaxValue + ") ");
result
.Add(StringHelper.Join(", ", columnsOrAliases))
Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-05-29 18:06:21 UTC (rev 5879)
+++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-05-29 18:36:56 UTC (rev 5880)
@@ -1098,6 +1098,29 @@
return dialect.SupportsLimit && (HasMaxRows(selection) || HasOffset(selection));
}
+ /// <summary>
+ /// Performs dialect-specific manipulations on the offset value before returning it.
+ /// This method is applicable for use in limit statements only.
+ /// </summary>
+ internal static int? GetOffsetUsingDialect(RowSelection selection, Dialect.Dialect dialect)
+ {
+ int firstRow = GetFirstRow(selection);
+ if (firstRow == 0)
+ return null;
+ return dialect.GetOffsetValue(firstRow);
+ }
+
+ /// <summary>
+ /// Performs dialect-specific manipulations on the limit value before returning it.
+ /// This method is applicable for use in limit statements only.
+ /// </summary>
+ internal static int? GetLimitUsingDialect(RowSelection selection, Dialect.Dialect dialect)
+ {
+ if (selection == null || selection.MaxRows == RowSelection.NoValue)
+ return null;
+ return dialect.GetLimitValue(GetFirstRow(selection), selection.MaxRows);
+ }
+
/// <summary>
/// Obtain an <c>IDbCommand</c> with all parameters pre-bound. Bind positional parameters,
/// named parameters, and limit parameters.
@@ -1127,14 +1150,17 @@
if (useLimit)
{
- int max = GetMaxOrLimit(dialect, selection);
+ 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 ? (int?)dialect.GetOffsetValue(GetFirstRow(selection)) : null,
- max != int.MaxValue ? (int?)max : null,
- queryParameters.OffsetParameterIndex,
- queryParameters.LimitParameterIndex);
+ useOffset ? offset : null,
+ limit,
+ useOffset ? offsetParameter : null,
+ limitParameter);
}
sqlString = PreprocessSQL(sqlString, queryParameters, dialect);
@@ -1742,15 +1768,18 @@
if (useLimit)
{
- int max = GetMaxOrLimit(dialect, selection);
- sqlString =
- dialect.GetLimitString(
- sqlString.Trim(),
- useOffset ? (int?)dialect.GetOffsetValue(GetFirstRow(selection)) : null,
- max != int.MaxValue ? (int?)max : null,
- parameters.OffsetParameterIndex,
- parameters.LimitParameterIndex);
- }
+ int? offset = GetOffsetUsingDialect(selection, dialect);
+ int? limit = GetLimitUsingDialect(selection, dialect);
+ Parameter offsetParameter = parameters.OffsetParameterIndex.HasValue ? Parameter.WithIndex(parameters.OffsetParameterIndex.Value) : null;
+ Parameter limitParameter = parameters.LimitParameterIndex.HasValue ? Parameter.WithIndex(parameters.LimitParameterIndex.Value) : null;
+ sqlString =
+ dialect.GetLimitString(
+ sqlString.Trim(),
+ useOffset ? offset : null,
+ limit,
+ useOffset ? offsetParameter : null,
+ limitParameter);
+ }
sqlString = PreprocessSQL(sqlString, parameters, dialect);
return new SqlCommandInfo(sqlString, sqlTypes);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|