1 //------------------------------------------------------------------------------
2 // <copyright file="OdbcTransaction.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 //------------------------------------------------------------------------------
11 using System.Data.Common;
12 using System.Threading;
14 namespace System.Data.Odbc
16 public sealed class OdbcTransaction : DbTransaction {
17 private OdbcConnection _connection;
18 private IsolationLevel _isolevel = IsolationLevel.Unspecified;
19 private OdbcConnectionHandle _handle;
21 internal OdbcTransaction(OdbcConnection connection, IsolationLevel isolevel, OdbcConnectionHandle handle) {
22 OdbcConnection.VerifyExecutePermission();
24 _connection = connection;
29 new public OdbcConnection Connection { // MDAC 66655
35 override protected DbConnection DbConnection { // MDAC 66655
41 override public IsolationLevel IsolationLevel {
43 OdbcConnection connection = _connection;
44 if (null == connection ) {
45 throw ADP.TransactionZombied(this);
48 //We need to query for the case where the user didn't set the isolevel
49 //BeginTransaction(), but we should also query to see if the driver
50 //"rolled" the level to a higher supported one...
51 if(IsolationLevel.Unspecified == _isolevel) {
52 //Get the isolation level
53 int sql_iso= connection .GetConnectAttr(ODBC32.SQL_ATTR.TXN_ISOLATION, ODBC32.HANDLER.THROW);
54 switch((ODBC32.SQL_TRANSACTION)sql_iso) {
55 case ODBC32.SQL_TRANSACTION.READ_UNCOMMITTED:
56 _isolevel = IsolationLevel.ReadUncommitted;
58 case ODBC32.SQL_TRANSACTION.READ_COMMITTED:
59 _isolevel = IsolationLevel.ReadCommitted;
61 case ODBC32.SQL_TRANSACTION.REPEATABLE_READ:
62 _isolevel = IsolationLevel.RepeatableRead;
64 case ODBC32.SQL_TRANSACTION.SERIALIZABLE:
65 _isolevel = IsolationLevel.Serializable;
67 case ODBC32.SQL_TRANSACTION.SNAPSHOT:
68 _isolevel = IsolationLevel.Snapshot;
71 throw ODBC.NoMappingForSqlTransactionLevel(sql_iso);
78 override public void Commit() {
79 OdbcConnection.ExecutePermission.Demand(); // MDAC 81476
81 OdbcConnection connection = _connection;
82 if (null == connection) {
83 throw ADP.TransactionZombied(this);
86 connection.CheckState(ADP.CommitTransaction); // MDAC 68289
88 //Note: SQLEndTran success if not actually in a transaction, so we have to throw
89 //since the IDbTransaciton spec indicates this is an error for the managed packages
91 throw ODBC.NotInTransaction();
94 ODBC32.RetCode retcode = _handle.CompleteTransaction(ODBC32.SQL_COMMIT);
95 if (retcode == ODBC32.RetCode.ERROR) {
96 //If an error has occurred, we will throw an exception in HandleError,
97 //and leave the transaction active for the user to retry
98 connection.HandleError(_handle, retcode);
101 //Transaction is complete...
102 connection.LocalTransaction = null;
108 protected override void Dispose(bool disposing) {
110 OdbcConnectionHandle handle = _handle;
114 ODBC32.RetCode retcode = handle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
115 if (retcode == ODBC32.RetCode.ERROR) {
116 //don't throw an exception here, but trace it so it can be logged
117 if (_connection != null) {
118 Exception e = _connection.HandleErrorNoThrow(handle, retcode);
119 ADP.TraceExceptionWithoutRethrow(e);
125 if (!ADP.IsCatchableExceptionType(e)) {
130 if (_connection != null) {
131 if (_connection.IsOpen) {
132 _connection.LocalTransaction = null;
136 _isolevel = IsolationLevel.Unspecified;
138 base.Dispose(disposing);
141 override public void Rollback() {
142 OdbcConnection connection = _connection;
143 if (null == connection) {
144 throw ADP.TransactionZombied(this);
146 connection.CheckState(ADP.RollbackTransaction); // MDAC 68289
148 //Note: SQLEndTran success if not actually in a transaction, so we have to throw
149 //since the IDbTransaciton spec indicates this is an error for the managed packages
150 if(null == _handle) {
151 throw ODBC.NotInTransaction();
154 ODBC32.RetCode retcode = _handle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
155 if (retcode == ODBC32.RetCode.ERROR) {
156 //If an error has occurred, we will throw an exception in HandleError,
157 //and leave the transaction active for the user to retry
158 connection.HandleError(_handle, retcode);
160 connection.LocalTransaction = null;