Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Data / System / Data / SqlClient / SqlInternalConnectionSmi.cs / 1 / 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
- StringFunctions.cs
- EntityContainerAssociationSet.cs
- login.cs
- CheckBoxList.cs
- QilPatternFactory.cs
- SqlClientMetaDataCollectionNames.cs
- XmlDictionaryReaderQuotas.cs
- CollectionBuilder.cs
- CacheModeValueSerializer.cs
- SqlProfileProvider.cs
- IRCollection.cs
- AuthenticatingEventArgs.cs
- ReadOnlyDataSource.cs
- translator.cs
- ActivityValidator.cs
- CrossAppDomainChannel.cs
- SQLMembershipProvider.cs
- Operand.cs
- CategoryAttribute.cs
- MarkupCompilePass2.cs
- XmlRawWriterWrapper.cs
- UnaryNode.cs
- Rule.cs
- RelationshipDetailsCollection.cs
- IImplicitResourceProvider.cs
- DesignerSerializerAttribute.cs
- Comparer.cs
- PostBackTrigger.cs
- CacheRequest.cs
- formatter.cs
- WebPartTransformerCollection.cs
- FullTextState.cs
- PanelDesigner.cs
- WebPartZoneBase.cs
- FormViewUpdateEventArgs.cs
- WbemException.cs
- XsltCompileContext.cs
- FileSystemEventArgs.cs
- TextEvent.cs
- ApplicationSecurityManager.cs
- Point3DAnimationBase.cs
- WCFServiceClientProxyGenerator.cs
- UnauthorizedWebPart.cs
- HttpCachePolicy.cs
- HostUtils.cs
- BindStream.cs
- SmtpAuthenticationManager.cs
- ColorContextHelper.cs
- XmlSchemaGroupRef.cs
- LayoutSettings.cs
- EtwTrace.cs
- RunInstallerAttribute.cs
- X509Certificate2.cs
- Bits.cs
- QueryableFilterUserControl.cs
- DropDownList.cs
- HtmlToClrEventProxy.cs
- SmtpLoginAuthenticationModule.cs
- WebPartDisplayModeCollection.cs
- EventLogger.cs
- MessageQueueAccessControlEntry.cs
- ComponentManagerBroker.cs
- RegisteredHiddenField.cs
- Paragraph.cs
- updatecommandorderer.cs
- SqlUserDefinedTypeAttribute.cs
- DrawListViewSubItemEventArgs.cs
- ImageSourceTypeConverter.cs
- DecimalConverter.cs
- BackoffTimeoutHelper.cs
- WindowsScroll.cs
- EditorOptionAttribute.cs
- ConfigXmlAttribute.cs
- Debug.cs
- Missing.cs
- PagerSettings.cs
- NativeMethods.cs
- XLinq.cs
- OpenTypeCommon.cs
- GridEntry.cs
- RadioButton.cs
- FloaterBaseParaClient.cs
- SqlBinder.cs
- SqlTriggerAttribute.cs
- Deserializer.cs
- WorkflowOwnershipException.cs
- CqlLexerHelpers.cs
- BrowserDefinition.cs
- VirtualizedItemPattern.cs
- XmlObjectSerializerWriteContextComplexJson.cs
- VSDExceptions.cs
- ProvidersHelper.cs
- TransformerTypeCollection.cs
- TraceEventCache.cs
- ConfigurationErrorsException.cs
- UnmanagedMemoryStream.cs
- ToolStripPanelRenderEventArgs.cs
- KeyValuePair.cs
- ClientOptions.cs
- FontNamesConverter.cs