Skip to content

Commit 8c9b699

Browse files
authored
Extend DateOnly/TimeOnly support to include DataTable as structured parameter (#2258)
1 parent 4e6853e commit 8c9b699

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ExtendedClrTypeCode.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ internal enum ExtendedClrTypeCode
4949
IEnumerableOfSqlDataRecord, // System.Collections.Generic.IEnumerable<Microsoft.Data.SqlClient.Server.SqlDataRecord>
5050
TimeSpan, // System.TimeSpan
5151
DateTimeOffset, // System.DateTimeOffset
52+
#if NET6_0_OR_GREATER
53+
DateOnly, // System.DateOnly
54+
TimeOnly, // System.TimeOnly
55+
#endif
5256
Stream, // System.IO.Stream
5357
TextReader, // System.IO.TextReader
5458
XmlReader, // System.Xml.XmlReader

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/MetadataUtilsSmi.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ internal class MetaDataUtilsSmi
7575
SqlDbType.Structured, // System.Collections.Generic.IEnumerable<Microsoft.Data.SqlClient.Server.SqlDataRecord>
7676
SqlDbType.Time, // System.TimeSpan
7777
SqlDbType.DateTimeOffset, // System.DateTimeOffset
78+
#if NET6_0_OR_GREATER
79+
SqlDbType.Date, // System.DateOnly
80+
SqlDbType.Time, // System.TimeOnly
81+
#endif
7882
};
7983

8084

@@ -86,7 +90,11 @@ internal class MetaDataUtilsSmi
8690

8791
private static Dictionary<Type, ExtendedClrTypeCode> CreateTypeToExtendedTypeCodeMap()
8892
{
93+
#if NET6_0_OR_GREATER
94+
int Count = 44;
95+
#else
8996
int Count = 42;
97+
#endif
9098
// Keep this initialization list in the same order as ExtendedClrTypeCode for ease in validating!
9199
var dictionary = new Dictionary<Type, ExtendedClrTypeCode>(Count)
92100
{
@@ -132,6 +140,10 @@ private static Dictionary<Type, ExtendedClrTypeCode> CreateTypeToExtendedTypeCod
132140
{ typeof(IEnumerable<SqlDataRecord>), ExtendedClrTypeCode.IEnumerableOfSqlDataRecord },
133141
{ typeof(TimeSpan), ExtendedClrTypeCode.TimeSpan },
134142
{ typeof(DateTimeOffset), ExtendedClrTypeCode.DateTimeOffset },
143+
#if NET6_0_OR_GREATER
144+
{ typeof(DateOnly), ExtendedClrTypeCode.DateOnly },
145+
{ typeof(TimeOnly), ExtendedClrTypeCode.TimeOnly },
146+
#endif
135147
};
136148
return dictionary;
137149
}
@@ -244,6 +256,16 @@ Type udtType
244256
extendedCode = ExtendedClrTypeCode.Char;
245257
break;
246258
case SqlDbType.Date:
259+
#if NET6_0_OR_GREATER
260+
if (value.GetType() == typeof(DateOnly))
261+
extendedCode = ExtendedClrTypeCode.DateOnly;
262+
else if (value.GetType() == typeof(DateTime))
263+
extendedCode = ExtendedClrTypeCode.DateTime;
264+
else if (value.GetType() == typeof(SqlDateTime))
265+
extendedCode = ExtendedClrTypeCode.SqlDateTime;
266+
267+
break;
268+
#endif
247269
case SqlDbType.DateTime2:
248270
#if NETFRAMEWORK
249271
if (smiVersion >= SmiContextFactory.Sql2008Version)
@@ -330,6 +352,14 @@ Type udtType
330352
extendedCode = ExtendedClrTypeCode.Invalid;
331353
}
332354
break;
355+
#if NET6_0_OR_GREATER
356+
case SqlDbType.Time:
357+
if (value.GetType() == typeof(TimeOnly))
358+
extendedCode = ExtendedClrTypeCode.TimeOnly;
359+
else if (value.GetType() == typeof(TimeSpan))
360+
extendedCode = ExtendedClrTypeCode.TimeSpan;
361+
break;
362+
#else
333363
case SqlDbType.Time:
334364
if (value.GetType() == typeof(TimeSpan)
335365
#if NETFRAMEWORK
@@ -338,6 +368,7 @@ Type udtType
338368
)
339369
extendedCode = ExtendedClrTypeCode.TimeSpan;
340370
break;
371+
#endif
341372
case SqlDbType.DateTimeOffset:
342373
if (value.GetType() == typeof(DateTimeOffset)
343374
#if NETFRAMEWORK

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,14 @@ value is DataFeed
15421542
SetCompatibleValue(sink, setters, ordinal, metaData, charsValue, ExtendedClrTypeCode.CharArray, 0);
15431543
break;
15441544
}
1545+
#if NET6_0_OR_GREATER
1546+
case ExtendedClrTypeCode.DateOnly:
1547+
SetDateTime_Checked(sink, setters, ordinal, metaData, ((DateOnly)value).ToDateTime(new TimeOnly(0, 0)));
1548+
break;
1549+
case ExtendedClrTypeCode.TimeOnly:
1550+
SetTimeSpan_Checked(sink, (SmiTypedGetterSetter)setters, ordinal, metaData, ((TimeOnly)value).ToTimeSpan());
1551+
break;
1552+
#endif
15451553
case ExtendedClrTypeCode.DateTime:
15461554
SetDateTime_Checked(sink, setters, ordinal, metaData, (DateTime)value);
15471555
break;
@@ -2899,6 +2907,10 @@ int length
28992907
/*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable<SqlDataRecord>*/
29002908
/*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/
29012909
/*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/
2910+
#if NET6_0_OR_GREATER
2911+
/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/
2912+
/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/
2913+
#endif
29022914
/*Strm */{ _ , X , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _, _ , _ , _ , _ , },/*Stream*/
29032915
/*TxRdr*/{ _ , _ , _ , X , _ , _ , _ , _ , _ , _ , X , X , X , _ , _ , _ , _ , _ , X , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/
29042916
/*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/
@@ -2951,6 +2963,10 @@ int length
29512963
/*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable<SqlDataRecord>*/
29522964
/*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/
29532965
/*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/
2966+
#if NET6_0_OR_GREATER
2967+
/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/
2968+
/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/
2969+
#endif
29542970
/*Strm */{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*Stream*/
29552971
/*TxRdr*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/
29562972
/*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
using System.Data.SqlTypes;
1010
using System.Threading;
1111
using Xunit;
12+
#if NET6_0_OR_GREATER
13+
using Microsoft.Data.SqlClient.Server;
14+
#endif
1215

1316
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
1417
{
@@ -306,6 +309,56 @@ public static void TestParametersWithDatatablesTVPInsert()
306309
}
307310
}
308311

312+
#if NET6_0_OR_GREATER
313+
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
314+
public static void TestDateOnlyTVPDataTable_CommandSP()
315+
{
316+
string tableTypeName = "[dbo]." + DataTestUtility.GetUniqueNameForSqlServer("UDTTTestDateOnlyTVP");
317+
string spName = DataTestUtility.GetUniqueNameForSqlServer("spTestDateOnlyTVP");
318+
SqlConnection connection = new(s_connString);
319+
try
320+
{
321+
connection.Open();
322+
using (SqlCommand cmd = connection.CreateCommand())
323+
{
324+
cmd.CommandType = CommandType.Text;
325+
cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)";
326+
cmd.ExecuteNonQuery();
327+
cmd.CommandText = $"CREATE PROCEDURE {spName} (@dates {tableTypeName} READONLY) AS SELECT COUNT(*) FROM @dates";
328+
cmd.ExecuteNonQuery();
329+
}
330+
using (SqlCommand cmd = connection.CreateCommand())
331+
{
332+
cmd.CommandText = spName;
333+
cmd.CommandType = CommandType.StoredProcedure;
334+
335+
DataTable dtTest = new();
336+
dtTest.Columns.Add(new DataColumn("DateColumn", typeof(DateOnly)));
337+
dtTest.Columns.Add(new DataColumn("TimeColumn", typeof(TimeOnly)));
338+
var dataRow = dtTest.NewRow();
339+
dataRow["DateColumn"] = new DateOnly(2023, 11, 15);
340+
dataRow["TimeColumn"] = new TimeOnly(12, 30, 45);
341+
dtTest.Rows.Add(dataRow);
342+
343+
cmd.Parameters.Add(new SqlParameter
344+
{
345+
ParameterName = "@dates",
346+
SqlDbType = SqlDbType.Structured,
347+
TypeName = tableTypeName,
348+
Value = dtTest,
349+
});
350+
351+
cmd.ExecuteNonQuery();
352+
}
353+
}
354+
finally
355+
{
356+
DataTestUtility.DropStoredProcedure(connection, spName);
357+
DataTestUtility.DropUserDefinedType(connection, tableTypeName);
358+
}
359+
}
360+
#endif
361+
309362
#region Scaled Decimal Parameter & TVP Test
310363
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
311364
[InlineData("CAST(1.0 as decimal(38, 37))", "1.0000000000000000000000000000")]

0 commit comments

Comments
 (0)