internal Task WriteBulkCopyDone(TdsParserStateObject stateObj) { // Write DONE packet // if (!(State == TdsParserState.OpenNotLoggedIn || State == TdsParserState.OpenLoggedIn)) { throw ADP.ClosedConnectionError(); } stateObj.WriteByte(TdsEnums.SQLDONE); WriteShort(0, stateObj); WriteShort(0, stateObj); WriteInt(0, stateObj); stateObj._pendingData = true; stateObj._messageStatus = 0; return stateObj.WritePacket(TdsEnums.HARDFLUSH); }
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(); } } }
internal void WriteByteArray(byte[] b, int len, int offsetBuffer, TdsParserStateObject stateObj) { int srcOffset = offsetBuffer; while (len > 0) { if ((stateObj._outBytesUsed + len) > stateObj._outBuff.Length) { int count = stateObj._outBuff.Length - stateObj._outBytesUsed; Buffer.BlockCopy(b, srcOffset, stateObj._outBuff, stateObj._outBytesUsed, count); srcOffset += count; stateObj._outBytesUsed += count; if (stateObj._outBytesUsed == stateObj._outBuff.Length) { stateObj.WritePacket(0); } len -= count; } else { Buffer.BlockCopy(b, srcOffset, stateObj._outBuff, stateObj._outBytesUsed, len); stateObj._outBytesUsed += len; return; } } }
internal void WriteByte(byte b, TdsParserStateObject stateObj) { if (stateObj._outBytesUsed == stateObj._outBuff.Length) { stateObj.WritePacket(0); } stateObj._outBuff[stateObj._outBytesUsed++] = b; }
internal void WriteBulkCopyDone(TdsParserStateObject stateObj) { this.WriteByte(0xfd, stateObj); this.WriteShort(0, stateObj); this.WriteShort(0, stateObj); this.WriteInt(0, stateObj); stateObj.WritePacket(1); stateObj._pendingData = true; }
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; }