|
From: <ric...@us...> - 2010-04-13 18:10:39
|
Revision: 4971
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4971&view=rev
Author: ricbrown
Date: 2010-04-13 18:10:31 +0000 (Tue, 13 Apr 2010)
Log Message:
-----------
Fix NH-2173 (SetMaxResults fails when Dialect has BindLimitParametersFirst == true)
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate.Test/Pagination/CustomDialectFixture.cs
trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDialect.cs
trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDriver.cs
Modified: trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-04-07 10:48:41 UTC (rev 4970)
+++ trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-04-13 18:10:31 UTC (rev 4971)
@@ -526,7 +526,7 @@
public int BindParameters(IDbCommand command, int start, ISessionImplementor session)
{
- int location = 0;
+ int location = start;
var values = new List<object>();
var types = new List<IType>();
var sources = new List<string>();
@@ -565,13 +565,14 @@
}
int span = 0;
- for (int i = 0; i < values.Count; i++)
+ for (int i = start; i < values.Count; i++)
{
IType type = types[i];
object value = values[i];
+ string source = sources[i];
if (log.IsDebugEnabled)
{
- log.Debug(string.Format("BindParameters({0}:{1}) {2} -> [{3}]", "Named", type, value, i));
+ log.Debug(string.Format("BindParameters({0}:{1}) {2} -> [{3}]", source, type, value, i));
}
type.NullSafeSet(command, value, start + span, session);
span += type.GetColumnSpan(session.Factory);
Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-04-07 10:48:41 UTC (rev 4970)
+++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-04-13 18:10:31 UTC (rev 4971)
@@ -1104,9 +1104,10 @@
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;
- SqlType[] parameterTypes = queryParameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, 0, useLimit, useOffset);
+ SqlType[] parameterTypes = queryParameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, startIndex, useLimit, useOffset);
if (useLimit)
{
@@ -1204,6 +1205,13 @@
}
}
+ private int GetFirstLimitParameterCount(Dialect.Dialect dialect, bool useLimit, bool hasFirstRow, bool useOffset)
+ {
+ if (!useLimit) return 0;
+ if (!dialect.BindLimitParametersFirst) return 0;
+ return (hasFirstRow && useOffset) ? 2 : 1;
+ }
+
/// <summary>
/// Bind parameters needed by the dialect-specific LIMIT clause
/// </summary>
@@ -1264,7 +1272,7 @@
// NH Different behavior:
// The responsibility of parameter binding was entirely moved to QueryParameters
// to deal with positionslParameter+NamedParameter+ParameterOfFilters
- return queryParameters.BindParameters(statement, 0, session);
+ return queryParameters.BindParameters(statement, startIndex, session);
}
public virtual int[] GetNamedParameterLocs(string name)
@@ -1693,8 +1701,9 @@
bool useLimit = UseLimit(selection, dialect);
bool hasFirstRow = GetFirstRow(selection) > 0;
bool useOffset = hasFirstRow && useLimit && dialect.SupportsLimitOffset;
+ int limitParameterCount = GetFirstLimitParameterCount(dialect, useLimit, hasFirstRow, useOffset);
- SqlType[] sqlTypes = parameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, startParameterIndex, useLimit, useOffset);
+ SqlType[] sqlTypes = parameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, startParameterIndex + limitParameterCount, useLimit, useOffset);
if (useLimit)
{
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-04-07 10:48:41 UTC (rev 4970)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-04-13 18:10:31 UTC (rev 4971)
@@ -1320,6 +1320,9 @@
<Compile Include="Operations\PersonalDetails.cs" />
<Compile Include="Operations\TimestampedEntity.cs" />
<Compile Include="Operations\VersionedEntity.cs" />
+ <Compile Include="Pagination\CustomDialectFixture.cs" />
+ <Compile Include="Pagination\CustomMsSqlDialect.cs" />
+ <Compile Include="Pagination\CustomMsSqlDriver.cs" />
<Compile Include="Pagination\DataPoint.cs" />
<Compile Include="Pagination\PaginationFixture.cs" />
<Compile Include="ProjectionFixtures\Key.cs" />
Added: trunk/nhibernate/src/NHibernate.Test/Pagination/CustomDialectFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Pagination/CustomDialectFixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Pagination/CustomDialectFixture.cs 2010-04-13 18:10:31 UTC (rev 4971)
@@ -0,0 +1,119 @@
+using System.Collections;
+using System.Collections.Generic;
+using NHibernate.Cfg;
+using NHibernate.Criterion;
+using NUnit.Framework;
+using Environment = NHibernate.Cfg.Environment;
+
+namespace NHibernate.Test.Pagination
+{
+ [TestFixture]
+ public class CustomDialectFixture : TestCase
+ {
+ protected override string MappingsAssembly
+ {
+ get { return "NHibernate.Test"; }
+ }
+
+ protected override IList Mappings
+ {
+ get { return new[] {"Pagination.DataPoint.hbm.xml"}; }
+ }
+
+ protected override void Configure(Configuration configuration)
+ {
+ if (!(Dialect is Dialect.MsSql2005Dialect))
+ Assert.Ignore("Test is for SQL dialect only");
+
+ cfg.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName);
+ cfg.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName);
+ }
+
+ private CustomMsSqlDialect CustomDialect
+ {
+ get { return (CustomMsSqlDialect)Sfi.Dialect; }
+ }
+
+ private CustomMsSqlDriver CustomDriver
+ {
+ get { return (CustomMsSqlDriver)Sfi.ConnectionProvider.Driver; }
+ }
+
+ protected override void OnSetUp()
+ {
+ base.OnSetUp();
+
+ CustomDriver.CustomMsSqlDialect = CustomDialect;
+
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Save(new DataPoint() { X = 5 });
+ s.Save(new DataPoint() { X = 6 });
+ s.Save(new DataPoint() { X = 7 });
+ s.Save(new DataPoint() { X = 8 });
+ s.Save(new DataPoint() { X = 9 });
+ t.Commit();
+ }
+ }
+
+ protected override void OnTearDown()
+ {
+
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Delete("from DataPoint");
+ t.Commit();
+ }
+ base.OnTearDown();
+ }
+
+ [Test]
+ public void LimitFirst()
+ {
+ using (ISession s = OpenSession())
+ {
+ CustomDialect.ForcedSupportsVariableLimit = true;
+ CustomDialect.ForcedBindLimitParameterFirst = true;
+
+ var points =
+ s.CreateCriteria<DataPoint>()
+ .Add(Restrictions.Gt("X", 5.1d))
+ .AddOrder(Order.Asc("X"))
+ .SetFirstResult(1)
+ .SetMaxResults(2)
+ .List<DataPoint>();
+
+ Assert.That(points.Count, Is.EqualTo(2));
+ Assert.That(points[0].X, Is.EqualTo(7d));
+ Assert.That(points[1].X, Is.EqualTo(8d));
+ }
+ }
+
+ [Test]
+ public void LimitFirstMultiCriteria()
+ {
+ using (ISession s = OpenSession())
+ {
+ CustomDialect.ForcedSupportsVariableLimit = true;
+ CustomDialect.ForcedBindLimitParameterFirst = true;
+
+ var criteria =
+ s.CreateMultiCriteria()
+ .Add<DataPoint>(
+ s.CreateCriteria<DataPoint>()
+ .Add(Restrictions.Gt("X", 5.1d))
+ .AddOrder(Order.Asc("X"))
+ .SetFirstResult(1)
+ .SetMaxResults(2));
+
+ var points = (IList<DataPoint>)criteria.List()[0];
+
+ Assert.That(points.Count, Is.EqualTo(2));
+ Assert.That(points[0].X, Is.EqualTo(7d));
+ Assert.That(points[1].X, Is.EqualTo(8d));
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDialect.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDialect.cs 2010-04-13 18:10:31 UTC (rev 4971)
@@ -0,0 +1,17 @@
+using NHibernate.Dialect;
+
+namespace NHibernate.Test.Pagination
+{
+ /// <summary>
+ /// Class to simulate dialects with different binding of limit parameters
+ /// using an MSSql database
+ /// </summary>
+ public class CustomMsSqlDialect : MsSql2005Dialect
+ {
+ public bool ForcedBindLimitParameterFirst;
+ public bool ForcedSupportsVariableLimit;
+
+ public override bool BindLimitParametersFirst { get { return ForcedBindLimitParameterFirst; } }
+ public override bool SupportsVariableLimit { get { return ForcedSupportsVariableLimit; } }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDriver.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDriver.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Pagination/CustomMsSqlDriver.cs 2010-04-13 18:10:31 UTC (rev 4971)
@@ -0,0 +1,35 @@
+using System.Data;
+using System.Text.RegularExpressions;
+using NHibernate.Driver;
+using NUnit.Framework;
+
+namespace NHibernate.Test.Pagination
+{
+ /// <summary>
+ /// Class to work with CustomMsSqlDialect to allow
+ /// verification of simulated limit parameters
+ /// </summary>
+ public class CustomMsSqlDriver : SqlClientDriver
+ {
+ public CustomMsSqlDialect CustomMsSqlDialect;
+
+ protected override void OnBeforePrepare(IDbCommand command)
+ {
+ bool hasLimit = new Regex(@"select\s+top").IsMatch(command.CommandText.ToLower());
+
+ if (hasLimit && CustomMsSqlDialect.ForcedSupportsVariableLimit && CustomMsSqlDialect.ForcedBindLimitParameterFirst)
+ {
+ int offset = (int)((IDataParameter)command.Parameters[0]).Value;
+ int limit = (int)((IDataParameter)command.Parameters[1]).Value;
+
+ Assert.That(command.CommandText.ToLower().Contains("top " + limit),
+ "Expected string containing 'top " + limit + "', but got " + command.CommandText);
+
+ Assert.That(command.CommandText.ToLower().Contains("hibernate_sort_row > " + offset),
+ "Expected string containing 'hibernate_sort_row > " + offset + "', but got " + command.CommandText);
+ }
+
+ base.OnBeforePrepare(command);
+ }
+ }
+}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|