Welcome to mirror list, hosted at ThFree Co, Russian Federation.

OdbcTransaction.cs « Odbc « Data « System « System.Data « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 25dbd7179841ce314e68672ea1ae0e1bc3d58a68 (plain)
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;
        }
    }
}