From 7674cdfaac397505ebb9b4cab26ac02b4543783b Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Sun, 13 Mar 2022 23:23:26 +0000 Subject: [PATCH 1/5] add and use TryReadChars method --- src/Microsoft.Data.SqlClient.sln | 15 ++++++ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 12 +++-- .../Data/SqlClient/TdsParserStateObject.cs | 46 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index c5b34945a0..3da1a292a1 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -205,6 +205,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4F3CD363-B1E EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlServer.Server", "Microsoft.SqlServer.Server\Microsoft.SqlServer.Server.csproj", "{A314812A-7820-4565-A2A8-ABBE391C11E4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SqlBench3.0", "..\..\dev\SqlClient-Integrated\SqlBench3.0\SqlBench3.0.csproj", "{1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -489,6 +491,18 @@ Global {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x64.Build.0 = Release|Any CPU {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x86.ActiveCfg = Release|Any CPU {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x86.Build.0 = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x64.ActiveCfg = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x64.Build.0 = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x86.ActiveCfg = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x86.Build.0 = Debug|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|Any CPU.Build.0 = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x64.ActiveCfg = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x64.Build.0 = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x86.ActiveCfg = Release|Any CPU + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -525,6 +539,7 @@ Global {B93A3149-67E8-491E-A1E5-19D65F9D9E98} = {0CC4817A-12F3-4357-912C-09315FAAD008} {599A336B-2A5F-473D-8442-1223ED37C93E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {A314812A-7820-4565-A2A8-ABBE391C11E4} = {4F3CD363-B1E6-4D6D-9466-97D78A56BE45} + {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} 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 7b700a1edd..72a7204f01 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 @@ -10,6 +10,8 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Text; using System.Threading; @@ -12505,14 +12507,14 @@ private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsPar // stateObj._longlenleft is in bytes if ((stateObj._longlenleft >> 1) < (ulong)len) + { charsRead = (int)(stateObj._longlenleft >> 1); + } - for (int ii = 0; ii < charsRead; ii++) + if (!stateObj.TryReadChars(buff, offst, len, out charsRead)) { - if (!stateObj.TryReadChar(out buff[offst + ii])) - { - return false; - } + charsRead = 0; + return false; } stateObj._longlenleft -= ((ulong)charsRead << 1); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 1565a618a2..814e8bc6df 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -487,6 +487,52 @@ internal bool TryReadChar(out char value) AssertValidState(); value = (char)((buffer[1] << 8) + buffer[0]); + + return true; + } + + internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out int charsCopied) + { + charsCopied = 0; + while (charsCopied < charsCount) + { + // check if the current buffer contains some bytes we need to copy and copy them + // in a block + int bytesToRead = Math.Min( + (charsCount - charsCopied) * 2, + unchecked((_inBytesRead - _inBytesUsed) & (int)0xFFFFFFFE) // it the result is odd take off the 0 to make it even + ); + if (bytesToRead > 0) + { + Buffer.BlockCopy( + _inBuff, + _inBytesUsed, + chars, + (charsOffset + charsCopied) * 2, // offset in bytes, + bytesToRead + ); + charsCopied = bytesToRead / 2; + _inBytesUsed += bytesToRead; + _inBytesPacket -= bytesToRead; + } + + // if the number of chars requested is lower than the number copied then we need + // to request a new packet, use TryReadChar() to do this then loop back to see + // if we can copy another bulk of chars from the new buffer + + if (charsCopied < charsCount) + { + bool result = TryReadChar(out chars[charsOffset + charsCopied]); + if (result) + { + charsCopied += 1; + } + else + { + return false; + } + } + } return true; } From 600f607521de24a3b3273b20321056c52c1b5db9 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Mon, 14 Mar 2022 10:39:50 +0000 Subject: [PATCH 2/5] fixes --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 72a7204f01..d0a1822a5c 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 @@ -12503,15 +12503,16 @@ private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsPar return true; } - charsRead = len; + int charsToRead = len; // stateObj._longlenleft is in bytes if ((stateObj._longlenleft >> 1) < (ulong)len) { - charsRead = (int)(stateObj._longlenleft >> 1); + charsToRead = (int)(stateObj._longlenleft >> 1); } - if (!stateObj.TryReadChars(buff, offst, len, out charsRead)) + + if (!stateObj.TryReadChars(buff, offst, charsToRead, out charsRead)) { charsRead = 0; return false; From 01514a62148ac57bccd5333788c5d50c311be79a Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Wed, 13 Apr 2022 20:26:34 +0100 Subject: [PATCH 3/5] minor update for CI results --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d0a1822a5c..c2b1abaa51 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 @@ -12506,7 +12506,7 @@ private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsPar int charsToRead = len; // stateObj._longlenleft is in bytes - if ((stateObj._longlenleft >> 1) < (ulong)len) + if ((stateObj._longlenleft / 2) < (ulong)len) { charsToRead = (int)(stateObj._longlenleft >> 1); } From 63668a3ea6c2af3e5522f09a85b0e60d2ae1d145 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Thu, 18 Aug 2022 23:39:28 +0100 Subject: [PATCH 4/5] revert sln change --- src/Microsoft.Data.SqlClient.sln | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index 3da1a292a1..c5b34945a0 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -205,8 +205,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4F3CD363-B1E EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlServer.Server", "Microsoft.SqlServer.Server\Microsoft.SqlServer.Server.csproj", "{A314812A-7820-4565-A2A8-ABBE391C11E4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SqlBench3.0", "..\..\dev\SqlClient-Integrated\SqlBench3.0\SqlBench3.0.csproj", "{1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -491,18 +489,6 @@ Global {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x64.Build.0 = Release|Any CPU {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x86.ActiveCfg = Release|Any CPU {A314812A-7820-4565-A2A8-ABBE391C11E4}.Release|x86.Build.0 = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x64.ActiveCfg = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x64.Build.0 = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x86.ActiveCfg = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Debug|x86.Build.0 = Debug|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|Any CPU.Build.0 = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x64.ActiveCfg = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x64.Build.0 = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x86.ActiveCfg = Release|Any CPU - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -539,7 +525,6 @@ Global {B93A3149-67E8-491E-A1E5-19D65F9D9E98} = {0CC4817A-12F3-4357-912C-09315FAAD008} {599A336B-2A5F-473D-8442-1223ED37C93E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {A314812A-7820-4565-A2A8-ABBE391C11E4} = {4F3CD363-B1E6-4D6D-9466-97D78A56BE45} - {1BCC919A-CA34-4A5C-B0C3-69A16FA844D7} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} From 2ad4391da28fe0d2cbffd00ad6053199232aed73 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Fri, 3 Feb 2023 23:27:09 +0000 Subject: [PATCH 5/5] move TryReadChars to shared and cleanup --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 3 -- .../Data/SqlClient/TdsParserStateObject.cs | 48 ------------------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 17 ++++--- .../Data/SqlClient/TdsParserStateObject.cs | 45 +++++++++++++++++ 4 files changed, 53 insertions(+), 60 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 c2b1abaa51..49327a4cdd 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 @@ -10,8 +10,6 @@ using System.Diagnostics; using System.Globalization; using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security.Authentication; using System.Text; using System.Threading; @@ -12511,7 +12509,6 @@ private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsPar charsToRead = (int)(stateObj._longlenleft >> 1); } - if (!stateObj.TryReadChars(buff, offst, charsToRead, out charsRead)) { charsRead = 0; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 814e8bc6df..bc7cd362a8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -3,12 +3,9 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Runtime.InteropServices; using System.Security; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.Common; @@ -491,51 +488,6 @@ internal bool TryReadChar(out char value) return true; } - internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out int charsCopied) - { - charsCopied = 0; - while (charsCopied < charsCount) - { - // check if the current buffer contains some bytes we need to copy and copy them - // in a block - int bytesToRead = Math.Min( - (charsCount - charsCopied) * 2, - unchecked((_inBytesRead - _inBytesUsed) & (int)0xFFFFFFFE) // it the result is odd take off the 0 to make it even - ); - if (bytesToRead > 0) - { - Buffer.BlockCopy( - _inBuff, - _inBytesUsed, - chars, - (charsOffset + charsCopied) * 2, // offset in bytes, - bytesToRead - ); - charsCopied = bytesToRead / 2; - _inBytesUsed += bytesToRead; - _inBytesPacket -= bytesToRead; - } - - // if the number of chars requested is lower than the number copied then we need - // to request a new packet, use TryReadChar() to do this then loop back to see - // if we can copy another bulk of chars from the new buffer - - if (charsCopied < charsCount) - { - bool result = TryReadChar(out chars[charsOffset + charsCopied]); - if (result) - { - charsCopied += 1; - } - else - { - return false; - } - } - } - return true; - } - internal bool TryReadInt16(out short value) { Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); 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 70673ef343..a15da77757 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 @@ -13528,7 +13528,6 @@ internal void WriteParameterVarLen(MetaType type, int size, bool isNull, TdsPars // Returns the actual chars read private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsParserStateObject stateObj, out int charsRead) { - Debug.Assert((buff == null && len == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!"); Debug.Assert((stateObj._longlen != 0) && (stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request"); @@ -13539,18 +13538,18 @@ private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsPar return true; } - charsRead = len; + int charsToRead = len; // stateObj._longlenleft is in bytes - if ((stateObj._longlenleft >> 1) < (ulong)len) - charsRead = (int)(stateObj._longlenleft >> 1); + if ((stateObj._longlenleft / 2) < (ulong)len) + { + charsToRead = (int)(stateObj._longlenleft >> 1); + } - for (int ii = 0; ii < charsRead; ii++) + if (!stateObj.TryReadChars(buff, offst, charsToRead, out charsRead)) { - if (!stateObj.TryReadChar(out buff[offst + ii])) - { - return false; - } + charsRead = 0; + return false; } stateObj._longlenleft -= ((ulong)charsRead << 1); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 86f51fba2a..62c02e4db7 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -436,6 +436,51 @@ internal bool TryStartNewRow(bool isNullCompressed, int nullBitmapColumnsCount = return true; } + internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out int charsCopied) + { + charsCopied = 0; + while (charsCopied < charsCount) + { + // check if the current buffer contains some bytes we need to copy and copy them + // in a block + int bytesToRead = Math.Min( + (charsCount - charsCopied) * 2, + unchecked((_inBytesRead - _inBytesUsed) & (int)0xFFFFFFFE) // it the result is odd take off the 0 to make it even + ); + if (bytesToRead > 0) + { + Buffer.BlockCopy( + _inBuff, + _inBytesUsed, + chars, + (charsOffset + charsCopied) * 2, // offset in bytes, + bytesToRead + ); + charsCopied += (bytesToRead / 2); + _inBytesUsed += bytesToRead; + _inBytesPacket -= bytesToRead; + } + + // if the number of chars requested is lower than the number copied then we need + // to request a new packet, use TryReadChar() to do this then loop back to see + // if we can copy another bulk of chars from the new buffer + + if (charsCopied < charsCount) + { + bool result = TryReadChar(out chars[charsOffset + charsCopied]); + if (result) + { + charsCopied += 1; + } + else + { + return false; + } + } + } + return true; + } + internal bool IsRowTokenReady() { // Removing one byte since TryReadByteArray\TryReadByte will aggressively read the next packet if there is no data left - so we need to ensure there is a spare byte