/ Check-in [3ca8856a]
Login

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

Overview
Comment:Fix virtual table support for SQLITE_OPEN_REUSABLE_SCHEMA connections.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256: 3ca8856a7b1c36885cea007b8fb05b59f1fdc9d4b54436819193f498519a23c7
User & Date: dan 2019-02-09 17:47:14
Wiki:reuse-schema
Context
2019-02-11
19:34
Add eponymous virtual table "schemapool". For inspecting the current contents of the schema-pool. check-in: 2ebeb747 user: dan tags: reuse-schema
2019-02-09
17:47
Fix virtual table support for SQLITE_OPEN_REUSABLE_SCHEMA connections. check-in: 3ca8856a user: dan tags: reuse-schema
2019-02-08
19:30
Add test cases and fix problems on this branch. check-in: 2b2e9f81 user: dan tags: reuse-schema
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/callback.c.

   627    627     if( IsReuseSchema(db) && iDb!=1 ){
   628    628       Db *pDb = &db->aDb[iDb];
   629    629       SchemaPool *pSPool = pDb->pSPool;
   630    630       assert_schema_state_ok(db);
   631    631       assert( pDb->pSchema );
   632    632   
   633    633       if( pSPool==0 ){
          634  +      assert( pDb->pVTable==0 );
   634    635         if( bNew==0 ){
   635    636           schemaDelete(pDb->pSchema);
   636    637           pDb->pSchema = 0;
   637    638         }
   638    639       }else{
          640  +      VTable *p;
          641  +      VTable *pNext;
          642  +      for(p=pDb->pVTable; p; p=pNext){
          643  +        pNext = p->pNext;
          644  +        sqlite3VtabUnlock(p);
          645  +      }
          646  +      pDb->pVTable = 0;
   639    647         sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   640    648         if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){
   641    649           schemaRelease(pDb);
   642    650         }
   643    651         if( bNew ){
   644    652           Schema *pNew = sqlite3SchemaGet(db, 0);
   645    653           if( pNew==0 ){
................................................................................
   706    714   }
   707    715   
   708    716   /*
   709    717   ** Find and return the schema associated with a BTree.  Create
   710    718   ** a new one if necessary.
   711    719   */
   712    720   Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
   713         -  Schema * p;
          721  +  Schema *p;
   714    722     if( pBt && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA)==0 ){
   715    723       p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
   716    724     }else{
   717    725       p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
   718    726     }
   719    727     if( !p ){
   720    728       sqlite3OomFault(db);

Changes to src/main.c.

  1049   1049     for(i=0; i<db->nDb; i++){
  1050   1050       Schema *pSchema = db->aDb[i].pSchema;
  1051   1051       if( pSchema ){
  1052   1052         for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
  1053   1053           Table *pTab = (Table *)sqliteHashData(p);
  1054   1054           if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
  1055   1055         }
         1056  +    }
         1057  +    if( i!=1 && IsReuseSchema(db) ){
         1058  +      VTable *pVTable;
         1059  +      VTable *pNext;
         1060  +      for(pVTable=db->aDb[i].pVTable; pVTable; pVTable=pNext){
         1061  +        pNext = pVTable->pNext;
         1062  +        sqlite3VtabUnlock(pVTable);
         1063  +      }
         1064  +      db->aDb[i].pVTable = 0;
  1056   1065       }
  1057   1066     }
  1058   1067     for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){
  1059   1068       Module *pMod = (Module *)sqliteHashData(p);
  1060   1069       if( pMod->pEpoTab ){
  1061   1070         sqlite3VtabDisconnect(db, pMod->pEpoTab);
  1062   1071       }

Changes to src/sqliteInt.h.

  1200   1200   struct Db {
  1201   1201     char *zDbSName;      /* Name of this database. (schema name, not filename) */
  1202   1202     Btree *pBt;          /* The B*Tree structure for this database file */
  1203   1203     u8 safety_level;     /* How aggressive at syncing data to disk */
  1204   1204     u8 bSyncSet;         /* True if "PRAGMA synchronous=N" has been run */
  1205   1205     Schema *pSchema;     /* Pointer to database schema (possibly shared) */
  1206   1206     SchemaPool *pSPool;  /* For REUSE_SCHEMA mode */
         1207  +  VTable *pVTable;     /* List of all VTable objects (REUSE_SCHEMA mode only) */
  1207   1208   };
  1208   1209   
  1209   1210   /*
  1210   1211   ** An instance of the following structure stores a database schema.
  1211   1212   **
  1212   1213   ** Most Schema objects are associated with a Btree.  The exception is
  1213   1214   ** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
................................................................................
  1952   1953     sqlite3 *db;              /* Database connection associated with this table */
  1953   1954     Module *pMod;             /* Pointer to module implementation */
  1954   1955     sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
  1955   1956     int nRef;                 /* Number of pointers to this structure */
  1956   1957     u8 bConstraint;           /* True if constraints are supported */
  1957   1958     int iSavepoint;           /* Depth of the SAVEPOINT stack */
  1958   1959     VTable *pNext;            /* Next in linked list (see above) */
         1960  +  char *zName;              /* Table name (REUSE_SCHEMA mode) */
  1959   1961   };
  1960   1962   
  1961   1963   /*
  1962   1964   ** The schema for each SQL table and view is represented in memory
  1963   1965   ** by an instance of the following structure.
  1964   1966   */
  1965   1967   struct Table {

Changes to src/vtab.c.

   140    140   ** pTab is a pointer to a Table structure representing a virtual-table.
   141    141   ** Return a pointer to the VTable object used by connection db to access 
   142    142   ** this virtual-table, if one has been created, or NULL otherwise.
   143    143   */
   144    144   VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
   145    145     VTable *pVtab;
   146    146     assert( IsVirtual(pTab) );
          147  +  if( IsReuseSchema(db) ){
          148  +    int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
          149  +    if( iDb!=1 ){
          150  +      for(pVtab=db->aDb[iDb].pVTable; pVtab; pVtab=pVtab->pNext){
          151  +        if( sqlite3StrICmp(pTab->zName, pVtab->zName)==0 ) break;
          152  +      }
          153  +      return pVtab;
          154  +    }
          155  +  }
   147    156     for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
   148    157     return pVtab;
   149    158   }
   150    159   
   151    160   /*
   152    161   ** Decrement the ref-count on a virtual table object. When the ref-count
   153    162   ** reaches zero, call the xDisconnect() method to delete the object.
................................................................................
   504    513     int rc;
   505    514     const char *const*azArg = (const char *const*)pTab->azModuleArg;
   506    515     int nArg = pTab->nModuleArg;
   507    516     char *zErr = 0;
   508    517     char *zModuleName;
   509    518     int iDb;
   510    519     VtabCtx *pCtx;
          520  +  int nByte;                      /* Bytes of space to allocate */
   511    521   
   512    522     /* Check that the virtual-table is not already being initialized */
   513    523     for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
   514    524       if( pCtx->pTab==pTab ){
   515    525         *pzErr = sqlite3MPrintf(db, 
   516    526             "vtable constructor called recursively: %s", pTab->zName
   517    527         );
................................................................................
   520    530     }
   521    531   
   522    532     zModuleName = sqlite3DbStrDup(db, pTab->zName);
   523    533     if( !zModuleName ){
   524    534       return SQLITE_NOMEM_BKPT;
   525    535     }
   526    536   
   527         -  pVTable = sqlite3MallocZero(sizeof(VTable));
          537  +  nByte = sizeof(VTable) + sqlite3Strlen30(pTab->zName) + 1;
          538  +  pVTable = (VTable*)sqlite3MallocZero(nByte);
   528    539     if( !pVTable ){
   529    540       sqlite3OomFault(db);
   530    541       sqlite3DbFree(db, zModuleName);
   531    542       return SQLITE_NOMEM_BKPT;
   532    543     }
   533    544     pVTable->db = db;
   534    545     pVTable->pMod = pMod;
          546  +  pVTable->zName = (char*)&pVTable[1];
          547  +  memcpy(pVTable->zName, pTab->zName, nByte-sizeof(VTable));
   535    548   
   536    549     iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
   537    550     pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
   538    551   
   539    552     /* Invoke the virtual table constructor */
   540    553     assert( &db->pVtabCtx );
   541    554     assert( xConstruct );
................................................................................
   568    581         *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
   569    582         sqlite3VtabUnlock(pVTable);
   570    583         rc = SQLITE_ERROR;
   571    584       }else{
   572    585         int iCol;
   573    586         u8 oooHidden = 0;
   574    587         /* If everything went according to plan, link the new VTable structure
   575         -      ** into the linked list headed by pTab->pVTable. Then loop through the 
   576         -      ** columns of the table to see if any of them contain the token "hidden".
   577         -      ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
   578         -      ** the type string.  */
   579         -      pVTable->pNext = pTab->pVTable;
   580         -      pTab->pVTable = pVTable;
          588  +      ** into the linked list headed by pTab->pVTable. Or, if this is a
          589  +      ** reusable schema, into the linked list headed by Db.pVTable.
          590  +      **
          591  +      ** Then loop through the columns of the table to see if any of them
          592  +      ** contain the token "hidden". If so, set the Column COLFLAG_HIDDEN flag
          593  +      ** and remove the token from the type string.  */
          594  +      if( IsReuseSchema(db) && iDb!=1 ){
          595  +        pVTable->pNext = db->aDb[iDb].pVTable;
          596  +        db->aDb[iDb].pVTable = pVTable;
          597  +      }else{
          598  +        pVTable->pNext = pTab->pVTable;
          599  +        pTab->pVTable = pVTable;
          600  +      }
   581    601   
   582    602         for(iCol=0; iCol<pTab->nCol; iCol++){
   583    603           char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
   584    604           int nType;
   585    605           int i = 0;
   586    606           nType = sqlite3Strlen30(zType);
   587    607           for(i=0; i<nType; i++){

Changes to test/reuse2.test.

    12     12   #
    13     13   
    14     14   
    15     15   set testdir [file dirname $argv0]
    16     16   source $testdir/tester.tcl
    17     17   set testprefix reuse2
    18     18   
    19         -
    20     19   do_execsql_test 1.0 {
    21     20     CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
    22     21     CREATE INDEX i1 ON t1(z);
    23     22     PRAGMA schema_version;
    24     23   } {2}
    25     24   
    26     25   do_test 1.2 {
................................................................................
    37     36   do_execsql_test -db db2 1.3.2 {
    38     37     INSERT INTO t1 VALUES(4, 5, 6);
    39     38   }
    40     39   
    41     40   do_execsql_test 1.3.3 {
    42     41     SELECT * FROM t1;
    43     42   } {1 2 3 4 5 6}
           43  +
           44  +#--------------------------------------------------------------------------
           45  +reset_db
           46  +ifcapable fts5 {
           47  +  do_execsql_test 2.0 {
           48  +    CREATE VIRTUAL TABLE ft USING fts5(c);
           49  +    INSERT INTO ft VALUES('one two three');
           50  +  }
           51  +  db close
           52  +  sqlite3 db test.db -reuse-schema 1
           53  +
           54  +  do_execsql_test 2.1 {
           55  +    SELECT * FROM ft
           56  +  } {{one two three}}
           57  +}
    44     58   
    45     59   finish_test