/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Save/*' /> public void Save(string savePointName) { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; long scopeID = SqlClientEventSource.Log.ScopeEnterEvent("<sc.SqlTransaction.Save|API> {0}# savePointName='{1}'", ObjectID, savePointName); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _internalTransaction.Save(savePointName); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { SqlStatistics.StopTimer(statistics); SqlClientEventSource.Log.ScopeLeaveEvent(scopeID); } }
//////////////////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS //////////////////////////////////////////////////////////////////////////////////////// override public void Commit() { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; IntPtr hscp; Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Commit|API> %d#", ObjectID); Bid.CorrelationTrace("<sc.SqlTransaction.Commit|API|Correlation> ObjectID%d#, ActivityID %ls", ObjectID); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Commit(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { _isFromAPI = false; SqlStatistics.StopTimer(statistics); Bid.ScopeLeave(ref hscp); } }
public void Initialize() { // if we get here, then we know for certain that we're the delegated // transaction. SqlInternalConnection connection = _connection; SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, delegating transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG if (connection.IsEnlistedInTransaction) // defect first { Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, was enlisted, now defecting.\n", ObjectID, connection.ObjectID); connection.EnlistNull(); } _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null); connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true); // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw. if (null == connection.CurrentTransaction) { connection.DoomThisConnection(); throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure); } _active = true; } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } }
static public void DeriveParameters(SqlCommand command) { // MDAC 65927\ SqlConnection.ExecutePermission.Demand(); if (null == command) { throw ADP.ArgumentNull("command"); } TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(command.Connection); command.DeriveParameters(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif } catch (System.OutOfMemoryException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } throw; } catch (System.StackOverflowException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } throw; } catch (System.Threading.ThreadAbortException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } }
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommandBuilder.xml' path='docs/members[@name="SqlCommandBuilder"]/DeriveParameters/*'/> public static void DeriveParameters(SqlCommand command) { #if NETFRAMEWORK SqlConnection.ExecutePermission.Demand(); #endif if (null == command) { throw ADP.ArgumentNull(nameof(command)); } #if NETFRAMEWORK TdsParser bestEffortCleanupTarget = null; #endif RuntimeHelpers.PrepareConstrainedRegions(); try { #if NETFRAMEWORK #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif // DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(command.Connection); #endif // NETFRAMEWORK command.DeriveParameters(); #if NETFRAMEWORK } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif // DEBUG #endif // NETFRAMEWORK } catch (OutOfMemoryException e) { command?.Connection?.Abort(e); throw; } catch (StackOverflowException e) { command?.Connection?.Abort(e); throw; } catch (ThreadAbortException e) { command?.Connection?.Abort(e); #if NETFRAMEWORK SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); #endif throw; } }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/DisposeDisposing/*' /> protected override void Dispose(bool disposing) { if (disposing) { TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); if (!IsZombied && !IsYukonPartialZombie) { _internalTransaction.Dispose(); } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } } base.Dispose(disposing); }
override protected void Deactivate() { SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.Deactivate|ADV> {0} deactivating", ObjectID); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; if (null != referenceCollection) { referenceCollection.Deactivate(); } // Invoke subclass-specific deactivation logic InternalDeactivate(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException) { DoomThisConnection(); throw; } catch (System.StackOverflowException) { DoomThisConnection(); throw; } catch (System.Threading.ThreadAbortException) { DoomThisConnection(); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } catch (Exception e) { // UNDONE - should not be catching all exceptions!!! if (!ADP.IsCatchableExceptionType(e)) { throw; } // if an exception occurred, the inner connection will be // marked as unusable and destroyed upon returning to the // pool DoomThisConnection(); ADP.TraceExceptionWithoutRethrow(e); } }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue SqlClientEventSource.Log.AdvanceTrace("<sc.SqlTransaction.Rollback|ADV> {0}# partial zombie no rollback required", ObjectID); _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; long scopeID = SqlClientEventSource.Log.ScopeEnterEvent("<sc.SqlTransaction.Rollback|API> {0}#", ObjectID); SqlClientEventSource.Log.CorrelationTraceEvent("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID {0}#, ActivityID {1}", ObjectID, ActivityCorrelator.Current.ToString()); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Rollback(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { _isFromAPI = false; SqlStatistics.StopTimer(statistics); SqlClientEventSource.Log.ScopeLeaveEvent(scopeID); } } }
//////////////////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS //////////////////////////////////////////////////////////////////////////////////////// /// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Commit/*' /> override public void Commit() { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; long scopeID = SqlClientEventSource.Log.ScopeEnterEvent("<sc.SqlTransaction.Commit|API> {0}#", ObjectID); SqlClientEventSource.Log.CorrelationTraceEvent("<sc.SqlTransaction.Commit|API|Correlation> ObjectID {0}#, ActivityID {1}", ObjectID, ActivityCorrelator.Current.ToString()); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Commit(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } catch (SqlException e) { // GitHub Issue #130 - When a timeout exception has occurred on transaction completion request, // this connection may not be in reusable state. // We will abort this connection and make sure it does not go back to the pool. var innerException = e.InnerException as Win32Exception; if (innerException != null && innerException.NativeErrorCode == TdsEnums.SNI_WAIT_TIMEOUT) { _connection.Abort(e); } throw; } finally { _isFromAPI = false; SqlStatistics.StopTimer(statistics); SqlClientEventSource.Log.ScopeLeaveEvent(scopeID); } }
// Called by the transaction to initiate commit sequence public void SinglePhaseCommit(SysTx.SinglePhaseEnlistment enlistment) { Debug.Assert(null != enlistment, "null enlistment?"); SqlInternalConnection connection = GetValidConnection(); SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.SinglePhaseCommit|RES|CPOOL> %d#, Connection %d#, committing transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG // If the connection is dooomed, we can be certain that the // transaction will eventually be rolled back, and we shouldn't // attempt to commit it. if (connection.IsConnectionDoomed) { lock (connection) { _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. _connection = null; } enlistment.Aborted(SQL.ConnectionDoomed()); } else { Exception commitException; lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, IsolationLevel.Unspecified, _internalTransaction, true); commitException = null; } catch (SqlException e) { commitException = e; ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); } catch (InvalidOperationException e) { commitException = e; ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } if (commitException != null) { // connection.ExecuteTransaction failed with exception if (_internalTransaction.IsCommitted) { // Even though we got an exception, the transaction // was committed by the server. enlistment.Committed(); } else if (_internalTransaction.IsAborted) { // The transaction was aborted, report that to // SysTx. enlistment.Aborted(commitException); } else { // The transaction is still active, we cannot // know the state of the transaction. enlistment.InDoubt(commitException); } // We eat the exception. This is called on the SysTx // thread, not the applications thread. If we don't // eat the exception an UnhandledException will occur, // causing the process to FailFast. } connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); if (commitException == null) { // connection.ExecuteTransaction succeeded enlistment.Committed(); } } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } }
// Called by transaction to initiate abort sequence public void Rollback(SysTx.SinglePhaseEnlistment enlistment) { Debug.Assert(null != enlistment, "null enlistment?"); SqlInternalConnection connection = GetValidConnection(); SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Rollback|RES|CPOOL> %d#, Connection %d#, aborting transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); _active = false; // set to inactive first, doesn't matter how the execute completes, this transaction is done. _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event // If we haven't already rolled back (or aborted) then tell the SQL Server to roll back if (!_internalTransaction.IsAborted) { connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Rollback, null, IsolationLevel.Unspecified, _internalTransaction, true); } } catch (SqlException e) { ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); // Unlike SinglePhaseCommit, a rollback is a rollback, regardless // of how it happens, so SysTx won't throw an exception, and we // don't want to throw an exception either, because SysTx isn't // handling it and it may create a fail fast scenario. In the end, // there is no way for us to communicate to the consumer that this // failed for more serious reasons than usual. // // This is a bit like "should you throw if Close fails", however, // it only matters when you really need to know. In that case, // we have the tracing that we're doing to fallback on for the // investigation. } catch (InvalidOperationException e) { ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } // it doesn't matter whether the rollback succeeded or not, we presume // that the transaction is aborted, because it will be eventually. connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); enlistment.Aborted(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } }
public Byte[] Promote() { // Operations that might be affected by multi-threaded use MUST be done inside the lock. // Don't read values off of the connection outside the lock unless it doesn't really matter // from an operational standpoint (i.e. logging connection's ObjectID should be fine, // but the PromotedDTCToken can change over calls. so that must be protected). SqlInternalConnection connection = GetValidConnection(); Exception promoteException; byte[] returnValue = null; SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Promote|RES|CPOOL> %d#, Connection %d#, promoting transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Promote, null, IsolationLevel.Unspecified, _internalTransaction, true); returnValue = _connection.PromotedDTCToken; // For Global Transactions, we need to set the Transaction Id since we use a Non-MSDTC Promoter type. if (_connection.IsGlobalTransaction) { if (SysTxForGlobalTransactions.SetDistributedTransactionIdentifier == null) { throw SQL.UnsupportedSysTxForGlobalTransactions(); } if (!_connection.IsGlobalTransactionsEnabledForServer) { throw SQL.GlobalTransactionsNotEnabled(); } SysTxForGlobalTransactions.SetDistributedTransactionIdentifier.Invoke(_atomicTransaction, new object[] { this, GetGlobalTxnIdentifierFromToken() }); } promoteException = null; } catch (SqlException e) { promoteException = e; ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); } catch (InvalidOperationException e) { promoteException = e; ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } if (promoteException != null) { throw SQL.PromotionFailed(promoteException); } return(returnValue); }
override public void EnlistTransaction(SysTx.Transaction transaction) { SqlConnection.VerifyExecutePermission(); ValidateConnectionForExecute(null); // If a connection has a local transaction outstanding and you try // to enlist in a DTC transaction, SQL Server will rollback the // local transaction and then do the enlist (7.0 and 2000). So, if // the user tries to do this, throw. if (HasLocalTransaction) { throw ADP.LocalTransactionPresent(); } if (null != transaction && transaction.Equals(EnlistedTransaction)) { // No-op if this is the current transaction return; } // If a connection is already enlisted in a DTC transaction and you // try to enlist in another one, in 7.0 the existing DTC transaction // would roll back and then the connection would enlist in the new // one. In SQL 2000 & 2005, when you enlist in a DTC transaction // while the connection is already enlisted in a DTC transaction, // the connection simply switches enlistments. Regardless, simply // enlist in the user specified distributed transaction. This // behavior matches OLEDB and ODBC. TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); Enlist(transaction); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { Connection.Abort(e); throw; } catch (System.StackOverflowException e) { Connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { Connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } }
public Byte[] Promote() { // Operations that might be affected by multi-threaded use MUST be done inside the lock. // Don't read values off of the connection outside the lock unless it doesn't really matter // from an operational standpoint (i.e. logging connection's ObjectID should be fine, // but the PromotedDTCToken can change over calls. so that must be protected). SqlInternalConnection connection = GetValidConnection(); Exception promoteException; byte[] returnValue = null; if (null != connection) { SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("<sc.SqlDelegatedTransaction.Promote|RES|CPOOL> {0}, Connection {1}, promoting transaction.", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Promote, null, IsolationLevel.Unspecified, _internalTransaction, true); returnValue = _connection.PromotedDTCToken; // For Global Transactions, we need to set the Transaction Id since we use a Non-MSDTC Promoter type. if (_connection.IsGlobalTransaction) { if (SysTxForGlobalTransactions.SetDistributedTransactionIdentifier == null) { throw SQL.UnsupportedSysTxForGlobalTransactions(); } if (!_connection.IsGlobalTransactionsEnabledForServer) { throw SQL.GlobalTransactionsNotEnabled(); } SysTxForGlobalTransactions.SetDistributedTransactionIdentifier.Invoke(_atomicTransaction, new object[] { this, GetGlobalTxnIdentifierFromToken() }); } promoteException = null; } catch (SqlException e) { promoteException = e; ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); } catch (InvalidOperationException e) { promoteException = e; ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } //Throw exception only if Transaction is still active and not yet aborted. if (promoteException != null) { try { // Safely access Transction status - as it's possible Transaction is not in right state. if (Transaction?.TransactionInformation?.Status == SysTx.TransactionStatus.Aborted) { throw SQL.PromotionFailed(promoteException); } } catch (SysTx.TransactionException te) { SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Promote | RES | CPOOL | Object Id {0}, Client Connection Id {1}, Transaction exception occurred: {2}.", ObjectID, usersConnection?.ClientConnectionId, te.Message); // Throw promote exception if transaction state is unknown. throw SQL.PromotionFailed(promoteException); } } else { // The transaction was aborted externally, since it's already doomed above, we only log the same. SqlClientEventSource.Log.TryTraceEvent("<sc.SqlDelegatedTransaction.Promote|RES|CPOOL> {0}, Connection {1}, aborted during promote.", ObjectID, connection.ObjectID); } } else { // The transaction was aborted externally, doom the connection to make sure it's eventually rolled back and log the same. SqlClientEventSource.Log.TryTraceEvent("<sc.SqlDelegatedTransaction.Promote|RES|CPOOL> {0}, Connection null, aborted before promoting.", ObjectID); } return(returnValue); }
virtual internal SqlTransaction BeginSqlTransaction(IsolationLevel iso, string transactionName, bool shouldReconnect) { SqlStatistics statistics = null; TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); statistics = SqlStatistics.StartTimer(Connection.Statistics); SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ValidateConnectionForExecute(null); if (HasLocalTransactionFromAPI) { throw ADP.ParallelTransactionsNotSupported(Connection); } if (iso == IsolationLevel.Unspecified) { iso = IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. } SqlTransaction transaction = new SqlTransaction(this, Connection, iso, AvailableInternalTransaction); transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); transaction.InternalTransaction.RestoreBrokenConnection = false; return(transaction); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { Connection.Abort(e); throw; } catch (System.StackOverflowException e) { Connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { Connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { SqlStatistics.StopTimer(statistics); } }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/RollbackTransactionName/*' /> public void Rollback(string transactionName) { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; using (TryEventScope.Create("<sc.SqlTransaction.Rollback|API> {0} transactionName='{1}'", ObjectID, transactionName)) { TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Rollback(transactionName); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { _isFromAPI = false; SqlStatistics.StopTimer(statistics); } } }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", ObjectID); } _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; IntPtr hscp; Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d#", ObjectID); Bid.CorrelationTrace("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID); TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Rollback(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { _connection.Abort(e); throw; } catch (System.StackOverflowException e) { _connection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { _connection.Abort(e); SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } finally { _isFromAPI = false; SqlStatistics.StopTimer(statistics); Bid.ScopeLeave(ref hscp); } } }