From 4b9a0cf16bd5791cefef2cf26918ccddd995b457 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Wed, 12 Sep 2018 09:35:38 +0200 Subject: [PATCH 1/4] Adjusting string parameter sizes for MSSQL --- .../Async/NHSpecificTest/GH1300/Fixture.cs | 228 ++++++++++++++++++ .../NHSpecificTest/GH1300/Entity.cs | 9 + .../NHSpecificTest/GH1300/Fixture.cs | 216 +++++++++++++++++ .../NHSpecificTest/GH1300/Mappings.hbm.xml | 10 + .../GH1300/TestSqlClientDriver.cs | 23 ++ src/NHibernate/AdoNet/IParameterAdjuster.cs | 11 + src/NHibernate/Driver/DriverExtensions.cs | 16 ++ src/NHibernate/Driver/SqlClientDriver.cs | 24 +- src/NHibernate/Type/AbstractStringType.cs | 4 + 9 files changed, 539 insertions(+), 2 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1300/TestSqlClientDriver.cs create mode 100644 src/NHibernate/AdoNet/IParameterAdjuster.cs create mode 100644 src/NHibernate/Driver/DriverExtensions.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs new file mode 100644 index 00000000000..40939c7d679 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs @@ -0,0 +1,228 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Connection; +using NHibernate.Criterion; +using NHibernate.Dialect; +using NHibernate.Driver; +using NHibernate.Engine; +using NHibernate.Exceptions; +using NHibernate.Linq; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1300 +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return dialect is MsSql2000Dialect; + } + + protected override bool AppliesTo(ISessionFactoryImplementor factory) + { + return factory.ConnectionProvider.Driver is SqlClientDriver; + } + + protected override void Configure(Configuration configuration) + { + using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + { + if (cp.Driver is SqlClientDriver) + { + configuration.SetProperty(Environment.ConnectionDriver, typeof(TestSqlClientDriver).AssemblyQualifiedName); + } + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + + protected override void OnSetUp() + { + base.OnSetUp(); + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + transaction.Commit(); + } + } + + [Test] + public async Task InsertShouldUseMappedSizeAsync() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Al", AnsiName = "Al" }; + await (session.SaveAsync(e1)); + await (transaction.CommitAsync()); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Last().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Last().Size, Is.EqualTo(3)); + } + } + + [Test] + public void InsertWithTooLongValuesShouldThrowAsync() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Alal", AnsiName = "Alal" }; + + var ex = Assert.ThrowsAsync( + async () => + { + await (session.SaveAsync(e1)); + await (transaction.CommitAsync()); + }); + + var sqlEx = ex.InnerException as SqlException; + Assert.That(sqlEx, Is.Not.Null); + Assert.That(sqlEx.Number, Is.EqualTo(8152)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public async Task LinqEqualsShouldUseMappedSizeAsync(string property, SqlDbType expectedDbType, CancellationToken cancellationToken = default(CancellationToken)) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + if (property == "Name") + { + await (session.Query().Where(x => x.Name == "Bob").ToListAsync(cancellationToken)); + } + else + { + await (session.Query().Where(x => x.AnsiName == "Bob").ToListAsync(cancellationToken)); + } + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [Test] + public async Task MappedAsShouldUseExplicitSizeAsync() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + await (session.Query().Where(x => x.Name == "Bob".MappedAs(TypeFactory.Basic("AnsiString(200)"))).ToListAsync()); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(200)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + } + } + + [Test] + public async Task LongStringCausesClobSizedParameterAsync() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + await (session.Query().Where(x => x.Name == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedString + 1)).ToListAsync()); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + + await (session.Query().Where(x => x.AnsiName == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString + 1)).ToListAsync()); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public async Task HqlLikeShouldUseLargerSizeAsync(string property, SqlDbType expectedDbType, CancellationToken cancellationToken = default(CancellationToken)) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + await (session.CreateQuery("from Entity where " + property + " like :name").SetParameter("name", "%Bob%").ListAsync(cancellationToken)); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(5)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public async Task CriteriaEqualsShouldUseMappedSizeAsync(string property, SqlDbType expectedDbType, CancellationToken cancellationToken = default(CancellationToken)) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + Driver.ClearCommands(); + + await (session.CreateCriteria().Add(Restrictions.Eq(property, "Bob")) + .ListAsync(cancellationToken)); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(3)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public async Task CriteriaLikeShouldUseLargerSizeAsync(string property, SqlDbType expectedDbType, CancellationToken cancellationToken = default(CancellationToken)) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + await (session.CreateCriteria().Add(Restrictions.Like(property, "%Bob%")) + .ListAsync(cancellationToken)); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(5)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + private TestSqlClientDriver Driver => Sfi.ConnectionProvider.Driver as TestSqlClientDriver; + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs new file mode 100644 index 00000000000..14ad45b4ea8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.GH1300 +{ + class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual string AnsiName { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs new file mode 100644 index 00000000000..87293858302 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs @@ -0,0 +1,216 @@ +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Connection; +using NHibernate.Criterion; +using NHibernate.Dialect; +using NHibernate.Driver; +using NHibernate.Engine; +using NHibernate.Exceptions; +using NHibernate.Linq; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1300 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return dialect is MsSql2000Dialect; + } + + protected override bool AppliesTo(ISessionFactoryImplementor factory) + { + return factory.ConnectionProvider.Driver is SqlClientDriver; + } + + protected override void Configure(Configuration configuration) + { + using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + { + if (cp.Driver is SqlClientDriver) + { + configuration.SetProperty(Environment.ConnectionDriver, typeof(TestSqlClientDriver).AssemblyQualifiedName); + } + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + + protected override void OnSetUp() + { + base.OnSetUp(); + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + transaction.Commit(); + } + } + + [Test] + public void InsertShouldUseMappedSize() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Al", AnsiName = "Al" }; + session.Save(e1); + transaction.Commit(); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Last().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Last().Size, Is.EqualTo(3)); + } + } + + [Test] + public void InsertWithTooLongValuesShouldThrow() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Alal", AnsiName = "Alal" }; + + var ex = Assert.Throws( + () => + { + session.Save(e1); + transaction.Commit(); + }); + + var sqlEx = ex.InnerException as SqlException; + Assert.That(sqlEx, Is.Not.Null); + Assert.That(sqlEx.Number, Is.EqualTo(8152)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public void LinqEqualsShouldUseMappedSize(string property, SqlDbType expectedDbType) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + if (property == "Name") + { + session.Query().Where(x => x.Name == "Bob").ToList(); + } + else + { + session.Query().Where(x => x.AnsiName == "Bob").ToList(); + } + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [Test] + public void MappedAsShouldUseExplicitSize() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Query().Where(x => x.Name == "Bob".MappedAs(TypeFactory.Basic("AnsiString(200)"))).ToList(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(200)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + } + } + + [Test] + public void LongStringCausesClobSizedParameter() + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.Query().Where(x => x.Name == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedString + 1)).ToList(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + + session.Query().Where(x => x.AnsiName == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString + 1)).ToList(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public void HqlLikeShouldUseLargerSize(string property, SqlDbType expectedDbType) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("from Entity where " + property + " like :name").SetParameter("name", "%Bob%").List(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(5)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public void CriteriaEqualsShouldUseMappedSize(string property, SqlDbType expectedDbType) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + Driver.ClearCommands(); + + session.CreateCriteria().Add(Restrictions.Eq(property, "Bob")) + .List(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(3)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + + [TestCase("Name", SqlDbType.NVarChar)] + [TestCase("AnsiName", SqlDbType.VarChar)] + public void CriteriaLikeShouldUseLargerSize(string property, SqlDbType expectedDbType) + { + Driver.ClearCommands(); + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateCriteria().Add(Restrictions.Like(property, "%Bob%")) + .List(); + + Assert.That(Driver.LastCommandParameters.First().Size, Is.GreaterThanOrEqualTo(5)); + Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(expectedDbType)); + } + } + private TestSqlClientDriver Driver => Sfi.ConnectionProvider.Driver as TestSqlClientDriver; + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml new file mode 100644 index 00000000000..d2cd4bfd837 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/TestSqlClientDriver.cs b/src/NHibernate.Test/NHSpecificTest/GH1300/TestSqlClientDriver.cs new file mode 100644 index 00000000000..40fe814c262 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/TestSqlClientDriver.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Data.Common; +using System.Data.SqlClient; +using System.Linq; +using NHibernate.Driver; + +namespace NHibernate.Test.NHSpecificTest.GH1300 +{ + public class TestSqlClientDriver : SqlClientDriver + { + public List LastCommandParameters { get; private set; }=new List(); + + public override void AdjustCommand(DbCommand command) + { + base.AdjustCommand(command); + LastCommandParameters = command.Parameters.OfType().ToList(); + } + public void ClearCommands() + { + LastCommandParameters.Clear(); + } + } +} diff --git a/src/NHibernate/AdoNet/IParameterAdjuster.cs b/src/NHibernate/AdoNet/IParameterAdjuster.cs new file mode 100644 index 00000000000..4211b2a5e37 --- /dev/null +++ b/src/NHibernate/AdoNet/IParameterAdjuster.cs @@ -0,0 +1,11 @@ +using System.Data.Common; +using NHibernate.SqlTypes; +using NHibernate.Type; + +namespace NHibernate.AdoNet +{ + internal interface IParameterAdjuster + { + void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, object value); + } +} diff --git a/src/NHibernate/Driver/DriverExtensions.cs b/src/NHibernate/Driver/DriverExtensions.cs new file mode 100644 index 00000000000..ef7b4a3df78 --- /dev/null +++ b/src/NHibernate/Driver/DriverExtensions.cs @@ -0,0 +1,16 @@ +using System.Data.Common; +using NHibernate.AdoNet; +using NHibernate.SqlTypes; +using NHibernate.Type; + +namespace NHibernate.Driver +{ + internal static class DriverExtensions + { + internal static void AdjustParameterForValue(this IDriver driver, DbParameter parameter, SqlType sqlType, object value) + { + var adjustingDriver = driver as IParameterAdjuster; + adjustingDriver?.AdjustParameterForValue(parameter, sqlType, value); + } + } +} diff --git a/src/NHibernate/Driver/SqlClientDriver.cs b/src/NHibernate/Driver/SqlClientDriver.cs index 679fe397bc4..c99d1f99365 100644 --- a/src/NHibernate/Driver/SqlClientDriver.cs +++ b/src/NHibernate/Driver/SqlClientDriver.cs @@ -9,6 +9,7 @@ using NHibernate.Dialect; using NHibernate.Engine; using NHibernate.SqlTypes; +using NHibernate.Type; namespace NHibernate.Driver { @@ -17,10 +18,11 @@ namespace NHibernate.Driver /// public class SqlClientDriver #if NETFX - : DriverBase, IEmbeddedBatcherFactoryProvider + : DriverBase, #else - : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider + : ReflectionBasedDriver, #endif + IEmbeddedBatcherFactoryProvider, IParameterAdjuster { // Since v5.1 [Obsolete("Use MsSql2000Dialect.MaxSizeForAnsiClob")] @@ -301,5 +303,23 @@ public override bool SupportsMultipleQueries /// public override DateTime MinDate => new DateTime(1753, 1, 1); + + public void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, object value) + { + if (value is string stringVal) + { + switch (parameter.DbType) + { + case DbType.AnsiString: + case DbType.AnsiStringFixedLength: + parameter.Size = IsAnsiText(parameter, sqlType) || stringVal.Length > MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString ? MsSql2000Dialect.MaxSizeForAnsiClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); + break; + case DbType.String: + case DbType.StringFixedLength: + parameter.Size = IsText(parameter, sqlType) || stringVal.Length > MsSql2000Dialect.MaxSizeForLengthLimitedString ? MsSql2000Dialect.MaxSizeForClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); + break; + } + } + } } } diff --git a/src/NHibernate/Type/AbstractStringType.cs b/src/NHibernate/Type/AbstractStringType.cs index b8a5ade41ad..267ccec6da5 100644 --- a/src/NHibernate/Type/AbstractStringType.cs +++ b/src/NHibernate/Type/AbstractStringType.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Globalization; +using NHibernate.Driver; using NHibernate.Engine; using NHibernate.SqlTypes; using NHibernate.UserTypes; @@ -57,6 +58,9 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme { var parameter = cmd.Parameters[index]; + //Allow the driver to adjust the parameter for the value + session.Factory.ConnectionProvider.Driver.AdjustParameterForValue(parameter, SqlType, value); + // set the parameter value before the size check, since ODBC changes the size automatically parameter.Value = value; From 5cd9d274565e30234f281ca2db3c98a8b8e11c49 Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Wed, 12 Sep 2018 21:58:39 +0200 Subject: [PATCH 2/4] Added more properties to the test entity --- .../NHSpecificTest/GH1300/Entity.cs | 2 ++ .../NHSpecificTest/GH1300/Fixture.cs | 36 ++++++------------- .../NHSpecificTest/GH1300/Mappings.hbm.xml | 14 ++++---- src/NHibernate/Driver/SqlClientDriver.cs | 6 ++-- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs index 14ad45b4ea8..abd53ce2050 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Entity.cs @@ -5,5 +5,7 @@ class Entity public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string AnsiName { get; set; } + public virtual string FullText { get; set; } + public virtual string AnsiFullText { get; set; } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs index 87293858302..8f994c19117 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Fixture.cs @@ -70,13 +70,17 @@ public void InsertShouldUseMappedSize() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - var e1 = new Entity { Name = "Al", AnsiName = "Al" }; + var e1 = new Entity { Name = "1", AnsiName = "2", FullText = "3", AnsiFullText = "4" }; session.Save(e1); transaction.Commit(); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); - Assert.That(Driver.LastCommandParameters.Last().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); - Assert.That(Driver.LastCommandParameters.Last().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "1").SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "1").Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "2").SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "2").Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "3").SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "3").Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "4").SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "4").Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); } } @@ -139,27 +143,7 @@ public void MappedAsShouldUseExplicitSize() Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); } } - - [Test] - public void LongStringCausesClobSizedParameter() - { - Driver.ClearCommands(); - - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - session.Query().Where(x => x.Name == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedString + 1)).ToList(); - - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); - - session.Query().Where(x => x.AnsiName == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString + 1)).ToList(); - - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); - } - } - + [TestCase("Name", SqlDbType.NVarChar)] [TestCase("AnsiName", SqlDbType.VarChar)] public void HqlLikeShouldUseLargerSize(string property, SqlDbType expectedDbType) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml index d2cd4bfd837..6c828e207ea 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH1300/Mappings.hbm.xml @@ -1,10 +1,10 @@ - - - - - - - + + + + + + + diff --git a/src/NHibernate/Driver/SqlClientDriver.cs b/src/NHibernate/Driver/SqlClientDriver.cs index c99d1f99365..81d46097a50 100644 --- a/src/NHibernate/Driver/SqlClientDriver.cs +++ b/src/NHibernate/Driver/SqlClientDriver.cs @@ -304,7 +304,7 @@ public override bool SupportsMultipleQueries /// public override DateTime MinDate => new DateTime(1753, 1, 1); - public void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, object value) + public virtual void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, object value) { if (value is string stringVal) { @@ -312,11 +312,11 @@ public void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, obje { case DbType.AnsiString: case DbType.AnsiStringFixedLength: - parameter.Size = IsAnsiText(parameter, sqlType) || stringVal.Length > MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString ? MsSql2000Dialect.MaxSizeForAnsiClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); + parameter.Size = IsAnsiText(parameter, sqlType) ? MsSql2000Dialect.MaxSizeForAnsiClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); break; case DbType.String: case DbType.StringFixedLength: - parameter.Size = IsText(parameter, sqlType) || stringVal.Length > MsSql2000Dialect.MaxSizeForLengthLimitedString ? MsSql2000Dialect.MaxSizeForClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); + parameter.Size = IsText(parameter, sqlType) ? MsSql2000Dialect.MaxSizeForClob : Math.Max(stringVal.Length, sqlType.LengthDefined ? sqlType.Length : parameter.Size); break; } } From e5d9d3dedd8ed5adacd8ae55c47eb4f823d2960b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Fri, 14 Sep 2018 12:25:48 +0200 Subject: [PATCH 3/4] fixup! Added more properties to the test entity Regen async tests --- .../Async/NHSpecificTest/GH1300/Fixture.cs | 36 ++++++------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs index 40939c7d679..11f20de84c2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1300/Fixture.cs @@ -82,13 +82,17 @@ public async Task InsertShouldUseMappedSizeAsync() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - var e1 = new Entity { Name = "Al", AnsiName = "Al" }; + var e1 = new Entity { Name = "1", AnsiName = "2", FullText = "3", AnsiFullText = "4" }; await (session.SaveAsync(e1)); await (transaction.CommitAsync()); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(3)); - Assert.That(Driver.LastCommandParameters.Last().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); - Assert.That(Driver.LastCommandParameters.Last().Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "1").SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "1").Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "2").SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "2").Size, Is.EqualTo(3)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "3").SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "3").Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "4").SqlDbType, Is.EqualTo(SqlDbType.VarChar)); + Assert.That(Driver.LastCommandParameters.Single(x => (string) x.Value == "4").Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); } } @@ -151,27 +155,7 @@ public async Task MappedAsShouldUseExplicitSizeAsync() Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); } } - - [Test] - public async Task LongStringCausesClobSizedParameterAsync() - { - Driver.ClearCommands(); - - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - await (session.Query().Where(x => x.Name == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedString + 1)).ToListAsync()); - - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForClob)); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.NVarChar)); - - await (session.Query().Where(x => x.AnsiName == new string('x', MsSql2000Dialect.MaxSizeForLengthLimitedAnsiString + 1)).ToListAsync()); - - Assert.That(Driver.LastCommandParameters.First().Size, Is.EqualTo(MsSql2000Dialect.MaxSizeForAnsiClob)); - Assert.That(Driver.LastCommandParameters.First().SqlDbType, Is.EqualTo(SqlDbType.VarChar)); - } - } - + [TestCase("Name", SqlDbType.NVarChar)] [TestCase("AnsiName", SqlDbType.VarChar)] public async Task HqlLikeShouldUseLargerSizeAsync(string property, SqlDbType expectedDbType, CancellationToken cancellationToken = default(CancellationToken)) From 14b4930f27af2a088b61f1b83e8452348db6a401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Sun, 16 Sep 2018 15:25:31 +0200 Subject: [PATCH 4/4] Switch IParameterAdjuster to public and add some doc on it --- src/NHibernate/AdoNet/IParameterAdjuster.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/AdoNet/IParameterAdjuster.cs b/src/NHibernate/AdoNet/IParameterAdjuster.cs index 4211b2a5e37..23121520d89 100644 --- a/src/NHibernate/AdoNet/IParameterAdjuster.cs +++ b/src/NHibernate/AdoNet/IParameterAdjuster.cs @@ -1,11 +1,22 @@ using System.Data.Common; +using NHibernate.Driver; using NHibernate.SqlTypes; -using NHibernate.Type; namespace NHibernate.AdoNet { - internal interface IParameterAdjuster + /// + /// Supports adjusting a according to a and + /// the parameter's value. An may implement this interface. + /// + public interface IParameterAdjuster { + /// + /// Adjust the provided parameter according to its and + /// . + /// + /// The parameter to adjust. + /// The parameter's . + /// The parameter's value. void AdjustParameterForValue(DbParameter parameter, SqlType sqlType, object value); } }