You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,354 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OleDbTransaction.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.OleDb {
|
||||
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
public sealed class OleDbTransaction : DbTransaction {
|
||||
|
||||
private readonly OleDbTransaction _parentTransaction; // strong reference to keep parent alive
|
||||
private readonly System.Data.IsolationLevel _isolationLevel;
|
||||
|
||||
private WeakReference _nestedTransaction; // child transactions
|
||||
private WrappedTransaction _transaction;
|
||||
|
||||
internal OleDbConnection _parentConnection;
|
||||
|
||||
private static int _objectTypeCount; // Bid counter
|
||||
internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
|
||||
|
||||
private sealed class WrappedTransaction : WrappedIUnknown {
|
||||
|
||||
private bool _mustComplete;
|
||||
|
||||
internal WrappedTransaction(UnsafeNativeMethods.ITransactionLocal transaction, int isolevel, out OleDbHResult hr) : base(transaction) {
|
||||
int transactionLevel = 0;
|
||||
Bid.Trace("<oledb.ITransactionLocal.StartTransaction|API|OLEDB>\n");
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
hr = transaction.StartTransaction(isolevel, 0, IntPtr.Zero, out transactionLevel);
|
||||
if (0 <= hr) {
|
||||
_mustComplete = true;
|
||||
}
|
||||
}
|
||||
Bid.Trace("<oledb.ITransactionLocal.StartTransaction|API|OLEDB|RET> %08X{HRESULT}\n", hr);
|
||||
}
|
||||
|
||||
internal bool MustComplete {
|
||||
get { return _mustComplete; }
|
||||
}
|
||||
|
||||
internal OleDbHResult Abort() {
|
||||
Debug.Assert(_mustComplete, "transaction already completed");
|
||||
OleDbHResult hr;
|
||||
bool mustRelease = false;
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
DangerousAddRef(ref mustRelease);
|
||||
|
||||
Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB> handle=%p\n", base.handle);
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
hr = (OleDbHResult)NativeOledbWrapper.ITransactionAbort(DangerousGetHandle());
|
||||
_mustComplete = false;
|
||||
}
|
||||
Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|RET> %08X{HRESULT}\n", hr);
|
||||
}
|
||||
finally {
|
||||
if (mustRelease) {
|
||||
DangerousRelease();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
internal OleDbHResult Commit() {
|
||||
Debug.Assert(_mustComplete, "transaction already completed");
|
||||
OleDbHResult hr;
|
||||
bool mustRelease = false;
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
DangerousAddRef(ref mustRelease);
|
||||
|
||||
Bid.Trace("<oledb.ITransactionLocal.Commit|API|OLEDB> handle=%p\n", base.handle);
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
hr = (OleDbHResult)NativeOledbWrapper.ITransactionCommit(DangerousGetHandle());
|
||||
if ((0 <= (int)hr) || (OleDbHResult.XACT_E_NOTRANSACTION == hr)) {
|
||||
_mustComplete = false;
|
||||
}
|
||||
}
|
||||
Bid.Trace("<oledb.ITransactionLocal.Commit|API|OLEDB|RET> %08X{HRESULT}\n", hr);
|
||||
}
|
||||
finally {
|
||||
if (mustRelease) {
|
||||
DangerousRelease();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
override protected bool ReleaseHandle() {
|
||||
if (_mustComplete && (IntPtr.Zero != base.handle)) {
|
||||
Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|INFO> handle=%p\n", base.handle);
|
||||
OleDbHResult hr = (OleDbHResult)NativeOledbWrapper.ITransactionAbort(base.handle);
|
||||
_mustComplete = false;
|
||||
Bid.Trace("<oledb.ITransactionLocal.Abort|API|OLEDB|INFO|RET> %08X{HRESULT}\n", hr);
|
||||
}
|
||||
return base.ReleaseHandle();
|
||||
}
|
||||
}
|
||||
|
||||
internal OleDbTransaction(OleDbConnection connection, OleDbTransaction transaction, IsolationLevel isolevel) {
|
||||
OleDbConnection.VerifyExecutePermission();
|
||||
|
||||
_parentConnection = connection;
|
||||
_parentTransaction = transaction;
|
||||
|
||||
switch(isolevel) {
|
||||
case IsolationLevel.Unspecified: // OLE DB doesn't support this isolevel on local transactions
|
||||
isolevel = IsolationLevel.ReadCommitted;
|
||||
break;
|
||||
case IsolationLevel.Chaos:
|
||||
case IsolationLevel.ReadUncommitted:
|
||||
case IsolationLevel.ReadCommitted:
|
||||
case IsolationLevel.RepeatableRead:
|
||||
case IsolationLevel.Serializable:
|
||||
case IsolationLevel.Snapshot:
|
||||
break;
|
||||
default:
|
||||
throw ADP.InvalidIsolationLevel(isolevel); // MDAC 74269
|
||||
}
|
||||
_isolationLevel = isolevel;
|
||||
}
|
||||
|
||||
new public OleDbConnection Connection { // MDAC 66655
|
||||
get {
|
||||
return _parentConnection;
|
||||
}
|
||||
}
|
||||
|
||||
override protected DbConnection DbConnection {
|
||||
get {
|
||||
return Connection;
|
||||
}
|
||||
}
|
||||
|
||||
override public IsolationLevel IsolationLevel {
|
||||
get {
|
||||
if (null == _transaction) {
|
||||
throw ADP.TransactionZombied(this);
|
||||
}
|
||||
return _isolationLevel;
|
||||
}
|
||||
}
|
||||
|
||||
internal int ObjectID {
|
||||
get {
|
||||
return _objectID;
|
||||
}
|
||||
}
|
||||
|
||||
internal OleDbTransaction Parent {
|
||||
get {
|
||||
return _parentTransaction;
|
||||
}
|
||||
}
|
||||
|
||||
public OleDbTransaction Begin(IsolationLevel isolevel) {
|
||||
OleDbConnection.ExecutePermission.Demand(); // MDAC 81476
|
||||
|
||||
IntPtr hscp;
|
||||
Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Begin|API> %d#, isolevel=%d{IsolationLevel}", ObjectID, (int)isolevel);
|
||||
try {
|
||||
if (null == _transaction) {
|
||||
throw ADP.TransactionZombied(this);
|
||||
}
|
||||
else if ((null != _nestedTransaction) && _nestedTransaction.IsAlive) {
|
||||
throw ADP.ParallelTransactionsNotSupported(Connection);
|
||||
}
|
||||
// either the connection will be open or this will be a zombie
|
||||
|
||||
OleDbTransaction transaction = new OleDbTransaction(_parentConnection, this, isolevel);
|
||||
_nestedTransaction = new WeakReference(transaction, false);
|
||||
|
||||
UnsafeNativeMethods.ITransactionLocal wrapper = null;
|
||||
try {
|
||||
wrapper = (UnsafeNativeMethods.ITransactionLocal)_transaction.ComWrapper();
|
||||
transaction.BeginInternal(wrapper);
|
||||
}
|
||||
finally {
|
||||
if (null != wrapper) {
|
||||
Marshal.ReleaseComObject(wrapper);
|
||||
}
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
finally {
|
||||
Bid.ScopeLeave(ref hscp);
|
||||
}
|
||||
}
|
||||
|
||||
public OleDbTransaction Begin() {
|
||||
return Begin(IsolationLevel.ReadCommitted);
|
||||
}
|
||||
|
||||
internal void BeginInternal(UnsafeNativeMethods.ITransactionLocal transaction) {
|
||||
OleDbHResult hr;
|
||||
_transaction = new WrappedTransaction(transaction, (int) _isolationLevel, out hr);
|
||||
if (hr < 0) {
|
||||
_transaction.Dispose();
|
||||
_transaction = null;
|
||||
ProcessResults(hr);
|
||||
}
|
||||
}
|
||||
|
||||
override public void Commit() {
|
||||
OleDbConnection.ExecutePermission.Demand(); // MDAC 81476
|
||||
|
||||
IntPtr hscp;
|
||||
Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Commit|API> %d#", ObjectID);
|
||||
try {
|
||||
if (null == _transaction) {
|
||||
throw ADP.TransactionZombied(this);
|
||||
}
|
||||
CommitInternal();
|
||||
}
|
||||
finally {
|
||||
Bid.ScopeLeave(ref hscp);
|
||||
}
|
||||
}
|
||||
|
||||
private void CommitInternal() {
|
||||
if (null == _transaction) {
|
||||
return;
|
||||
}
|
||||
if (null != _nestedTransaction) {
|
||||
OleDbTransaction transaction = (OleDbTransaction) _nestedTransaction.Target;
|
||||
if ((null != transaction) && _nestedTransaction.IsAlive) {
|
||||
transaction.CommitInternal();
|
||||
}
|
||||
_nestedTransaction = null;
|
||||
}
|
||||
OleDbHResult hr = _transaction.Commit();
|
||||
if (!_transaction.MustComplete) {
|
||||
_transaction.Dispose();
|
||||
_transaction = null;
|
||||
|
||||
DisposeManaged();
|
||||
}
|
||||
if (hr < 0) {
|
||||
// if an exception is thrown, user can try to commit their transaction again
|
||||
ProcessResults(hr);
|
||||
}
|
||||
}
|
||||
|
||||
/*public OleDbCommand CreateCommand() { // MDAC 68309
|
||||
OleDbCommand cmd = Connection.CreateCommand();
|
||||
cmd.Transaction = this;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
IDbCommand IDbTransaction.CreateCommand() {
|
||||
return CreateCommand();
|
||||
}*/
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
DisposeManaged();
|
||||
RollbackInternal(false);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void DisposeManaged() {
|
||||
if (null != _parentTransaction) {
|
||||
_parentTransaction._nestedTransaction = null;
|
||||
//_parentTransaction = null;
|
||||
}
|
||||
else if (null != _parentConnection) { // MDAC 67287
|
||||
_parentConnection.LocalTransaction = null;
|
||||
}
|
||||
_parentConnection = null;
|
||||
}
|
||||
|
||||
private void ProcessResults(OleDbHResult hr) {
|
||||
Exception e = OleDbConnection.ProcessResults(hr, _parentConnection, this);
|
||||
if (null != e) { throw e; }
|
||||
}
|
||||
|
||||
override public void Rollback() {
|
||||
IntPtr hscp;
|
||||
Bid.ScopeEnter(out hscp, "<oledb.OleDbTransaction.Rollback|API> %d#", ObjectID);
|
||||
try {
|
||||
if (null == _transaction) {
|
||||
throw ADP.TransactionZombied(this);
|
||||
}
|
||||
DisposeManaged();
|
||||
RollbackInternal(true); // no recover if this throws an exception
|
||||
}
|
||||
finally {
|
||||
Bid.ScopeLeave(ref hscp);
|
||||
}
|
||||
}
|
||||
|
||||
/*protected virtual*/internal OleDbHResult RollbackInternal(bool exceptionHandling) {
|
||||
OleDbHResult hr = 0;
|
||||
if (null != _transaction) {
|
||||
if (null != _nestedTransaction) {
|
||||
OleDbTransaction transaction = (OleDbTransaction) _nestedTransaction.Target;
|
||||
if ((null != transaction) && _nestedTransaction.IsAlive) {
|
||||
hr = transaction.RollbackInternal(exceptionHandling);
|
||||
if (exceptionHandling && (hr < 0)) {
|
||||
SafeNativeMethods.Wrapper.ClearErrorInfo();
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
_nestedTransaction = null;
|
||||
}
|
||||
hr = _transaction.Abort();
|
||||
_transaction.Dispose();
|
||||
_transaction = null;
|
||||
if (hr < 0) {
|
||||
if (exceptionHandling) {
|
||||
ProcessResults(hr);
|
||||
}
|
||||
else {
|
||||
SafeNativeMethods.Wrapper.ClearErrorInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static internal OleDbTransaction TransactionLast(OleDbTransaction head) {
|
||||
if (null != head._nestedTransaction) {
|
||||
OleDbTransaction current = (OleDbTransaction) head._nestedTransaction.Target;
|
||||
if ((null != current) && head._nestedTransaction.IsAlive) {
|
||||
return TransactionLast(current);
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
static internal OleDbTransaction TransactionUpdate(OleDbTransaction transaction) {
|
||||
if ((null != transaction) && (null == transaction._transaction)) {
|
||||
return null;
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user