* attribute.cs (GetMarshal): Work even if "DefineCustom" is
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Firebird / FbTransaction.cs
1 /*\r
2  *      Firebird ADO.NET Data provider for .NET and     Mono \r
3  * \r
4  *         The contents of this file are subject to the Initial \r
5  *         Developer's Public License Version 1.0 (the "License"); \r
6  *         you may not use this file except in compliance with the \r
7  *         License. You may obtain a copy of the License at \r
8  *         http://www.firebirdsql.org/index.php?op=doc&id=idpl\r
9  *\r
10  *         Software distributed under the License is distributed on \r
11  *         an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either \r
12  *         express or implied. See the License for the specific \r
13  *         language governing rights and limitations under the License.\r
14  * \r
15  *      Copyright (c) 2002, 2005 Carlos Guzman Alvarez\r
16  *      All Rights Reserved.\r
17  */\r
18 \r
19 using System;\r
20 using System.Data;\r
21 using System.Collections;\r
22 \r
23 using FirebirdSql.Data.Common;\r
24 \r
25 namespace FirebirdSql.Data.Firebird\r
26 {\r
27         /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/overview/*'/>\r
28         public sealed class FbTransaction : MarshalByRefObject, IDbTransaction, IDisposable\r
29         {\r
30                 #region Fields\r
31 \r
32                 private ITransaction    transaction;\r
33                 private FbConnection    connection;\r
34                 private IsolationLevel  isolationLevel;\r
35                 private bool                    disposed;\r
36                 private bool                    isUpdated;\r
37 \r
38                 #endregion\r
39 \r
40                 #region Properties\r
41 \r
42                 IDbConnection IDbTransaction.Connection\r
43                 {\r
44                         get { return this.Connection; }\r
45                 }\r
46 \r
47                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/property[@name="Connection"]/*'/>\r
48                 public FbConnection Connection\r
49                 {\r
50                         get\r
51                         {\r
52                                 if (!this.isUpdated)\r
53                                 {\r
54                                         return this.connection;\r
55                                 }\r
56                                 else\r
57                                 {\r
58                                         return null;\r
59                                 }\r
60                         }\r
61                 }\r
62 \r
63                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/property[@name="IsolationLevel"]/*'/>\r
64                 public IsolationLevel IsolationLevel\r
65                 {\r
66                         get { return this.isolationLevel; }\r
67                 }\r
68 \r
69                 #endregion\r
70 \r
71                 #region Internal Properties\r
72 \r
73                 internal ITransaction Transaction\r
74                 {\r
75                         get { return this.transaction; }\r
76                 }\r
77 \r
78                 internal bool IsUpdated\r
79                 {\r
80                         get { return this.isUpdated; }\r
81                 }\r
82 \r
83                 #endregion\r
84 \r
85                 #region Constructors\r
86 \r
87                 internal FbTransaction(FbConnection connection) : this(connection, IsolationLevel.ReadCommitted)\r
88                 {\r
89                 }\r
90 \r
91                 internal FbTransaction(FbConnection connection, IsolationLevel il)\r
92                 {\r
93                         this.isolationLevel = il;\r
94                         this.connection         = connection;\r
95                 }\r
96 \r
97                 #endregion\r
98 \r
99                 #region Finalizer\r
100 \r
101                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbCommandBuilder"]/destructor[@name="Finalize"]/*'/>\r
102                 ~FbTransaction()\r
103                 {\r
104                         this.Dispose(false);\r
105                 }\r
106 \r
107                 #endregion\r
108 \r
109                 #region IDisposable     Methods\r
110 \r
111                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Dispose"]/*'/>\r
112                 public void Dispose()\r
113                 {\r
114                         this.Dispose(true);\r
115                         GC.SuppressFinalize(this);\r
116                 }\r
117 \r
118                 private void Dispose(bool disposing)\r
119                 {\r
120                         lock (this)\r
121                         {\r
122                                 if (!this.disposed)\r
123                                 {\r
124                                         try\r
125                                         {\r
126                                                 // release any unmanaged resources\r
127                                                 if (this.transaction != null)\r
128                                                 {\r
129                                                         if ((this.transaction.State == TransactionState.TransactionStarted\r
130                                                                 || this.transaction.State == TransactionState.TransactionPrepared)\r
131                                                                 && !this.isUpdated)\r
132                                                         {\r
133                                                                 this.transaction.Dispose();\r
134                                                                 this.transaction = null;\r
135                                                         }\r
136                                                 }\r
137 \r
138                                                 // release any managed resources\r
139                                                 if (disposing)\r
140                                                 {\r
141                                                         this.connection = null;\r
142                                                         this.transaction = null;\r
143                                                 }\r
144                                         }\r
145                                         finally\r
146                                         {\r
147                                                 this.isUpdated = true;\r
148                                                 this.disposed = true;\r
149                                         }\r
150                                 }\r
151                         }\r
152                 }\r
153 \r
154                 #endregion\r
155 \r
156                 #region Methods\r
157 \r
158                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Commit"]/*'/>\r
159                 public void Commit()\r
160                 {\r
161                         lock (this)\r
162                         {\r
163                                 if (this.isUpdated)\r
164                                 {\r
165                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
166                                 }\r
167 \r
168                                 try\r
169                                 {\r
170                                         this.transaction.Commit();\r
171                                         this.UpdateTransaction();\r
172                                 }\r
173                                 catch (IscException ex)\r
174                                 {\r
175                                         throw new FbException(ex.Message, ex);\r
176                                 }\r
177                         }\r
178                 }\r
179 \r
180                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Rollback"]/*'/>\r
181                 public void Rollback()\r
182                 {\r
183                         lock (this)\r
184                         {\r
185                                 if (this.isUpdated)\r
186                                 {\r
187                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
188                                 }\r
189 \r
190                                 try\r
191                                 {\r
192                                         this.transaction.Rollback();\r
193                                         this.UpdateTransaction();\r
194                                 }\r
195                                 catch (IscException ex)\r
196                                 {\r
197                                         throw new FbException(ex.Message, ex);\r
198                                 }\r
199                         }\r
200                 }\r
201 \r
202                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Save(System.String)"]/*'/>\r
203                 public void Save(string savePointName)\r
204                 {\r
205                         lock (this)\r
206                         {\r
207                                 if (savePointName == null)\r
208                                 {\r
209                                         throw new ArgumentException("No transaction name was be specified.");\r
210                                 }\r
211                                 else\r
212                                 {\r
213                                         if (savePointName.Length == 0)\r
214                                         {\r
215                                                 throw new ArgumentException("No transaction name was be specified.");\r
216                                         }\r
217                                 }\r
218                                 if (this.isUpdated)\r
219                                 {\r
220                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
221                                 }\r
222 \r
223                                 try\r
224                                 {\r
225                                         FbCommand command = new FbCommand(\r
226                                                 "SAVEPOINT " + savePointName,\r
227                                                 this.connection,\r
228                                                 this);\r
229                                         command.ExecuteNonQuery();\r
230                                         command.Dispose();\r
231                                 }\r
232                                 catch (IscException ex)\r
233                                 {\r
234                                         throw new FbException(ex.Message, ex);\r
235                                 }\r
236                         }\r
237                 }\r
238 \r
239                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Commit(System.String)"]/*'/>\r
240                 public void Commit(string savePointName)\r
241                 {\r
242                         lock (this)\r
243                         {\r
244                                 if (savePointName == null)\r
245                                 {\r
246                                         throw new ArgumentException("No transaction name was be specified.");\r
247                                 }\r
248                                 else\r
249                                 {\r
250                                         if (savePointName.Length == 0)\r
251                                         {\r
252                                                 throw new ArgumentException("No transaction name was be specified.");\r
253                                         }\r
254                                 }\r
255                                 if (this.isUpdated)\r
256                                 {\r
257                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
258                                 }\r
259 \r
260                                 try\r
261                                 {\r
262                                         FbCommand command = new FbCommand(\r
263                                                 "RELEASE SAVEPOINT " + savePointName,\r
264                                                 this.connection,\r
265                                                 this);\r
266                                         command.ExecuteNonQuery();\r
267                                         command.Dispose();\r
268                                 }\r
269                                 catch (IscException ex)\r
270                                 {\r
271                                         throw new FbException(ex.Message, ex);\r
272                                 }\r
273                         }\r
274                 }\r
275 \r
276                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="Rollback(System.String)"]/*'/>\r
277                 public void Rollback(string savePointName)\r
278                 {\r
279                         lock (this)\r
280                         {\r
281                                 if (savePointName == null)\r
282                                 {\r
283                                         throw new ArgumentException("No transaction name was be specified.");\r
284                                 }\r
285                                 else\r
286                                 {\r
287                                         if (savePointName.Length == 0)\r
288                                         {\r
289                                                 throw new ArgumentException("No transaction name was be specified.");\r
290                                         }\r
291                                 }\r
292                                 if (this.isUpdated)\r
293                                 {\r
294                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
295                                 }\r
296 \r
297                                 try\r
298                                 {\r
299                                         FbCommand command = new FbCommand(\r
300                                                 "ROLLBACK WORK TO SAVEPOINT " + savePointName,\r
301                                                 this.connection,\r
302                                                 this);\r
303                                         command.ExecuteNonQuery();\r
304                                         command.Dispose();\r
305                                 }\r
306                                 catch (IscException ex)\r
307                                 {\r
308                                         throw new FbException(ex.Message, ex);\r
309                                 }\r
310                         }\r
311                 }\r
312 \r
313                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="CommitRetaining"]/*'/>\r
314                 public void CommitRetaining()\r
315                 {\r
316                         lock (this)\r
317                         {\r
318                                 if (this.isUpdated)\r
319                                 {\r
320                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
321                                 }\r
322 \r
323                                 try\r
324                                 {\r
325                                         this.transaction.CommitRetaining();\r
326                                 }\r
327                                 catch (IscException ex)\r
328                                 {\r
329                                         throw new FbException(ex.Message, ex);\r
330                                 }\r
331                         }\r
332                 }\r
333 \r
334                 /// <include file='Doc/en_EN/FbTransaction.xml' path='doc/class[@name="FbTransaction"]/method[@name="RollbackRetaining"]/*'/>\r
335                 public void RollbackRetaining()\r
336                 {\r
337                         lock (this)\r
338                         {\r
339                                 if (this.isUpdated)\r
340                                 {\r
341                                         throw new InvalidOperationException("This Transaction has completed; it is no longer usable.");\r
342                                 }\r
343 \r
344                                 try\r
345                                 {\r
346                                         this.transaction.RollbackRetaining();\r
347                                 }\r
348                                 catch (IscException ex)\r
349                                 {\r
350                                         throw new FbException(ex.Message, ex);\r
351                                 }\r
352                         }\r
353                 }\r
354 \r
355                 #endregion\r
356 \r
357                 #region InternalMethods\r
358 \r
359                 internal void BeginTransaction()\r
360                 {\r
361                         lock (this)\r
362                         {\r
363                                 try\r
364                                 {\r
365                                         IDatabase database = this.connection.InnerConnection.Database;\r
366                                         this.transaction = database.BeginTransaction(this.BuildTpb());\r
367                                 }\r
368                                 catch (IscException ex)\r
369                                 {\r
370                                         throw new FbException(ex.Message, ex);\r
371                                 }\r
372                         }\r
373                 }\r
374 \r
375                 internal void BeginTransaction(FbTransactionOptions options)\r
376                 {\r
377                         lock (this)\r
378                         {\r
379                                 try\r
380                                 {\r
381                                         IDatabase database = this.connection.InnerConnection.Database;\r
382                                         this.transaction = database.BeginTransaction(this.BuildTpb(options));\r
383                                 }\r
384                                 catch (IscException ex)\r
385                                 {\r
386                                         throw new FbException(ex.Message, ex);\r
387                                 }\r
388                         }\r
389                 }\r
390 \r
391                 #endregion\r
392 \r
393                 #region Private Methods\r
394 \r
395                 private void UpdateTransaction()\r
396                 {\r
397                         if (this.connection != null)\r
398                         {\r
399                                 this.connection.InnerConnection.TransactionUpdated();\r
400                         }\r
401 \r
402                         this.isUpdated  = true;\r
403                         this.connection = null;\r
404                         this.transaction = null;\r
405                 }\r
406 \r
407                 private TransactionParameterBuffer BuildTpb()\r
408                 {\r
409                         FbTransactionOptions options = FbTransactionOptions.Write;\r
410 \r
411                         options |= FbTransactionOptions.Wait;\r
412 \r
413                         /* Isolation level */\r
414                         switch (this.isolationLevel)\r
415                         {\r
416                                 case IsolationLevel.Serializable:\r
417                                         options |= FbTransactionOptions.Consistency;\r
418                                         break;\r
419 \r
420                                 case IsolationLevel.RepeatableRead:\r
421                                         options |= FbTransactionOptions.Concurrency;\r
422                                         break;\r
423 \r
424                                 case IsolationLevel.ReadUncommitted:\r
425                                         options |= FbTransactionOptions.ReadCommitted;\r
426                                         options |= FbTransactionOptions.RecVersion;\r
427                                         break;\r
428 \r
429                                 case IsolationLevel.ReadCommitted:\r
430                                 default:\r
431                                         options |= FbTransactionOptions.ReadCommitted;\r
432                                         options |= FbTransactionOptions.NoRecVersion;\r
433                                         break;\r
434                         }\r
435 \r
436                         return this.BuildTpb(options);\r
437                 }\r
438 \r
439 #if     (!NETCF)\r
440 \r
441                 private TransactionParameterBuffer BuildTpb(FbTransactionOptions options)\r
442                 {\r
443                         TransactionParameterBuffer tpb = new TransactionParameterBuffer();\r
444 \r
445                         tpb.Append(IscCodes.isc_tpb_version3);\r
446 \r
447                         FbTransactionOptions[] o = (FbTransactionOptions[])Enum.GetValues(options.GetType());\r
448                         for (int i = 0; i < o.Length; i++)\r
449                         {\r
450                                 FbTransactionOptions option = ((FbTransactionOptions)(o[i]));\r
451                                 if ((options & option) == option)\r
452                                 {\r
453                                         switch (option)\r
454                                         {\r
455                                                 case FbTransactionOptions.Consistency:\r
456                                                         tpb.Append(IscCodes.isc_tpb_consistency);\r
457                                                         break;\r
458 \r
459                                                 case FbTransactionOptions.Concurrency:\r
460                                                         tpb.Append(IscCodes.isc_tpb_concurrency);\r
461                                                         break;\r
462 \r
463                                                 case FbTransactionOptions.Shared:\r
464                                                         tpb.Append(IscCodes.isc_tpb_shared);\r
465                                                         break;\r
466 \r
467                                                 case FbTransactionOptions.Protected:\r
468                                                         tpb.Append(IscCodes.isc_tpb_protected);\r
469                                                         break;\r
470 \r
471                                                 case FbTransactionOptions.Exclusive:\r
472                                                         tpb.Append(IscCodes.isc_tpb_exclusive);\r
473                                                         break;\r
474 \r
475                                                 case FbTransactionOptions.Wait:\r
476                                                         tpb.Append(IscCodes.isc_tpb_wait);\r
477                                                         break;\r
478 \r
479                                                 case FbTransactionOptions.NoWait:\r
480                                                         tpb.Append(IscCodes.isc_tpb_nowait);\r
481                                                         break;\r
482 \r
483                                                 case FbTransactionOptions.Read:\r
484                                                         tpb.Append(IscCodes.isc_tpb_read);\r
485                                                         break;\r
486 \r
487                                                 case FbTransactionOptions.Write:\r
488                                                         tpb.Append(IscCodes.isc_tpb_write);\r
489                                                         break;\r
490 \r
491                                                 case FbTransactionOptions.LockRead:\r
492                                                         tpb.Append(IscCodes.isc_tpb_lock_read);\r
493                                                         break;\r
494 \r
495                                                 case FbTransactionOptions.LockWrite:\r
496                                                         tpb.Append(IscCodes.isc_tpb_lock_write);\r
497                                                         break;\r
498 \r
499                                                 case FbTransactionOptions.ReadCommitted:\r
500                                                         tpb.Append(IscCodes.isc_tpb_read_committed);\r
501                                                         break;\r
502 \r
503                                                 case FbTransactionOptions.Autocommit:\r
504                                                         tpb.Append(IscCodes.isc_tpb_autocommit);\r
505                                                         break;\r
506 \r
507                                                 case FbTransactionOptions.RecVersion:\r
508                                                         tpb.Append(IscCodes.isc_tpb_rec_version);\r
509                                                         break;\r
510 \r
511                                                 case FbTransactionOptions.NoRecVersion:\r
512                                                         tpb.Append(IscCodes.isc_tpb_no_rec_version);\r
513                                                         break;\r
514 \r
515                                                 case FbTransactionOptions.RestartRequests:\r
516                                                         tpb.Append(IscCodes.isc_tpb_restart_requests);\r
517                                                         break;\r
518 \r
519                                                 case FbTransactionOptions.NoAutoUndo:\r
520                                                         tpb.Append(IscCodes.isc_tpb_no_auto_undo);\r
521                                                         break;\r
522                                         }\r
523                                 }\r
524                         }\r
525 \r
526                         return tpb;\r
527                 }\r
528 \r
529 #else\r
530 \r
531                 private TransactionParameterBuffer BuildTpb(FbTransactionOptions options)\r
532                 {\r
533                         TransactionParameterBuffer tpb = new TransactionParameterBuffer();\r
534 \r
535                         tpb.Append(IscCodes.isc_tpb_version3);\r
536 \r
537                         if ((options & FbTransactionOptions.Consistency) ==     FbTransactionOptions.Consistency)\r
538                         {\r
539                                 tpb.Append(IscCodes.isc_tpb_consistency);\r
540                         }\r
541                         if ((options & FbTransactionOptions.Concurrency) ==     FbTransactionOptions.Concurrency)\r
542                         {\r
543                                 tpb.Append(IscCodes.isc_tpb_concurrency);\r
544                         }\r
545                         if ((options & FbTransactionOptions.Shared) == FbTransactionOptions.Shared)\r
546                         {\r
547                                 tpb.Append(IscCodes.isc_tpb_shared);\r
548                         }\r
549                         if ((options & FbTransactionOptions.Protected) == FbTransactionOptions.Protected)\r
550                         {\r
551                                 tpb.Append(IscCodes.isc_tpb_protected);\r
552                         }\r
553                         if ((options & FbTransactionOptions.Exclusive) == FbTransactionOptions.Exclusive)\r
554                         {\r
555                                 tpb.Append(IscCodes.isc_tpb_exclusive);\r
556                         }\r
557                         if ((options & FbTransactionOptions.Wait) == FbTransactionOptions.Wait)\r
558                         {\r
559                                 tpb.Append(IscCodes.isc_tpb_wait);\r
560                         }\r
561                         if ((options & FbTransactionOptions.NoWait) == FbTransactionOptions.NoWait)\r
562                         {\r
563                                 tpb.Append(IscCodes.isc_tpb_nowait);\r
564                         }\r
565                         if ((options & FbTransactionOptions.Read) == FbTransactionOptions.Read)\r
566                         {\r
567                                 tpb.Append(IscCodes.isc_tpb_read);\r
568                         }\r
569                         if ((options & FbTransactionOptions.Write) == FbTransactionOptions.Write)\r
570                         {\r
571                                 tpb.Append(IscCodes.isc_tpb_write);\r
572                         }\r
573                         if ((options & FbTransactionOptions.LockRead) == FbTransactionOptions.LockRead)\r
574                         {\r
575                                 tpb.Append(IscCodes.isc_tpb_lock_read);\r
576                         }\r
577                         if ((options & FbTransactionOptions.LockWrite) == FbTransactionOptions.LockWrite)\r
578                         {\r
579                                 tpb.Append(IscCodes.isc_tpb_lock_write);\r
580                         }\r
581                         if ((options & FbTransactionOptions.ReadCommitted) == FbTransactionOptions.ReadCommitted)\r
582                         {\r
583                                 tpb.Append(IscCodes.isc_tpb_read_committed);\r
584                         }\r
585                         if ((options & FbTransactionOptions.Autocommit) == FbTransactionOptions.Autocommit)\r
586                         {\r
587                                 tpb.Append(IscCodes.isc_tpb_autocommit);\r
588                         }\r
589                         if ((options & FbTransactionOptions.RecVersion) == FbTransactionOptions.RecVersion)\r
590                         {\r
591                                 tpb.Append(IscCodes.isc_tpb_rec_version);\r
592                         }\r
593                         if ((options & FbTransactionOptions.NoRecVersion) == FbTransactionOptions.NoRecVersion)\r
594                         {\r
595                                 tpb.Append(IscCodes.isc_tpb_no_rec_version);\r
596                         }\r
597                         if ((options & FbTransactionOptions.RestartRequests) == FbTransactionOptions.RestartRequests)\r
598                         {\r
599                                 tpb.Append(IscCodes.isc_tpb_restart_requests);\r
600                         }\r
601                         if ((options & FbTransactionOptions.NoAutoUndo) == FbTransactionOptions.NoAutoUndo)\r
602                         {\r
603                                 tpb.Append(IscCodes.isc_tpb_no_auto_undo);\r
604                         }\r
605                         \r
606                         return tpb;\r
607                 }\r
608 \r
609 #endif\r
610 \r
611                 #endregion\r
612         }\r
613 }\r