-
Notifications
You must be signed in to change notification settings - Fork 314
Description
Describe the bug
ArgumentNullException is thrown when calling GetValue on a SqlDataRecord for a column type defined as SqlMetaData("geog", SqlDbTypeUdt, typeof(SqlGeography))
Exception message: System.ArgumentNullException: Value cannot be null. (Parameter 'key')
Stack trace:
System.Collections.Concurrent.dll!System.ThrowHelper.ThrowArgumentNullException(string name) Line 14
System.Collections.Concurrent.dll!System.Collections.Concurrent.ConcurrentDictionary<System.Type, Microsoft.Data.SqlClient.Server.Serializer>.TryGetValue(System.Type key, out Microsoft.Data.SqlClient.Server.Serializer value) Line 476
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.SerializationHelperSql9.GetSerializer(System.Type t) Line 77
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.SerializationHelperSql9.Deserialize(System.IO.Stream s, System.Type resultType) Line 53
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetUdt_LengthChecked(Microsoft.Data.SqlClient.Server.SmiEventSink_Default sink, Microsoft.Data.SqlClient.Server.ITypedGettersV3 getters, int ordinal, Microsoft.Data.SqlClient.Server.SmiMetaData metaData) Line 2263
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetValue(Microsoft.Data.SqlClient.Server.SmiEventSink_Default sink, Microsoft.Data.SqlClient.Server.ITypedGettersV3 getters, int ordinal, Microsoft.Data.SqlClient.Server.SmiMetaData metaData, object context) Line 1033
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetValue200(Microsoft.Data.SqlClient.Server.SmiEventSink_Default sink, Microsoft.Data.SqlClient.Server.SmiTypedGetterSetter getters, int ordinal, Microsoft.Data.SqlClient.Server.SmiMetaData metaData, object context) Line 926
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.SqlDataRecord.GetValueFrameworkSpecific(int ordinal) Line 23
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.Server.SqlDataRecord.GetValue(int ordinal) Line 61
SqlGeographyTest.dll!SqlGeographyTest.Program.Main(string[] args) Line 20
To reproduce
The following code can be used to reproduce the issue.
using Microsoft.Data.SqlClient.Server;
using Microsoft.SqlServer.Types;
using System.Data;
namespace SqlGeographyTest
{
class Program
{
static void Main(string[] args)
{
SqlGeography geog = SqlGeography.Point(43, -81, 4326);
SqlMetaData[] metadata = new SqlMetaData[] { new SqlMetaData("geog", SqlDbType.Udt, typeof(SqlGeography), "Geography") };
SqlDataRecord record = new SqlDataRecord(metadata);
record.SetValue(0, geog);
var checkValue = record.GetValue(0);
}
}
}
After debugging, the issue appears to arise from the following code in the SqlMetaDataToSmiExtendedMetaData method in MetaDataUtilsSmi (Microsoft.Data.SqlClient.Server).
return new SmiExtendedMetaData(source.SqlDbType,
source.MaxLength,
source.Precision,
source.Scale,
source.LocaleId,
source.CompareOptions,
#if NETFRAMEWORK
source.Type,
#else
null,
#endif
source.Name,
typeSpecificNamePart1,
typeSpecificNamePart2,
typeSpecificNamePart3);
In .NET 8, the type is set to null instead of source.Type due to the #if NETFRAMEWORK directive.
Then when SqlDataRecord.GetValue is called, the Deserialize method throws an exception because it tries to use a null type.
See GetUdt_LengthChecked method in ValueUtilsSmi (Microsoft.Data.SqlClient.Server). metaData.Type is null.
Stream stream = new SmiGettersStream(sink, getters, ordinal, metaData);
result = SerializationHelperSql9.Deserialize(stream, metaData.Type);
Expected behavior
The call to GetValue should return the value that was set in the call to SetValue.
Further technical details
Microsoft.Data.SqlClient version: 5.2.0
Microsoft.SqlServer.Server: 1.0.0
Microsoft.SqlServer.Types: 160.1000.6
.NET target: .NET 8
Operating system: Windows 11
Additional context
Metadata
Metadata
Assignees
Labels
Type
Projects
Status