internal SqlDataReader TdsExecuteTransactionManagerRequest( byte[] buffer, TdsEnums.TransactionManagerRequestType request, string transactionName, TdsEnums.TransactionManagerIsolationLevel isoLevel, int timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj ) { Debug.Assert(this == stateObj.Parser, "different parsers"); if (TdsParserState.Broken == State || TdsParserState.Closed == State) { return null; } // Promote, Commit and Rollback requests for // delegated transactions often happen while there is an open result // set, so we need to handle them by using a different MARS session, // otherwise we'll write on the physical state objects while someone // else is using it. When we don't have MARS enabled, we need to // lock the physical state object to syncronize it's use at least // until we increment the open results count. Once it's been // incremented the delegated transaction requests will fail, so they // won't stomp on anything. Debug.Assert(!_connHandler.ThreadHasParserLockForClose || _connHandler._parserLock.ThreadMayHaveLock(), "Thread claims to have parser lock, but lock is not taken"); bool callerHasConnectionLock = _connHandler.ThreadHasParserLockForClose; // If the thread already claims to have the parser lock, then we will let the caller handle releasing it if (!callerHasConnectionLock) { _connHandler._parserLock.Wait(canReleaseFromAnyThread: false); _connHandler.ThreadHasParserLockForClose = true; } // Capture _asyncWrite (after taking lock) to restore it afterwards bool hadAsyncWrites = _asyncWrite; try { // Temprarily disable async writes _asyncWrite = false; stateObj._outputMessageType = TdsEnums.MT_TRANS; // set message type stateObj.SetTimeoutSeconds(timeout); stateObj.SniContext = SniContext.Snix_Execute; const int marsHeaderSize = 18; // 4 + 2 + 8 + 4 const int totalHeaderLength = 22; // 4 + 4 + 2 + 8 + 4 Debug.Assert(stateObj._outBytesUsed == stateObj._outputHeaderLen, "Output bytes written before total header length"); // Write total header length WriteInt(totalHeaderLength, stateObj); // Write mars header length WriteInt(marsHeaderSize, stateObj); WriteMarsHeaderData(stateObj, _currentTransaction); WriteShort((short)request, stateObj); // write TransactionManager Request type bool returnReader = false; switch (request) { case TdsEnums.TransactionManagerRequestType.Begin: Debug.Assert(null != transaction, "Should have specified an internalTransaction when doing a BeginTransaction request!"); // Only assign the passed in transaction if it is not equal to the current transaction. // And, if it is not equal, the current actually should be null. Anything else // is a unexpected state. The concern here is mainly for the mixed use of // T-SQL and API transactions. // Expected states: // 1) _pendingTransaction = null, _currentTransaction = null, non null transaction // passed in on BeginTransaction API call. // 2) _currentTransaction != null, _pendingTransaction = null, non null transaction // passed in but equivalent to _currentTransaction. // #1 will occur on standard BeginTransactionAPI call. #2 should only occur if // t-sql transaction started followed by a call to SqlConnection.BeginTransaction. // Any other state is unknown. if (_currentTransaction != transaction) { Debug.Assert(_currentTransaction == null || true == _fResetConnection, "We should not have a current Tx at this point"); PendingTransaction = transaction; } stateObj.WriteByte((byte)isoLevel); stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string). WriteString(transactionName, stateObj); break; case TdsEnums.TransactionManagerRequestType.Commit: Debug.Assert(transactionName.Length == 0, "Should not have a transaction name on Commit"); stateObj.WriteByte((byte)0); // No xact name stateObj.WriteByte(0); // No flags Debug.Assert(isoLevel == TdsEnums.TransactionManagerIsolationLevel.Unspecified, "Should not have isolation level other than unspecified on Commit!"); // WriteByte((byte) 0, stateObj); // IsolationLevel // WriteByte((byte) 0, stateObj); // No begin xact name break; case TdsEnums.TransactionManagerRequestType.Rollback: stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string). WriteString(transactionName, stateObj); stateObj.WriteByte(0); // No flags Debug.Assert(isoLevel == TdsEnums.TransactionManagerIsolationLevel.Unspecified, "Should not have isolation level other than unspecified on Commit!"); // WriteByte((byte) 0, stateObj); // IsolationLevel // WriteByte((byte) 0, stateObj); // No begin xact name break; case TdsEnums.TransactionManagerRequestType.Save: stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string). WriteString(transactionName, stateObj); break; default: Debug.Assert(false, "Unexpected TransactionManagerRequest"); break; } Task writeTask = stateObj.WritePacket(TdsEnums.HARDFLUSH); Debug.Assert(writeTask == null, "Writes should not pend when writing sync"); stateObj._pendingData = true; stateObj._messageStatus = 0; SqlDataReader dtcReader = null; stateObj.SniContext = SniContext.Snix_Read; if (returnReader) { dtcReader = new SqlDataReader(null, CommandBehavior.Default); Debug.Assert(this == stateObj.Parser, "different parser"); #if DEBUG // Remove the current owner of stateObj - otherwise we will hit asserts stateObj.Owner = null; #endif dtcReader.Bind(stateObj); // force consumption of metadata _SqlMetaDataSet metaData = dtcReader.MetaData; } else { Run(RunBehavior.UntilDone, null, null, null, stateObj); } return dtcReader; } catch (Exception e) { if (!ADP.IsCatchableExceptionType(e)) { throw; } FailureCleanup(stateObj, e); throw; } finally { // SQLHotfix 50000518 // make sure we don't leave temporary fields set when leaving this function _pendingTransaction = null; _asyncWrite = hadAsyncWrites; if (!callerHasConnectionLock) { _connHandler.ThreadHasParserLockForClose = false; _connHandler._parserLock.Release(); } } }
private void FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, string resetOptionsString) { this.NotifyDependency(); if (runBehavior == RunBehavior.UntilDone) { try { this._stateObj.Parser.Run(RunBehavior.UntilDone, this, ds, null, this._stateObj); } catch (Exception exception2) { if (ADP.IsCatchableExceptionType(exception2)) { if (this._inPrepare) { this._inPrepare = false; this.IsDirty = true; this._execType = EXECTYPE.PREPAREPENDING; } if (ds != null) { ds.Close(); } } throw; } } if (ds != null) { ds.Bind(this._stateObj); this._stateObj = null; ds.ResetOptionsString = resetOptionsString; this._activeConnection.AddWeakReference(ds, 1); try { this._cachedMetaData = ds.MetaData; ds.IsInitialized = true; } catch (Exception exception) { if (ADP.IsCatchableExceptionType(exception)) { if (this._inPrepare) { this._inPrepare = false; this.IsDirty = true; this._execType = EXECTYPE.PREPAREPENDING; } ds.Close(); } throw; } } }
private SqlDataReader InternalPrepare(CommandBehavior behavior) { SqlDataReader dataStream = null; if (this.IsDirty) { this.Unprepare(false); this.IsDirty = false; } if (this._activeConnection.IsShiloh) { this._execType = EXECTYPE.PREPAREPENDING; } else { this.BuildPrepare(behavior); this._inPrepare = true; dataStream = new SqlDataReader(this, behavior); try { this._stateObj.Parser.TdsExecuteRPC(this._rpcArrayOf1, this.CommandTimeout, false, null, this._stateObj, System.Data.CommandType.StoredProcedure == this.CommandType); this._stateObj.Parser.Run(RunBehavior.UntilDone, this, dataStream, null, this._stateObj); } catch { this._inPrepare = false; throw; } dataStream.Bind(this._stateObj); this._execType = EXECTYPE.PREPARED; Bid.Trace("<sc.SqlCommand.Prepare|INFO> %d#, Command prepared.\n", this.ObjectID); } if (this.Statistics != null) { this.Statistics.SafeIncrement(ref this.Statistics._prepares); } this._activeConnection.AddPreparedCommand(this); return dataStream; }
internal SqlDataReader TdsExecuteTransactionManagerRequest(byte[] buffer, TdsEnums.TransactionManagerRequestType request, string transactionName, TdsEnums.TransactionManagerIsolationLevel isoLevel, int timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, bool isDelegateControlRequest) { SqlDataReader reader2; if ((TdsParserState.Broken == this.State) || (this.State == TdsParserState.Closed)) { return null; } bool lockTaken = false; lock (this._connHandler) { try { try { if (this._isYukon && !this.MARSOn) { Monitor.Enter(this._physicalStateObj, ref lockTaken); } if (!isDelegateControlRequest) { this._connHandler.CheckEnlistedTransactionBinding(); } stateObj._outputMessageType = 14; stateObj.SetTimeoutSeconds(timeout); stateObj.SniContext = SniContext.Snix_Execute; if (this._isYukon) { this.WriteMarsHeader(stateObj, this._currentTransaction); } this.WriteShort((short) request, stateObj); bool flag = false; switch (request) { case TdsEnums.TransactionManagerRequestType.GetDTCAddress: this.WriteShort(0, stateObj); flag = true; goto Label_0193; case TdsEnums.TransactionManagerRequestType.Propagate: if (buffer == null) { break; } this.WriteShort(buffer.Length, stateObj); this.WriteByteArray(buffer, buffer.Length, 0, stateObj); goto Label_0193; case TdsEnums.TransactionManagerRequestType.Begin: if (this._currentTransaction != transaction) { this.PendingTransaction = transaction; } this.WriteByte((byte) isoLevel, stateObj); this.WriteByte((byte) (transactionName.Length * 2), stateObj); this.WriteString(transactionName, stateObj); goto Label_0193; case TdsEnums.TransactionManagerRequestType.Commit: this.WriteByte(0, stateObj); this.WriteByte(0, stateObj); goto Label_0193; case TdsEnums.TransactionManagerRequestType.Rollback: this.WriteByte((byte) (transactionName.Length * 2), stateObj); this.WriteString(transactionName, stateObj); this.WriteByte(0, stateObj); goto Label_0193; case TdsEnums.TransactionManagerRequestType.Save: this.WriteByte((byte) (transactionName.Length * 2), stateObj); this.WriteString(transactionName, stateObj); goto Label_0193; default: goto Label_0193; } this.WriteShort(0, stateObj); Label_0193: stateObj.WritePacket(1); stateObj._pendingData = true; SqlDataReader reader = null; stateObj.SniContext = SniContext.Snix_Read; if (flag) { reader = new SqlDataReader(null, CommandBehavior.Default); reader.Bind(stateObj); _SqlMetaDataSet metaData = reader.MetaData; } else { this.Run(RunBehavior.UntilDone, null, null, null, stateObj); } if ((request == TdsEnums.TransactionManagerRequestType.Begin) || (request == TdsEnums.TransactionManagerRequestType.Propagate)) { if ((transaction != null) && (transaction.TransactionId == this._retainedTransactionId)) { return reader; } this._retainedTransactionId = 0L; } return reader; } catch (Exception exception) { if (!ADP.IsCatchableExceptionType(exception)) { throw; } this.FailureCleanup(stateObj, exception); throw; } return reader2; } finally { this._pendingTransaction = null; if (lockTaken) { Monitor.Exit(this._physicalStateObj); } } } return reader2; }