From cd2211a80846c4c0f2a54bfa7c0d5a2798737666 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:46:46 +0100 Subject: [PATCH 01/17] netcore, netfx: sync declarations of TdsOperationStatus variables --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 92 ++++++++++--------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 32 +++---- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 8bb547497a..b1554792df 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -2724,14 +2724,13 @@ private TdsOperationStatus TryProcessEnvChange(int tokenLength, TdsParserStateOb int processedLength = 0; SqlEnvChange head = null; SqlEnvChange tail = null; - TdsOperationStatus result; sqlEnvChange = null; while (tokenLength > processedLength) { SqlEnvChange env = new SqlEnvChange(); - result = stateObj.TryReadByte(out env._type); + TdsOperationStatus result = stateObj.TryReadByte(out env._type); if (result != TdsOperationStatus.Done) { return result; @@ -4671,9 +4670,11 @@ internal void DrainData(TdsParserStateObject stateObj) if (sharedState != null && sharedState._dataReady) { _SqlMetaDataSet metadata = stateObj._cleanupMetaData; + TdsOperationStatus result; if (stateObj._partialHeaderBytesRead > 0) { - if (stateObj.TryProcessHeader() != TdsOperationStatus.Done) + result = stateObj.TryProcessHeader(); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4681,7 +4682,8 @@ internal void DrainData(TdsParserStateObject stateObj) if (0 == sharedState._nextColumnHeaderToRead) { // i. user called read but didn't fetch anything - if (stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4695,7 +4697,8 @@ internal void DrainData(TdsParserStateObject stateObj) { if (stateObj._longlen != 0) { - if (TrySkipPlpValue(ulong.MaxValue, stateObj, out _) != TdsOperationStatus.Done) + result = TrySkipPlpValue(ulong.MaxValue, stateObj, out _); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4704,7 +4707,8 @@ internal void DrainData(TdsParserStateObject stateObj) else if (0 < sharedState._columnDataBytesRemaining) { - if (stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining) != TdsOperationStatus.Done) + result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4713,7 +4717,8 @@ internal void DrainData(TdsParserStateObject stateObj) // Read the remaining values off the wire for this row - if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -6552,9 +6557,8 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value, private TdsOperationStatus TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj) { Span datetimeBuffer = ((uint)length <= 16) ? stackalloc byte[16] : new byte[length]; - TdsOperationStatus result; - result = stateObj.TryReadByteArray(datetimeBuffer, length); + TdsOperationStatus result = stateObj.TryReadByteArray(datetimeBuffer, length); if (result != TdsOperationStatus.Done) { return result; @@ -8076,47 +8080,45 @@ internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject s return stateObj.TryReadInt32(out tokenLength); } + if (token == TdsEnums.SQLUDT) + { // special case for UDTs + tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLRETURNVALUE) { - if (token == TdsEnums.SQLUDT) - { // special case for UDTs - tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLRETURNVALUE) - { - tokenLength = -1; // In 2005, the RETURNVALUE token stream no longer has length - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLXMLTYPE) - { - ushort value; - result = stateObj.TryReadUInt16(out value); - if (result != TdsOperationStatus.Done) - { - tokenLength = 0; - return result; - } - tokenLength = (int)value; - Debug.Assert(tokenLength == TdsEnums.SQL_USHORTVARMAXLEN, "Invalid token stream for xml datatype"); - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLJSON) + tokenLength = -1; // In 2005, the RETURNVALUE token stream no longer has length + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLXMLTYPE) + { + ushort value; + result = stateObj.TryReadUInt16(out value); + if (result != TdsOperationStatus.Done) { - tokenLength = -1; - return TdsOperationStatus.Done; + tokenLength = 0; + return result; } - else if (token == TdsEnums.SQLVECTOR) + tokenLength = (int)value; + Debug.Assert(tokenLength == TdsEnums.SQL_USHORTVARMAXLEN, "Invalid token stream for xml datatype"); + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLJSON) + { + tokenLength = -1; + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLVECTOR) + { + ushort value; + result = stateObj.TryReadUInt16(out value); + if (result != TdsOperationStatus.Done) { - ushort value; - result = stateObj.TryReadUInt16(out value); - if (result != TdsOperationStatus.Done) - { - tokenLength = 0; - return result; - } - tokenLength = value; - return TdsOperationStatus.Done; + tokenLength = 0; + return result; } + tokenLength = value; + return TdsOperationStatus.Done; } switch (token & TdsEnums.SQLLenMask) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 7aafe80082..a010549f04 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -4134,11 +4134,10 @@ internal TdsOperationStatus TryProcessReturnValue(int length, out SqlReturnValue returnValue, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { - TdsOperationStatus result; returnValue = null; SqlReturnValue rec = new SqlReturnValue(); rec.length = length; // In 2005 this length is -1 - result = stateObj.TryReadUInt16(out rec.parmIndex); + TdsOperationStatus result = stateObj.TryReadUInt16(out rec.parmIndex); if (result != TdsOperationStatus.Done) { return result; @@ -4693,9 +4692,10 @@ internal void DrainData(TdsParserStateObject stateObj) if (sharedState != null && sharedState._dataReady) { var metadata = stateObj._cleanupMetaData; + TdsOperationStatus result; if (stateObj._partialHeaderBytesRead > 0) { - TdsOperationStatus result = stateObj.TryProcessHeader(); + result = stateObj.TryProcessHeader(); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4704,7 +4704,7 @@ internal void DrainData(TdsParserStateObject stateObj) if (0 == sharedState._nextColumnHeaderToRead) { // i. user called read but didn't fetch anything - TdsOperationStatus result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); + result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4719,7 +4719,7 @@ internal void DrainData(TdsParserStateObject stateObj) { if (stateObj._longlen != 0) { - TdsOperationStatus result = TrySkipPlpValue(UInt64.MaxValue, stateObj, out _); + result = TrySkipPlpValue(ulong.MaxValue, stateObj, out _); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4729,18 +4729,18 @@ internal void DrainData(TdsParserStateObject stateObj) else if (0 < sharedState._columnDataBytesRemaining) { - TdsOperationStatus result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } } - } // Read the remaining values off the wire for this row - if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -5082,9 +5082,10 @@ internal TdsOperationStatus TryProcessMetaData(int cColumns, TdsParserStateObjec // Read the cipher info table first SqlTceCipherInfoTable cipherTable = null; + TdsOperationStatus result; if (IsColumnEncryptionSupported) { - TdsOperationStatus result = TryProcessCipherInfoTable(stateObj, out cipherTable); + result = TryProcessCipherInfoTable(stateObj, out cipherTable); if (result != TdsOperationStatus.Done) { metaData = null; @@ -5096,7 +5097,7 @@ internal TdsOperationStatus TryProcessMetaData(int cColumns, TdsParserStateObjec _SqlMetaDataSet newMetaData = new _SqlMetaDataSet(cColumns, cipherTable); for (int i = 0; i < cColumns; i++) { - TdsOperationStatus result = TryCommonProcessMetaData(stateObj, newMetaData[i], cipherTable, fColMD: true, columnEncryptionSetting: columnEncryptionSetting); + result = TryCommonProcessMetaData(stateObj, newMetaData[i], cipherTable, fColMD: true, columnEncryptionSetting: columnEncryptionSetting); if (result != TdsOperationStatus.Done) { metaData = null; @@ -5315,10 +5316,9 @@ private TdsOperationStatus TryCommonProcessMetaData(TdsParserStateObject stateOb { byte byteLen; uint userType; - TdsOperationStatus result; // read user type - 4 bytes 2005, 2 backwards - result = stateObj.TryReadUInt32(out userType); + TdsOperationStatus result = stateObj.TryReadUInt32(out userType); if (result != TdsOperationStatus.Done) { return result; @@ -5650,13 +5650,12 @@ private TdsOperationStatus TryProcessColInfo(_SqlMetaDataSet columns, SqlDataRea Debug.Assert(columns != null && columns.Length > 0, "no metadata available!"); metaData = null; - TdsOperationStatus result; for (int i = 0; i < columns.Length; i++) { _SqlMetaData col = columns[i]; - result = stateObj.TryReadByte(out _); + TdsOperationStatus result = stateObj.TryReadByte(out _); if (result != TdsOperationStatus.Done) { return result; @@ -8221,6 +8220,7 @@ internal TdsOperationStatus TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserS internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject stateObj, out int tokenLength) { Debug.Assert(token != 0, "0 length token!"); + TdsOperationStatus result; switch (token) { // rules about SQLLenMask no longer apply to new tokens (as of 7.4) @@ -8232,8 +8232,6 @@ internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject s return stateObj.TryReadInt32(out tokenLength); } - TdsOperationStatus result; - if (token == TdsEnums.SQLUDT) { // special case for UDTs tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? @@ -13693,8 +13691,8 @@ internal TdsOperationStatus TrySkipPlpValue(ulong cb, TdsParserStateObject state { // Read and skip cb bytes or until ReadPlpLength returns 0. int bytesSkipped; - totalBytesSkipped = 0; TdsOperationStatus result; + totalBytesSkipped = 0; if (stateObj._longlenleft == 0) { From 076f87bae9093bd5caf270b0eb15c941808f0346 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:48:26 +0100 Subject: [PATCH 02/17] netcore: reorder TryProcessUDTMetadata --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 159 +++++++++--------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index b1554792df..cd41f2fc47 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -5324,6 +5324,85 @@ private TdsOperationStatus TryCommonProcessMetaData(TdsParserStateObject stateOb return TdsOperationStatus.Done; } + private TdsOperationStatus TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) + { + ushort shortLength; + byte byteLength; + + // max byte size + TdsOperationStatus result = stateObj.TryReadUInt16(out shortLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + metaData.length = shortLength; + + // database name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (metaData.udt is null) + { + metaData.udt = new SqlMetaDataUdt(); + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.DatabaseName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + // schema name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.SchemaName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + // type name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.TypeName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + result = stateObj.TryReadUInt16(out shortLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (shortLength != 0) + { + result = stateObj.TryReadString(shortLength, out metaData.udt.AssemblyQualifiedName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + return TdsOperationStatus.Done; + } + private void WriteUDTMetaData(object value, string database, string schema, string type, TdsParserStateObject stateObj) { @@ -13616,86 +13695,6 @@ internal ulong PlpBytesTotalLength(TdsParserStateObject stateObj) return stateObj._longlen; } - private TdsOperationStatus TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) - { - - ushort shortLength; - byte byteLength; - // max byte size - - TdsOperationStatus result = stateObj.TryReadUInt16(out shortLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - metaData.length = shortLength; - - // database name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (metaData.udt is null) - { - metaData.udt = new SqlMetaDataUdt(); - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.DatabaseName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - // schema name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.SchemaName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - // type name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.TypeName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - result = stateObj.TryReadUInt16(out shortLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (shortLength != 0) - { - result = stateObj.TryReadString(shortLength, out metaData.udt.AssemblyQualifiedName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - return TdsOperationStatus.Done; - } - const string StateTraceFormatString = "\n\t" + " _physicalStateObj = {0}\n\t" + " _pMarsPhysicalConObj = {1}\n\t" From 9499343d7bca7d7f5bba97a36c79e4462d58deb1 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:51:06 +0100 Subject: [PATCH 03/17] netfx: reorder WriteTceFeatureRequest --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index a010549f04..c8c9abaf09 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -8601,31 +8601,31 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return totalLen; } - internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteTceFeatureRequest(bool write /* if false just calculates the length */) { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version if (write) { - // Write Feature ID, length of the version# field and Sensitivity Classification Version# - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_DATACLASSIFICATION); + // Write Feature ID, length of the version# field and TCE Version# + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_TCE); WriteInt(1, _physicalStateObj); - _physicalStateObj.WriteByte(TdsEnums.DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED); + _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_TCE_VERSION); } return len; // size of data written } - internal int WriteTceFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version if (write) { - // Write Feature ID, length of the version# field and TCE Version# - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_TCE); + // Write Feature ID, length of the version# field and Sensitivity Classification Version# + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_DATACLASSIFICATION); WriteInt(1, _physicalStateObj); - _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_TCE_VERSION); + _physicalStateObj.WriteByte(TdsEnums.DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED); } return len; // size of data written From 06b292d20303ac918d35398a6e381e7c1f1502e0 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:51:51 +0100 Subject: [PATCH 04/17] netfx: reorder WriteAzureSQLSupportFeatureRequest --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index c8c9abaf09..f02e15920d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -8616,6 +8616,24 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; // size of data written } + internal int WriteAzureSQLSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = featureData + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_AZURESQLSUPPORT); + + // Feature Data length + WriteInt(s_featureExtDataAzureSQLSupportFeatureRequest.Length, _physicalStateObj); + + _physicalStateObj.WriteByteArray(s_featureExtDataAzureSQLSupportFeatureRequest, s_featureExtDataAzureSQLSupportFeatureRequest.Length, 0); + } + + return len; + } + internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version @@ -8645,24 +8663,6 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } - internal int WriteAzureSQLSupportFeatureRequest(bool write /* if false just calculates the length */) - { - int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = featureData - - if (write) - { - // Write Feature ID - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_AZURESQLSUPPORT); - - // Feature Data length - WriteInt(s_featureExtDataAzureSQLSupportFeatureRequest.Length, _physicalStateObj); - - _physicalStateObj.WriteByteArray(s_featureExtDataAzureSQLSupportFeatureRequest, s_featureExtDataAzureSQLSupportFeatureRequest.Length, 0); - } - - return len; - } - internal int WriteUTF8SupportFeatureRequest(bool write /* if false just calculates the length */) { int len = 5; // 1byte = featureID, 4bytes = featureData length, sizeof(DWORD) From 878fcd46225f6ad67fc5402114c9c4bbcae2d557 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 00:04:46 +0100 Subject: [PATCH 05/17] netcore, netfx: merge WriteInt and SerializeInt netcore: removed a simple WriteInt which did nothing besides call BinaryPrimitives. netcore: when there's space in the packet buffer, WriteInt will now write to it directly (rather than write to a stack-allocated span and copy.) --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 14 +++++------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 22 +++++++------------ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index cd41f2fc47..ebf4c20748 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1748,16 +1748,17 @@ internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) Debug.Assert(sizeof(int) == stateObj._bIntBytes.Length); } - WriteInt(stateObj._bIntBytes.AsSpan(), v); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._bIntBytes, v); return stateObj._bIntBytes; } internal void WriteInt(int v, TdsParserStateObject stateObj) { - Span buffer = stackalloc byte[sizeof(int)]; - WriteInt(buffer, v); if ((stateObj._outBytesUsed + 4) > stateObj._outBuff.Length) { + Span buffer = stackalloc byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32LittleEndian(buffer, v); // if all of the int doesn't fit into the buffer for (int index = 0; index < sizeof(int); index++) { @@ -1767,16 +1768,11 @@ internal void WriteInt(int v, TdsParserStateObject stateObj) else { // all of the int fits into the buffer - buffer.CopyTo(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int))); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int)), v); stateObj._outBytesUsed += 4; } } - internal static void WriteInt(Span buffer, int value) - { - BinaryPrimitives.TryWriteInt32LittleEndian(buffer, value); - } - // // Takes a float and writes it as a 32 bit float. // diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index f02e15920d..9ea55ea54b 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1776,33 +1776,27 @@ internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) Debug.Assert(sizeof(int) == stateObj._bIntBytes.Length); } - int current = 0; - byte[] bytes = stateObj._bIntBytes; - bytes[current++] = (byte)(v & 0xff); - bytes[current++] = (byte)((v >> 8) & 0xff); - bytes[current++] = (byte)((v >> 16) & 0xff); - bytes[current++] = (byte)((v >> 24) & 0xff); - return bytes; + BinaryPrimitives.WriteInt32LittleEndian(stateObj._bIntBytes, v); + return stateObj._bIntBytes; } internal void WriteInt(int v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 4) > stateObj._outBuff.Length) { + Span buffer = stackalloc byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32LittleEndian(buffer, v); // if all of the int doesn't fit into the buffer - for (int shiftValue = 0; shiftValue < sizeof(int) * 8; shiftValue += 8) + for (int index = 0; index < sizeof(int); index++) { - stateObj.WriteByte((byte)((v >> shiftValue) & 0xff)); + stateObj.WriteByte(buffer[index]); } } else { // all of the int fits into the buffer - // NOTE: We don't use a loop here for performance - stateObj._outBuff[stateObj._outBytesUsed] = (byte)(v & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 1] = (byte)((v >> 8) & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 2] = (byte)((v >> 16) & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 3] = (byte)((v >> 24) & 0xff); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int)), v); stateObj._outBytesUsed += 4; } } From c19a10d73c2a61973187b146e6bfc1ebbb818ef1 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 00:16:16 +0100 Subject: [PATCH 06/17] netcore: remove ConstructGuid method --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- .../src/Microsoft/Data/SqlClient/TdsParser.netcore.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index ebf4c20748..673bf84513 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -6871,7 +6871,7 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp { return result; } - value.Guid = ConstructGuid(b); + value.Guid = new Guid(b); break; } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs index 95dd0d9731..c8c2c22a6a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs @@ -15,11 +15,5 @@ internal sealed partial class TdsParser internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); internal static void FillFloatBytes(float value, Span buffer) => BinaryPrimitives.TryWriteInt32LittleEndian(buffer, BitConverterCompatible.SingleToInt32Bits(value)); - - internal static Guid ConstructGuid(ReadOnlySpan bytes) - { - Debug.Assert(bytes.Length >= 16, "not enough bytes to set guid"); - return new Guid(bytes); - } } } From 8806a93ecc449abacea4a8e837d729e61bff0572 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 16:19:27 +0100 Subject: [PATCH 07/17] netcore, netfx: refactor and sync serialization of guids --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 97 ++++++++++++------- .../Data/SqlClient/TdsParser.netcore.cs | 2 - .../src/Microsoft/Data/SqlClient/TdsParser.cs | 90 ++++++++++------- 3 files changed, 117 insertions(+), 72 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 673bf84513..906f4b20ef 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -829,13 +829,13 @@ private void SendPreLoginHandshake( break; case (int)PreLoginOptions.TRACEID: - FillGuidBytes(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); + SerializeGuid(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; offset += GUID_SIZE; optionDataSize = GUID_SIZE; ActivityCorrelator.ActivityId actId = ActivityCorrelator.Next(); - FillGuidBytes(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); + SerializeGuid(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; payload[payloadLength++] = (byte)(0x000000ff & actId.Sequence); payload[payloadLength++] = (byte)((0x0000ff00 & actId.Sequence) >> 8); @@ -1721,6 +1721,48 @@ internal void WriteUnsignedShort(ushort us, TdsParserStateObject stateObj) WriteShort((short)us, stateObj); } + // + // Writes a guid, either to a specific buffer or to the wire. + // + private static void SerializeGuid(in Guid v, Span buffer) + { + Debug.Assert(buffer.Length >= GUID_SIZE); +#if NET + v.TryWriteBytes(buffer, bigEndian: false, out _); +#else + byte[] guidBytes = v.ToByteArray(); + guidBytes.AsSpan().CopyTo(buffer); +#endif + } + + private static void WriteGuid(in SqlGuid v, TdsParserStateObject stateObj) + { + Guid innerValue = v.IsNull ? Guid.Empty : v.Value; + + WriteGuid(in innerValue, stateObj); + } + + private static void WriteGuid(in Guid v, TdsParserStateObject stateObj) + { + if ((stateObj._outBytesUsed + GUID_SIZE) > stateObj._outBuff.Length) + { + Span buffer = stackalloc byte[GUID_SIZE]; + + SerializeGuid(in v, buffer); + // if all of the guid doesn't fit into the buffer + for (int index = 0; index < buffer.Length; index++) + { + stateObj.WriteByte(buffer[index]); + } + } + else + { + // all of the guid fits into the buffer + SerializeGuid(in v, stateObj._outBuff.AsSpan(stateObj._outBytesUsed, GUID_SIZE)); + stateObj._outBytesUsed += GUID_SIZE; + } + } + // // Takes a long and writes out an unsigned int // @@ -6865,13 +6907,24 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp { Debug.Assert(length == GUID_SIZE, "invalid length for SqlGuid type!"); +#if NET Span b = stackalloc byte[GUID_SIZE]; +#else + byte[] b = _tempGuidBytes; + if (b is null) + { + b = new byte[GUID_SIZE]; + } +#endif result = stateObj.TryReadByteArray(b, length); if (result != TdsOperationStatus.Done) { return result; } value.Guid = new Guid(b); +#if NETFRAMEWORK + _tempGuidBytes = b; +#endif break; } @@ -7217,12 +7270,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - Span b = stackalloc byte[16]; - TdsParser.FillGuidBytes(guid, b); - - Debug.Assert((length == b.Length) && (length == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteSpan(b); + WriteGuid((Guid)value, stateObj); + Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); break; } @@ -7375,14 +7424,8 @@ internal Task WriteSqlVariantDataRowValue(object value, TdsParserStateObject sta case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - Span b = stackalloc byte[16]; - FillGuidBytes(guid, b); - - length = b.Length; - Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); WriteSqlVariantHeader(18, metatype.TDSType, metatype.PropBytes, stateObj); - stateObj.WriteByteSpan(b); + WriteGuid((Guid)value, stateObj); break; } @@ -11797,26 +11840,8 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLUNIQUEID: { Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); - Span b = stackalloc byte[16]; - if (value is Guid guid) - { - FillGuidBytes(guid, b); - } - else - { - SqlGuid sqlGuid = (SqlGuid)value; - if (sqlGuid.IsNull) - { - b.Clear(); // this is needed because initlocals may be supressed in framework assemblies meaning the memory is not automaticaly zeroed - } - else - { - FillGuidBytes(sqlGuid.Value, b); - } - } - stateObj.WriteByteSpan(b); + WriteGuid((SqlGuid)value, stateObj); break; - } case TdsEnums.SQLBITN: @@ -12493,9 +12518,7 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLUNIQUEID: { Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); - Span b = stackalloc byte[16]; - FillGuidBytes((System.Guid)value, b); - stateObj.WriteByteSpan(b); + WriteGuid((Guid)value, stateObj); break; } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs index c8c2c22a6a..19c096b84b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs @@ -10,8 +10,6 @@ namespace Microsoft.Data.SqlClient { internal sealed partial class TdsParser { - internal static void FillGuidBytes(Guid guid, Span buffer) => guid.TryWriteBytes(buffer); - internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); internal static void FillFloatBytes(float value, Span buffer) => BinaryPrimitives.TryWriteInt32LittleEndian(buffer, BitConverterCompatible.SingleToInt32Bits(value)); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 9ea55ea54b..9927a9112e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -880,16 +880,13 @@ private void SendPreLoginHandshake( break; case (int)PreLoginOptions.TRACEID: - byte[] connectionIdBytes = _connHandler._clientConnectionId.ToByteArray(); - Debug.Assert(GUID_SIZE == connectionIdBytes.Length); - Buffer.BlockCopy(connectionIdBytes, 0, payload, payloadLength, GUID_SIZE); + SerializeGuid(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; offset += GUID_SIZE; optionDataSize = GUID_SIZE; ActivityCorrelator.ActivityId actId = ActivityCorrelator.Next(); - connectionIdBytes = actId.Id.ToByteArray(); - Buffer.BlockCopy(connectionIdBytes, 0, payload, payloadLength, GUID_SIZE); + SerializeGuid(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; payload[payloadLength++] = (byte)(0x000000ff & actId.Sequence); payload[payloadLength++] = (byte)((0x0000ff00 & actId.Sequence) >> 8); @@ -1749,6 +1746,48 @@ internal void WriteUnsignedShort(ushort us, TdsParserStateObject stateObj) WriteShort((short)us, stateObj); } + // + // Writes a guid, either to a specific buffer or to the wire. + // + private static void SerializeGuid(in Guid v, Span buffer) + { + Debug.Assert(buffer.Length >= GUID_SIZE); +#if NET + v.TryWriteBytes(buffer, bigEndian: false, out _); +#else + byte[] guidBytes = v.ToByteArray(); + guidBytes.AsSpan().CopyTo(buffer); +#endif + } + + private static void WriteGuid(in SqlGuid v, TdsParserStateObject stateObj) + { + Guid innerValue = v.IsNull ? Guid.Empty : v.Value; + + WriteGuid(in innerValue, stateObj); + } + + private static void WriteGuid(in Guid v, TdsParserStateObject stateObj) + { + if ((stateObj._outBytesUsed + GUID_SIZE) > stateObj._outBuff.Length) + { + Span buffer = stackalloc byte[GUID_SIZE]; + + SerializeGuid(in v, buffer); + // if all of the guid doesn't fit into the buffer + for (int index = 0; index < buffer.Length; index++) + { + stateObj.WriteByte(buffer[index]); + } + } + else + { + // all of the guid fits into the buffer + SerializeGuid(in v, stateObj._outBuff.AsSpan(stateObj._outBytesUsed, GUID_SIZE)); + stateObj._outBytesUsed += GUID_SIZE; + } + } + // // Takes a long and writes out an unsigned int // @@ -6938,18 +6977,24 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp { Debug.Assert(length == GUID_SIZE, "invalid length for SqlGuid type!"); +#if NET + Span b = stackalloc byte[GUID_SIZE]; +#else byte[] b = _tempGuidBytes; if (b is null) { b = new byte[GUID_SIZE]; } +#endif result = stateObj.TryReadByteArray(b, length); if (result != TdsOperationStatus.Done) { return result; } value.Guid = new Guid(b); +#if NETFRAMEWORK _tempGuidBytes = b; +#endif break; } @@ -7295,11 +7340,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - Debug.Assert((length == b.Length) && (length == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, length, 0); + WriteGuid((Guid)value, stateObj); + Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); break; } @@ -7452,13 +7494,8 @@ internal Task WriteSqlVariantDataRowValue(object value, TdsParserStateObject sta case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - length = b.Length; - Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); WriteSqlVariantHeader(18, metatype.TDSType, metatype.PropBytes, stateObj); - stateObj.WriteByteArray(b, length, 0); + WriteGuid((Guid)value, stateObj); break; } @@ -11876,18 +11913,8 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLUNIQUEID: { - byte[] b; - if (value is Guid guid) - { - b = guid.ToByteArray(); - } - else - { - b = ((SqlGuid)value).ToByteArray(); - } - - Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, actualLength, 0); + Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); + WriteGuid((SqlGuid)value, stateObj); break; } @@ -12561,11 +12588,8 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, actualLength, 0); + Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; } From b9d396ffea3afc48f8ccc693944b298c7ebb0f8a Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 16:31:11 +0100 Subject: [PATCH 08/17] netcore, netfx: refactor and sync serialization of floats and doubles This removes the need for TdsParser.netcore.cs. --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 1 - .../src/Microsoft/Data/SqlClient/TdsParser.cs | 4 ++-- .../Data/SqlClient/TdsParser.netcore.cs | 17 ----------------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 12 ++++++------ 4 files changed, 8 insertions(+), 26 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index f52e488239..f6770f6ca6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -804,7 +804,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 906f4b20ef..89b28c9648 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1833,7 +1833,7 @@ internal byte[] SerializeFloat(float v) internal void WriteFloat(float v, TdsParserStateObject stateObj) { Span bytes = stackalloc byte[sizeof(float)]; - FillFloatBytes(v, bytes); + BinaryPrimitives.WriteInt32LittleEndian(bytes, BitConverterCompatible.SingleToInt32Bits(v)); stateObj.WriteByteSpan(bytes); } @@ -1958,7 +1958,7 @@ internal byte[] SerializeDouble(double v) internal void WriteDouble(double v, TdsParserStateObject stateObj) { Span bytes = stackalloc byte[sizeof(double)]; - FillDoubleBytes(v, bytes); + BinaryPrimitives.WriteInt64LittleEndian(bytes, BitConverter.DoubleToInt64Bits(v)); stateObj.WriteByteSpan(bytes); } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs deleted file mode 100644 index 19c096b84b..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -using System; -using System.Diagnostics; -using System.Buffers.Binary; - -namespace Microsoft.Data.SqlClient -{ - internal sealed partial class TdsParser - { - internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); - - internal static void FillFloatBytes(float value, Span buffer) => BinaryPrimitives.TryWriteInt32LittleEndian(buffer, BitConverterCompatible.SingleToInt32Bits(value)); - } -} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 9927a9112e..a9aa387935 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1855,9 +1855,9 @@ internal byte[] SerializeFloat(float v) internal void WriteFloat(float v, TdsParserStateObject stateObj) { - byte[] bytes = BitConverter.GetBytes(v); - - stateObj.WriteByteArray(bytes, bytes.Length, 0); + Span bytes = stackalloc byte[sizeof(float)]; + BinaryPrimitives.WriteInt32LittleEndian(bytes, BitConverterCompatible.SingleToInt32Bits(v)); + stateObj.WriteByteSpan(bytes); } // @@ -1978,9 +1978,9 @@ internal byte[] SerializeDouble(double v) internal void WriteDouble(double v, TdsParserStateObject stateObj) { - byte[] bytes = BitConverter.GetBytes(v); - - stateObj.WriteByteArray(bytes, bytes.Length, 0); + Span bytes = stackalloc byte[sizeof(double)]; + BinaryPrimitives.WriteInt64LittleEndian(bytes, BitConverter.DoubleToInt64Bits(v)); + stateObj.WriteByteSpan(bytes); } internal void PrepareResetConnection(bool preserveTransaction) From 43e90ddb6888c73339856b8b3bd3c71a1112737d Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 16:34:51 +0100 Subject: [PATCH 09/17] netfx: adjust TraceString - parameter was being passed to it which was never referenced in the format string --- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index a9aa387935..f41e79eaf0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -13841,8 +13841,7 @@ internal string TraceString() _statistics == null ? bool.TrueString : bool.FalseString, _statisticsIsInTransaction ? bool.TrueString : bool.FalseString, _fPreserveTransaction ? bool.TrueString : bool.FalseString, - _connHandler == null ? "(null)" : _connHandler.ConnectionOptions.MultiSubnetFailover.ToString((IFormatProvider)null), - _connHandler == null ? "(null)" : _connHandler.ConnectionOptions.TransparentNetworkIPResolution.ToString((IFormatProvider)null)); + _connHandler == null ? "(null)" : _connHandler.ConnectionOptions.MultiSubnetFailover.ToString((IFormatProvider)null)); } private string TraceObjectClass(object instance) From a8be2f1d5c9ccc790801494d37954aee02f1257e Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 16:44:32 +0100 Subject: [PATCH 10/17] netcore: sync exception messages with netfx Messages of the netfx exceptions are more detailed --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 89b28c9648..8ede7b6288 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -964,7 +964,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( if (_physicalStateObj._inBytesPacket > TdsEnums.MAX_PACKET_SIZE || _physicalStateObj._inBytesPacket <= 0) { - throw SQL.ParsingError(); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); } byte[] payload = new byte[_physicalStateObj._inBytesPacket]; @@ -2105,7 +2105,7 @@ internal TdsOperationStatus TryRun(RunBehavior runBehavior, SqlCommand cmdHandle #if DEBUG throw new InvalidOperationException(message); #else - throw SQL.ParsingError(); + throw SQL.ParsingErrorToken(ParsingErrorState.InvalidTdsTokenReceived, token); // MDAC 82443 #endif } @@ -3674,7 +3674,7 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj, { if (length < 5) { - throw SQL.ParsingError(); + throw SQL.ParsingErrorLength(ParsingErrorState.SessionStateLengthTooShort, length); } uint seqNum; TdsOperationStatus result = stateObj.TryReadUInt32(out seqNum); @@ -3694,7 +3694,7 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj, } if (status > 1) { - throw SQL.ParsingError(); + throw SQL.ParsingErrorStatus(ParsingErrorState.SessionStateInvalidStatus, status); } bool recoverable = status != 0; length -= 5; From 8793af7ce5edaa2284616866e1c8a5968d9c4a9f Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:03:11 +0100 Subject: [PATCH 11/17] netfx, netcore: centralise masking of received server options Added mask to netcore logic. Also removed mask on _encryptionOption from netfx - this will never be outside the range of EncryptionOptions.OPTIONS_MASK. --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 8ede7b6288..8f3f90de33 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1013,7 +1013,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( payloadOffset = payload[offset++] << 8 | payload[offset++]; payloadLength = payload[offset++] << 8 | payload[offset++]; - EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset]; + EncryptionOptions serverOption = ((EncryptionOptions)payload[payloadOffset]) & EncryptionOptions.OPTIONS_MASK; /* internal enum EncryptionOptions { OFF, diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index f41e79eaf0..ab68d68634 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1077,7 +1077,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( payloadOffset = payload[offset++] << 8 | payload[offset++]; payloadLength = payload[offset++] << 8 | payload[offset++]; - EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset]; + EncryptionOptions serverOption = ((EncryptionOptions)payload[payloadOffset]) & EncryptionOptions.OPTIONS_MASK; /* internal enum EncryptionOptions { OFF, @@ -1089,26 +1089,26 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } */ // Any response other than NOT_SUP means the server supports encryption. - serverSupportsEncryption = (serverOption & EncryptionOptions.OPTIONS_MASK) != EncryptionOptions.NOT_SUP; + serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP; - switch (_encryptionOption & EncryptionOptions.OPTIONS_MASK) + switch (_encryptionOption) { case (EncryptionOptions.OFF): - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.OFF) + if (serverOption == EncryptionOptions.OFF) { // Only encrypt login. - _encryptionOption = EncryptionOptions.LOGIN | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK); + _encryptionOption = EncryptionOptions.LOGIN; } - else if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ) + else if (serverOption == EncryptionOptions.REQ) { // Encrypt all. - _encryptionOption = EncryptionOptions.ON | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK); + _encryptionOption = EncryptionOptions.ON; } // NOT_SUP: No encryption. break; case (EncryptionOptions.NOT_SUP): - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ) + if (serverOption == EncryptionOptions.REQ) { // Server requires encryption, but client does not support it. _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0)); @@ -1119,7 +1119,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( break; default: // Any other client option needs encryption - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.NOT_SUP) + if (serverOption == EncryptionOptions.NOT_SUP) { _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0)); _physicalStateObj.Dispose(); @@ -1208,8 +1208,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } } - if ((_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.ON || - (_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.LOGIN) + if (_encryptionOption == EncryptionOptions.ON || + _encryptionOption == EncryptionOptions.LOGIN) { if (!serverSupportsEncryption) { From 01b02dbad59a5b7587d568b8ba00182e5cb6f07c Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:06:48 +0100 Subject: [PATCH 12/17] netcore: enforce server certificate validation if AccessTokenCallback is set and certificate is not automatically trusted --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 3 ++- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 8f3f90de33..5046697b5f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1156,7 +1156,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server. bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || - (_connHandler._accessTokenInBytes != null && !trustServerCert); + ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); + uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0) | TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index ab68d68634..18371fcdf0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1219,7 +1219,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server. - bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); + bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || + ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0) | TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE; From 209663e4076ee5ab15fc924da889bb929c170711 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:26:02 +0100 Subject: [PATCH 13/17] netfx: add static lambda to TdsExecuteSQLBatch --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 18371fcdf0..fab8149a3a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -9576,29 +9576,34 @@ internal Task TdsExecuteSQLBatch(string text, int timeout, SqlNotificationReques // Need to wait for flush - continuation will unlock the connection bool taskReleaseConnectionLock = releaseConnectionLock; releaseConnectionLock = false; - return executeTask.ContinueWith(t => - { - Debug.Assert(!t.IsCanceled, "Task should not be canceled"); - try - { - if (t.IsFaulted) - { - FailureCleanup(stateObj, t.Exception.InnerException); - throw t.Exception.InnerException; - } - else + return executeTask.ContinueWith( + static (Task task, object state) => + { + Debug.Assert(!task.IsCanceled, "Task should not be canceled"); + var parameters = (Tuple)state; + TdsParser parser = parameters.Item1; + TdsParserStateObject tdsParserStateObject = parameters.Item2; + SqlInternalConnectionTds internalConnectionTds = parameters.Item3; + try { - stateObj.SniContext = SniContext.Snix_Read; + if (task.IsFaulted) + { + parser.FailureCleanup(tdsParserStateObject, task.Exception.InnerException); + throw task.Exception.InnerException; + } + else + { + tdsParserStateObject.SniContext = SniContext.Snix_Read; + } } - } - finally - { - if (taskReleaseConnectionLock) + finally { - _connHandler._parserLock.Release(); + internalConnectionTds?._parserLock.Release(); } - } - }, TaskScheduler.Default); + }, + Tuple.Create(this, stateObj, taskReleaseConnectionLock ? _connHandler : null), + TaskScheduler.Default + ); } // Finished sync From 693069f391c0e5e05bfb4615ec49dbb52a138296 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:28:58 +0100 Subject: [PATCH 14/17] netfx: remove failed attempt at static lambda This passed state around, but never passed enough state to remove the state machine. Sync with netcore. --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index fab8149a3a..837b41f678 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -10377,27 +10377,23 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet // This is in its own method to avoid always allocating the lambda in TDSExecuteRPCParameter private void TDSExecuteRPCParameterSetupWriteCompletion(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout, bool inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, bool isCommandProc, bool sync, TaskCompletionSource completion, int startRpc, int startParam, Task writeParamTask) { - AsyncHelper.ContinueTaskWithState( + AsyncHelper.ContinueTask( writeParamTask, completion, - this, - (object state) => - { - TdsParser tdsParser = (TdsParser)state; - TdsExecuteRPC( - cmd, - rpcArray, - timeout, - inSchema, - notificationRequest, - stateObj, - isCommandProc, - sync, - completion, - startRpc, - startParam); - }, - onFailure: (Exception exc, object state) => ((TdsParser)state).TdsExecuteRPC_OnFailure(exc, stateObj), + () => TdsExecuteRPC( + cmd, + rpcArray, + timeout, + inSchema, + notificationRequest, + stateObj, + isCommandProc, + sync, + completion, + startRpc, + startParam + ), + onFailure: exc => TdsExecuteRPC_OnFailure(exc, stateObj), connectionToDoom: _connHandler ); } From 6d98357ce2df0cfdc85e54c82f8cab086d1aca14 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 19:19:13 +0100 Subject: [PATCH 15/17] netfx: sync reference to length of JSON metadata substitution sequence --- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 837b41f678..2e288feb5f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -11191,7 +11191,7 @@ internal void WriteBulkCopyMetaData(_SqlMetaDataSet metadataCollection, int coun stateObj.WriteByte(md.scale); break; case SqlDbTypeExtensions.Json: - stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_xmlMetadataSubstituteSequence.Length, 0); + stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_jsonMetadataSubstituteSequence.Length, 0); break; case SqlDbTypeExtensions.Vector: stateObj.WriteByte(md.tdsType); From 1d3930a5b089da5632f878d914e4c7986a333755 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Sun, 10 Aug 2025 21:05:53 +0100 Subject: [PATCH 16/17] netfx: pre-PR correction: match previous behaviour when writing Guid instances from WriteUnterminatedSqlValue --- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 2e288feb5f..05d61ef556 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -11916,7 +11916,15 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLUNIQUEID: { Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); - WriteGuid((SqlGuid)value, stateObj); + if (value is Guid guid) + { + WriteGuid(in guid, stateObj); + } + else + { + SqlGuid sqlGuid = (SqlGuid)value; + WriteGuid(in sqlGuid, stateObj); + } break; } From 539b9935e306e7682209643cd156b924bfc2b585 Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Tue, 12 Aug 2025 21:38:36 +0100 Subject: [PATCH 17/17] Flip order of debug assertion --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 5046697b5f..988f89e907 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -7271,8 +7271,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - WriteGuid((Guid)value, stateObj); Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 05d61ef556..d93cdc0917 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -7341,8 +7341,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - WriteGuid((Guid)value, stateObj); Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; }