System.Data.SQLite

Login
This project makes use of Eagle, provided by Mistachkin Systems.
Eagle: Secure Software Automation

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

Changes In Branch tkt-0e48e80333 Excluding Merge-Ins

This is equivalent to a diff from 67190e9b52 to dbf44d7cf2

2017-11-14
16:19
Attempt to invalidate all native delegates from a connection during its disposal. Pursuant to [0e48e80333]. check-in: a6f55afb81 user: mistachkin tags: trunk
16:17
Add and enhance tests for ticket [0e48e80333]. Updates to test suite infrastructure. Closed-Leaf check-in: dbf44d7cf2 user: mistachkin tags: tkt-0e48e80333
08:47
Initial work on tests for ticket [0e48e80333]. check-in: c2d56cbccf user: mistachkin tags: tkt-0e48e80333
2017-11-12
05:36
Pass the connection string and parsed connection string properties to the Changed/Opened event handler. check-in: 2cdf95611e user: mistachkin tags: trunk
2017-11-09
08:04
Attempt to invalidate all native delegates from a connection during its disposal. Pursuant to [0e48e80333]. Still needs tests. check-in: aa99152568 user: mistachkin tags: tkt-0e48e80333
2017-11-07
03:38
Update a doc comment. check-in: 67190e9b52 user: mistachkin tags: trunk
03:33
Fix an incorrect memory allocation count in the SQLiteIndex class for SQLite memory freed without using the SQLiteMemory class. Only debug builds with TRACK_MEMORY_BYTES defined were impacted. check-in: 52d29df7aa user: mistachkin tags: trunk

Changes to Externals/Eagle/lib/Eagle1.0/vendor.eagle.

29
30
31
32
33
34
35

















36
37
38
39
40
41
42
#
# NOTE: Use our own namespace here because even though we do not directly
#       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 checkForTestOverrides { channel varNames quiet } {
      set result 0

      foreach varName $varNames {
        if {![uplevel 1 [list info exists $varName]]} then {
          continue
        }







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







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
#
# NOTE: Use our own namespace here because even though we do not directly
#       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 {
          continue
        }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
        interop_assembly_file_names native_library_file_names release_version \
        scratch_directory temporary_directory test_clr test_clr_v2 \
        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

    #
    # NOTE: Set the name of the running test suite, if necessary.
    #
    if {![info exists test_suite]} then {
      set test_suite "System.Data.SQLite Test Suite for Eagle"
    }







|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
        interop_assembly_file_names native_library_file_names release_version \
        scratch_directory temporary_directory test_clr test_clr_v2 \
        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]}] [checkForVendorQuiet checkForTestOverrides]

    #
    # NOTE: Set the name of the running test suite, if necessary.
    #
    if {![info exists test_suite]} then {
      set test_suite "System.Data.SQLite Test Suite for Eagle"
    }
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
      #       current interpreter.  Normally, this will also set the variable
      #       created above to point to the directory added to the auto-path;
      #       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)]

      unset have_vendor_directory

      #
      # NOTE: This procedure will attempt to find the vendor-specific testing
      #       directory.  Normally, this will also set the variable created
      #       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)]

      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)]
      }
    }

    #
    # HACK: Prevent the Eagle core test suite infrastructure from checking
    #       test constraints that are time-consuming and/or most likely to
    #       be superfluous to third-party test suites (i.e. those that are







|











|









|
|







406
407
408
409
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
435
436
437
438
439
440
441
442
443
      #       current interpreter.  Normally, this will also set the variable
      #       created above to point to the directory added to the auto-path;
      #       however, this will not be done if the variable was not created
      #       by us.
      #
      addTestSuiteToAutoPath stdout \
          [expr {$have_vendor_directory ? "" : "vendor_directory"}] \
          [checkForVendorQuiet addTestSuiteToAutoPath]

      unset have_vendor_directory

      #
      # NOTE: This procedure will attempt to find the vendor-specific testing
      #       directory.  Normally, this will also set the variable created
      #       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"}] \
          [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 \
            [checkForVendorQuiet setupInterpreterTestPath]
      }
    }

    #
    # HACK: Prevent the Eagle core test suite infrastructure from checking
    #       test constraints that are time-consuming and/or most likely to
    #       be superfluous to third-party test suites (i.e. those that are

Changes to Setup/data/verify.lst.

830
831
832
833
834
835
836

837
838
839
840
841
842
843
  Tests/stress.eagle
  Tests/template/
  Tests/template/empty.eagle
  Tests/thread.eagle
  Tests/tkt-00f86f9739.eagle
  Tests/tkt-0a32885109.eagle
  Tests/tkt-0d5b1ef362.eagle

  Tests/tkt-0ed01c447c.eagle
  Tests/tkt-17045010df.eagle
  Tests/tkt-1c456ae75f.eagle
  Tests/tkt-1f7bfff467.eagle
  Tests/tkt-201128cc88.eagle
  Tests/tkt-2556655d1b.eagle
  Tests/tkt-2abbf2c244.eagle







>







830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  Tests/stress.eagle
  Tests/template/
  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
  Tests/tkt-2556655d1b.eagle
  Tests/tkt-2abbf2c244.eagle

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

63
64
65
66
67
68
69

70
71
72
73
74
75
76

    /// <summary>
    /// The opaque pointer returned to us by the sqlite provider
    /// </summary>
    protected internal SQLiteConnectionHandle _sql;
    protected string _fileName;
    protected SQLiteConnectionFlags _flags;

    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
    private bool _buildingSchema;
#endif







>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

    /// <summary>
    /// The opaque pointer returned to us by the sqlite provider
    /// </summary>
    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
    private bool _buildingSchema;
#endif
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
                // release unmanaged resources here...
                //////////////////////////////////////

#if INTEROP_VIRTUAL_TABLE
                DisposeModules();
#endif

                Close(false); /* Disposing, cannot throw. */
            }
        }
        finally
        {
            base.Dispose(disposing);

            //







|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
                // release unmanaged resources here...
                //////////////////////////////////////

#if INTEROP_VIRTUAL_TABLE
                DisposeModules();
#endif

                Close(true); /* Disposing, cannot throw. */
            }
        }
        finally
        {
            base.Dispose(disposing);

            //
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
269
270

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

    // 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 (!_sql.OwnHandle)
          {
              _sql = null;
              return;
          }

          bool unbindFunctions = ((_flags & SQLiteConnectionFlags.UnbindFunctionsOnClose)
                == SQLiteConnectionFlags.UnbindFunctionsOnClose);



          if (_usePool)
          {
              if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))

              {
                  if (unbindFunctions)
                  {
                      if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
                      {
#if !NET_COMPACT_20 && TRACE_CONNECTION
                          Trace.WriteLine(HelperMethods.StringFormat(







|











>
>



|
>







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
269
270
271
272
273
274

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

    // 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 disposing)
    {
      if (_sql != null)
      {
          if (!_sql.OwnHandle)
          {
              _sql = null;
              return;
          }

          bool unbindFunctions = ((_flags & SQLiteConnectionFlags.UnbindFunctionsOnClose)
                == SQLiteConnectionFlags.UnbindFunctionsOnClose);

      retry:

          if (_usePool)
          {
              if (SQLiteBase.ResetConnection(_sql, _sql, !disposing) &&
                  UnhookNativeCallbacks(true, !disposing))
              {
                  if (unbindFunctions)
                  {
                      if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
                      {
#if !NET_COMPACT_20 && TRACE_CONNECTION
                          Trace.WriteLine(HelperMethods.StringFormat(
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

308
309
310
311

312






313

314
315
316



317
318
319
320
321
322
323
#endif

                  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 }));

#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
              {

                  Trace.WriteLine(HelperMethods.StringFormat(
                      CultureInfo.CurrentCulture,
                      "Close (Pool) Failure: {0}",
                      HandleToString()));

              }






#endif

          }
          else
          {



              if (unbindFunctions)
              {
                  if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
                  {
#if !NET_COMPACT_20 && TRACE_CONNECTION
                      Trace.WriteLine(HelperMethods.StringFormat(
                          CultureInfo.CurrentCulture,







|








<


>




>
|
>
>
>
>
>
>
|
>



>
>
>







293
294
295
296
297
298
299
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
332
333
334
335
336
337
338
#endif

                  SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);

                  SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
                      SQLiteConnectionEventType.ClosedToPool, null, null,
                      null, null, _sql, _fileName, new object[] {
                      typeof(SQLite3), !disposing, _fileName, _poolVersion }));

#if !NET_COMPACT_20 && TRACE_CONNECTION
                  Trace.WriteLine(HelperMethods.StringFormat(
                      CultureInfo.CurrentCulture,
                      "Close (Pool) Success: {0}",
                      HandleToString()));
#endif
              }

              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;
              }
          }
          else
          {
              /* IGNORED */
              UnhookNativeCallbacks(disposing, !disposing);

              if (unbindFunctions)
              {
                  if (SQLiteFunction.UnbindAllFunctions(this, _flags, false))
                  {
#if !NET_COMPACT_20 && TRACE_CONNECTION
                      Trace.WriteLine(HelperMethods.StringFormat(
                          CultureInfo.CurrentCulture,
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
    {
      //
      // 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);

      //
      // NOTE: If the connection was not closed successfully, throw an
      //       exception now.
      //
      if (_sql != null)
          throw new SQLiteException("connection handle is still active");







|







958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
    {
      //
      // 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(false);

      //
      // NOTE: If the connection was not closed successfully, throw an
      //       exception now.
      //
      if (_sql != null)
          throw new SQLiteException("connection handle is still active");
2940
2941
2942
2943
2944
2945
2946



2947
2948









































































































































































































































































































































2949
2950
2951
2952
2953
2954
2955
    /// <param name="func">The callback function to invoke.</param>
    /// <returns>Returns a result code</returns>
    internal override SQLiteErrorCode SetLogCallback(SQLiteLogCallback func)
    {
        SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3_config_log(
            SQLiteConfigOpsEnum.SQLITE_CONFIG_LOG, func, IntPtr.Zero);




        return rc;
    }










































































































































































































































































































































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

    /// <summary>
    /// Creates a new SQLite backup object based on the provided destination
    /// database connection.  The source database connection is the one
    /// associated with this object.  The source and destination database







>
>
>


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







2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
    /// <param name="func">The callback function to invoke.</param>
    /// <returns>Returns a result code</returns>
    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;
    }

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

    /// <summary>
    /// Appends an error message and an appropriate line-ending to a <see cref="StringBuilder" />
    /// instance.  This is useful because the .NET Compact Framework has a slightly different set
    /// of supported methods for the <see cref="StringBuilder" /> class.
    /// </summary>
    /// <param name="builder">
    /// The <see cref="StringBuilder" /> instance to append to.
    /// </param>
    /// <param name="message">
    /// The message to append.  It will be followed by an appropriate line-ending.
    /// </param>
    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
    }

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

    /// <summary>
    /// 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.
    /// <param name="includeGlobal">
    /// Non-zero to also invalidate global function pointers (i.e. those that
    /// are not directly associated with this connection on the native side).
    /// </param>
    /// <param name="canThrow">
    /// Non-zero if this method is being executed within a context where it can
    /// throw an exception in the event of failure; otherwise, zero.
    /// </param>
    /// </summary>
    /// <returns>
    /// Non-zero if this method was successful; otherwise, zero.
    /// </returns>
    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;
    }

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

    /// <summary>
    /// Creates a new SQLite backup object based on the provided destination
    /// database connection.  The source database connection is the one
    /// associated with this object.  The source and destination database

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

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    {
      //
      // 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);

      //
      // NOTE: If the connection was not closed successfully, throw an
      //       exception now.
      //
      if (_sql != null)
          throw new SQLiteException("connection handle is still active");







|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    {
      //
      // 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(false);

      //
      // NOTE: If the connection was not closed successfully, throw an
      //       exception now.
      //
      if (_sql != null)
          throw new SQLiteException("connection handle is still active");

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

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    /// <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







|
|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    /// <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="disposing">Non-zero if connection is being disposed, zero otherwise.</param>
    internal abstract void Close(bool disposing);
    /// <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

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

2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931

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

      StateChangeEventArgs eventArgs = null;







|







2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931

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

      StateChangeEventArgs eventArgs = null;
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
    public SQLiteErrorCode Shutdown()
    {
        CheckDisposed();

        if (_sql == null)
            throw new InvalidOperationException("Database connection not valid for shutdown.");

        _sql.Close(true); /* 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(
                CultureInfo.CurrentCulture,
                "Shutdown (Instance) Failed: {0}", rc));







|







4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
    public SQLiteErrorCode Shutdown()
    {
        CheckDisposed();

        if (_sql == null)
            throw new InvalidOperationException("Database connection not valid for 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(
                CultureInfo.CurrentCulture,
                "Shutdown (Instance) Failed: {0}", rc));

Added Tests/tkt-0e48e80333.eagle.





















































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
95
96
97
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
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 {
    <?xml version="1.0" encoding="UTF-8" ?>
    <mdaConfig xmlns="http://schemas.microsoft.com/CLR/2004/10/mda">
      <assistants>
        <callbackOnCollectedDelegate listSize="50" />
      </assistants>
    </mdaConfig>
  }]]

  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 {
    <?xml version="1.0" encoding="UTF-8" ?>
    <mdaConfig xmlns="http://schemas.microsoft.com/CLR/2004/10/mda">
      <assistants>
        <callbackOnCollectedDelegate listSize="50" />
      </assistants>
    </mdaConfig>
  }]]

  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

Changes to Tests/tkt-d4728aecb7.eagle.

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    [getAppDomainPreamble] -body {
  package require Eagle.Library
  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 {
    <?xml version="1.0"?>
    <configuration>
      <appSettings>
        <add key="d472_1"
             value="prfx1/%PreLoadSQLite_AssemblyDirectory%/sufx1" />
        <add key="d472_2"
             value="prfx2/%PreLoadSQLite_TargetFramework%/sufx2" />
        <add key="d472_3"
             value="prfx3/%PreLoadSQLite_XmlConfigDirectory%/sufx3" />
      </appSettings>
    </configuration>
  }]

  object load -loadtype Bytes [base64 encode [readFile [file join \
      [getBinaryDirectory] System.Data.SQLite.dll]]]

  set result [list]

  lappend result [string map [list \\ /] [object invoke -flags +NonPublic \







|
<
<
<











|







78
79
80
81
82
83
84
85



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    [getAppDomainPreamble] -body {
  package require Eagle.Library
  package require Eagle.Test
  package require System.Data.SQLite.Test

  moveSystemDataSQLiteDllConfig false

  set fileName [writeSystemDataSQLiteDllConfig [string trim {



    <?xml version="1.0"?>
    <configuration>
      <appSettings>
        <add key="d472_1"
             value="prfx1/%PreLoadSQLite_AssemblyDirectory%/sufx1" />
        <add key="d472_2"
             value="prfx2/%PreLoadSQLite_TargetFramework%/sufx2" />
        <add key="d472_3"
             value="prfx3/%PreLoadSQLite_XmlConfigDirectory%/sufx3" />
      </appSettings>
    </configuration>
  }]]

  object load -loadtype Bytes [base64 encode [readFile [file join \
      [getBinaryDirectory] System.Data.SQLite.dll]]]

  set result [list]

  lappend result [string map [list \\ /] [object invoke -flags +NonPublic \

Changes to lib/System.Data.SQLite/common.eagle.

1196
1197
1198
1199
1200
1201
1202









































































































1203
1204
1205
1206
1207
1208
1209
            tputs $::test_channel [appendArgs \
                "---- skipped moving \"" $fileName(1) \
                "\", it does not exist\n"]
          }
        }
      }
    }










































































































    proc getAppDomainPreamble { {prefix ""} {suffix ""} } {
      #
      # NOTE: This procedure returns a test setup script fragment suitable for
      #       evaluation by an interpreter created in an isolated application
      #       domain.  The script fragment being returned will be surrounded by
      #       the prefix and suffix "script fragments" specified by our caller,







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







1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
            tputs $::test_channel [appendArgs \
                "---- skipped moving \"" $fileName(1) \
                "\", 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
      #       domain.  The script fragment being returned will be surrounded by
      #       the prefix and suffix "script fragments" specified by our caller,
2929
2930
2931
2932
2933
2934
2935












2936
2937
2938
2939
2940
2941
2942
      # NOTE: This is self-cleaning.  If no saved environment variables now
      #       exist, remove the array.
      #
      if {[array size savedEnv] == 0} then {
        unset -nocomplain savedEnv
      }
    }













    proc saveGetSettingValueEnvironment {} {
      upvar 1 savedEnv savedEnv

      saveEnvironmentVariables [list \
          No_Expand No_SQLiteGetSettingValue No_SQLiteXmlConfigFile] \
          savedEnv







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







3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
      # NOTE: This is self-cleaning.  If no saved environment variables now
      #       exist, remove the array.
      #
      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 \
          No_Expand No_SQLiteGetSettingValue No_SQLiteXmlConfigFile] \
          savedEnv