Skip to content

Commit

Permalink
2. Merging "Buffer read" methods of TdsParserStateObject, port dotnet…
Browse files Browse the repository at this point in the history
…#667 to netfx.
  • Loading branch information
panoskj committed Sep 25, 2023
1 parent bebf28c commit ecc8c29
Show file tree
Hide file tree
Showing 3 changed files with 387 additions and 774 deletions.
Expand Up @@ -282,393 +282,6 @@ internal void StartSession(object cancellationOwner)
// Buffer read methods - data values //
///////////////////////////////////////

internal bool TryReadInt16(out short value)
{
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");

Span<byte> buffer = stackalloc byte[2];
if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2))
{
// If the int16 isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.
if (!TryReadByteArray(buffer, 2))
{
value = default;
return false;
}
}
else
{
// The entire int16 is in the packet and in the buffer, so just return it
// and take care of the counters.
buffer = _inBuff.AsSpan(_inBytesUsed, 2);
_inBytesUsed += 2;
_inBytesPacket -= 2;
}

AssertValidState();
value = (short)((buffer[1] << 8) + buffer[0]);
return true;
}

internal bool TryReadInt32(out int value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt32"); // you need to setup for a thread abort somewhere before you call this method
#endif
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
Span<byte> buffer = stackalloc byte[4];
if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4))
{
// If the int isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.
if (!TryReadByteArray(buffer, 4))
{
value = 0;
return false;
}
}
else
{
// The entire int is in the packet and in the buffer, so just return it
// and take care of the counters.
buffer = _inBuff.AsSpan(_inBytesUsed, 4);
_inBytesUsed += 4;
_inBytesPacket -= 4;
}

AssertValidState();
value = (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
return true;
}

// This method is safe to call when doing async without snapshot
internal bool TryReadInt64(out long value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt64"); // you need to setup for a thread abort somewhere before you call this method
#endif
if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead))
{
if (!TryPrepareBuffer())
{
value = 0;
return false;
}
}

if ((_bTmpRead > 0) || (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)))
{
// If the long isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.

int bytesRead;
if (!TryReadByteArray(_bTmp.AsSpan(start: _bTmpRead), 8 - _bTmpRead, out bytesRead))
{
Debug.Assert(_bTmpRead + bytesRead <= 8, "Read more data than required");
_bTmpRead += bytesRead;
value = 0;
return false;
}
else
{
Debug.Assert(_bTmpRead + bytesRead == 8, "TryReadByteArray returned true without reading all data required");
_bTmpRead = 0;
AssertValidState();
value = BitConverter.ToInt64(_bTmp, 0);
return true;
}
}
else
{
// The entire long is in the packet and in the buffer, so just return it
// and take care of the counters.

value = BitConverter.ToInt64(_inBuff, _inBytesUsed);

_inBytesUsed += 8;
_inBytesPacket -= 8;

AssertValidState();
return true;
}
}

internal bool TryReadUInt16(out ushort value)
{
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");

Span<byte> buffer = stackalloc byte[2];
if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2))
{
// If the uint16 isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.
if (!TryReadByteArray(buffer, 2))
{
value = default;
return false;
}
}
else
{
// The entire uint16 is in the packet and in the buffer, so just return it
// and take care of the counters.
buffer = _inBuff.AsSpan(_inBytesUsed, 2);
_inBytesUsed += 2;
_inBytesPacket -= 2;
}

AssertValidState();
value = (ushort)((buffer[1] << 8) + buffer[0]);
return true;
}

// This method is safe to call when doing async without replay
internal bool TryReadUInt32(out uint value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadUInt32"); // you need to setup for a thread abort somewhere before you call this method
#endif
if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead))
{
if (!TryPrepareBuffer())
{
value = 0;
return false;
}
}

if ((_bTmpRead > 0) || (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)))
{
// If the int isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.

int bytesRead;
if (!TryReadByteArray(_bTmp.AsSpan(start: _bTmpRead), 4 - _bTmpRead, out bytesRead))
{
Debug.Assert(_bTmpRead + bytesRead <= 4, "Read more data than required");
_bTmpRead += bytesRead;
value = 0;
return false;
}
else
{
Debug.Assert(_bTmpRead + bytesRead == 4, "TryReadByteArray returned true without reading all data required");
_bTmpRead = 0;
AssertValidState();
value = BitConverter.ToUInt32(_bTmp, 0);
return true;
}
}
else
{
// The entire int is in the packet and in the buffer, so just return it
// and take care of the counters.

value = BitConverter.ToUInt32(_inBuff, _inBytesUsed);

_inBytesUsed += 4;
_inBytesPacket -= 4;

AssertValidState();
return true;
}
}

internal bool TryReadSingle(out float value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadSingle"); // you need to setup for a thread abort somewhere before you call this method
#endif
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4))
{
// If the float isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.

if (!TryReadByteArray(_bTmp, 4))
{
value = default;
return false;
}

AssertValidState();
value = BitConverter.ToSingle(_bTmp, 0);
return true;
}
else
{
// The entire float is in the packet and in the buffer, so just return it
// and take care of the counters.

value = BitConverter.ToSingle(_inBuff, _inBytesUsed);

_inBytesUsed += 4;
_inBytesPacket -= 4;

AssertValidState();
return true;
}
}

internal bool TryReadDouble(out double value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadDouble"); // you need to setup for a thread abort somewhere before you call this method
#endif
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8))
{
// If the double isn't fully in the buffer, or if it isn't fully in the packet,
// then use ReadByteArray since the logic is there to take care of that.

if (!TryReadByteArray(_bTmp, 8))
{
value = default;
return false;
}

AssertValidState();
value = BitConverter.ToDouble(_bTmp, 0);
return true;
}
else
{
// The entire double is in the packet and in the buffer, so just return it
// and take care of the counters.

value = BitConverter.ToDouble(_inBuff, _inBytesUsed);

_inBytesUsed += 8;
_inBytesPacket -= 8;

AssertValidState();
return true;
}
}

internal bool TryReadString(int length, out string value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadString"); // you need to setup for a thread abort somewhere before you call this method
#endif
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
int cBytes = length << 1;
byte[] buf;
int offset = 0;

if (((_inBytesUsed + cBytes) > _inBytesRead) || (_inBytesPacket < cBytes))
{
if (_bTmp == null || _bTmp.Length < cBytes)
{
_bTmp = new byte[cBytes];
}

if (!TryReadByteArray(_bTmp, cBytes))
{
value = null;
return false;
}

// assign local to point to parser scratch buffer
buf = _bTmp;

AssertValidState();
}
else
{
// assign local to point to _inBuff
buf = _inBuff;
offset = _inBytesUsed;
_inBytesUsed += cBytes;
_inBytesPacket -= cBytes;

AssertValidState();
}

value = System.Text.Encoding.Unicode.GetString(buf, offset, cBytes);
return true;
}

internal bool TryReadStringWithEncoding(int length, System.Text.Encoding encoding, bool isPlp, out string value)
{
#if NETFRAMEWORK
TdsParser.ReliabilitySection.Assert("unreliable call to ReadStringWithEncoding"); // you need to setup for a thread abort somewhere before you call this method
#endif
Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");

if (null == encoding)
{
// Need to skip the current column before throwing the error - this ensures that the state shared between this and the data reader is consistent when calling DrainData
if (isPlp)
{
if (!_parser.TrySkipPlpValue((ulong)length, this, out _))
{
value = null;
return false;
}
}
else
{
if (!TrySkipBytes(length))
{
value = null;
return false;
}
}

_parser.ThrowUnsupportedCollationEncountered(this);
}
byte[] buf = null;
int offset = 0;

if (isPlp)
{
if (!TryReadPlpBytes(ref buf, 0, int.MaxValue, out length))
{
value = null;
return false;
}

AssertValidState();
}
else
{
if (((_inBytesUsed + length) > _inBytesRead) || (_inBytesPacket < length))
{
if (_bTmp == null || _bTmp.Length < length)
{
_bTmp = new byte[length];
}

if (!TryReadByteArray(_bTmp, length))
{
value = null;
return false;
}

// assign local to point to parser scratch buffer
buf = _bTmp;

AssertValidState();
}
else
{
// assign local to point to _inBuff
buf = _inBuff;
offset = _inBytesUsed;
_inBytesUsed += length;
_inBytesPacket -= length;

AssertValidState();
}
}

// BCL optimizes to not use char[] underneath
value = encoding.GetString(buf, offset, length);
return true;
}

internal ulong ReadPlpLength(bool returnPlpNullIfNull)
{
ulong value;
Expand Down

0 comments on commit ecc8c29

Please sign in to comment.