System.Data.SQLite
Check-in [8e2c95ad40]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Avoid throwing non-fatal exceptions during connection disposal. Make the handle checking and disposal code more consistent. Update version history docs with the latest changes. Allow stress test to optionally skip some workloads.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8e2c95ad40fa6854b55bfb504f3bd710b2a049bb
User & Date: mistachkin 2012-10-06 07:05:42
Context
2012-10-06
23:57
Update the master release archive manifest. check-in: a2cb6af104 user: mistachkin tags: trunk
07:05
Avoid throwing non-fatal exceptions during connection disposal. Make the handle checking and disposal code more consistent. Update version history docs with the latest changes. Allow stress test to optionally skip some workloads. check-in: 8e2c95ad40 user: mistachkin tags: trunk
05:58
Remove superfluous Unicode related defines in the native project files. check-in: e84d4d5613 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Doc/Extra/version.html.

57
58
59
60
61
62
63



64
65
66
67
68
69
70
      <li>Make the test project for the .NET Compact Framework more flexible.</li>
      <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
      <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>



    </ul>
    <p><b>1.0.82.0 - September 3, 2012</b></p>
    <ul>
      <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_14.html">SQLite 3.7.14</a>.</li>
      <li>Properly handle quoted data source values in the connection string. Fix for <a href="http://system.data.sqlite.org/index.html/info/8c3bee31c8">[8c3bee31c8]</a>.</li>
      <li>The <a href="http://nuget.org/packages/System.Data.SQLite">primary NuGet package</a> now supports x86 / x64 and the .NET Framework 2.0 / 4.0 (i.e. in a single package).</li>
      <li>Change the default value for the Synchronous connection string property to Full to match the default used by the SQLite core library itself.&nbsp;<b>** Potentially Incompatible Change **</b></li>







>
>
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
      <li>Make the test project for the .NET Compact Framework more flexible.</li>
      <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
      <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Implement more robust locking semantics for the CriticalHandle derived classes when compiled for the .NET Compact Framework.</li>
      <li>Cache column indexes are they are looked up when using the SQLiteDataReader to improve performance.</li>
      <li>Prevent the SQLiteConnection.Close method from throwing non-fatal exceptions during its disposal.</li>
    </ul>
    <p><b>1.0.82.0 - September 3, 2012</b></p>
    <ul>
      <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_14.html">SQLite 3.7.14</a>.</li>
      <li>Properly handle quoted data source values in the connection string. Fix for <a href="http://system.data.sqlite.org/index.html/info/8c3bee31c8">[8c3bee31c8]</a>.</li>
      <li>The <a href="http://nuget.org/packages/System.Data.SQLite">primary NuGet package</a> now supports x86 / x64 and the .NET Framework 2.0 / 4.0 (i.e. in a single package).</li>
      <li>Change the default value for the Synchronous connection string property to Full to match the default used by the SQLite core library itself.&nbsp;<b>** Potentially Incompatible Change **</b></li>

Changes to System.Data.SQLite/SQLite3.cs.

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
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
                //    ////////////////////////////////////
                //}

                //////////////////////////////////////
                // release unmanaged resources here...
                //////////////////////////////////////

                Close();

                disposed = true;
            }
        }
        finally
        {
            base.Dispose(disposing);
................................................................................

    ///////////////////////////////////////////////////////////////////////////////////////////////

    // 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()
    {
      if (_sql != null)
      {
          if (_usePool)
          {
              SQLiteBase.ResetConnection(_sql, _sql);

              SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);

#if !NET_COMPACT_20 && TRACE_CONNECTION
              Trace.WriteLine(String.Format("Close (Pool): {0}", _sql));







#endif
          }
          else
          {
              _sql.Dispose();
          }
          _sql = null;







|







 







|





|
>
|


|
>
>
>
>
>
>
>







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
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
                //    ////////////////////////////////////
                //}

                //////////////////////////////////////
                // release unmanaged resources here...
                //////////////////////////////////////

                Close(false); /* Disposing, cannot throw. */

                disposed = true;
            }
        }
        finally
        {
            base.Dispose(disposing);
................................................................................

    ///////////////////////////////////////////////////////////////////////////////////////////////

    // 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)
    {
      if (_sql != null)
      {
          if (_usePool)
          {
              if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))
              {
                  SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);

#if !NET_COMPACT_20 && TRACE_CONNECTION
                  Trace.WriteLine(String.Format("Close (Pool) Success: {0}", _sql));
#endif
              }
#if !NET_COMPACT_20 && TRACE_CONNECTION
              else
              {
                  Trace.WriteLine(String.Format("Close (Pool) Failure: {0}", _sql));
              }
#endif
          }
          else
          {
              _sql.Dispose();
          }
          _sql = null;

Changes to System.Data.SQLite/SQLiteBase.cs.

78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571



572
573
574
575
576
577
578
...
584
585
586
587
588
589
590



591



592
593
594

595
596
597
598
599
600
601
602
603
604
605
606

607
608
609
610
611
612
613
    /// <summary>
    /// Closes the currently-open database.
    /// </summary>
    /// <remarks>
    /// 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.
    /// </remarks>

    internal abstract void Close();
    /// <summary>
    /// Sets the busy timeout on the connection.  SQLiteCommand will call this before executing any command.
    /// </summary>
    /// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>
    internal abstract void SetTimeout(int nTimeoutMS);
    /// <summary>
    /// Returns the text of the last error issued by SQLite
................................................................................

#if PLATFORM_COMPACTFRAMEWORK
        lock (hdl.syncRoot)
#else
        lock (hdl)
#endif
        {
            if (hdl.IsClosed || hdl.IsInvalid)
                return "closed or invalid connection handle";

#if !SQLITE_STANDARD
            int len;
            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);
#else
            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);
................................................................................
                n = UnsafeNativeMethods.sqlite3_close(db);
            }
#endif
            if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db));
        }
    }

    internal static void ResetConnection(SQLiteConnectionHandle hdl, IntPtr db)
    {
        if ((hdl == null) || (db == IntPtr.Zero)) return;
#if PLATFORM_COMPACTFRAMEWORK
        lock (hdl.syncRoot)
#else
        lock (hdl)
#endif
        {
            if (hdl.IsInvalid)
                throw new InvalidOperationException("The connection handle is invalid.");

            if (hdl.IsClosed)
                throw new InvalidOperationException("The connection handle is closed.");




            IntPtr stmt = IntPtr.Zero;
            SQLiteErrorCode n;
            do
            {
                stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
                if (stmt != IntPtr.Zero)
................................................................................
#endif
                }
            } while (stmt != IntPtr.Zero);

            if (IsAutocommit(hdl, db) == false) // a transaction is pending on the connection
            {
                n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);



                if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db));



            }
        }
        GC.KeepAlive(hdl);

    }

    internal static bool IsAutocommit(SQLiteConnectionHandle hdl, IntPtr db)
    {
      if (db == IntPtr.Zero) return false;
      if (hdl.IsClosed || hdl.IsInvalid) return false;
#if PLATFORM_COMPACTFRAMEWORK
      lock (hdl.syncRoot)
#else
      lock (hdl)
#endif
      {

          return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1);
      }
#pragma warning disable 162
      GC.KeepAlive(hdl); /* NOTE: Unreachable code. */
#pragma warning restore 162
    }
  }







>
|







 







|







 







|

|






|


|

>
>
>







 







>
>
>
|
>
>
>



>





<






>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
...
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618
619
620
621
622
623
624
    /// <summary>
    /// Closes the currently-open database.
    /// </summary>
    /// <remarks>
    /// 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.
    /// </remarks>
    /// <param name="canThrow">Non-zero if the operation is allowed to throw exceptions, zero otherwise.</param>
    internal abstract void Close(bool canThrow);
    /// <summary>
    /// Sets the busy timeout on the connection.  SQLiteCommand will call this before executing any command.
    /// </summary>
    /// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>
    internal abstract void SetTimeout(int nTimeoutMS);
    /// <summary>
    /// Returns the text of the last error issued by SQLite
................................................................................

#if PLATFORM_COMPACTFRAMEWORK
        lock (hdl.syncRoot)
#else
        lock (hdl)
#endif
        {
            if (hdl.IsInvalid || hdl.IsClosed)
                return "closed or invalid connection handle";

#if !SQLITE_STANDARD
            int len;
            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);
#else
            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);
................................................................................
                n = UnsafeNativeMethods.sqlite3_close(db);
            }
#endif
            if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db));
        }
    }

    internal static bool ResetConnection(SQLiteConnectionHandle hdl, IntPtr db, bool canThrow)
    {
        if ((hdl == null) || (db == IntPtr.Zero)) return false;
#if PLATFORM_COMPACTFRAMEWORK
        lock (hdl.syncRoot)
#else
        lock (hdl)
#endif
        {
            if (canThrow && hdl.IsInvalid)
                throw new InvalidOperationException("The connection handle is invalid.");

            if (canThrow && hdl.IsClosed)
                throw new InvalidOperationException("The connection handle is closed.");

            if (!canThrow && (hdl.IsInvalid || hdl.IsClosed))
                return false;

            IntPtr stmt = IntPtr.Zero;
            SQLiteErrorCode n;
            do
            {
                stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
                if (stmt != IntPtr.Zero)
................................................................................
#endif
                }
            } while (stmt != IntPtr.Zero);

            if (IsAutocommit(hdl, db) == false) // a transaction is pending on the connection
            {
                n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
                if (n != SQLiteErrorCode.Ok)
                {
                    if (canThrow)
                        throw new SQLiteException(n, GetLastError(hdl, db));
                    else
                        return false;
                }
            }
        }
        GC.KeepAlive(hdl);
        return true;
    }

    internal static bool IsAutocommit(SQLiteConnectionHandle hdl, IntPtr db)
    {
      if (db == IntPtr.Zero) return false;

#if PLATFORM_COMPACTFRAMEWORK
      lock (hdl.syncRoot)
#else
      lock (hdl)
#endif
      {
          if (hdl.IsInvalid || hdl.IsClosed) return false;
          return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1);
      }
#pragma warning disable 162
      GC.KeepAlive(hdl); /* NOTE: Unreachable code. */
#pragma warning restore 162
    }
  }

Changes to System.Data.SQLite/SQLiteConnection.cs.

348
349
350
351
352
353
354





355
356
357
358
359
360
361
...
717
718
719
720
721
722
723


724
725
726
727
728
729
730
...
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
    /// </summary>
    private string _connectionString;
    /// <summary>
    /// Nesting level of the transactions open on the connection
    /// </summary>
    internal int _transactionLevel;






    /// <summary>
    /// The default isolation level for new transactions
    /// </summary>
    private IsolationLevel _defaultIsolation;

#if !PLATFORM_COMPACTFRAMEWORK
    /// <summary>
................................................................................
#endif
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////

    protected override void Dispose(bool disposing)
    {


        try
        {
            if (!disposed)
            {
                //if (disposing)
                //{
                //    ////////////////////////////////////
................................................................................

          _sql = null;
          _enlistment = null;
        }
#endif
        if (_sql != null)
        {
          _sql.Close();
          _sql = null;
        }
        _transactionLevel = 0;
      }

      StateChangeEventArgs eventArgs = null;
      OnStateChange(ConnectionState.Closed, ref eventArgs);







>
>
>
>
>







 







>
>







 







|







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
    /// </summary>
    private string _connectionString;
    /// <summary>
    /// Nesting level of the transactions open on the connection
    /// </summary>
    internal int _transactionLevel;

    /// <summary>
    /// If set, then the connection is currently being disposed.
    /// </summary>
    private bool _disposing;

    /// <summary>
    /// The default isolation level for new transactions
    /// </summary>
    private IsolationLevel _defaultIsolation;

#if !PLATFORM_COMPACTFRAMEWORK
    /// <summary>
................................................................................
#endif
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////

    protected override void Dispose(bool disposing)
    {
        _disposing = true;

        try
        {
            if (!disposed)
            {
                //if (disposing)
                //{
                //    ////////////////////////////////////
................................................................................

          _sql = null;
          _enlistment = null;
        }
#endif
        if (_sql != null)
        {
          _sql.Close(!_disposing);
          _sql = null;
        }
        _transactionLevel = 0;
      }

      StateChangeEventArgs eventArgs = null;
      OnStateChange(ConnectionState.Closed, ref eventArgs);

Changes to System.Data.SQLite/SQLiteConnectionPool.cs.

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

                    //
                    // BUGFIX: For ticket [996d13cd87], step #3.  Next, verify that
                    //         the connection handle is actually valid and [still?]
                    //         not closed prior to actually returning it to our
                    //         caller.
                    //
                    if (!hdl.IsClosed && !hdl.IsInvalid)
                    {
                        Interlocked.Increment(ref _poolOpened);
                        return hdl;
                    }
                }
                finally
                {







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

                    //
                    // BUGFIX: For ticket [996d13cd87], step #3.  Next, verify that
                    //         the connection handle is actually valid and [still?]
                    //         not closed prior to actually returning it to our
                    //         caller.
                    //
                    if (!hdl.IsInvalid && !hdl.IsClosed)
                    {
                        Interlocked.Increment(ref _poolOpened);
                        return hdl;
                    }
                }
                finally
                {

Changes to Tests/stress.eagle.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
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
...
532
533
534
535
536
537
538

539
540
541

542
543
544
545
546
547
548
...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test stress-1.1 {multithreaded stress testing} -setup {
  unset -nocomplain result thread index workload srcDb db fileName compiled \
      options count

  #############################################################################

  proc expectedError { error } {
    return [expr {[regexp -- {\sno such table: t1\s} $error] || \
        [regexp -- {\sdatabase is locked\s} $error]}]
  }
................................................................................
  }

  #############################################################################

  set count(0) 1
  set count(1) 5
  set count(2) 300


  if {[info exists argv] && [llength $argv] > 0} then {
    parse options -flags \
        {-StopOnUnknown +IgnoreOnUnknown SkipOnUnknown} -- [list \
        [list null MustHaveIntegerValue -1 -1 -count0 $count(0)] \
        [list null MustHaveIntegerValue -1 -1 -count1 $count(1)] \
        [list null MustHaveIntegerValue -1 -1 -count2 $count(2)]] $argv


    set count(0) $options(-count0,value)
    set count(1) $options(-count1,value)
    set count(2) $options(-count2,value)

  }

  #############################################################################

  tputs $test_channel [appendArgs \
      "---- workloads will repeat " $count(0) " time(s)...\n"]

  tputs $test_channel [appendArgs \
      "---- workloads will have " $count(1) " iteration(s)...\n"]

  tputs $test_channel [appendArgs \
      "---- workloads will wait at least " $count(2) " millisecond(s)...\n"]






  #############################################################################

  set compiled(12) ""
  set compiled(13) ""

  #############################################################################
................................................................................
} -body {
  for {set index(0) 0} {$index(0) < $count(0)} {incr index(0)} {
    sql execute $db "CREATE TABLE IF NOT EXISTS t1(x PRIMARY KEY, y, z);"

    unset -nocomplain thread

    foreach index(1) [lsort -integer [array names workload]] {

      set thread($index(1)) [object create -alias System.Threading.Thread \
          [list apply $workload($index(1)) $fileName(1) $fileName(2) t1 \
          $count(1)]]

    }

    foreach index(1) [list Start Join] {
      foreach index(2) [array names thread] {
        $thread($index(2)) $index(1)
      }
    }
................................................................................
  foreach index(0) [array names workload] {
    catch {
      object removecallback [list apply $workload($index(0)) $fileName(1) \
          $fileName(2) t1 $count(1)]
    }
  }

  unset -nocomplain result thread index workload srcDb db fileName compiled \
      options count times
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result {}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue







|
|







 







>






|
>




>












>
>
>
>
>







 







>
|
|
|
>







 







|
|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
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
...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test stress-1.1 {multithreaded stress testing} -setup {
  unset -nocomplain result thread index workload noWorkload srcDb db \
      fileName compiled options count

  #############################################################################

  proc expectedError { error } {
    return [expr {[regexp -- {\sno such table: t1\s} $error] || \
        [regexp -- {\sdatabase is locked\s} $error]}]
  }
................................................................................
  }

  #############################################################################

  set count(0) 1
  set count(1) 5
  set count(2) 300
  set noWorkload [list]

  if {[info exists argv] && [llength $argv] > 0} then {
    parse options -flags \
        {-StopOnUnknown +IgnoreOnUnknown SkipOnUnknown} -- [list \
        [list null MustHaveIntegerValue -1 -1 -count0 $count(0)] \
        [list null MustHaveIntegerValue -1 -1 -count1 $count(1)] \
        [list null MustHaveIntegerValue -1 -1 -count2 $count(2)] \
        [list null MustHaveListValue -1 -1 -noWorkload $noWorkload]] $argv

    set count(0) $options(-count0,value)
    set count(1) $options(-count1,value)
    set count(2) $options(-count2,value)
    set noWorkload $options(-noWorkload,value)
  }

  #############################################################################

  tputs $test_channel [appendArgs \
      "---- workloads will repeat " $count(0) " time(s)...\n"]

  tputs $test_channel [appendArgs \
      "---- workloads will have " $count(1) " iteration(s)...\n"]

  tputs $test_channel [appendArgs \
      "---- workloads will wait at least " $count(2) " millisecond(s)...\n"]

  if {[llength $noWorkload] > 0} then {
    tputs $test_channel [appendArgs \
        "---- workloads to be skipped... " $noWorkload \n]
  }

  #############################################################################

  set compiled(12) ""
  set compiled(13) ""

  #############################################################################
................................................................................
} -body {
  for {set index(0) 0} {$index(0) < $count(0)} {incr index(0)} {
    sql execute $db "CREATE TABLE IF NOT EXISTS t1(x PRIMARY KEY, y, z);"

    unset -nocomplain thread

    foreach index(1) [lsort -integer [array names workload]] {
      if {[lsearch -exact $noWorkload $index(1)] == -1} then {
        set thread($index(1)) [object create -alias System.Threading.Thread \
            [list apply $workload($index(1)) $fileName(1) $fileName(2) t1 \
            $count(1)]]
      }
    }

    foreach index(1) [list Start Join] {
      foreach index(2) [array names thread] {
        $thread($index(2)) $index(1)
      }
    }
................................................................................
  foreach index(0) [array names workload] {
    catch {
      object removecallback [list apply $workload($index(0)) $fileName(1) \
          $fileName(2) t1 $count(1)]
    }
  }

  unset -nocomplain result thread index workload noWorkload srcDb db \
      fileName compiled options count times
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result {}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue

Changes to readme.htm.

202
203
204
205
206
207
208



209
210
211
212
213
214
215
    <li>Make the test project for the .NET Compact Framework more flexible.</li>
    <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
    <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>



</ul>
<p>
    <b>1.0.82.0 - September 3, 2012</b>
</p>
<ul>
    <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_14.html">SQLite 3.7.14</a>.</li>
    <li>Properly handle quoted data source values in the connection string. Fix for [8c3bee31c8].</li>







>
>
>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    <li>Make the test project for the .NET Compact Framework more flexible.</li>
    <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
    <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Implement more robust locking semantics for the CriticalHandle derived classes when compiled for the .NET Compact Framework.</li>
    <li>Cache column indexes are they are looked up when using the SQLiteDataReader to improve performance.</li>
    <li>Prevent the SQLiteConnection.Close method from throwing non-fatal exceptions during its disposal.</li>
</ul>
<p>
    <b>1.0.82.0 - September 3, 2012</b>
</p>
<ul>
    <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_14.html">SQLite 3.7.14</a>.</li>
    <li>Properly handle quoted data source values in the connection string. Fix for [8c3bee31c8].</li>

Changes to www/news.wiki.

18
19
20
21
22
23
24



25
26
27
28
29
30
31
    <li>Make the test project for the .NET Compact Framework more flexible.</li>
    <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
    <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>



</ul>
<p>
    <b>1.0.82.0 - September 3, 2012</b>
</p>
<ul>
    <li>Updated to [http://www.sqlite.org/releaselog/3_7_14.html|SQLite 3.7.14].</li>
    <li>Properly handle quoted data source values in the connection string. Fix for [8c3bee31c8].</li>







>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    <li>Make the test project for the .NET Compact Framework more flexible.</li>
    <li>When available, the new sqlite3_errstr function from the core library is used to get the error message for a specific return code.</li>
    <li>The SetMemoryStatus, Shutdown, ResultCode, ExtendedResultCode, and SetAvRetry methods of the SQLiteConnection class now return a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The public constructor for the SQLiteException now takes a SQLiteErrorCode instead of an integer error code.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode property of the SQLiteException is now an Int32, to allow the property inherited from the base class to be properly overridden.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The ErrorCode field of the LogEventArgs is now an object instead of an integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>The names and messages associated with the SQLiteErrorCode enumeration values have been normalized to match those in the SQLite core library.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Implement more robust locking semantics for the CriticalHandle derived classes when compiled for the .NET Compact Framework.</li>
    <li>Cache column indexes are they are looked up when using the SQLiteDataReader to improve performance.</li>
    <li>Prevent the SQLiteConnection.Close method from throwing non-fatal exceptions during its disposal.</li>
</ul>
<p>
    <b>1.0.82.0 - September 3, 2012</b>
</p>
<ul>
    <li>Updated to [http://www.sqlite.org/releaselog/3_7_14.html|SQLite 3.7.14].</li>
    <li>Properly handle quoted data source values in the connection string. Fix for [8c3bee31c8].</li>