From 8dd368d5112cf17741dd3c4b8329ceb0180b56de Mon Sep 17 00:00:00 2001 From: ErikEJ Date: Wed, 16 Oct 2019 17:55:28 +0200 Subject: [PATCH 1/4] Get and set expected value for DdType.Date and DbType.Time Breaks support for SQL Server 2008 (I believe) fixes #5 --- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 3 +- .../Microsoft/Data/SqlClient/SqlParameter.cs | 6 +- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 3 +- .../Microsoft/Data/SqlClient/SqlParameter.cs | 6 +- .../tests/FunctionalTests/SqlParameterTest.cs | 85 +++++++++++++++++++ 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnums.cs index 656858b1fa..e07a449607 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -278,6 +278,7 @@ internal static MetaType GetMetaTypeFromDbType(DbType target) case DbType.Currency: return s_metaMoney; case DbType.Date: + return s_metaDate; case DbType.DateTime: return s_metaDateTime; case DbType.Decimal: @@ -301,7 +302,7 @@ internal static MetaType GetMetaTypeFromDbType(DbType target) case DbType.StringFixedLength: return s_metaNChar; case DbType.Time: - return s_metaDateTime; + return MetaTime; case DbType.Xml: return MetaXml; case DbType.DateTime2: diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlParameter.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlParameter.cs index 81d4b47210..77a15904ae 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -330,11 +330,7 @@ public override DbType DbType set { MetaType metatype = _metaType; - if ((null == metatype) || (metatype.DbType != value) || - // Two special datetime cases for backward compat - // DbType.Date and DbType.Time should always be treated as setting DbType.DateTime instead - value == DbType.Date || - value == DbType.Time) + if ((null == metatype) || (metatype.DbType != value)) { PropertyTypeChanging(); _metaType = MetaType.GetMetaTypeFromDbType(value); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlEnums.cs index 5fe6338173..288eead39f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -279,6 +279,7 @@ internal static MetaType GetMetaTypeFromDbType(DbType target) case DbType.Currency: return MetaMoney; case DbType.Date: + return MetaDate; case DbType.DateTime: return MetaDateTime; case DbType.Decimal: @@ -302,7 +303,7 @@ internal static MetaType GetMetaTypeFromDbType(DbType target) case DbType.StringFixedLength: return MetaNChar; case DbType.Time: - return MetaDateTime; + return MetaTime; case DbType.Xml: return MetaXml; case DbType.DateTime2: diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlParameter.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlParameter.cs index 21a4266759..1648e9f24d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -343,11 +343,7 @@ override public DbType DbType set { MetaType metatype = _metaType; - if ((null == metatype) || (metatype.DbType != value) || - // SQLBU 504029: Two special datetime cases for backward compat - // DbType.Date and DbType.Time should always be treated as setting DbType.DateTime instead - value == DbType.Date || - value == DbType.Time) + if ((null == metatype) || (metatype.DbType != value)) { PropertyTypeChanging(); _metaType = MetaType.GetMetaTypeFromDbType(value); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index 8fe10372b9..a6e03a6b04 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -648,6 +648,17 @@ public void InferType_TimeSpan() Assert.Equal(DbType.Time, param.DbType); } + [Fact] + public void InferType_DateTimeOffset() + { + DateTimeOffset value = new DateTimeOffset(new DateTime(2019, 10, 15), new TimeSpan(1, 0, 0)); + + SqlParameter param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.DateTimeOffset, param.SqlDbType); + Assert.Equal(DbType.DateTimeOffset, param.DbType); + } + [Fact] public void LocaleId() { @@ -834,6 +845,80 @@ public void ResetDbType() Assert.Null(p.Value); } + //[InlineData(SqlDbType.BigInt, DbType.Int64)] + //[InlineData(SqlDbType.Binary, DbType.Binary)] + //[InlineData(SqlDbType.Bit, DbType.Boolean)] + //[InlineData(SqlDbType.Char, DbType.AnsiStringFixedLength)] + //[InlineData(SqlDbType.Date, DbType.Date)] + //[InlineData(SqlDbType.DateTime, DbType.DateTime)] + //[InlineData(SqlDbType.DateTimeOffset, DbType.DateTimeOffset)] + //[InlineData(SqlDbType.Decimal, DbType.Decimal)] + //[InlineData(SqlDbType.Float, DbType.Double)] + //[InlineData(SqlDbType.Image, DbType.Binary)] + //[InlineData(SqlDbType.Int, DbType.Int32)] + //[InlineData(SqlDbType.Money, DbType.Currency)] + //[InlineData(SqlDbType.NChar, DbType.StringFixedLength)] + //[InlineData(SqlDbType.NText, DbType.String)] + //[InlineData(SqlDbType.NVarChar, DbType.String)] + //[InlineData(SqlDbType.Real, DbType.Single)] + //[InlineData(SqlDbType.SmallDateTime, DbType.DateTime)] + //[InlineData(SqlDbType.SmallInt, DbType.Int16)] + //[InlineData(SqlDbType.SmallMoney, DbType.Currency)] + //[InlineData(SqlDbType.Structured, DbType.Object)] + //[InlineData(SqlDbType.Text, DbType.AnsiString)] + //[InlineData(SqlDbType.Time, DbType.Time)] + //[InlineData(SqlDbType.Timestamp, DbType.Binary)] + //[InlineData(SqlDbType.TinyInt, DbType.Byte)] + //[InlineData(SqlDbType.Udt, DbType.Object)] + //[InlineData(SqlDbType.UniqueIdentifier, DbType.Guid)] + //[InlineData(SqlDbType.VarBinary, DbType.Binary)] + //[InlineData(SqlDbType.VarChar, DbType.AnsiString)] + //[InlineData(SqlDbType.Variant, DbType.Object)] + //[InlineData(SqlDbType.Xml, DbType.Xml)] + + + [Theory] + [InlineData(DbType.AnsiString, SqlDbType.VarChar)] + [InlineData(DbType.AnsiStringFixedLength, SqlDbType.Char)] + [InlineData(DbType.Binary, SqlDbType.VarBinary)] + [InlineData(DbType.Boolean, SqlDbType.Bit)] + [InlineData(DbType.Byte, SqlDbType.TinyInt)] + [InlineData(DbType.Currency, SqlDbType.Money)] + [InlineData(DbType.Date, SqlDbType.Date)] + [InlineData(DbType.DateTime, SqlDbType.DateTime)] + [InlineData(DbType.DateTime2, SqlDbType.DateTime2)] + [InlineData(DbType.DateTimeOffset, SqlDbType.DateTimeOffset)] + [InlineData(DbType.Decimal, SqlDbType.Decimal)] + [InlineData(DbType.Double, SqlDbType.Float)] + [InlineData(DbType.Guid, SqlDbType.UniqueIdentifier)] + [InlineData(DbType.Int16, SqlDbType.SmallInt)] + [InlineData(DbType.Int32, SqlDbType.Int)] + [InlineData(DbType.Int64, SqlDbType.BigInt)] + [InlineData(DbType.Object, SqlDbType.Variant)] + [InlineData(DbType.Single, SqlDbType.Real)] + [InlineData(DbType.String, SqlDbType.NVarChar)] + [InlineData(DbType.Time, SqlDbType.Time)] + [InlineData(DbType.Xml, SqlDbType.Xml)] + public void Parameter_Supported(DbType dbType, SqlDbType sqlDbType) + { + var parameter = new SqlParameter(); + parameter.DbType = dbType; + Assert.Equal(dbType, parameter.DbType); + Assert.Equal(sqlDbType, parameter.SqlDbType); + } + + [Theory] + [InlineData(DbType.SByte)] + [InlineData(DbType.UInt16)] + [InlineData(DbType.UInt32)] + [InlineData(DbType.UInt64)] + [InlineData(DbType.VarNumeric)] + public void Parameter_Unsupported(DbType dbType) + { + var parameter = new SqlParameter(); + Assert.Throws(() => parameter.DbType = dbType); + } + [Fact] public void ResetSqlDbType() { From 5d2ba8c49466bbfe73d8a4cca2bd53d5d39ad65f Mon Sep 17 00:00:00 2001 From: ErikEJ Date: Wed, 16 Oct 2019 17:56:58 +0200 Subject: [PATCH 2/4] Fixup --- .../tests/FunctionalTests/SqlParameterTest.cs | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index a6e03a6b04..fc95fba50b 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -845,38 +845,6 @@ public void ResetDbType() Assert.Null(p.Value); } - //[InlineData(SqlDbType.BigInt, DbType.Int64)] - //[InlineData(SqlDbType.Binary, DbType.Binary)] - //[InlineData(SqlDbType.Bit, DbType.Boolean)] - //[InlineData(SqlDbType.Char, DbType.AnsiStringFixedLength)] - //[InlineData(SqlDbType.Date, DbType.Date)] - //[InlineData(SqlDbType.DateTime, DbType.DateTime)] - //[InlineData(SqlDbType.DateTimeOffset, DbType.DateTimeOffset)] - //[InlineData(SqlDbType.Decimal, DbType.Decimal)] - //[InlineData(SqlDbType.Float, DbType.Double)] - //[InlineData(SqlDbType.Image, DbType.Binary)] - //[InlineData(SqlDbType.Int, DbType.Int32)] - //[InlineData(SqlDbType.Money, DbType.Currency)] - //[InlineData(SqlDbType.NChar, DbType.StringFixedLength)] - //[InlineData(SqlDbType.NText, DbType.String)] - //[InlineData(SqlDbType.NVarChar, DbType.String)] - //[InlineData(SqlDbType.Real, DbType.Single)] - //[InlineData(SqlDbType.SmallDateTime, DbType.DateTime)] - //[InlineData(SqlDbType.SmallInt, DbType.Int16)] - //[InlineData(SqlDbType.SmallMoney, DbType.Currency)] - //[InlineData(SqlDbType.Structured, DbType.Object)] - //[InlineData(SqlDbType.Text, DbType.AnsiString)] - //[InlineData(SqlDbType.Time, DbType.Time)] - //[InlineData(SqlDbType.Timestamp, DbType.Binary)] - //[InlineData(SqlDbType.TinyInt, DbType.Byte)] - //[InlineData(SqlDbType.Udt, DbType.Object)] - //[InlineData(SqlDbType.UniqueIdentifier, DbType.Guid)] - //[InlineData(SqlDbType.VarBinary, DbType.Binary)] - //[InlineData(SqlDbType.VarChar, DbType.AnsiString)] - //[InlineData(SqlDbType.Variant, DbType.Object)] - //[InlineData(SqlDbType.Xml, DbType.Xml)] - - [Theory] [InlineData(DbType.AnsiString, SqlDbType.VarChar)] [InlineData(DbType.AnsiStringFixedLength, SqlDbType.Char)] From 3b3fb2c02c3e52b63f8a4013623ed43f431a011f Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Fri, 18 Oct 2019 10:08:44 +0200 Subject: [PATCH 3/4] Rename test --- .../tests/FunctionalTests/SqlParameterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index fc95fba50b..203fcc5a65 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -881,7 +881,7 @@ public void Parameter_Supported(DbType dbType, SqlDbType sqlDbType) [InlineData(DbType.UInt32)] [InlineData(DbType.UInt64)] [InlineData(DbType.VarNumeric)] - public void Parameter_Unsupported(DbType dbType) + public void Parameter_NotSupported(DbType dbType) { var parameter = new SqlParameter(); Assert.Throws(() => parameter.DbType = dbType); From 0b1224561660ed0b4f9e0a71554dcc4479851f03 Mon Sep 17 00:00:00 2001 From: dengel Date: Fri, 1 Nov 2019 16:14:02 -0700 Subject: [PATCH 4/4] Extend DateTimeTest.ReaderParameterTest to cover DbType parameters --- .../SQL/DateTimeTest/DateTimeTest.cs | 185 +++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs index 1556ccc99a..c7825ddf93 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs @@ -4,6 +4,7 @@ using System; using System.Data; +using System.Data.Common; using System.Data.SqlTypes; using Xunit; @@ -239,9 +240,172 @@ public static void ReaderParameterTest() Assert.True(IsValidParam(SqlDbType.DateTimeOffset, "c4", dto.LocalDateTime, conn, tableName), "FAILED: Invalid param for DateTimeOffset SqlDbType"); Assert.False(IsValidParam(SqlDbType.DateTimeOffset, "c4", new TimeSpan(), conn, tableName), "FAILED: Invalid param for DateTimeOffset SqlDbType"); Assert.True(IsValidParam(SqlDbType.DateTimeOffset, "c4", "9999-12-31 23:59:59.997 +00:00", conn, tableName), "FAILED: Invalid param for DateTimeOffset SqlDbType"); - #endregion } + // Do the same thing as above except using DbType now + using (DbCommand cmd3 = conn.CreateCommand()) + { + cmd3.CommandText = tempTableInsert2; + DbParameter pi = cmd3.CreateParameter(); + pi.DbType = DbType.Int32; + pi.ParameterName = "@pi"; + DbParameter p0 = cmd3.CreateParameter(); + p0.DbType = DbType.DateTime; + p0.ParameterName = "@p0"; + DbParameter p1 = cmd3.CreateParameter(); + p1.DbType = DbType.Date; + p1.ParameterName = "@p1"; + DbParameter p2 = cmd3.CreateParameter(); + p2.DbType = DbType.Time; + p2.ParameterName = "@p2"; + DbParameter p3 = cmd3.CreateParameter(); + p3.DbType = DbType.DateTime2; + p3.ParameterName = "@p3"; + DbParameter p4 = cmd3.CreateParameter(); + p4.DbType = DbType.DateTimeOffset; + p4.ParameterName = "@p4"; + pi.Value = DBNull.Value; + p0.Value = DBNull.Value; + p1.Value = DBNull.Value; + p2.Value = DBNull.Value; + p3.Value = DBNull.Value; + p4.Value = DBNull.Value; + p3.Scale = 7; + + cmd3.Parameters.Add(pi); + cmd3.Parameters.Add(p0); + cmd3.Parameters.Add(p1); + cmd3.Parameters.Add(p2); + cmd3.Parameters.Add(p3); + cmd3.Parameters.Add(p4); + cmd3.ExecuteNonQuery(); + pi.Value = 1; + p0.Value = new DateTime(2000, 12, 31); + p1.Value = new DateTime(2000, 12, 31); + p2.Value = new TimeSpan(23, 59, 59); + p3.Value = new DateTime(2000, 12, 31); + p4.Value = new DateTimeOffset(2000, 12, 31, 23, 59, 59, new TimeSpan(-8, 0, 0)); + p3.Scale = 3; + + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + cmd3.ExecuteNonQuery(); + + // Test 2 + cmd3.CommandText = "SELECT COUNT(*) FROM " + tableName + " WHERE @pi = ci AND @p0 = c0 AND @p1 = c1 AND @p2 = c2 AND @p3 = c3 AND @p4 = c4"; + pi.Value = 0; + p0.Value = new DateTime(1753, 1, 1, 0, 0, 0); + p1.Value = new DateTime(1753, 1, 1, 0, 0, 0); + p2.Value = new TimeSpan(0, 20, 12, 13, 360); + p3.Value = new DateTime(2000, 12, 31, 23, 59, 59, 997); + p4.Value = new DateTimeOffset(9999, 12, 31, 23, 59, 59, 997, TimeSpan.Zero); + p4.Scale = 3; + cmd3.Parameters.Clear(); + cmd3.Parameters.Add(pi); + cmd3.Parameters.Add(p0); + cmd3.Parameters.Add(p1); + cmd3.Parameters.Add(p2); + cmd3.Parameters.Add(p3); + cmd3.Parameters.Add(p4); + + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + object scalarResult = cmd3.ExecuteScalar(); + Assert.True(scalarResult.Equals(1), string.Format("FAILED: Execute scalar returned unexpected result. Expected: {0}. Actual: {1}.", 1, scalarResult)); + + // Test 3 + + using (SqlCommand cmd4 = conn.CreateCommand()) + { + cmd4.CommandType = CommandType.StoredProcedure; + cmd4.CommandText = procName; + p0 = cmd3.CreateParameter(); + p0.DbType = DbType.DateTime; + p0.ParameterName = "@p0"; + cmd4.Parameters.Add(p0); + p1 = cmd3.CreateParameter(); + p1.DbType = DbType.Date; + p1.ParameterName = "@p1"; + cmd4.Parameters.Add(p1); + p2 = cmd3.CreateParameter(); + p2.DbType = DbType.Time; + p2.ParameterName = "@p2"; + cmd4.Parameters.Add(p2); + p3 = cmd3.CreateParameter(); + p3.DbType = DbType.DateTime2; + p3.ParameterName = "@p3"; + cmd4.Parameters.Add(p3); + p4 = cmd3.CreateParameter(); + p4.DbType = DbType.DateTimeOffset; + p4.ParameterName = "@p4"; + cmd4.Parameters.Add(p4); + p0.Direction = ParameterDirection.Output; + p1.Direction = ParameterDirection.Output; + p2.Direction = ParameterDirection.Output; + p3.Direction = ParameterDirection.Output; + p4.Direction = ParameterDirection.Output; + p2.Scale = 7; + cmd4.ExecuteNonQuery(); + + Assert.True(p0.Value.Equals((new SqlDateTime(1753, 1, 1, 0, 0, 0)).Value), "FAILED: SqlParameter p0 contained incorrect value"); + Assert.True(p1.Value.Equals(new DateTime(1753, 1, 1, 0, 0, 0)), "FAILED: SqlParameter p1 contained incorrect value"); + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + Assert.True(p2.Value.Equals(new TimeSpan(0, 20, 12, 13, 360)), "FAILED: SqlParameter p2 contained incorrect value"); + Assert.True(p2.Scale.Equals(7), "FAILED: SqlParameter p0 contained incorrect scale"); + Assert.True(p3.Value.Equals(new DateTime(2000, 12, 31, 23, 59, 59, 997)), "FAILED: SqlParameter p3 contained incorrect value"); + Assert.True(p3.Scale.Equals(7), "FAILED: SqlParameter p3 contained incorrect scale"); + Assert.True(p4.Value.Equals(new DateTimeOffset(9999, 12, 31, 23, 59, 59, 997, TimeSpan.Zero)), "FAILED: SqlParameter p4 contained incorrect value"); + Assert.True(p4.Scale.Equals(7), "FAILED: SqlParameter p4 contained incorrect scale"); + + // Test 4 + cmd4.CommandText = procNullName; + cmd4.ExecuteNonQuery(); + } + Assert.True(p0.Value.Equals(DBNull.Value), "FAILED: SqlParameter p0 expected to be NULL"); + Assert.True(p1.Value.Equals(DBNull.Value), "FAILED: SqlParameter p1 expected to be NULL"); + Assert.True(p2.Value.Equals(DBNull.Value), "FAILED: SqlParameter p2 expected to be NULL"); + Assert.True(p3.Value.Equals(DBNull.Value), "FAILED: SqlParameter p3 expected to be NULL"); + Assert.True(p4.Value.Equals(DBNull.Value), "FAILED: SqlParameter p4 expected to be NULL"); + + // Date + Assert.False(IsValidParam(DbType.Date, "c1", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new TimeSpan(), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", "1753-1-1", conn, tableName), "FAILED: Invalid param for Date DbType"); + + // Time + // These 7 Asserts used to be broken for before removing back-compat code for DbType.Date and DbType.Time parameters + Assert.False(IsValidParam(DbType.Time, "c2", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", TimeSpan.Parse("20:12:13.36"), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", "20:12:13.36", conn, tableName), "FAILED: Invalid param for Time DbType"); + + // DateTime2 + DateTime dt = DateTime.Parse("2000-12-31 23:59:59.997"); + Assert.False(IsValidParam(DbType.DateTime2, "c3", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.False(IsValidParam(DbType.DateTime2, "c3", new SqlDateTime(2000, 12, 31, 23, 59, 59, 997), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.True(IsValidParam(DbType.DateTime2, "c3", new DateTime(2000, 12, 31, 23, 59, 59, 997, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.True(IsValidParam(DbType.DateTime2, "c3", new DateTime(2000, 12, 31, 23, 59, 59, 997, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.True(IsValidParam(DbType.DateTime2, "c3", new DateTime(2000, 12, 31, 23, 59, 59, 997, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.False(IsValidParam(DbType.DateTime2, "c3", new TimeSpan(), conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + Assert.True(IsValidParam(DbType.DateTime2, "c3", "2000-12-31 23:59:59.997", conn, tableName), "FAILED: Invalid param for DateTime2 DbType"); + + // DateTimeOffset + DateTimeOffset dto = DateTimeOffset.Parse("9999-12-31 23:59:59.997 +00:00"); + Assert.True(IsValidParam(DbType.DateTimeOffset, "c4", dto, conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.False(IsValidParam(DbType.DateTimeOffset, "c4", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.True(IsValidParam(DbType.DateTimeOffset, "c4", new DateTime(9999, 12, 31, 15, 59, 59, 997, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.True(IsValidParam(DbType.DateTimeOffset, "c4", dto.UtcDateTime, conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.True(IsValidParam(DbType.DateTimeOffset, "c4", dto.LocalDateTime, conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.False(IsValidParam(DbType.DateTimeOffset, "c4", new TimeSpan(), conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + Assert.True(IsValidParam(DbType.DateTimeOffset, "c4", "9999-12-31 23:59:59.997 +00:00", conn, tableName), "FAILED: Invalid param for DateTimeOffset DbType"); + } + #endregion + #region reader // Reader Tests cmd.CommandText = "SELECT * FROM " + tableName; @@ -443,6 +607,25 @@ private static bool IsValidParam(SqlDbType dbType, string col, object value, Sql return true; } + private static bool IsValidParam(DbType dbType, string col, object value, SqlConnection conn, string tempTable) + { + try + { + DbCommand cmd = new SqlCommand("SELECT COUNT(*) FROM " + tempTable + " WHERE " + col + " = @p", conn); + DbParameter p = cmd.CreateParameter(); + p.ParameterName = "@p"; + p.DbType = dbType; + p.Value = value; + cmd.Parameters.Add(p); + cmd.ExecuteScalar(); + } + catch (InvalidCastException) + { + return false; + } + return true; + } + private static bool IsString(SqlDataReader rdr, int column) { if (!rdr.IsDBNull(column))