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 f0ae13e6cd..986e464acb 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 @@ -257,33 +257,14 @@ internal _SqlMetaDataSet MetaData { throw SQL.PendingBeginXXXExists(); } - -#if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); -#endif -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + + Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + if (TryConsumeMetaData() != TdsOperationStatus.Done) { -#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(); + throw SQL.SynchronousCallMayNotPend(); } -#endif } + return _metaData; } } @@ -856,30 +837,10 @@ private TdsOperationStatus TryCleanPartialRead() private void CleanPartialReadReliable() { AssertReaderState(requireData: true, permitAsync: false); - -#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 + + TdsOperationStatus result = TryCleanPartialRead(); + Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call"); + Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared"); } /// @@ -1004,77 +965,60 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) #endif try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) { -#endif - if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) + // It is possible for this to be called during connection close on a + // broken connection, so check state first. + if (parser.State == TdsParserState.OpenLoggedIn) { - // 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 ... + // 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) + 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) { - _sharedState._dataReady = true; // set _sharedState._dataReady to not confuse CleanPartialRead + cleanDataFailed = false; } - _stateObj.SetTimeoutStateStopped(); - if (_sharedState._dataReady) + else { - cleanDataFailed = true; - result = TryCleanPartialRead(); - if (result == TdsOperationStatus.Done) - { - cleanDataFailed = false; - } - else - { - return result; - } + return result; } + } #if DEBUG - else + else + { + byte token; + result = _stateObj.TryPeekByte(out token); + if (result != TdsOperationStatus.Done) { - 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}"); + return result; } + + 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; } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif + + RestoreServerSettings(parser, stateObj); + return TdsOperationStatus.Done; } finally { @@ -1113,45 +1057,25 @@ 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(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + + // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed + if (!wasClosed && stateObj != null) { -#endif - // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed - if (!wasClosed && stateObj != null) + if (!cleanDataFailed) { - if (!cleanDataFailed) + stateObj.CloseSession(); + } + else + { + if (parser != null) { - stateObj.CloseSession(); - } - else - { - 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(); - } + 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 - } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); } -#endif + // 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 retry here result = TrySetMetaData(null, false); @@ -1731,251 +1655,232 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf { remaining = 0; TdsOperationStatus result; -#if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); -#endif -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + int cbytes = 0; + AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true); + + // sequential reading + if (IsCommandBehavior(CommandBehavior.SequentialAccess)) { -#endif - int cbytes = 0; - AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true); + Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader"); - // sequential reading - if (IsCommandBehavior(CommandBehavior.SequentialAccess)) + if (_metaData[i] != null && _metaData[i].cipherMD != null) { - Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader"); - - if (_metaData[i] != null && _metaData[i].cipherMD != null) - { - throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column); - } + throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column); + } - if (_sharedState._nextColumnHeaderToRead <= i) + if (_sharedState._nextColumnHeaderToRead <= i) + { + result = TryReadColumnHeader(i); + if (result != TdsOperationStatus.Done) { - result = TryReadColumnHeader(i); - if (result != TdsOperationStatus.Done) - { - return result; - } + return result; } + } - // If data is null, ReadColumnHeader sets the data.IsNull bit. - if (_data[i] != null && _data[i].IsNull) - { - throw new SqlNullValueException(); - } + // 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) && (_metaData[i].metaType.IsPlp)) + // 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) { - ulong left; - result = _parser.TryPlpBytesLeft(_stateObj, out left); - if (result != TdsOperationStatus.Done) - { - return result; - } - _sharedState._columnDataBytesRemaining = (long)left; + return result; } + _sharedState._columnDataBytesRemaining = (long)left; + } - if (0 == _sharedState._columnDataBytesRemaining) - { - return TdsOperationStatus.Done; // We've read this column to the end - } + 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) + // if no buffer is passed in, return the number total of bytes, or -1 + if (buffer == null) + { + if (_metaData[i].metaType.IsPlp) { - if (_metaData[i].metaType.IsPlp) - { - remaining = (long)_parser.PlpBytesTotalLength(_stateObj); - return TdsOperationStatus.Done; - } - remaining = _sharedState._columnDataBytesRemaining; + remaining = (long)_parser.PlpBytesTotalLength(_stateObj); 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) + // Skip if needed + if (cb > 0) + { + if (_metaData[i].metaType.IsPlp) { - if (_metaData[i].metaType.IsPlp) + ulong skipped; + result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped); + if (result != TdsOperationStatus.Done) { - ulong skipped; - result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped); - if (result != TdsOperationStatus.Done) - { - return result; - } - _columnDataBytesRead += (long)skipped; + return result; } - else + _columnDataBytesRead += (long)skipped; + } + else + { + result = _stateObj.TrySkipLongBytes(cb); + if (result != TdsOperationStatus.Done) { - result = _stateObj.TrySkipLongBytes(cb); - if (result != TdsOperationStatus.Done) - { - return result; - } - _columnDataBytesRead += cb; - _sharedState._columnDataBytesRemaining -= cb; + return result; } + _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)); + } + + int ndataIndex = (int)dataIndex; + byte[] data; - // 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) + // 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?"); + + SqlString temp = GetSqlString(i); + if (_metaData[i].metaType.IsNCharType) { - data = GetSqlBinary(i).Value; + data = temp.GetUnicodeBytes(); } else { - Debug.Assert(_metaData[i].metaType.IsLong, "non long type?"); - Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?"); + 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; + } - SqlString temp = GetSqlString(i); - if (_metaData[i].metaType.IsNCharType) + // 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) { - data = temp.GetUnicodeBytes(); + cbytes = cbytes - ndataIndex; } else { - data = temp.GetNonUnicodeBytes(); + cbytes = length; } } + Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes); + } + catch (Exception e) + { + if (!ADP.IsCatchableExceptionType(e)) + { + throw; + } cbytes = data.Length; - // if no buffer is passed in, return the number of characters we have - if (buffer == null) + if (length < 0) { - remaining = cbytes; - return TdsOperationStatus.Done; + throw ADP.InvalidDataLength(length); } - // if dataIndex is outside of data range, return 0 - if (ndataIndex < 0 || ndataIndex >= cbytes) + // if bad buffer index, throw + if (bufferIndex < 0 || bufferIndex >= buffer.Length) { - return TdsOperationStatus.Done; + throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex)); } - 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; - } - } - Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes); - } - catch (Exception e) + // if there is not enough room in the buffer for data + if (cbytes + bufferIndex > buffer.Length) { - 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 ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex); } - remaining = cbytes; - return TdsOperationStatus.Done; + throw; } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + + remaining = cbytes; + return TdsOperationStatus.Done; } internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int length, long? timeoutMilliseconds = null) @@ -2027,66 +1932,47 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer, bytesRead = 0; TdsOperationStatus result; -#if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); -#endif -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try + if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) { - tdsReliabilitySection.Start(); -#else + // No data left or nothing requested, return 0 + bytesRead = 0; + return TdsOperationStatus.Done; + } + else { -#endif - if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) - { - // 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) { - // if plp columns, do partial reads. Don't read the entire value in one shot. - if (_metaData[i].metaType.IsPlp) + // Read in data + result = _stateObj.TryReadPlpBytes(ref buffer, index, length, out bytesRead); + _columnDataBytesRead += bytesRead; + if (result != TdsOperationStatus.Done) { - // 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) - { - _sharedState._columnDataBytesRemaining = -1; - return result; - } - _sharedState._columnDataBytesRemaining = (long)left; - return TdsOperationStatus.Done; + return result; } - else + + // Query for number of bytes left + ulong left; + result = _parser.TryPlpBytesLeft(_stateObj, out left); + if (result != TdsOperationStatus.Done) { - // 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; + _sharedState._columnDataBytesRemaining = -1; 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 } /// @@ -2358,113 +2244,93 @@ 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(); -#endif -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + long cch; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif - 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"); + 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 (!_metaData[i].metaType.IsCharType) - { - throw SQL.NonCharColumn(_metaData[i].column); - } + if (!_metaData[i].metaType.IsCharType) + { + throw SQL.NonCharColumn(_metaData[i].column); + } - if (_sharedState._nextColumnHeaderToRead <= i) - { - ReadColumnHeader(i); - } + if (_sharedState._nextColumnHeaderToRead <= i) + { + ReadColumnHeader(i); + } - // If data is null, ReadColumnHeader sets the data.IsNull bit. - if (_data[i] != null && _data[i].IsNull) - { - throw new SqlNullValueException(); - } + // If data is null, ReadColumnHeader sets the data.IsNull bit. + if (_data[i] != null && _data[i].IsNull) + { + throw new SqlNullValueException(); + } - if (dataIndex < _columnDataCharsRead) - { - // Don't allow re-read of same chars in sequential access mode - throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars)); - } + if (dataIndex < _columnDataCharsRead) + { + // Don't allow re-read of same chars in sequential access mode + throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars)); + } - // 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 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; + } - bool isUnicode = _metaData[i].metaType.IsNCharType; + bool isUnicode = _metaData[i].metaType.IsNCharType; - // 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 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 (0 == _sharedState._columnDataBytesRemaining) - { - _stateObj._plpdecoder = null; - return 0; // We've read this column to the end - } + 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 + // 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; + // 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; + if (isUnicode) + { + cch = (long)_parser.ReadPlpUnicodeChars(ref buffer, bufferIndex, length, _stateObj); + _columnDataBytesRead += (cch << 1); } -#if NETFRAMEWORK && DEBUG - finally + else { - tdsReliabilitySection.Stop(); + cch = (long)_parser.ReadPlpAnsiChars(ref buffer, bufferIndex, length, _metaData[i], _stateObj); + _columnDataBytesRead += cch << 1; } -#endif + _columnDataCharsRead += cch; + _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj); + return cch; } internal long GetStreamingXmlChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) @@ -3565,155 +3431,138 @@ private TdsOperationStatus TryNextResult(out bool more) try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + SetTimeout(_defaultTimeoutMilliseconds); + + if (IsClosed) { -#endif - statistics = SqlStatistics.StartTimer(Statistics); + throw ADP.DataReaderClosed(nameof(NextResult)); + } + _fieldNameLookup = null; - SetTimeout(_defaultTimeoutMilliseconds); + bool success = false; // WebData 100390 + _hasRows = false; // reset HasRows - if (IsClosed) + // 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) { - throw ADP.DataReaderClosed(nameof(NextResult)); + more = false; + return result; } - _fieldNameLookup = null; - bool success = false; // WebData 100390 - _hasRows = false; // reset HasRows + // 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 we are specifically only processing a single result, then read all the results off the wire and detach - if (IsCommandBehavior(CommandBehavior.SingleResult)) + if (_parser != null) + { + // if there are more rows, then skip them, the user wants the next result + bool moreRows = true; + while (moreRows) { - result = TryCloseInternal(closeReader: false); + result = TryReadInternal(false, out moreRows); if (result != TdsOperationStatus.Done) { + // don't reset set the timeout value 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 (_parser != null) + // 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) { - // if there are more rows, then skip them, the user wants the next result - bool moreRows = true; - while (moreRows) + more = false; + return result; + } + if (moreResults) + { + _metaDataConsumed = false; + _browseModeInfoConsumed = false; + + switch (_altRowStatus) { - result = TryReadInternal(false, out moreRows); - if (result != TdsOperationStatus.Done) - { - // don't reset set the timeout value - more = false; - return result; - } + 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; } - } - // we may be done, so continue only if we have not detached ourselves from the parser - if (_parser != null) + success = true; + } + else { - bool moreResults; - result = TryHasMoreResults(out moreResults); + // detach the parser from this reader now + result = TryCloseInternal(closeReader: false); if (result != TdsOperationStatus.Done) { more = false; - return result; + return TdsOperationStatus.Done; } - if (moreResults) - { - _metaDataConsumed = false; - _browseModeInfoConsumed = false; - - 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 + // 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) { - // 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; - } + 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; } -#if NETFRAMEWORK && DEBUG - finally + else { - tdsReliabilitySection.Stop(); + // 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(); } -#endif + + more = success; + return TdsOperationStatus.Done; } finally { @@ -3755,140 +3604,117 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + TdsOperationStatus result; + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if (_parser != null) { -#endif - TdsOperationStatus result; - statistics = SqlStatistics.StartTimer(Statistics); - - if (_parser != null) + if (setTimeout) { - if (setTimeout) - { - SetTimeout(_defaultTimeoutMilliseconds); - } - if (_sharedState._dataReady) + SetTimeout(_defaultTimeoutMilliseconds); + } + if (_sharedState._dataReady) + { + result = TryCleanPartialRead(); + if (result != TdsOperationStatus.Done) { - result = TryCleanPartialRead(); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + 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) + if (!_haltRead) + { + bool moreRows; + result = TryHasMoreRows(out moreRows); + if (result != TdsOperationStatus.Done) { - bool moreRows; - result = TryHasMoreRows(out moreRows); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } - if (moreRows) + more = false; + return result; + } + if (moreRows) + { + // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) + while (_stateObj.HasPendingData) { - // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) - while (_stateObj.HasPendingData) + if (_altRowStatus != ALTROWSTATUS.AltRow) { - if (_altRowStatus != ALTROWSTATUS.AltRow) + // 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 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; - } + more = false; + return result; } - 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; } } - if (_sharedState._dataReady) + else { - _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); - more = true; - return TdsOperationStatus.Done; + // ALTROW token and AltrowId are already consumed ... + Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Done; + _sharedState._dataReady = true; + break; } } - - if (!_stateObj.HasPendingData) + if (_sharedState._dataReady) { - result = TryCloseInternal(closeReader: false); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); + more = true; + return TdsOperationStatus.Done; } } - else + + if (!_stateObj.HasPendingData) { - // 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); + result = TryCloseInternal(closeReader: false); if (result != TdsOperationStatus.Done) { more = false; return result; } - while (moreRows) + } + } + 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) { - // 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) - { - result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } - } - - if (_sharedState._dataReady) + result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady); + if (result != TdsOperationStatus.Done) { - result = TryCleanPartialRead(); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + more = false; + return result; } + } - // clear out our buffers - SqlBuffer.Clear(_data); - - _sharedState._nextColumnHeaderToRead = 0; - - result = TryHasMoreRows(out moreRows); + if (_sharedState._dataReady) + { + result = TryCleanPartialRead(); if (result != TdsOperationStatus.Done) { more = false; @@ -3896,38 +3722,44 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) } } - // reset haltRead - _haltRead = false; + // 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; } - 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)) + if ((!_sharedState._dataReady) && (_stateObj.HasPendingData)) + { + byte token; + result = _stateObj.TryPeekByte(out token); + if (result != TdsOperationStatus.Done) { - 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}"); + return result; } -#endif - return TdsOperationStatus.Done; - } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); + Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); } -#endif //DEBUG +#endif + + return TdsOperationStatus.Done; } catch (OutOfMemoryException e) { @@ -3987,41 +3819,22 @@ 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(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#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(); - } -#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?"); return TdsOperationStatus.Done; } @@ -4065,27 +3878,7 @@ private TdsOperationStatus TryReadColumnHeader(int i) throw SQL.InvalidRead(); } -#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 + return TryReadColumnInternal(i, readHeaderOnly: true); } internal TdsOperationStatus TryReadColumnInternal(int i, bool readHeaderOnly = false, bool forStreaming = false) @@ -5556,25 +5349,7 @@ 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 - + bool internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done; if (internalReadSuccess) { return Task.FromResult(reader.GetFieldValueFromSqlBufferInternal(reader._data[columnIndex], reader._metaData[columnIndex], isAsync: true)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs index f6e639c5f9..71ef5e9381 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs @@ -21,27 +21,6 @@ internal struct SNIErrorDetails public Exception exception; } - internal struct ReliabilitySection - { - /// - /// This is a no-op in netcore version. Only needed for merging with netfx codebase. - /// - [Conditional("NETFRAMEWORK")] - internal static void Assert(string message) - { - } - - [Conditional("NETFRAMEWORK")] - internal void Start() - { - } - - [Conditional("NETFRAMEWORK")] - internal void Stop() - { - } - } - internal static void FillGuidBytes(Guid guid, Span buffer) => guid.TryWriteBytes(buffer); internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); 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 4f655dc403..3f32dbeebd 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 @@ -298,8 +298,6 @@ internal bool ValidateSNIConnection() // This method should only be called by ReadSni! If not - it may have problems with timeouts! private void ReadSniError(TdsParserStateObject stateObj, uint error) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadSniSyncError"); // you need to setup for a thread abort somewhere before you call this method - if (TdsEnums.SNI_WAIT_TIMEOUT == error) { Debug.Assert(_syncOverAsync, "Should never reach here with async on!"); @@ -753,8 +751,6 @@ public void WriteAsyncCallback(IntPtr key, PacketHandle packet, uint sniError) // internal void WriteSecureString(SecureString secureString) { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteSecureString"); // you need to setup for a thread abort somewhere before you call this method - Debug.Assert(_securePasswords[0] == null || _securePasswords[1] == null, "There are more than two secure passwords"); int index = _securePasswords[0] != null ? 1 : 0; @@ -829,8 +825,6 @@ internal Task WaitForAccumulatedWrites() // and then the buffer is re-initialized in flush() and then the byte is put in the buffer. internal void WriteByte(byte b) { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteByte"); // you need to setup for a thread abort somewhere before you call this method - Debug.Assert(_outBytesUsed <= _outBuff.Length, "ERROR - TDSParser: _outBytesUsed > _outBuff.Length"); // check to make sure we haven't used the full amount of space available in the buffer, if so, flush it @@ -866,8 +860,6 @@ private Task WriteBytes(ReadOnlySpan b, int len, int offsetBuffer, bool ca } try { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteByteArray"); // you need to setup for a thread abort somewhere before you call this method - bool async = _parser._asyncWrite; // NOTE: We are capturing this now for the assert after the Task is returned, since WritePacket will turn off async if there is an exception Debug.Assert(async || _asyncWriteCount == 0); // Do we have to send out in packet size chunks, or can we rely on netlib layer to break it up? diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs index ac9e1a79c7..040ef93723 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs @@ -2059,58 +2059,40 @@ private Task WriteRowSourceToServerAsync(int columnCount, CancellationToken ctok RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else // !DEBUG - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - WriteRowSourceToServerCommon(columnCount); //this is common in both sync and async - Task resultTask = WriteToServerInternalAsync(ctoken); // resultTask is null for sync, but Task for async. - if (resultTask != null) - { - finishedSynchronously = false; - return resultTask.ContinueWith( - static (Task task, object state) => + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + WriteRowSourceToServerCommon(columnCount); //this is common in both sync and async + Task resultTask = WriteToServerInternalAsync(ctoken); // resultTask is null for sync, but Task for async. + if (resultTask != null) + { + finishedSynchronously = false; + return resultTask.ContinueWith( + static (Task task, object state) => + { + SqlBulkCopy sqlBulkCopy = (SqlBulkCopy)state; + try { - SqlBulkCopy sqlBulkCopy = (SqlBulkCopy)state; - try + sqlBulkCopy.AbortTransaction(); // if there is one, on success transactions will be commited + } + finally + { + sqlBulkCopy._isBulkCopyingInProgress = false; + if (sqlBulkCopy._parser != null) { - sqlBulkCopy.AbortTransaction(); // if there is one, on success transactions will be commited + sqlBulkCopy._parser._asyncWrite = false; } - finally + if (sqlBulkCopy._parserLock != null) { - sqlBulkCopy._isBulkCopyingInProgress = false; - if (sqlBulkCopy._parser != null) - { - sqlBulkCopy._parser._asyncWrite = false; - } - if (sqlBulkCopy._parserLock != null) - { - sqlBulkCopy._parserLock.Release(); - sqlBulkCopy._parserLock = null; - } + sqlBulkCopy._parserLock.Release(); + sqlBulkCopy._parserLock = null; } - return task; - }, - state: this, - scheduler: TaskScheduler.Default - ).Unwrap(); - } - return null; - } - -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); + } + return task; + }, + state: this, + scheduler: TaskScheduler.Default + ).Unwrap(); } -#endif //DEBUG + return null; } catch (System.OutOfMemoryException e) { @@ -2796,13 +2778,6 @@ private void CopyBatchesAsyncContinuedOnError(bool cleanupParser) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG if ((cleanupParser) && (_parser != null) && (_stateObj != null)) { _parser._asyncWrite = false; @@ -2815,13 +2790,6 @@ private void CopyBatchesAsyncContinuedOnError(bool cleanupParser) { CleanUpStateObject(); } -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG } catch (OutOfMemoryException) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index f66d9a811d..579c64181a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -534,22 +534,8 @@ private SqlCommand(SqlCommand from) : this() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - // cleanup - Unprepare(); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + // cleanup + Unprepare(); } catch (System.OutOfMemoryException) { @@ -1077,23 +1063,7 @@ public override void Prepare() } } -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - InternalPrepare(); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + InternalPrepare(); } catch (System.OutOfMemoryException e) { @@ -1261,48 +1231,31 @@ public override void Cancel() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - - if (!_pendingCancel) - { // Do nothing if aleady pending. - // Before attempting actual cancel, set the _pendingCancel flag to false. - // This denotes to other thread before obtaining stateObject from the - // session pool that there is another thread wishing to cancel. - // The period in question is between entering the ExecuteAPI and obtaining - // a stateObject. - _pendingCancel = true; - - TdsParserStateObject stateObj = _stateObj; - if (stateObj != null) - { - stateObj.Cancel(ObjectID); - } - else + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + + if (!_pendingCancel) + { // Do nothing if aleady pending. + // Before attempting actual cancel, set the _pendingCancel flag to false. + // This denotes to other thread before obtaining stateObject from the + // session pool that there is another thread wishing to cancel. + // The period in question is between entering the ExecuteAPI and obtaining + // a stateObject. + _pendingCancel = true; + + TdsParserStateObject stateObj = _stateObj; + if (stateObj != null) + { + stateObj.Cancel(ObjectID); + } + else + { + SqlDataReader reader = connection.FindLiveReader(this); + if (reader != null) { - SqlDataReader reader = connection.FindLiveReader(this); - if (reader != null) - { - reader.Cancel(ObjectID); - } + reader.Cancel(ObjectID); } } } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG } catch (System.OutOfMemoryException e) { @@ -1685,27 +1638,10 @@ private void BeginExecuteNonQueryInternalReadStage(TaskCompletionSource RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - // must finish caching information before ReadSni which can activate the callback before returning - cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteNonQuery), _activeConnection); - _stateObj.ReadSni(completion); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // must finish caching information before ReadSni which can activate the callback before returning + cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteNonQuery), _activeConnection); + _stateObj.ReadSni(completion); } catch (System.OutOfMemoryException e) { @@ -1918,101 +1854,84 @@ private object InternalEndExecuteNonQuery(IAsyncResult asyncResult, string endMe try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + VerifyEndExecuteState((Task)asyncResult, endMethod); + WaitForAsyncResults(asyncResult, isInternal); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + // If column encryption is enabled, also check the state after waiting for the task. + // It would be better to do this for all cases, but avoiding for compatibility reasons. + if (IsColumnEncryptionEnabled) { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - VerifyEndExecuteState((Task)asyncResult, endMethod); - WaitForAsyncResults(asyncResult, isInternal); + VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true); + } - // If column encryption is enabled, also check the state after waiting for the task. - // It would be better to do this for all cases, but avoiding for compatibility reasons. - if (IsColumnEncryptionEnabled) + bool processFinallyBlock = true; + try + { + // If this is not for internal usage, notify the dependency. + // If we have already initiated the end internally, the reader should be ready, so just return the rows affected. + if (!isInternal) { - VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true); - } + NotifyDependency(); - bool processFinallyBlock = true; - try - { - // If this is not for internal usage, notify the dependency. - // If we have already initiated the end internally, the reader should be ready, so just return the rows affected. - if (!isInternal) + if (_internalEndExecuteInitiated) { - NotifyDependency(); + Debug.Assert(_stateObj == null); - if (_internalEndExecuteInitiated) - { - Debug.Assert(_stateObj == null); - - // Reset the state since we exit early. - cachedAsyncState.ResetAsyncState(); + // Reset the state since we exit early. + cachedAsyncState.ResetAsyncState(); - return _rowsAffected; - } + return _rowsAffected; } + } - CheckThrowSNIException(); + CheckThrowSNIException(); - // only send over SQL Batch command if we are not a stored proc and have no parameters - if ((System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) + // only send over SQL Batch command if we are not a stored proc and have no parameters + if ((System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) + { + try { - try - { - Debug.Assert(_stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); - TdsOperationStatus result = _stateObj.Parser.TryRun(RunBehavior.UntilDone, this, null, null, _stateObj, out _); - if (result != TdsOperationStatus.Done) - { - throw SQL.SynchronousCallMayNotPend(); - } - } - finally + Debug.Assert(_stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + TdsOperationStatus result = _stateObj.Parser.TryRun(RunBehavior.UntilDone, this, null, null, _stateObj, out _); + if (result != TdsOperationStatus.Done) { - // Don't reset the state for internal End. The user End will do that eventually. - if (!isInternal) - { - cachedAsyncState.ResetAsyncState(); - } + throw SQL.SynchronousCallMayNotPend(); } } - else - { // otherwise, use a full-fledged execute that can handle params and stored procs - SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); - if (reader != null) + finally + { + // Don't reset the state for internal End. The user End will do that eventually. + if (!isInternal) { - reader.Close(); + cachedAsyncState.ResetAsyncState(); } } } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (processFinallyBlock) + else + { // otherwise, use a full-fledged execute that can handle params and stored procs + SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); + if (reader != null) { - PutStateObject(); + reader.Close(); } } - - Debug.Assert(_stateObj == null, "non-null state object in EndExecuteNonQuery"); - return _rowsAffected; } -#if DEBUG + catch (Exception e) + { + processFinallyBlock = ADP.IsCatchableExceptionType(e); + throw; + } finally { - tdsReliabilitySection.Stop(); + if (processFinallyBlock) + { + PutStateObject(); + } } -#endif //DEBUG + + Debug.Assert(_stateObj == null, "non-null state object in EndExecuteNonQuery"); + return _rowsAffected; } catch (System.OutOfMemoryException e) { @@ -2046,88 +1965,71 @@ private Task InternalExecuteNonQuery(TaskCompletionSource completion, st RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // @devnote: this function may throw for an invalid connection + // @devnote: returns false for empty command text + if (!inRetry) { - tdsReliabilitySection.Start(); -#else + ValidateCommand(methodName, async); + } + CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection! + + Task task = null; + + // only send over SQL Batch command if we are not a stored proc and have no parameters and not in batch RPC mode + if (_activeConnection.IsContextConnection) { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - // @devnote: this function may throw for an invalid connection - // @devnote: returns false for empty command text - if (!inRetry) + if (statistics != null) { - ValidateCommand(methodName, async); + statistics.SafeIncrement(ref statistics._unpreparedExecs); } - CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection! - Task task = null; + RunExecuteNonQuerySmi(sendToPipe); + } - // only send over SQL Batch command if we are not a stored proc and have no parameters and not in batch RPC mode - if (_activeConnection.IsContextConnection) + //Always Encrypted generally operates only on parameterized queries. However enclave based Always encrypted also supports unparameterized queries + //We skip this block for enclave based always encrypted so that we can make a call to SQL Server to get the encryption information + else if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && (System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) + { + Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); + if (statistics != null) { - if (statistics != null) + if (!this.IsDirty && this.IsPrepared) + { + statistics.SafeIncrement(ref statistics._preparedExecs); + } + else { statistics.SafeIncrement(ref statistics._unpreparedExecs); } - - RunExecuteNonQuerySmi(sendToPipe); } - //Always Encrypted generally operates only on parameterized queries. However enclave based Always encrypted also supports unparameterized queries - //We skip this block for enclave based always encrypted so that we can make a call to SQL Server to get the encryption information - else if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && (System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) - { - Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); - if (statistics != null) - { - if (!this.IsDirty && this.IsPrepared) - { - statistics.SafeIncrement(ref statistics._preparedExecs); - } - else - { - statistics.SafeIncrement(ref statistics._unpreparedExecs); - } - } + // We should never get here for a retry since we only have retries for parameters. + Debug.Assert(!inRetry); - // We should never get here for a retry since we only have retries for parameters. - Debug.Assert(!inRetry); + task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite); + } + else + { + // otherwise, use a full-fledged execute that can handle params and stored procs + Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); + SqlClientEventSource.Log.TryTraceEvent(" {0}, Command executed as RPC.", ObjectID); - task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite); - } - else + SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, out usedCache, asyncWrite, inRetry); + if (reader != null) { - // otherwise, use a full-fledged execute that can handle params and stored procs - Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); - SqlClientEventSource.Log.TryTraceEvent(" {0}, Command executed as RPC.", ObjectID); - - SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, out usedCache, asyncWrite, inRetry); - if (reader != null) + if (task != null) { - if (task != null) - { - task = AsyncHelper.CreateContinuationTask(task, () => reader.Close()); - } - else - { - reader.Close(); - } + task = AsyncHelper.CreateContinuationTask(task, () => reader.Close()); + } + else + { + reader.Close(); } } - Debug.Assert(async || _stateObj == null, "non-null state object in InternalExecuteNonQuery"); - return task; } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + Debug.Assert(async || _stateObj == null, "non-null state object in InternalExecuteNonQuery"); + return task; } catch (System.OutOfMemoryException e) { @@ -2293,27 +2195,10 @@ private void BeginExecuteXmlReaderInternalReadStage(TaskCompletionSource RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - // must finish caching information before ReadSni which can activate the callback before returning - cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteXmlReader), _activeConnection); - _stateObj.ReadSni(completion); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // must finish caching information before ReadSni which can activate the callback before returning + cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteXmlReader), _activeConnection); + _stateObj.ReadSni(completion); } catch (System.OutOfMemoryException e) { @@ -2555,28 +2440,11 @@ internal SqlDataReader ExecuteReader(CommandBehavior behavior, string method) try { WriteBeginExecuteEvent(); -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - statistics = SqlStatistics.StartTimer(Statistics); - SqlDataReader result = RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, method); - success = true; - return result; - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + statistics = SqlStatistics.StartTimer(Statistics); + SqlDataReader result = RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, method); + success = true; + return result; } catch (SqlException e) { @@ -2929,27 +2797,10 @@ private void BeginExecuteReaderInternalReadStage(TaskCompletionSource co RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - // must finish caching information before ReadSni which can activate the callback before returning - cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteReader), _activeConnection); - _stateObj.ReadSni(completion); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // must finish caching information before ReadSni which can activate the callback before returning + cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteReader), _activeConnection); + _stateObj.ReadSni(completion); } catch (System.OutOfMemoryException e) { @@ -3004,27 +2855,10 @@ private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, string RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); - Debug.Assert(_stateObj == null, "non-null state object in InternalEndExecuteReader"); - return reader; - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); + Debug.Assert(_stateObj == null, "non-null state object in InternalEndExecuteReader"); + return reader; } catch (System.OutOfMemoryException e) { @@ -3791,7 +3625,6 @@ internal void DeriveParameters() } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to DeriveParameters"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock) { r?.Close(); @@ -4012,7 +3845,6 @@ private Task RunExecuteNonQueryTds(string methodName, bool async, int timeout, b } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to RunExecuteNonQueryTds"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock && !async) { // When executing Async, we need to keep the _stateObj alive... @@ -4081,7 +3913,6 @@ private void RunExecuteNonQuerySmi(bool sendToPipe) } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to RunExecuteNonQuerySmi"); // you need to setup for a thread abort somewhere before you call this method if (eventStream != null && processFinallyBlock) { eventStream.Close(EventSink); @@ -4231,62 +4062,127 @@ private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool r RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); try { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - try + // Fetch the encryption information that applies to any of the input parameters. + describeParameterEncryptionDataReader = TryFetchInputParameterEncryptionInfo(timeout, + async, + asyncWrite, + out describeParameterEncryptionNeeded, + out fetchInputParameterEncryptionInfoTask, + out describeParameterEncryptionRpcOriginalRpcMap, + inRetry); + + Debug.Assert(describeParameterEncryptionNeeded || describeParameterEncryptionDataReader == null, + "describeParameterEncryptionDataReader should be null if we don't need to request describe parameter encryption request."); + + Debug.Assert(fetchInputParameterEncryptionInfoTask == null || async, + "Task returned by TryFetchInputParameterEncryptionInfo, when in sync mode, in PrepareForTransparentEncryption."); + + Debug.Assert((describeParameterEncryptionRpcOriginalRpcMap != null) == _batchRPCMode, + "describeParameterEncryptionRpcOriginalRpcMap can be non-null if and only if it is in _batchRPCMode."); + + // If we didn't have parameters, we can fall back to regular code path, by simply returning. + if (!describeParameterEncryptionNeeded) { - // Fetch the encryption information that applies to any of the input parameters. - describeParameterEncryptionDataReader = TryFetchInputParameterEncryptionInfo(timeout, - async, - asyncWrite, - out describeParameterEncryptionNeeded, - out fetchInputParameterEncryptionInfoTask, - out describeParameterEncryptionRpcOriginalRpcMap, - inRetry); + Debug.Assert(fetchInputParameterEncryptionInfoTask == null, + "fetchInputParameterEncryptionInfoTask should not be set if describe parameter encryption is not needed."); - Debug.Assert(describeParameterEncryptionNeeded || describeParameterEncryptionDataReader == null, - "describeParameterEncryptionDataReader should be null if we don't need to request describe parameter encryption request."); + Debug.Assert(describeParameterEncryptionDataReader == null, + "SqlDataReader created for describe parameter encryption params when it is not needed."); - Debug.Assert(fetchInputParameterEncryptionInfoTask == null || async, - "Task returned by TryFetchInputParameterEncryptionInfo, when in sync mode, in PrepareForTransparentEncryption."); + return; + } + + // If we are in async execution, we need to decrement our async count on exception. + decrementAsyncCountInFinallyBlock = async; - Debug.Assert((describeParameterEncryptionRpcOriginalRpcMap != null) == _batchRPCMode, - "describeParameterEncryptionRpcOriginalRpcMap can be non-null if and only if it is in _batchRPCMode."); + Debug.Assert(describeParameterEncryptionDataReader != null, + "describeParameterEncryptionDataReader should not be null, as it is required to get results of describe parameter encryption."); - // If we didn't have parameters, we can fall back to regular code path, by simply returning. - if (!describeParameterEncryptionNeeded) + // Fire up another task to read the results of describe parameter encryption + if (fetchInputParameterEncryptionInfoTask != null) + { + // Mark that we should not process the finally block since we have async execution pending. + // Note that this should be done outside the task's continuation delegate. + processFinallyBlock = false; + returnTask = AsyncHelper.CreateContinuationTask(fetchInputParameterEncryptionInfoTask, () => { - Debug.Assert(fetchInputParameterEncryptionInfoTask == null, - "fetchInputParameterEncryptionInfoTask should not be set if describe parameter encryption is not needed."); + bool processFinallyBlockAsync = true; + bool decrementAsyncCountInFinallyBlockAsync = true; - Debug.Assert(describeParameterEncryptionDataReader == null, - "SqlDataReader created for describe parameter encryption params when it is not needed."); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + // Check for any exceptions on network write, before reading. + CheckThrowSNIException(); - return; - } + // If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count. + // Decrement it when we are about to complete async execute reader. + SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); + if (internalConnectionTds != null) + { + internalConnectionTds.DecrementAsyncCount(); + decrementAsyncCountInFinallyBlockAsync = false; + } - // If we are in async execution, we need to decrement our async count on exception. - decrementAsyncCountInFinallyBlock = async; + // Complete executereader. + describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); + Debug.Assert(_stateObj == null, "non-null state object in PrepareForTransparentEncryption."); - Debug.Assert(describeParameterEncryptionDataReader != null, - "describeParameterEncryptionDataReader should not be null, as it is required to get results of describe parameter encryption."); + // Read the results of describe parameter encryption. + ReadDescribeEncryptionParameterResults( + describeParameterEncryptionDataReader, + describeParameterEncryptionRpcOriginalRpcMap, + inRetry); - // Fire up another task to read the results of describe parameter encryption - if (fetchInputParameterEncryptionInfoTask != null) +#if DEBUG + // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. + if (_sleepAfterReadDescribeEncryptionParameterResults) + { + Thread.Sleep(10000); + } +#endif //DEBUG + } + catch (Exception e) + { + processFinallyBlockAsync = ADP.IsCatchableExceptionType(e); + throw; + } + finally + { + PrepareTransparentEncryptionFinallyBlock(closeDataReader: processFinallyBlockAsync, + decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync, + clearDataStructures: processFinallyBlockAsync, + wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, + describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, + describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); + } + }, + onFailure: ((exception) => + { + if (_cachedAsyncState != null) + { + _cachedAsyncState.ResetAsyncState(); + } + if (exception != null) + { + throw exception; + } + })); + + decrementAsyncCountInFinallyBlock = false; + } + else + { + // If it was async, ending the reader is still pending. + if (async) { // Mark that we should not process the finally block since we have async execution pending. // Note that this should be done outside the task's continuation delegate. processFinallyBlock = false; - returnTask = AsyncHelper.CreateContinuationTask(fetchInputParameterEncryptionInfoTask, () => + returnTask = Task.Run(() => { bool processFinallyBlockAsync = true; bool decrementAsyncCountInFinallyBlockAsync = true; @@ -4294,47 +4190,32 @@ private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool r RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySectionAsync = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySectionAsync.Start(); -#endif //DEBUG - // Check for any exceptions on network write, before reading. - CheckThrowSNIException(); - // If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count. - // Decrement it when we are about to complete async execute reader. - SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); - if (internalConnectionTds != null) - { - internalConnectionTds.DecrementAsyncCount(); - decrementAsyncCountInFinallyBlockAsync = false; - } + // Check for any exceptions on network write, before reading. + CheckThrowSNIException(); - // Complete executereader. - describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); - Debug.Assert(_stateObj == null, "non-null state object in PrepareForTransparentEncryption."); + // If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count. + // Decrement it when we are about to complete async execute reader. + SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); + if (internalConnectionTds != null) + { + internalConnectionTds.DecrementAsyncCount(); + decrementAsyncCountInFinallyBlockAsync = false; + } - // Read the results of describe parameter encryption. - ReadDescribeEncryptionParameterResults( - describeParameterEncryptionDataReader, - describeParameterEncryptionRpcOriginalRpcMap, - inRetry); + // Complete executereader. + describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); + Debug.Assert(_stateObj == null, "non-null state object in PrepareForTransparentEncryption."); + // Read the results of describe parameter encryption. + ReadDescribeEncryptionParameterResults(describeParameterEncryptionDataReader, describeParameterEncryptionRpcOriginalRpcMap, inRetry); #if DEBUG - // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. - if (_sleepAfterReadDescribeEncryptionParameterResults) - { - Thread.Sleep(10000); - } - } - finally + // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. + if (_sleepAfterReadDescribeEncryptionParameterResults) { - tdsReliabilitySectionAsync.Stop(); + Thread.Sleep(10000); } -#endif //DEBUG +#endif } catch (Exception e) { @@ -4350,134 +4231,41 @@ private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool r describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); } - }, - onFailure: ((exception) => - { - if (_cachedAsyncState != null) - { - _cachedAsyncState.ResetAsyncState(); - } - if (exception != null) - { - throw exception; - } - })); + }); decrementAsyncCountInFinallyBlock = false; } else { - // If it was async, ending the reader is still pending. - if (async) - { - // Mark that we should not process the finally block since we have async execution pending. - // Note that this should be done outside the task's continuation delegate. - processFinallyBlock = false; - returnTask = Task.Run(() => - { - bool processFinallyBlockAsync = true; - bool decrementAsyncCountInFinallyBlockAsync = true; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySectionAsync = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySectionAsync.Start(); -#endif //DEBUG - - // Check for any exceptions on network write, before reading. - CheckThrowSNIException(); - - // If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count. - // Decrement it when we are about to complete async execute reader. - SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); - if (internalConnectionTds != null) - { - internalConnectionTds.DecrementAsyncCount(); - decrementAsyncCountInFinallyBlockAsync = false; - } - - // Complete executereader. - describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); - Debug.Assert(_stateObj == null, "non-null state object in PrepareForTransparentEncryption."); - - // Read the results of describe parameter encryption. - ReadDescribeEncryptionParameterResults(describeParameterEncryptionDataReader, describeParameterEncryptionRpcOriginalRpcMap, inRetry); -#if DEBUG - // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. - if (_sleepAfterReadDescribeEncryptionParameterResults) - { - Thread.Sleep(10000); - } -#endif -#if DEBUG - } - finally - { - tdsReliabilitySectionAsync.Stop(); - } -#endif //DEBUG - } - catch (Exception e) - { - processFinallyBlockAsync = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - PrepareTransparentEncryptionFinallyBlock(closeDataReader: processFinallyBlockAsync, - decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync, - clearDataStructures: processFinallyBlockAsync, - wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, - describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, - describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); - } - }); - - decrementAsyncCountInFinallyBlock = false; - } - else - { - // For synchronous execution, read the results of describe parameter encryption here. - ReadDescribeEncryptionParameterResults(describeParameterEncryptionDataReader, describeParameterEncryptionRpcOriginalRpcMap, inRetry); - } + // For synchronous execution, read the results of describe parameter encryption here. + ReadDescribeEncryptionParameterResults(describeParameterEncryptionDataReader, describeParameterEncryptionRpcOriginalRpcMap, inRetry); + } #if DEBUG - // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. - if (_sleepAfterReadDescribeEncryptionParameterResults) - { - Thread.Sleep(10000); - } -#endif + // Failpoint to force the thread to halt to simulate cancellation of SqlCommand. + if (_sleepAfterReadDescribeEncryptionParameterResults) + { + Thread.Sleep(10000); } - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - exceptionCaught = true; - throw; - } - finally - { - // Free up the state only for synchronous execution. For asynchronous execution, free only if there was an exception. - PrepareTransparentEncryptionFinallyBlock(closeDataReader: (processFinallyBlock && !async) || exceptionCaught, - decrementAsyncCount: decrementAsyncCountInFinallyBlock && exceptionCaught, - clearDataStructures: (processFinallyBlock && !async) || exceptionCaught, - wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, - describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, - describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); +#endif } } -#if DEBUG + catch (Exception e) + { + processFinallyBlock = ADP.IsCatchableExceptionType(e); + exceptionCaught = true; + throw; + } finally { - tdsReliabilitySection.Stop(); + // Free up the state only for synchronous execution. For asynchronous execution, free only if there was an exception. + PrepareTransparentEncryptionFinallyBlock(closeDataReader: (processFinallyBlock && !async) || exceptionCaught, + decrementAsyncCount: decrementAsyncCountInFinallyBlock && exceptionCaught, + clearDataStructures: (processFinallyBlock && !async) || exceptionCaught, + wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, + describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, + describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); } -#endif //DEBUG } catch (System.OutOfMemoryException e) { @@ -5163,59 +4951,87 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + SqlStatistics statistics = Statistics; + if (statistics != null) { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - SqlStatistics statistics = Statistics; - if (statistics != null) + if ((!this.IsDirty && this.IsPrepared && !_hiddenPrepare) + || (this.IsPrepared && _execType == EXECTYPE.PREPAREPENDING)) { - if ((!this.IsDirty && this.IsPrepared && !_hiddenPrepare) - || (this.IsPrepared && _execType == EXECTYPE.PREPAREPENDING)) - { - statistics.SafeIncrement(ref statistics._preparedExecs); - } - else - { - statistics.SafeIncrement(ref statistics._unpreparedExecs); - } + statistics.SafeIncrement(ref statistics._preparedExecs); } + else + { + statistics.SafeIncrement(ref statistics._unpreparedExecs); + } + } - // Reset the encryption related state of the command and its parameters. - ResetEncryptionState(); + // Reset the encryption related state of the command and its parameters. + ResetEncryptionState(); - if (_activeConnection.IsContextConnection) + if (_activeConnection.IsContextConnection) + { + return RunExecuteReaderSmi(cmdBehavior, runBehavior, returnStream); + } + else if (IsColumnEncryptionEnabled) + { + Task returnTask = null; + PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async, out usedCache, inRetry); + Debug.Assert(usedCache || (async == (returnTask != null)), @"if we didn't use the cache, returnTask should be null if and only if async is false."); + + long firstAttemptStart = ADP.TimerCurrent(); + + try { - return RunExecuteReaderSmi(cmdBehavior, runBehavior, returnStream); + return RunExecuteReaderTdsWithTransparentParameterEncryption(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry, ds: null, + describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask); } - else if (IsColumnEncryptionEnabled) + + catch (EnclaveDelegate.RetryableEnclaveQueryExecutionException) { - Task returnTask = null; - PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async, out usedCache, inRetry); - Debug.Assert(usedCache || (async == (returnTask != null)), @"if we didn't use the cache, returnTask should be null if and only if async is false."); + if (inRetry) + { + throw; + } - long firstAttemptStart = ADP.TimerCurrent(); + // Retry if the command failed with appropriate error. + // First invalidate the entry from the cache, so that we refresh our encryption MD. + SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this); - try + InvalidateEnclaveSession(); + + return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); + } + + catch (SqlException ex) + { + // We only want to retry once, so don't retry if we are already in retry. + // If we didn't use the cache, we don't want to retry. + if (inRetry || (!usedCache && !ShouldUseEnclaveBasedWorkflow)) { - return RunExecuteReaderTdsWithTransparentParameterEncryption(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry, ds: null, - describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask); + throw; } - catch (EnclaveDelegate.RetryableEnclaveQueryExecutionException) + bool shouldRetry = false; + + // Check if we have an error indicating that we can retry. + for (int i = 0; i < ex.Errors.Count; i++) { - if (inRetry) + + if ((usedCache && (ex.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY)) || + (ShouldUseEnclaveBasedWorkflow && (ex.Errors[i].Number == TdsEnums.TCE_ENCLAVE_INVALID_SESSION_HANDLE))) { - throw; + shouldRetry = true; + break; } + } + if (!shouldRetry) + { + throw; + } + else + { // Retry if the command failed with appropriate error. // First invalidate the entry from the cache, so that we refresh our encryption MD. SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this); @@ -5224,57 +5040,12 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); } - - catch (SqlException ex) - { - // We only want to retry once, so don't retry if we are already in retry. - // If we didn't use the cache, we don't want to retry. - if (inRetry || (!usedCache && !ShouldUseEnclaveBasedWorkflow)) - { - throw; - } - - bool shouldRetry = false; - - // Check if we have an error indicating that we can retry. - for (int i = 0; i < ex.Errors.Count; i++) - { - - if ((usedCache && (ex.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY)) || - (ShouldUseEnclaveBasedWorkflow && (ex.Errors[i].Number == TdsEnums.TCE_ENCLAVE_INVALID_SESSION_HANDLE))) - { - shouldRetry = true; - break; - } - } - - if (!shouldRetry) - { - throw; - } - else - { - // Retry if the command failed with appropriate error. - // First invalidate the entry from the cache, so that we refresh our encryption MD. - SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this); - - InvalidateEnclaveSession(); - - return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); - } - } - } - else - { - return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry); } } -#if DEBUG - finally + else { - tdsReliabilitySection.Stop(); + return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry); } -#endif //DEBUG } catch (System.OutOfMemoryException e) { @@ -5668,7 +5439,6 @@ private SqlDataReader RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavi } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to RunExecuteReaderTds"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock && !async) { // When executing async, we need to keep the _stateObj alive... @@ -5778,7 +5548,6 @@ private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool f } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to CompleteAsyncExecuteReader"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock) { // Don't reset the state for internal End. The user End will do that eventually. @@ -5984,28 +5753,10 @@ private void ValidateCommand(string method, bool async) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - // close any non MARS dead readers, if applicable, and then throw if still busy. - // Throw if we have a live reader on this command - _activeConnection.ValidateConnectionForExecute(method, this); - - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // close any non MARS dead readers, if applicable, and then throw if still busy. + // Throw if we have a live reader on this command + _activeConnection.ValidateConnectionForExecute(method, this); } catch (System.OutOfMemoryException e) { @@ -6130,26 +5881,8 @@ private void ReliablePutStateObject() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - PutStateObject(); - - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + PutStateObject(); } catch (System.OutOfMemoryException e) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs index 931fb96640..09a4ae7a90 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -1426,26 +1426,9 @@ override public void ChangeDatabase(string database) try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); - statistics = SqlStatistics.StartTimer(Statistics); - InnerConnection.ChangeDatabase(database); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); + statistics = SqlStatistics.StartTimer(Statistics); + InnerConnection.ChangeDatabase(database); } catch (System.OutOfMemoryException e) { @@ -1524,48 +1507,31 @@ override public void Close() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + Task reconnectTask = _currentReconnectionTask; + if (reconnectTask != null && !reconnectTask.IsCompleted) { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); - statistics = SqlStatistics.StartTimer(Statistics); - - Task reconnectTask = _currentReconnectionTask; - if (reconnectTask != null && !reconnectTask.IsCompleted) + CancellationTokenSource cts = _reconnectionCancellationSource; + if (cts != null) { - CancellationTokenSource cts = _reconnectionCancellationSource; - if (cts != null) - { - cts.Cancel(); - } - AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection - if (State != ConnectionState.Open) - {// if we cancelled before the connection was opened - OnStateChange(DbConnectionInternal.StateChangeClosed); - } + cts.Cancel(); } - CancelOpenAndWait(); - CloseInnerConnection(); - GC.SuppressFinalize(this); - - if (Statistics != null) - { - _statistics._closeTimestamp = ADP.TimerCurrent(); + AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection + if (State != ConnectionState.Open) + {// if we cancelled before the connection was opened + OnStateChange(DbConnectionInternal.StateChangeClosed); } } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + CancelOpenAndWait(); + CloseInnerConnection(); + GC.SuppressFinalize(this); + + if (Statistics != null) + { + _statistics._closeTimestamp = ADP.TimerCurrent(); + } } catch (System.OutOfMemoryException e) { @@ -2138,69 +2104,52 @@ private bool TryOpenInner(TaskCompletionSource retry) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if (ForceNewConnection) { -#endif //DEBUG - if (ForceNewConnection) + if (!InnerConnection.TryReplaceConnection(this, ConnectionFactory, retry, UserConnectionOptions)) { - if (!InnerConnection.TryReplaceConnection(this, ConnectionFactory, retry, UserConnectionOptions)) - { - return false; - } + return false; } - else + } + else + { + if (!InnerConnection.TryOpenConnection(this, ConnectionFactory, retry, UserConnectionOptions)) { - if (!InnerConnection.TryOpenConnection(this, ConnectionFactory, retry, UserConnectionOptions)) - { - return false; - } + return false; } - // does not require GC.KeepAlive(this) because of OnStateChange + } + // does not require GC.KeepAlive(this) because of OnStateChange - // GetBestEffortCleanup must happen AFTER OpenConnection to get the correct target. - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); + // GetBestEffortCleanup must happen AFTER OpenConnection to get the correct target. + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); + + var tdsInnerConnection = (InnerConnection as SqlInternalConnectionTds); + if (tdsInnerConnection == null) + { + SqlInternalConnectionSmi innerConnection = (InnerConnection as SqlInternalConnectionSmi); + innerConnection.AutomaticEnlistment(); + } + else + { + Debug.Assert(tdsInnerConnection.Parser != null, "Where's the parser?"); - var tdsInnerConnection = (InnerConnection as SqlInternalConnectionTds); - if (tdsInnerConnection == null) + if (!tdsInnerConnection.ConnectionOptions.Pooling) { - SqlInternalConnectionSmi innerConnection = (InnerConnection as SqlInternalConnectionSmi); - innerConnection.AutomaticEnlistment(); + // For non-pooled connections, we need to make sure that the finalizer does actually run to avoid leaking SNI handles + GC.ReRegisterForFinalize(this); + } + + if (StatisticsEnabled) + { + _statistics._openTimestamp = ADP.TimerCurrent(); + tdsInnerConnection.Parser.Statistics = _statistics; } else { - Debug.Assert(tdsInnerConnection.Parser != null, "Where's the parser?"); - - if (!tdsInnerConnection.ConnectionOptions.Pooling) - { - // For non-pooled connections, we need to make sure that the finalizer does actually run to avoid leaking SNI handles - GC.ReRegisterForFinalize(this); - } - - if (StatisticsEnabled) - { - _statistics._openTimestamp = ADP.TimerCurrent(); - tdsInnerConnection.Parser.Statistics = _statistics; - } - else - { - tdsInnerConnection.Parser.Statistics = null; - _statistics = null; // in case of previous Open/Close/reset_CollectStats sequence - } + tdsInnerConnection.Parser.Statistics = null; + _statistics = null; // in case of previous Open/Close/reset_CollectStats sequence } } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG } catch (System.OutOfMemoryException e) { 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 2cd5370c8e..4a5fc39811 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 @@ -264,29 +264,11 @@ internal _SqlMetaDataSet MetaData RuntimeHelpers.PrepareConstrainedRegions(); try { -#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 + Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + if (TryConsumeMetaData() != TdsOperationStatus.Done) { - tdsReliabilitySection.Stop(); + throw SQL.SynchronousCallMayNotPend(); } -#endif //DEBUG } catch (System.OutOfMemoryException e) { @@ -891,26 +873,9 @@ private void CleanPartialReadReliable() RuntimeHelpers.PrepareConstrainedRegions(); try { -#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 + TdsOperationStatus result = TryCleanPartialRead(); + Debug.Assert(result == TdsOperationStatus.Done, "Should not pend on sync call"); + Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared"); } catch (System.OutOfMemoryException e) { @@ -1060,77 +1025,60 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) { -#endif //DEBUG - if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj.HasPendingData)) + // It is possible for this to be called during connection close on a + // broken connection, so check state first. + if (parser.State == TdsParserState.OpenLoggedIn) { - // 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 ... + // 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, String.Format((IFormatProvider)null, "The SniContext should be Snix_Read but it actually is {0}", stateObj.SniContext)); + Debug.Assert(SniContext.Snix_Read == stateObj.SniContext, String.Format((IFormatProvider)null, "The SniContext should be Snix_Read but it actually is {0}", stateObj.SniContext)); - if (_altRowStatus == ALTROWSTATUS.AltRow) + 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) { - _sharedState._dataReady = true; // set _sharedState._dataReady to not confuse CleanPartialRead + cleanDataFailed = false; } - _stateObj.SetTimeoutStateStopped(); - if (_sharedState._dataReady) + else { - cleanDataFailed = true; - result = TryCleanPartialRead(); - if (result == TdsOperationStatus.Done) - { - cleanDataFailed = false; - } - else - { - return result; - } + return result; } + } #if DEBUG - else + else + { + byte token; + result = _stateObj.TryPeekByte(out token); + if (result != TdsOperationStatus.Done) { - 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}"); + return result; } + + 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; - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); } -#endif //DEBUG + + RestoreServerSettings(parser, stateObj); + return TdsOperationStatus.Done; } catch (System.OutOfMemoryException e) { @@ -1204,41 +1152,24 @@ private TdsOperationStatus TryCloseInternal(bool closeReader) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed + if (!wasClosed && stateObj != null) { -#endif //DEBUG - // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed - if (!wasClosed && stateObj != null) + if (!cleanDataFailed) { - if (!cleanDataFailed) - { - stateObj.CloseSession(); - } - else + stateObj.CloseSession(); + } + else + { + if (parser != null) { - 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(); - } + 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 - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); } -#endif //DEBUG + // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread } catch (System.OutOfMemoryException e) { @@ -1851,249 +1782,232 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + int cbytes = 0; + AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + // sequential reading + if (IsCommandBehavior(CommandBehavior.SequentialAccess)) { -#endif //DEBUG - int cbytes = 0; - AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true); + Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader"); - // sequential reading - if (IsCommandBehavior(CommandBehavior.SequentialAccess)) + if (_metaData[i] != null && _metaData[i].cipherMD != null) { - Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader"); - - if (_metaData[i] != null && _metaData[i].cipherMD != null) - { - throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column); - } + throw SQL.SequentialAccessNotSupportedOnEncryptedColumn(_metaData[i].column); + } - if (_sharedState._nextColumnHeaderToRead <= i) + if (_sharedState._nextColumnHeaderToRead <= i) + { + result = TryReadColumnHeader(i); + if (result != TdsOperationStatus.Done) { - result = TryReadColumnHeader(i); - if (result != TdsOperationStatus.Done) - { - return result; - } + return result; } + } - // If data is null, ReadColumnHeader sets the data.IsNull bit. - if (_data[i] != null && _data[i].IsNull) - { - throw new SqlNullValueException(); - } + // 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) && (_metaData[i].metaType.IsPlp)) + // 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) { - ulong left; - result = _parser.TryPlpBytesLeft(_stateObj, out left); - if (result != TdsOperationStatus.Done) - { - return result; - } - _sharedState._columnDataBytesRemaining = (long)left; + return result; } + _sharedState._columnDataBytesRemaining = (long)left; + } - if (0 == _sharedState._columnDataBytesRemaining) - { - return TdsOperationStatus.Done; // We've read this column to the end - } + 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) + // if no buffer is passed in, return the number total of bytes, or -1 + if (buffer == null) + { + if (_metaData[i].metaType.IsPlp) { - if (_metaData[i].metaType.IsPlp) - { - remaining = (long)_parser.PlpBytesTotalLength(_stateObj); - return TdsOperationStatus.Done; - } - remaining = _sharedState._columnDataBytesRemaining; + remaining = (long)_parser.PlpBytesTotalLength(_stateObj); 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) + // Skip if needed + if (cb > 0) + { + if (_metaData[i].metaType.IsPlp) { - if (_metaData[i].metaType.IsPlp) + ulong skipped; + result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped); + if (result != TdsOperationStatus.Done) { - ulong skipped; - result = _parser.TrySkipPlpValue((ulong)cb, _stateObj, out skipped); - if (result != TdsOperationStatus.Done) - { - return result; - } - _columnDataBytesRead += (long)skipped; + return result; } - else + _columnDataBytesRead += (long)skipped; + } + else + { + result = _stateObj.TrySkipLongBytes(cb); + if (result != TdsOperationStatus.Done) { - result = _stateObj.TrySkipLongBytes(cb); - if (result != TdsOperationStatus.Done) - { - return result; - } - _columnDataBytesRead += cb; - _sharedState._columnDataBytesRemaining -= cb; + return result; } + _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)); + } + + if (dataIndex > int.MaxValue) + { + throw ADP.InvalidSourceBufferIndex(cbytes, dataIndex, nameof(dataIndex)); + } - int ndataIndex = (int)dataIndex; - byte[] data; + int ndataIndex = (int)dataIndex; + byte[] data; + + // 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?"); - // 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) + SqlString temp = GetSqlString(i); + if (_metaData[i].metaType.IsNCharType) { - data = GetSqlBinary(i).Value; + data = temp.GetUnicodeBytes(); } else { - Debug.Assert(_metaData[i].metaType.IsLong, "non long type?"); - Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?"); + 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; + } - SqlString temp = GetSqlString(i); - if (_metaData[i].metaType.IsNCharType) + // 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) { - data = temp.GetUnicodeBytes(); + cbytes = cbytes - ndataIndex; } else { - data = temp.GetNonUnicodeBytes(); + cbytes = length; } } + Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes); + } + catch (Exception e) + { + // UNDONE - should not be catching all exceptions!!! + if (!ADP.IsCatchableExceptionType(e)) + { + throw; + } cbytes = data.Length; - // if no buffer is passed in, return the number of characters we have - if (buffer == null) + if (length < 0) { - remaining = cbytes; - return TdsOperationStatus.Done; + throw ADP.InvalidDataLength(length); } - // if dataIndex is outside of data range, return 0 - if (ndataIndex < 0 || ndataIndex >= cbytes) + // if bad buffer index, throw + if (bufferIndex < 0 || bufferIndex >= buffer.Length) { - return TdsOperationStatus.Done; + throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex)); } - 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; - } - } - Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes); - } - catch (Exception e) + // if there is not enough room in the buffer for data + if (cbytes + bufferIndex > buffer.Length) { - // UNDONE - should not be catching all exceptions!!! - 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 ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex); } - remaining = cbytes; - return TdsOperationStatus.Done; - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); + throw; } -#endif //DEBUG + + remaining = cbytes; + return TdsOperationStatus.Done; } catch (System.OutOfMemoryException e) { @@ -2177,61 +2091,46 @@ internal TdsOperationStatus TryGetBytesInternalSequential(int i, byte[] buffer, RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try + if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) { - tdsReliabilitySection.Start(); -#endif //DEBUG - if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) - { - // No data left or nothing requested, return 0 - bytesRead = 0; - return TdsOperationStatus.Done; - } - else + // 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) { - // if plp columns, do partial reads. Don't read the entire value in one shot. - if (_metaData[i].metaType.IsPlp) + // Read in data + result = _stateObj.TryReadPlpBytes(ref buffer, index, length, out bytesRead); + _columnDataBytesRead += bytesRead; + if (result != TdsOperationStatus.Done) { - // 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) - { - _sharedState._columnDataBytesRemaining = -1; - return result; - } - _sharedState._columnDataBytesRemaining = (long)left; - return TdsOperationStatus.Done; + return result; } - else + + // Query for number of bytes left + ulong left; + result = _parser.TryPlpBytesLeft(_stateObj, out left); + if (result != TdsOperationStatus.Done) { - // 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; + _sharedState._columnDataBytesRemaining = -1; 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 } catch (System.OutOfMemoryException e) { @@ -2534,113 +2433,96 @@ private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int buffe RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - long cch; + 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"); + 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 (!_metaData[i].metaType.IsCharType) - { - throw SQL.NonCharColumn(_metaData[i].column); - } + if (!_metaData[i].metaType.IsCharType) + { + throw SQL.NonCharColumn(_metaData[i].column); + } - if (_sharedState._nextColumnHeaderToRead <= i) - { - ReadColumnHeader(i); - } + if (_sharedState._nextColumnHeaderToRead <= i) + { + ReadColumnHeader(i); + } - // If data is null, ReadColumnHeader sets the data.IsNull bit. - if (_data[i] != null && _data[i].IsNull) - { - throw new SqlNullValueException(); - } + // If data is null, ReadColumnHeader sets the data.IsNull bit. + if (_data[i] != null && _data[i].IsNull) + { + throw new SqlNullValueException(); + } - if (dataIndex < _columnDataCharsRead) - { - // Don't allow re-read of same chars in sequential access mode - throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars)); - } + if (dataIndex < _columnDataCharsRead) + { + // Don't allow re-read of same chars in sequential access mode + throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, nameof(GetChars)); + } - // 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 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; + } - bool isUnicode = _metaData[i].metaType.IsNCharType; + bool isUnicode = _metaData[i].metaType.IsNCharType; - // 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 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 (0 == _sharedState._columnDataBytesRemaining) - { - _stateObj._plpdecoder = null; - return 0; // We've read this column to the end - } + 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 - // TODO: for DBCS encoding it returns number of bytes, not number of chars - if (buffer == null) - { - cch = (long)_parser.PlpBytesTotalLength(_stateObj); - return (isUnicode && (cch > 0)) ? cch >> 1 : cch; - } - if (dataIndex > _columnDataCharsRead) - { - // Skip chars + // if no buffer is passed in, return the total number of characters or -1 + // TODO: for DBCS encoding it returns number of bytes, not number of chars + 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; - // TODO: for DBCS encoding skip positioning dataIndex is not in characters but is interpreted as - // number of chars already read + number of bytes to skip - 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; + // 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; + // TODO: for DBCS encoding skip positioning dataIndex is not in characters but is interpreted as + // number of chars already read + number of bytes to skip + 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; + if (isUnicode) + { + cch = (long)_parser.ReadPlpUnicodeChars(ref buffer, bufferIndex, length, _stateObj); + _columnDataBytesRead += (cch << 1); } -#if DEBUG - finally + else { - tdsReliabilitySection.Stop(); + cch = (long)_parser.ReadPlpAnsiChars(ref buffer, bufferIndex, length, _metaData[i], _stateObj); + _columnDataBytesRead += cch << 1; } -#endif //DEBUG + _columnDataCharsRead += cch; + _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj); + return cch; } catch (System.OutOfMemoryException e) { @@ -3785,156 +3667,139 @@ private TdsOperationStatus TryNextResult(out bool more) try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try + SetTimeout(_defaultTimeoutMilliseconds); + + if (IsClosed) { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - statistics = SqlStatistics.StartTimer(Statistics); + throw ADP.DataReaderClosed(nameof(NextResult)); + } + _fieldNameLookup = null; - SetTimeout(_defaultTimeoutMilliseconds); + bool success = false; // WebData 100390 + _hasRows = false; // reset HasRows - if (IsClosed) + // 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) { - throw ADP.DataReaderClosed(nameof(NextResult)); + more = false; + return result; } - _fieldNameLookup = null; - bool success = false; // WebData 100390 - _hasRows = false; // reset HasRows + // 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 we are specifically only processing a single result, then read all the results off the wire and detach - if (IsCommandBehavior(CommandBehavior.SingleResult)) + if (_parser != null) + { + // if there are more rows, then skip them, the user wants the next result + bool moreRows = true; + while (moreRows) { - result = TryCloseInternal(closeReader: false); + result = TryReadInternal(false, out moreRows); if (result != TdsOperationStatus.Done) { + // don't reset set the timeout value 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 (_parser != null) + // 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) { - // if there are more rows, then skip them, the user wants the next result - bool moreRows = true; - while (moreRows) + more = false; + return result; + } + if (moreResults) + { + _metaDataConsumed = false; + _browseModeInfoConsumed = false; + + switch (_altRowStatus) { - result = TryReadInternal(false, out moreRows); - if (result != TdsOperationStatus.Done) - { - // don't reset set the timeout value - more = false; - return result; - } + 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; } - } - // we may be done, so continue only if we have not detached ourselves from the parser - if (_parser != null) + success = true; + } + else { - bool moreResults; - result = TryHasMoreResults(out moreResults); + // detach the parser from this reader now + result = TryCloseInternal(closeReader: false); if (result != TdsOperationStatus.Done) { more = false; return result; } - if (moreResults) - { - _metaDataConsumed = false; - _browseModeInfoConsumed = false; - - 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 + // 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) { - // detach the parser from this reader now - result = TryCloseInternal(closeReader: false); - 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. - result = TrySetMetaData(null, false); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + more = false; + return result; } } - else - { - // Clear state in case of Read calling CloseInternal() then user calls NextResult() - // MDAC 81986. Or, also the case where the Read() above will do essentially the same - // thing. - ClearMetaData(); - } - - more = success; - return TdsOperationStatus.Done; } -#if DEBUG - finally + else { - tdsReliabilitySection.Stop(); + // Clear state in case of Read calling CloseInternal() then user calls NextResult() + // MDAC 81986. Or, also the case where the Read() above will do essentially the same + // thing. + ClearMetaData(); } -#endif //DEBUG + + more = success; + return TdsOperationStatus.Done; } catch (System.OutOfMemoryException e) { @@ -4001,140 +3866,117 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + TdsOperationStatus result; + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try + if (_parser != null) { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - TdsOperationStatus result; - statistics = SqlStatistics.StartTimer(Statistics); - - if (_parser != null) + if (setTimeout) { - if (setTimeout) - { - SetTimeout(_defaultTimeoutMilliseconds); - } - if (_sharedState._dataReady) + SetTimeout(_defaultTimeoutMilliseconds); + } + if (_sharedState._dataReady) + { + result = TryCleanPartialRead(); + if (result != TdsOperationStatus.Done) { - result = TryCleanPartialRead(); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + 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) + if (!_haltRead) + { + bool moreRows; + result = TryHasMoreRows(out moreRows); + if (result != TdsOperationStatus.Done) { - bool moreRows; - result = TryHasMoreRows(out moreRows); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } - if (moreRows) + more = false; + return result; + } + if (moreRows) + { + // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) + while (_stateObj.HasPendingData) { - // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) - while (_stateObj.HasPendingData) + if (_altRowStatus != ALTROWSTATUS.AltRow) { - if (_altRowStatus != ALTROWSTATUS.AltRow) + // 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 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; - } + more = false; + return result; } - 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; } } - if (_sharedState._dataReady) + else { - _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); - more = true; - return TdsOperationStatus.Done; + // ALTROW token and AltrowId are already consumed ... + Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Done; + _sharedState._dataReady = true; + break; } } - - if (!_stateObj.HasPendingData) + if (_sharedState._dataReady) { - result = TryCloseInternal(closeReader: false); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); + more = true; + return TdsOperationStatus.Done; } } - else + + if (!_stateObj.HasPendingData) { - // 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); + result = TryCloseInternal(closeReader: false); if (result != TdsOperationStatus.Done) { more = false; return result; } - while (moreRows) + } + } + 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) { - // 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) - { - result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } - } - - if (_sharedState._dataReady) + result = _parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady); + if (result != TdsOperationStatus.Done) { - result = TryCleanPartialRead(); - if (result != TdsOperationStatus.Done) - { - more = false; - return result; - } + more = false; + return result; } + } - // clear out our buffers - SqlBuffer.Clear(_data); - - _sharedState._nextColumnHeaderToRead = 0; - - result = TryHasMoreRows(out moreRows); + if (_sharedState._dataReady) + { + result = TryCleanPartialRead(); if (result != TdsOperationStatus.Done) { more = false; @@ -4142,38 +3984,44 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more) } } - // reset haltRead - _haltRead = false; - } - } - else if (IsClosed) - { - throw ADP.DataReaderClosed(nameof(Read)); - } - more = false; + // clear out our buffers + SqlBuffer.Clear(_data); -#if DEBUG - if ((!_sharedState._dataReady) && (_stateObj.HasPendingData)) - { - byte token; - result = _stateObj.TryPeekByte(out token); - if (result != TdsOperationStatus.Done) - { - return result; + _sharedState._nextColumnHeaderToRead = 0; + + result = TryHasMoreRows(out moreRows); + if (result != TdsOperationStatus.Done) + { + more = false; + return result; + } } - Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); + // reset haltRead + _haltRead = false; } -#endif - - return TdsOperationStatus.Done; } + else if (IsClosed) + { + throw ADP.DataReaderClosed(nameof(Read)); + } + more = false; + #if DEBUG - finally + if ((!_sharedState._dataReady) && (_stateObj.HasPendingData)) { - tdsReliabilitySection.Stop(); + 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}"); } -#endif //DEBUG +#endif + + return TdsOperationStatus.Done; } catch (OutOfMemoryException e) { @@ -4234,38 +4082,21 @@ private TdsOperationStatus TryReadColumn(int i, bool setTimeout, bool allowParti RuntimeHelpers.PrepareConstrainedRegions(); try { -#if 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"); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if (setTimeout) { -#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?"); + SetTimeout(_defaultTimeoutMilliseconds); } -#if DEBUG - finally + + TdsOperationStatus result = TryReadColumnInternal(i, readHeaderOnly: false, forStreaming: forStreaming); + if (result != TdsOperationStatus.Done) { - tdsReliabilitySection.Stop(); + return result; } -#endif //DEBUG + + Debug.Assert(_data[i] != null, " data buffer is null?"); } catch (System.OutOfMemoryException e) { @@ -4339,22 +4170,7 @@ private TdsOperationStatus TryReadColumnHeader(int i) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - return TryReadColumnInternal(i, readHeaderOnly: true, forStreaming: false); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + return TryReadColumnInternal(i, readHeaderOnly: true, forStreaming: false); } catch (System.OutOfMemoryException e) { @@ -5824,18 +5640,7 @@ private static Task GetFieldValueAsyncExecute(Task task, object state) { if (reader.IsCommandBehavior(CommandBehavior.SequentialAccess) && reader._sharedState._dataReady) { - bool internalReadSuccess = false; - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); - internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true, forStreaming: false) == TdsOperationStatus.Done; - } - finally - { - tdsReliabilitySection.Stop(); - } + bool internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true, forStreaming: false) == TdsOperationStatus.Done; if (internalReadSuccess) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index d0c64d07e3..9385c1953f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -511,51 +511,34 @@ internal SqlInternalConnectionTds( RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + _timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + // If transient fault handling is enabled then we can retry the login upto the ConnectRetryCount. + int connectionEstablishCount = applyTransientFaultHandling ? connectionOptions.ConnectRetryCount + 1 : 1; + int transientRetryIntervalInMilliSeconds = connectionOptions.ConnectRetryInterval * 1000; // Max value of transientRetryInterval is 60*1000 ms. The max value allowed for ConnectRetryInterval is 60 + for (int i = 0; i < connectionEstablishCount; i++) { -#endif //DEBUG - _timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); - - // If transient fault handling is enabled then we can retry the login upto the ConnectRetryCount. - int connectionEstablishCount = applyTransientFaultHandling ? connectionOptions.ConnectRetryCount + 1 : 1; - int transientRetryIntervalInMilliSeconds = connectionOptions.ConnectRetryInterval * 1000; // Max value of transientRetryInterval is 60*1000 ms. The max value allowed for ConnectRetryInterval is 60 - for (int i = 0; i < connectionEstablishCount; i++) + try { - try + OpenLoginEnlist(_timeout, connectionOptions, credential, newPassword, newSecurePassword, redirectedUserInstance); + break; + } + catch (SqlException sqlex) + { + if (i + 1 == connectionEstablishCount + || !applyTransientFaultHandling + || _timeout.IsExpired + || _timeout.MillisecondsRemaining < transientRetryIntervalInMilliSeconds + || !IsTransientError(sqlex)) { - OpenLoginEnlist(_timeout, connectionOptions, credential, newPassword, newSecurePassword, redirectedUserInstance); - break; + throw; } - catch (SqlException sqlex) + else { - if (i + 1 == connectionEstablishCount - || !applyTransientFaultHandling - || _timeout.IsExpired - || _timeout.MillisecondsRemaining < transientRetryIntervalInMilliSeconds - || !IsTransientError(sqlex)) - { - throw; - } - else - { - Thread.Sleep(transientRetryIntervalInMilliSeconds); - } + Thread.Sleep(transientRetryIntervalInMilliSeconds); } } } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG } catch (System.OutOfMemoryException) { @@ -973,29 +956,8 @@ internal void CheckEnlistedTransactionBinding() } } - internal override bool IsConnectionAlive(bool throwOnException) - { - bool isAlive = false; -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - - isAlive = _parser._physicalStateObj.IsConnectionAlive(throwOnException); - -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG - return isAlive; - } + internal override bool IsConnectionAlive(bool throwOnException) => + _parser._physicalStateObj.IsConnectionAlive(throwOnException); //////////////////////////////////////////////////////////////////////////////////////// // POOLING METHODS @@ -2374,32 +2336,18 @@ internal bool GetSessionAndReconnectIfNeeded(SqlConnection parent, int timeout = RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try + Task reconnectTask = parent.ValidateAndReconnect(() => { - tdsReliabilitySection.Start(); -#endif //DEBUG - Task reconnectTask = parent.ValidateAndReconnect(() => - { - ThreadHasParserLockForClose = false; - _parserLock.Release(); - releaseConnectionLock = false; - }, timeout); - if (reconnectTask != null) - { - AsyncHelper.WaitForCompletion(reconnectTask, timeout); - return true; - } - return false; -#if DEBUG - } - finally + ThreadHasParserLockForClose = false; + _parserLock.Release(); + releaseConnectionLock = false; + }, timeout); + if (reconnectTask != null) { - tdsReliabilitySection.Stop(); + AsyncHelper.WaitForCompletion(reconnectTask, timeout); + return true; } -#endif //DEBUG + return false; } catch (System.OutOfMemoryException) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs index d5a93b1b86..fb72a5e0c8 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs @@ -32,29 +32,12 @@ public override void Commit() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); + _isFromAPI = true; - _isFromAPI = true; - - _internalTransaction.Commit(); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + _internalTransaction.Commit(); } catch (System.OutOfMemoryException e) { @@ -101,28 +84,11 @@ protected override void Dispose(bool disposing) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - if (!IsZombied && !Is2005PartialZombie) - { - _internalTransaction.Dispose(); - } - } -#if DEBUG - finally + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + if (!IsZombied && !Is2005PartialZombie) { - tdsReliabilitySection.Stop(); + _internalTransaction.Dispose(); } -#endif //DEBUG } catch (System.OutOfMemoryException e) { @@ -167,29 +133,12 @@ public override void Rollback() RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - _isFromAPI = true; + _isFromAPI = true; - _internalTransaction.Rollback(); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + _internalTransaction.Rollback(); } catch (System.OutOfMemoryException e) { @@ -231,29 +180,12 @@ public void Rollback(string transactionName) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); + _isFromAPI = true; - _isFromAPI = true; - - _internalTransaction.Rollback(transactionName); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + _internalTransaction.Rollback(transactionName); } catch (System.OutOfMemoryException e) { @@ -295,27 +227,10 @@ public void Save(string savePointName) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); - - _internalTransaction.Save(savePointName); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + _internalTransaction.Save(savePointName); } catch (System.OutOfMemoryException e) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index e845f1bdb9..b92e962248 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -55,7 +55,7 @@ internal int ObjectID /// Verify client encryption possibility. /// private bool ClientOSEncryptionSupport => SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport; - + // Default state object for parser internal TdsParserStateObject _physicalStateObj = null; // Default stateObj and connection for Dbnetlib and non-MARS SNI. @@ -159,7 +159,7 @@ internal int ObjectID // size of Guid (e.g. _clientConnectionId, ActivityId.Id) private const int GUID_SIZE = 16; private byte[] _tempGuidBytes; - + // now data length is 1 byte // First bit is 1 indicating client support failover partner with readonly intent private static readonly byte[] s_FeatureExtDataAzureSQLSupportFeatureRequest = { 0x01 }; @@ -1812,8 +1812,6 @@ internal byte[] SerializeShort(int v, TdsParserStateObject stateObj) // internal void WriteShort(int v, TdsParserStateObject stateObj) { - ReliabilitySection.Assert("unreliable call to WriteShort"); // you need to setup for a thread abort somewhere before you call this method - if ((stateObj._outBytesUsed + 2) > stateObj._outBuff.Length) { // if all of the short doesn't fit into the buffer @@ -1872,8 +1870,6 @@ internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) internal void WriteInt(int v, TdsParserStateObject stateObj) { - ReliabilitySection.Assert("unreliable call to WriteInt"); // you need to setup for a thread abort somewhere before you call this method - if ((stateObj._outBytesUsed + 4) > stateObj._outBuff.Length) { // if all of the int doesn't fit into the buffer @@ -1942,8 +1938,6 @@ internal byte[] SerializeLong(long v, TdsParserStateObject stateObj) internal void WriteLong(long v, TdsParserStateObject stateObj) { - ReliabilitySection.Assert("unreliable call to WriteLong"); // you need to setup for a thread abort somewhere before you call this method - if ((stateObj._outBytesUsed + 8) > stateObj._outBuff.Length) { // if all of the long doesn't fit into the buffer @@ -1989,7 +1983,6 @@ internal byte[] SerializePartialLong(long v, int length) internal void WritePartialLong(long v, int length, TdsParserStateObject stateObj) { - ReliabilitySection.Assert("unreliable call to WritePartialLong"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(length <= 8, "Length specified is longer than the size of a long"); Debug.Assert(length >= 0, "Length should not be negative"); @@ -2107,7 +2100,6 @@ internal static bool IsValidTdsToken(byte token) // Main parse loop for the top-level tds tokens, calls back into the I*Handler interfaces internal TdsOperationStatus TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, out bool dataReady) { - ReliabilitySection.Assert("unreliable call to Run"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert((SniContext.Undefined != stateObj.SniContext) && // SniContext must not be Undefined ((stateObj._attentionSent) || ((SniContext.Snix_Execute != stateObj.SniContext) && (SniContext.Snix_SendRows != stateObj.SniContext))), // SniContext should not be Execute or SendRows unless attention was sent (and, therefore, we are looking for an ACK) $"Unexpected SniContext on call to TryRun; SniContext={stateObj.SniContext}"); @@ -4936,89 +4928,72 @@ internal void DrainData(TdsParserStateObject stateObj) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); try { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - try + SqlDataReader.SharedState sharedState = stateObj._readerState; + if (sharedState != null && sharedState._dataReady) { - SqlDataReader.SharedState sharedState = stateObj._readerState; - if (sharedState != null && sharedState._dataReady) + var metadata = stateObj._cleanupMetaData; + if (stateObj._partialHeaderBytesRead > 0) { - var metadata = stateObj._cleanupMetaData; - if (stateObj._partialHeaderBytesRead > 0) + TdsOperationStatus result = stateObj.TryProcessHeader(); + if (result != TdsOperationStatus.Done) { - TdsOperationStatus result = stateObj.TryProcessHeader(); - if (result != TdsOperationStatus.Done) - { - throw SQL.SynchronousCallMayNotPend(); - } + throw SQL.SynchronousCallMayNotPend(); } - if (0 == sharedState._nextColumnHeaderToRead) + } + if (0 == sharedState._nextColumnHeaderToRead) + { + // i. user called read but didn't fetch anything + TdsOperationStatus result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); + if (result != TdsOperationStatus.Done) { - // i. user called read but didn't fetch anything - TdsOperationStatus result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); - if (result != TdsOperationStatus.Done) - { - throw SQL.SynchronousCallMayNotPend(); - } + throw SQL.SynchronousCallMayNotPend(); } - else + } + else + { + // iia. if we still have bytes left from a partially read column, skip + if (sharedState._nextColumnDataToRead < sharedState._nextColumnHeaderToRead) { - // iia. if we still have bytes left from a partially read column, skip - if (sharedState._nextColumnDataToRead < sharedState._nextColumnHeaderToRead) + if ((sharedState._nextColumnHeaderToRead > 0) && (metadata[sharedState._nextColumnHeaderToRead - 1].metaType.IsPlp)) { - if ((sharedState._nextColumnHeaderToRead > 0) && (metadata[sharedState._nextColumnHeaderToRead - 1].metaType.IsPlp)) - { - if (stateObj._longlen != 0) - { - TdsOperationStatus result = TrySkipPlpValue(UInt64.MaxValue, stateObj, out _); - if (result != TdsOperationStatus.Done) - { - throw SQL.SynchronousCallMayNotPend(); - } - } - } - - else if (0 < sharedState._columnDataBytesRemaining) + if (stateObj._longlen != 0) { - TdsOperationStatus result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + TdsOperationStatus result = TrySkipPlpValue(UInt64.MaxValue, stateObj, out _); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } } - } - - // Read the remaining values off the wire for this row - if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + else if (0 < sharedState._columnDataBytesRemaining) { - throw SQL.SynchronousCallMayNotPend(); + TdsOperationStatus result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + if (result != TdsOperationStatus.Done) + { + throw SQL.SynchronousCallMayNotPend(); + } } + + } + + + // Read the remaining values off the wire for this row + if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + { + throw SQL.SynchronousCallMayNotPend(); } } - Run(RunBehavior.Clean, null, null, null, stateObj); - } - catch - { - _connHandler.DoomThisConnection(); - throw; } + Run(RunBehavior.Clean, null, null, null, stateObj); } -#if DEBUG - finally + catch { - tdsReliabilitySection.Stop(); + _connHandler.DoomThisConnection(); + throw; } -#endif //DEBUG } catch (System.OutOfMemoryException) { @@ -10581,24 +10556,7 @@ private void TdsExecuteRPC_OnFailure(Exception exc, TdsParserStateObject stateOb RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - FailureCleanup(stateObj, exc); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + FailureCleanup(stateObj, exc); } catch (System.OutOfMemoryException) { @@ -10628,24 +10586,7 @@ private void ExecuteFlushTaskCallback(Task tsk, TdsParserStateObject stateObj, T RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - FailureCleanup(stateObj, tsk.Exception); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + FailureCleanup(stateObj, tsk.Exception); } catch (System.OutOfMemoryException e) { @@ -12353,31 +12294,14 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - Task task = null; - if (count > 0) - { - _parser.WriteInt(count, _stateObj); // write length of chunk - task = _stateObj.WriteByteArray(buffer, count, offset, canAccumulate: false); - } - - return task ?? Task.CompletedTask; - } -#if DEBUG - finally + Task task = null; + if (count > 0) { - tdsReliabilitySection.Stop(); + _parser.WriteInt(count, _stateObj); // write length of chunk + task = _stateObj.WriteByteArray(buffer, count, offset, canAccumulate: false); } -#endif //DEBUG + + return task ?? Task.CompletedTask; } catch (System.OutOfMemoryException) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs index 32d9b091ce..7150aadfd2 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs @@ -9,88 +9,6 @@ namespace Microsoft.Data.SqlClient { internal sealed partial class TdsParser { - // ReliabilitySection Usage: - // - // #if DEBUG - // TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - // - // RuntimeHelpers.PrepareConstrainedRegions(); - // try { - // tdsReliabilitySection.Start(); - // #else - // { - // #endif //DEBUG - // - // // code that requires reliability - // - // } - // #if DEBUG - // finally { - // tdsReliabilitySection.Stop(); - // } - // #endif //DEBUG - - internal struct ReliabilitySection - { -#if DEBUG - // do not allocate TLS data in RETAIL bits - [ThreadStatic] - private static int s_reliabilityCount; // initialized to 0 by CLR - - private bool m_started; // initialized to false (not started) by CLR -#endif //DEBUG - - [Conditional("DEBUG")] - internal void Start() - { -#if DEBUG - Debug.Assert(!m_started); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - ++s_reliabilityCount; - m_started = true; - } -#endif //DEBUG - } - - [Conditional("DEBUG")] - internal void Stop() - { -#if DEBUG - // cannot assert m_started - ThreadAbortException can be raised before Start is called - - if (m_started) - { - Debug.Assert(s_reliabilityCount > 0); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - --s_reliabilityCount; - m_started = false; - } - } -#endif //DEBUG - } - - // you need to setup for a thread abort somewhere before you call this method - [Conditional("DEBUG")] - internal static void Assert(string message) - { -#if DEBUG - Debug.Assert(s_reliabilityCount > 0, message); -#endif //DEBUG - } - } - // This is called from a ThreadAbort - ensure that it can be run from a CER Catch internal void BestEffortCleanup() { @@ -185,21 +103,7 @@ internal bool RunReliably(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDat RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); } catch (OutOfMemoryException) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs index 0ce58d120a..2bb9873984 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs @@ -214,22 +214,7 @@ private void ResetCancelAndProcessAttention() // We serialize Cancel/CloseSession to prevent a race condition between these two states. // The problem is that both sending and receiving attentions are time taking // operations. -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - Parser.ProcessPendingAck(this); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + Parser.ProcessPendingAck(this); } SetTimeoutStateStopped(); } @@ -429,8 +414,6 @@ internal bool ValidateSNIConnection() // This method should only be called by ReadSni! If not - it may have problems with timeouts! private void ReadSniError(TdsParserStateObject stateObj, uint error) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadSniSyncError"); // you need to setup for a thread abort somewhere before you call this method - if (TdsEnums.SNI_WAIT_TIMEOUT == error) { Debug.Assert(_syncOverAsync, "Should never reach here with async on!"); @@ -840,8 +823,6 @@ public void WriteAsyncCallback(IntPtr key, PacketHandle packet, uint sniError) // internal void WriteSecureString(SecureString secureString) { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteSecureString"); // you need to setup for a thread abort somewhere before you call this method - Debug.Assert(_securePasswords[0] == null || _securePasswords[1] == null, "There are more than two secure passwords"); int index = _securePasswords[0] != null ? 1 : 0; @@ -919,8 +900,6 @@ internal Task WaitForAccumulatedWrites() // and then the buffer is re-initialized in flush() and then the byte is put in the buffer. internal void WriteByte(byte b) { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteByte"); // you need to setup for a thread abort somewhere before you call this method - Debug.Assert(_outBytesUsed <= _outBuff.Length, "ERROR - TDSParser: _outBytesUsed > _outBuff.Length"); // check to make sure we haven't used the full amount of space available in the buffer, if so, flush it @@ -936,8 +915,6 @@ internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumu { try { - TdsParser.ReliabilitySection.Assert("unreliable call to WriteByteArray"); // you need to setup for a thread abort somewhere before you call this method - bool async = _parser._asyncWrite; // NOTE: We are capturing this now for the assert after the Task is returned, since WritePacket will turn off async if there is an exception Debug.Assert(async || _asyncWriteCount == 0); // Do we have to send out in packet size chunks, or can we rely on netlib layer to break it up? diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs index 336f690776..b3a9217892 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs @@ -1158,29 +1158,14 @@ private void WaitForPendingOpen() #endif try { -#if DEBUG - Microsoft.Data.SqlClient.TdsParser.ReliabilitySection tdsReliabilitySection = new Microsoft.Data.SqlClient.TdsParser.ReliabilitySection(); - -#if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); -#endif - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bool allowCreate = true; - bool onlyOneCheckConnection = false; - ADP.SetCurrentTransaction(next.Completion.Task.AsyncState as Transaction); - timeout = !TryGetConnection(next.Owner, delay, allowCreate, onlyOneCheckConnection, next.UserOptions, out connection); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + ADP.SetCurrentTransaction(next.Completion.Task.AsyncState as Transaction); + timeout = !TryGetConnection( + next.Owner, + delay, + allowCreate: true, + onlyOneCheckConnection: false, + next.UserOptions, + out connection); } catch (System.OutOfMemoryException) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs index 0f57a0e74f..bf1e7e97bb 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs @@ -260,27 +260,11 @@ public static void DeriveParameters(SqlCommand command) #endif try { -#if NETFRAMEWORK -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try { - tdsReliabilitySection.Start(); -#else - { -#endif // DEBUG + #if NETFRAMEWORK bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(command.Connection); -#endif // NETFRAMEWORK + #endif + command.DeriveParameters(); -#if NETFRAMEWORK - } -#if DEBUG - finally { - tdsReliabilitySection.Stop(); - } -#endif // DEBUG -#endif // NETFRAMEWORK } catch (OutOfMemoryException e) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs index 174a1eb1bb..02c10569bc 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs @@ -86,43 +86,26 @@ public void Initialize() #endif try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + if (connection.IsEnlistedInTransaction) { -#endif - if (connection.IsEnlistedInTransaction) - { - SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Initialize | RES | CPOOL | {0}, Client Connection Id {1}, was enlisted, now defecting.", ObjectID, usersConnection?.ClientConnectionId); - - // defect first - connection.EnlistNull(); - } + SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Initialize | RES | CPOOL | {0}, Client Connection Id {1}, was enlisted, now defecting.", ObjectID, usersConnection?.ClientConnectionId); - _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null); + // defect first + connection.EnlistNull(); + } - connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true); + _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null); - // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw. - if (connection.CurrentTransaction == null) - { - connection.DoomThisConnection(); - throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure); - } + connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true); - _active = true; - } -#if NETFRAMEWORK && DEBUG - finally + // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw. + if (connection.CurrentTransaction == null) { - tdsReliabilitySection.Stop(); + connection.DoomThisConnection(); + throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure); } -#endif + + _active = true; } catch (System.OutOfMemoryException e) { @@ -168,69 +151,52 @@ public byte[] Promote() #endif try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else + lock (connection) { -#endif - lock (connection) + try { - try - { - // Now that we've acquired the lock, make sure we still have valid state for this operation. - ValidateActiveOnConnection(connection); + // Now that we've acquired the lock, make sure we still have valid state for this operation. + ValidateActiveOnConnection(connection); - connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Promote, null, System.Data.IsolationLevel.Unspecified, _internalTransaction, true); - returnValue = connection.PromotedDTCToken; + connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Promote, null, System.Data.IsolationLevel.Unspecified, _internalTransaction, true); + returnValue = connection.PromotedDTCToken; - // For Global Transactions, we need to set the Transaction Id since we use a Non-MSDTC Promoter type. - if (connection.IsGlobalTransaction) + // For Global Transactions, we need to set the Transaction Id since we use a Non-MSDTC Promoter type. + if (connection.IsGlobalTransaction) + { + if (SysTxForGlobalTransactions.SetDistributedTransactionIdentifier == null) { - if (SysTxForGlobalTransactions.SetDistributedTransactionIdentifier == null) - { - throw SQL.UnsupportedSysTxForGlobalTransactions(); - } - - if (!connection.IsGlobalTransactionsEnabledForServer) - { - throw SQL.GlobalTransactionsNotEnabled(); - } + throw SQL.UnsupportedSysTxForGlobalTransactions(); + } - SysTxForGlobalTransactions.SetDistributedTransactionIdentifier.Invoke(_atomicTransaction, new object[] { this, GetGlobalTxnIdentifierFromToken() }); + if (!connection.IsGlobalTransactionsEnabledForServer) + { + throw SQL.GlobalTransactionsNotEnabled(); } - promoteException = null; + SysTxForGlobalTransactions.SetDistributedTransactionIdentifier.Invoke(_atomicTransaction, new object[] { this, GetGlobalTxnIdentifierFromToken() }); } - catch (SqlException e) - { - promoteException = e; - ADP.TraceExceptionWithoutRethrow(e); + promoteException = null; + } + catch (SqlException e) + { + promoteException = e; - // Doom the connection, to make sure that the transaction is - // eventually rolled back. - // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event - connection.DoomThisConnection(); - } - catch (InvalidOperationException e) - { - promoteException = e; - ADP.TraceExceptionWithoutRethrow(e); - connection.DoomThisConnection(); - } + ADP.TraceExceptionWithoutRethrow(e); + + // Doom the connection, to make sure that the transaction is + // eventually rolled back. + // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event + connection.DoomThisConnection(); + } + catch (InvalidOperationException e) + { + promoteException = e; + ADP.TraceExceptionWithoutRethrow(e); + connection.DoomThisConnection(); } } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif } catch (System.OutOfMemoryException e) { @@ -288,10 +254,6 @@ public void Rollback(SinglePhaseEnlistment enlistment) if (connection != null) { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - tdsReliabilitySection.Start(); -#endif //DEBUG SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Rollback | RES | CPOOL | Object Id {0}, Client Connection Id {1}, rolling back transaction.", ObjectID, usersConnection?.ClientConnectionId); #if NETFRAMEWORK @@ -362,12 +324,6 @@ public void Rollback(SinglePhaseEnlistment enlistment) usersConnection.Abort(e); throw; } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif } else { @@ -393,103 +349,88 @@ public void SinglePhaseCommit(SinglePhaseEnlistment enlistment) try { -#if NETFRAMEWORK && DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - try - { - tdsReliabilitySection.Start(); -#else + // If the connection is doomed, we can be certain that the + // transaction will eventually be rolled back or has already been aborted externally, and we shouldn't + // attempt to commit it. + if (connection.IsConnectionDoomed) { -#endif - // If the connection is doomed, we can be certain that the - // transaction will eventually be rolled back or has already been aborted externally, and we shouldn't - // attempt to commit it. - if (connection.IsConnectionDoomed) + lock (connection) { - lock (connection) - { - _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. - _connection = null; - } - - enlistment.Aborted(SQL.ConnectionDoomed()); + _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. + _connection = null; } - else + + enlistment.Aborted(SQL.ConnectionDoomed()); + } + else + { + Exception commitException; + lock (connection) { - Exception commitException; - lock (connection) + try { - try - { - // Now that we've acquired the lock, make sure we still have valid state for this operation. - ValidateActiveOnConnection(connection); + // Now that we've acquired the lock, make sure we still have valid state for this operation. + ValidateActiveOnConnection(connection); - _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. - _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event + _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. + _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event - connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, System.Data.IsolationLevel.Unspecified, _internalTransaction, true); - commitException = null; - } - catch (SqlException e) - { - commitException = e; + connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, System.Data.IsolationLevel.Unspecified, _internalTransaction, true); + commitException = null; + } + catch (SqlException e) + { + commitException = e; - ADP.TraceExceptionWithoutRethrow(e); + ADP.TraceExceptionWithoutRethrow(e); - // Doom the connection, to make sure that the transaction is - // eventually rolled back. - // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event - connection.DoomThisConnection(); - } - catch (InvalidOperationException e) - { - commitException = e; - ADP.TraceExceptionWithoutRethrow(e); - connection.DoomThisConnection(); - } + // Doom the connection, to make sure that the transaction is + // eventually rolled back. + // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event + connection.DoomThisConnection(); } - if (commitException != null) + catch (InvalidOperationException e) { - // connection.ExecuteTransaction failed with exception - if (_internalTransaction.IsCommitted) - { - // Even though we got an exception, the transaction - // was committed by the server. - enlistment.Committed(); - } - else if (_internalTransaction.IsAborted) - { - // The transaction was aborted, report that to - // System.Transactions. - enlistment.Aborted(commitException); - } - else - { - // The transaction is still active, we cannot - // know the state of the transaction. - enlistment.InDoubt(commitException); - } - - // We eat the exception. This is called on the SysTx - // thread, not the applications thread. If we don't - // eat the exception an UnhandledException will occur, - // causing the process to FailFast. + commitException = e; + ADP.TraceExceptionWithoutRethrow(e); + connection.DoomThisConnection(); } - - connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); - if (commitException == null) + } + if (commitException != null) + { + // connection.ExecuteTransaction failed with exception + if (_internalTransaction.IsCommitted) { - // connection.ExecuteTransaction succeeded + // Even though we got an exception, the transaction + // was committed by the server. enlistment.Committed(); } + else if (_internalTransaction.IsAborted) + { + // The transaction was aborted, report that to + // System.Transactions. + enlistment.Aborted(commitException); + } + else + { + // The transaction is still active, we cannot + // know the state of the transaction. + enlistment.InDoubt(commitException); + } + + // We eat the exception. This is called on the SysTx + // thread, not the applications thread. If we don't + // eat the exception an UnhandledException will occur, + // causing the process to FailFast. + } + + connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); + if (commitException == null) + { + // connection.ExecuteTransaction succeeded + enlistment.Committed(); } } -#if NETFRAMEWORK && DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif } catch (System.OutOfMemoryException e) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs index 8854ce055b..00d4ed3951 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs @@ -237,50 +237,33 @@ virtual internal SqlTransaction BeginSqlTransaction(System.Data.IsolationLevel i #endif try { -#if NETFRAMEWORK -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); + #if NETFRAMEWORK + bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); + #endif - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif // DEBUG - bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); -#endif // NETFRAMEWORK - statistics = SqlStatistics.StartTimer(Connection.Statistics); + statistics = SqlStatistics.StartTimer(Connection.Statistics); -#if NETFRAMEWORK - SqlConnection.ExecutePermission.Demand(); // MDAC 81476 -#endif // NETFRAMEWORK - ValidateConnectionForExecute(null); + #if NETFRAMEWORK + SqlConnection.ExecutePermission.Demand(); // MDAC 81476 + #endif - if (HasLocalTransactionFromAPI) - { - throw ADP.ParallelTransactionsNotSupported(Connection); - } + ValidateConnectionForExecute(null); - if (iso == System.Data.IsolationLevel.Unspecified) - { - iso = System.Data.IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. - } - - SqlTransaction transaction = new(this, Connection, iso, AvailableInternalTransaction); - transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; - ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); - transaction.InternalTransaction.RestoreBrokenConnection = false; - return transaction; -#if NETFRAMEWORK + if (HasLocalTransactionFromAPI) + { + throw ADP.ParallelTransactionsNotSupported(Connection); } -#if DEBUG - finally + + if (iso == System.Data.IsolationLevel.Unspecified) { - tdsReliabilitySection.Stop(); + iso = System.Data.IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. } -#endif // DEBUG -#endif // NETFRAMEWORK + + SqlTransaction transaction = new(this, Connection, iso, AvailableInternalTransaction); + transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; + ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); + transaction.InternalTransaction.RestoreBrokenConnection = false; + return transaction; } catch (OutOfMemoryException e) { @@ -346,36 +329,18 @@ override protected void Deactivate() { SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlInternalConnection.Deactivate | ADV | Object Id {0} deactivating, Client Connection Id {1}", ObjectID, Connection?.ClientConnectionId); -#if NETFRAMEWORK -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); + #if NETFRAMEWORK + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); + #endif - RuntimeHelpers.PrepareConstrainedRegions(); - try + SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; + if (referenceCollection != null) { - tdsReliabilitySection.Start(); -#else - { -#endif // DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); -#endif // NETFRAMEWORK - SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; - if (referenceCollection != null) - { - referenceCollection.Deactivate(); - } - - // Invoke subclass-specific deactivation logic - InternalDeactivate(); -#if NETFRAMEWORK - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); + referenceCollection.Deactivate(); } -#endif // DEBUG -#endif // NETFRAMEWORK + + // Invoke subclass-specific deactivation logic + InternalDeactivate(); } catch (OutOfMemoryException) { @@ -684,25 +649,8 @@ override public void EnlistTransaction(Transaction transaction) RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif // DEBUG - bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); - Enlist(transaction); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif // DEBUG + bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); + Enlist(transaction); } #else try diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs index 127663cd0b..18291aca27 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs @@ -203,7 +203,6 @@ internal void CloseFromConnection() } finally { - TdsParser.ReliabilitySection.Assert("unreliable call to CloseFromConnection"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock) { // Always ensure we're zombied; 2005 will send an EnvChange that diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs index 67e082a0bc..3a01ca9b5a 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -183,21 +183,7 @@ internal static void ContinueTask(Task task, RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - onSuccess(); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + onSuccess(); } catch (System.OutOfMemoryException e) { @@ -330,21 +316,7 @@ internal static void ContinueTaskWithState(Task task, RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - onSuccess(state2); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG + onSuccess(state2); } catch (System.OutOfMemoryException e) { 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 b3cf628594..ae32de9e2c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -1018,7 +1018,6 @@ internal void SetBuffer(byte[] buffer, int inBytesUsed, int inBytesRead/*, [Call // NOTE: This method (and all it calls) should be retryable without replaying a snapshot internal TdsOperationStatus TryPrepareBuffer() { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadBuffer"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_inBuff != null, "packet buffer should not be null!"); // Header spans packets, or we haven't read the header yet - process header @@ -1208,7 +1207,6 @@ public TdsOperationStatus TryReadByteArray(Span buff, int len) // Every time you call this method increment the offset and decrease len by the value of totalRead public TdsOperationStatus TryReadByteArray(Span buff, int len, out int totalRead) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadByteArray"); // you need to setup for a thread abort somewhere before you call this method totalRead = 0; #if DEBUG @@ -1268,7 +1266,6 @@ public TdsOperationStatus TryReadByteArray(Span buff, int len, out int tot // before the byte is returned. internal TdsOperationStatus TryReadByte(out byte value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadByte"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_inBytesUsed >= 0 && _inBytesUsed <= _inBytesRead, "ERROR - TDSParser: _inBytesUsed < 0 or _inBytesUsed > _inBytesRead"); value = 0; @@ -1375,7 +1372,6 @@ internal TdsOperationStatus TryReadInt16(out short value) internal TdsOperationStatus TryReadInt32(out int value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt32"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); Span buffer = stackalloc byte[4]; if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) @@ -1406,7 +1402,6 @@ internal TdsOperationStatus TryReadInt32(out int value) // This method is safe to call when doing async without snapshot internal TdsOperationStatus TryReadInt64(out long value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt64"); // you need to setup for a thread abort somewhere before you call this method if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) { TdsOperationStatus result = TryPrepareBuffer(); @@ -1488,7 +1483,6 @@ internal TdsOperationStatus TryReadUInt16(out ushort value) // This method is safe to call when doing async without replay internal TdsOperationStatus TryReadUInt32(out uint value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadUInt32"); // you need to setup for a thread abort somewhere before you call this method if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) { TdsOperationStatus result = TryPrepareBuffer(); @@ -1539,7 +1533,6 @@ internal TdsOperationStatus TryReadUInt32(out uint value) internal TdsOperationStatus TryReadSingle(out float value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadSingle"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) { @@ -1574,7 +1567,6 @@ internal TdsOperationStatus TryReadSingle(out float value) internal TdsOperationStatus TryReadDouble(out double value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadDouble"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) { @@ -1609,7 +1601,6 @@ internal TdsOperationStatus TryReadDouble(out double value) internal TdsOperationStatus TryReadString(int length, out string value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadString"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); int cBytes = length << 1; byte[] buf; @@ -1651,7 +1642,6 @@ internal TdsOperationStatus TryReadString(int length, out string value) internal TdsOperationStatus TryReadStringWithEncoding(int length, System.Text.Encoding encoding, bool isPlp, out string value) { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadStringWithEncoding"); // you need to setup for a thread abort somewhere before you call this method Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async"); if (encoding == null) @@ -1992,8 +1982,6 @@ internal TdsOperationStatus TrySkipBytes(int num) internal TdsOperationStatus TryReadNetworkPacket() { - TdsParser.ReliabilitySection.Assert("unreliable call to TryReadNetworkPacket"); // you need to setup for a thread abort somewhere before you call this method - #if DEBUG Debug.Assert(!_shouldHaveEnoughData || _attentionSent, "Caller said there should be enough data, but we are currently reading a packet"); #endif @@ -2077,8 +2065,6 @@ internal void ReadSniSyncOverAsync() bool shouldDecrement = false; try { - TdsParser.ReliabilitySection.Assert("unreliable call to ReadSniSync"); // you need to setup for a thread abort somewhere before you call this method - Interlocked.Increment(ref _readingCount); shouldDecrement = true; @@ -2499,8 +2485,6 @@ internal bool IsConnectionAlive(bool throwOnException) } else { - TdsParser.ReliabilitySection.Assert("unreliable call to IsConnectionAlive"); // you need to setup for a thread abort somewhere before you call this method - SniContext = SniContext.Snix_Connect; uint error = CheckConnection();