System.Data.SQLite

Check-in [78e8297a83]
Login

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

Overview
Comment:First attempt at making virtual table support work on the .NET Compact Framework.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | virtualTables
Files: files | file ages | folders
SHA1: 78e8297a835ca07341e26447c44e2a46718e7823
User & Date: mistachkin 2013-06-25 11:55:41.393
Context
2013-06-25
19:49
Modify native argument marshalling so that it will work properly on the .NET Compact Framework. check-in: 9946328e41 user: mistachkin tags: virtualTables
11:55
First attempt at making virtual table support work on the .NET Compact Framework. check-in: 78e8297a83 user: mistachkin tags: virtualTables
09:53
When marshalling from/to the SQLiteIndex class, only marshal data members of the needed direction. The SQLiteVirtualTableCursorEnumerable class should implement the IDisposable pattern. More work on docs. check-in: c6a8523c45 user: mistachkin tags: virtualTables
Changes
Unified Diff Ignore Whitespace Patch
Changes to SQLite.Interop/src/win/interop.c.
329
330
331
332
333
334
335






























































336
337
338
339
340
341
342
  sqlite3InteropDebug("sqlite3_prepare_interop(): sqlite3_prepare16(%p, \"%s\", %d, %p) returned %d.\n", db, sql, nchars, ppstmt, n);
#endif

  *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0;

  return n;
}































































SQLITE_API int WINAPI sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val)
{
	return sqlite3_bind_double(stmt,iCol,*val);
}

SQLITE_API int WINAPI sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val)







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







329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
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
  sqlite3InteropDebug("sqlite3_prepare_interop(): sqlite3_prepare16(%p, \"%s\", %d, %p) returned %d.\n", db, sql, nchars, ppstmt, n);
#endif

  *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0;

  return n;
}

SQLITE_API void *WINAPI sqlite3_create_disposable_module_interop(
  sqlite3 *db,
  const char *zName,
  sqlite3_module *pModule,
  int iVersion,
  int (*xCreate)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
  int (*xConnect)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
  int (*xBestIndex)(sqlite3_vtab *, sqlite3_index_info*),
  int (*xDisconnect)(sqlite3_vtab *),
  int (*xDestroy)(sqlite3_vtab *),
  int (*xOpen)(sqlite3_vtab *, sqlite3_vtab_cursor **),
  int (*xClose)(sqlite3_vtab_cursor*),
  int (*xFilter)(sqlite3_vtab_cursor*, int, const char *, int, sqlite3_value **),
  int (*xNext)(sqlite3_vtab_cursor*),
  int (*xEof)(sqlite3_vtab_cursor*),
  int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int),
  int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *),
  int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *),
  int (*xBegin)(sqlite3_vtab *),
  int (*xSync)(sqlite3_vtab *),
  int (*xCommit)(sqlite3_vtab *),
  int (*xRollback)(sqlite3_vtab *),
  int (*xFindFunction)(sqlite3_vtab *, int, const char *, void (**pxFunc)(sqlite3_context*, int, sqlite3_value**), void **ppArg),
  int (*xRename)(sqlite3_vtab *, const char *),
  int (*xSavepoint)(sqlite3_vtab *, int),
  int (*xRelease)(sqlite3_vtab *, int),
  int (*xRollbackTo)(sqlite3_vtab *, int),
  void *pClientData,
  void(*xDestroyModule)(void*)
){
  memset(pModule, 0, sizeof(*pModule));
  pModule->iVersion = iVersion;
  pModule->xCreate = xCreate;
  pModule->xConnect = xConnect;
  pModule->xBestIndex = xBestIndex;
  pModule->xDisconnect = xDisconnect;
  pModule->xDestroy = xDestroy;
  pModule->xOpen = xOpen;
  pModule->xClose = xClose;
  pModule->xFilter = xFilter;
  pModule->xNext = xNext;
  pModule->xEof = xEof;
  pModule->xColumn = xColumn;
  pModule->xRowid = xRowid;
  pModule->xUpdate = xUpdate;
  pModule->xBegin = xBegin;
  pModule->xSync = xSync;
  pModule->xCommit = xCommit;
  pModule->xRollback = xRollback;
  pModule->xFindFunction = xFindFunction;
  pModule->xRename = xRename;
  pModule->xSavepoint = xSavepoint;
  pModule->xRelease = xRelease;
  pModule->xRollbackTo = xRollbackTo;
  return sqlite3_create_disposable_module(db, zName, pModule, pClientData, xDestroyModule);
}

SQLITE_API void WINAPI sqlite3_dispose_module_interop(void *pModule)
{
  sqlite3_dispose_module(pModule);
}

SQLITE_API int WINAPI sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val)
{
	return sqlite3_bind_double(stmt,iCol,*val);
}

SQLITE_API int WINAPI sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val)
Changes to System.Data.SQLite/SQLite3.cs.
1654
1655
1656
1657
1658
1659
1660

1661
1662
1663
















1664
1665
1666
1667
1668
1669
1670
        try
        {
            pName = SQLiteString.Utf8IntPtrFromString(module.Name);

            UnsafeNativeMethods.sqlite3_module nativeModule =
                module.CreateNativeModule();


            if (UnsafeNativeMethods.sqlite3_create_disposable_module(
                    _sql, pName, ref nativeModule, IntPtr.Zero,
                    null) != IntPtr.Zero)
















            {
                if (_modules == null)
                    _modules = new Dictionary<string, SQLiteModule>();

                _modules.Add(module.Name, module);
            }
            else







>



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







1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
        try
        {
            pName = SQLiteString.Utf8IntPtrFromString(module.Name);

            UnsafeNativeMethods.sqlite3_module nativeModule =
                module.CreateNativeModule();

#if !PLATFORM_COMPACTFRAMEWORK
            if (UnsafeNativeMethods.sqlite3_create_disposable_module(
                    _sql, pName, ref nativeModule, IntPtr.Zero,
                    null) != IntPtr.Zero)
#else
            if (UnsafeNativeMethods.sqlite3_create_disposable_module_interop(
                    _sql, pName, module.CreateNativeModuleInterop(),
                    nativeModule.iVersion, nativeModule.xCreate,
                    nativeModule.xConnect, nativeModule.xBestIndex,
                    nativeModule.xDisconnect, nativeModule.xDestroy,
                    nativeModule.xOpen, nativeModule.xClose,
                    nativeModule.xFilter, nativeModule.xNext,
                    nativeModule.xEof, nativeModule.xColumn,
                    nativeModule.xRowId, nativeModule.xUpdate,
                    nativeModule.xBegin, nativeModule.xSync,
                    nativeModule.xCommit, nativeModule.xRollback,
                    nativeModule.xFindFunction, nativeModule.xRename,
                    nativeModule.xSavepoint, nativeModule.xRelease,
                    nativeModule.xRollbackTo, IntPtr.Zero, null) != IntPtr.Zero)
#endif
            {
                if (_modules == null)
                    _modules = new Dictionary<string, SQLiteModule>();

                _modules.Add(module.Name, module);
            }
            else
Changes to System.Data.SQLite/SQLiteModule.cs.
5115
5116
5117
5118
5119
5120
5121











5122
5123
5124
5125
5126
5127
5128
        /// This field is used to store the native sqlite3_module structure
        /// associated with this object instance.
        /// </summary>
        private UnsafeNativeMethods.sqlite3_module nativeModule;

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












        /// <summary>
        /// This field is used to store the virtual table instances associated
        /// with this module.  The native pointer to the sqlite3_vtab derived
        /// structure is used to key into this collection.
        /// </summary>
        private Dictionary<IntPtr, SQLiteVirtualTable> tables;








>
>
>
>
>
>
>
>
>
>
>







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
        /// This field is used to store the native sqlite3_module structure
        /// associated with this object instance.
        /// </summary>
        private UnsafeNativeMethods.sqlite3_module nativeModule;

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

#if PLATFORM_COMPACTFRAMEWORK
        /// <summary>
        /// This field is used to hold the block of native memory that contains
        /// the native sqlite3_module structure associated with this object
        /// instance when running on the .NET Compact Framework.
        /// </summary>
        private IntPtr pNativeModule;
#endif

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

        /// <summary>
        /// This field is used to store the virtual table instances associated
        /// with this module.  The native pointer to the sqlite3_vtab derived
        /// structure is used to key into this collection.
        /// </summary>
        private Dictionary<IntPtr, SQLiteVirtualTable> tables;

5170
5171
5172
5173
5174
5175
5176



































5177
5178
5179
5180
5181
5182
5183
        /// default) <see cref="ISQLiteNativeModule" /> interface
        /// implementation.
        /// </returns>
        internal UnsafeNativeMethods.sqlite3_module CreateNativeModule()
        {
            return CreateNativeModule(GetNativeModuleImpl());
        }



































        #endregion

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

        #region Private Methods
        /// <summary>
        /// Creates and returns the native sqlite_module structure using the







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







5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
        /// default) <see cref="ISQLiteNativeModule" /> interface
        /// implementation.
        /// </returns>
        internal UnsafeNativeMethods.sqlite3_module CreateNativeModule()
        {
            return CreateNativeModule(GetNativeModuleImpl());
        }

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

#if PLATFORM_COMPACTFRAMEWORK
        /// <summary>
        /// Creates and returns a memory block obtained from the SQLite core
        /// library used to store the native sqlite3_module structure for this
        /// object instance when running on the .NET Compact Framework.
        /// </summary>
        /// <returns>
        /// The native pointer to the native sqlite3_module structure.
        /// </returns>
        internal IntPtr CreateNativeModuleInterop()
        {
            if (pNativeModule == IntPtr.Zero)
            {
                //
                // HACK: No easy way to determine the size of the native
                //       sqlite_module structure when running on the .NET
                //       Compact Framework; therefore, just base the size
                //       on what we know:
                //
                //       There is one integer member.
                //       There are 22 function pointers.
                //
                pNativeModule = SQLiteMemory.Allocate(
                    sizeof(int) + (22 * IntPtr.Size));

                if (pNativeModule == IntPtr.Zero)
                    throw new OutOfMemoryException("sqlite3_module");
            }

            return pNativeModule;
        }
#endif
        #endregion

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

        #region Private Methods
        /// <summary>
        /// Creates and returns the native sqlite_module structure using the
7725
7726
7727
7728
7729
7730
7731

7732
7733














7734
7735
7736
7737
7738
7739
7740

                //////////////////////////////////////
                // release unmanaged resources here...
                //////////////////////////////////////

                try
                {

                    UnsafeNativeMethods.sqlite3_dispose_module(
                        ref nativeModule);














                }
                catch (Exception e)
                {
                    try
                    {
                        if (LogExceptions)
                        {







>


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







7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801

                //////////////////////////////////////
                // release unmanaged resources here...
                //////////////////////////////////////

                try
                {
#if !PLATFORM_COMPACTFRAMEWORK
                    UnsafeNativeMethods.sqlite3_dispose_module(
                        ref nativeModule);
#else
                    if (pNativeModule != IntPtr.Zero)
                    {
                        try
                        {
                            UnsafeNativeMethods.sqlite3_dispose_module_interop(
                                pNativeModule);
                        }
                        finally
                        {
                            SQLiteMemory.Free(pNativeModule);
                        }
                    }
#endif
                }
                catch (Exception e)
                {
                    try
                    {
                        if (LogExceptions)
                        {
Changes to System.Data.SQLite/UnsafeNativeMethods.cs.
1639
1640
1641
1642
1643
1644
1645














1646
1647
1648
1649
1650
1651
1652
    internal static extern void sqlite3_value_int64_interop(IntPtr p, out Int64 value);

    [DllImport(SQLITE_DLL)]
    internal static extern void sqlite3_result_double_interop(IntPtr context, ref double value);

    [DllImport(SQLITE_DLL)]
    internal static extern void sqlite3_result_int64_interop(IntPtr context, ref Int64 value);














#endif
    // PLATFORM_COMPACTFRAMEWORK && !SQLITE_STANDARD
    #endregion

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

    #region Native Delegates







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







1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
    internal static extern void sqlite3_value_int64_interop(IntPtr p, out Int64 value);

    [DllImport(SQLITE_DLL)]
    internal static extern void sqlite3_result_double_interop(IntPtr context, ref double value);

    [DllImport(SQLITE_DLL)]
    internal static extern void sqlite3_result_int64_interop(IntPtr context, ref Int64 value);

    [DllImport(SQLITE_DLL)]
    internal static extern IntPtr sqlite3_create_disposable_module_interop(
        IntPtr db, IntPtr name, IntPtr pModule, int iVersion, xCreate xCreate,
        xConnect xConnect, xBestIndex xBestIndex, xDisconnect xDisconnect,
        xDestroy xDestroy, xOpen xOpen, xClose xClose, xFilter xFilter,
        xNext xNext, xEof xEof, xColumn xColumn, xRowId xRowId, xUpdate xUpdate,
        xBegin xBegin, xSync xSync, xCommit xCommit, xRollback xRollback,
        xFindFunction xFindFunction, xRename xRename, xSavepoint xSavepoint,
        xRelease xRelease, xRollbackTo xRollbackTo, IntPtr pClientData,
        xDestroyModule xDestroyModule);

    [DllImport(SQLITE_DLL)]
    internal static extern void sqlite3_dispose_module_interop(IntPtr pModule);
#endif
    // PLATFORM_COMPACTFRAMEWORK && !SQLITE_STANDARD
    #endregion

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

    #region Native Delegates
Changes to testce/TestCases.cs.
215
216
217
218
219
220
221




222
223
224
225
226
227
228
      try { UserCollation(cnn); frm.WriteLine("SUCCESS - UserCollation"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserCollation"); failed++; }

      total++;
      try { Int64Properties(cnn); frm.WriteLine("SUCCESS - Int64Properties"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - Int64Properties"); failed++; }





      total++;
      try { MultipleThreadStress(cnn); frm.WriteLine("SUCCESS - MultipleThreadStress"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - MultipleThreadStress"); failed++; }

      total++;
      try { DropTable(cnn); frm.WriteLine("SUCCESS - DropTable"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - DropTable"); failed++; }







>
>
>
>







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
      try { UserCollation(cnn); frm.WriteLine("SUCCESS - UserCollation"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserCollation"); failed++; }

      total++;
      try { Int64Properties(cnn); frm.WriteLine("SUCCESS - Int64Properties"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - Int64Properties"); failed++; }

      total++;
      try { ManagedVirtualTable(cnn); frm.WriteLine("SUCCESS - ManagedVirtualTable"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - ManagedVirtualTable"); failed++; }

      total++;
      try { MultipleThreadStress(cnn); frm.WriteLine("SUCCESS - MultipleThreadStress"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - MultipleThreadStress"); failed++; }

      total++;
      try { DropTable(cnn); frm.WriteLine("SUCCESS - DropTable"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - DropTable"); failed++; }
941
942
943
944
945
946
947





























































948
949
950
951
952
953
954
            foreach (long value in new long[] {
                    cnn2.LastInsertRowId, cnn2.MemoryUsed,
                    cnn2.MemoryHighwater
                })
            {
                // do nothing.
            }






























































            return;
        }

        throw new NotSupportedException("not a SQLite connection");
    }








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







945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
            foreach (long value in new long[] {
                    cnn2.LastInsertRowId, cnn2.MemoryUsed,
                    cnn2.MemoryHighwater
                })
            {
                // do nothing.
            }

            return;
        }

        throw new NotSupportedException("not a SQLite connection");
    }

    // Make sure that managed virtual table support works on the .NET Compact Framework.
    internal void ManagedVirtualTable(DbConnection cnn)
    {
        SQLiteConnection cnn2 = cnn as SQLiteConnection;

        if (cnn2 != null)
        {
            string[] result = new string[5];

            cnn2.CreateModule(new SQLiteModuleEnumerable("enumMod", new string[] {
                "one", "two", "three", "4", "5.0"
            }));

            using (SQLiteCommand command = cnn2.CreateCommand())
            {
                command.CommandText = "CREATE VIRTUAL TABLE enumTab USING enumMod;";
                command.ExecuteNonQuery();
            }

            using (SQLiteCommand command = cnn2.CreateCommand())
            {
                command.CommandText = "SELECT * FROM enumTab;";

                using (SQLiteDataReader dataReader = command.ExecuteReader())
                {
                    int index = 0;

                    while (dataReader.Read())
                        result[index++] = dataReader[0].ToString();

                    if (result[0] != "one") throw new ArgumentException("one");
                    if (result[1] != "two") throw new ArgumentException("two");
                    if (result[2] != "three") throw new ArgumentException("three");
                    if (result[3] != "4") throw new ArgumentException("4");
                    if (result[4] != "5.0") throw new ArgumentException("5.0");
                }
            }

            using (SQLiteCommand command = cnn2.CreateCommand())
            {
                command.CommandText = "UPDATE enumTab SET x = 1;";

                try
                {
                    command.ExecuteNonQuery();

                    throw new InvalidOperationException(
                        "UPDATE should throw exception");
                }
                catch (SQLiteException)
                {
                    // do nothing.
                }
            }

            return;
        }

        throw new NotSupportedException("not a SQLite connection");
    }