Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge | Align Task usage / ArrayPool / IsColumnEncryptionSupported netcore/netfx #2982

Merged
merged 14 commits into from
Nov 26, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -6710,19 +6710,35 @@ private TdsOperationStatus TryReadSqlStringValue(SqlBuffer value, byte type, int
if (isPlp)
{
char[] cc = null;

result = TryReadPlpUnicodeChars(ref cc, 0, length >> 1, stateObj, out length);
if (result != TdsOperationStatus.Done)
bool buffIsRented = false;
result = TryReadPlpUnicodeChars(ref cc, 0, length >> 1, stateObj, out length, supportRentedBuff: true, rentedBuff: ref buffIsRented);

if (result == TdsOperationStatus.Done)
{
return result;
if (length > 0)
{
s = new string(cc, 0, length);
}
else
{
s = "";
MichelZ marked this conversation as resolved.
Show resolved Hide resolved
}
}
if (length > 0)

if (buffIsRented)
{
s = new string(cc, 0, length);
// do not use clearArray:true on the rented array because it can be massively larger
// than the space we've used and we would incur performance clearing memory that
// we haven't used and can't leak out information.
// clear only the length that we know we have used.
cc.AsSpan(0, length).Clear();
ArrayPool<char>.Shared.Return(cc, clearArray: false);
cc = null;
}
else

if (result != TdsOperationStatus.Done)
{
s = "";
return result;
}
}
else
Expand Down Expand Up @@ -13680,8 +13696,9 @@ private TdsOperationStatus TryReadPlpUnicodeCharsChunk(char[] buff, int offst, i
internal int ReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj)
{
int charsRead;
bool rentedBuff = false;
Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
TdsOperationStatus result = TryReadPlpUnicodeChars(ref buff, offst, len, stateObj, out charsRead);
TdsOperationStatus result = TryReadPlpUnicodeChars(ref buff, offst, len, stateObj, out charsRead, supportRentedBuff: false, ref rentedBuff);
if (result != TdsOperationStatus.Done)
{
throw SQL.SynchronousCallMayNotPend();
Expand All @@ -13693,32 +13710,42 @@ internal int ReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserS
// requested length is -1 or larger than the actual length of data. First call to this method
// should be preceeded by a call to ReadPlpLength or ReadDataLength.
// Returns the actual chars read.
internal TdsOperationStatus TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead)
internal TdsOperationStatus TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead, bool supportRentedBuff, ref bool rentedBuff)
MichelZ marked this conversation as resolved.
Show resolved Hide resolved
{
int charsRead = 0;
int charsLeft = 0;
char[] newbuf;
TdsOperationStatus result;


if (stateObj._longlen == 0)
{
Debug.Assert(stateObj._longlenleft == 0);
totalCharsRead = 0;
return TdsOperationStatus.Done; // No data
}

Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL),
"Out of sync plp read request");
Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request");
MichelZ marked this conversation as resolved.
Show resolved Hide resolved

Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!");
charsLeft = len;

// If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time
if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN)
// If total length is known up front, the length isn't specified as unknown
// and the caller doesn't pass int.max/2 indicating that it doesn't know the length
// allocate the whole buffer in one shot instead of realloc'ing and copying over each time
if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN && len < (int.MaxValue >> 1))
{
buff = new char[(int)Math.Min((int)stateObj._longlen, len)];
if (supportRentedBuff && len < 1073741824) // 1 Gib
{
buff = ArrayPool<char>.Shared.Rent((int)Math.Min((int)stateObj._longlen, len));
rentedBuff = true;
}
else
{
buff = new char[(int)Math.Min((int)stateObj._longlen, len)];
rentedBuff = false;
}
}

TdsOperationStatus result;
if (stateObj._longlenleft == 0)
{
result = stateObj.TryReadPlpLength(false, out _);
Expand All @@ -13740,11 +13767,26 @@ internal TdsOperationStatus TryReadPlpUnicodeChars(ref char[] buff, int offst, i
charsRead = (int)Math.Min((stateObj._longlenleft + 1) >> 1, (ulong)charsLeft);
if ((buff == null) || (buff.Length < (offst + charsRead)))
{
// Grow the array
newbuf = new char[offst + charsRead];
bool returnRentedBufferAfterCopy = rentedBuff;
if (supportRentedBuff && (offst + charsRead) < 1073741824) // 1 Gib
{
newbuf = ArrayPool<char>.Shared.Rent(offst + charsRead);
rentedBuff = true;
}
else
{
newbuf = new char[offst + charsRead];
rentedBuff = false;
}

if (buff != null)
{
Buffer.BlockCopy(buff, 0, newbuf, 0, offst * 2);
if (returnRentedBufferAfterCopy)
{
buff.AsSpan(0, offst).Clear();
ArrayPool<char>.Shared.Return(buff, clearArray: false);
}
}
buff = newbuf;
}
Expand Down
Loading