System.Data.SQLite
Check-in [6bf64f992e]
Not logged in

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

Overview
Comment:Support alternate VFSs when opening a database connection. More work on ZipVFS integration. This is an interim check-in and needs testing.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | zipvfs
Files: files | file ages | folders
SHA1: 6bf64f992e71087e4e956d1d3b486843ccae3c19
User & Date: mistachkin 2015-06-03 02:16:33
Context
2015-06-03
02:46
For ZipVFS, also include the 'algorithms.c' file. check-in: 694e4bfe9b user: mistachkin tags: zipvfs
02:16
Support alternate VFSs when opening a database connection. More work on ZipVFS integration. This is an interim check-in and needs testing. check-in: 6bf64f992e user: mistachkin tags: zipvfs
00:28
Add special 'placeholder' defines to the interop assembly props files. check-in: 3d46b94d99 user: mistachkin tags: zipvfs
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite.Interop/src/win/interop.c.

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
}

SQLITE_API const char *WINAPI interop_sourceid(void)
{
  return INTEROP_SOURCE_ID " " INTEROP_SOURCE_TIMESTAMP;
}

SQLITE_API int WINAPI sqlite3_open_interop(const char *filename, int flags, sqlite3 **ppdb)
{
  int ret;

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN)
  sqlite3InteropDebug("sqlite3_open_interop(): calling sqlite3_open_v2(\"%s\", %d, %p)...\n", filename, flags, ppdb);
#endif

  ret = sqlite3_open_v2(filename, ppdb, flags, NULL);

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN)
  sqlite3InteropDebug("sqlite3_open_interop(): sqlite3_open_v2(\"%s\", %d, %p) returned %d.\n", filename, flags, ppdb, ret);
#endif

#if defined(INTEROP_EXTENSION_FUNCTIONS)
  if ((ret == SQLITE_OK) && ppdb)
    RegisterExtensionFunctions(*ppdb);
#endif

  return ret;
}

SQLITE_API int WINAPI sqlite3_open16_interop(const char *filename, int flags, sqlite3 **ppdb)
{
  int ret;

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN16)
  sqlite3InteropDebug("sqlite3_open16_interop(): calling sqlite3_open_interop(\"%s\", %d, %p)...\n", filename, flags, ppdb);
#endif

  ret = sqlite3_open_interop(filename, flags, ppdb);

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN16)
  sqlite3InteropDebug("sqlite3_open16_interop(): sqlite3_open_interop(\"%s\", %d, %p) returned %d.\n", filename, flags, ppdb, ret);
#endif

  if ((ret == SQLITE_OK) && ppdb && !DbHasProperty(*ppdb, 0, DB_SchemaLoaded))
  {
    ENC(*ppdb) = SQLITE_UTF16NATIVE;

#if SQLITE_VERSION_NUMBER >= 3008008







|




|


|


|



|






|




|


|


|







360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
}

SQLITE_API const char *WINAPI interop_sourceid(void)
{
  return INTEROP_SOURCE_ID " " INTEROP_SOURCE_TIMESTAMP;
}

SQLITE_API int WINAPI sqlite3_open_interop(const char *filename, const char *vfsName, int flags, int extFuncs, sqlite3 **ppdb)
{
  int ret;

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN)
  sqlite3InteropDebug("sqlite3_open_interop(): calling sqlite3_open_v2(\"%s\", \"%s\", %d, %d, %p)...\n", filename, vfsName, flags, extFuncs, ppdb);
#endif

  ret = sqlite3_open_v2(filename, ppdb, flags, vfsName);

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN)
  sqlite3InteropDebug("sqlite3_open_interop(): sqlite3_open_v2(\"%s\", \"%s\", %d, %d, %p) returned %d.\n", filename, vfsName, flags, extFuncs, ppdb, ret);
#endif

#if defined(INTEROP_EXTENSION_FUNCTIONS)
  if ((ret == SQLITE_OK) && ppdb && extFuncs)
    RegisterExtensionFunctions(*ppdb);
#endif

  return ret;
}

SQLITE_API int WINAPI sqlite3_open16_interop(const char *filename, const char *vfsName, int flags, int extFuncs, sqlite3 **ppdb)
{
  int ret;

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN16)
  sqlite3InteropDebug("sqlite3_open16_interop(): calling sqlite3_open_interop(\"%s\", \"%s\", %d, %d, %p)...\n", filename, vfsName, flags, extFuncs, ppdb);
#endif

  ret = sqlite3_open_interop(filename, vfsName, flags, extFuncs, ppdb);

#if defined(INTEROP_DEBUG) && (INTEROP_DEBUG & INTEROP_DEBUG_OPEN16)
  sqlite3InteropDebug("sqlite3_open16_interop(): sqlite3_open_interop(\"%s\", \"%s\", %d, %d, %p) returned %d.\n", filename, vfsName, flags, extFuncs, ppdb, ret);
#endif

  if ((ret == SQLITE_OK) && ppdb && !DbHasProperty(*ppdb, 0, DB_SchemaLoaded))
  {
    ENC(*ppdb) = SQLITE_UTF16NATIVE;

#if SQLITE_VERSION_NUMBER >= 3008008

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

688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
...
729
730
731
732
733
734
735
736
737


738
739
740
741
742
743
744
745
746
747
748
749
750
...
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
    /// Non-zero if the associated native connection handle is open.
    /// </returns>
    internal override bool IsOpen()
    {
        return (_sql != null) && !_sql.IsInvalid && !_sql.IsClosed;
    }

    internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
    {
      //
      // 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.
      //
................................................................................
        }
        finally /* NOTE: Thread.Abort() protection. */
        {
          IntPtr db = IntPtr.Zero;
          SQLiteErrorCode n;

#if !SQLITE_STANDARD
          if ((connectionFlags & SQLiteConnectionFlags.NoExtensionFunctions) != SQLiteConnectionFlags.NoExtensionFunctions)
          {


            n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), openFlags, ref db);
          }
          else
#endif
          {
            n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), ref db, openFlags, IntPtr.Zero);
          }

#if !NET_COMPACT_20 && TRACE_CONNECTION
          Trace.WriteLine(String.Format("Open: {0}", db));
#endif

          if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
................................................................................
          _sql = new SQLiteConnectionHandle(db, true);
        }
        lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }

        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
            SQLiteConnectionEventType.NewCriticalHandle, null, null,
            null, null, _sql, strFilename, new object[] { strFilename,
            connectionFlags, openFlags, maxPoolSize, usePool }));
      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)







|







 







|
|
>
>
|




|







 







|







688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
...
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
    /// Non-zero if the associated native connection handle is open.
    /// </returns>
    internal override bool IsOpen()
    {
        return (_sql != null) && !_sql.IsInvalid && !_sql.IsClosed;
    }

    internal override void Open(string strFilename, string vfsName, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
    {
      //
      // 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.
      //
................................................................................
        }
        finally /* NOTE: Thread.Abort() protection. */
        {
          IntPtr db = IntPtr.Zero;
          SQLiteErrorCode n;

#if !SQLITE_STANDARD
          int extFuncs = ((connectionFlags & SQLiteConnectionFlags.NoExtensionFunctions) != SQLiteConnectionFlags.NoExtensionFunctions) ? 1 : 0;

          if (extFuncs != 0)
          {
            n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), ToUTF8(vfsName), openFlags, extFuncs, ref db);
          }
          else
#endif
          {
            n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), ref db, openFlags, ToUTF8(vfsName));
          }

#if !NET_COMPACT_20 && TRACE_CONNECTION
          Trace.WriteLine(String.Format("Open: {0}", db));
#endif

          if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
................................................................................
          _sql = new SQLiteConnectionHandle(db, true);
        }
        lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }

        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
            SQLiteConnectionEventType.NewCriticalHandle, null, null,
            null, null, _sql, strFilename, new object[] { strFilename,
            vfsName, connectionFlags, openFlags, maxPoolSize, usePool }));
      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)

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

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
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
...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

      if (nbytelen == -1)
        return Marshal.PtrToStringUni(b);
      else
        return Marshal.PtrToStringUni(b, nbytelen / 2);
    }

    internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
    {
      //
      // 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.
      //
................................................................................
            // do nothing.
        }
        finally /* NOTE: Thread.Abort() protection. */
        {
          IntPtr db = IntPtr.Zero;
          SQLiteErrorCode n;



#if !SQLITE_STANDARD
          if ((connectionFlags & SQLiteConnectionFlags.NoExtensionFunctions) != SQLiteConnectionFlags.NoExtensionFunctions)

          {
            n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), openFlags, ref db);
          }
          else
#endif
          {
            //
            // NOTE: This flag check is designed to enforce the constraint that opening
            //       a database file that does not already exist requires specifying the
            //       "Create" flag, even when a native API is used that does not accept
            //       a flags parameter.
            //
            if (((openFlags & SQLiteOpenFlagsEnum.Create) != SQLiteOpenFlagsEnum.Create) && !File.Exists(strFilename))
              throw new SQLiteException(SQLiteErrorCode.CantOpen, strFilename);







            n = UnsafeNativeMethods.sqlite3_open16(strFilename, ref db);
          }

#if !NET_COMPACT_20 && TRACE_CONNECTION
          Trace.WriteLine(String.Format("Open16: {0}", db));
#endif
................................................................................
          _sql = new SQLiteConnectionHandle(db, true);
        }
        lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }

        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
            SQLiteConnectionEventType.NewCriticalHandle, null, null,
            null, null, _sql, strFilename, new object[] { strFilename,
            connectionFlags, openFlags, maxPoolSize, usePool }));
      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)







|







 







>
>

<
>

|












>
>
>
>
>
>







 







|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
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
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

      if (nbytelen == -1)
        return Marshal.PtrToStringUni(b);
      else
        return Marshal.PtrToStringUni(b, nbytelen / 2);
    }

    internal override void Open(string strFilename, string vfsName, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool)
    {
      //
      // 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.
      //
................................................................................
            // do nothing.
        }
        finally /* NOTE: Thread.Abort() protection. */
        {
          IntPtr db = IntPtr.Zero;
          SQLiteErrorCode n;

          int extFuncs = ((connectionFlags & SQLiteConnectionFlags.NoExtensionFunctions) != SQLiteConnectionFlags.NoExtensionFunctions) ? 1 : 0;

#if !SQLITE_STANDARD

          if ((vfsName != null) || (extFuncs != 0))
          {
            n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), ToUTF8(vfsName), openFlags, extFuncs, ref db);
          }
          else
#endif
          {
            //
            // NOTE: This flag check is designed to enforce the constraint that opening
            //       a database file that does not already exist requires specifying the
            //       "Create" flag, even when a native API is used that does not accept
            //       a flags parameter.
            //
            if (((openFlags & SQLiteOpenFlagsEnum.Create) != SQLiteOpenFlagsEnum.Create) && !File.Exists(strFilename))
              throw new SQLiteException(SQLiteErrorCode.CantOpen, strFilename);

            if (vfsName != null)
            {
              throw new SQLiteException(SQLiteErrorCode.CantOpen, String.Format(
                "cannot open using UTF-16 and VFS \"{0}\": need interop assembly", vfsName));
            }

            n = UnsafeNativeMethods.sqlite3_open16(strFilename, ref db);
          }

#if !NET_COMPACT_20 && TRACE_CONNECTION
          Trace.WriteLine(String.Format("Open16: {0}", db));
#endif
................................................................................
          _sql = new SQLiteConnectionHandle(db, true);
        }
        lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }

        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
            SQLiteConnectionEventType.NewCriticalHandle, null, null,
            null, null, _sql, strFilename, new object[] { strFilename,
            vfsName, connectionFlags, openFlags, maxPoolSize, usePool }));
      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)

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

91
92
93
94
95
96
97

98
99
100
101
102
103
104
105
106
107
108
109
    /// Opens a database.
    /// </summary>
    /// <remarks>
    /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection
    /// to bind all attributed user-defined functions and collating sequences to the new connection.
    /// </remarks>
    /// <param name="strFilename">The filename of the database to open.  SQLite automatically creates it if it doesn't exist.</param>

    /// <param name="connectionFlags">The flags associated with the parent connection object</param>
    /// <param name="openFlags">The open flags to use when creating the connection</param>
    /// <param name="maxPoolSize">The maximum size of the pool for the given filename</param>
    /// <param name="usePool">If true, the connection can be pulled from the connection pool</param>
    internal abstract void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool);
    /// <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>







>




|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    /// Opens a database.
    /// </summary>
    /// <remarks>
    /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection
    /// to bind all attributed user-defined functions and collating sequences to the new connection.
    /// </remarks>
    /// <param name="strFilename">The filename of the database to open.  SQLite automatically creates it if it doesn't exist.</param>
    /// <param name="vfsName">The name of the VFS to use -OR- null to use the default VFS.</param>
    /// <param name="connectionFlags">The flags associated with the parent connection object</param>
    /// <param name="openFlags">The open flags to use when creating the connection</param>
    /// <param name="maxPoolSize">The maximum size of the pool for the given filename</param>
    /// <param name="usePool">If true, the connection can be pulled from the connection pool</param>
    internal abstract void Open(string strFilename, string vfsName, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool);
    /// <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>

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

384
385
386
387
388
389
390








391
392
393
394
395
396
397
...
521
522
523
524
525
526
527





528
529
530
531
532
533
534
...
676
677
678
679
680
681
682

683
684
685
686
687
688
689
....
2494
2495
2496
2497
2498
2499
2500

2501
2502
2503
2504
2505
2506
2507
2508
2509






















2510
2511
2512
2513
2514
2515
2516
....
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
....
2834
2835
2836
2837
2838
2839
2840










2841
2842
2843
2844
2845
2846
2847
    private const bool DefaultToFullPath = true;
    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 int SQLITE_FCNTL_CHUNK_SIZE = 6;
    private const int SQLITE_FCNTL_WIN32_AV_RETRY = 9;

    private const string _dataDirectory = "|DataDirectory|";
    private const string _masterdb = "sqlite_master";
    private const string _tempmasterdb = "sqlite_temp_master";
................................................................................
    /// <summary>
    /// The default databse type name for this connection.  This value will only
    /// be used if the <see cref="SQLiteConnectionFlags.UseConnectionTypes" />
    /// flag is set.
    /// </summary>
    private string _defaultTypeName;






    /// <summary>
    /// Default command timeout
    /// </summary>
    private int _defaultTimeout = DefaultConnectionTimeout;

    /// <summary>
    /// The maximum number of retries when preparing SQL to be executed.  This
................................................................................
          new TypeNameStringComparer());

      _typeNames = new SQLiteDbTypeMap();
      _parseViaFramework = parseViaFramework;
      _flags = SQLiteConnectionFlags.Default;
      _defaultDbType = null;
      _defaultTypeName = null;

      _connectionState = ConnectionState.Closed;
      _connectionString = null;

      if (connectionString != null)
        ConnectionString = connectionString;
    }

................................................................................
      //       SQLiteConnectionStringBuilder.DefaultDbType property to null
      //       here.
      //
      if ((_defaultDbType != null) && ((DbType)_defaultDbType == BadDbType))
        _defaultDbType = null;

      _defaultTypeName = FindKey(opts, "DefaultTypeName", null);


#if !NET_COMPACT_20 && TRACE_WARNING
      bool uri = false;
#endif
      bool fullUri = false;
      string fileName;

      if (Convert.ToInt32(FindKey(opts, "Version", DefaultVersion.ToString()), CultureInfo.InvariantCulture) != DefaultVersion)
        throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, "Only SQLite Version {0} is supported at this time", DefaultVersion));























      fileName = FindKey(opts, "Data Source", DefaultDataSource);

      if (String.IsNullOrEmpty(fileName))
      {
        fileName = FindKey(opts, "Uri", DefaultUri);
        if (String.IsNullOrEmpty(fileName))
................................................................................
        {
          flags |= SQLiteOpenFlagsEnum.ReadWrite;
        }

        if (fullUri)
            flags |= SQLiteOpenFlagsEnum.Uri;

        _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling);

        _binaryGuid = SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", DefaultBinaryGUID.ToString()));

#if INTEROP_CODEC || INTEROP_INCLUDE_SEE
        string hexPassword = FindKey(opts, "HexPassword", DefaultHexPassword);

        if (hexPassword != null)
................................................................................
    /// value will only be used when not null.
    /// </summary>
    public string DefaultTypeName
    {
      get { CheckDisposed(); return _defaultTypeName; }
      set { CheckDisposed(); _defaultTypeName = value; }
    }











    /// <summary>
    /// Returns non-zero if the underlying native connection handle is
    /// owned by this instance.
    /// </summary>
    public bool OwnHandle
    {







>
>
>
>
>
>
>
>







 







>
>
>
>
>







 







>







 







>









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







 







|







 







>
>
>
>
>
>
>
>
>
>







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
....
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
....
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
....
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
    private const bool DefaultToFullPath = true;
    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_V2 = "v2";
    private const string ZipVfs_V3 = "v3";

    private const string DefaultZipVfsVersion = null;
#endif

    private const int SQLITE_FCNTL_CHUNK_SIZE = 6;
    private const int SQLITE_FCNTL_WIN32_AV_RETRY = 9;

    private const string _dataDirectory = "|DataDirectory|";
    private const string _masterdb = "sqlite_master";
    private const string _tempmasterdb = "sqlite_temp_master";
................................................................................
    /// <summary>
    /// The default databse type name for this connection.  This value will only
    /// be used if the <see cref="SQLiteConnectionFlags.UseConnectionTypes" />
    /// flag is set.
    /// </summary>
    private string _defaultTypeName;

    /// <summary>
    /// The name of the VFS to be used when opening the database connection.
    /// </summary>
    private string _vfsName;

    /// <summary>
    /// Default command timeout
    /// </summary>
    private int _defaultTimeout = DefaultConnectionTimeout;

    /// <summary>
    /// The maximum number of retries when preparing SQL to be executed.  This
................................................................................
          new TypeNameStringComparer());

      _typeNames = new SQLiteDbTypeMap();
      _parseViaFramework = parseViaFramework;
      _flags = SQLiteConnectionFlags.Default;
      _defaultDbType = null;
      _defaultTypeName = null;
      _vfsName = null;
      _connectionState = ConnectionState.Closed;
      _connectionString = null;

      if (connectionString != null)
        ConnectionString = connectionString;
    }

................................................................................
      //       SQLiteConnectionStringBuilder.DefaultDbType property to null
      //       here.
      //
      if ((_defaultDbType != null) && ((DbType)_defaultDbType == BadDbType))
        _defaultDbType = null;

      _defaultTypeName = FindKey(opts, "DefaultTypeName", null);
      _vfsName = FindKey(opts, "VfsName", DefaultVfsName);

#if !NET_COMPACT_20 && TRACE_WARNING
      bool uri = false;
#endif
      bool fullUri = false;
      string fileName;

      if (Convert.ToInt32(FindKey(opts, "Version", DefaultVersion.ToString()), CultureInfo.InvariantCulture) != DefaultVersion)
        throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, "Only SQLite Version {0} is supported at this time", DefaultVersion));

#if INTEROP_INCLUDE_ZIPVFS
      string zipVfsVersion = FindKey(opts, "ZipVfsVersion", DefaultZipVfsVersion);

      if (zipVfsVersion != null)
      {
          if (String.Compare(zipVfsVersion, ZipVfs_V2) == 0)
          {
              UnsafeNativeMethods.zipvfsInit_v2();
          }
          else if (String.Compare(zipVfsVersion, ZipVfs_V3) == 0)
          {
              UnsafeNativeMethods.zipvfsInit_v3(0);
          }
          else
          {
              throw new NotSupportedException(String.Format(
                  CultureInfo.CurrentCulture, "Only ZipVFS versions {0} and {1} are supported at this time",
                  ZipVfs_V2, ZipVfs_V3));
          }
      }
#endif

      fileName = FindKey(opts, "Data Source", DefaultDataSource);

      if (String.IsNullOrEmpty(fileName))
      {
        fileName = FindKey(opts, "Uri", DefaultUri);
        if (String.IsNullOrEmpty(fileName))
................................................................................
        {
          flags |= SQLiteOpenFlagsEnum.ReadWrite;
        }

        if (fullUri)
            flags |= SQLiteOpenFlagsEnum.Uri;

        _sql.Open(fileName, _vfsName, _flags, flags, maxPoolSize, usePooling);

        _binaryGuid = SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", DefaultBinaryGUID.ToString()));

#if INTEROP_CODEC || INTEROP_INCLUDE_SEE
        string hexPassword = FindKey(opts, "HexPassword", DefaultHexPassword);

        if (hexPassword != null)
................................................................................
    /// value will only be used when not null.
    /// </summary>
    public string DefaultTypeName
    {
      get { CheckDisposed(); return _defaultTypeName; }
      set { CheckDisposed(); _defaultTypeName = value; }
    }

    /// <summary>
    /// Gets/sets the VFS name for this connection.  This value will only be
    /// used when opening the database.
    /// </summary>
    public string VfsName
    {
      get { CheckDisposed(); return _vfsName; }
      set { CheckDisposed(); _vfsName = value; }
    }

    /// <summary>
    /// Returns non-zero if the underlying native connection handle is
    /// owned by this instance.
    /// </summary>
    public bool OwnHandle
    {

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

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
...
664
665
666
667
668
669
670
671
672
673
674
675
676
677




















678
679
680
681
682
683
684
...
691
692
693
694
695
696
697























698
699
700
701
702
703
704
    [DefaultValue("")]
    public string DataSource
    {
      get
      {
        object value;
        TryGetValue("data source", out value);
        return value.ToString();
      }
      set
      {
        this["data source"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string Uri
    {
      get
      {
        object value;
        TryGetValue("uri", out value);
        return value.ToString();
      }
      set
      {
        this["uri"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string FullUri
    {
      get
      {
        object value;
        TryGetValue("fulluri", out value);
        return value.ToString();
      }
      set
      {
        this["fulluri"] = value;
      }
    }

................................................................................
    [DefaultValue("")]
    public string Password
    {
      get
      {
        object value;
        TryGetValue("password", out value);
        return value.ToString();
      }
      set
      {
        this["password"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string DefaultTypeName
    {
        get
        {
            object value;
            TryGetValue("defaulttypename", out value);
            return value.ToString();
        }
        set
        {
            this["defaulttypename"] = value;
        }
    }





















    /// <summary>
    /// If enabled, use foreign key constraints
    /// </summary>
    [DisplayName("Foreign Keys")]
    [Browsable(true)]
    [DefaultValue(false)]
................................................................................
            return SQLiteConvert.ToBoolean(value);
        }
        set
        {
            this["foreign keys"] = value;
        }
    }
























    /// <summary>
    /// Gets/Sets the extra behavioral flags.
    /// </summary>
    [Browsable(true)]
    [DefaultValue(SQLiteConnectionFlags.Default)]
    public SQLiteConnectionFlags Flags







|







 







|







 







|







 







|







 







|






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







 







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







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
    [DefaultValue("")]
    public string DataSource
    {
      get
      {
        object value;
        TryGetValue("data source", out value);
        return (value != null) ? value.ToString() : null;
      }
      set
      {
        this["data source"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string Uri
    {
      get
      {
        object value;
        TryGetValue("uri", out value);
        return (value != null) ? value.ToString() : null;
      }
      set
      {
        this["uri"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string FullUri
    {
      get
      {
        object value;
        TryGetValue("fulluri", out value);
        return (value != null) ? value.ToString() : null;
      }
      set
      {
        this["fulluri"] = value;
      }
    }

................................................................................
    [DefaultValue("")]
    public string Password
    {
      get
      {
        object value;
        TryGetValue("password", out value);
        return (value != null) ? value.ToString() : null;
      }
      set
      {
        this["password"] = value;
      }
    }

................................................................................
    [DefaultValue(null)]
    public string DefaultTypeName
    {
        get
        {
            object value;
            TryGetValue("defaulttypename", out value);
            return (value != null) ? value.ToString() : null;
        }
        set
        {
            this["defaulttypename"] = value;
        }
    }

    /// <summary>
    /// Gets/sets the VFS name for the connection.
    /// </summary>
    [DisplayName("VFS Name")]
    [Browsable(true)]
    [DefaultValue(null)]
    public string VfsName
    {
        get
        {
            object value;
            TryGetValue("vfsname", out value);
            return (value != null) ? value.ToString() : null;
        }
        set
        {
            this["vfsname"] = value;
        }
    }

    /// <summary>
    /// If enabled, use foreign key constraints
    /// </summary>
    [DisplayName("Foreign Keys")]
    [Browsable(true)]
    [DefaultValue(false)]
................................................................................
            return SQLiteConvert.ToBoolean(value);
        }
        set
        {
            this["foreign keys"] = value;
        }
    }

    /// <summary>
    /// If non-null, this is the version of ZipVFS to use.  This requires the
    /// System.Data.SQLite interop assembly -AND- primary managed assembly to
    /// be compiled with the INTEROP_INCLUDE_ZIPVFS option; otherwise, this
    /// property does nothing.
    /// </summary>
    [DisplayName("ZipVFS Version")]
    [Browsable(true)]
    [DefaultValue(null)]
    public string ZipVfsVersion
    {
        get
        {
            object value;
            TryGetValue("zipvfsversion", out value);
            return (value != null) ? value.ToString() : null;
        }
        set
        {
            this["zipvfsversion"] = value;
        }
    }

    /// <summary>
    /// Gets/Sets the extra behavioral flags.
    /// </summary>
    [Browsable(true)]
    [DefaultValue(SQLiteConnectionFlags.Default)]
    public SQLiteConnectionFlags Flags

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

152
153
154
155
156
157
158

159
160
161
162
163
164
165
    /// <summary>
    /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.
    /// </summary>
    /// <param name="sourceText">The string to convert to UTF-8</param>
    /// <returns>A byte array containing the converted string plus an extra 0 terminating byte at the end of the array.</returns>
    public static byte[] ToUTF8(string sourceText)
    {

      Byte[] byteArray;
      int nlen = _utf8.GetByteCount(sourceText) + 1;

      byteArray = new byte[nlen];
      nlen = _utf8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);
      byteArray[nlen] = 0;








>







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    /// <summary>
    /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.
    /// </summary>
    /// <param name="sourceText">The string to convert to UTF-8</param>
    /// <returns>A byte array containing the converted string plus an extra 0 terminating byte at the end of the array.</returns>
    public static byte[] ToUTF8(string sourceText)
    {
      if (sourceText == null) return null;
      Byte[] byteArray;
      int nlen = _utf8.GetByteCount(sourceText) + 1;

      byteArray = new byte[nlen];
      nlen = _utf8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);
      byteArray[nlen] = 0;

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

1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
....
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
....
2105
2106
2107
2108
2109
2110
2111
















2112
2113
2114
2115
2116
2117
2118
    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_finalize_interop(IntPtr stmt);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_backup_finish_interop(IntPtr backup);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_open_interop(byte[] utf8Filename, SQLiteOpenFlagsEnum flags, ref IntPtr db);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_open16_interop(byte[] utf8Filename, SQLiteOpenFlagsEnum flags, ref IntPtr db);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_reset_interop(IntPtr stmt);

    [DllImport(SQLITE_DLL)]
    internal static extern int sqlite3_changes_interop(IntPtr db);
#endif
................................................................................
    internal static extern void sqlite3_free(IntPtr p);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern SQLiteErrorCode sqlite3_open_v2(byte[] utf8Filename, ref IntPtr db, SQLiteOpenFlagsEnum flags, IntPtr vfs);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
#else
    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
#endif
    internal static extern SQLiteErrorCode sqlite3_open16(string fileName, ref IntPtr db);
................................................................................
#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern SQLiteErrorCode sqlite3_rekey(IntPtr db, byte[] key, int keylen);
#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);







|


|







 







|







 







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







1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
....
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
....
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_finalize_interop(IntPtr stmt);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_backup_finish_interop(IntPtr backup);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_open_interop(byte[] utf8Filename, byte[] vfsName, SQLiteOpenFlagsEnum flags, int extFuncs, ref IntPtr db);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_open16_interop(byte[] utf8Filename, byte[] vfsName, SQLiteOpenFlagsEnum flags, int extFuncs, ref IntPtr db);

    [DllImport(SQLITE_DLL)]
    internal static extern SQLiteErrorCode sqlite3_reset_interop(IntPtr stmt);

    [DllImport(SQLITE_DLL)]
    internal static extern int sqlite3_changes_interop(IntPtr db);
#endif
................................................................................
    internal static extern void sqlite3_free(IntPtr p);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern SQLiteErrorCode sqlite3_open_v2(byte[] utf8Filename, ref IntPtr db, SQLiteOpenFlagsEnum flags, byte[] vfsName);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
#else
    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
#endif
    internal static extern SQLiteErrorCode sqlite3_open16(string fileName, ref IntPtr db);
................................................................................
#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern SQLiteErrorCode sqlite3_rekey(IntPtr db, byte[] key, int keylen);
#endif

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

#if !PLATFORM_COMPACTFRAMEWORK
    [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);

Changes to Tests/basic.eagle.

1049
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
....
1102
1103
1104
1105
1106
1107
1108
1109

1110
1111
1112
1113
1114
1115
1116
    set keys [list null Version Synchronous UseUTF16Encoding Pooling \
                   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]


    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]

    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]

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

................................................................................
DateTimeFormatString=yyyy-MM-dd\} 0 \{sqlite_schema,\
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\}$}}


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

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








|
>








|









|







 







|
>







1049
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
....
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
    set keys [list null Version Synchronous UseUTF16Encoding Pooling \
                   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]

    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 v3 test]

    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]

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

................................................................................
DateTimeFormatString=yyyy-MM-dd\} 0 \{sqlite_schema,\
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\}$}}

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

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