Fix operator != handling of LHS null
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlPromotableSinglePhaseNotification.cs
1 // NpgsqlPromotableSinglePhaseNotification.cs
2 //
3 // Author:
4 //  Josh Cooley <jbnpgsql@tuxinthebox.net>
5 //
6 // Copyright (C) 2007, The Npgsql Development Team
7 //
8 // Permission to use, copy, modify, and distribute this software and its
9 // documentation for any purpose, without fee, and without a written
10 // agreement is hereby granted, provided that the above copyright notice
11 // and this paragraph and the following two paragraphs appear in all copies.
12 // 
13 // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
14 // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
15 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
16 // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
17 // THE POSSIBILITY OF SUCH DAMAGE.
18 // 
19 // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
20 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21 // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
23 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
25 using System;
26 using System.Transactions;
27
28 namespace Npgsql
29 {
30         internal class NpgsqlPromotableSinglePhaseNotification : IPromotableSinglePhaseNotification
31         {
32                 private readonly NpgsqlConnection _connection;
33                 private IsolationLevel _isolationLevel;
34                 private NpgsqlTransaction _npgsqlTx;
35                 private NpgsqlTransactionCallbacks _callbacks;
36         private INpgsqlResourceManager _rm;
37         private bool _inTransaction;
38
39                 private static readonly String CLASSNAME = "NpgsqlPromotableSinglePhaseNotification";
40
41                 public NpgsqlPromotableSinglePhaseNotification(NpgsqlConnection connection)
42                 {
43                         _connection = connection;
44                 }
45
46                 public void Enlist(Transaction tx)
47                 {
48                         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Enlist");
49                         if (tx != null)
50                         {
51                                 _isolationLevel = tx.IsolationLevel;
52                                 if (!tx.EnlistPromotableSinglePhase(this))
53                                 {
54                                         // must already have a durable resource
55                                         // start transaction
56                                         _npgsqlTx = _connection.BeginTransaction(ConvertIsolationLevel(_isolationLevel));
57                     _inTransaction = true;
58                     _rm = CreateResourceManager();
59                     _callbacks = new NpgsqlTransactionCallbacks(_connection);
60                     _rm.Enlist(_callbacks, TransactionInterop.GetTransmitterPropagationToken(tx));
61                                         // enlisted in distributed transaction
62                                         // disconnect and cleanup local transaction
63                                         _npgsqlTx.Cancel();
64                                         _npgsqlTx.Dispose();
65                                         _npgsqlTx = null;
66                                 }
67                         }
68                 }
69
70                 /// <summary>
71                 /// Used when a connection is closed
72                 /// </summary>
73                 public void Prepare()
74                 {
75             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Prepare");
76             if (_inTransaction)
77             {
78                 // may not be null if Promote or Enlist is called first
79                 if (_callbacks == null)
80                 {
81                     _callbacks = new NpgsqlTransactionCallbacks(_connection);
82                 }
83                 _callbacks.PrepareTransaction();
84                 if (_npgsqlTx != null)
85                 {
86                     // cancel the NpgsqlTransaction since this will
87                     // be handled by a two phase commit.
88                     _npgsqlTx.Cancel();
89                     _npgsqlTx.Dispose();
90                     _npgsqlTx = null;
91                 }
92             }
93                 }
94
95                 #region IPromotableSinglePhaseNotification Members
96
97                 public void Initialize()
98                 {
99                         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Initialize");
100                         _npgsqlTx = _connection.BeginTransaction(ConvertIsolationLevel(_isolationLevel));
101             _inTransaction = true;
102                 }
103
104                 public void Rollback(SinglePhaseEnlistment singlePhaseEnlistment)
105                 {
106                         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Rollback");
107             // try to rollback the transaction with either the
108             // ADO.NET transaction or the callbacks that managed the
109             // two phase commit transaction.
110                         if (_npgsqlTx != null)
111                         {
112                                 _npgsqlTx.Rollback();
113                                 _npgsqlTx.Dispose();
114                 _npgsqlTx = null;
115                 singlePhaseEnlistment.Aborted();
116                         }
117             else if (_callbacks != null)
118             {
119                 if (_rm != null)
120                 {
121                     _rm.RollbackWork(_callbacks.GetName());
122                     singlePhaseEnlistment.Aborted();
123                 }
124                 else
125                 {
126                     _callbacks.RollbackTransaction();
127                     singlePhaseEnlistment.Aborted();
128                 }
129                 _callbacks = null;
130             }
131             _inTransaction = false;
132                 }
133
134                 public void SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment)
135                 {
136                         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "SinglePhaseCommit");
137                         if (_npgsqlTx != null)
138                         {
139                                 _npgsqlTx.Commit();
140                                 _npgsqlTx.Dispose();
141                                 _npgsqlTx = null;
142                                 singlePhaseEnlistment.Committed();
143                         }
144                         else if (_callbacks != null)
145                         {
146                 if (_rm != null)
147                 {
148                     _rm.CommitWork(_callbacks.GetName());
149                     singlePhaseEnlistment.Committed();
150                 }
151                 else
152                 {
153                     _callbacks.CommitTransaction();
154                     singlePhaseEnlistment.Committed();
155                 }
156                 _callbacks = null;
157                         }
158             _inTransaction = false;
159                 }
160
161                 #endregion
162
163                 #region ITransactionPromoter Members
164
165                 public byte[] Promote()
166                 {
167                         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Promote");
168             _rm = CreateResourceManager();
169             // may not be null if Prepare or Enlist is called first
170             if (_callbacks == null)
171             {
172                 _callbacks = new NpgsqlTransactionCallbacks(_connection);
173             }
174             byte[] token = _rm.Promote(_callbacks);
175             // mostly likely case for this is the transaction has been prepared.
176             if (_npgsqlTx != null)
177             {
178                 // cancel the NpgsqlTransaction since this will
179                 // be handled by a two phase commit.
180                 _npgsqlTx.Cancel();
181                 _npgsqlTx.Dispose();
182                 _npgsqlTx = null;
183             }
184                         return token;
185                 }
186
187                 #endregion
188
189                 private static INpgsqlResourceManager _resourceManager;
190
191                 private static INpgsqlResourceManager CreateResourceManager()
192                 {
193                         // TODO: create network proxy for resource manager
194                         if (_resourceManager == null)
195                         {
196                                 AppDomain rmDomain = AppDomain.CreateDomain("NpgsqlResourceManager", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
197                                 _resourceManager =
198                                         (INpgsqlResourceManager)
199                                         rmDomain.CreateInstanceAndUnwrap(typeof (NpgsqlResourceManager).Assembly.FullName,
200                                                                          typeof (NpgsqlResourceManager).FullName);
201                         }
202                         return _resourceManager;
203                         //return new NpgsqlResourceManager();
204                 }
205
206                 private static System.Data.IsolationLevel ConvertIsolationLevel(IsolationLevel _isolationLevel)
207                 {
208                         switch (_isolationLevel)
209                         {
210                                 case IsolationLevel.Chaos:
211                                         return System.Data.IsolationLevel.Chaos;
212                                 case IsolationLevel.ReadCommitted:
213                                         return System.Data.IsolationLevel.ReadCommitted;
214                                 case IsolationLevel.ReadUncommitted:
215                                         return System.Data.IsolationLevel.ReadUncommitted;
216                                 case IsolationLevel.RepeatableRead:
217                                         return System.Data.IsolationLevel.RepeatableRead;
218                                 case IsolationLevel.Serializable:
219                                         return System.Data.IsolationLevel.Serializable;
220                                 case IsolationLevel.Snapshot:
221                                         return System.Data.IsolationLevel.Snapshot;
222                                 case IsolationLevel.Unspecified:
223                                 default:
224                                         return System.Data.IsolationLevel.Unspecified;
225                         }
226                 }
227         }
228 }