| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- //------------------------------------------------------------------------------
- // <copyright file="SqlTransaction.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.SqlClient {
- using System.Data;
- using System.Data.Common;
- using System.Data.ProviderBase;
- using System.Data.Sql;
- using System.Data.SqlTypes;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Threading;
- public sealed class SqlTransaction : DbTransaction {
- private static int _objectTypeCount; // Bid counter
- internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
- internal readonly IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;
- private SqlInternalTransaction _internalTransaction;
- private SqlConnection _connection;
- private bool _isFromAPI;
- internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con,
- IsolationLevel iso, SqlInternalTransaction internalTransaction) {
- SqlConnection.VerifyExecutePermission();
- _isolationLevel = iso;
- _connection = con;
- if (internalTransaction == null) {
- _internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
- }
- else {
- Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!");
- _internalTransaction = internalTransaction;
- _internalTransaction.InitParent(this);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // PROPERTIES
- ////////////////////////////////////////////////////////////////////////////////////////
- new public SqlConnection Connection { // MDAC 66655
- get {
- if (IsZombied) {
- return null;
- }
- else {
- return _connection;
- }
- }
- }
- override protected DbConnection DbConnection {
- get {
- return Connection;
- }
- }
- internal SqlInternalTransaction InternalTransaction {
- get {
- return _internalTransaction;
- }
- }
- override public IsolationLevel IsolationLevel {
- get {
- ZombieCheck();
- return _isolationLevel;
- }
- }
- private bool IsYukonPartialZombie {
- get {
- return (null != _internalTransaction && _internalTransaction.IsCompleted);
- }
- }
- internal bool IsZombied {
- get {
- return (null == _internalTransaction || _internalTransaction.IsCompleted);
- }
- }
- internal int ObjectID {
- get {
- return _objectID;
- }
- }
- internal SqlStatistics Statistics {
- get {
- if (null != _connection) {
- if (_connection.StatisticsEnabled) {
- return _connection.Statistics;
- }
- }
- return null;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // 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);
- }
- }
- 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 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);
- }
- }
- }
- public void Rollback(string transactionName) {
- SqlConnection.ExecutePermission.Demand(); // MDAC 81476
- ZombieCheck();
- SqlStatistics statistics = null;
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d# transactionName='%ls'", 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);
- Bid.ScopeLeave(ref hscp);
- }
- }
- public void Save(string savePointName) {
- SqlConnection.ExecutePermission.Demand(); // MDAC 81476
- ZombieCheck();
-
- SqlStatistics statistics = null;
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Save|API> %d# savePointName='%ls'", 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);
- Bid.ScopeLeave(ref hscp);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // INTERNAL METHODS
- ////////////////////////////////////////////////////////////////////////////////////////
- internal void Zombie() {
- // SQLBUDT #402544 For Yukon, we have to defer "zombification" until
- // we get past the users' next rollback, else we'll
- // throw an exception there that is a breaking change.
- // Of course, if the connection is aready closed,
- // then we're free to zombify...
- SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);
- if (null != internalConnection && internalConnection.IsYukonOrNewer && !_isFromAPI) {
- if (Bid.AdvancedOn) {
- Bid.Trace("<sc.SqlTransaction.Zombie|ADV> %d# yukon deferred zombie\n", ObjectID);
- }
- }
- else {
- _internalTransaction = null; // pre-yukon zombification
- }
-
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // PRIVATE METHODS
- ////////////////////////////////////////////////////////////////////////////////////////
- private void ZombieCheck() {
- // If this transaction has been completed, throw exception since it is unusable.
- if (IsZombied) {
- if (IsYukonPartialZombie) {
- _internalTransaction = null; // yukon zombification
- }
-
- throw ADP.TransactionZombied(this);
- }
- }
- }
- }
|