Index: Externals/Eagle/lib/Eagle1.0/vendor.eagle
==================================================================
--- Externals/Eagle/lib/Eagle1.0/vendor.eagle
+++ Externals/Eagle/lib/Eagle1.0/vendor.eagle
@@ -31,10 +31,27 @@
# support namespaces ourselves, we do not want to pollute the global
# namespace if this script actually ends up being evaluated in Tcl.
#
namespace eval ::Eagle {
if {[isEagle]} then {
+ proc checkForVendorQuiet { {name ""} } {
+ if {[info exists ::env(checkForVendorQuiet)]} then {
+ return true
+ }
+
+ if {[string length $name] > 0} then {
+ set envVarName [appendArgs quiet [string toupper \
+ [string index $name 0]] [string range $name 1 end]]
+
+ if {[info exists ::env($envVarName)]} then {
+ return true
+ }
+ }
+
+ return false
+ }
+
proc checkForTestOverrides { channel varNames quiet } {
set result 0
foreach varName $varNames {
if {![uplevel 1 [list info exists $varName]]} then {
@@ -343,11 +360,11 @@
test_clr_v4 test_configuration test_configurations test_constraints \
test_machine test_net_fx test_net_fx_2005 test_net_fx_2008 \
test_net_fx_2010 test_net_fx_2012 test_net_fx_2013 test_net_fx_2015 \
test_overrides test_platform test_suite test_year test_years \
test_year_clr_v2 test_year_clr_v4 vendor_directory \
- vendor_test_directory]}] false
+ vendor_test_directory]}] [checkForVendorQuiet checkForTestOverrides]
#
# NOTE: Set the name of the running test suite, if necessary.
#
if {![info exists test_suite]} then {
@@ -391,11 +408,11 @@
# however, this will not be done if the variable was not created
# by us.
#
addTestSuiteToAutoPath stdout \
[expr {$have_vendor_directory ? "" : "vendor_directory"}] \
- [info exists ::env(quietAddTestSuiteToAutoPath)]
+ [checkForVendorQuiet addTestSuiteToAutoPath]
unset have_vendor_directory
#
# NOTE: This procedure will attempt to find the vendor-specific testing
@@ -403,22 +420,22 @@
# above to point to the directory; however, this will not be done
# if the variable was not created by us.
#
findInterpreterTestPath stdout $vendor_directory \
[expr {$have_vendor_test_directory ? "" : "vendor_test_directory"}] \
- [info exists ::env(quietFindInterpreterTestPath)]
+ [checkForVendorQuiet findInterpreterTestPath]
unset have_vendor_test_directory
#
# NOTE: If we actually found a vendor-specific testing infrastructure
# directory then modify the TestPath property of the current
# interpreter to point directly to it.
#
if {[string length $vendor_test_directory] > 0} then {
- setupInterpreterTestPath stdout $vendor_test_directory [info exists \
- ::env(quietSetupInterpreterTestPath)]
+ setupInterpreterTestPath stdout $vendor_test_directory \
+ [checkForVendorQuiet setupInterpreterTestPath]
}
}
#
# HACK: Prevent the Eagle core test suite infrastructure from checking
Index: Setup/data/verify.lst
==================================================================
--- Setup/data/verify.lst
+++ Setup/data/verify.lst
@@ -832,10 +832,11 @@
Tests/template/empty.eagle
Tests/thread.eagle
Tests/tkt-00f86f9739.eagle
Tests/tkt-0a32885109.eagle
Tests/tkt-0d5b1ef362.eagle
+ Tests/tkt-0e48e80333.eagle
Tests/tkt-0ed01c447c.eagle
Tests/tkt-17045010df.eagle
Tests/tkt-1c456ae75f.eagle
Tests/tkt-1f7bfff467.eagle
Tests/tkt-201128cc88.eagle
Index: System.Data.SQLite/SQLite3.cs
==================================================================
--- System.Data.SQLite/SQLite3.cs
+++ System.Data.SQLite/SQLite3.cs
@@ -65,10 +65,11 @@
/// The opaque pointer returned to us by the sqlite provider
///
protected internal SQLiteConnectionHandle _sql;
protected string _fileName;
protected SQLiteConnectionFlags _flags;
+ private bool _setLogCallback;
protected bool _usePool;
protected int _poolVersion;
private int _cancelCount;
#if (NET_35 || NET_40 || NET_45 || NET_451 || NET_452 || NET_46 || NET_461 || NET_462 || NET_47) && !PLATFORM_COMPACTFRAMEWORK
@@ -190,11 +191,11 @@
#if INTEROP_VIRTUAL_TABLE
DisposeModules();
#endif
- Close(false); /* Disposing, cannot throw. */
+ Close(true); /* Disposing, cannot throw. */
}
}
finally
{
base.Dispose(disposing);
@@ -243,11 +244,11 @@
// It isn't necessary to cleanup any functions we've registered. If the connection
// goes to the pool and is resurrected later, re-registered functions will overwrite the
// previous functions. The SQLiteFunctionCookieHandle will take care of freeing unmanaged
// resources belonging to the previously-registered functions.
- internal override void Close(bool canThrow)
+ internal override void Close(bool disposing)
{
if (_sql != null)
{
if (!_sql.OwnHandle)
{
@@ -255,14 +256,17 @@
return;
}
bool unbindFunctions = ((_flags & SQLiteConnectionFlags.UnbindFunctionsOnClose)
== SQLiteConnectionFlags.UnbindFunctionsOnClose);
+
+ retry:
if (_usePool)
{
- if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))
+ if (SQLiteBase.ResetConnection(_sql, _sql, !disposing) &&
+ UnhookNativeCallbacks(true, !disposing))
{
if (unbindFunctions)
{
if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
{
@@ -291,31 +295,42 @@
SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);
SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
SQLiteConnectionEventType.ClosedToPool, null, null,
null, null, _sql, _fileName, new object[] {
- typeof(SQLite3), canThrow, _fileName, _poolVersion }));
+ typeof(SQLite3), !disposing, _fileName, _poolVersion }));
#if !NET_COMPACT_20 && TRACE_CONNECTION
Trace.WriteLine(HelperMethods.StringFormat(
CultureInfo.CurrentCulture,
"Close (Pool) Success: {0}",
HandleToString()));
#endif
}
-#if !NET_COMPACT_20 && TRACE_CONNECTION
else
{
+#if !NET_COMPACT_20 && TRACE_CONNECTION
Trace.WriteLine(HelperMethods.StringFormat(
CultureInfo.CurrentCulture,
"Close (Pool) Failure: {0}",
HandleToString()));
+#endif
+
+ //
+ // NOTE: This connection cannot be added to the pool;
+ // therefore, just use the normal disposal
+ // procedure on it.
+ //
+ _usePool = false;
+ goto retry;
}
-#endif
}
else
{
+ /* IGNORED */
+ UnhookNativeCallbacks(disposing, !disposing);
+
if (unbindFunctions)
{
if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
{
#if !NET_COMPACT_20 && TRACE_CONNECTION
@@ -945,11 +960,11 @@
// NOTE: If the database connection is currently open, attempt to
// close it now. This must be done because the file name or
// other parameters that may impact the underlying database
// connection may have changed.
//
- if (_sql != null) Close(true);
+ if (_sql != null) Close(false);
//
// NOTE: If the connection was not closed successfully, throw an
// exception now.
//
@@ -2942,12 +2957,344 @@
internal override SQLiteErrorCode SetLogCallback(SQLiteLogCallback func)
{
SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3_config_log(
SQLiteConfigOpsEnum.SQLITE_CONFIG_LOG, func, IntPtr.Zero);
+ if (rc == SQLiteErrorCode.Ok)
+ _setLogCallback = (func != null);
+
return rc;
}
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Appends an error message and an appropriate line-ending to a
+ /// instance. This is useful because the .NET Compact Framework has a slightly different set
+ /// of supported methods for the class.
+ ///
+ ///
+ /// The instance to append to.
+ ///
+ ///
+ /// The message to append. It will be followed by an appropriate line-ending.
+ ///
+ private static void AppendError(
+ StringBuilder builder,
+ string message
+ )
+ {
+ if (builder == null)
+ return;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+ builder.AppendLine(message);
+#else
+ builder.Append(message);
+ builder.Append("\r\n");
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to cause the SQLite native library to invalidate
+ /// its function pointers that refer to this instance. This is necessary
+ /// to prevent calls from native code into delegates that may have been
+ /// garbage collected. Normally, these types of issues can only arise for
+ /// connections that are added to the pool; howver, it is good practice to
+ /// unconditionally invalidate function pointers that may refer to objects
+ /// being disposed.
+ ///
+ /// Non-zero to also invalidate global function pointers (i.e. those that
+ /// are not directly associated with this connection on the native side).
+ ///
+ ///
+ /// Non-zero if this method is being executed within a context where it can
+ /// throw an exception in the event of failure; otherwise, zero.
+ ///
+ ///
+ ///
+ /// Non-zero if this method was successful; otherwise, zero.
+ ///
+ private bool UnhookNativeCallbacks(
+ bool includeGlobal,
+ bool canThrow
+ )
+ {
+ //
+ // NOTE: Initially, this method assumes success. Then, if any attempt
+ // to invalidate a function pointer fails, the overall result is
+ // set to failure. However, this will not prevent further
+ // attempts, if any, to invalidate subsequent function pointers.
+ //
+ bool result = true;
+ SQLiteErrorCode rc = SQLiteErrorCode.Ok;
+ StringBuilder builder = new StringBuilder();
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Rollback Hook (Per-Connection)
+ try
+ {
+ SetRollbackHook(null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset rollback hook: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset rollback hook");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Trace Callback (Per-Connection)
+ try
+ {
+ SetTraceCallback(null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset trace callback: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset trace callback");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Commit Hook (Per-Connection)
+ try
+ {
+ SetCommitHook(null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset commit hook: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset commit hook");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Update Hook (Per-Connection)
+ try
+ {
+ SetUpdateHook(null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset update hook: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset update hook");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Authorizer Hook (Per-Connection)
+ try
+ {
+ SetAuthorizerHook(null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset authorizer hook: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset authorizer hook");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Progress Hook (Per-Connection)
+ try
+ {
+ SetProgressHook(0, null); /* throw */
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset progress hook: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset progress hook");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ #region Log Callback (Global)
+ //
+ // NOTE: We have to be careful here because the log callback
+ // is not per-connection on the native side. It should
+ // only be unset by this method if this instance was
+ // responsible for setting it.
+ //
+ if (includeGlobal && _setLogCallback)
+ {
+ try
+ {
+ SQLiteErrorCode rc2 = SetLogCallback(null); /* throw */
+
+ if (rc2 != SQLiteErrorCode.Ok)
+ {
+ AppendError(builder, "could not unset log callback");
+ rc = rc2;
+
+ result = false;
+ }
+ }
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ catch (Exception e)
+#else
+ catch (Exception)
+#endif
+ {
+#if !NET_COMPACT_20 && TRACE_CONNECTION
+ try
+ {
+ Trace.WriteLine(HelperMethods.StringFormat(
+ CultureInfo.CurrentCulture,
+ "Failed to unset log callback: {0}",
+ e)); /* throw */
+ }
+ catch
+ {
+ // do nothing.
+ }
+#endif
+
+ AppendError(builder, "failed to unset log callback");
+ rc = SQLiteErrorCode.Error;
+
+ result = false;
+ }
+ }
+ #endregion
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ if (!result && canThrow)
+ throw new SQLiteException(rc, builder.ToString());
+
+ return result;
+ }
///////////////////////////////////////////////////////////////////////////////////////////////
///
/// Creates a new SQLite backup object based on the provided destination
Index: System.Data.SQLite/SQLite3_UTF16.cs
==================================================================
--- System.Data.SQLite/SQLite3_UTF16.cs
+++ System.Data.SQLite/SQLite3_UTF16.cs
@@ -136,11 +136,11 @@
// NOTE: If the database connection is currently open, attempt to
// close it now. This must be done because the file name or
// other parameters that may impact the underlying database
// connection may have changed.
//
- if (_sql != null) Close(true);
+ if (_sql != null) Close(false);
//
// NOTE: If the connection was not closed successfully, throw an
// exception now.
//
Index: System.Data.SQLite/SQLiteBase.cs
==================================================================
--- System.Data.SQLite/SQLiteBase.cs
+++ System.Data.SQLite/SQLiteBase.cs
@@ -127,12 +127,12 @@
///
///
/// After the database has been closed implemeters should call SQLiteFunction.UnbindFunctions() to deallocate all interop allocated
/// memory associated with the user-defined functions and collating sequences tied to the closed connection.
///
- /// Non-zero if the operation is allowed to throw exceptions, zero otherwise.
- internal abstract void Close(bool canThrow);
+ /// Non-zero if connection is being disposed, zero otherwise.
+ internal abstract void Close(bool disposing);
///
/// Sets the busy timeout on the connection. SQLiteCommand will call this before executing any command.
///
/// The number of milliseconds to wait before returning SQLITE_BUSY
internal abstract void SetTimeout(int nTimeoutMS);
Index: System.Data.SQLite/SQLiteConnection.cs
==================================================================
--- System.Data.SQLite/SQLiteConnection.cs
+++ System.Data.SQLite/SQLiteConnection.cs
@@ -2919,11 +2919,11 @@
_enlistment = null;
}
#endif
if (_sql != null)
{
- _sql.Close(!_disposing);
+ _sql.Close(_disposing);
_sql = null;
}
_transactionLevel = 0;
_transactionSequence = 0;
}
@@ -4845,11 +4845,11 @@
CheckDisposed();
if (_sql == null)
throw new InvalidOperationException("Database connection not valid for shutdown.");
- _sql.Close(true); /* NOTE: MUST be closed before shutdown. */
+ _sql.Close(false); /* NOTE: MUST be closed before shutdown. */
SQLiteErrorCode rc = _sql.Shutdown();
#if !NET_COMPACT_20 && TRACE_CONNECTION
if (rc != SQLiteErrorCode.Ok)
System.Diagnostics.Trace.WriteLine(HelperMethods.StringFormat(
ADDED Tests/tkt-0e48e80333.eagle
Index: Tests/tkt-0e48e80333.eagle
==================================================================
--- /dev/null
+++ Tests/tkt-0e48e80333.eagle
@@ -0,0 +1,298 @@
+###############################################################################
+#
+# tkt-0e48e80333.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-0e48e80333-1.1 {unhook delegates on pooled close} -setup {
+ moveEagleShellMdaConfig false
+ saveMdaConfigEnvironment
+} -body {
+ set configFileName [writeEagleShellMdaConfig [string trim {
+
+
+
+
+
+
+ }]]
+
+ set scriptFileName [file tempname]
+
+ writeFile $scriptFileName [string trim {
+ package require Eagle
+ package require Eagle.Library
+ package require Eagle.Test
+ package require System.Data.SQLite.Test
+
+ proc traceCallback { sender e } {
+ lappend ::result [$e Statement]
+ lappend ::result [$sender IsReadOnly null]
+ }
+
+ object load System.Data.SQLite
+ set ::test_channel stdout
+
+ setupDb [set fileName tkt-0e48e80333-1.1.db]
+ sql execute $db {CREATE TABLE t1(x);}
+ cleanupDb $fileName db true false false
+
+ set ::result ""
+
+ set count 10
+
+ set sql [string trim { \
+ INSERT INTO t1 (x) VALUES(1); \
+ }]
+
+ for {set i 0} {$i < $count} {incr i} {
+ setupDb $fileName \
+ "" "" "" "" "Pooling=True;" false false
+
+ set connection [getDbConnection]
+ $connection add_Trace traceCallback
+
+ sql execute $db $sql
+
+ freeDbConnection
+ cleanupDb $fileName db true false false
+ }
+
+ if {$::result eq [lrepeat $count $sql False]} then {
+ exit Success
+ } else {
+ exit Failure
+ }
+ }]
+
+ set env(COMPLUS_MDA) 1; # enable MDA config file.
+
+ set code [catch {
+ execTestShell [list \
+ -eventflags Wait -success Success -stdout output] \
+ -preInitialize [appendArgs \" "set no(logFileName) 1" \"] \
+ -file [appendArgs \" $scriptFileName \"] \
+ -logFile [appendArgs \" [getTestLog] \"]
+ } error]
+
+ tlog "---- BEGIN STDOUT OUTPUT\n"
+ tlog $output
+ tlog "\n---- END STDOUT OUTPUT\n"
+
+ set code
+} -cleanup {
+ catch {file delete $scriptFileName}
+ catch {file delete $configFileName}
+
+ unset -nocomplain code output error scriptFileName configFileName
+
+ restoreMdaConfigEnvironment
+ moveEagleShellMdaConfig true
+} -constraints {eagle dotNet testExec command.object monoBug28 command.sql\
+compile.DATA SQLite System.Data.SQLite} -result {0}}
+
+###############################################################################
+
+runTest {test tkt-0e48e80333-1.2 {delegate MDA on pooled close} -setup {
+ moveEagleShellMdaConfig false
+ saveEnvironmentVariables [list checkForVendorQuiet]
+ saveMdaConfigEnvironment
+
+ setupDb [set fileName tkt-0e48e80333-1.2.db]
+} -body {
+ set configFileName [writeEagleShellMdaConfig [string trim {
+
+
+
+
+
+
+ }]]
+
+ set scriptFileName [file tempname]
+
+ writeFile $scriptFileName [string trim {
+ package require Eagle
+ package require Eagle.Library
+ package require Eagle.Test
+ package require System.Data.SQLite.Test
+
+ set ::test_channel ""; # disable [tputs]
+
+ set id [object invoke Interpreter.GetActive NextId]
+ set dataSource [file join [getDatabaseDirectory] $fileName]
+
+ set count(1) 1000; # thread work-item count
+ set count(2) 1000; # per-thread query count
+ set count(3) [expr {$count(1) * $count(2)}]; # total query count
+ set count(4) [expr {0.5 * $count(3)}]; # timeout in seconds
+ set count(5) 10; # busy loop sleep milliseconds
+
+ set sql { \
+ SELECT 1; \
+ }
+
+ unset -nocomplain results errors
+
+ set code [compileCSharpWith [subst {
+ using System;
+ using System.Data;
+ using System.Data.SQLite;
+ using System.Threading;
+
+ namespace _Dynamic${id}
+ {
+ public static class Test${id}
+ {
+ #region Private Static Data
+ private static long count;
+
+ /////////////////////////////////////////////////////////////////////
+
+ private static SQLiteTraceEventHandler handler;
+ #endregion
+
+ /////////////////////////////////////////////////////////////////////
+
+ #region Public Static Methods
+ public static void TraceEventHandler(
+ object sender,
+ TraceEventArgs e
+ )
+ {
+ /* IGNORED */
+ Interlocked.Increment(ref count);
+ }
+
+ /////////////////////////////////////////////////////////////////////
+
+ public static SQLiteConnection MakeConnection()
+ {
+ SQLiteConnection connection = new SQLiteConnection(
+ "Data Source=${dataSource};Journal Mode=Wal;Pooling=true;" +
+ "[getFlagsProperty AllowNestedTransactions]");
+
+ connection.Open();
+ connection.Trace += handler;
+
+ return connection;
+ }
+
+ /////////////////////////////////////////////////////////////////////
+
+ public static long ThreadedPoolTraceTest()
+ {
+ for (int index1 = 0; index1 < ${count(1)}; index1++)
+ {
+ ThreadPool.QueueUserWorkItem(delegate(object state) {
+ using (SQLiteConnection connection = MakeConnection())
+ {
+ for (int index2 = 0; index2 < ${count(2)}; index2++)
+ {
+ using (SQLiteTransaction transaction =
+ connection.BeginTransaction())
+ {
+ using (SQLiteCommand command =
+ connection.CreateCommand())
+ {
+ command.CommandText = "[subst ${sql}]";
+ command.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+ });
+
+ GC.Collect();
+ }
+
+ DateTime start = DateTime.UtcNow;
+
+ while (true)
+ {
+ if (Interlocked.CompareExchange(ref count, 0, 0) >= ${count(3)})
+ break;
+
+ if (DateTime.UtcNow.Subtract(start).TotalSeconds >= ${count(4)})
+ break;
+
+ Thread.Sleep(${count(5)});
+ }
+
+ return Interlocked.CompareExchange(ref count, 0, 0);
+ }
+
+ /////////////////////////////////////////////////////////////////////
+
+ public static void Main()
+ {
+ handler = new SQLiteTraceEventHandler(TraceEventHandler);
+ }
+ #endregion
+ }
+ }
+ }] true true true results errors System.Data.SQLite.dll]
+
+ puts stdout [list $code $results \
+ [expr {[info exists errors] ? $errors : ""}] \
+ [expr {$code eq "Ok" ? [catch {
+ object invoke _Dynamic${id}.Test${id} Main
+ } result] : [set result ""]}] $result \
+ [expr {$code eq "Ok" ? [catch {
+ object invoke _Dynamic${id}.Test${id} ThreadedPoolTraceTest
+ } result] : [set result ""]}] $result]
+ }]
+
+ set env(checkForVendorQuiet) 1
+ set env(COMPLUS_MDA) 1; # enable MDA config file.
+
+ set code [catch {
+ execTestShell [list \
+ -eventflags Wait -success Success -stdout output] \
+ -preInitialize [appendArgs \" "set fileName {" $fileName }\"] \
+ -preInitialize [appendArgs \" "set no(logFileName) 1" \"] \
+ -file [appendArgs \" $scriptFileName \"] \
+ -logFile [appendArgs \" [getTestLog] \"]
+ } error]
+
+ tlog "---- BEGIN STDOUT OUTPUT\n"
+ tlog $output
+ tlog "\n---- END STDOUT OUTPUT\n"
+
+ list $code [string trim $error]
+} -cleanup {
+ cleanupDb $fileName
+
+ catch {file delete $scriptFileName}
+ catch {file delete $configFileName}
+
+ unset -nocomplain code output error scriptFileName configFileName
+ unset -nocomplain db fileName
+
+ restoreMdaConfigEnvironment
+ restoreEnvironmentVariables [list checkForVendorQuiet]
+ moveEagleShellMdaConfig true
+} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
+System.Data.SQLite compileCSharp} -match regexp -result {^0 \{Ok\
+System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\} 0 1000\}$}}
+
+###############################################################################
+
+runSQLiteTestEpilogue
+runTestEpilogue
Index: Tests/tkt-d4728aecb7.eagle
==================================================================
--- Tests/tkt-d4728aecb7.eagle
+++ Tests/tkt-d4728aecb7.eagle
@@ -80,14 +80,11 @@
package require Eagle.Test
package require System.Data.SQLite.Test
moveSystemDataSQLiteDllConfig false
- set fileName [file join \
- [getBinaryDirectory] System.Data.SQLite.dll.config]
-
- writeFile $fileName [string trim {
+ set fileName [writeSystemDataSQLiteDllConfig [string trim {
@@ -95,11 +92,11 @@
value="prfx2/%PreLoadSQLite_TargetFramework%/sufx2" />
- }]
+ }]]
object load -loadtype Bytes [base64 encode [readFile [file join \
[getBinaryDirectory] System.Data.SQLite.dll]]]
set result [list]
Index: lib/System.Data.SQLite/common.eagle
==================================================================
--- lib/System.Data.SQLite/common.eagle
+++ lib/System.Data.SQLite/common.eagle
@@ -1198,10 +1198,115 @@
"\", it does not exist\n"]
}
}
}
}
+
+ proc writeSystemDataSQLiteDllConfig { data {verbose true} } {
+ set directory [getBinaryDirectory]
+
+ if {[string length $directory] == 0} then {
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- skipped moving \"System.Data.SQLite.dll.config\", " \
+ "no binary directory\n"]
+ }
+
+ return
+ }
+
+ set fileName [file normalize \
+ [file join $directory System.Data.SQLite.dll.config]]
+
+ writeFile $fileName $data
+
+ if {$verbose} then {
+ tputs $::test_channel \
+ "---- wrote \"System.Data.SQLite.dll.config\"\n"
+ }
+
+ return $fileName
+ }
+
+ proc moveEagleShellMdaConfig { {restore false} {verbose true} } {
+ set directory [getBinaryDirectory]
+
+ if {[string length $directory] == 0} then {
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- skipped moving \"EagleShell.exe.mda.config\", " \
+ "no binary directory\n"]
+ }
+
+ return
+ }
+
+ set fileName(1) [file normalize \
+ [file join $directory EagleShell.exe.mda.config]]
+
+ set fileName(2) [appendArgs $fileName(1) .moved]
+
+ if {$restore} then {
+ if {[file exists $fileName(2)]} then {
+ file rename $fileName(2) $fileName(1)
+
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- moved \"" $fileName(2) "\" to \"" \
+ $fileName(1) \"\n]
+ }
+ } else {
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- skipped moving \"" $fileName(2) \
+ "\", it does not exist\n"]
+ }
+ }
+ } else {
+ if {[file exists $fileName(1)]} then {
+ file rename $fileName(1) $fileName(2)
+
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- moved \"" $fileName(1) "\" to \"" \
+ $fileName(2) \"\n]
+ }
+ } else {
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- skipped moving \"" $fileName(1) \
+ "\", it does not exist\n"]
+ }
+ }
+ }
+ }
+
+ proc writeEagleShellMdaConfig { data {verbose true} } {
+ set directory [getBinaryDirectory]
+
+ if {[string length $directory] == 0} then {
+ if {$verbose} then {
+ tputs $::test_channel [appendArgs \
+ "---- skipped moving \"EagleShell.exe.mda.config\", " \
+ "no binary directory\n"]
+ }
+
+ return
+ }
+
+ set fileName [file normalize \
+ [file join $directory EagleShell.exe.mda.config]]
+
+ writeFile $fileName $data
+
+ if {$verbose} then {
+ tputs $::test_channel \
+ "---- wrote \"EagleShell.exe.mda.config\"\n"
+ }
+
+ return $fileName
+ }
proc getAppDomainPreamble { {prefix ""} {suffix ""} } {
#
# NOTE: This procedure returns a test setup script fragment suitable for
# evaluation by an interpreter created in an isolated application
@@ -2931,10 +3036,22 @@
#
if {[array size savedEnv] == 0} then {
unset -nocomplain savedEnv
}
}
+
+ proc saveMdaConfigEnvironment {} {
+ upvar 1 savedEnv savedEnv
+
+ saveEnvironmentVariables [list COMPLUS_MDA] savedEnv
+ }
+
+ proc restoreMdaConfigEnvironment {} {
+ upvar 1 savedEnv savedEnv
+
+ restoreEnvironmentVariables [list COMPLUS_MDA] savedEnv
+ }
proc saveGetSettingValueEnvironment {} {
upvar 1 savedEnv savedEnv
saveEnvironmentVariables [list \