1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
//------------------------------------------------------------------------------
// <copyright file="OdbcTransaction.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Data;
using System.Data.Common;
using System.Threading;
namespace System.Data.Odbc
{
public sealed class OdbcTransaction : DbTransaction {
private OdbcConnection _connection;
private IsolationLevel _isolevel = IsolationLevel.Unspecified;
private OdbcConnectionHandle _handle;
internal OdbcTransaction(OdbcConnection connection, IsolationLevel isolevel, OdbcConnectionHandle handle) {
OdbcConnection.VerifyExecutePermission();
_connection = connection;
_isolevel = isolevel;
_handle = handle;
}
new public OdbcConnection Connection { // MDAC 66655
get {
return _connection;
}
}
override protected DbConnection DbConnection { // MDAC 66655
get {
return Connection;
}
}
override public IsolationLevel IsolationLevel {
get {
OdbcConnection connection = _connection;
if (null == connection ) {
throw ADP.TransactionZombied(this);
}
//We need to query for the case where the user didn't set the isolevel
//BeginTransaction(), but we should also query to see if the driver
//"rolled" the level to a higher supported one...
if(IsolationLevel.Unspecified == _isolevel) {
//Get the isolation level
int sql_iso= connection .GetConnectAttr(ODBC32.SQL_ATTR.TXN_ISOLATION, ODBC32.HANDLER.THROW);
switch((ODBC32.SQL_TRANSACTION)sql_iso) {
case ODBC32.SQL_TRANSACTION.READ_UNCOMMITTED:
_isolevel = IsolationLevel.ReadUncommitted;
break;
case ODBC32.SQL_TRANSACTION.READ_COMMITTED:
_isolevel = IsolationLevel.ReadCommitted;
break;
case ODBC32.SQL_TRANSACTION.REPEATABLE_READ:
_isolevel = IsolationLevel.RepeatableRead;
break;
case ODBC32.SQL_TRANSACTION.SERIALIZABLE:
_isolevel = IsolationLevel.Serializable;
break;
case ODBC32.SQL_TRANSACTION.SNAPSHOT:
_isolevel = IsolationLevel.Snapshot;
break;
default:
throw ODBC.NoMappingForSqlTransactionLevel(sql_iso);
};
}
return _isolevel;
}
}
override public void Commit() {
OdbcConnection.ExecutePermission.Demand(); // MDAC 81476
OdbcConnection connection = _connection;
if (null == connection) {
throw ADP.TransactionZombied(this);
}
connection.CheckState(ADP.CommitTransaction); // MDAC 68289
//Note: SQLEndTran success if not actually in a transaction, so we have to throw
//since the IDbTransaciton spec indicates this is an error for the managed packages
if(null == _handle) {
throw ODBC.NotInTransaction();
}
ODBC32.RetCode retcode = _handle.CompleteTransaction(ODBC32.SQL_COMMIT);
if (retcode == ODBC32.RetCode.ERROR) {
//If an error has occurred, we will throw an exception in HandleError,
//and leave the transaction active for the user to retry
connection.HandleError(_handle, retcode);
}
//Transaction is complete...
connection.LocalTransaction = null;
_connection = null;
_handle = null;
}
protected override void Dispose(bool disposing) {
if (disposing) {
OdbcConnectionHandle handle = _handle;
_handle = null;
if (null != handle){
try{
ODBC32.RetCode retcode = handle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
if (retcode == ODBC32.RetCode.ERROR) {
//don't throw an exception here, but trace it so it can be logged
if (_connection != null) {
Exception e = _connection.HandleErrorNoThrow(handle, retcode);
ADP.TraceExceptionWithoutRethrow(e);
}
}
}
catch (Exception e){
//
if (!ADP.IsCatchableExceptionType(e)) {
throw;
}
}
}
if (_connection != null) {
if (_connection.IsOpen) {
_connection.LocalTransaction = null;
}
}
_connection = null;
_isolevel = IsolationLevel.Unspecified;
}
base.Dispose(disposing);
}
override public void Rollback() {
OdbcConnection connection = _connection;
if (null == connection) {
throw ADP.TransactionZombied(this);
}
connection.CheckState(ADP.RollbackTransaction); // MDAC 68289
//Note: SQLEndTran success if not actually in a transaction, so we have to throw
//since the IDbTransaciton spec indicates this is an error for the managed packages
if(null == _handle) {
throw ODBC.NotInTransaction();
}
ODBC32.RetCode retcode = _handle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
if (retcode == ODBC32.RetCode.ERROR) {
//If an error has occurred, we will throw an exception in HandleError,
//and leave the transaction active for the user to retry
connection.HandleError(_handle, retcode);
}
connection.LocalTransaction = null;
_connection = null;
_handle = null;
}
}
}
|