System.Data.SQLite
Check-in [1808779aa2]
Not logged in

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

Overview
Comment:Add SQLiteSourceId property to the SQLiteConnection class to return the SQLite core library source identifier. Enhance and revising Trace output (in DEBUG only) to be more accurate and to report resource cleanup exceptions. More work on unit testing infrastructure and the test case for ticket [e30b820248]. The SQLite3 class should always attempt to dispose the contained SQLiteConnectionHandle, even when called via the finalizer.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tkt-e30b820248
Files: files | file ages | folders
SHA1: 1808779aa2a28a3b0072e1aa7739ba0d4b776436
User & Date: mistachkin 2011-11-15 04:01:14
Context
2011-11-15
05:02
Plug memory leak in the sqlite3_close_interop function when a statement cannot be finalized. Have the vendor-specific initialization file for Eagle automatically set the TestPath of the interpreter. Closed-Leaf check-in: 10d400ebd0 user: mistachkin tags: tkt-e30b820248
04:01
Add SQLiteSourceId property to the SQLiteConnection class to return the SQLite core library source identifier. Enhance and revising Trace output (in DEBUG only) to be more accurate and to report resource cleanup exceptions. More work on unit testing infrastructure and the test case for ticket [e30b820248]. The SQLite3 class should always attempt to dispose the contained SQLiteConnectionHandle, even when called via the finalizer. check-in: 1808779aa2 user: mistachkin tags: tkt-e30b820248
2011-11-14
05:40
Allow the SQLiteLog class to be used without having an open connection (i.e. and skip going through the SQLite core library to do it). check-in: 374756ec29 user: mistachkin tags: tkt-e30b820248
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
90
91
92
93
94
95
96








97
98
99
100
101
102
103
    internal SQLite3(SQLiteDateFormats fmt, DateTimeKind kind)
      : base(fmt, kind)
    {
    }

    protected override void Dispose(bool bDisposing)
    {
      if (bDisposing)
        Close();
    }

    // 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()
................................................................................
    internal static string SQLiteVersion
    {
      get
      {
        return UTF8ToString(UnsafeNativeMethods.sqlite3_libversion(), -1);
      }
    }









    internal override bool AutoCommit
    {
      get
      {
        return IsAutocommit(_sql);
      }







<
|







 







>
>
>
>
>
>
>
>







46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    internal SQLite3(SQLiteDateFormats fmt, DateTimeKind kind)
      : base(fmt, kind)
    {
    }

    protected override void Dispose(bool bDisposing)
    {

      Close();
    }

    // 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()
................................................................................
    internal static string SQLiteVersion
    {
      get
      {
        return UTF8ToString(UnsafeNativeMethods.sqlite3_libversion(), -1);
      }
    }

    internal static string SQLiteSourceId
    {
      get
      {
        return UTF8ToString(UnsafeNativeMethods.sqlite3_sourceid(), -1);
      }
    }

    internal override bool AutoCommit
    {
      get
      {
        return IsAutocommit(_sql);
      }

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

217
218
219
220
221
222
223


224
225
226
227

228
229
230

231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
    /// </summary>
    internal SQLiteStatement BuildNextCommand()
    {
      SQLiteStatement stmt = null;

      try
      {


        if (_statementList == null)
          _remainingText = _commandText;

        stmt = _cnn._sql.Prepare(_cnn, _remainingText, (_statementList == null) ? null : _statementList[_statementList.Count - 1], (uint)(_commandTimeout * 1000), out _remainingText);

        if (stmt != null)
        {
          stmt._command = this;

          if (_statementList == null)
            _statementList = new List<SQLiteStatement>();

          _statementList.Add(stmt);

          _parameterCollection.MapParameters(stmt);
          stmt.BindParameters();
        }        

        return stmt;
      }
      catch (Exception)
      {
        if (stmt != null)
        {
          if (_statementList.Contains(stmt))
            _statementList.Remove(stmt);

          stmt.Dispose();
        }

        // If we threw an error compiling the statement, we cannot continue on so set the remaining text to null.
        _remainingText = null;







>
>
|
|

|
>
|
|
|
>
|
|

|

|
|
|
>






|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    /// </summary>
    internal SQLiteStatement BuildNextCommand()
    {
      SQLiteStatement stmt = null;

      try
      {
        if ((_cnn != null) && (_cnn._sql != null))
        {
          if (_statementList == null)
            _remainingText = _commandText;

          stmt = _cnn._sql.Prepare(_cnn, _remainingText, (_statementList == null) ? null : _statementList[_statementList.Count - 1], (uint)(_commandTimeout * 1000), out _remainingText);

          if (stmt != null)
          {
            stmt._command = this;

            if (_statementList == null)
              _statementList = new List<SQLiteStatement>();

            _statementList.Add(stmt);

            _parameterCollection.MapParameters(stmt);
            stmt.BindParameters();
          }
        }
        return stmt;
      }
      catch (Exception)
      {
        if (stmt != null)
        {
          if ((_statementList != null) && _statementList.Contains(stmt))
            _statementList.Remove(stmt);

          stmt.Dispose();
        }

        // If we threw an error compiling the statement, we cannot continue on so set the remaining text to null.
        _remainingText = null;

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

483
484
485
486
487
488
489
490
491

492
493
494
495
496
497
498
....
1075
1076
1077
1078
1079
1080
1081










1082
1083
1084
1085
1086
1087
1088
          _sql = null;
          _enlistment = null;
        }
#endif
        if (_sql != null)
        {
          _sql.Close();
        }
        _sql = null;

        _transactionLevel = 0;
      }
      OnStateChange(ConnectionState.Closed);
    }

    /// <summary>
    /// Clears the connection pool associated with the connection.  Any other active connections using the same database file
................................................................................
    /// <summary>
    /// Returns the version of the underlying SQLite database engine
    /// </summary>
    public static string SQLiteVersion
    {
      get { return SQLite3.SQLiteVersion; }
    }











    /// <summary>
    /// Returns the state of the connection.
    /// </summary>
#if !PLATFORM_COMPACTFRAMEWORK
    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
#endif







<
|
>







 







>
>
>
>
>
>
>
>
>
>







483
484
485
486
487
488
489

490
491
492
493
494
495
496
497
498
....
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
          _sql = null;
          _enlistment = null;
        }
#endif
        if (_sql != null)
        {
          _sql.Close();

          _sql = null;
        }
        _transactionLevel = 0;
      }
      OnStateChange(ConnectionState.Closed);
    }

    /// <summary>
    /// Clears the connection pool associated with the connection.  Any other active connections using the same database file
................................................................................
    /// <summary>
    /// Returns the version of the underlying SQLite database engine
    /// </summary>
    public static string SQLiteVersion
    {
      get { return SQLite3.SQLiteVersion; }
    }

    /// <summary>
    /// This method returns the string whose value is the same as the
    /// SQLITE_SOURCE_ID C preprocessor macro used when compiling the
    /// SQLite core library.
    /// </summary>
    public static string SQLiteSourceId
    {
      get { return SQLite3.SQLiteSourceId; }
    }

    /// <summary>
    /// Returns the state of the connection.
    /// </summary>
#if !PLATFORM_COMPACTFRAMEWORK
    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
#endif

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

353
354
355
356
357
358
359







360
361
362
363
364
365
366
...
872
873
874
875
876
877
878


879



880




881
882
883
884
885
886
887



888

889











890
891
892
893
894
895
896
...
925
926
927
928
929
930
931


932



933




934
935
936
937
938
939
940



941

942











943
944
945
946
947
948
949
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_libversion();

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else







    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void sqlite3_interrupt(IntPtr db);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
................................................................................
    {
    }

    protected override bool ReleaseHandle()
    {
      try
      {


#if DEBUG



        Trace.WriteLine(String.Format("CloseConnection: {0}", handle));




#endif

        SQLiteBase.CloseConnection(this);
#if DEBUG
        return true;
#endif
      }



      catch (SQLiteException)

      {











      }
#if DEBUG
      return false;
#else
      return true;
#endif
    }
................................................................................
    {
    }

    protected override bool ReleaseHandle()
    {
      try
      {


#if DEBUG



        Trace.WriteLine(String.Format("FinalizeStatement: {0}", handle));




#endif

        SQLiteBase.FinalizeStatement(this);
#if DEBUG
        return true;
#endif
      }



      catch (SQLiteException)

      {











      }
#if DEBUG
      return false;
#else
      return true;
#endif
    }







>
>
>
>
>
>
>







 







>
>

>
>
>
|
>
>
>
>


<




>
>
>

>

>
>
>
>
>
>
>
>
>
>
>







 







>
>

>
>
>
|
>
>
>
>


<




>
>
>

>

>
>
>
>
>
>
>
>
>
>
>







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898

899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
...
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_libversion();

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_sourceid();

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void sqlite3_interrupt(IntPtr db);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
................................................................................
    {
    }

    protected override bool ReleaseHandle()
    {
      try
      {
        SQLiteBase.CloseConnection(this);

#if DEBUG
        try
        {
          Trace.WriteLine(String.Format(
              "CloseConnection: {0}", handle));
        }
        catch
        {
        }
#endif


#if DEBUG
        return true;
#endif
      }
#if DEBUG
      catch (SQLiteException e)
#else
      catch (SQLiteException)
#endif
      {
#if DEBUG
        try
        {
          Trace.WriteLine(String.Format(
              "CloseConnection: {0}, exception: {1}",
              handle, e));
        }
        catch
        {
        }
#endif
      }
#if DEBUG
      return false;
#else
      return true;
#endif
    }
................................................................................
    {
    }

    protected override bool ReleaseHandle()
    {
      try
      {
        SQLiteBase.FinalizeStatement(this);

#if DEBUG
        try
        {
          Trace.WriteLine(String.Format(
              "FinalizeStatement: {0}", handle));
        }
        catch
        {
        }
#endif


#if DEBUG
        return true;
#endif
      }
#if DEBUG
      catch (SQLiteException e)
#else
      catch (SQLiteException)
#endif
      {
#if DEBUG
        try
        {
          Trace.WriteLine(String.Format(
              "FinalizeStatement: {0}, exception: {1}",
              handle, e));
        }
        catch
        {
        }
#endif
      }
#if DEBUG
      return false;
#else
      return true;
#endif
    }

Changes to Tests/common.eagle.

300
301
302
303
304
305
306












307
308
309
310
311
312
313
314
315
316
317
318
319
...
398
399
400
401
402
403
404
405
406
407
408







409
410
411
412
413
414
415
...
466
467
468
469
470
471
472
473
474

475






476
477
478
479
480

481








482




483

484
485
486
487

488

489
490
491
492



493
494
495




496

497
498
499
500

501

502
503
504
505



506
507



508
509
510
511
512
513
514
...
517
518
519
520
521
522
523

524
525
526
527
528
529
530
531
532

533
534
535
536
537
538
539
    }
 
    proc checkForSQLite { channel } {
      tputs $channel "---- checking for core SQLite library... "

      if {[catch {object invoke -flags +NonPublic System.Data.SQLite.SQLite3 \
              SQLiteVersion} version] == 0} then {












        #
        # NOTE: Yes, the SQLite core library appears to be available.
        #
        addConstraint SQLite

        tputs $channel [appendArgs "yes (" $version ")\n"]
      } else {
        tputs $channel no\n
      }
    }
 
    proc getDateTimeFormat {} {
      #
................................................................................
      #       the temporary directory.  Each database used by a test should be
      #       cleaned up by that test using the "cleanupDb" procedure, below.
      #
      set fileName [file join [getTemporaryPath] [file tail $fileName]]

      #
      # NOTE: By default, delete any pre-existing database with the same file
      #       name.
      #
      if {$delete} then {
        catch {file delete $fileName}







      }

      #
      # NOTE: Refer to the specified variable (e.g. "db") in the context of the
      #       caller.  The handle to the opened database will be stored there.
      #
      upvar 1 $varName db
................................................................................
      #
      upvar 1 $varName db

      #
      # NOTE: Close the connection to the database now.  This should allow us to
      #       delete the underlying database file.
      #
      catch {sql close $db}


      #






      # NOTE: Delete the test database file now.  For now, all test database
      #       files are stored in the temporary directory.
      #
      catch {file delete [file join [getTemporaryPath] [file tail $fileName]]}
    }

 








    proc reportSQLiteResources { channel } {




      tputs $channel "---- current memory in use by SQLite... "


      if {[catch {object invoke -flags +NonPublic \
              System.Data.SQLite.UnsafeNativeMethods \
              sqlite3_memory_used} memory] == 0} then {

        tputs $channel [appendArgs $memory " bytes\n"]

      } else {
        #
        # NOTE: Maybe the SQLite native library is unavailable?
        #



        tputs $channel unknown\n
      }





      tputs $channel "---- maximum memory in use by SQLite... "


      if {[catch {object invoke -flags +NonPublic \
              System.Data.SQLite.UnsafeNativeMethods \
              sqlite3_memory_highwater 0} memory] == 0} then {

        tputs $channel [appendArgs $memory " bytes\n"]

      } else {
        #
        # NOTE: Maybe the SQLite native library is unavailable?
        #



        tputs $channel unknown\n
      }



    }
 
    proc runSQLiteTestPrologue {} {
      #
      # NOTE: Skip running our custom prologue if the main one has been skipped.
      #
      if {![info exists ::no(prologue.eagle)]} then {
................................................................................
        #       copying, and loading) if we are so instructed.
        #
        if {![info exists ::no(sqliteFiles)]} then {
          #
          # NOTE: Skip trying to delete any files if we are so instructed.
          #
          if {![info exists ::no(deleteSqliteFiles)]} then {

            tryDeleteAssembly SQLite.Interop.dll
            tryDeleteAssembly System.Data.SQLite.dll
            tryDeleteAssembly System.Data.SQLite.Linq.dll
          }

          #
          # NOTE: Skip trying to copy any files if we are so instructed.
          #
          if {![info exists ::no(copySqliteFiles)]} then {

            tryCopyAssembly SQLite.Interop.dll
            tryCopyAssembly System.Data.SQLite.dll
            tryCopyAssembly System.Data.SQLite.Linq.dll
          }

          #
          # NOTE: Skip trying to load any files if we are so instructed.







>
>
>
>
>
>
>
>
>
>
>
>





|







 







|

|
|
>
>
>
>
>
>
>







 







|
|
>
|
>
>
>
>
>
>
|
|

|
|
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
|
>




>
|
>




>
>
>
|
|
|
>
>
>
>
|
>




>
|
>




>
>
>
|
|
>
>
>







 







>









>







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
    }
 
    proc checkForSQLite { channel } {
      tputs $channel "---- checking for core SQLite library... "

      if {[catch {object invoke -flags +NonPublic System.Data.SQLite.SQLite3 \
              SQLiteVersion} version] == 0} then {
        #
        # NOTE: Attempt to query the Fossil source identifier for the SQLite
        #       core library.
        #
        if {[catch {object invoke -flags +NonPublic System.Data.SQLite.SQLite3 \
                SQLiteSourceId} sourceId]} then {
          #
          # NOTE: We failed to query the Fossil source identifier.
          #
          set sourceId unknown
        }

        #
        # NOTE: Yes, the SQLite core library appears to be available.
        #
        addConstraint SQLite

        tputs $channel [appendArgs "yes (" $version " " $sourceId ")\n"]
      } else {
        tputs $channel no\n
      }
    }
 
    proc getDateTimeFormat {} {
      #
................................................................................
      #       the temporary directory.  Each database used by a test should be
      #       cleaned up by that test using the "cleanupDb" procedure, below.
      #
      set fileName [file join [getTemporaryPath] [file tail $fileName]]

      #
      # NOTE: By default, delete any pre-existing database with the same file
      #       name if it currently exists.
      #
      if {$delete && [file exists $fileName]} then {
        if {[catch {file delete $fileName} error]} then {
          #
          # NOTE: We somehow failed to delete the file, report why.
          #
          tputs $::test_channel [appendArgs \
              "==== WARNING: failed to delete database file \"" $fileName \
              "\" during setup, error: " \n\t $error \n]
        }
      }

      #
      # NOTE: Refer to the specified variable (e.g. "db") in the context of the
      #       caller.  The handle to the opened database will be stored there.
      #
      upvar 1 $varName db
................................................................................
      #
      upvar 1 $varName db

      #
      # NOTE: Close the connection to the database now.  This should allow us to
      #       delete the underlying database file.
      #
      if {[info exists db] && [catch {sql close $db} error]} then {
        #
        # NOTE: We somehow failed to close the database, report why.
        #
        tputs $::test_channel [appendArgs \
            "==== WARNING: failed to close database \"" $db "\", error: " \
            \n\t $error \n]
      }

      #
      # NOTE: Attempt to delete the test database file now.  For now, all test
      #       database files are stored in the temporary directory.
      #
      set fileName [file join [getTemporaryPath] [file tail $fileName]]

      if {[catch {file delete $fileName} error]} then {
        #
        # NOTE: We somehow failed to delete the file, report why.
        #
        tputs $::test_channel [appendArgs \
            "==== WARNING: failed to delete database file \"" $fileName \
            "\" during cleanup, error: " \n\t $error \n]
      }
    }
 
    proc reportSQLiteResources { channel {quiet false} } {
      #
      # NOTE: Skip all output if we are running in "quiet" mode.
      #
      if {!$quiet} then {
        tputs $channel "---- current memory in use by SQLite... "
      }

      if {[catch {object invoke -flags +NonPublic \
              System.Data.SQLite.UnsafeNativeMethods \
              sqlite3_memory_used} memory] == 0} then {
        if {!$quiet} then {
          tputs $channel [appendArgs $memory " bytes\n"]
        }
      } else {
        #
        # NOTE: Maybe the SQLite native library is unavailable?
        #
        set memory unknown

        if {!$quiet} then {
          tputs $channel [appendArgs $memory \n]
        }
      }

      set result $memory; # NOTE: Return memory in-use to caller.

      if {!$quiet} then {
        tputs $channel "---- maximum memory in use by SQLite... "
      }

      if {[catch {object invoke -flags +NonPublic \
              System.Data.SQLite.UnsafeNativeMethods \
              sqlite3_memory_highwater 0} memory] == 0} then {
        if {!$quiet} then {
          tputs $channel [appendArgs $memory " bytes\n"]
        }
      } else {
        #
        # NOTE: Maybe the SQLite native library is unavailable?
        #
        set memory unknown

        if {!$quiet} then {
          tputs $channel [appendArgs $memory \n]
        }
      }

      return $result
    }
 
    proc runSQLiteTestPrologue {} {
      #
      # NOTE: Skip running our custom prologue if the main one has been skipped.
      #
      if {![info exists ::no(prologue.eagle)]} then {
................................................................................
        #       copying, and loading) if we are so instructed.
        #
        if {![info exists ::no(sqliteFiles)]} then {
          #
          # NOTE: Skip trying to delete any files if we are so instructed.
          #
          if {![info exists ::no(deleteSqliteFiles)]} then {
            tryDeleteAssembly sqlite3.dll
            tryDeleteAssembly SQLite.Interop.dll
            tryDeleteAssembly System.Data.SQLite.dll
            tryDeleteAssembly System.Data.SQLite.Linq.dll
          }

          #
          # NOTE: Skip trying to copy any files if we are so instructed.
          #
          if {![info exists ::no(copySqliteFiles)]} then {
            tryCopyAssembly sqlite3.dll
            tryCopyAssembly SQLite.Interop.dll
            tryCopyAssembly System.Data.SQLite.dll
            tryCopyAssembly System.Data.SQLite.Linq.dll
          }

          #
          # NOTE: Skip trying to load any files if we are so instructed.

Changes to Tests/tkt-e30b820248.eagle.

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
..
91
92
93
94
95
96
97
98

99
100
101
102
103
104

105
106
107
108
109





















































































































































110
111
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

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





runTest {test tkt-e30b820248-1.1 {statement disposal ordering} -setup {
  setupDb [set fileName tkt-e30b820248-1.1.db]
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getTemporaryPath] $fileName]
  set name [file rootname [file tail $fileName]]

  set sql { \
    CREATE TABLE t1 (id1 INTEGER); \
    INSERT INTO t1 (id1) VALUES (1); \
    INSERT INTO t1 (id1) VALUES (2); \
    INSERT INTO t1 (id1) VALUES (?); \
    INSERT INTO t1 (id1) VALUES (?); \
    INSERT INTO t1 (id1) VALUES (?); \

  }

  unset -nocomplain results errors

  set code [compileCSharpWith [subst {
    using System.Data.SQLite;
    using System.Diagnostics;


    namespace _Dynamic${id}
    {
      public class Test${id}
      {
        public static void Main()
        {
          using (TraceListener listener = new TextWriterTraceListener(
              "${test_log}", "${name}"))

          {
            Trace.Listeners.Add(listener);
            Trace.WriteLine("---- START TRACE \\"${name}\\"");

            using (SQLiteConnection connection = new SQLiteConnection(
                "Data Source=${dataSource};"))
            {
................................................................................
    }
  }] 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} Main
      } result] : [set result ""]}] $result

} -cleanup {
  cleanupDb $fileName

  unset -nocomplain result code results errors sql dataSource id db fileName
} -constraints \
{eagle logFile monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \

-match regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0\
\{\}$}}

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






















































































































































runSQLiteTestEpilogue
runTestEpilogue







>
>
>
>
|
|












>







>








|
>







 







|
>






>
|
<



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


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
..
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

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

set memory_used [reportSQLiteResources $test_channel true]

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

runTest {test tkt-e30b820248-1.1 {disposal ordering} -setup {
  set fileName tkt-e30b820248-1.1.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getTemporaryPath] $fileName]
  set name [file rootname [file tail $fileName]]

  set sql { \
    CREATE TABLE t1 (id1 INTEGER); \
    INSERT INTO t1 (id1) VALUES (1); \
    INSERT INTO t1 (id1) VALUES (2); \
    INSERT INTO t1 (id1) VALUES (?); \
    INSERT INTO t1 (id1) VALUES (?); \
    INSERT INTO t1 (id1) VALUES (?); \
    SELECT * FROM t1 ORDER BY id1; \
  }

  unset -nocomplain results errors

  set code [compileCSharpWith [subst {
    using System.Data.SQLite;
    using System.Diagnostics;
    using System.IO;

    namespace _Dynamic${id}
    {
      public class Test${id}
      {
        public static void Main()
        {
          using (TraceListener listener = new TextWriterTraceListener(
              new FileStream("${test_log}", FileMode.Append,
                  FileAccess.Write, FileShare.ReadWrite), "${name}"))
          {
            Trace.Listeners.Add(listener);
            Trace.WriteLine("---- START TRACE \\"${name}\\"");

            using (SQLiteConnection connection = new SQLiteConnection(
                "Data Source=${dataSource};"))
            {
................................................................................
    }
  }] 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} Main
      } result] : [set result ""]}] $result \
      [reportSQLiteResources $test_channel true]
} -cleanup {
  cleanupDb $fileName

  unset -nocomplain result code results errors sql dataSource id db fileName
} -constraints \
{eagle logFile monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \
-match regexp -result [appendArgs "^Ok\
System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} 0 \\{\\} " $memory_used \$]}


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

for {set i 2} {$i < 4} {incr i} {
  set memory_used [reportSQLiteResources $test_channel true]

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

  runTest {test [appendArgs tkt-e30b820248-1. $i] {disposal ordering} -setup {
    set fileName [appendArgs tkt-e30b820248-1. $i .db]
  } -body {
    set id [object invoke Interpreter.GetActive NextId]
    set dataSource [file join [getTemporaryPath] $fileName]
    set name [file rootname [file tail $fileName]]

    set sql { \
      CREATE TABLE t1 (id1 INTEGER); \
      INSERT INTO t1 (id1) VALUES (1); \
      INSERT INTO t1 (id1) VALUES (2); \
      INSERT INTO t1 (id1) VALUES (3); \
      INSERT INTO t1 (id1) VALUES (4); \
      INSERT INTO t1 (id1) VALUES (5); \
      SELECT * FROM t1 ORDER BY id1; \
    }

    unset -nocomplain results errors

    set code [compileCSharpWith [subst {
      [expr {$i == 3 ? "using System;" : ""}]
      using System.Data.SQLite;
      using System.Diagnostics;
      using System.IO;

      namespace _Dynamic${id}
      {
        public class Test${id}
        {
          #region Private Static Data
          private static SQLiteConnection connection;
          #endregion

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

          #region Public Static Methods
          public static void OpenConnection()
          {
            connection = new SQLiteConnection("Data Source=${dataSource};");
            connection.Open();
            connection.LogMessage(0, "Connection opened.");
          }

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

          public static SQLiteCommand CreateCommand(string sql)
          {
            SQLiteCommand command = connection.CreateCommand();
            command.CommandText = sql;
            connection.LogMessage(0, "Command created.");
            return command;
          }

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

          public static SQLiteDataReader ExecuteReader(SQLiteCommand command)
          {
            SQLiteDataReader dataReader = command.ExecuteReader();
            connection.LogMessage(0, "Command executed.");
            return dataReader;
          }

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

          public static SQLiteDataReader ExecuteReader(string sql)
          {
            SQLiteCommand command = CreateCommand(sql);
            SQLiteDataReader dataReader = command.ExecuteReader();
            connection.LogMessage(0, "Command executed.");
            return dataReader;
          }

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

          public static void CloseConnection()
          {
            connection.LogMessage(0, "Closing connection...");
            connection.Close();
          }
          #endregion

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

          public static void Main()
          {
            using (TraceListener listener = new TextWriterTraceListener(
                new FileStream("${test_log}", FileMode.Append,
                    FileAccess.Write, FileShare.ReadWrite), "${name}"))
            {
              Trace.Listeners.Add(listener);
              Trace.WriteLine("---- START TRACE \\"${name}\\"");

              OpenConnection();
              SQLiteDataReader dataReader = ExecuteReader("${sql}");

              [expr {$i == 3 ? {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
              } : ""}]

              dataReader.Close();

              [expr {$i == 3 ? {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
              } : ""}]

              CloseConnection();

              Trace.WriteLine("---- END TRACE \\"${name}\\"");
              Trace.Listeners.Remove(listener);
            }
          }
        }
      }
    }] 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} Main
        } result] : [set result ""]}] $result \
        [reportSQLiteResources $test_channel true]
  } -cleanup {
    cleanupDb $fileName

    unset -nocomplain result code results errors sql dataSource id db fileName
  } -constraints {eagle logFile monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -match regexp -result [appendArgs "^Ok\
System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} 0 \\{\\} " $memory_used \$]}
}

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

unset -nocomplain i

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

unset -nocomplain memory_used

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

runSQLiteTestEpilogue
runTestEpilogue