Index: Doc/Extra/version.html ================================================================== --- Doc/Extra/version.html +++ Doc/Extra/version.html @@ -52,10 +52,11 @@
  • Add experimental support for the native regexp extension.
  • Never create a new connection wrapper in the SQLiteConnection.Shutdown method. ** Potentially Incompatible Change **
  • Add experimental GetMemoryStatistics, ReleaseMemory, and Shutdown methods to the SQLiteConnection class.
  • Add memory leak detection to the test project for the .NET Compact Framework.
  • Add SQLITE_ENABLE_MEMORY_MANAGEMENT compile-time option to the interop assembly.
  • +
  • Use current isolation level when enlisting into an existing transaction. Fix for [56b42d99c1].
  • Better handling of non-error log messages from the SQLite core library. Pursuant to [44df10ea90].
  • Add TraceWarning connection flag to enable tracing of type mapping failures and disable tracing of them by default. Pursuant to [6d45c782e4].
  • Use 32-bit values to keep track of numeric precision and scale when building the schema table for a query. Fix for [ef2216192d].
  • 1.0.89.0 - October 28, 2013

    Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -1106,10 +1106,37 @@ StateChange(this, localEventArgs); eventArgs = localEventArgs; } } + +#if !PLATFORM_COMPACTFRAMEWORK + /// + /// Determines and returns the fallback default isolation level when one cannot be + /// obtained from an existing connection instance. + /// + /// + /// The fallback default isolation level for this connection instance -OR- + /// if it cannot be determined. + /// + internal static IsolationLevel GetFallbackDefaultIsolationLevel() + { + return DefaultIsolationLevel; + } + + /// + /// Determines and returns the default isolation level for this connection instance. + /// + /// + /// The default isolation level for this connection instance -OR- + /// if it cannot be determined. + /// + internal IsolationLevel GetDefaultIsolationLevel() + { + return _defaultIsolation; + } +#endif /// /// OBSOLETE. Creates a new SQLiteTransaction if one isn't already active on the connection. /// /// This parameter is ignored. Index: System.Data.SQLite/SQLiteEnlistment.cs ================================================================== --- System.Data.SQLite/SQLiteEnlistment.cs +++ System.Data.SQLite/SQLiteEnlistment.cs @@ -8,35 +8,98 @@ #if !PLATFORM_COMPACTFRAMEWORK namespace System.Data.SQLite { using System.Transactions; - internal sealed class SQLiteEnlistment : IEnlistmentNotification, IDisposable + internal sealed class SQLiteEnlistment : IDisposable, IEnlistmentNotification { internal SQLiteTransaction _transaction; internal Transaction _scope; internal bool _disposeConnection; internal SQLiteEnlistment(SQLiteConnection cnn, Transaction scope) { - _transaction = cnn.BeginTransaction(); + _transaction = cnn.BeginTransaction(GetSystemDataIsolationLevel( + cnn, scope)); + _scope = scope; _scope.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None); } - /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + #region Private Methods + private System.Data.IsolationLevel GetSystemDataIsolationLevel( + SQLiteConnection connection, + Transaction transaction + ) + { + if (transaction == null) + { + // + // TODO: Perhaps throw an exception here if the connection + // is null? + // + return (connection != null) ? + connection.GetDefaultIsolationLevel() : + SQLiteConnection.GetFallbackDefaultIsolationLevel(); + } + + System.Transactions.IsolationLevel isolationLevel = + transaction.IsolationLevel; + + // + // TODO: Are these isolation level mappings actually correct? + // + switch (isolationLevel) + { + case IsolationLevel.Chaos: + return System.Data.IsolationLevel.Chaos; + case IsolationLevel.ReadCommitted: + return System.Data.IsolationLevel.ReadCommitted; + case IsolationLevel.ReadUncommitted: + return System.Data.IsolationLevel.ReadUncommitted; + case IsolationLevel.RepeatableRead: + return System.Data.IsolationLevel.RepeatableRead; + case IsolationLevel.Serializable: + return System.Data.IsolationLevel.Serializable; + case IsolationLevel.Snapshot: + return System.Data.IsolationLevel.Snapshot; + case IsolationLevel.Unspecified: + return System.Data.IsolationLevel.Unspecified; + } + + // + // TODO: Perhaps throw an exception here? + // + return SQLiteConnection.GetFallbackDefaultIsolationLevel(); + } + + /////////////////////////////////////////////////////////////////////////// + + private void Cleanup(SQLiteConnection cnn) + { + if (_disposeConnection) + cnn.Dispose(); + + _transaction = null; + _scope = null; + } + #endregion + + /////////////////////////////////////////////////////////////////////////// #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion - /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; private void CheckDisposed() /* throw */ { @@ -44,11 +107,11 @@ if (disposed) throw new ObjectDisposedException(typeof(SQLiteEnlistment).Name); #endif } - /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// private /* protected virtual */ void Dispose(bool disposing) { if (!disposed) { @@ -78,32 +141,22 @@ disposed = true; } } #endregion - /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// #region Destructor ~SQLiteEnlistment() { Dispose(false); } #endregion - /////////////////////////////////////////////////////////////////////////////////////////////// - - private void Cleanup(SQLiteConnection cnn) - { - if (_disposeConnection) - cnn.Dispose(); - - _transaction = null; - _scope = null; - } + /////////////////////////////////////////////////////////////////////////// #region IEnlistmentNotification Members - public void Commit(Enlistment enlistment) { CheckDisposed(); SQLiteConnection cnn = _transaction.Connection; @@ -121,15 +174,19 @@ { Cleanup(cnn); } } + /////////////////////////////////////////////////////////////////////////// + public void InDoubt(Enlistment enlistment) { CheckDisposed(); enlistment.Done(); } + + /////////////////////////////////////////////////////////////////////////// public void Prepare(PreparingEnlistment preparingEnlistment) { CheckDisposed(); @@ -136,10 +193,12 @@ if (_transaction.IsValid(false) == false) preparingEnlistment.ForceRollback(); else preparingEnlistment.Prepared(); } + + /////////////////////////////////////////////////////////////////////////// public void Rollback(Enlistment enlistment) { CheckDisposed(); @@ -154,10 +213,9 @@ finally { Cleanup(cnn); } } - #endregion } } -#endif // !PLATFORM_COMPACT_FRAMEWORK +#endif // !PLATFORM_COMPACT_FRAMEWORK Index: Tests/common.eagle ================================================================== --- Tests/common.eagle +++ Tests/common.eagle @@ -1265,12 +1265,14 @@ # # NOTE: Create the base command to evaluate and add the property settings # that are almost always needed by our unit tests (i.e. the System # and System.Data assembly references). # - set command [list compileCSharp $text $memory $symbols $strict results \ - errors $add System.dll $add System.Data.dll $add System.Xml.dll] + set command [list \ + compileCSharp $text $memory $symbols $strict results errors \ + $add System.dll $add System.Data.dll $add System.Transactions.dll \ + $add System.Xml.dll] # # NOTE: Add all the provided file names as assembly references. # foreach fileName $fileNames { ADDED Tests/tkt-56b42d99c1.eagle Index: Tests/tkt-56b42d99c1.eagle ================================================================== --- /dev/null +++ Tests/tkt-56b42d99c1.eagle @@ -0,0 +1,109 @@ +############################################################################### +# +# tkt-56b42d99c1.eagle -- +# +# Written by Joe Mistachkin. +# Released to the public domain, use at your own risk! +# +############################################################################### + +package require Eagle +package require Eagle.Library +package require Eagle.Test + +runTestPrologue + +############################################################################### + +package require System.Data.SQLite.Test +runSQLiteTestPrologue + +############################################################################### + +runTest {test tkt-56b42d99c1-1.1 {enlisted transaction isolation} -setup { + setupDb [set fileName tkt-56b42d99c1-1.1.db] +} -body { + set id [object invoke Interpreter.GetActive NextId] + set dataSource [file join [getDatabaseDirectory] $fileName] + + unset -nocomplain results errors + + set code [compileCSharpWith [subst { + using System.Data.SQLite; + using System.Reflection; + using System.Transactions; + + namespace _Dynamic${id} + { + public static class Test${id} + { + public static bool TryEnlistInTransaction() + { + TransactionOptions transactionOptions = new TransactionOptions(); + transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted; + + using (TransactionScope transactionScope = new TransactionScope( + TransactionScopeOption.Required, transactionOptions)) + { + using (SQLiteConnection connection1 = new SQLiteConnection( + "Data Source=${dataSource};")) + { + connection1.Open(); + + using (SQLiteConnection connection2 = new SQLiteConnection( + "Data Source=${dataSource};")) + { + connection2.Open(); + + BindingFlags bindingFlags = BindingFlags.Instance | + BindingFlags.NonPublic | BindingFlags.GetField; + + FieldInfo fieldInfo1 = connection1.GetType().GetField( + "_enlistment", bindingFlags); + + object enlistment1 = fieldInfo1.GetValue(connection1); + object enlistment2 = fieldInfo1.GetValue(connection2); + + FieldInfo fieldInfo2 = enlistment1.GetType().GetField( + "_transaction", bindingFlags); + + SQLiteTransaction transaction1 = + (SQLiteTransaction)fieldInfo2.GetValue(enlistment1); + + SQLiteTransaction transaction2 = + (SQLiteTransaction)fieldInfo2.GetValue(enlistment2); + + return (transaction1.IsolationLevel == + transaction2.IsolationLevel); + } + } + } + } + + /////////////////////////////////////////////////////////////////////// + + public static void Main() + { + // do nothing. + } + } + } + }] true true true results errors System.Data.SQLite.dll] + + list $code $results \ + [expr {[info exists errors] ? $errors : ""}] \ + [expr {$code eq "Ok" ? [catch { + object invoke _Dynamic${id}.Test${id} TryEnlistInTransaction + } result] : [set result ""]}] $result +} -cleanup { + cleanupDb $fileName + + unset -nocomplain result results errors code dataSource id db fileName +} -constraints {eagle monoBug28 command.sql compile.DATA SQLite\ +System.Data.SQLite compileCSharp} -match regexp -result {^Ok\ +System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 True$}} + +############################################################################### + +runSQLiteTestEpilogue +runTestEpilogue Index: readme.htm ================================================================== --- readme.htm +++ readme.htm @@ -197,10 +197,11 @@
  • Add experimental support for the native regexp extension.
  • Never create a new connection wrapper in the SQLiteConnection.Shutdown method. ** Potentially Incompatible Change **
  • Add experimental GetMemoryStatistics, ReleaseMemory, and Shutdown methods to the SQLiteConnection class.
  • Add memory leak detection to the test project for the .NET Compact Framework.
  • Add SQLITE_ENABLE_MEMORY_MANAGEMENT compile-time option to the interop assembly.
  • +
  • Use current isolation level when enlisting into an existing transaction. Fix for [56b42d99c1].
  • Better handling of non-error log messages from the SQLite core library. Pursuant to [44df10ea90].
  • Add TraceWarning connection flag to enable tracing of type mapping failures and disable tracing of them by default. Pursuant to [6d45c782e4].
  • Use 32-bit values to keep track of numeric precision and scale when building the schema table for a query. Fix for [ef2216192d].
  • Index: www/news.wiki ================================================================== --- www/news.wiki +++ www/news.wiki @@ -13,10 +13,11 @@

  • Add experimental support for the native regexp extension.
  • Never create a new connection wrapper in the SQLiteConnection.Shutdown method. ** Potentially Incompatible Change **
  • Add experimental GetMemoryStatistics, ReleaseMemory, and Shutdown methods to the SQLiteConnection class.
  • Add memory leak detection to the test project for the .NET Compact Framework.
  • Add SQLITE_ENABLE_MEMORY_MANAGEMENT compile-time option to the interop assembly.
  • +
  • Use current isolation level when enlisting into an existing transaction. Fix for [56b42d99c1].
  • Better handling of non-error log messages from the SQLite core library. Pursuant to [44df10ea90].
  • Add TraceWarning connection flag to enable tracing of type mapping failures and disable tracing of them by default. Pursuant to [6d45c782e4].
  • Use 32-bit values to keep track of numeric precision and scale when building the schema table for a query. Fix for [ef2216192d].