Skip to content

Commit

Permalink
Extend DateOnly/TimeOnly support to include DataTable as structured p…
Browse files Browse the repository at this point in the history
…arameter (#2258)
  • Loading branch information
ErikEJ authored Apr 9, 2024
1 parent 4e6853e commit 8c9b699
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ internal enum ExtendedClrTypeCode
IEnumerableOfSqlDataRecord, // System.Collections.Generic.IEnumerable<Microsoft.Data.SqlClient.Server.SqlDataRecord>
TimeSpan, // System.TimeSpan
DateTimeOffset, // System.DateTimeOffset
#if NET6_0_OR_GREATER
DateOnly, // System.DateOnly
TimeOnly, // System.TimeOnly
#endif
Stream, // System.IO.Stream
TextReader, // System.IO.TextReader
XmlReader, // System.Xml.XmlReader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ internal class MetaDataUtilsSmi
SqlDbType.Structured, // System.Collections.Generic.IEnumerable<Microsoft.Data.SqlClient.Server.SqlDataRecord>
SqlDbType.Time, // System.TimeSpan
SqlDbType.DateTimeOffset, // System.DateTimeOffset
#if NET6_0_OR_GREATER
SqlDbType.Date, // System.DateOnly
SqlDbType.Time, // System.TimeOnly
#endif
};


Expand All @@ -86,7 +90,11 @@ internal class MetaDataUtilsSmi

private static Dictionary<Type, ExtendedClrTypeCode> CreateTypeToExtendedTypeCodeMap()
{
#if NET6_0_OR_GREATER
int Count = 44;
#else
int Count = 42;
#endif
// Keep this initialization list in the same order as ExtendedClrTypeCode for ease in validating!
var dictionary = new Dictionary<Type, ExtendedClrTypeCode>(Count)
{
Expand Down Expand Up @@ -132,6 +140,10 @@ private static Dictionary<Type, ExtendedClrTypeCode> CreateTypeToExtendedTypeCod
{ typeof(IEnumerable<SqlDataRecord>), ExtendedClrTypeCode.IEnumerableOfSqlDataRecord },
{ typeof(TimeSpan), ExtendedClrTypeCode.TimeSpan },
{ typeof(DateTimeOffset), ExtendedClrTypeCode.DateTimeOffset },
#if NET6_0_OR_GREATER
{ typeof(DateOnly), ExtendedClrTypeCode.DateOnly },
{ typeof(TimeOnly), ExtendedClrTypeCode.TimeOnly },
#endif
};
return dictionary;
}
Expand Down Expand Up @@ -244,6 +256,16 @@ Type udtType
extendedCode = ExtendedClrTypeCode.Char;
break;
case SqlDbType.Date:
#if NET6_0_OR_GREATER
if (value.GetType() == typeof(DateOnly))
extendedCode = ExtendedClrTypeCode.DateOnly;
else if (value.GetType() == typeof(DateTime))
extendedCode = ExtendedClrTypeCode.DateTime;
else if (value.GetType() == typeof(SqlDateTime))
extendedCode = ExtendedClrTypeCode.SqlDateTime;

break;
#endif
case SqlDbType.DateTime2:
#if NETFRAMEWORK
if (smiVersion >= SmiContextFactory.Sql2008Version)
Expand Down Expand Up @@ -330,6 +352,14 @@ Type udtType
extendedCode = ExtendedClrTypeCode.Invalid;
}
break;
#if NET6_0_OR_GREATER
case SqlDbType.Time:
if (value.GetType() == typeof(TimeOnly))
extendedCode = ExtendedClrTypeCode.TimeOnly;
else if (value.GetType() == typeof(TimeSpan))
extendedCode = ExtendedClrTypeCode.TimeSpan;
break;
#else
case SqlDbType.Time:
if (value.GetType() == typeof(TimeSpan)
#if NETFRAMEWORK
Expand All @@ -338,6 +368,7 @@ Type udtType
)
extendedCode = ExtendedClrTypeCode.TimeSpan;
break;
#endif
case SqlDbType.DateTimeOffset:
if (value.GetType() == typeof(DateTimeOffset)
#if NETFRAMEWORK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,14 @@ value is DataFeed
SetCompatibleValue(sink, setters, ordinal, metaData, charsValue, ExtendedClrTypeCode.CharArray, 0);
break;
}
#if NET6_0_OR_GREATER
case ExtendedClrTypeCode.DateOnly:
SetDateTime_Checked(sink, setters, ordinal, metaData, ((DateOnly)value).ToDateTime(new TimeOnly(0, 0)));
break;
case ExtendedClrTypeCode.TimeOnly:
SetTimeSpan_Checked(sink, (SmiTypedGetterSetter)setters, ordinal, metaData, ((TimeOnly)value).ToTimeSpan());
break;
#endif
case ExtendedClrTypeCode.DateTime:
SetDateTime_Checked(sink, setters, ordinal, metaData, (DateTime)value);
break;
Expand Down Expand Up @@ -2899,6 +2907,10 @@ int length
/*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable<SqlDataRecord>*/
/*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/
/*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/
#if NET6_0_OR_GREATER
/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/
/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/
#endif
/*Strm */{ _ , X , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _, _ , _ , _ , _ , },/*Stream*/
/*TxRdr*/{ _ , _ , _ , X , _ , _ , _ , _ , _ , _ , X , X , X , _ , _ , _ , _ , _ , X , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/
/*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/
Expand Down Expand Up @@ -2951,6 +2963,10 @@ int length
/*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable<SqlDataRecord>*/
/*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/
/*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/
#if NET6_0_OR_GREATER
/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/
/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/
#endif
/*Strm */{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*Stream*/
/*TxRdr*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/
/*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
using System.Data.SqlTypes;
using System.Threading;
using Xunit;
#if NET6_0_OR_GREATER
using Microsoft.Data.SqlClient.Server;
#endif

namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
Expand Down Expand Up @@ -306,6 +309,56 @@ public static void TestParametersWithDatatablesTVPInsert()
}
}

#if NET6_0_OR_GREATER
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
public static void TestDateOnlyTVPDataTable_CommandSP()
{
string tableTypeName = "[dbo]." + DataTestUtility.GetUniqueNameForSqlServer("UDTTTestDateOnlyTVP");
string spName = DataTestUtility.GetUniqueNameForSqlServer("spTestDateOnlyTVP");
SqlConnection connection = new(s_connString);
try
{
connection.Open();
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)";
cmd.ExecuteNonQuery();
cmd.CommandText = $"CREATE PROCEDURE {spName} (@dates {tableTypeName} READONLY) AS SELECT COUNT(*) FROM @dates";
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = spName;
cmd.CommandType = CommandType.StoredProcedure;

DataTable dtTest = new();
dtTest.Columns.Add(new DataColumn("DateColumn", typeof(DateOnly)));
dtTest.Columns.Add(new DataColumn("TimeColumn", typeof(TimeOnly)));
var dataRow = dtTest.NewRow();
dataRow["DateColumn"] = new DateOnly(2023, 11, 15);
dataRow["TimeColumn"] = new TimeOnly(12, 30, 45);
dtTest.Rows.Add(dataRow);

cmd.Parameters.Add(new SqlParameter
{
ParameterName = "@dates",
SqlDbType = SqlDbType.Structured,
TypeName = tableTypeName,
Value = dtTest,
});

cmd.ExecuteNonQuery();
}
}
finally
{
DataTestUtility.DropStoredProcedure(connection, spName);
DataTestUtility.DropUserDefinedType(connection, tableTypeName);
}
}
#endif

#region Scaled Decimal Parameter & TVP Test
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
[InlineData("CAST(1.0 as decimal(38, 37))", "1.0000000000000000000000000000")]
Expand Down

0 comments on commit 8c9b699

Please sign in to comment.