Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / OleDbTransaction.cs
blob14881edbcff5e09a942a547d173934c59be2b387
1 //------------------------------------------------------------------------------
2 // <copyright file="OleDbTransaction.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data.OleDb {
11 using System.Data;
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();
41 try { } finally {
42 hr = transaction.StartTransaction(isolevel, 0, IntPtr.Zero, out transactionLevel);
43 if (0 <= hr) {
44 _mustComplete = true;
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");
56 OleDbHResult hr;
57 bool mustRelease = false;
58 RuntimeHelpers.PrepareConstrainedRegions();
59 try {
60 DangerousAddRef(ref mustRelease);
62 Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB> handle=%p\n", base.handle);
63 RuntimeHelpers.PrepareConstrainedRegions();
64 try { } finally {
65 hr = (OleDbHResult)NativeOledbWrapper.ITransactionAbort(DangerousGetHandle());
66 _mustComplete = false;
68 Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|RET> %08X{HRESULT}\n", hr);
70 finally {
71 if (mustRelease) {
72 DangerousRelease();
75 return hr;
78 internal OleDbHResult Commit() {
79 Debug.Assert(_mustComplete, "transaction already completed");
80 OleDbHResult hr;
81 bool mustRelease = false;
82 RuntimeHelpers.PrepareConstrainedRegions();
83 try {
84 DangerousAddRef(ref mustRelease);
86 Bid.Trace("<oledb.ITransactionLocal.Commit|API|OLEDB> handle=%p\n", base.handle);
87 RuntimeHelpers.PrepareConstrainedRegions();
88 try { } finally {
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);
96 finally {
97 if (mustRelease) {
98 DangerousRelease();
101 return 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;
121 switch(isolevel) {
122 case IsolationLevel.Unspecified: // OLE DB doesn't support this isolevel on local transactions
123 isolevel = IsolationLevel.ReadCommitted;
124 break;
125 case IsolationLevel.Chaos:
126 case IsolationLevel.ReadUncommitted:
127 case IsolationLevel.ReadCommitted:
128 case IsolationLevel.RepeatableRead:
129 case IsolationLevel.Serializable:
130 case IsolationLevel.Snapshot:
131 break;
132 default:
133 throw ADP.InvalidIsolationLevel(isolevel); // MDAC 74269
135 _isolationLevel = isolevel;
138 new public OleDbConnection Connection { // MDAC 66655
139 get {
140 return _parentConnection;
144 override protected DbConnection DbConnection {
145 get {
146 return Connection;
150 override public IsolationLevel IsolationLevel {
151 get {
152 if (null == _transaction) {
153 throw ADP.TransactionZombied(this);
155 return _isolationLevel;
159 internal int ObjectID {
160 get {
161 return _objectID;
165 internal OleDbTransaction Parent {
166 get {
167 return _parentTransaction;
171 public OleDbTransaction Begin(IsolationLevel isolevel) {
172 OleDbConnection.ExecutePermission.Demand(); // MDAC 81476
174 IntPtr hscp;
175 Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Begin|API> %d#, isolevel=%d{IsolationLevel}", ObjectID, (int)isolevel);
176 try {
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;
189 try {
190 wrapper = (UnsafeNativeMethods.ITransactionLocal)_transaction.ComWrapper();
191 transaction.BeginInternal(wrapper);
193 finally {
194 if (null != wrapper) {
195 Marshal.ReleaseComObject(wrapper);
198 return transaction;
200 finally {
201 Bid.ScopeLeave(ref hscp);
205 public OleDbTransaction Begin() {
206 return Begin(IsolationLevel.ReadCommitted);
209 internal void BeginInternal(UnsafeNativeMethods.ITransactionLocal transaction) {
210 OleDbHResult hr;
211 _transaction = new WrappedTransaction(transaction, (int) _isolationLevel, out hr);
212 if (hr < 0) {
213 _transaction.Dispose();
214 _transaction = null;
215 ProcessResults(hr);
219 override public void Commit() {
220 OleDbConnection.ExecutePermission.Demand(); // MDAC 81476
222 IntPtr hscp;
223 Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Commit|API> %d#", ObjectID);
224 try {
225 if (null == _transaction) {
226 throw ADP.TransactionZombied(this);
228 CommitInternal();
230 finally {
231 Bid.ScopeLeave(ref hscp);
235 private void CommitInternal() {
236 if (null == _transaction) {
237 return;
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();
249 _transaction = null;
251 DisposeManaged();
253 if (hr < 0) {
254 // if an exception is thrown, user can try to commit their transaction again
255 ProcessResults(hr);
259 /*public OleDbCommand CreateCommand() { // MDAC 68309
260 OleDbCommand cmd = Connection.CreateCommand();
261 cmd.Transaction = this;
262 return cmd;
265 IDbCommand IDbTransaction.CreateCommand() {
266 return CreateCommand();
269 protected override void Dispose(bool disposing) {
270 if (disposing) {
271 DisposeManaged();
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() {
294 IntPtr hscp;
295 Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Rollback|API> %d#", ObjectID);
296 try {
297 if (null == _transaction) {
298 throw ADP.TransactionZombied(this);
300 DisposeManaged();
301 RollbackInternal(true); // no recover if this throws an exception
303 finally {
304 Bid.ScopeLeave(ref hscp);
308 /*protected virtual*/internal OleDbHResult RollbackInternal(bool exceptionHandling) {
309 OleDbHResult hr = 0;
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();
317 return hr;
320 _nestedTransaction = null;
322 hr = _transaction.Abort();
323 _transaction.Dispose();
324 _transaction = null;
325 if (hr < 0) {
326 if (exceptionHandling) {
327 ProcessResults(hr);
329 else {
330 SafeNativeMethods.Wrapper.ClearErrorInfo();
334 return hr;
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);
344 return head;
347 static internal OleDbTransaction TransactionUpdate(OleDbTransaction transaction) {
348 if ((null != transaction) && (null == transaction._transaction)) {
349 return null;
351 return transaction;