System.Data.SQLite
Check-in [aa99152568]
Not logged in

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

Overview
Comment:Attempt to invalidate all native delegates from a connection during its disposal. Pursuant to [0e48e80333]. Still needs tests.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tkt-0e48e80333
Files: files | file ages | folders
SHA1:aa991525681a68d2bf2ed86014ad0ba1934f5cc8
User & Date: mistachkin 2017-11-09 08:04:19
Context
2017-11-09
08:37
Add another error message to the UnhookNativeCallbacks method. check-in: df1cca89d1 user: mistachkin tags: tkt-0e48e80333
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
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

63
64
65
66
67
68
69

70
71
72
73
74
75
76
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
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
...
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
...
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
....
2940
2941
2942
2943
2944
2945
2946



2947
2948







































































































































































































































































































































2949
2950
2951
2952
2953
2954
2955

    /// <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
................................................................................
                // release unmanaged resources here...
                //////////////////////////////////////

#if INTEROP_VIRTUAL_TABLE
                DisposeModules();
#endif

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

            //
................................................................................

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

    // It isn't necessary to cleanup any functions we've registered.  If the connection
    // goes to the pool and is resurrected later, re-registered functions will overwrite the
    // previous functions.  The SQLiteFunctionCookieHandle will take care of freeing unmanaged
    // resources belonging to the previously-registered functions.
    internal override void Close(bool canThrow)
    {
      if (_sql != null)
      {
          if (!_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(
................................................................................
#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,
................................................................................
    {
      //
      // 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");
................................................................................
    /// <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







>







 







|







 







|











>
>



|
>







 







|








<


>




<

>
>
>
>
>
>
>
>
>



>
>
>







 







|







 







>
>
>


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







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
...
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
...
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
...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
....
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

    /// <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
................................................................................
                // release unmanaged resources here...
                //////////////////////////////////////

#if INTEROP_VIRTUAL_TABLE
                DisposeModules();
#endif

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

            //
................................................................................

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

    // It isn't necessary to cleanup any functions we've registered.  If the connection
    // goes to the pool and is resurrected later, re-registered functions will overwrite the
    // previous functions.  The SQLiteFunctionCookieHandle will take care of freeing unmanaged
    // resources belonging to the previously-registered functions.
    internal override void Close(bool 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(
................................................................................
#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,
................................................................................
    {
      //
      // 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");
................................................................................
    /// <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)
                {
                    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
....
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857

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

      StateChangeEventArgs eventArgs = null;
................................................................................
    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));







|







 







|







2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
....
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857

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

      StateChangeEventArgs eventArgs = null;
................................................................................
    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));