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 167 168 169 170 171
|
/********************************************************
* ADO.NET 2.0 Data Provider for SQLite Version 3.X
* Written by Robert Simpson (robert@blackcastlesoft.com)
*
* Released to the public domain, use at your own risk!
********************************************************/
namespace Mono.Data.Sqlite
{
using System;
using System.Data;
using System.Data.Common;
/// <summary>
/// SQLite implementation of DbTransaction.
/// </summary>
public sealed class SqliteTransaction : DbTransaction
{
/// <summary>
/// The connection to which this transaction is bound
/// </summary>
internal SqliteConnection _cnn;
internal long _version; // Matches the version of the connection
private IsolationLevel _level;
/// <summary>
/// Constructs the transaction object, binding it to the supplied connection
/// </summary>
/// <param name="connection">The connection to open a transaction on</param>
/// <param name="deferredLock">TRUE to defer the writelock, or FALSE to lock immediately</param>
internal SqliteTransaction(SqliteConnection connection, bool deferredLock)
{
_cnn = connection;
_version = _cnn._version;
_level = (deferredLock == true) ? IsolationLevel.ReadCommitted : IsolationLevel.Serializable;
if (_cnn._transactionLevel++ == 0)
{
try
{
using (SqliteCommand cmd = _cnn.CreateCommand())
{
if (!deferredLock)
cmd.CommandText = "BEGIN IMMEDIATE";
else
cmd.CommandText = "BEGIN";
cmd.ExecuteNonQuery();
}
}
catch (SqliteException)
{
_cnn._transactionLevel--;
_cnn = null;
throw;
}
}
}
/// <summary>
/// Commits the current transaction.
/// </summary>
public override void Commit()
{
IsValid(true);
if (_cnn._transactionLevel - 1 == 0)
{
using (SqliteCommand cmd = _cnn.CreateCommand())
{
cmd.CommandText = "COMMIT";
cmd.ExecuteNonQuery();
}
}
_cnn._transactionLevel--;
_cnn = null;
}
/// <summary>
/// Returns the underlying connection to which this transaction applies.
/// </summary>
public new SqliteConnection Connection
{
get { return _cnn; }
}
/// <summary>
/// Forwards to the local Connection property
/// </summary>
protected override DbConnection DbConnection
{
get { return Connection; }
}
/// <summary>
/// Disposes the transaction. If it is currently active, any changes are rolled back.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
if (IsValid(false))
Rollback();
_cnn = null;
}
}
base.Dispose(disposing);
}
/// <summary>
/// Gets the isolation level of the transaction. SQLite only supports Serializable transactions.
/// </summary>
public override IsolationLevel IsolationLevel
{
get { return _level; }
}
/// <summary>
/// Rolls back the active transaction.
/// </summary>
public override void Rollback()
{
IsValid(true);
IssueRollback(_cnn);
_cnn._transactionLevel = 0;
_cnn = null;
}
internal static void IssueRollback(SqliteConnection cnn)
{
using (SqliteCommand cmd = cnn.CreateCommand())
{
cmd.CommandText = "ROLLBACK";
cmd.ExecuteNonQuery();
}
}
internal bool IsValid(bool throwError)
{
if (_cnn == null)
{
if (throwError == true) throw new ArgumentNullException("No connection associated with this transaction");
else return false;
}
if (_cnn._transactionLevel == 0)
{
if (throwError == true) throw new SqliteException((int)SQLiteErrorCode.Misuse, "No transaction is active on this connection");
else return false;
}
if (_cnn._version != _version)
{
if (throwError == true) throw new SqliteException((int)SQLiteErrorCode.Misuse, "The connection was closed and re-opened, changes were rolled back");
else return false;
}
if (_cnn.State != ConnectionState.Open)
{
if (throwError == true) throw new SqliteException((int)SQLiteErrorCode.Misuse, "Connection was closed");
else return false;
}
return true;
}
}
}
|