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. |