System.Data.SQLite
Check-in [3b020c8c80]
Not logged in

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

Overview
Comment:Change the base type for the SQLiteConnectionFlags enumeration to long integer. Improve exception handling in all native callbacks implemented in the SQLiteConnection class. Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3b020c8c802fea88260e0c8598ad0b432253b91f
User & Date: mistachkin 2015-06-24 20:02:06
Context
2015-06-24
22:43
Make sure that manually calling the Cancel method still causes an Interrupt exception to be thrown. Update master release archive manifest. check-in: dae0c2e6fc user: mistachkin tags: trunk
20:02
Change the base type for the SQLiteConnectionFlags enumeration to long integer. Improve exception handling in all native callbacks implemented in the SQLiteConnection class. Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries. check-in: 3b020c8c80 user: mistachkin tags: trunk
00:13
Minor enhancement to the batch build tool. check-in: 2cccb64c09 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Doc/Extra/Provider/version.html.

44
45
46
47
48
49
50



51
52
53
54
55
56
57
    <div id="mainBody">
    <h1 class="heading">Version History</h1>
    <p><b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/draft/releaselog/3_8_11.html">SQLite 3.8.11</a>.</li>
      <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for <a href="https://system.data.sqlite.org/index.html/info/9d353b0bd8">[9d353b0bd8]</a>.</li>



      <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
      <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
      <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
    </ul>
    <p><b>1.0.97.0 - May 26, 2015</b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/releaselog/3_8_10_2.html">SQLite 3.8.10.2</a>.</li>







>
>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    <div id="mainBody">
    <h1 class="heading">Version History</h1>
    <p><b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/draft/releaselog/3_8_11.html">SQLite 3.8.11</a>.</li>
      <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for <a href="https://system.data.sqlite.org/index.html/info/9d353b0bd8">[9d353b0bd8]</a>.</li>
      <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
      <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
      <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
      <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
      <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
    </ul>
    <p><b>1.0.97.0 - May 26, 2015</b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/releaselog/3_8_10_2.html">SQLite 3.8.10.2</a>.</li>

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

817
818
819
820
821
822
823

824
825
826
827
828
829
830
...
953
954
955
956
957
958
959


960
961

962
963
964
965
966
967
968
....
1126
1127
1128
1129
1130
1131
1132


1133
1134
1135
1136
1137
1138
1139
1140
....
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207
1208
1209
1210
....
2404
2405
2406
2407
2408
2409
2410





2411
2412
2413
2414
2415
2416
2417
        finally /* NOTE: Thread.Abort() protection. */
        {
          n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
        }

        if (n == SQLiteErrorCode.Row) return true;
        if (n == SQLiteErrorCode.Done) return false;


        if (n != SQLiteErrorCode.Ok)
        {
          SQLiteErrorCode r;

          // An error occurred, attempt to reset the statement.  If the reset worked because the
          // schema has changed, re-try the step again.  If it errored our because the database
................................................................................
        // Recreate a dummy statement
        string str = null;
        using (SQLiteStatement tmp = Prepare(null, stmt._sqlStatement, null, (uint)(stmt._command._commandTimeout * 1000), ref str))
        {
          // Finalize the existing statement
          stmt._sqlite_stmt.Dispose();
          // Reassign a new statement pointer to the old statement and clear the temporary one


          stmt._sqlite_stmt = tmp._sqlite_stmt;
          tmp._sqlite_stmt = null;


          // Reapply parameters
          stmt.BindParameters();
        }
        return SQLiteErrorCode.Unknown; // Reset was OK, with schema change
      }
      else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy)
................................................................................
          {
            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
              SQLiteConnectionEventType.NewCriticalHandle, null, null,
              null, null, statementHandle, strSql, new object[] { cnn,
              strSql, previous, timeoutMS }));
          }



          if (n == SQLiteErrorCode.Schema)
            retries++;
          else if (n == SQLiteErrorCode.Error)
          {
            if (String.Compare(GetLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
            {
              int pos = strSql.IndexOf(';');
              if (pos == -1) pos = strSql.Length - 1;
................................................................................
            {
              // Otherwise sleep for a random amount of time up to 150ms
              System.Threading.Thread.Sleep(rnd.Next(1, 150));
            }
          }
        }


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

        strRemain = UTF8ToString(ptr, len);

        if (statementHandle != null) cmd = new SQLiteStatement(this, flags, statementHandle, strSql.Substring(0, strSql.Length - strRemain.Length), previous);

        return cmd;
................................................................................

    internal override void ChangePassword(byte[] newPasswordBytes)
    {
      SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
      if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
    }
#endif






    internal override void SetAuthorizerHook(SQLiteAuthorizerCallback func)
    {
      UnsafeNativeMethods.sqlite3_set_authorizer(_sql, func, IntPtr.Zero);
    }

    internal override void SetUpdateHook(SQLiteUpdateCallback func)







>







 







>
>
|
|
>







 







>
>
|







 







>







 







>
>
>
>
>







817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
...
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
....
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
....
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
....
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
        finally /* NOTE: Thread.Abort() protection. */
        {
          n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
        }

        if (n == SQLiteErrorCode.Row) return true;
        if (n == SQLiteErrorCode.Done) return false;
        if (n == SQLiteErrorCode.Interrupt) return false;

        if (n != SQLiteErrorCode.Ok)
        {
          SQLiteErrorCode r;

          // An error occurred, attempt to reset the statement.  If the reset worked because the
          // schema has changed, re-try the step again.  If it errored our because the database
................................................................................
        // Recreate a dummy statement
        string str = null;
        using (SQLiteStatement tmp = Prepare(null, stmt._sqlStatement, null, (uint)(stmt._command._commandTimeout * 1000), ref str))
        {
          // Finalize the existing statement
          stmt._sqlite_stmt.Dispose();
          // Reassign a new statement pointer to the old statement and clear the temporary one
          if (tmp != null)
          {
            stmt._sqlite_stmt = tmp._sqlite_stmt;
            tmp._sqlite_stmt = null;
          }

          // Reapply parameters
          stmt.BindParameters();
        }
        return SQLiteErrorCode.Unknown; // Reset was OK, with schema change
      }
      else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy)
................................................................................
          {
            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
              SQLiteConnectionEventType.NewCriticalHandle, null, null,
              null, null, statementHandle, strSql, new object[] { cnn,
              strSql, previous, timeoutMS }));
          }

          if (n == SQLiteErrorCode.Interrupt)
            break;
          else if (n == SQLiteErrorCode.Schema)
            retries++;
          else if (n == SQLiteErrorCode.Error)
          {
            if (String.Compare(GetLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
            {
              int pos = strSql.IndexOf(';');
              if (pos == -1) pos = strSql.Length - 1;
................................................................................
            {
              // Otherwise sleep for a random amount of time up to 150ms
              System.Threading.Thread.Sleep(rnd.Next(1, 150));
            }
          }
        }

        if (n == SQLiteErrorCode.Interrupt) return null;
        if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());

        strRemain = UTF8ToString(ptr, len);

        if (statementHandle != null) cmd = new SQLiteStatement(this, flags, statementHandle, strSql.Substring(0, strSql.Length - strRemain.Length), previous);

        return cmd;
................................................................................

    internal override void ChangePassword(byte[] newPasswordBytes)
    {
      SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
      if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
    }
#endif

    internal override void SetProgressHook(int nOps, SQLiteProgressCallback func)
    {
        UnsafeNativeMethods.sqlite3_progress_handler(_sql, nOps, func, IntPtr.Zero);
    }

    internal override void SetAuthorizerHook(SQLiteAuthorizerCallback func)
    {
      UnsafeNativeMethods.sqlite3_set_authorizer(_sql, func, IntPtr.Zero);
    }

    internal override void SetUpdateHook(SQLiteUpdateCallback func)

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

383
384
385
386
387
388
389

390
391
392
393
394
395
396
...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
....
1078
1079
1080
1081
1082
1083
1084
























1085
1086
1087
1088
1089
1090
1091
    internal abstract void LogMessage(SQLiteErrorCode iErrCode, string zMessage);

#if INTEROP_CODEC || INTEROP_INCLUDE_SEE
    internal abstract void SetPassword(byte[] passwordBytes);
    internal abstract void ChangePassword(byte[] newPasswordBytes);
#endif


    internal abstract void SetAuthorizerHook(SQLiteAuthorizerCallback func);
    internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
    internal abstract void SetCommitHook(SQLiteCommitCallback func);
    internal abstract void SetTraceCallback(SQLiteTraceCallback func);
    internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
    internal abstract SQLiteErrorCode SetLogCallback(SQLiteLogCallback func);

................................................................................
    Default = 0x06,
  }

  /// <summary>
  /// The extra behavioral flags that can be applied to a connection.
  /// </summary>
  [Flags()]
  public enum SQLiteConnectionFlags
  {
      /// <summary>
      /// No extra flags.
      /// </summary>
      None = 0x0,

      /// <summary>
................................................................................
      /// <summary>
      /// When binding parameter values with the <see cref="DateTime" />
      /// type, take their <see cref="DateTimeKind" /> into account as
      /// well as that of the associated <see cref="SQLiteConnection" />.
      /// </summary>
      BindDateTimeWithKind = 0x10000000,

























      /// <summary>
      /// When binding parameter values or returning column values, always
      /// treat them as though they were plain text (i.e. no numeric,
      /// date/time, or other conversions should be attempted).
      /// </summary>
      BindAndGetAllAsText = BindAllAsText | GetAllAsText,








>







 







|







 







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







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
...
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
....
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
    internal abstract void LogMessage(SQLiteErrorCode iErrCode, string zMessage);

#if INTEROP_CODEC || INTEROP_INCLUDE_SEE
    internal abstract void SetPassword(byte[] passwordBytes);
    internal abstract void ChangePassword(byte[] newPasswordBytes);
#endif

    internal abstract void SetProgressHook(int nOps, SQLiteProgressCallback func);
    internal abstract void SetAuthorizerHook(SQLiteAuthorizerCallback func);
    internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
    internal abstract void SetCommitHook(SQLiteCommitCallback func);
    internal abstract void SetTraceCallback(SQLiteTraceCallback func);
    internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
    internal abstract SQLiteErrorCode SetLogCallback(SQLiteLogCallback func);

................................................................................
    Default = 0x06,
  }

  /// <summary>
  /// The extra behavioral flags that can be applied to a connection.
  /// </summary>
  [Flags()]
  public enum SQLiteConnectionFlags : long
  {
      /// <summary>
      /// No extra flags.
      /// </summary>
      None = 0x0,

      /// <summary>
................................................................................
      /// <summary>
      /// When binding parameter values with the <see cref="DateTime" />
      /// type, take their <see cref="DateTimeKind" /> into account as
      /// well as that of the associated <see cref="SQLiteConnection" />.
      /// </summary>
      BindDateTimeWithKind = 0x10000000,

      /// <summary>
      /// If an exception is caught when raising the
      /// <see cref="SQLiteConnection.Commit" /> event, the transaction
      /// should be rolled back.  If this is not specified, the transaction
      /// will continue the commit process instead.
      /// </summary>
      RollbackOnException = 0x20000000,

      /// <summary>
      /// If an exception is caught when raising the
      /// <see cref="SQLiteConnection.Authorize" /> event, the action should
      /// should be denied.  If this is not specified, the action will be
      /// allowed instead.
      /// </summary>
      DenyOnException = 0x40000000,

      /// <summary>
      /// If an exception is caught when raising the
      /// <see cref="SQLiteConnection.Progress" /> event, the operation
      /// should be interrupted.  If this is not specified, the operation
      /// will simply continue.
      /// </summary>
      InterruptOnException = 0x80000000,

      /// <summary>
      /// When binding parameter values or returning column values, always
      /// treat them as though they were plain text (i.e. no numeric,
      /// date/time, or other conversions should be attempted).
      /// </summary>
      BindAndGetAllAsText = BindAllAsText | GetAllAsText,

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

405
406
407
408
409
410
411










412
413
414
415
416
417
418
...
463
464
465
466
467
468
469

470
471
472
473
474
475
476
...
633
634
635
636
637
638
639








640
641
642
643
644
645
646
647
648
649

650
651
652
653
654
655

656
657
658
659
660
661
662
....
2698
2699
2700
2701
2702
2703
2704

2705
2706
2707
2708
2709
2710
2711
....
2864
2865
2866
2867
2868
2869
2870



2871
2872
2873
2874
2875
2876
2877
....
2948
2949
2950
2951
2952
2953
2954













2955
2956
2957
2958
2959
2960
2961
....
4893
4894
4895
4896
4897
4898
4899


































4900
4901
4902
4903
4904
4905
4906
....
4957
4958
4959
4960
4961
4962
4963
4964















































4965
4966
4967
4968
4969
4970
4971
4972


4973
4974
4975
4976
4977
4978
4979
4980
4981
4982

4983































4984






4985


4986
4987
4988
4989
4990



















4991
4992
4993
4994
4995
4996
4997
....
5046
5047
5048
5049
5050
5051
5052
5053



5054



5055
5056



















5057
5058
5059
5060
5061
5062
5063
....
5081
5082
5083
5084
5085
5086
5087


5088
5089
5090


5091


5092

5093
5094

5095































5096


5097



5098
5099

5100

















5101
5102
5103
5104
5105
5106
5107
....
5115
5116
5117
5118
5119
5120
5121





5122
5123
5124
5125
5126
5127
5128
....
5147
5148
5149
5150
5151
5152
5153










5154
5155
5156
5157
5158
5159
5160
....
5224
5225
5226
5227
5228
5229
5230












































5231
5232
5233
5234
5235
5236
5237
  /// The maximum number of retries when preparing SQL to be executed.  This
  /// normally only applies to preparation errors resulting from the database
  /// schema being changed.
  /// </description>
  /// <description>N</description>
  /// <description>3</description>
  /// </item>










  /// </list>
  /// </remarks>
  public sealed partial class SQLiteConnection : DbConnection, ICloneable, IDisposable
  {
    #region Private Constants
    /// <summary>
    /// The "invalid value" for the <see cref="DbType" /> enumeration used
................................................................................
    private const bool DefaultPooling = false; // TODO: Maybe promote this to static property?
    private const bool DefaultLegacyFormat = false;
    private const bool DefaultForeignKeys = false;
    private const bool DefaultEnlist = true;
    private const bool DefaultSetDefaults = true;
    internal const int DefaultPrepareRetries = 3;
    private const string DefaultVfsName = null;


#if INTEROP_INCLUDE_ZIPVFS
    private const string ZipVfs_Automatic = "automatic";
    private const string ZipVfs_V2 = "v2";
    private const string ZipVfs_V3 = "v3";

    private const string DefaultZipVfsVersion = null;
................................................................................
    /// <summary>
    /// The maximum number of retries when preparing SQL to be executed.  This
    /// normally only applies to preparation errors resulting from the database
    /// schema being changed.
    /// </summary>
    internal int _prepareRetries = DefaultPrepareRetries;









    /// <summary>
    /// Non-zero if the built-in (i.e. framework provided) connection string
    /// parser should be used when opening the connection.
    /// </summary>
    private bool _parseViaFramework;

    internal bool _binaryGuid;

    internal int _version;


    private event SQLiteAuthorizerEventHandler _authorizerHandler;
    private event SQLiteUpdateEventHandler _updateHandler;
    private event SQLiteCommitHandler _commitHandler;
    private event SQLiteTraceEventHandler _traceHandler;
    private event EventHandler _rollbackHandler;


    private SQLiteAuthorizerCallback _authorizerCallback;
    private SQLiteUpdateCallback _updateCallback;
    private SQLiteCommitCallback _commitCallback;
    private SQLiteTraceCallback _traceCallback;
    private SQLiteRollbackCallback _rollbackCallback;
    #endregion

................................................................................
      {
        bool usePooling = SQLiteConvert.ToBoolean(FindKey(opts, "Pooling", GetDefaultPooling().ToString()));
        int maxPoolSize = Convert.ToInt32(FindKey(opts, "Max Pool Size", DefaultMaxPoolSize.ToString()), CultureInfo.InvariantCulture);

        _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", DefaultConnectionTimeout.ToString()), CultureInfo.InvariantCulture);
        _busyTimeout = Convert.ToInt32(FindKey(opts, "BusyTimeout", DefaultBusyTimeout.ToString()), CultureInfo.InvariantCulture);
        _prepareRetries = Convert.ToInt32(FindKey(opts, "PrepareRetries", DefaultPrepareRetries.ToString()), CultureInfo.InvariantCulture);


        enumValue = TryParseEnum(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", DefaultIsolationLevel.ToString()), true);
        _defaultIsolation = (enumValue is IsolationLevel) ? (IsolationLevel)enumValue : DefaultIsolationLevel;
        _defaultIsolation = GetEffectiveIsolationLevel(_defaultIsolation);

        if (_defaultIsolation != ImmediateIsolationLevel && _defaultIsolation != DeferredIsolationLevel)
          throw new NotSupportedException("Invalid Default IsolationLevel specified");
................................................................................
                  {
                      cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", boolValue ? "ON" : "OFF");
                      cmd.ExecuteNonQuery();
                  }
              }
          }




          if (_authorizerHandler != null)
              _sql.SetAuthorizerHook(_authorizerCallback);

          if (_commitHandler != null)
            _sql.SetCommitHook(_commitCallback);

          if (_updateHandler != null)
................................................................................
    /// schema being changed.
    /// </summary>
    public int PrepareRetries
    {
        get { CheckDisposed(); return _prepareRetries; }
        set { CheckDisposed(); _prepareRetries = value; }
    }














    /// <summary>
    /// Non-zero if the built-in (i.e. framework provided) connection string
    /// parser should be used when opening the connection.
    /// </summary>
    public bool ParseViaFramework
    {
................................................................................
      }

      tbl.EndLoadData();
      tbl.AcceptChanges();

      return tbl;
    }



































    /// <summary>
    /// This event is raised whenever SQLite encounters an action covered by the
    /// authorizer during query preparation.  Changing the value of the
    /// <see cref="AuthorizerEventArgs.ReturnCode" /> property will determine if
    /// the specific action will be allowed, ignored, or denied.  For the entire
    /// duration of the event, the associated connection and statement objects
................................................................................
        if (_updateHandler == null)
        {
          if (_sql != null) _sql.SetUpdateHook(null);
          _updateCallback = null;
        }
      }
    }
















































    private SQLiteAuthorizerReturnCode AuthorizerCallback(
        IntPtr pUserData,
        SQLiteAuthorizerActionCode actionCode,
        IntPtr pArgument1,
        IntPtr pArgument2,
        IntPtr pDatabase,
        IntPtr pAuthContext)
    {


        AuthorizerEventArgs eventArgs = new AuthorizerEventArgs(pUserData, actionCode,
            SQLiteBase.UTF8ToString(pArgument1, -1), SQLiteBase.UTF8ToString(pArgument2, -1),
            SQLiteBase.UTF8ToString(pDatabase, -1), SQLiteBase.UTF8ToString(pAuthContext, -1),
            SQLiteAuthorizerReturnCode.Ok);

        if (_authorizerHandler != null)
            _authorizerHandler(this, eventArgs);

        return eventArgs.ReturnCode;
    }

































    private void UpdateCallback(IntPtr puser, int type, IntPtr database, IntPtr table, Int64 rowid)






    {


      _updateHandler(this, new UpdateEventArgs(
        SQLiteBase.UTF8ToString(database, -1),
        SQLiteBase.UTF8ToString(table, -1),
        (UpdateEventType)type,
        rowid));



















    }

    /// <summary>
    /// This event is raised whenever SQLite is committing a transaction.
    /// Return non-zero to trigger a rollback.
    /// </summary>
    public event SQLiteCommitHandler Commit
................................................................................
        {
          if (_sql != null) _sql.SetTraceCallback(null);
            _traceCallback = null;
        }
      }
    }

    private void TraceCallback(IntPtr puser, IntPtr statement)



    {



      _traceHandler(this, new TraceEventArgs(
        SQLiteBase.UTF8ToString(statement, -1)));



















    }

    /// <summary>
    /// This event is raised whenever SQLite is rolling back a transaction.
    /// </summary>
    public event EventHandler RollBack
    {
................................................................................
        {
          if (_sql != null) _sql.SetRollbackHook(null);
          _rollbackCallback = null;
        }
      }
    }




    private int CommitCallback(IntPtr parg)
    {


      CommitEventArgs e = new CommitEventArgs();


      _commitHandler(this, e);

      return (e.AbortTransaction == true) ? 1 : 0;
    }

































    private void RollbackCallback(IntPtr parg)


    {



      _rollbackHandler(this, EventArgs.Empty);
    }



















  }

  /// <summary>
  /// The I/O file cache flushing behavior for the connection
  /// </summary>
  public enum SynchronizationModes
  {
................................................................................
    Full = 1,
    /// <summary>
    /// Use the default operating system's file flushing, SQLite does not explicitly flush the file buffers after writing
    /// </summary>
    Off = 2,
  }






#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate SQLiteAuthorizerReturnCode SQLiteAuthorizerCallback(
    IntPtr pUserData,
    SQLiteAuthorizerActionCode actionCode,
    IntPtr pArgument1,
................................................................................
  internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteRollbackCallback(IntPtr puser);











  /// <summary>
  /// Raised when authorization is required to perform an action contained
  /// within a SQL query.
  /// </summary>
  /// <param name="sender">The connection performing the action.</param>
  /// <param name="e">A <see cref="AuthorizerEventArgs" /> that contains the
  /// event data.</param>
................................................................................
    string destinationName,
    int pages,
    int remainingPages,
    int totalPages,
    bool retry
  );
  #endregion













































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

  /// <summary>
  /// The data associated with a call into the authorizer.
  /// </summary>
  public class AuthorizerEventArgs : EventArgs







>
>
>
>
>
>
>
>
>
>







 







>







 







>
>
>
>
>
>
>
>










>






>







 







>







 







>
>
>







 







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







 







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







 








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

|






>
>
|
|
|
|

|
|

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

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







 







|
>
>
>

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







 







>
>
|
<

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

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







 







>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>







 







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







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
....
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
....
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
....
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
....
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
....
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
....
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
....
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295

5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
....
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
....
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
....
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
  /// The maximum number of retries when preparing SQL to be executed.  This
  /// normally only applies to preparation errors resulting from the database
  /// schema being changed.
  /// </description>
  /// <description>N</description>
  /// <description>3</description>
  /// </item>
  /// <item>
  /// <description>ProgressOps</description>
  /// <description>
  /// The approximate number of virtual machine instructions between progress
  /// events.  In order for progress events to actually fire, the event handler
  /// must be added to the <see cref="Progress" /> event as well.
  /// </description>
  /// <description>N</description>
  /// <description>0</description>
  /// </item>
  /// </list>
  /// </remarks>
  public sealed partial class SQLiteConnection : DbConnection, ICloneable, IDisposable
  {
    #region Private Constants
    /// <summary>
    /// The "invalid value" for the <see cref="DbType" /> enumeration used
................................................................................
    private const bool DefaultPooling = false; // TODO: Maybe promote this to static property?
    private const bool DefaultLegacyFormat = false;
    private const bool DefaultForeignKeys = false;
    private const bool DefaultEnlist = true;
    private const bool DefaultSetDefaults = true;
    internal const int DefaultPrepareRetries = 3;
    private const string DefaultVfsName = null;
    private const int DefaultProgressOps = 0;

#if INTEROP_INCLUDE_ZIPVFS
    private const string ZipVfs_Automatic = "automatic";
    private const string ZipVfs_V2 = "v2";
    private const string ZipVfs_V3 = "v3";

    private const string DefaultZipVfsVersion = null;
................................................................................
    /// <summary>
    /// The maximum number of retries when preparing SQL to be executed.  This
    /// normally only applies to preparation errors resulting from the database
    /// schema being changed.
    /// </summary>
    internal int _prepareRetries = DefaultPrepareRetries;

    /// <summary>
    /// The approximate number of virtual machine instructions between progress
    /// events.  In order for progress events to actually fire, the event handler
    /// must be added to the <see cref="SQLiteConnection.Progress" /> event as
    /// well.  This value will only be used when opening the database.
    /// </summary>
    private int _progressOps = DefaultProgressOps;

    /// <summary>
    /// Non-zero if the built-in (i.e. framework provided) connection string
    /// parser should be used when opening the connection.
    /// </summary>
    private bool _parseViaFramework;

    internal bool _binaryGuid;

    internal int _version;

    private event SQLiteProgressEventHandler _progressHandler;
    private event SQLiteAuthorizerEventHandler _authorizerHandler;
    private event SQLiteUpdateEventHandler _updateHandler;
    private event SQLiteCommitHandler _commitHandler;
    private event SQLiteTraceEventHandler _traceHandler;
    private event EventHandler _rollbackHandler;

    private SQLiteProgressCallback _progressCallback;
    private SQLiteAuthorizerCallback _authorizerCallback;
    private SQLiteUpdateCallback _updateCallback;
    private SQLiteCommitCallback _commitCallback;
    private SQLiteTraceCallback _traceCallback;
    private SQLiteRollbackCallback _rollbackCallback;
    #endregion

................................................................................
      {
        bool usePooling = SQLiteConvert.ToBoolean(FindKey(opts, "Pooling", GetDefaultPooling().ToString()));
        int maxPoolSize = Convert.ToInt32(FindKey(opts, "Max Pool Size", DefaultMaxPoolSize.ToString()), CultureInfo.InvariantCulture);

        _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", DefaultConnectionTimeout.ToString()), CultureInfo.InvariantCulture);
        _busyTimeout = Convert.ToInt32(FindKey(opts, "BusyTimeout", DefaultBusyTimeout.ToString()), CultureInfo.InvariantCulture);
        _prepareRetries = Convert.ToInt32(FindKey(opts, "PrepareRetries", DefaultPrepareRetries.ToString()), CultureInfo.InvariantCulture);
        _progressOps = Convert.ToInt32(FindKey(opts, "ProgressOps", DefaultProgressOps.ToString()), CultureInfo.InvariantCulture);

        enumValue = TryParseEnum(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", DefaultIsolationLevel.ToString()), true);
        _defaultIsolation = (enumValue is IsolationLevel) ? (IsolationLevel)enumValue : DefaultIsolationLevel;
        _defaultIsolation = GetEffectiveIsolationLevel(_defaultIsolation);

        if (_defaultIsolation != ImmediateIsolationLevel && _defaultIsolation != DeferredIsolationLevel)
          throw new NotSupportedException("Invalid Default IsolationLevel specified");
................................................................................
                  {
                      cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", boolValue ? "ON" : "OFF");
                      cmd.ExecuteNonQuery();
                  }
              }
          }

          if (_progressHandler != null)
              _sql.SetProgressHook(_progressOps, _progressCallback);

          if (_authorizerHandler != null)
              _sql.SetAuthorizerHook(_authorizerCallback);

          if (_commitHandler != null)
            _sql.SetCommitHook(_commitCallback);

          if (_updateHandler != null)
................................................................................
    /// schema being changed.
    /// </summary>
    public int PrepareRetries
    {
        get { CheckDisposed(); return _prepareRetries; }
        set { CheckDisposed(); _prepareRetries = value; }
    }

    /// <summary>
    /// The approximate number of virtual machine instructions between progress
    /// events.  In order for progress events to actually fire, the event handler
    /// must be added to the <see cref="SQLiteConnection.Progress" /> event as
    /// well.  This value will only be used when the underlying native progress
    /// callback needs to be changed.
    /// </summary>
    public int ProgressOps
    {
        get { CheckDisposed(); return _progressOps; }
        set { CheckDisposed(); _progressOps = value; }
    }

    /// <summary>
    /// Non-zero if the built-in (i.e. framework provided) connection string
    /// parser should be used when opening the connection.
    /// </summary>
    public bool ParseViaFramework
    {
................................................................................
      }

      tbl.EndLoadData();
      tbl.AcceptChanges();

      return tbl;
    }

    /// <summary>
    /// This event is raised periodically during long running queries.  Changing
    /// the value of the <see cref="ProgressEventArgs.ReturnCode" /> property will
    /// determine if the operation in progress will continue or be interrupted.
    /// For the entire duration of the event, the associated connection and
    /// statement objects must not be modified, either directly or indirectly, by
    /// the called code.
    /// </summary>
    public event SQLiteProgressEventHandler Progress
    {
        add
        {
            CheckDisposed();

            if (_progressHandler == null)
            {
                _progressCallback = new SQLiteProgressCallback(ProgressCallback);
                if (_sql != null) _sql.SetProgressHook(_progressOps, _progressCallback);
            }
            _progressHandler += value;
        }
        remove
        {
            CheckDisposed();

            _progressHandler -= value;
            if (_progressHandler == null)
            {
                if (_sql != null) _sql.SetProgressHook(0, null);
                _progressCallback = null;
            }
        }
    }

    /// <summary>
    /// This event is raised whenever SQLite encounters an action covered by the
    /// authorizer during query preparation.  Changing the value of the
    /// <see cref="AuthorizerEventArgs.ReturnCode" /> property will determine if
    /// the specific action will be allowed, ignored, or denied.  For the entire
    /// duration of the event, the associated connection and statement objects
................................................................................
        if (_updateHandler == null)
        {
          if (_sql != null) _sql.SetUpdateHook(null);
          _updateCallback = null;
        }
      }
    }

    private SQLiteProgressReturnCode ProgressCallback(
        IntPtr pUserData /* NOT USED: Always IntPtr.Zero. */
        )
    {
        try
        {
            ProgressEventArgs eventArgs = new ProgressEventArgs(
                pUserData, SQLiteProgressReturnCode.Continue);

            if (_progressHandler != null)
                _progressHandler(this, eventArgs);

            return eventArgs.ReturnCode;
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Progress\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }

        //
        // NOTE: Should throwing an exception interrupt the operation?
        //
        if ((_flags & SQLiteConnectionFlags.InterruptOnException) ==
                SQLiteConnectionFlags.InterruptOnException)
        {
            return SQLiteProgressReturnCode.Interrupt;
        }
        else
        {
            return SQLiteProgressReturnCode.Continue;
        }
    }

    private SQLiteAuthorizerReturnCode AuthorizerCallback(
        IntPtr pUserData, /* NOT USED: Always IntPtr.Zero. */
        SQLiteAuthorizerActionCode actionCode,
        IntPtr pArgument1,
        IntPtr pArgument2,
        IntPtr pDatabase,
        IntPtr pAuthContext)
    {
        try
        {
            AuthorizerEventArgs eventArgs = new AuthorizerEventArgs(pUserData, actionCode,
                SQLiteBase.UTF8ToString(pArgument1, -1), SQLiteBase.UTF8ToString(pArgument2, -1),
                SQLiteBase.UTF8ToString(pDatabase, -1), SQLiteBase.UTF8ToString(pAuthContext, -1),
                SQLiteAuthorizerReturnCode.Ok);

            if (_authorizerHandler != null)
                _authorizerHandler(this, eventArgs);

            return eventArgs.ReturnCode;
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Authorize\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }

        //
        // NOTE: Should throwing an exception deny the action?
        //
        if ((_flags & SQLiteConnectionFlags.DenyOnException) ==
                SQLiteConnectionFlags.DenyOnException)
        {
            return SQLiteAuthorizerReturnCode.Deny;
        }
        else
        {
            return SQLiteAuthorizerReturnCode.Ok;
        }
    }

    private void UpdateCallback(
        IntPtr puser, /* NOT USED */
        int type,
        IntPtr database,
        IntPtr table,
        Int64 rowid
        )
    {
        try
        {
            _updateHandler(this, new UpdateEventArgs(
              SQLiteBase.UTF8ToString(database, -1),
              SQLiteBase.UTF8ToString(table, -1),
              (UpdateEventType)type,
              rowid));
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Update\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }
    }

    /// <summary>
    /// This event is raised whenever SQLite is committing a transaction.
    /// Return non-zero to trigger a rollback.
    /// </summary>
    public event SQLiteCommitHandler Commit
................................................................................
        {
          if (_sql != null) _sql.SetTraceCallback(null);
            _traceCallback = null;
        }
      }
    }

    private void TraceCallback(
        IntPtr puser, /* NOT USED */
        IntPtr statement
        )
    {
        try
        {
            if (_traceHandler != null)
                _traceHandler(this, new TraceEventArgs(
                  SQLiteBase.UTF8ToString(statement, -1)));
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Trace\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }
    }

    /// <summary>
    /// This event is raised whenever SQLite is rolling back a transaction.
    /// </summary>
    public event EventHandler RollBack
    {
................................................................................
        {
          if (_sql != null) _sql.SetRollbackHook(null);
          _rollbackCallback = null;
        }
      }
    }

    private int CommitCallback(
        IntPtr parg /* NOT USED */
        )

    {
        try
        {
            CommitEventArgs e = new CommitEventArgs();

            if (_commitHandler != null)
                _commitHandler(this, e);

            return (e.AbortTransaction == true) ? 1 : 0;
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Commit\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }

        //
        // NOTE: Should throwing an exception rollback the transaction?
        //
        if ((_flags & SQLiteConnectionFlags.RollbackOnException) ==
                SQLiteConnectionFlags.RollbackOnException)
        {
            return 1; // rollback
        }
        else
        {
            return 0; // commit
        }
    }

    private void RollbackCallback(
        IntPtr parg /* NOT USED */
        )
    {
        try
        {
            if (_rollbackHandler != null)
                _rollbackHandler(this, EventArgs.Empty);
        }
        catch (Exception e) /* NOTE: Must catch ALL. */
        {
            try
            {
                if ((_flags & SQLiteConnectionFlags.LogCallbackException) ==
                        SQLiteConnectionFlags.LogCallbackException)
                {
                    SQLiteLog.LogMessage(SQLiteBase.COR_E_EXCEPTION,
                        String.Format(CultureInfo.CurrentCulture,
                        "Caught exception in \"Rollback\" method: {1}",
                        e)); /* throw */
                }
            }
            catch
            {
                // do nothing.
            }
        }
    }
  }

  /// <summary>
  /// The I/O file cache flushing behavior for the connection
  /// </summary>
  public enum SynchronizationModes
  {
................................................................................
    Full = 1,
    /// <summary>
    /// Use the default operating system's file flushing, SQLite does not explicitly flush the file buffers after writing
    /// </summary>
    Off = 2,
  }

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate SQLiteProgressReturnCode SQLiteProgressCallback(IntPtr pUserData);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate SQLiteAuthorizerReturnCode SQLiteAuthorizerCallback(
    IntPtr pUserData,
    SQLiteAuthorizerActionCode actionCode,
    IntPtr pArgument1,
................................................................................
  internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteRollbackCallback(IntPtr puser);

  /// <summary>
  /// Raised each time the number of virtual machine instructions is
  /// approximately equal to the value of the
  /// <see cref="SQLiteConnection.ProgressOps" /> property.
  /// </summary>
  /// <param name="sender">The connection performing the operation.</param>
  /// <param name="e">A <see cref="ProgressEventArgs" /> that contains the
  /// event data.</param>
  public delegate void SQLiteProgressEventHandler(object sender, ProgressEventArgs e);

  /// <summary>
  /// Raised when authorization is required to perform an action contained
  /// within a SQL query.
  /// </summary>
  /// <param name="sender">The connection performing the action.</param>
  /// <param name="e">A <see cref="AuthorizerEventArgs" /> that contains the
  /// event data.</param>
................................................................................
    string destinationName,
    int pages,
    int remainingPages,
    int totalPages,
    bool retry
  );
  #endregion

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

  public class ProgressEventArgs : EventArgs
  {
      /// <summary>
      /// The user-defined native data associated with this event.  Currently,
      /// this will always contain the value of <see cref="IntPtr.Zero" />.
      /// </summary>
      public readonly IntPtr UserData;

      /// <summary>
      /// The return code for the current call into the progress callback.
      /// </summary>
      public SQLiteProgressReturnCode ReturnCode;

      /// <summary>
      /// Constructs an instance of this class with default property values.
      /// </summary>
      private ProgressEventArgs()
      {
          this.UserData = IntPtr.Zero;
          this.ReturnCode = SQLiteProgressReturnCode.Continue;
      }

      /// <summary>
      /// Constructs an instance of this class with specific property values.
      /// </summary>
      /// <param name="pUserData">
      /// The user-defined native data associated with this event.
      /// </param>
      /// <param name="returnCode">
      /// The progress return code.
      /// </param>
      internal ProgressEventArgs(
          IntPtr pUserData,
          SQLiteProgressReturnCode returnCode
          )
          : this()
      {
          this.UserData = pUserData;
          this.ReturnCode = returnCode;
      }
  }

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

  /// <summary>
  /// The data associated with a call into the authorizer.
  /// </summary>
  public class AuthorizerEventArgs : EventArgs

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

289
290
291
292
293
294
295























296
297
298
299
300
301
302
            return Convert.ToInt32(value, CultureInfo.CurrentCulture);
        }
        set
        {
            this["prepareretries"] = value;
        }
    }
























    /// <summary>
    /// Determines whether or not the connection will automatically participate
    /// in the current distributed transaction (if one exists)
    /// </summary>
    [Browsable(true)]
    [DefaultValue(true)]







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







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
324
325
            return Convert.ToInt32(value, CultureInfo.CurrentCulture);
        }
        set
        {
            this["prepareretries"] = value;
        }
    }

    /// <summary>
    /// Gets/sets the approximate number of virtual machine instructions between
    /// progress events.  In order for progress events to actually fire, the event
    /// handler must be added to the <see cref="SQLiteConnection.Progress" /> event
    /// as well.
    /// </summary>
    [DisplayName("Progress Ops")]
    [Browsable(true)]
    [DefaultValue(0)]
    public int ProgressOps
    {
        get
        {
            object value;
            TryGetValue("progressops", out value);
            return Convert.ToInt32(value, CultureInfo.CurrentCulture);
        }
        set
        {
            this["progressops"] = value;
        }
    }

    /// <summary>
    /// Determines whether or not the connection will automatically participate
    /// in the current distributed transaction (if one exists)
    /// </summary>
    [Browsable(true)]
    [DefaultValue(true)]

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

2611
2612
2613
2614
2615
2616
2617
















2618
2619
2620
2621
2622
2623
2624

      /// <summary>
      /// A recursive query will be executed.  The action-specific arguments
      /// are two null values.
      /// </summary>
      Recursive = 33
  }

















  /// <summary>
  /// The return code for the current call into the authorizer.
  /// </summary>
  public enum SQLiteAuthorizerReturnCode
  {
      /// <summary>







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







2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640

      /// <summary>
      /// A recursive query will be executed.  The action-specific arguments
      /// are two null values.
      /// </summary>
      Recursive = 33
  }

  /// <summary>
  /// The possible return codes for the progress callback.
  /// </summary>
  public enum SQLiteProgressReturnCode /* int */
  {
      /// <summary>
      /// The operation should continue.
      /// </summary>
      Continue = 0,

      /// <summary>
      /// The operation should be interrupted.
      /// </summary>
      Interrupt = 1
  }

  /// <summary>
  /// The return code for the current call into the authorizer.
  /// </summary>
  public enum SQLiteAuthorizerReturnCode
  {
      /// <summary>

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

2122
2123
2124
2125
2126
2127
2128







2129
2130
2131
2132
2133
2134
2135
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void zipvfsInit_v3(int regDflt);
#endif








#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_set_authorizer(IntPtr db, SQLiteAuthorizerCallback func, IntPtr pvUser);








>
>
>
>
>
>
>







2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void zipvfsInit_v3(int regDflt);
#endif

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void sqlite3_progress_handler(IntPtr db, int ops, SQLiteProgressCallback func, IntPtr pvUser);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_set_authorizer(IntPtr db, SQLiteAuthorizerCallback func, IntPtr pvUser);

Changes to Tests/basic.eagle.

1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
....
1105
1106
1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117
1118
1119
                   BinaryGUID "Data Source" Uri FullUri "Default Timeout" \
                   Enlist FailIfMissing "Legacy Format" "Read Only" \
                   Password "Page Size" "Max Page Count" "Cache Size" \
                   DateTimeFormat DateTimeKind DateTimeFormatString \
                   BaseSchemaName "Journal Mode" "Default IsolationLevel" \
                   "Foreign Keys" Flags SetDefaults ToFullPath HexPassword \
                   DefaultDbType DefaultTypeName NoSharedFlags PrepareRetries \
                   ZipVfsVersion VfsName BusyTimeout]

    set values [list null 3 Normal True False \
                     True test.db test.db file:test.db 60 \
                     False True False True \
                     secret 4096 1024 8192 \
                     UnixEpoch Utc yyyy-MM-dd sqlite_schema \
                     Memory Serializable False \
                     Default False False 736563726574 String \
                     TEXT True 20 v2 test 1000]

    set propertyNames [list null Version SyncMode UseUTF16Encoding Pooling \
                            BinaryGUID DataSource Uri FullUri DefaultTimeout \
                            Enlist FailIfMissing LegacyFormat ReadOnly \
                            Password PageSize MaxPageCount CacheSize \
                            DateTimeFormat DateTimeKind DateTimeFormatString \
                            BaseSchemaName JournalMode DefaultIsolationLevel \
                            ForeignKeys Flags SetDefaults ToFullPath \
                            HexPassword DefaultDbType DefaultTypeName \
                            NoSharedFlags PrepareRetries ZipVfsVersion \
                            VfsName BusyTimeout]

    foreach key $keys value $values propertyName $propertyNames {
      set code [catch {
        object invoke _Dynamic${id}.Test${id} GetConnectionString \
            $key $value $propertyName
      } result]

................................................................................
BaseSchemaName=sqlite_schema\} 0 \{Memory, Journal Mode=Memory\} 0\
\{Serializable, Default IsolationLevel=Serializable\} 0 \{False, Foreign\
Keys=False\} 0 \{(?:Default|LogCallbackException),\
Flags=(?:Default|LogCallbackException)\} 0 \{False, SetDefaults=False\} 0\
\{False, ToFullPath=False\} 0 {736563726574, HexPassword=736563726574} 0\
\{String, DefaultDbType=String\} 0 \{TEXT, DefaultTypeName=TEXT\} 0 \{True,\
NoSharedFlags=True\} 0 \{20, PrepareRetries=20\} 0 \{v2, ZipVfsVersion=v2\} 0\
\{test, VfsName=test\} 0 \{1000, BusyTimeout=1000\}$}}


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

runTest {test data-1.18 {SQLiteConvert ToDateTime (Julian Day)} -body {
  set dateTime [object invoke -create System.Data.SQLite.SQLiteConvert \
      ToDateTime 2455928.0 Utc]








|








|










|







 







|
>







1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
....
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
                   BinaryGUID "Data Source" Uri FullUri "Default Timeout" \
                   Enlist FailIfMissing "Legacy Format" "Read Only" \
                   Password "Page Size" "Max Page Count" "Cache Size" \
                   DateTimeFormat DateTimeKind DateTimeFormatString \
                   BaseSchemaName "Journal Mode" "Default IsolationLevel" \
                   "Foreign Keys" Flags SetDefaults ToFullPath HexPassword \
                   DefaultDbType DefaultTypeName NoSharedFlags PrepareRetries \
                   ZipVfsVersion VfsName BusyTimeout ProgressOps]

    set values [list null 3 Normal True False \
                     True test.db test.db file:test.db 60 \
                     False True False True \
                     secret 4096 1024 8192 \
                     UnixEpoch Utc yyyy-MM-dd sqlite_schema \
                     Memory Serializable False \
                     Default False False 736563726574 String \
                     TEXT True 20 v2 test 1000 2000]

    set propertyNames [list null Version SyncMode UseUTF16Encoding Pooling \
                            BinaryGUID DataSource Uri FullUri DefaultTimeout \
                            Enlist FailIfMissing LegacyFormat ReadOnly \
                            Password PageSize MaxPageCount CacheSize \
                            DateTimeFormat DateTimeKind DateTimeFormatString \
                            BaseSchemaName JournalMode DefaultIsolationLevel \
                            ForeignKeys Flags SetDefaults ToFullPath \
                            HexPassword DefaultDbType DefaultTypeName \
                            NoSharedFlags PrepareRetries ZipVfsVersion \
                            VfsName BusyTimeout ProgressOps]

    foreach key $keys value $values propertyName $propertyNames {
      set code [catch {
        object invoke _Dynamic${id}.Test${id} GetConnectionString \
            $key $value $propertyName
      } result]

................................................................................
BaseSchemaName=sqlite_schema\} 0 \{Memory, Journal Mode=Memory\} 0\
\{Serializable, Default IsolationLevel=Serializable\} 0 \{False, Foreign\
Keys=False\} 0 \{(?:Default|LogCallbackException),\
Flags=(?:Default|LogCallbackException)\} 0 \{False, SetDefaults=False\} 0\
\{False, ToFullPath=False\} 0 {736563726574, HexPassword=736563726574} 0\
\{String, DefaultDbType=String\} 0 \{TEXT, DefaultTypeName=TEXT\} 0 \{True,\
NoSharedFlags=True\} 0 \{20, PrepareRetries=20\} 0 \{v2, ZipVfsVersion=v2\} 0\
\{test, VfsName=test\} 0 \{1000, BusyTimeout=1000\} 0 \{2000,\
ProgressOps=2000\}$}}

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

runTest {test data-1.18 {SQLiteConvert ToDateTime (Julian Day)} -body {
  set dateTime [object invoke -create System.Data.SQLite.SQLiteConvert \
      ToDateTime 2455928.0 Utc]

Added Tests/progress.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
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
###############################################################################
#
# progress.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 progress-1.1 {no progress without ProgressOps} -setup {
  setupDb [set fileName progress-1.1.db]
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

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

  unset -nocomplain results errors

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

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        private static int count = 0;

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

        public static void MyProgressHandler(
          object sender,
          ProgressEventArgs e
          )
        {
          count++;
        }

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

        public static int Main()
        {
          using (SQLiteConnection connection = new SQLiteConnection(
              "Data Source=${dataSource};[getFlagsProperty]"))
          {
            connection.Progress += MyProgressHandler;
            connection.Open();

            using (SQLiteCommand command = new SQLiteCommand("${sql}",
                connection))
            {
              command.ExecuteNonQuery();
            }
          }

          return count;
        }
      }
    }
  }] true true true 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 \
      [expr {[string is integer -strict $result] && $result == 0 ? 1 : 0}]
} -cleanup {
  cleanupDb $fileName

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

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

runTest {test progress-1.2 {simple progress counter} -setup {
  setupDb [set fileName progress-1.2.db]
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

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

  unset -nocomplain results errors

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

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        private static int count = 0;

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

        public static void MyProgressHandler(
          object sender,
          ProgressEventArgs e
          )
        {
          count++;
        }

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

        public static int Main()
        {
          using (SQLiteConnection connection = new SQLiteConnection(
              "Data Source=${dataSource};ProgressOps=1;[getFlagsProperty]"))
          {
            connection.Progress += MyProgressHandler;
            connection.Open();

            using (SQLiteCommand command = new SQLiteCommand("${sql}",
                connection))
            {
              command.ExecuteNonQuery();
            }
          }

          return count;
        }
      }
    }
  }] true true true 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 \
      [expr {[string is integer -strict $result] && $result > 0 ? 1 : 0}]
} -cleanup {
  cleanupDb $fileName

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

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

runTest {test progress-1.3 {progress with interrupt} -setup {
  setupDb [set fileName progress-1.3.db]
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

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

  unset -nocomplain results errors

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

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        private static int count = 0;

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

        public static void MyProgressHandler(
          object sender,
          ProgressEventArgs e
          )
        {
          count++;
          e.ReturnCode = SQLiteProgressReturnCode.Interrupt;
        }

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

        public static int Main()
        {
          using (SQLiteConnection connection = new SQLiteConnection(
              "Data Source=${dataSource};ProgressOps=1;[getFlagsProperty]"))
          {
            connection.Progress += MyProgressHandler;
            connection.Open();

            using (SQLiteCommand command = new SQLiteCommand("${sql}",
                connection))
            {
              command.ExecuteNonQuery();
            }
          }

          return count;
        }
      }
    }
  }] true true true 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 \
      [expr {[string is integer -strict $result] && $result > 0 ? 1 : 0}]
} -cleanup {
  cleanupDb $fileName

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

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

runTest {test progress-1.4 {progress with exception} -setup {
  setupDb [set fileName progress-1.4.db]
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

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

  unset -nocomplain results errors

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

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        private static int count = 0;

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

        public static void MyProgressHandler(
          object sender,
          ProgressEventArgs e
          )
        {
          count++;
          throw new Exception();
        }

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

        public static int Main()
        {
          using (SQLiteConnection connection = new SQLiteConnection(
              "Data Source=${dataSource};ProgressOps=1;[getFlagsProperty]"))
          {
            connection.Progress += MyProgressHandler;
            connection.Open();

            using (SQLiteCommand command = new SQLiteCommand("${sql}",
                connection))
            {
              command.ExecuteNonQuery();
            }
          }

          return count;
        }
      }
    }
  }] true true true 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 \
      [expr {[string is integer -strict $result] && $result > 0 ? 1 : 0}]
} -cleanup {
  cleanupDb $fileName

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

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

runSQLiteTestEpilogue
runTestEpilogue

Changes to readme.htm.

211
212
213
214
215
216
217



218
219
220
221
222
223
224
<p>
    <b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to <a href="https://www.sqlite.org/draft/releaselog/3_8_11.html">SQLite 3.8.11</a>.</li>
    <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for [9d353b0bd8].</li>



    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>







>
>
>







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<p>
    <b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to <a href="https://www.sqlite.org/draft/releaselog/3_8_11.html">SQLite 3.8.11</a>.</li>
    <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for [9d353b0bd8].</li>
    <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
    <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>

Changes to www/news.wiki.

5
6
7
8
9
10
11



12
13
14
15
16
17
18
<p>
    <b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to [https://www.sqlite.org/draft/releaselog/3_8_11.html|SQLite 3.8.11].</li>
    <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for [9d353b0bd8].</li>



    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Enable integration with the [http://www.hwaci.com/sw/sqlite/zipvfs.html|ZipVFS] extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>







>
>
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<p>
    <b>1.0.98.0 - August XX, 2015 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to [https://www.sqlite.org/draft/releaselog/3_8_11.html|SQLite 3.8.11].</li>
    <li>Implement the Substring method for LINQ using the &quot;substr&quot; core SQL function.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Remove errant semi-colons from the SQL used by LINQ to INSERT and then SELECT rows with composite primary keys. Fix for [9d353b0bd8].</li>
    <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
    <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Enable integration with the [http://www.hwaci.com/sw/sqlite/zipvfs.html|ZipVFS] extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>