diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs
index 6825139a15..72051fec39 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs
@@ -477,6 +477,12 @@ internal void ThrowIfInvalidOrdinal(int ordinal)
}
}
+ internal SmiMetaData GetVariantInternalMetaData(int ordinal)
+ {
+ ThrowIfInvalidOrdinal(ordinal);
+ return _recordBuffer.GetVariantType(ordinal);
+ }
+
///
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
IDataReader System.Data.IDataRecord.GetData(int ordinal) => throw ADP.NotSupported();
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlRecordBuffer.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlRecordBuffer.cs
index d8e9dc94c6..bb9bdbc446 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlRecordBuffer.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlRecordBuffer.cs
@@ -463,7 +463,7 @@ internal SmiMetaData VariantType
}
set
{
- Debug.Assert(value != null && (value.SqlDbType == SqlDbType.Money || value.SqlDbType == SqlDbType.NVarChar),
+ Debug.Assert(value != null && (value.SqlDbType is SqlDbType.Money or SqlDbType.NVarChar or SqlDbType.Date),
"Invalid metadata");
_metadata = value;
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs
index 94338c8dfb..1fc31c287a 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs
@@ -1504,7 +1504,7 @@ value is DataFeed
}
#if NET
case ExtendedClrTypeCode.DateOnly:
- SetDateTime_Checked(setters, ordinal, metaData, ((DateOnly)value).ToDateTime(new TimeOnly(0, 0)));
+ SetDate_Checked(setters, ordinal, metaData, ((DateOnly)value).ToDateTime(new TimeOnly(0, 0)));
break;
case ExtendedClrTypeCode.TimeOnly:
SetTimeSpan_Checked(setters, ordinal, metaData, ((TimeOnly)value).ToTimeSpan());
@@ -2033,9 +2033,35 @@ internal static void FillCompatibleSettersFromRecord(SmiTypedGetterSetter setter
SetSqlXml_Unchecked(setters, i, record.GetSqlXml(i)); // perf improvement?
break;
case SqlDbType.Variant:
- object o = record.GetSqlValue(i);
+ SmiMetaData variantMetadata = record.GetVariantInternalMetaData(i);
+ SqlBuffer.StorageType storageType;
+ object o;
+
+ // We cannot transport a DateOnly instance using the GetSqlValue method. This is because
+ // GetSqlValue will return a SqlDateTime, which has a much tighter range of expected
+ // values (so trying to send DateOnly.MinValue will overflow.) Instead, use GetValue (which
+ // will return a DateTime, with identical ranges of expected values.)
+ if (variantMetadata.SqlDbType is SqlDbType.Date)
+ {
+ storageType = SqlBuffer.StorageType.Date;
+ o = record.GetValue(i);
+ }
+ else
+ {
+ storageType = SqlBuffer.StorageType.Empty;
+ o = record.GetSqlValue(i);
+ }
+
ExtendedClrTypeCode typeCode = MetaDataUtilsSmi.DetermineExtendedTypeCode(o);
- SetCompatibleValueV200(setters, i, metaData[i], o, typeCode, 0, null /* no peekahead */);
+
+ if (storageType is not SqlBuffer.StorageType.Empty)
+ {
+ SetCompatibleValueV200(setters, i, metaData[i], o, typeCode, 0, null /* no peekahead */, storageType);
+ }
+ else
+ {
+ SetCompatibleValueV200(setters, i, metaData[i], o, typeCode, 0, null /* no peekahead */);
+ }
break;
case SqlDbType.Udt:
Debug.Assert(CanAccessSetterDirectly(metaData[i], ExtendedClrTypeCode.SqlBytes));
@@ -3135,8 +3161,11 @@ private static void SetDateTime2_Unchecked(ITypedSettersV3 setters, int ordinal,
private static void SetDate_Unchecked(ITypedSettersV3 setters, int ordinal, SmiMetaData metaData, DateTime value)
{
- Debug.Assert(metaData.SqlDbType == SqlDbType.Variant, "Invalid type. This should be called only when the type is variant.");
- setters.SetVariantMetaData(ordinal, SmiMetaData.DefaultDate);
+ if (metaData.SqlDbType == SqlDbType.Variant)
+ {
+ setters.SetVariantMetaData(ordinal, SmiMetaData.DefaultDate);
+ }
+
setters.SetDateTime(ordinal, value);
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTests.cs
index 3d84e0ff2c..e968295b5a 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTests.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -987,12 +987,7 @@ public static IEnumerable