From 4dde0bff420568bfe50e2b3f43764232ce63768c Mon Sep 17 00:00:00 2001 From: Michel Zehnder Date: Sun, 3 Nov 2024 17:22:19 +0100 Subject: [PATCH 1/5] Align CER from netfx to netcore for code merge netfx/netcore --- .../src/Microsoft.Data.SqlClient.csproj | 1 + .../Microsoft/Data/SqlClient/SqlDataReader.cs | 1297 ++++++++++------- .../SqlClient/TdsParserStateObject.netcore.cs | 11 - .../netcore/src/RuntimeHelpers.cs | 15 + .../Microsoft/Data/SqlClient/SqlDataReader.cs | 1 + 5 files changed, 767 insertions(+), 558 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.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 de863051e0..045f2535f2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -674,6 +674,7 @@ + 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..2b9fdee247 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,30 @@ internal _SqlMetaDataSet MetaData throw SQL.PendingBeginXXXExists(); } - Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); - if (TryConsumeMetaData() != TdsOperationStatus.Done) + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + + Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + if (TryConsumeMetaData() != TdsOperationStatus.Done) + { + throw SQL.SynchronousCallMayNotPend(); + } + } +#if DEBUG + finally { - throw SQL.SynchronousCallMayNotPend(); + tdsReliabilitySection.Stop(); } +#endif //DEBUG } return _metaData; } @@ -837,9 +856,27 @@ 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"); + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + TdsOperationStatus result = TryCleanPartialRead(); + Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call"); + Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared"); + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } /// @@ -958,63 +995,80 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) bool aborting = false; bool cleanDataFailed = false; TdsOperationStatus result; - + RuntimeHelpers.PrepareConstrainedRegions(); try { - if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) +#if 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 //DEBUG + 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 DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } finally { @@ -1055,24 +1109,42 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) } - // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed - if (!wasClosed && stateObj != null) + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try { - if (!cleanDataFailed) - { - stateObj.CloseSession(); - } - else + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + // 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 DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG // do not retry here result = TrySetMetaData(null, false); @@ -1654,231 +1726,249 @@ 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); + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - // sequential reading - if (IsCommandBehavior(CommandBehavior.SequentialAccess)) + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else { - Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader"); +#endif //DEBUG + 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) + { + 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) { - remaining = (long)_parser.PlpBytesTotalLength(_stateObj); + 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; - - // if no buffer is passed in, return the number of characters we have - if (buffer == null) - { - remaining = cbytes; - return TdsOperationStatus.Done; - } + Debug.Assert(_metaData[i].metaType.IsLong, "non long type?"); + Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?"); - // 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 DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int length, long? timeoutMilliseconds = null) @@ -1930,46 +2020,63 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer, bytesRead = 0; TdsOperationStatus result; - if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) - { - // No data left or nothing requested, return 0 - bytesRead = 0; - return TdsOperationStatus.Done; - } - else + + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try { - // if plp columns, do partial reads. Don't read the entire value in one shot. - if (_metaData[i].metaType.IsPlp) + tdsReliabilitySection.Start(); +#endif //DEBUG + 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 DEBUG } + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } /// @@ -2241,93 +2348,111 @@ 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"); + RuntimeHelpers.PrepareConstrainedRegions(); +#if 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 //DEBUG + 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 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 //DEBUG } internal long GetStreamingXmlChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) @@ -3422,140 +3547,159 @@ private TdsOperationStatus TryNextResult(out bool more) SqlStatistics statistics = null; using (TryEventScope.Create("SqlDataReader.NextResult | API | Object Id {0}", ObjectID)) { + RuntimeHelpers.PrepareConstrainedRegions(); + try { - statistics = SqlStatistics.StartTimer(Statistics); - - SetTimeout(_defaultTimeoutMilliseconds); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - if (IsClosed) + RuntimeHelpers.PrepareConstrainedRegions(); + try { - throw ADP.DataReaderClosed(nameof(NextResult)); - } - _fieldNameLookup = null; + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + 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 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 //DEBUG } finally { @@ -3591,123 +3735,144 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) SqlStatistics statistics = null; using (TryEventScope.Create("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID)) { -#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#endif try { - TdsOperationStatus result; - statistics = SqlStatistics.StartTimer(Statistics); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - if (_parser != null) + RuntimeHelpers.PrepareConstrainedRegions(); + try { - if (setTimeout) - { - SetTimeout(_defaultTimeoutMilliseconds); - } - if (_sharedState._dataReady) + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + 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 +3880,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 DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } catch (OutOfMemoryException e) { @@ -3813,21 +3972,39 @@ private TdsOperationStatus TryReadColumn(int i, bool setTimeout, bool allowParti { CheckDataIsReady(columnIndex: i, permitAsync: true, allowPartiallyReadColumn: allowPartiallyReadColumn, methodName: null); - Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large"); - Debug.Assert(_sharedState._nextColumnDataToRead <= _metaData.Length, "_sharedState._nextColumnDataToRead too large"); + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - if (setTimeout) + RuntimeHelpers.PrepareConstrainedRegions(); + try { - SetTimeout(_defaultTimeoutMilliseconds); + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + 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?"); } - - TdsOperationStatus result = TryReadColumnInternal(i, readHeaderOnly: false, forStreaming: forStreaming); - if (result != TdsOperationStatus.Done) +#if DEBUG + finally { - return result; + tdsReliabilitySection.Stop(); } - - Debug.Assert(_data[i] != null, " data buffer is null?"); +#endif //DEBUG return TdsOperationStatus.Done; } @@ -3870,7 +4047,23 @@ private TdsOperationStatus TryReadColumnHeader(int i) { throw SQL.InvalidRead(); } - return TryReadColumnInternal(i, readHeaderOnly: true); + RuntimeHelpers.PrepareConstrainedRegions(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#endif //DEBUG + return TryReadColumnInternal(i, readHeaderOnly: true); +#if DEBUG + } + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG } internal TdsOperationStatus TryReadColumnInternal(int i, bool readHeaderOnly = false, bool forStreaming = false) @@ -5342,7 +5535,17 @@ 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; + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); + internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done; + } + finally + { + tdsReliabilitySection.Stop(); + } 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..4b91371883 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 @@ -16,17 +16,6 @@ namespace Microsoft.Data.SqlClient { internal abstract partial class TdsParserStateObject { - private struct RuntimeHelpers - { - /// - /// This is a no-op in netcore version. Only needed for merging with netfx codebase. - /// - [Conditional("NETFRAMEWORK")] - internal static void PrepareConstrainedRegions() - { - } - } - private static readonly ContextCallback s_readAsyncCallbackComplete = ReadAsyncCallbackComplete; // Timeout variables diff --git a/src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs b/src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs new file mode 100644 index 0000000000..6a01273a73 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs @@ -0,0 +1,15 @@ +using System.Diagnostics; + +namespace Microsoft.Data.SqlClient +{ + internal struct RuntimeHelpers + { + /// + /// This is a no-op in netcore version. Only needed for merging with netfx codebase. + /// + [Conditional("NETFRAMEWORK")] + internal static void PrepareConstrainedRegions() + { + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index d3a2e605da..2ac927c841 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -3999,6 +3999,7 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) SqlStatistics statistics = null; using (TryEventScope.Create(" {0}", ObjectID)) { +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); try From ab0fd785a2c19b87daa3f669dca98417b4be2338 Mon Sep 17 00:00:00 2001 From: Michel Zehnder Date: Sun, 3 Nov 2024 17:25:49 +0100 Subject: [PATCH 2/5] Remove missed NETFRAMEWORK check --- .../netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 2ac927c841..d3a2e605da 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -3999,7 +3999,6 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) SqlStatistics statistics = null; using (TryEventScope.Create(" {0}", ObjectID)) { -#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); try From 982819d2b0c07a2215904242f7414d1852e48de3 Mon Sep 17 00:00:00 2001 From: Michel Zehnder Date: Mon, 4 Nov 2024 07:39:16 +0100 Subject: [PATCH 3/5] Find a new home for RuntimeHelpers --- .../Runtime/CompilerServicesOverride}/RuntimeHelpers.cs | 2 +- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- .../netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs | 1 + .../Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs | 1 + .../src/Microsoft/Data/SqlClient/TdsParserStateObject.cs | 4 +++- 5 files changed, 7 insertions(+), 3 deletions(-) rename src/Microsoft.Data.SqlClient/netcore/src/{ => Common/System/Runtime/CompilerServicesOverride}/RuntimeHelpers.cs (86%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs similarity index 86% rename from src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs index 6a01273a73..da9ae4467f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/RuntimeHelpers.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs @@ -1,6 +1,6 @@ using System.Diagnostics; -namespace Microsoft.Data.SqlClient +namespace System.Runtime.CompilerServicesOverride { internal struct RuntimeHelpers { 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 045f2535f2..fa35590230 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -628,6 +628,7 @@ + @@ -674,7 +675,6 @@ - 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 2b9fdee247..94f1e63b0f 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 @@ -14,6 +14,7 @@ using System.Globalization; using System.IO; using System.Reflection; +using RuntimeHelpers = System.Runtime.CompilerServicesOverride.RuntimeHelpers; using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; 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 4b91371883..a63753ceb4 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 @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Buffers.Binary; +using System.Runtime.CompilerServicesOverride; using System.Runtime.InteropServices; using System.Security; using System.Threading; 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..28987dde6c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -17,8 +17,10 @@ namespace Microsoft.Data.SqlClient #if NETFRAMEWORK using PacketHandle = IntPtr; using RuntimeHelpers = System.Runtime.CompilerServices.RuntimeHelpers; +#else + using System.Runtime.CompilerServicesOverride; #endif - + sealed internal class LastIOTimer { internal long _value; From 19d0997b7ba723b655f6a7c92469ebdbcce30f25 Mon Sep 17 00:00:00 2001 From: Michel Zehnder Date: Wed, 6 Nov 2024 08:42:56 +0100 Subject: [PATCH 4/5] Rebase main & Move RuntimeHelpers --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- .../Data/SqlClient}/RuntimeHelpers.cs | 2 +- .../netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs | 1 - .../Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs | 1 - .../src/Microsoft/Data/SqlClient/TdsParserStateObject.cs | 2 -- 5 files changed, 2 insertions(+), 6 deletions(-) rename src/Microsoft.Data.SqlClient/netcore/src/{Common/System/Runtime/CompilerServicesOverride => Microsoft/Data/SqlClient}/RuntimeHelpers.cs (86%) 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 fa35590230..41db4a8a6b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -628,11 +628,11 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs similarity index 86% rename from src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs index da9ae4467f..6a01273a73 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/System/Runtime/CompilerServicesOverride/RuntimeHelpers.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs @@ -1,6 +1,6 @@ using System.Diagnostics; -namespace System.Runtime.CompilerServicesOverride +namespace Microsoft.Data.SqlClient { internal struct RuntimeHelpers { 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 94f1e63b0f..2b9fdee247 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 @@ -14,7 +14,6 @@ using System.Globalization; using System.IO; using System.Reflection; -using RuntimeHelpers = System.Runtime.CompilerServicesOverride.RuntimeHelpers; using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; 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 a63753ceb4..4b91371883 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 @@ -5,7 +5,6 @@ using System; using System.Diagnostics; using System.Buffers.Binary; -using System.Runtime.CompilerServicesOverride; using System.Runtime.InteropServices; using System.Security; using System.Threading; 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 28987dde6c..b3cf628594 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -17,8 +17,6 @@ namespace Microsoft.Data.SqlClient #if NETFRAMEWORK using PacketHandle = IntPtr; using RuntimeHelpers = System.Runtime.CompilerServices.RuntimeHelpers; -#else - using System.Runtime.CompilerServicesOverride; #endif sealed internal class LastIOTimer From 759e6e0d3c02984535ed096d0f9fa49b5818f32d Mon Sep 17 00:00:00 2001 From: Michel Zehnder Date: Wed, 13 Nov 2024 09:07:32 +0100 Subject: [PATCH 5/5] Wrap CER/TDSReliabilitySection in #IF NETFRAMEWORK --- .../src/Microsoft.Data.SqlClient.csproj | 1 - .../Data/SqlClient/RuntimeHelpers.cs | 15 -- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 174 ++++++++++-------- .../SqlClient/TdsParserStateObject.netcore.cs | 11 ++ 4 files changed, 113 insertions(+), 88 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.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 41db4a8a6b..de863051e0 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -632,7 +632,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs deleted file mode 100644 index 6a01273a73..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/RuntimeHelpers.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Diagnostics; - -namespace Microsoft.Data.SqlClient -{ - internal struct RuntimeHelpers - { - /// - /// This is a no-op in netcore version. Only needed for merging with netfx codebase. - /// - [Conditional("NETFRAMEWORK")] - internal static void PrepareConstrainedRegions() - { - } - } -} 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 2b9fdee247..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,8 +258,10 @@ internal _SqlMetaDataSet MetaData throw SQL.PendingBeginXXXExists(); } +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -268,20 +270,19 @@ internal _SqlMetaDataSet MetaData tdsReliabilitySection.Start(); #else { -#endif //DEBUG - +#endif Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); if (TryConsumeMetaData() != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif } return _metaData; } @@ -856,27 +857,29 @@ private void CleanPartialReadReliable() { AssertReaderState(requireData: true, permitAsync: false); +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); +#endif +#if NETFRAMEWORK && DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else - { -#endif //DEBUG - TdsOperationStatus result = TryCleanPartialRead(); - Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call"); - Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared"); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + { +#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 } /// @@ -995,10 +998,13 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) bool aborting = false; bool cleanDataFailed = false; TdsOperationStatus result; + +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { -#if DEBUG +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -1007,7 +1013,7 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) { // It is possible for this to be called during connection close on a @@ -1063,12 +1069,12 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) RestoreServerSettings(parser, stateObj); return TdsOperationStatus.Done; } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif } finally { @@ -1108,9 +1114,10 @@ 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(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -1119,7 +1126,7 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed if (!wasClosed && stateObj != null) { @@ -1139,12 +1146,12 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) } // 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 DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif // do not retry here result = TrySetMetaData(null, false); @@ -1726,8 +1733,10 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf { remaining = 0; TdsOperationStatus result; +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -1736,7 +1745,7 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif int cbytes = 0; AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true); @@ -1963,7 +1972,7 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf remaining = cbytes; return TdsOperationStatus.Done; } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); @@ -2020,16 +2029,19 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer, bytesRead = 0; TdsOperationStatus result; - +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); -#endif //DEBUG +#else + { +#endif if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) { // No data left or nothing requested, return 0 @@ -2070,13 +2082,13 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer, return result; } } -#if DEBUG } +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif } /// @@ -2348,8 +2360,10 @@ 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) { +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -2358,7 +2372,7 @@ private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int buffe tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif long cch; AssertReaderState(requireData: true, permitAsync: false, columnIndex: i, enforceSequentialAccess: true); @@ -2447,12 +2461,12 @@ private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int buffe _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj); return cch; } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif } internal long GetStreamingXmlChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) @@ -3547,11 +3561,13 @@ private TdsOperationStatus TryNextResult(out bool more) SqlStatistics statistics = null; using (TryEventScope.Create("SqlDataReader.NextResult | API | Object Id {0}", ObjectID)) { - RuntimeHelpers.PrepareConstrainedRegions(); +#if NETFRAMEWORK + RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { -#if DEBUG +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -3560,7 +3576,7 @@ private TdsOperationStatus TryNextResult(out bool more) tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif statistics = SqlStatistics.StartTimer(Statistics); SetTimeout(_defaultTimeoutMilliseconds); @@ -3694,12 +3710,12 @@ private TdsOperationStatus TryNextResult(out bool more) more = success; return TdsOperationStatus.Done; } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif } finally { @@ -3735,11 +3751,13 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) SqlStatistics statistics = null; using (TryEventScope.Create("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID)) { +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { -#if DEBUG +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -3748,7 +3766,7 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif TdsOperationStatus result; statistics = SqlStatistics.StartTimer(Statistics); @@ -3906,7 +3924,7 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) return TdsOperationStatus.Done; } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); @@ -3971,9 +3989,10 @@ 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(); -#if DEBUG +#endif +#if NETFRAMEWORK && DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); @@ -3982,7 +4001,7 @@ private TdsOperationStatus TryReadColumn(int i, bool setTimeout, bool allowParti tdsReliabilitySection.Start(); #else { -#endif //DEBUG +#endif Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large"); Debug.Assert(_sharedState._nextColumnDataToRead <= _metaData.Length, "_sharedState._nextColumnDataToRead too large"); @@ -3999,12 +4018,12 @@ private TdsOperationStatus TryReadColumn(int i, bool setTimeout, bool allowParti Debug.Assert(_data[i] != null, " data buffer is null?"); } -#if DEBUG +#if NETFRAMEWORK && DEBUG finally { tdsReliabilitySection.Stop(); } -#endif //DEBUG +#endif return TdsOperationStatus.Done; } @@ -4047,23 +4066,28 @@ private TdsOperationStatus TryReadColumnHeader(int i) { throw SQL.InvalidRead(); } + +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); +#endif +#if NETFRAMEWORK && DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - return TryReadColumnInternal(i, readHeaderOnly: true); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + 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) @@ -5535,17 +5559,23 @@ private static Task GetFieldValueAsyncExecute(Task task, object state) if (reader.IsCommandBehavior(CommandBehavior.SequentialAccess) && reader._sharedState._dataReady) { bool internalReadSuccess = false; +#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 4b91371883..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 @@ -16,6 +16,17 @@ namespace Microsoft.Data.SqlClient { internal abstract partial class TdsParserStateObject { + private struct RuntimeHelpers + { + /// + /// This is a no-op in netcore version. Only needed for merging with netfx codebase. + /// + [Conditional("NETFRAMEWORK")] + internal static void PrepareConstrainedRegions() + { + } + } + private static readonly ContextCallback s_readAsyncCallbackComplete = ReadAsyncCallbackComplete; // Timeout variables