System.Data.SQLite
Check-in [78e8297a83]
Not logged in

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 | SQL archive
Timelines: family | ancestors | descendants | both | virtualTables
Files: files | file ages | folders
SHA1: 78e8297a835ca07341e26447c44e2a46718e7823
User & Date: mistachkin 2013-06-25 11:55:41
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
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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

   329    329     sqlite3InteropDebug("sqlite3_prepare_interop(): sqlite3_prepare16(%p, \"%s\", %d, %p) returned %d.\n", db, sql, nchars, ppstmt, n);
   330    330   #endif
   331    331   
   332    332     *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0;
   333    333   
   334    334     return n;
   335    335   }
          336  +
          337  +SQLITE_API void *WINAPI sqlite3_create_disposable_module_interop(
          338  +  sqlite3 *db,
          339  +  const char *zName,
          340  +  sqlite3_module *pModule,
          341  +  int iVersion,
          342  +  int (*xCreate)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
          343  +  int (*xConnect)(sqlite3*, void *, int, const char *const*, sqlite3_vtab **, char**),
          344  +  int (*xBestIndex)(sqlite3_vtab *, sqlite3_index_info*),
          345  +  int (*xDisconnect)(sqlite3_vtab *),
          346  +  int (*xDestroy)(sqlite3_vtab *),
          347  +  int (*xOpen)(sqlite3_vtab *, sqlite3_vtab_cursor **),
          348  +  int (*xClose)(sqlite3_vtab_cursor*),
          349  +  int (*xFilter)(sqlite3_vtab_cursor*, int, const char *, int, sqlite3_value **),
          350  +  int (*xNext)(sqlite3_vtab_cursor*),
          351  +  int (*xEof)(sqlite3_vtab_cursor*),
          352  +  int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int),
          353  +  int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *),
          354  +  int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *),
          355  +  int (*xBegin)(sqlite3_vtab *),
          356  +  int (*xSync)(sqlite3_vtab *),
          357  +  int (*xCommit)(sqlite3_vtab *),
          358  +  int (*xRollback)(sqlite3_vtab *),
          359  +  int (*xFindFunction)(sqlite3_vtab *, int, const char *, void (**pxFunc)(sqlite3_context*, int, sqlite3_value**), void **ppArg),
          360  +  int (*xRename)(sqlite3_vtab *, const char *),
          361  +  int (*xSavepoint)(sqlite3_vtab *, int),
          362  +  int (*xRelease)(sqlite3_vtab *, int),
          363  +  int (*xRollbackTo)(sqlite3_vtab *, int),
          364  +  void *pClientData,
          365  +  void(*xDestroyModule)(void*)
          366  +){
          367  +  memset(pModule, 0, sizeof(*pModule));
          368  +  pModule->iVersion = iVersion;
          369  +  pModule->xCreate = xCreate;
          370  +  pModule->xConnect = xConnect;
          371  +  pModule->xBestIndex = xBestIndex;
          372  +  pModule->xDisconnect = xDisconnect;
          373  +  pModule->xDestroy = xDestroy;
          374  +  pModule->xOpen = xOpen;
          375  +  pModule->xClose = xClose;
          376  +  pModule->xFilter = xFilter;
          377  +  pModule->xNext = xNext;
          378  +  pModule->xEof = xEof;
          379  +  pModule->xColumn = xColumn;
          380  +  pModule->xRowid = xRowid;
          381  +  pModule->xUpdate = xUpdate;
          382  +  pModule->xBegin = xBegin;
          383  +  pModule->xSync = xSync;
          384  +  pModule->xCommit = xCommit;
          385  +  pModule->xRollback = xRollback;
          386  +  pModule->xFindFunction = xFindFunction;
          387  +  pModule->xRename = xRename;
          388  +  pModule->xSavepoint = xSavepoint;
          389  +  pModule->xRelease = xRelease;
          390  +  pModule->xRollbackTo = xRollbackTo;
          391  +  return sqlite3_create_disposable_module(db, zName, pModule, pClientData, xDestroyModule);
          392  +}
          393  +
          394  +SQLITE_API void WINAPI sqlite3_dispose_module_interop(void *pModule)
          395  +{
          396  +  sqlite3_dispose_module(pModule);
          397  +}
   336    398   
   337    399   SQLITE_API int WINAPI sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val)
   338    400   {
   339    401   	return sqlite3_bind_double(stmt,iCol,*val);
   340    402   }
   341    403   
   342    404   SQLITE_API int WINAPI sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val)

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

  1654   1654           try
  1655   1655           {
  1656   1656               pName = SQLiteString.Utf8IntPtrFromString(module.Name);
  1657   1657   
  1658   1658               UnsafeNativeMethods.sqlite3_module nativeModule =
  1659   1659                   module.CreateNativeModule();
  1660   1660   
         1661  +#if !PLATFORM_COMPACTFRAMEWORK
  1661   1662               if (UnsafeNativeMethods.sqlite3_create_disposable_module(
  1662   1663                       _sql, pName, ref nativeModule, IntPtr.Zero,
  1663   1664                       null) != IntPtr.Zero)
         1665  +#else
         1666  +            if (UnsafeNativeMethods.sqlite3_create_disposable_module_interop(
         1667  +                    _sql, pName, module.CreateNativeModuleInterop(),
         1668  +                    nativeModule.iVersion, nativeModule.xCreate,
         1669  +                    nativeModule.xConnect, nativeModule.xBestIndex,
         1670  +                    nativeModule.xDisconnect, nativeModule.xDestroy,
         1671  +                    nativeModule.xOpen, nativeModule.xClose,
         1672  +                    nativeModule.xFilter, nativeModule.xNext,
         1673  +                    nativeModule.xEof, nativeModule.xColumn,
         1674  +                    nativeModule.xRowId, nativeModule.xUpdate,
         1675  +                    nativeModule.xBegin, nativeModule.xSync,
         1676  +                    nativeModule.xCommit, nativeModule.xRollback,
         1677  +                    nativeModule.xFindFunction, nativeModule.xRename,
         1678  +                    nativeModule.xSavepoint, nativeModule.xRelease,
         1679  +                    nativeModule.xRollbackTo, IntPtr.Zero, null) != IntPtr.Zero)
         1680  +#endif
  1664   1681               {
  1665   1682                   if (_modules == null)
  1666   1683                       _modules = new Dictionary<string, SQLiteModule>();
  1667   1684   
  1668   1685                   _modules.Add(module.Name, module);
  1669   1686               }
  1670   1687               else

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

  5115   5115           /// This field is used to store the native sqlite3_module structure
  5116   5116           /// associated with this object instance.
  5117   5117           /// </summary>
  5118   5118           private UnsafeNativeMethods.sqlite3_module nativeModule;
  5119   5119   
  5120   5120           ///////////////////////////////////////////////////////////////////////
  5121   5121   
         5122  +#if PLATFORM_COMPACTFRAMEWORK
         5123  +        /// <summary>
         5124  +        /// This field is used to hold the block of native memory that contains
         5125  +        /// the native sqlite3_module structure associated with this object
         5126  +        /// instance when running on the .NET Compact Framework.
         5127  +        /// </summary>
         5128  +        private IntPtr pNativeModule;
         5129  +#endif
         5130  +
         5131  +        ///////////////////////////////////////////////////////////////////////
         5132  +
  5122   5133           /// <summary>
  5123   5134           /// This field is used to store the virtual table instances associated
  5124   5135           /// with this module.  The native pointer to the sqlite3_vtab derived
  5125   5136           /// structure is used to key into this collection.
  5126   5137           /// </summary>
  5127   5138           private Dictionary<IntPtr, SQLiteVirtualTable> tables;
  5128   5139   
................................................................................
  5170   5181           /// default) <see cref="ISQLiteNativeModule" /> interface
  5171   5182           /// implementation.
  5172   5183           /// </returns>
  5173   5184           internal UnsafeNativeMethods.sqlite3_module CreateNativeModule()
  5174   5185           {
  5175   5186               return CreateNativeModule(GetNativeModuleImpl());
  5176   5187           }
         5188  +
         5189  +        ///////////////////////////////////////////////////////////////////////
         5190  +
         5191  +#if PLATFORM_COMPACTFRAMEWORK
         5192  +        /// <summary>
         5193  +        /// Creates and returns a memory block obtained from the SQLite core
         5194  +        /// library used to store the native sqlite3_module structure for this
         5195  +        /// object instance when running on the .NET Compact Framework.
         5196  +        /// </summary>
         5197  +        /// <returns>
         5198  +        /// The native pointer to the native sqlite3_module structure.
         5199  +        /// </returns>
         5200  +        internal IntPtr CreateNativeModuleInterop()
         5201  +        {
         5202  +            if (pNativeModule == IntPtr.Zero)
         5203  +            {
         5204  +                //
         5205  +                // HACK: No easy way to determine the size of the native
         5206  +                //       sqlite_module structure when running on the .NET
         5207  +                //       Compact Framework; therefore, just base the size
         5208  +                //       on what we know:
         5209  +                //
         5210  +                //       There is one integer member.
         5211  +                //       There are 22 function pointers.
         5212  +                //
         5213  +                pNativeModule = SQLiteMemory.Allocate(
         5214  +                    sizeof(int) + (22 * IntPtr.Size));
         5215  +
         5216  +                if (pNativeModule == IntPtr.Zero)
         5217  +                    throw new OutOfMemoryException("sqlite3_module");
         5218  +            }
         5219  +
         5220  +            return pNativeModule;
         5221  +        }
         5222  +#endif
  5177   5223           #endregion
  5178   5224   
  5179   5225           ///////////////////////////////////////////////////////////////////////
  5180   5226   
  5181   5227           #region Private Methods
  5182   5228           /// <summary>
  5183   5229           /// Creates and returns the native sqlite_module structure using the
................................................................................
  7725   7771   
  7726   7772                   //////////////////////////////////////
  7727   7773                   // release unmanaged resources here...
  7728   7774                   //////////////////////////////////////
  7729   7775   
  7730   7776                   try
  7731   7777                   {
         7778  +#if !PLATFORM_COMPACTFRAMEWORK
  7732   7779                       UnsafeNativeMethods.sqlite3_dispose_module(
  7733   7780                           ref nativeModule);
         7781  +#else
         7782  +                    if (pNativeModule != IntPtr.Zero)
         7783  +                    {
         7784  +                        try
         7785  +                        {
         7786  +                            UnsafeNativeMethods.sqlite3_dispose_module_interop(
         7787  +                                pNativeModule);
         7788  +                        }
         7789  +                        finally
         7790  +                        {
         7791  +                            SQLiteMemory.Free(pNativeModule);
         7792  +                        }
         7793  +                    }
         7794  +#endif
  7734   7795                   }
  7735   7796                   catch (Exception e)
  7736   7797                   {
  7737   7798                       try
  7738   7799                       {
  7739   7800                           if (LogExceptions)
  7740   7801                           {

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

  1639   1639       internal static extern void sqlite3_value_int64_interop(IntPtr p, out Int64 value);
  1640   1640   
  1641   1641       [DllImport(SQLITE_DLL)]
  1642   1642       internal static extern void sqlite3_result_double_interop(IntPtr context, ref double value);
  1643   1643   
  1644   1644       [DllImport(SQLITE_DLL)]
  1645   1645       internal static extern void sqlite3_result_int64_interop(IntPtr context, ref Int64 value);
         1646  +
         1647  +    [DllImport(SQLITE_DLL)]
         1648  +    internal static extern IntPtr sqlite3_create_disposable_module_interop(
         1649  +        IntPtr db, IntPtr name, IntPtr pModule, int iVersion, xCreate xCreate,
         1650  +        xConnect xConnect, xBestIndex xBestIndex, xDisconnect xDisconnect,
         1651  +        xDestroy xDestroy, xOpen xOpen, xClose xClose, xFilter xFilter,
         1652  +        xNext xNext, xEof xEof, xColumn xColumn, xRowId xRowId, xUpdate xUpdate,
         1653  +        xBegin xBegin, xSync xSync, xCommit xCommit, xRollback xRollback,
         1654  +        xFindFunction xFindFunction, xRename xRename, xSavepoint xSavepoint,
         1655  +        xRelease xRelease, xRollbackTo xRollbackTo, IntPtr pClientData,
         1656  +        xDestroyModule xDestroyModule);
         1657  +
         1658  +    [DllImport(SQLITE_DLL)]
         1659  +    internal static extern void sqlite3_dispose_module_interop(IntPtr pModule);
  1646   1660   #endif
  1647   1661       // PLATFORM_COMPACTFRAMEWORK && !SQLITE_STANDARD
  1648   1662       #endregion
  1649   1663   
  1650   1664       ///////////////////////////////////////////////////////////////////////////
  1651   1665   
  1652   1666       #region Native Delegates

Changes to testce/TestCases.cs.

   215    215         try { UserCollation(cnn); frm.WriteLine("SUCCESS - UserCollation"); passed++; }
   216    216         catch (Exception) { frm.WriteLine("FAIL - UserCollation"); failed++; }
   217    217   
   218    218         total++;
   219    219         try { Int64Properties(cnn); frm.WriteLine("SUCCESS - Int64Properties"); passed++; }
   220    220         catch (Exception) { frm.WriteLine("FAIL - Int64Properties"); failed++; }
   221    221   
          222  +      total++;
          223  +      try { ManagedVirtualTable(cnn); frm.WriteLine("SUCCESS - ManagedVirtualTable"); passed++; }
          224  +      catch (Exception) { frm.WriteLine("FAIL - ManagedVirtualTable"); failed++; }
          225  +
   222    226         total++;
   223    227         try { MultipleThreadStress(cnn); frm.WriteLine("SUCCESS - MultipleThreadStress"); passed++; }
   224    228         catch (Exception) { frm.WriteLine("FAIL - MultipleThreadStress"); failed++; }
   225    229   
   226    230         total++;
   227    231         try { DropTable(cnn); frm.WriteLine("SUCCESS - DropTable"); passed++; }
   228    232         catch (Exception) { frm.WriteLine("FAIL - DropTable"); failed++; }
................................................................................
   941    945               foreach (long value in new long[] {
   942    946                       cnn2.LastInsertRowId, cnn2.MemoryUsed,
   943    947                       cnn2.MemoryHighwater
   944    948                   })
   945    949               {
   946    950                   // do nothing.
   947    951               }
          952  +
          953  +            return;
          954  +        }
          955  +
          956  +        throw new NotSupportedException("not a SQLite connection");
          957  +    }
          958  +
          959  +    // Make sure that managed virtual table support works on the .NET Compact Framework.
          960  +    internal void ManagedVirtualTable(DbConnection cnn)
          961  +    {
          962  +        SQLiteConnection cnn2 = cnn as SQLiteConnection;
          963  +
          964  +        if (cnn2 != null)
          965  +        {
          966  +            string[] result = new string[5];
          967  +
          968  +            cnn2.CreateModule(new SQLiteModuleEnumerable("enumMod", new string[] {
          969  +                "one", "two", "three", "4", "5.0"
          970  +            }));
          971  +
          972  +            using (SQLiteCommand command = cnn2.CreateCommand())
          973  +            {
          974  +                command.CommandText = "CREATE VIRTUAL TABLE enumTab USING enumMod;";
          975  +                command.ExecuteNonQuery();
          976  +            }
          977  +
          978  +            using (SQLiteCommand command = cnn2.CreateCommand())
          979  +            {
          980  +                command.CommandText = "SELECT * FROM enumTab;";
          981  +
          982  +                using (SQLiteDataReader dataReader = command.ExecuteReader())
          983  +                {
          984  +                    int index = 0;
          985  +
          986  +                    while (dataReader.Read())
          987  +                        result[index++] = dataReader[0].ToString();
          988  +
          989  +                    if (result[0] != "one") throw new ArgumentException("one");
          990  +                    if (result[1] != "two") throw new ArgumentException("two");
          991  +                    if (result[2] != "three") throw new ArgumentException("three");
          992  +                    if (result[3] != "4") throw new ArgumentException("4");
          993  +                    if (result[4] != "5.0") throw new ArgumentException("5.0");
          994  +                }
          995  +            }
          996  +
          997  +            using (SQLiteCommand command = cnn2.CreateCommand())
          998  +            {
          999  +                command.CommandText = "UPDATE enumTab SET x = 1;";
         1000  +
         1001  +                try
         1002  +                {
         1003  +                    command.ExecuteNonQuery();
         1004  +
         1005  +                    throw new InvalidOperationException(
         1006  +                        "UPDATE should throw exception");
         1007  +                }
         1008  +                catch (SQLiteException)
         1009  +                {
         1010  +                    // do nothing.
         1011  +                }
         1012  +            }
   948   1013   
   949   1014               return;
   950   1015           }
   951   1016   
   952   1017           throw new NotSupportedException("not a SQLite connection");
   953   1018       }
   954   1019