Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Data / System / Data / SqlClient / SqlInternalConnectionSmi.cs / 6 / SqlInternalConnectionSmi.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data.SqlClient { using Microsoft.SqlServer.Server; using System.Data; using System.Data.Common; using System.Diagnostics; using SysTx = System.Transactions; sealed internal class SqlInternalConnectionSmi : SqlInternalConnection { private SmiContext _smiContext; private SmiConnection _smiConnection; private SmiEventSink_Default _smiEventSink; private int _isInUse; // 1 = Connected to open outer connection, 0 = not connected private SqlInternalTransaction _pendingTransaction; // transaction awaiting event signalling that it is active private SqlInternalTransaction _currentTransaction; // currently active non-context transaction. sealed private class EventSink : SmiEventSink_Default { SqlInternalConnectionSmi _connection; override internal string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void DispatchMessages(bool ignoreNonFatalMessages) { // Override this on the Connection event sink, since we can deal // with info messages here. SqlException exception = ProcessMessages(false, ignoreNonFatalMessages); if (null != exception) { if (null != _connection.Connection && _connection.Connection.FireInfoMessageEventOnUserErrors) { _connection.Connection.OnInfoMessage(new SqlInfoMessageEventArgs(exception)); } else { _connection.OnError(exception, false); // we can't really ever break the direct connection, can we? } } } internal EventSink(SqlInternalConnectionSmi connection) { Debug.Assert(null != connection, "null connection?"); _connection = connection; } internal override void DefaultDatabaseChanged( string databaseName ) { if (Bid.AdvancedOn) { Bid.Trace("%d#, databaseName='%ls'.\n", _connection.ObjectID, databaseName); } _connection.CurrentDatabase = databaseName; } internal override void TransactionCommitted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Committed); } internal override void TransactionDefected( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Unknown); } internal override void TransactionEnlisted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, true); // distributed; } internal override void TransactionEnded( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEndedByServer(transactionId); } internal override void TransactionRolledBack( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Aborted); } internal override void TransactionStarted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, false); // not distributed; } } internal SqlInternalConnectionSmi(SqlConnectionString connectionOptions, SmiContext smiContext) : base(connectionOptions) { Debug.Assert(null != smiContext, "null smiContext?"); _smiContext = smiContext; _smiContext.OutOfScope += new EventHandler(OnOutOfScope); _smiConnection = _smiContext.ContextConnection; Debug.Assert(null != _smiConnection, "null SmiContext.ContextConnection?"); _smiEventSink = new EventSink(this); if (Bid.AdvancedOn) { Bid.Trace(" %d#, constructed new SMI internal connection\n", ObjectID); } } internal SmiContext InternalContext { get { return _smiContext; } } internal SmiConnection SmiConnection { get { return _smiConnection; } } internal SmiEventSink CurrentEventSink { get { return _smiEventSink; } } override internal SqlInternalTransaction CurrentTransaction { get { return _currentTransaction; } } override internal bool IsLockedForBulkCopy { get { return false; // no bulk copy in the Direct connection case. } } override internal bool IsShiloh { get { return false; // Can't be direct connecting to Shiloh. } } #if WINFSFunctionality override internal bool IsWinFS { get { return false; // } } #endif override internal bool IsYukonOrNewer { get { return true; // Must be direct connecting to Yukon or newer. } } override internal bool IsKatmaiOrNewer { get { return SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion; } } override internal SqlInternalTransaction PendingTransaction { get { return CurrentTransaction; // there are no differences between pending and current in proc. } } override public string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void Activate(SysTx.Transaction transaction) { Debug.Assert(false, "Activating an internal SMI connection?"); // we should never be activating, because that would indicate we're being pooled. } internal void Activate() { int wasInUse = System.Threading.Interlocked.Exchange(ref _isInUse, 1); if (0 != wasInUse) { throw SQL.ContextConnectionIsInUse(); } CurrentDatabase = _smiConnection.GetCurrentDatabase(_smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override internal void AddPreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } internal void AutomaticEnlistment() { SysTx.Transaction currentSystemTransaction = ADP.GetCurrentTransaction(); // NOTE: Must be first to ensure _smiContext.ContextTransaction is set! SysTx.Transaction contextTransaction = _smiContext.ContextTransaction; // returns the transaction that was handed to SysTx that wraps the ContextTransactionId. long contextTransactionId = _smiContext.ContextTransactionId; if (Bid.AdvancedOn) { Bid.Trace(" %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentSystemTransaction) ? currentSystemTransaction.GetHashCode() : 0); } if (SqlInternalTransaction.NullTransactionId != contextTransactionId) { if (null != currentSystemTransaction && contextTransaction != currentSystemTransaction) { throw SQL.NestedTransactionScopesNotSupported(); // can't use TransactionScope(RequiresNew) inside a Sql Transaction. } if (Bid.AdvancedOn) { Bid.Trace(" %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId); } _currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId); ContextTransaction = contextTransaction; } else if (null == currentSystemTransaction) { _currentTransaction = null; // there really isn't a transaction. if (Bid.AdvancedOn) { Bid.Trace(" %d#, no transaction.\n", base.ObjectID); } } else { if (Bid.AdvancedOn) { Bid.Trace(" %d#, using current System.Transaction.\n", base.ObjectID); } base.Enlist(currentSystemTransaction); } } override internal void ClearPreparedCommands() { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override protected void ChangeDatabaseInternal(string database) { _smiConnection.SetCurrentDatabase(database, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override protected void InternalDeactivate() { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Deactivating.\n", base.ObjectID); } // When we put this to bed, we should not hold on to the transaction // or any activity (commit/rollback) may cause it to hang. if (!IsNonPoolableTransactionRoot) { base.Enlist(null); } if (null != _currentTransaction) { if (_currentTransaction.IsContext) { _currentTransaction = null; } else if (_currentTransaction.IsLocal) { _currentTransaction.CloseFromConnection(); } } ContextTransaction = null; _isInUse = 0; // don't need compare-exchange. } override internal void DelegatedTransactionEnded() { base.DelegatedTransactionEnded(); if (Bid.AdvancedOn) { Bid.Trace(" %d#, cleaning up after Delegated Transaction Completion\n", base.ObjectID); } _currentTransaction = null; // clean up our current transaction too } override internal void DisconnectTransaction(SqlInternalTransaction internalTransaction) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Disconnecting Transaction %d#.\n", base.ObjectID, internalTransaction.ObjectID); } // VSTS 215465/15029: allow _currentTransaction to be null - it can be cleared before by server's callback Debug.Assert(_currentTransaction == null || _currentTransaction == internalTransaction, "disconnecting different transaction"); if (_currentTransaction != null && _currentTransaction == internalTransaction) { _currentTransaction = null; } } override public void Dispose() { _smiContext.OutOfScope -= new EventHandler(OnOutOfScope); base.Dispose(); } override internal void ExecuteTransaction(TransactionRequest transactionRequest, string transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionRequest=%s, transactionName='%ls', isolationLevel=%s, internalTransaction=#%d transactionId=0x%I64x.\n", base.ObjectID, transactionRequest.ToString(), (null != transactionName) ? transactionName : "null", iso.ToString(), (null != internalTransaction) ? internalTransaction.ObjectID : 0, (null != internalTransaction) ? internalTransaction.TransactionId : SqlInternalTransaction.NullTransactionId ); } switch (transactionRequest) { case TransactionRequest.Begin: try { _pendingTransaction = internalTransaction; // store this for the time being. _smiConnection.BeginTransaction(transactionName, iso, _smiEventSink); } finally { _pendingTransaction = null; } Debug.Assert(_smiEventSink.HasMessages || null != _currentTransaction, "begin transaction without TransactionStarted event?"); break; case TransactionRequest.Commit: Debug.Assert(null != _currentTransaction, "commit transaction without TransactionStarted event?"); _smiConnection.CommitTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Promote: Debug.Assert(null != _currentTransaction, "promote transaction without TransactionStarted event?"); PromotedDTCToken = _smiConnection.PromoteTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Rollback: case TransactionRequest.IfRollback: Debug.Assert(null != _currentTransaction, "rollback/ifrollback transaction without TransactionStarted event?"); _smiConnection.RollbackTransaction(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; case TransactionRequest.Save: Debug.Assert(null != _currentTransaction, "save transaction without TransactionStarted event?"); _smiConnection.CreateTransactionSavePoint(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; default: Debug.Assert (false, "unhandled case for TransactionRequest"); break; } _smiEventSink.ProcessMessagesAndThrow(); } override protected byte[] GetDTCAddress() { byte[] whereAbouts = _smiConnection.GetDTCAddress(_smiEventSink); // might want to store this on the SmiLink because it doesn't change, but we want to be compatible with TDS which doesn't have a link yet. _smiEventSink.ProcessMessagesAndThrow(); if (Bid.AdvancedOn) { if (null != whereAbouts) { Bid.TraceBin(" whereAbouts", whereAbouts, (UInt16)whereAbouts.Length); } else { Bid.Trace(" whereAbouts=null\n"); } } return whereAbouts; } internal void GetCurrentTransactionPair(out long transactionId, out SysTx.Transaction transaction) { // SQLBU 214740: Transaction state could change between obtaining tranid and transaction // due to background SqlDelegatedTransaction processing. Lock the connection to prevent that. lock (this) { transactionId = (null != CurrentTransaction) ? CurrentTransaction.TransactionId : 0; transaction = null; if (0 != transactionId) { transaction = InternalEnlistedTransaction; } } } private void OnOutOfScope(object s, EventArgs e) { // Called whenever the context goes out of scope, we need to make // sure that we close the connection, or the next person that uses // the context may appear to have the connection in use. if (Bid.AdvancedOn) { Bid.Trace(" %d# context is out of scope\n", base.ObjectID); } // DelegatedTransaction = null; // we don't want to hold this over to the next usage; it will automatically be reused as the context transaction... DbConnection owningObject = (DbConnection)Owner; try { if (null != owningObject && 1 == _isInUse) { // SQLBU 369953 // for various reasons, the owning object may no longer be connection to this // so call close on the owner, rather than trying to bypass to use internal close logic. owningObject.Close(); } } finally { // Now make sure this object is not left in an in-use state // this is safe, because no user code should be accessing the connection by this time ContextTransaction = null; _isInUse = 0; } } override protected void PropagateTransactionCookie(byte[] transactionCookie) { if (Bid.AdvancedOn) { if (null != transactionCookie) { Bid.TraceBin(" transactionCookie", transactionCookie, (UInt16)transactionCookie.Length); } else { Bid.Trace(" null\n"); } } // Propagate the transaction cookie to the server _smiConnection.EnlistTransaction(transactionCookie, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } private void TransactionEndedByServer(long transactionId) { // Some extra steps required when the server initiates the ending of a transaction unilaterally // as opposed to the client initiating it. // Basically, we have to make the delegated transaction (if there is one) aware of the situation. SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction; if (null != delegatedTransaction) { delegatedTransaction.Transaction.Rollback(); // just to make sure... DelegatedTransaction = null; // He's dead, Jim. } // Now handle the standard transaction-ended stuff. // TransactionEnded(transactionId, TransactionState.Unknown); } private void TransactionEnded(long transactionId, TransactionState transactionState) { // When we get notification of a completed transaction // we null out the current transaction. if (null != _currentTransaction) { #if DEBUG // Check null for case where Begin and Rollback obtained in the same message. if (0 != _currentTransaction.TransactionId) { Debug.Assert(_currentTransaction.TransactionId == transactionId, "transaction id's are not equal!"); } #endif _currentTransaction.Completed(transactionState); _currentTransaction = null; } } private void TransactionStarted(long transactionId, bool isDistributed) { // When we get notification from the server of a new // transaction, we move any pending transaction over to // the current transaction, then we store the token in it. // if there isn't a pending transaction, then it's either // a TSQL transaction or a distributed transaction. Debug.Assert(null == _currentTransaction, "non-null current transaction with an env change"); _currentTransaction = _pendingTransaction; _pendingTransaction = null; if (null != _currentTransaction) { _currentTransaction.TransactionId = transactionId; // this is defined as a ULongLong in the server and in the TDS Spec. } else { TransactionType transactionType = (isDistributed) ? TransactionType.Distributed : TransactionType.LocalFromTSQL; _currentTransaction = new SqlInternalTransaction(this, transactionType, null, transactionId); } _currentTransaction.Activate(); // SQLBUDT #376531 -- ensure this is activated to prevent asserts later. } override internal void RemovePreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override internal void ValidateConnectionForExecute(SqlCommand command) { SqlDataReader reader = FindLiveReader(null); if (null != reader) { // if MARS is on, then a datareader associated with the command exists // or if MARS is off, then a datareader exists throw ADP.OpenReaderExists(); // MDAC 66411 } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data.SqlClient { using Microsoft.SqlServer.Server; using System.Data; using System.Data.Common; using System.Diagnostics; using SysTx = System.Transactions; sealed internal class SqlInternalConnectionSmi : SqlInternalConnection { private SmiContext _smiContext; private SmiConnection _smiConnection; private SmiEventSink_Default _smiEventSink; private int _isInUse; // 1 = Connected to open outer connection, 0 = not connected private SqlInternalTransaction _pendingTransaction; // transaction awaiting event signalling that it is active private SqlInternalTransaction _currentTransaction; // currently active non-context transaction. sealed private class EventSink : SmiEventSink_Default { SqlInternalConnectionSmi _connection; override internal string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void DispatchMessages(bool ignoreNonFatalMessages) { // Override this on the Connection event sink, since we can deal // with info messages here. SqlException exception = ProcessMessages(false, ignoreNonFatalMessages); if (null != exception) { if (null != _connection.Connection && _connection.Connection.FireInfoMessageEventOnUserErrors) { _connection.Connection.OnInfoMessage(new SqlInfoMessageEventArgs(exception)); } else { _connection.OnError(exception, false); // we can't really ever break the direct connection, can we? } } } internal EventSink(SqlInternalConnectionSmi connection) { Debug.Assert(null != connection, "null connection?"); _connection = connection; } internal override void DefaultDatabaseChanged( string databaseName ) { if (Bid.AdvancedOn) { Bid.Trace("%d#, databaseName='%ls'.\n", _connection.ObjectID, databaseName); } _connection.CurrentDatabase = databaseName; } internal override void TransactionCommitted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Committed); } internal override void TransactionDefected( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Unknown); } internal override void TransactionEnlisted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, true); // distributed; } internal override void TransactionEnded( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEndedByServer(transactionId); } internal override void TransactionRolledBack( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Aborted); } internal override void TransactionStarted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, false); // not distributed; } } internal SqlInternalConnectionSmi(SqlConnectionString connectionOptions, SmiContext smiContext) : base(connectionOptions) { Debug.Assert(null != smiContext, "null smiContext?"); _smiContext = smiContext; _smiContext.OutOfScope += new EventHandler(OnOutOfScope); _smiConnection = _smiContext.ContextConnection; Debug.Assert(null != _smiConnection, "null SmiContext.ContextConnection?"); _smiEventSink = new EventSink(this); if (Bid.AdvancedOn) { Bid.Trace(" %d#, constructed new SMI internal connection\n", ObjectID); } } internal SmiContext InternalContext { get { return _smiContext; } } internal SmiConnection SmiConnection { get { return _smiConnection; } } internal SmiEventSink CurrentEventSink { get { return _smiEventSink; } } override internal SqlInternalTransaction CurrentTransaction { get { return _currentTransaction; } } override internal bool IsLockedForBulkCopy { get { return false; // no bulk copy in the Direct connection case. } } override internal bool IsShiloh { get { return false; // Can't be direct connecting to Shiloh. } } #if WINFSFunctionality override internal bool IsWinFS { get { return false; // } } #endif override internal bool IsYukonOrNewer { get { return true; // Must be direct connecting to Yukon or newer. } } override internal bool IsKatmaiOrNewer { get { return SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion; } } override internal SqlInternalTransaction PendingTransaction { get { return CurrentTransaction; // there are no differences between pending and current in proc. } } override public string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void Activate(SysTx.Transaction transaction) { Debug.Assert(false, "Activating an internal SMI connection?"); // we should never be activating, because that would indicate we're being pooled. } internal void Activate() { int wasInUse = System.Threading.Interlocked.Exchange(ref _isInUse, 1); if (0 != wasInUse) { throw SQL.ContextConnectionIsInUse(); } CurrentDatabase = _smiConnection.GetCurrentDatabase(_smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override internal void AddPreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } internal void AutomaticEnlistment() { SysTx.Transaction currentSystemTransaction = ADP.GetCurrentTransaction(); // NOTE: Must be first to ensure _smiContext.ContextTransaction is set! SysTx.Transaction contextTransaction = _smiContext.ContextTransaction; // returns the transaction that was handed to SysTx that wraps the ContextTransactionId. long contextTransactionId = _smiContext.ContextTransactionId; if (Bid.AdvancedOn) { Bid.Trace(" %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentSystemTransaction) ? currentSystemTransaction.GetHashCode() : 0); } if (SqlInternalTransaction.NullTransactionId != contextTransactionId) { if (null != currentSystemTransaction && contextTransaction != currentSystemTransaction) { throw SQL.NestedTransactionScopesNotSupported(); // can't use TransactionScope(RequiresNew) inside a Sql Transaction. } if (Bid.AdvancedOn) { Bid.Trace(" %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId); } _currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId); ContextTransaction = contextTransaction; } else if (null == currentSystemTransaction) { _currentTransaction = null; // there really isn't a transaction. if (Bid.AdvancedOn) { Bid.Trace(" %d#, no transaction.\n", base.ObjectID); } } else { if (Bid.AdvancedOn) { Bid.Trace(" %d#, using current System.Transaction.\n", base.ObjectID); } base.Enlist(currentSystemTransaction); } } override internal void ClearPreparedCommands() { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override protected void ChangeDatabaseInternal(string database) { _smiConnection.SetCurrentDatabase(database, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override protected void InternalDeactivate() { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Deactivating.\n", base.ObjectID); } // When we put this to bed, we should not hold on to the transaction // or any activity (commit/rollback) may cause it to hang. if (!IsNonPoolableTransactionRoot) { base.Enlist(null); } if (null != _currentTransaction) { if (_currentTransaction.IsContext) { _currentTransaction = null; } else if (_currentTransaction.IsLocal) { _currentTransaction.CloseFromConnection(); } } ContextTransaction = null; _isInUse = 0; // don't need compare-exchange. } override internal void DelegatedTransactionEnded() { base.DelegatedTransactionEnded(); if (Bid.AdvancedOn) { Bid.Trace(" %d#, cleaning up after Delegated Transaction Completion\n", base.ObjectID); } _currentTransaction = null; // clean up our current transaction too } override internal void DisconnectTransaction(SqlInternalTransaction internalTransaction) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Disconnecting Transaction %d#.\n", base.ObjectID, internalTransaction.ObjectID); } // VSTS 215465/15029: allow _currentTransaction to be null - it can be cleared before by server's callback Debug.Assert(_currentTransaction == null || _currentTransaction == internalTransaction, "disconnecting different transaction"); if (_currentTransaction != null && _currentTransaction == internalTransaction) { _currentTransaction = null; } } override public void Dispose() { _smiContext.OutOfScope -= new EventHandler(OnOutOfScope); base.Dispose(); } override internal void ExecuteTransaction(TransactionRequest transactionRequest, string transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionRequest=%s, transactionName='%ls', isolationLevel=%s, internalTransaction=#%d transactionId=0x%I64x.\n", base.ObjectID, transactionRequest.ToString(), (null != transactionName) ? transactionName : "null", iso.ToString(), (null != internalTransaction) ? internalTransaction.ObjectID : 0, (null != internalTransaction) ? internalTransaction.TransactionId : SqlInternalTransaction.NullTransactionId ); } switch (transactionRequest) { case TransactionRequest.Begin: try { _pendingTransaction = internalTransaction; // store this for the time being. _smiConnection.BeginTransaction(transactionName, iso, _smiEventSink); } finally { _pendingTransaction = null; } Debug.Assert(_smiEventSink.HasMessages || null != _currentTransaction, "begin transaction without TransactionStarted event?"); break; case TransactionRequest.Commit: Debug.Assert(null != _currentTransaction, "commit transaction without TransactionStarted event?"); _smiConnection.CommitTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Promote: Debug.Assert(null != _currentTransaction, "promote transaction without TransactionStarted event?"); PromotedDTCToken = _smiConnection.PromoteTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Rollback: case TransactionRequest.IfRollback: Debug.Assert(null != _currentTransaction, "rollback/ifrollback transaction without TransactionStarted event?"); _smiConnection.RollbackTransaction(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; case TransactionRequest.Save: Debug.Assert(null != _currentTransaction, "save transaction without TransactionStarted event?"); _smiConnection.CreateTransactionSavePoint(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; default: Debug.Assert (false, "unhandled case for TransactionRequest"); break; } _smiEventSink.ProcessMessagesAndThrow(); } override protected byte[] GetDTCAddress() { byte[] whereAbouts = _smiConnection.GetDTCAddress(_smiEventSink); // might want to store this on the SmiLink because it doesn't change, but we want to be compatible with TDS which doesn't have a link yet. _smiEventSink.ProcessMessagesAndThrow(); if (Bid.AdvancedOn) { if (null != whereAbouts) { Bid.TraceBin(" whereAbouts", whereAbouts, (UInt16)whereAbouts.Length); } else { Bid.Trace(" whereAbouts=null\n"); } } return whereAbouts; } internal void GetCurrentTransactionPair(out long transactionId, out SysTx.Transaction transaction) { // SQLBU 214740: Transaction state could change between obtaining tranid and transaction // due to background SqlDelegatedTransaction processing. Lock the connection to prevent that. lock (this) { transactionId = (null != CurrentTransaction) ? CurrentTransaction.TransactionId : 0; transaction = null; if (0 != transactionId) { transaction = InternalEnlistedTransaction; } } } private void OnOutOfScope(object s, EventArgs e) { // Called whenever the context goes out of scope, we need to make // sure that we close the connection, or the next person that uses // the context may appear to have the connection in use. if (Bid.AdvancedOn) { Bid.Trace(" %d# context is out of scope\n", base.ObjectID); } // DelegatedTransaction = null; // we don't want to hold this over to the next usage; it will automatically be reused as the context transaction... DbConnection owningObject = (DbConnection)Owner; try { if (null != owningObject && 1 == _isInUse) { // SQLBU 369953 // for various reasons, the owning object may no longer be connection to this // so call close on the owner, rather than trying to bypass to use internal close logic. owningObject.Close(); } } finally { // Now make sure this object is not left in an in-use state // this is safe, because no user code should be accessing the connection by this time ContextTransaction = null; _isInUse = 0; } } override protected void PropagateTransactionCookie(byte[] transactionCookie) { if (Bid.AdvancedOn) { if (null != transactionCookie) { Bid.TraceBin(" transactionCookie", transactionCookie, (UInt16)transactionCookie.Length); } else { Bid.Trace(" null\n"); } } // Propagate the transaction cookie to the server _smiConnection.EnlistTransaction(transactionCookie, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } private void TransactionEndedByServer(long transactionId) { // Some extra steps required when the server initiates the ending of a transaction unilaterally // as opposed to the client initiating it. // Basically, we have to make the delegated transaction (if there is one) aware of the situation. SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction; if (null != delegatedTransaction) { delegatedTransaction.Transaction.Rollback(); // just to make sure... DelegatedTransaction = null; // He's dead, Jim. } // Now handle the standard transaction-ended stuff. // TransactionEnded(transactionId, TransactionState.Unknown); } private void TransactionEnded(long transactionId, TransactionState transactionState) { // When we get notification of a completed transaction // we null out the current transaction. if (null != _currentTransaction) { #if DEBUG // Check null for case where Begin and Rollback obtained in the same message. if (0 != _currentTransaction.TransactionId) { Debug.Assert(_currentTransaction.TransactionId == transactionId, "transaction id's are not equal!"); } #endif _currentTransaction.Completed(transactionState); _currentTransaction = null; } } private void TransactionStarted(long transactionId, bool isDistributed) { // When we get notification from the server of a new // transaction, we move any pending transaction over to // the current transaction, then we store the token in it. // if there isn't a pending transaction, then it's either // a TSQL transaction or a distributed transaction. Debug.Assert(null == _currentTransaction, "non-null current transaction with an env change"); _currentTransaction = _pendingTransaction; _pendingTransaction = null; if (null != _currentTransaction) { _currentTransaction.TransactionId = transactionId; // this is defined as a ULongLong in the server and in the TDS Spec. } else { TransactionType transactionType = (isDistributed) ? TransactionType.Distributed : TransactionType.LocalFromTSQL; _currentTransaction = new SqlInternalTransaction(this, transactionType, null, transactionId); } _currentTransaction.Activate(); // SQLBUDT #376531 -- ensure this is activated to prevent asserts later. } override internal void RemovePreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override internal void ValidateConnectionForExecute(SqlCommand command) { SqlDataReader reader = FindLiveReader(null); if (null != reader) { // if MARS is on, then a datareader associated with the command exists // or if MARS is off, then a datareader exists throw ADP.OpenReaderExists(); // MDAC 66411 } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MimeBasePart.cs
- ContentPlaceHolder.cs
- AttributeUsageAttribute.cs
- StringValueConverter.cs
- IIS7WorkerRequest.cs
- WindowsGrip.cs
- TextElementCollection.cs
- FixedElement.cs
- UnsafeNativeMethods.cs
- DrawingState.cs
- SurrogateDataContract.cs
- MetadataFile.cs
- GlyphElement.cs
- DataObjectFieldAttribute.cs
- NameValueConfigurationElement.cs
- OleCmdHelper.cs
- CompareInfo.cs
- NumberFormatInfo.cs
- VersionedStream.cs
- SmiRequestExecutor.cs
- ImageSource.cs
- DispatchChannelSink.cs
- ScriptingProfileServiceSection.cs
- PenThread.cs
- PropertyBuilder.cs
- GiveFeedbackEventArgs.cs
- BamlBinaryReader.cs
- Wrapper.cs
- SequenceNumber.cs
- NameNode.cs
- ModuleBuilder.cs
- GregorianCalendar.cs
- PropertyEmitterBase.cs
- TraceRecord.cs
- DataServiceEntityAttribute.cs
- SystemWebCachingSectionGroup.cs
- AssemblyInfo.cs
- MouseButton.cs
- VectorCollectionConverter.cs
- TemplateControlParser.cs
- WebUtil.cs
- ExpressionConverter.cs
- Model3D.cs
- CachedCompositeFamily.cs
- StrokeCollection2.cs
- SymbolType.cs
- MemoryMappedViewAccessor.cs
- Transform.cs
- ItemCollection.cs
- LiteralControl.cs
- SystemKeyConverter.cs
- EndPoint.cs
- NonDualMessageSecurityOverHttpElement.cs
- HtmlImage.cs
- Message.cs
- SafeNativeMethodsMilCoreApi.cs
- TransformationRules.cs
- DataServiceKeyAttribute.cs
- TypeResolvingOptionsAttribute.cs
- nulltextnavigator.cs
- ActiveXContainer.cs
- ExecutedRoutedEventArgs.cs
- IconConverter.cs
- StorageRoot.cs
- BitmapEffect.cs
- TextLineBreak.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- DBBindings.cs
- NewItemsContextMenuStrip.cs
- IdentityReference.cs
- ConstraintStruct.cs
- ExpressionLexer.cs
- SafeProcessHandle.cs
- ServicePoint.cs
- FlowDocument.cs
- IOThreadScheduler.cs
- UserPreferenceChangedEventArgs.cs
- ProgramPublisher.cs
- PropertyGrid.cs
- IndentTextWriter.cs
- EventSinkHelperWriter.cs
- SettingsAttributeDictionary.cs
- SqlUtil.cs
- Point3DCollection.cs
- UserNameSecurityTokenParameters.cs
- FontClient.cs
- fixedPageContentExtractor.cs
- BitmapEffectInputData.cs
- UserPersonalizationStateInfo.cs
- DataBoundControlAdapter.cs
- XmlMtomWriter.cs
- SatelliteContractVersionAttribute.cs
- StateItem.cs
- KernelTypeValidation.cs
- TypeResolver.cs
- ClusterRegistryConfigurationProvider.cs
- PartBasedPackageProperties.cs
- VisualStateGroup.cs
- XmlSchemaAll.cs
- ConstructorNeedsTagAttribute.cs