1 //------------------------------------------------------------------------------
2 // <copyright file="OleDbTransaction.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 namespace System
.Data
.OleDb
{
12 using System
.Data
.Common
;
13 using System
.Data
.ProviderBase
;
14 using System
.Diagnostics
;
15 using System
.Runtime
.CompilerServices
;
16 using System
.Runtime
.ConstrainedExecution
;
17 using System
.Runtime
.InteropServices
;
18 using System
.Threading
;
20 public sealed class OleDbTransaction
: DbTransaction
{
22 private readonly OleDbTransaction _parentTransaction
; // strong reference to keep parent alive
23 private readonly System
.Data
.IsolationLevel _isolationLevel
;
25 private WeakReference _nestedTransaction
; // child transactions
26 private WrappedTransaction _transaction
;
28 internal OleDbConnection _parentConnection
;
30 private static int _objectTypeCount
; // Bid counter
31 internal readonly int _objectID
= System
.Threading
.Interlocked
.Increment(ref _objectTypeCount
);
33 private sealed class WrappedTransaction
: WrappedIUnknown
{
35 private bool _mustComplete
;
37 internal WrappedTransaction(UnsafeNativeMethods
.ITransactionLocal transaction
, int isolevel
, out OleDbHResult hr
) : base(transaction
) {
38 int transactionLevel
= 0;
39 Bid
.Trace("<oledb.ITransactionLocal.StartTransaction|API|OLEDB>\n");
40 RuntimeHelpers
.PrepareConstrainedRegions();
42 hr
= transaction
.StartTransaction(isolevel
, 0, IntPtr
.Zero
, out transactionLevel
);
47 Bid
.Trace("<oledb.ITransactionLocal.StartTransaction|API|OLEDB|RET> %08X{HRESULT}\n", hr
);
50 internal bool MustComplete
{
51 get { return _mustComplete; }
54 internal OleDbHResult
Abort() {
55 Debug
.Assert(_mustComplete
, "transaction already completed");
57 bool mustRelease
= false;
58 RuntimeHelpers
.PrepareConstrainedRegions();
60 DangerousAddRef(ref mustRelease
);
62 Bid
.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB> handle=%p\n", base.handle
);
63 RuntimeHelpers
.PrepareConstrainedRegions();
65 hr
= (OleDbHResult
)NativeOledbWrapper
.ITransactionAbort(DangerousGetHandle());
66 _mustComplete
= false;
68 Bid
.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|RET> %08X{HRESULT}\n", hr
);
78 internal OleDbHResult
Commit() {
79 Debug
.Assert(_mustComplete
, "transaction already completed");
81 bool mustRelease
= false;
82 RuntimeHelpers
.PrepareConstrainedRegions();
84 DangerousAddRef(ref mustRelease
);
86 Bid
.Trace("<oledb.ITransactionLocal.Commit|API|OLEDB> handle=%p\n", base.handle
);
87 RuntimeHelpers
.PrepareConstrainedRegions();
89 hr
= (OleDbHResult
)NativeOledbWrapper
.ITransactionCommit(DangerousGetHandle());
90 if ((0 <= (int)hr
) || (OleDbHResult
.XACT_E_NOTRANSACTION
== hr
)) {
91 _mustComplete
= false;
94 Bid
.Trace("<oledb.ITransactionLocal.Commit|API|OLEDB|RET> %08X{HRESULT}\n", hr
);
104 override protected bool ReleaseHandle() {
105 if (_mustComplete
&& (IntPtr
.Zero
!= base.handle
)) {
106 Bid
.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|INFO> handle=%p\n", base.handle
);
107 OleDbHResult hr
= (OleDbHResult
)NativeOledbWrapper
.ITransactionAbort(base.handle
);
108 _mustComplete
= false;
109 Bid
.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|INFO|RET> %08X{HRESULT}\n", hr
);
111 return base.ReleaseHandle();
115 internal OleDbTransaction(OleDbConnection connection
, OleDbTransaction transaction
, IsolationLevel isolevel
) {
116 OleDbConnection
.VerifyExecutePermission();
118 _parentConnection
= connection
;
119 _parentTransaction
= transaction
;
122 case IsolationLevel
.Unspecified
: // OLE DB doesn't support this isolevel on local transactions
123 isolevel
= IsolationLevel
.ReadCommitted
;
125 case IsolationLevel
.Chaos
:
126 case IsolationLevel
.ReadUncommitted
:
127 case IsolationLevel
.ReadCommitted
:
128 case IsolationLevel
.RepeatableRead
:
129 case IsolationLevel
.Serializable
:
130 case IsolationLevel
.Snapshot
:
133 throw ADP
.InvalidIsolationLevel(isolevel
); // MDAC 74269
135 _isolationLevel
= isolevel
;
138 new public OleDbConnection Connection
{ // MDAC 66655
140 return _parentConnection
;
144 override protected DbConnection DbConnection
{
150 override public IsolationLevel IsolationLevel
{
152 if (null == _transaction
) {
153 throw ADP
.TransactionZombied(this);
155 return _isolationLevel
;
159 internal int ObjectID
{
165 internal OleDbTransaction Parent
{
167 return _parentTransaction
;
171 public OleDbTransaction
Begin(IsolationLevel isolevel
) {
172 OleDbConnection
.ExecutePermission
.Demand(); // MDAC 81476
175 Bid
.ScopeEnter(out hscp
, "<oledb.OleDbTransaction.Begin|API> %d#, isolevel=%d{IsolationLevel}", ObjectID
, (int)isolevel
);
177 if (null == _transaction
) {
178 throw ADP
.TransactionZombied(this);
180 else if ((null != _nestedTransaction
) && _nestedTransaction
.IsAlive
) {
181 throw ADP
.ParallelTransactionsNotSupported(Connection
);
183 // either the connection will be open or this will be a zombie
185 OleDbTransaction transaction
= new OleDbTransaction(_parentConnection
, this, isolevel
);
186 _nestedTransaction
= new WeakReference(transaction
, false);
188 UnsafeNativeMethods
.ITransactionLocal wrapper
= null;
190 wrapper
= (UnsafeNativeMethods
.ITransactionLocal
)_transaction
.ComWrapper();
191 transaction
.BeginInternal(wrapper
);
194 if (null != wrapper
) {
195 Marshal
.ReleaseComObject(wrapper
);
201 Bid
.ScopeLeave(ref hscp
);
205 public OleDbTransaction
Begin() {
206 return Begin(IsolationLevel
.ReadCommitted
);
209 internal void BeginInternal(UnsafeNativeMethods
.ITransactionLocal transaction
) {
211 _transaction
= new WrappedTransaction(transaction
, (int) _isolationLevel
, out hr
);
213 _transaction
.Dispose();
219 override public void Commit() {
220 OleDbConnection
.ExecutePermission
.Demand(); // MDAC 81476
223 Bid
.ScopeEnter(out hscp
, "<oledb.OleDbTransaction.Commit|API> %d#", ObjectID
);
225 if (null == _transaction
) {
226 throw ADP
.TransactionZombied(this);
231 Bid
.ScopeLeave(ref hscp
);
235 private void CommitInternal() {
236 if (null == _transaction
) {
239 if (null != _nestedTransaction
) {
240 OleDbTransaction transaction
= (OleDbTransaction
) _nestedTransaction
.Target
;
241 if ((null != transaction
) && _nestedTransaction
.IsAlive
) {
242 transaction
.CommitInternal();
244 _nestedTransaction
= null;
246 OleDbHResult hr
= _transaction
.Commit();
247 if (!_transaction
.MustComplete
) {
248 _transaction
.Dispose();
254 // if an exception is thrown, user can try to commit their transaction again
259 /*public OleDbCommand CreateCommand() { // MDAC 68309
260 OleDbCommand cmd = Connection.CreateCommand();
261 cmd.Transaction = this;
265 IDbCommand IDbTransaction.CreateCommand() {
266 return CreateCommand();
269 protected override void Dispose(bool disposing
) {
272 RollbackInternal(false);
274 base.Dispose(disposing
);
277 private void DisposeManaged() {
278 if (null != _parentTransaction
) {
279 _parentTransaction
._nestedTransaction
= null;
280 //_parentTransaction = null;
282 else if (null != _parentConnection
) { // MDAC 67287
283 _parentConnection
.LocalTransaction
= null;
285 _parentConnection
= null;
288 private void ProcessResults(OleDbHResult hr
) {
289 Exception e
= OleDbConnection
.ProcessResults(hr
, _parentConnection
, this);
290 if (null != e
) { throw e; }
293 override public void Rollback() {
295 Bid
.ScopeEnter(out hscp
, "<oledb.OleDbTransaction.Rollback|API> %d#", ObjectID
);
297 if (null == _transaction
) {
298 throw ADP
.TransactionZombied(this);
301 RollbackInternal(true); // no recover if this throws an exception
304 Bid
.ScopeLeave(ref hscp
);
308 /*protected virtual*/internal OleDbHResult
RollbackInternal(bool exceptionHandling
) {
310 if (null != _transaction
) {
311 if (null != _nestedTransaction
) {
312 OleDbTransaction transaction
= (OleDbTransaction
) _nestedTransaction
.Target
;
313 if ((null != transaction
) && _nestedTransaction
.IsAlive
) {
314 hr
= transaction
.RollbackInternal(exceptionHandling
);
315 if (exceptionHandling
&& (hr
< 0)) {
316 SafeNativeMethods
.Wrapper
.ClearErrorInfo();
320 _nestedTransaction
= null;
322 hr
= _transaction
.Abort();
323 _transaction
.Dispose();
326 if (exceptionHandling
) {
330 SafeNativeMethods
.Wrapper
.ClearErrorInfo();
337 static internal OleDbTransaction
TransactionLast(OleDbTransaction head
) {
338 if (null != head
._nestedTransaction
) {
339 OleDbTransaction current
= (OleDbTransaction
) head
._nestedTransaction
.Target
;
340 if ((null != current
) && head
._nestedTransaction
.IsAlive
) {
341 return TransactionLast(current
);
347 static internal OleDbTransaction
TransactionUpdate(OleDbTransaction transaction
) {
348 if ((null != transaction
) && (null == transaction
._transaction
)) {