//
// Mono.Data.Sqlite.SQLiteTransaction.cs
//
// Author(s):
// Robert Simpson (robert@blackcastlesoft.com)
//
// Adapted and modified for the Mono Project by
// Marek Habersack (grendello@gmail.com)
//
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
// Copyright (C) 2007 Marek Habersack
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/********************************************************
* 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!
********************************************************/
#if NET_2_0
namespace Mono.Data.Sqlite
{
using System;
using System.Data;
using System.Data.Common;
///
/// Sqlite implementation of DbTransaction.
///
public sealed class SqliteTransaction : DbTransaction
{
///
/// The connection to which this transaction is bound
///
internal SqliteConnection _cnn;
internal long _version; // Matches the version of the connection
///
/// Constructs the transaction object, binding it to the supplied connection
///
/// The connection to open a transaction on
/// TRUE to defer the writelock, or FALSE to lock immediately
internal SqliteTransaction(SqliteConnection connection, bool deferredLock)
{
_cnn = connection;
_version = _cnn._version;
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;
}
}
}
///
/// Commits the current transaction.
///
public override void Commit()
{
IsValid(true);
if (--_cnn._transactionLevel == 0)
{
try
{
using (SqliteCommand cmd = _cnn.CreateCommand())
{
cmd.CommandText = "COMMIT";
cmd.ExecuteNonQuery();
}
}
finally
{
_cnn = null;
}
}
else
{
_cnn = null;
}
}
///
/// Returns the underlying connection to which this transaction applies.
///
public new SqliteConnection Connection
{
get { return _cnn; }
}
///
/// Forwards to the local Connection property
///
protected override DbConnection DbConnection
{
get { return Connection; }
}
///
/// Disposes the transaction. If it is currently active, any changes are rolled back.
///
protected override void Dispose(bool disposing)
{
if (IsValid(false))
Rollback();
_cnn = null;
base.Dispose(disposing);
}
///
/// Gets the isolation level of the transaction. Sqlite only supports Serializable transactions.
///
public override IsolationLevel IsolationLevel
{
get { return IsolationLevel.Serializable; }
}
///
/// Rolls back the active transaction.
///
public override void Rollback()
{
IsValid(true);
try
{
using (SqliteCommand cmd = _cnn.CreateCommand())
{
cmd.CommandText = "ROLLBACK";
cmd.ExecuteNonQuery();
}
_cnn._transactionLevel = 0;
}
finally
{
_cnn = null;
}
}
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;
}
}
}
#endif