diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs
index 5a877d61e9..edf9fd78e6 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs
@@ -258,11 +258,31 @@ internal _SqlMetaDataSet MetaData
throw SQL.PendingBeginXXXExists();
}
- Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
- if (TryConsumeMetaData() != TdsOperationStatus.Done)
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- throw SQL.SynchronousCallMayNotPend();
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
+ if (TryConsumeMetaData() != TdsOperationStatus.Done)
+ {
+ throw SQL.SynchronousCallMayNotPend();
+ }
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
}
+#endif
}
return _metaData;
}
@@ -837,9 +857,29 @@ private void CleanPartialReadReliable()
{
AssertReaderState(requireData: true, permitAsync: false);
- TdsOperationStatus result = TryCleanPartialRead();
- Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call");
- Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared");
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
+ {
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ TdsOperationStatus result = TryCleanPartialRead();
+ Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call");
+ Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared");
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
}
///
@@ -959,62 +999,82 @@ private TdsOperationStatus TryCloseInternal(bool closeReader)
bool cleanDataFailed = false;
TdsOperationStatus result;
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
try
{
- if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData))
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- // It is possible for this to be called during connection close on a
- // broken connection, so check state first.
- if (parser.State == TdsParserState.OpenLoggedIn)
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData))
{
- // if user called read but didn't fetch any values, skip the row
- // same applies after NextResult on ALTROW because NextResult starts rowconsumption in that case ...
+ // It is possible for this to be called during connection close on a
+ // broken connection, so check state first.
+ if (parser.State == TdsParserState.OpenLoggedIn)
+ {
+ // if user called read but didn't fetch any values, skip the row
+ // same applies after NextResult on ALTROW because NextResult starts rowconsumption in that case ...
- Debug.Assert(SniContext.Snix_Read == stateObj.SniContext, $"The SniContext should be Snix_Read but it actually is {stateObj.SniContext}");
+ Debug.Assert(SniContext.Snix_Read == stateObj.SniContext, $"The SniContext should be Snix_Read but it actually is {stateObj.SniContext}");
- if (_altRowStatus == ALTROWSTATUS.AltRow)
- {
- _sharedState._dataReady = true; // set _sharedState._dataReady to not confuse CleanPartialRead
- }
- _stateObj.SetTimeoutStateStopped();
- if (_sharedState._dataReady)
- {
- cleanDataFailed = true;
- result = TryCleanPartialRead();
- if (result == TdsOperationStatus.Done)
+ if (_altRowStatus == ALTROWSTATUS.AltRow)
{
- cleanDataFailed = false;
+ _sharedState._dataReady = true; // set _sharedState._dataReady to not confuse CleanPartialRead
}
- else
+ _stateObj.SetTimeoutStateStopped();
+ if (_sharedState._dataReady)
{
- return result;
+ cleanDataFailed = true;
+ result = TryCleanPartialRead();
+ if (result == TdsOperationStatus.Done)
+ {
+ cleanDataFailed = false;
+ }
+ else
+ {
+ return result;
+ }
}
- }
#if DEBUG
- else
- {
- byte token;
- result = _stateObj.TryPeekByte(out token);
- if (result != TdsOperationStatus.Done)
+ else
{
- return result;
- }
+ byte token;
+ result = _stateObj.TryPeekByte(out token);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
- Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}");
- }
+ Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}");
+ }
#endif
- result = parser.TryRun(RunBehavior.Clean, _command, this, null, stateObj, out _);
- if (result != TdsOperationStatus.Done)
- {
- return result;
+ result = parser.TryRun(RunBehavior.Clean, _command, this, null, stateObj, out _);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
}
}
- }
- RestoreServerSettings(parser, stateObj);
- return TdsOperationStatus.Done;
+ RestoreServerSettings(parser, stateObj);
+ return TdsOperationStatus.Done;
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
}
finally
{
@@ -1054,25 +1114,44 @@ private TdsOperationStatus TryCloseInternal(bool closeReader)
Connection.RemoveWeakReference(this); // This doesn't catch everything -- the connection may be closed, but it prevents dead readers from clogging the collection
}
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed
- if (!wasClosed && stateObj != null)
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- if (!cleanDataFailed)
- {
- stateObj.CloseSession();
- }
- else
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed
+ if (!wasClosed && stateObj != null)
{
- if (parser != null)
+ if (!cleanDataFailed)
+ {
+ stateObj.CloseSession();
+ }
+ else
{
- parser.State = TdsParserState.Broken; // We failed while draining data, so TDS pointer can be between tokens - cannot recover
- parser.PutSession(stateObj);
- parser.Connection.BreakConnection();
+ if (parser != null)
+ {
+ parser.State = TdsParserState.Broken; // We failed while draining data, so TDS pointer can be between tokens - cannot recover
+ parser.PutSession(stateObj);
+ parser.Connection.BreakConnection();
+ }
}
}
+ // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread
}
- // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
// do not retry here
result = TrySetMetaData(null, false);
@@ -1654,231 +1733,251 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
{
remaining = 0;
TdsOperationStatus result;
- int cbytes = 0;
- AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true);
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- // sequential reading
- if (IsCommandBehavior(CommandBehavior.SequentialAccess))
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader");
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ int cbytes = 0;
+ AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true);
- if (_metaData[i] != null && _metaData[i].cipherMD != null)
+ // sequential reading
+ if (IsCommandBehavior(CommandBehavior.SequentialAccess))
{
- throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column);
- }
+ Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader");
- if (_sharedState._nextColumnHeaderToRead <= i)
- {
- result = TryReadColumnHeader(i);
- if (result != TdsOperationStatus.Done)
+ if (_metaData[i] != null && _metaData[i].cipherMD != null)
{
- return result;
+ throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column);
}
- }
- // If data is null, ReadColumnHeader sets the data.IsNull bit.
- if (_data[i] != null && _data[i].IsNull)
- {
- throw new SqlNullValueException();
- }
+ if (_sharedState._nextColumnHeaderToRead <= i)
+ {
+ result = TryReadColumnHeader(i);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
+ }
- // If there are an unknown (-1) number of bytes left for a PLP, read its size
- if ((-1 == _sharedState._columnDataBytesRemaining) && (_metaData[i].metaType.IsPlp))
- {
- ulong left;
- result = _parser.TryPlpBytesLeft(_stateObj, out left);
- if (result != TdsOperationStatus.Done)
+ // If data is null, ReadColumnHeader sets the data.IsNull bit.
+ if (_data[i] != null && _data[i].IsNull)
{
- return result;
+ throw new SqlNullValueException();
}
- _sharedState._columnDataBytesRemaining = (long)left;
- }
- if (0 == _sharedState._columnDataBytesRemaining)
- {
- return TdsOperationStatus.Done; // We've read this column to the end
- }
+ // If there are an unknown (-1) number of bytes left for a PLP, read its size
+ if ((-1 == _sharedState._columnDataBytesRemaining) && (_metaData[i].metaType.IsPlp))
+ {
+ ulong left;
+ result = _parser.TryPlpBytesLeft(_stateObj, out left);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
+ _sharedState._columnDataBytesRemaining = (long)left;
+ }
- // if no buffer is passed in, return the number total of bytes, or -1
- if (buffer == null)
- {
- if (_metaData[i].metaType.IsPlp)
+ if (0 == _sharedState._columnDataBytesRemaining)
{
- remaining = (long)_parser.PlpBytesTotalLength(_stateObj);
+ return TdsOperationStatus.Done; // We've read this column to the end
+ }
+
+ // if no buffer is passed in, return the number total of bytes, or -1
+ if (buffer == null)
+ {
+ if (_metaData[i].metaType.IsPlp)
+ {
+ remaining = (long)_parser.PlpBytesTotalLength(_stateObj);
+ return TdsOperationStatus.Done;
+ }
+ remaining = _sharedState._columnDataBytesRemaining;
return TdsOperationStatus.Done;
}
- remaining = _sharedState._columnDataBytesRemaining;
- return TdsOperationStatus.Done;
- }
- if (dataIndex < 0)
- {
- throw ADP.NegativeParameter(nameof(dataIndex));
- }
+ if (dataIndex < 0)
+ {
+ throw ADP.NegativeParameter(nameof(dataIndex));
+ }
- if (dataIndex < _columnDataBytesRead)
- {
- throw ADP.NonSeqByteAccess(dataIndex, _columnDataBytesRead, nameof(GetBytes));
- }
+ if (dataIndex < _columnDataBytesRead)
+ {
+ throw ADP.NonSeqByteAccess(dataIndex, _columnDataBytesRead, nameof(GetBytes));
+ }
- // if the dataIndex is not equal to bytes read, then we have to skip bytes
- long cb = dataIndex - _columnDataBytesRead;
+ // if the dataIndex is not equal to bytes read, then we have to skip bytes
+ long cb = dataIndex - _columnDataBytesRead;
- // if dataIndex is outside of the data range, return 0
- if ((cb > _sharedState._columnDataBytesRemaining) && !_metaData[i].metaType.IsPlp)
- {
- return TdsOperationStatus.Done;
- }
+ // if dataIndex is outside of the data range, return 0
+ if ((cb > _sharedState._columnDataBytesRemaining) && !_metaData[i].metaType.IsPlp)
+ {
+ return TdsOperationStatus.Done;
+ }
- // if bad buffer index, throw
- if (bufferIndex < 0 || bufferIndex >= buffer.Length)
- {
- throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
- }
+ // if bad buffer index, throw
+ if (bufferIndex < 0 || bufferIndex >= buffer.Length)
+ {
+ throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
+ }
- // if there is not enough room in the buffer for data
- if (length + bufferIndex > buffer.Length)
- {
- throw ADP.InvalidBufferSizeOrIndex(length, bufferIndex);
- }
+ // if there is not enough room in the buffer for data
+ if (length + bufferIndex > buffer.Length)
+ {
+ throw ADP.InvalidBufferSizeOrIndex(length, bufferIndex);
+ }
- if (length < 0)
- {
- throw ADP.InvalidDataLength(length);
- }
+ if (length < 0)
+ {
+ throw ADP.InvalidDataLength(length);
+ }
- // Skip if needed
- if (cb > 0)
- {
- if (_metaData[i].metaType.IsPlp)
+ // Skip if needed
+ if (cb > 0)
{
- ulong skipped;
- result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped);
- if (result != TdsOperationStatus.Done)
+ if (_metaData[i].metaType.IsPlp)
{
- return result;
+ ulong skipped;
+ result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
+ _columnDataBytesRead += (long)skipped;
}
- _columnDataBytesRead += (long)skipped;
- }
- else
- {
- result = _stateObj.TrySkipLongBytes(cb);
- if (result != TdsOperationStatus.Done)
+ else
{
- return result;
+ result = _stateObj.TrySkipLongBytes(cb);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
+ _columnDataBytesRead += cb;
+ _sharedState._columnDataBytesRemaining -= cb;
}
- _columnDataBytesRead += cb;
- _sharedState._columnDataBytesRemaining -= cb;
}
- }
- int bytesRead;
- result = TryGetBytesInternalSequential(i, buffer, bufferIndex, length, out bytesRead);
- remaining = (int)bytesRead;
- return result;
- }
-
- // random access now!
- // note that since we are caching in an array, and arrays aren't 64 bit ready yet,
- // we need can cast to int if the dataIndex is in range
- if (dataIndex < 0)
- {
- throw ADP.NegativeParameter(nameof(dataIndex));
- }
+ int bytesRead;
+ result = TryGetBytesInternalSequential(i, buffer, bufferIndex, length, out bytesRead);
+ remaining = (int)bytesRead;
+ return result;
+ }
- if (dataIndex > int.MaxValue)
- {
- throw ADP.InvalidSourceBufferIndex(cbytes, dataIndex, nameof(dataIndex));
- }
+ // random access now!
+ // note that since we are caching in an array, and arrays aren't 64 bit ready yet,
+ // we need can cast to int if the dataIndex is in range
+ if (dataIndex < 0)
+ {
+ throw ADP.NegativeParameter(nameof(dataIndex));
+ }
- int ndataIndex = (int)dataIndex;
- byte[] data;
+ if (dataIndex > int.MaxValue)
+ {
+ throw ADP.InvalidSourceBufferIndex(cbytes, dataIndex, nameof(dataIndex));
+ }
- // WebData 99342 - in the non-sequential case, we need to support
- // the use of GetBytes on string data columns, but
- // GetSqlBinary isn't supposed to. What we end up
- // doing isn't exactly pretty, but it does work.
- if (_metaData[i].metaType.IsBinType)
- {
- data = GetSqlBinary(i).Value;
- }
- else
- {
- Debug.Assert(_metaData[i].metaType.IsLong, "non long type?");
- Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?");
+ int ndataIndex = (int)dataIndex;
+ byte[] data;
- SqlString temp = GetSqlString(i);
- if (_metaData[i].metaType.IsNCharType)
+ // WebData 99342 - in the non-sequential case, we need to support
+ // the use of GetBytes on string data columns, but
+ // GetSqlBinary isn't supposed to. What we end up
+ // doing isn't exactly pretty, but it does work.
+ if (_metaData[i].metaType.IsBinType)
{
- data = temp.GetUnicodeBytes();
+ data = GetSqlBinary(i).Value;
}
else
{
- data = temp.GetNonUnicodeBytes();
- }
- }
-
- cbytes = data.Length;
+ Debug.Assert(_metaData[i].metaType.IsLong, "non long type?");
+ Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?");
- // if no buffer is passed in, return the number of characters we have
- if (buffer == null)
- {
- remaining = cbytes;
- return TdsOperationStatus.Done;
- }
-
- // if dataIndex is outside of data range, return 0
- if (ndataIndex < 0 || ndataIndex >= cbytes)
- {
- return TdsOperationStatus.Done;
- }
- try
- {
- if (ndataIndex < cbytes)
- {
- // help the user out in the case where there's less data than requested
- if ((ndataIndex + length) > cbytes)
+ SqlString temp = GetSqlString(i);
+ if (_metaData[i].metaType.IsNCharType)
{
- cbytes = cbytes - ndataIndex;
+ data = temp.GetUnicodeBytes();
}
else
{
- cbytes = length;
+ data = temp.GetNonUnicodeBytes();
}
}
- Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes);
- }
- catch (Exception e)
- {
- if (!ADP.IsCatchableExceptionType(e))
- {
- throw;
- }
cbytes = data.Length;
- if (length < 0)
+ // if no buffer is passed in, return the number of characters we have
+ if (buffer == null)
{
- throw ADP.InvalidDataLength(length);
+ remaining = cbytes;
+ return TdsOperationStatus.Done;
}
- // if bad buffer index, throw
- if (bufferIndex < 0 || bufferIndex >= buffer.Length)
+ // if dataIndex is outside of data range, return 0
+ if (ndataIndex < 0 || ndataIndex >= cbytes)
{
- throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
+ return TdsOperationStatus.Done;
}
+ try
+ {
+ if (ndataIndex < cbytes)
+ {
+ // help the user out in the case where there's less data than requested
+ if ((ndataIndex + length) > cbytes)
+ {
+ cbytes = cbytes - ndataIndex;
+ }
+ else
+ {
+ cbytes = length;
+ }
+ }
- // if there is not enough room in the buffer for data
- if (cbytes + bufferIndex > buffer.Length)
+ Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes);
+ }
+ catch (Exception e)
{
- throw ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex);
+ if (!ADP.IsCatchableExceptionType(e))
+ {
+ throw;
+ }
+ cbytes = data.Length;
+
+ if (length < 0)
+ {
+ throw ADP.InvalidDataLength(length);
+ }
+
+ // if bad buffer index, throw
+ if (bufferIndex < 0 || bufferIndex >= buffer.Length)
+ {
+ throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
+ }
+
+ // if there is not enough room in the buffer for data
+ if (cbytes + bufferIndex > buffer.Length)
+ {
+ throw ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex);
+ }
+
+ throw;
}
- throw;
+ remaining = cbytes;
+ return TdsOperationStatus.Done;
}
-
- remaining = cbytes;
- return TdsOperationStatus.Done;
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif //DEBUG
}
internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int length, long? timeoutMilliseconds = null)
@@ -1930,46 +2029,66 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer,
bytesRead = 0;
TdsOperationStatus result;
- if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0))
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- // No data left or nothing requested, return 0
- bytesRead = 0;
- return TdsOperationStatus.Done;
- }
- else
+ tdsReliabilitySection.Start();
+#else
{
- // if plp columns, do partial reads. Don't read the entire value in one shot.
- if (_metaData[i].metaType.IsPlp)
+#endif
+ if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0))
{
- // Read in data
- result = _stateObj.TryReadPlpBytes(ref buffer, index, length, out bytesRead);
- _columnDataBytesRead += bytesRead;
- if (result != TdsOperationStatus.Done)
+ // No data left or nothing requested, return 0
+ bytesRead = 0;
+ return TdsOperationStatus.Done;
+ }
+ else
+ {
+ // if plp columns, do partial reads. Don't read the entire value in one shot.
+ if (_metaData[i].metaType.IsPlp)
{
- return result;
- }
+ // Read in data
+ result = _stateObj.TryReadPlpBytes(ref buffer, index, length, out bytesRead);
+ _columnDataBytesRead += bytesRead;
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
- // Query for number of bytes left
- ulong left;
- result = _parser.TryPlpBytesLeft(_stateObj, out left);
- if (result != TdsOperationStatus.Done)
+ // Query for number of bytes left
+ ulong left;
+ result = _parser.TryPlpBytesLeft(_stateObj, out left);
+ if (result != TdsOperationStatus.Done)
+ {
+ _sharedState._columnDataBytesRemaining = -1;
+ return result;
+ }
+ _sharedState._columnDataBytesRemaining = (long)left;
+ return TdsOperationStatus.Done;
+ }
+ else
{
- _sharedState._columnDataBytesRemaining = -1;
+ // Read data (not exceeding the total amount of data available)
+ int bytesToRead = (int)Math.Min((long)length, _sharedState._columnDataBytesRemaining);
+ result = _stateObj.TryReadByteArray(buffer.AsSpan(index), bytesToRead, out bytesRead);
+ _columnDataBytesRead += bytesRead;
+ _sharedState._columnDataBytesRemaining -= bytesRead;
return result;
}
- _sharedState._columnDataBytesRemaining = (long)left;
- return TdsOperationStatus.Done;
- }
- else
- {
- // Read data (not exceeding the total amount of data available)
- int bytesToRead = (int)Math.Min((long)length, _sharedState._columnDataBytesRemaining);
- result = _stateObj.TryReadByteArray(buffer.AsSpan(index), bytesToRead, out bytesRead);
- _columnDataBytesRead += bytesRead;
- _sharedState._columnDataBytesRemaining -= bytesRead;
- return result;
}
}
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
}
///
@@ -2241,93 +2360,113 @@ override public long GetChars(int i, long dataIndex, char[] buffer, int bufferIn
private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int bufferIndex, int length)
{
- long cch;
-
- AssertReaderState(requireData: true, permitAsync: false, columnIndex: i, enforceSequentialAccess: true);
- Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has active Stream or TextReader");
- // don't allow get bytes on non-long or non-binary columns
- Debug.Assert(_metaData[i].metaType.IsPlp, "GetCharsFromPlpData called on a non-plp column!");
- // Must be sequential reading
- Debug.Assert(IsCommandBehavior(CommandBehavior.SequentialAccess), "GetCharsFromPlpData called for non-Sequential access");
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- if (!_metaData[i].metaType.IsCharType)
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- throw SQL.NonCharColumn(_metaData[i].column);
- }
-
- if (_sharedState._nextColumnHeaderToRead <= i)
+ tdsReliabilitySection.Start();
+#else
{
- ReadColumnHeader(i);
- }
+#endif
+ long cch;
- // If data is null, ReadColumnHeader sets the data.IsNull bit.
- if (_data[i] != null && _data[i].IsNull)
- {
- throw new SqlNullValueException();
- }
+ AssertReaderState(requireData: true, permitAsync: false, columnIndex: i, enforceSequentialAccess: true);
+ Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has active Stream or TextReader");
+ // don't allow get bytes on non-long or non-binary columns
+ Debug.Assert(_metaData[i].metaType.IsPlp, "GetCharsFromPlpData called on a non-plp column!");
+ // Must be sequential reading
+ Debug.Assert(IsCommandBehavior(CommandBehavior.SequentialAccess), "GetCharsFromPlpData called for non-Sequential access");
- if (dataIndex < _columnDataCharsRead)
- {
- // Don't allow re-read of same chars in sequential access mode
- throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars));
- }
+ if (!_metaData[i].metaType.IsCharType)
+ {
+ throw SQL.NonCharColumn(_metaData[i].column);
+ }
- // If we start reading the new column, either dataIndex is 0 or
- // _columnDataCharsRead is 0 and dataIndex > _columnDataCharsRead is true below.
- // In both cases we will clean decoder
- if (dataIndex == 0)
- {
- _stateObj._plpdecoder = null;
- }
+ if (_sharedState._nextColumnHeaderToRead <= i)
+ {
+ ReadColumnHeader(i);
+ }
- bool isUnicode = _metaData[i].metaType.IsNCharType;
+ // If data is null, ReadColumnHeader sets the data.IsNull bit.
+ if (_data[i] != null && _data[i].IsNull)
+ {
+ throw new SqlNullValueException();
+ }
- // If there are an unknown (-1) number of bytes left for a PLP, read its size
- if (-1 == _sharedState._columnDataBytesRemaining)
- {
- _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
- }
+ if (dataIndex < _columnDataCharsRead)
+ {
+ // Don't allow re-read of same chars in sequential access mode
+ throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars));
+ }
- if (0 == _sharedState._columnDataBytesRemaining)
- {
- _stateObj._plpdecoder = null;
- return 0; // We've read this column to the end
- }
+ // If we start reading the new column, either dataIndex is 0 or
+ // _columnDataCharsRead is 0 and dataIndex > _columnDataCharsRead is true below.
+ // In both cases we will clean decoder
+ if (dataIndex == 0)
+ {
+ _stateObj._plpdecoder = null;
+ }
- // if no buffer is passed in, return the total number of characters or -1
- if (buffer == null)
- {
- cch = (long)_parser.PlpBytesTotalLength(_stateObj);
- return (isUnicode && (cch > 0)) ? cch >> 1 : cch;
- }
- if (dataIndex > _columnDataCharsRead)
- {
- // Skip chars
+ bool isUnicode = _metaData[i].metaType.IsNCharType;
- // Clean decoder state: we do not reset it, but destroy to ensure
- // that we do not start decoding the column with decoder from the old one
- _stateObj._plpdecoder = null;
- cch = dataIndex - _columnDataCharsRead;
- cch = isUnicode ? (cch << 1) : cch;
- cch = (long)_parser.SkipPlpValue((ulong)(cch), _stateObj);
- _columnDataBytesRead += cch;
- _columnDataCharsRead += (isUnicode && (cch > 0)) ? cch >> 1 : cch;
- }
- cch = length;
+ // If there are an unknown (-1) number of bytes left for a PLP, read its size
+ if (-1 == _sharedState._columnDataBytesRemaining)
+ {
+ _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
+ }
- if (isUnicode)
- {
- cch = (long)_parser.ReadPlpUnicodeChars(ref buffer, bufferIndex, length, _stateObj);
- _columnDataBytesRead += (cch << 1);
+ if (0 == _sharedState._columnDataBytesRemaining)
+ {
+ _stateObj._plpdecoder = null;
+ return 0; // We've read this column to the end
+ }
+
+ // if no buffer is passed in, return the total number of characters or -1
+ if (buffer == null)
+ {
+ cch = (long)_parser.PlpBytesTotalLength(_stateObj);
+ return (isUnicode && (cch > 0)) ? cch >> 1 : cch;
+ }
+ if (dataIndex > _columnDataCharsRead)
+ {
+ // Skip chars
+
+ // Clean decoder state: we do not reset it, but destroy to ensure
+ // that we do not start decoding the column with decoder from the old one
+ _stateObj._plpdecoder = null;
+ cch = dataIndex - _columnDataCharsRead;
+ cch = isUnicode ? (cch << 1) : cch;
+ cch = (long)_parser.SkipPlpValue((ulong)(cch), _stateObj);
+ _columnDataBytesRead += cch;
+ _columnDataCharsRead += (isUnicode && (cch > 0)) ? cch >> 1 : cch;
+ }
+ cch = length;
+
+ if (isUnicode)
+ {
+ cch = (long)_parser.ReadPlpUnicodeChars(ref buffer, bufferIndex, length, _stateObj);
+ _columnDataBytesRead += (cch << 1);
+ }
+ else
+ {
+ cch = (long)_parser.ReadPlpAnsiChars(ref buffer, bufferIndex, length, _metaData[i], _stateObj);
+ _columnDataBytesRead += cch << 1;
+ }
+ _columnDataCharsRead += cch;
+ _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
+ return cch;
}
- else
+#if NETFRAMEWORK && DEBUG
+ finally
{
- cch = (long)_parser.ReadPlpAnsiChars(ref buffer, bufferIndex, length, _metaData[i], _stateObj);
- _columnDataBytesRead += cch << 1;
+ tdsReliabilitySection.Stop();
}
- _columnDataCharsRead += cch;
- _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
- return cch;
+#endif
}
internal long GetStreamingXmlChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length)
@@ -3422,140 +3561,161 @@ private TdsOperationStatus TryNextResult(out bool more)
SqlStatistics statistics = null;
using (TryEventScope.Create("SqlDataReader.NextResult | API | Object Id {0}", ObjectID))
{
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+
try
{
- statistics = SqlStatistics.StartTimer(Statistics);
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- SetTimeout(_defaultTimeoutMilliseconds);
-
- if (IsClosed)
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- throw ADP.DataReaderClosed(nameof(NextResult));
- }
- _fieldNameLookup = null;
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ statistics = SqlStatistics.StartTimer(Statistics);
- bool success = false; // WebData 100390
- _hasRows = false; // reset HasRows
+ SetTimeout(_defaultTimeoutMilliseconds);
- // if we are specifically only processing a single result, then read all the results off the wire and detach
- if (IsCommandBehavior(CommandBehavior.SingleResult))
- {
- result = TryCloseInternal(closeReader: false);
- if (result != TdsOperationStatus.Done)
+ if (IsClosed)
{
- more = false;
- return result;
+ throw ADP.DataReaderClosed(nameof(NextResult));
}
+ _fieldNameLookup = null;
- // In the case of not closing the reader, null out the metadata AFTER
- // CloseInternal finishes - since CloseInternal may go to the wire
- // and use the metadata.
- ClearMetaData();
- more = success;
- return TdsOperationStatus.Done;
- }
+ bool success = false; // WebData 100390
+ _hasRows = false; // reset HasRows
- if (_parser != null)
- {
- // if there are more rows, then skip them, the user wants the next result
- bool moreRows = true;
- while (moreRows)
+ // if we are specifically only processing a single result, then read all the results off the wire and detach
+ if (IsCommandBehavior(CommandBehavior.SingleResult))
{
- result = TryReadInternal(false, out moreRows);
+ result = TryCloseInternal(closeReader: false);
if (result != TdsOperationStatus.Done)
{
- // don't reset set the timeout value
more = false;
return result;
}
- }
- }
- // we may be done, so continue only if we have not detached ourselves from the parser
- if (_parser != null)
- {
- bool moreResults;
- result = TryHasMoreResults(out moreResults);
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
+ // In the case of not closing the reader, null out the metadata AFTER
+ // CloseInternal finishes - since CloseInternal may go to the wire
+ // and use the metadata.
+ ClearMetaData();
+ more = success;
+ return TdsOperationStatus.Done;
}
- if (moreResults)
- {
- _metaDataConsumed = false;
- _browseModeInfoConsumed = false;
- switch (_altRowStatus)
+ if (_parser != null)
+ {
+ // if there are more rows, then skip them, the user wants the next result
+ bool moreRows = true;
+ while (moreRows)
{
- case ALTROWSTATUS.AltRow:
- int altRowId;
- result = _parser.TryGetAltRowId(_stateObj, out altRowId);
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
- }
- _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId);
- if (altMetaDataSet != null)
- {
- _metaData = altMetaDataSet;
- }
- Debug.Assert((_metaData != null), "Can't match up altrowmetadata");
- break;
- case ALTROWSTATUS.Done:
- // restore the row-metaData
- _metaData = _altMetaDataSetCollection.metaDataSet;
- Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus");
- _altRowStatus = ALTROWSTATUS.Null;
- break;
- default:
- result = TryConsumeMetaData();
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
- }
- if (_metaData == null)
- {
- more = false;
- return TdsOperationStatus.Done;
- }
- break;
+ result = TryReadInternal(false, out moreRows);
+ if (result != TdsOperationStatus.Done)
+ {
+ // don't reset set the timeout value
+ more = false;
+ return result;
+ }
}
-
- success = true;
}
- else
+
+ // we may be done, so continue only if we have not detached ourselves from the parser
+ if (_parser != null)
{
- // detach the parser from this reader now
- result = TryCloseInternal(closeReader: false);
+ bool moreResults;
+ result = TryHasMoreResults(out moreResults);
if (result != TdsOperationStatus.Done)
{
more = false;
- return TdsOperationStatus.Done;
+ return result;
}
+ if (moreResults)
+ {
+ _metaDataConsumed = false;
+ _browseModeInfoConsumed = false;
- // In the case of not closing the reader, null out the metadata AFTER
- // CloseInternal finishes - since CloseInternal may go to the wire
- // and use the metadata.
- result = TrySetMetaData(null, false);
- if (result != TdsOperationStatus.Done)
+ switch (_altRowStatus)
+ {
+ case ALTROWSTATUS.AltRow:
+ int altRowId;
+ result = _parser.TryGetAltRowId(_stateObj, out altRowId);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
+ _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId);
+ if (altMetaDataSet != null)
+ {
+ _metaData = altMetaDataSet;
+ }
+ Debug.Assert((_metaData != null), "Can't match up altrowmetadata");
+ break;
+ case ALTROWSTATUS.Done:
+ // restore the row-metaData
+ _metaData = _altMetaDataSetCollection.metaDataSet;
+ Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus");
+ _altRowStatus = ALTROWSTATUS.Null;
+ break;
+ default:
+ result = TryConsumeMetaData();
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
+ if (_metaData == null)
+ {
+ more = false;
+ return TdsOperationStatus.Done;
+ }
+ break;
+ }
+
+ success = true;
+ }
+ else
{
- more = false;
- return result;
+ // detach the parser from this reader now
+ result = TryCloseInternal(closeReader: false);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return TdsOperationStatus.Done;
+ }
+
+ // In the case of not closing the reader, null out the metadata AFTER
+ // CloseInternal finishes - since CloseInternal may go to the wire
+ // and use the metadata.
+ result = TrySetMetaData(null, false);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
}
}
+ else
+ {
+ // Clear state in case of Read calling CloseInternal() then user calls NextResult()
+ // and the case where the Read() above will do essentially the same thing.
+ ClearMetaData();
+ }
+
+ more = success;
+ return TdsOperationStatus.Done;
}
- else
+#if NETFRAMEWORK && DEBUG
+ finally
{
- // Clear state in case of Read calling CloseInternal() then user calls NextResult()
- // and the case where the Read() above will do essentially the same thing.
- ClearMetaData();
+ tdsReliabilitySection.Stop();
}
-
- more = success;
- return TdsOperationStatus.Done;
+#endif
}
finally
{
@@ -3597,117 +3757,140 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more)
try
{
- TdsOperationStatus result;
- statistics = SqlStatistics.StartTimer(Statistics);
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- if (_parser != null)
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- if (setTimeout)
- {
- SetTimeout(_defaultTimeoutMilliseconds);
- }
- if (_sharedState._dataReady)
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ TdsOperationStatus result;
+ statistics = SqlStatistics.StartTimer(Statistics);
+
+ if (_parser != null)
{
- result = TryCleanPartialRead();
- if (result != TdsOperationStatus.Done)
+ if (setTimeout)
{
- more = false;
- return result;
+ SetTimeout(_defaultTimeoutMilliseconds);
+ }
+ if (_sharedState._dataReady)
+ {
+ result = TryCleanPartialRead();
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
}
- }
- // clear out our buffers
- SqlBuffer.Clear(_data);
+ // clear out our buffers
+ SqlBuffer.Clear(_data);
- _sharedState._nextColumnHeaderToRead = 0;
- _sharedState._nextColumnDataToRead = 0;
- _sharedState._columnDataBytesRemaining = -1; // unknown
- _lastColumnWithDataChunkRead = -1;
+ _sharedState._nextColumnHeaderToRead = 0;
+ _sharedState._nextColumnDataToRead = 0;
+ _sharedState._columnDataBytesRemaining = -1; // unknown
+ _lastColumnWithDataChunkRead = -1;
- if (!_haltRead)
- {
- bool moreRows;
- result = TryHasMoreRows(out moreRows);
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
- }
- if (moreRows)
+ if (!_haltRead)
{
- // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...)
- while (_stateObj.HasPendingData)
+ bool moreRows;
+ result = TryHasMoreRows(out moreRows);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
+ if (moreRows)
{
- if (_altRowStatus != ALTROWSTATUS.AltRow)
+ // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...)
+ while (_stateObj.HasPendingData)
{
- // if this is an ordinary row we let the run method consume the ROW token
- result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady);
- if (result != TdsOperationStatus.Done)
+ if (_altRowStatus != ALTROWSTATUS.AltRow)
{
- more = false;
- return result;
+ // if this is an ordinary row we let the run method consume the ROW token
+ result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
+ if (_sharedState._dataReady)
+ {
+ break;
+ }
}
- if (_sharedState._dataReady)
+ else
{
+ // ALTROW token and AltrowId are already consumed ...
+ Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus");
+ _altRowStatus = ALTROWSTATUS.Done;
+ _sharedState._dataReady = true;
break;
}
}
- else
+ if (_sharedState._dataReady)
{
- // ALTROW token and AltrowId are already consumed ...
- Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus");
- _altRowStatus = ALTROWSTATUS.Done;
- _sharedState._dataReady = true;
- break;
+ _haltRead = IsCommandBehavior(CommandBehavior.SingleRow);
+ more = true;
+ return TdsOperationStatus.Done;
}
}
- if (_sharedState._dataReady)
+
+ if (!_stateObj.HasPendingData)
{
- _haltRead = IsCommandBehavior(CommandBehavior.SingleRow);
- more = true;
- return TdsOperationStatus.Done;
+ result = TryCloseInternal(closeReader: false);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
}
}
-
- if (!_stateObj.HasPendingData)
+ else
{
- result = TryCloseInternal(closeReader: false);
+ // if we did not get a row and halt is true, clean off rows of result
+ // success must be false - or else we could have just read off row and set
+ // halt to true
+ bool moreRows;
+ result = TryHasMoreRows(out moreRows);
if (result != TdsOperationStatus.Done)
{
more = false;
return result;
}
- }
- }
- else
- {
- // if we did not get a row and halt is true, clean off rows of result
- // success must be false - or else we could have just read off row and set
- // halt to true
- bool moreRows;
- result = TryHasMoreRows(out moreRows);
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
- }
- while (moreRows)
- {
- // if we are in SingleRow mode, and we've read the first row,
- // read the rest of the rows, if any
- while (_stateObj.HasPendingData && !_sharedState._dataReady)
+ while (moreRows)
{
- result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady);
- if (result != TdsOperationStatus.Done)
+ // if we are in SingleRow mode, and we've read the first row,
+ // read the rest of the rows, if any
+ while (_stateObj.HasPendingData && !_sharedState._dataReady)
{
- more = false;
- return result;
+ result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady);
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
}
- }
- if (_sharedState._dataReady)
- {
- result = TryCleanPartialRead();
+ if (_sharedState._dataReady)
+ {
+ result = TryCleanPartialRead();
+ if (result != TdsOperationStatus.Done)
+ {
+ more = false;
+ return result;
+ }
+ }
+
+ // clear out our buffers
+ SqlBuffer.Clear(_data);
+
+ _sharedState._nextColumnHeaderToRead = 0;
+
+ result = TryHasMoreRows(out moreRows);
if (result != TdsOperationStatus.Done)
{
more = false;
@@ -3715,44 +3898,38 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more)
}
}
- // clear out our buffers
- SqlBuffer.Clear(_data);
-
- _sharedState._nextColumnHeaderToRead = 0;
-
- result = TryHasMoreRows(out moreRows);
- if (result != TdsOperationStatus.Done)
- {
- more = false;
- return result;
- }
+ // reset haltRead
+ _haltRead = false;
}
-
- // reset haltRead
- _haltRead = false;
}
- }
- else if (IsClosed)
- {
- throw ADP.DataReaderClosed(nameof(Read));
- }
- more = false;
+ else if (IsClosed)
+ {
+ throw ADP.DataReaderClosed(nameof(Read));
+ }
+ more = false;
#if DEBUG
- if ((!_sharedState._dataReady) && (_stateObj.HasPendingData))
- {
- byte token;
- result = _stateObj.TryPeekByte(out token);
- if (result != TdsOperationStatus.Done)
+ if ((!_sharedState._dataReady) && (_stateObj.HasPendingData))
{
- return result;
- }
+ byte token;
+ result = _stateObj.TryPeekByte(out token);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
- Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}");
- }
+ Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}");
+ }
#endif
- return TdsOperationStatus.Done;
+ return TdsOperationStatus.Done;
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif //DEBUG
}
catch (OutOfMemoryException e)
{
@@ -3812,22 +3989,41 @@ private void ReadColumn(int i, bool setTimeout = true, bool allowPartiallyReadCo
private TdsOperationStatus TryReadColumn(int i, bool setTimeout, bool allowPartiallyReadColumn = false, bool forStreaming = false)
{
CheckDataIsReady(columnIndex: i, permitAsync: true, allowPartiallyReadColumn: allowPartiallyReadColumn, methodName: null);
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
- Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large");
- Debug.Assert(_sharedState._nextColumnDataToRead <= _metaData.Length, "_sharedState._nextColumnDataToRead too large");
-
- if (setTimeout)
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
{
- SetTimeout(_defaultTimeoutMilliseconds);
- }
-
- TdsOperationStatus result = TryReadColumnInternal(i, readHeaderOnly: false, forStreaming: forStreaming);
- if (result != TdsOperationStatus.Done)
+ tdsReliabilitySection.Start();
+#else
{
- return result;
+#endif
+ Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large");
+ Debug.Assert(_sharedState._nextColumnDataToRead <= _metaData.Length, "_sharedState._nextColumnDataToRead too large");
+
+ if (setTimeout)
+ {
+ SetTimeout(_defaultTimeoutMilliseconds);
+ }
+
+ TdsOperationStatus result = TryReadColumnInternal(i, readHeaderOnly: false, forStreaming: forStreaming);
+ if (result != TdsOperationStatus.Done)
+ {
+ return result;
+ }
+
+ Debug.Assert(_data[i] != null, " data buffer is null?");
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
}
-
- Debug.Assert(_data[i] != null, " data buffer is null?");
+#endif
return TdsOperationStatus.Done;
}
@@ -3870,7 +4066,28 @@ private TdsOperationStatus TryReadColumnHeader(int i)
{
throw SQL.InvalidRead();
}
- return TryReadColumnInternal(i, readHeaderOnly: true);
+
+#if NETFRAMEWORK
+ RuntimeHelpers.PrepareConstrainedRegions();
+#endif
+#if NETFRAMEWORK && DEBUG
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
+ {
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ return TryReadColumnInternal(i, readHeaderOnly: true);
+ }
+#if NETFRAMEWORK && DEBUG
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
}
internal TdsOperationStatus TryReadColumnInternal(int i, bool readHeaderOnly = false, bool forStreaming = false)
@@ -5342,7 +5559,23 @@ private static Task GetFieldValueAsyncExecute(Task task, object state)
if (reader.IsCommandBehavior(CommandBehavior.SequentialAccess) && reader._sharedState._dataReady)
{
bool internalReadSuccess = false;
- internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done;
+#if NETFRAMEWORK
+ TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
+ {
+ tdsReliabilitySection.Start();
+#else
+ {
+#endif
+ internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done;
+ }
+#if NETFRAMEWORK
+ finally
+ {
+ tdsReliabilitySection.Stop();
+ }
+#endif
if (internalReadSuccess)
{
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs
index 9eab4ae44f..4f655dc403 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs
@@ -22,8 +22,8 @@ private struct RuntimeHelpers
/// This is a no-op in netcore version. Only needed for merging with netfx codebase.
///
[Conditional("NETFRAMEWORK")]
- internal static void PrepareConstrainedRegions()
- {
+ internal static void PrepareConstrainedRegions()
+ {
}
}
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 0ee952026a..b3cf628594 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
@@ -18,7 +18,7 @@ namespace Microsoft.Data.SqlClient
using PacketHandle = IntPtr;
using RuntimeHelpers = System.Runtime.CompilerServices.RuntimeHelpers;
#endif
-
+
sealed internal class LastIOTimer
{
internal long _value;