/ Changes On Branch nVDestroy
Login

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

Changes In Branch nVDestroy Excluding Merge-Ins

This is equivalent to a diff from 0ee2d38deb to 5ee625b198

2015-03-24
16:43
Prevent a virtual table from being destroyed while it is in use. Also: replace Vdbe.inVtabMethod with sqlite3.nVDestroy. Simplify the EXPLAIN output for P4.pVtab to only show the sqlite3_vtab pointer. (check-in: cbeb9a1aed user: drh tags: trunk)
14:57
Add tests to check that attempting to DROP a virtual table while it is use does not cause problems. (Closed-Leaf check-in: 5ee625b198 user: dan tags: nVDestroy)
14:05
More defenses against virtual table being deleted out from under a running statement. (check-in: 116c998230 user: drh tags: nVDestroy)
12:51
Replace the Vdbe.inVtabMethod field with the sqlite3.nVDestroy counter. (check-in: 9faefb9627 user: drh tags: nVDestroy)
2015-03-23
21:32
Disable loadable extensions in the command-line shell on VxWorks user-space. (check-in: 0ee2d38deb user: drh tags: trunk)
19:55
Track total memory usage using a 64-bit integer on 64-bit systems. Add the sqlite3_status64() interface. Make the sqlite3_status() and sqlite3_status64() interfaces atomic using mutexes and verify correct mutex operation using assert() statements. (check-in: 6fc4e79a23 user: drh tags: trunk)

Changes to src/sqlite.h.in.

  5623   5623   ** take care that any prior string is freed by a call to [sqlite3_free()]
  5624   5624   ** prior to assigning a new string to zErrMsg.  ^After the error message
  5625   5625   ** is delivered up to the client application, the string will be automatically
  5626   5626   ** freed by sqlite3_free() and the zErrMsg field will be zeroed.
  5627   5627   */
  5628   5628   struct sqlite3_vtab {
  5629   5629     const sqlite3_module *pModule;  /* The module for this virtual table */
  5630         -  int nRef;                       /* NO LONGER USED */
         5630  +  int nRef;                       /* Number of open cursors */
  5631   5631     char *zErrMsg;                  /* Error message from sqlite3_mprintf() */
  5632   5632     /* Virtual table implementations will typically add additional fields */
  5633   5633   };
  5634   5634   
  5635   5635   /*
  5636   5636   ** CAPI3REF: Virtual Table Cursor Object
  5637   5637   ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}

Changes to src/sqliteInt.h.

  1108   1108       u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
  1109   1109       u8 imposterTable;           /* Building an imposter table */
  1110   1110     } init;
  1111   1111     int nVdbeActive;              /* Number of VDBEs currently running */
  1112   1112     int nVdbeRead;                /* Number of active VDBEs that read or write */
  1113   1113     int nVdbeWrite;               /* Number of active VDBEs that read and write */
  1114   1114     int nVdbeExec;                /* Number of nested calls to VdbeExec() */
         1115  +  int nVDestroy;                /* Number of active OP_VDestroy operations */
  1115   1116     int nExtension;               /* Number of loaded extensions */
  1116   1117     void **aExtension;            /* Array of shared library handles */
  1117   1118     void (*xTrace)(void*,const char*);        /* Trace function */
  1118   1119     void *pTraceArg;                          /* Argument to the trace function */
  1119   1120     void (*xProfile)(void*,const char*,u64);  /* Profiling function */
  1120   1121     void *pProfileArg;                        /* Argument to profile function */
  1121   1122     void *pCommitArg;                 /* Argument to xCommitCallback() */   

Changes to src/vdbe.c.

  4942   4942   ** the last one in the database) then a zero is stored in register P2.
  4943   4943   ** If AUTOVACUUM is disabled then a zero is stored in register P2.
  4944   4944   **
  4945   4945   ** See also: Clear
  4946   4946   */
  4947   4947   case OP_Destroy: {     /* out2-prerelease */
  4948   4948     int iMoved;
  4949         -  int iCnt;
  4950         -  Vdbe *pVdbe;
  4951   4949     int iDb;
  4952   4950   
  4953   4951     assert( p->readOnly==0 );
  4954         -#ifndef SQLITE_OMIT_VIRTUALTABLE
  4955         -  iCnt = 0;
  4956         -  for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
  4957         -    if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader 
  4958         -     && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 
  4959         -    ){
  4960         -      iCnt++;
  4961         -    }
  4962         -  }
  4963         -#else
  4964         -  iCnt = db->nVdbeRead;
  4965         -#endif
  4966   4952     pOut->flags = MEM_Null;
  4967         -  if( iCnt>1 ){
         4953  +  if( db->nVdbeRead > db->nVDestroy+1 ){
  4968   4954       rc = SQLITE_LOCKED;
  4969   4955       p->errorAction = OE_Abort;
  4970   4956     }else{
  4971   4957       iDb = pOp->p3;
  4972         -    assert( iCnt==1 );
  4973   4958       assert( DbMaskTest(p->btreeMask, iDb) );
  4974   4959       iMoved = 0;  /* Not needed.  Only to silence a warning. */
  4975   4960       rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
  4976   4961       pOut->flags = MEM_Int;
  4977   4962       pOut->u.i = iMoved;
  4978   4963   #ifndef SQLITE_OMIT_AUTOVACUUM
  4979   4964       if( rc==SQLITE_OK && iMoved!=0 ){
................................................................................
  6056   6041   #ifndef SQLITE_OMIT_VIRTUALTABLE
  6057   6042   /* Opcode: VDestroy P1 * * P4 *
  6058   6043   **
  6059   6044   ** P4 is the name of a virtual table in database P1.  Call the xDestroy method
  6060   6045   ** of that table.
  6061   6046   */
  6062   6047   case OP_VDestroy: {
  6063         -  p->inVtabMethod = 2;
         6048  +  db->nVDestroy++;
  6064   6049     rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
  6065         -  p->inVtabMethod = 0;
         6050  +  db->nVDestroy--;
  6066   6051     break;
  6067   6052   }
  6068   6053   #endif /* SQLITE_OMIT_VIRTUALTABLE */
  6069   6054   
  6070   6055   #ifndef SQLITE_OMIT_VIRTUALTABLE
  6071   6056   /* Opcode: VOpen P1 * * P4 *
  6072   6057   **
................................................................................
  6074   6059   ** P1 is a cursor number.  This opcode opens a cursor to the virtual
  6075   6060   ** table and stores that cursor in P1.
  6076   6061   */
  6077   6062   case OP_VOpen: {
  6078   6063     VdbeCursor *pCur;
  6079   6064     sqlite3_vtab_cursor *pVtabCursor;
  6080   6065     sqlite3_vtab *pVtab;
  6081         -  sqlite3_module *pModule;
         6066  +  const sqlite3_module *pModule;
  6082   6067   
  6083   6068     assert( p->bIsReader );
  6084   6069     pCur = 0;
  6085   6070     pVtabCursor = 0;
  6086   6071     pVtab = pOp->p4.pVtab->pVtab;
  6087         -  pModule = (sqlite3_module *)pVtab->pModule;
  6088         -  assert(pVtab && pModule);
         6072  +  if( pVtab==0 || NEVER(pVtab->pModule==0) ){
         6073  +    rc = SQLITE_LOCKED;
         6074  +    break;
         6075  +  }
         6076  +  pModule = pVtab->pModule;
  6089   6077     rc = pModule->xOpen(pVtab, &pVtabCursor);
  6090   6078     sqlite3VtabImportErrmsg(p, pVtab);
  6091   6079     if( SQLITE_OK==rc ){
  6092   6080       /* Initialize sqlite3_vtab_cursor base class */
  6093   6081       pVtabCursor->pVtab = pVtab;
  6094   6082   
  6095   6083       /* Initialize vdbe cursor object */
  6096   6084       pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
  6097   6085       if( pCur ){
  6098   6086         pCur->pVtabCursor = pVtabCursor;
         6087  +      pVtab->nRef++;
  6099   6088       }else{
  6100   6089         db->mallocFailed = 1;
  6101   6090         pModule->xClose(pVtabCursor);
  6102   6091       }
  6103   6092     }
  6104   6093     break;
  6105   6094   }
................................................................................
  6157   6146     {
  6158   6147       res = 0;
  6159   6148       apArg = p->apArg;
  6160   6149       for(i = 0; i<nArg; i++){
  6161   6150         apArg[i] = &pArgc[i+1];
  6162   6151       }
  6163   6152   
  6164         -    p->inVtabMethod = 1;
  6165   6153       rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
  6166         -    p->inVtabMethod = 0;
  6167   6154       sqlite3VtabImportErrmsg(p, pVtab);
  6168   6155       if( rc==SQLITE_OK ){
  6169   6156         res = pModule->xEof(pVtabCursor);
  6170   6157       }
  6171   6158       VdbeBranchTaken(res!=0,2);
  6172   6159       if( res ){
  6173   6160         pc = pOp->p2 - 1;
................................................................................
  6249   6236   
  6250   6237     /* Invoke the xNext() method of the module. There is no way for the
  6251   6238     ** underlying implementation to return an error if one occurs during
  6252   6239     ** xNext(). Instead, if an error occurs, true is returned (indicating that 
  6253   6240     ** data is available) and the error code returned when xColumn or
  6254   6241     ** some other method is next invoked on the save virtual table cursor.
  6255   6242     */
  6256         -  p->inVtabMethod = 1;
  6257   6243     rc = pModule->xNext(pCur->pVtabCursor);
  6258         -  p->inVtabMethod = 0;
  6259   6244     sqlite3VtabImportErrmsg(p, pVtab);
  6260   6245     if( rc==SQLITE_OK ){
  6261   6246       res = pModule->xEof(pCur->pVtabCursor);
  6262   6247     }
  6263   6248     VdbeBranchTaken(!res,2);
  6264   6249     if( !res ){
  6265   6250       /* If there is data, jump to P2 */
................................................................................
  6326   6311   ** is set to the value of the rowid for the row just inserted.
  6327   6312   **
  6328   6313   ** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
  6329   6314   ** apply in the case of a constraint failure on an insert or update.
  6330   6315   */
  6331   6316   case OP_VUpdate: {
  6332   6317     sqlite3_vtab *pVtab;
  6333         -  sqlite3_module *pModule;
         6318  +  const sqlite3_module *pModule;
  6334   6319     int nArg;
  6335   6320     int i;
  6336   6321     sqlite_int64 rowid;
  6337   6322     Mem **apArg;
  6338   6323     Mem *pX;
  6339   6324   
  6340   6325     assert( pOp->p2==1        || pOp->p5==OE_Fail   || pOp->p5==OE_Rollback 
  6341   6326          || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
  6342   6327     );
  6343   6328     assert( p->readOnly==0 );
  6344   6329     pVtab = pOp->p4.pVtab->pVtab;
  6345         -  pModule = (sqlite3_module *)pVtab->pModule;
         6330  +  if( pVtab==0 || NEVER(pVtab->pModule==0) ){
         6331  +    rc = SQLITE_LOCKED;
         6332  +    break;
         6333  +  }
         6334  +  pModule = pVtab->pModule;
  6346   6335     nArg = pOp->p2;
  6347   6336     assert( pOp->p4type==P4_VTAB );
  6348   6337     if( ALWAYS(pModule->xUpdate) ){
  6349   6338       u8 vtabOnConflict = db->vtabOnConflict;
  6350   6339       apArg = p->apArg;
  6351   6340       pX = &aMem[pOp->p3];
  6352   6341       for(i=0; i<nArg; i++){

Changes to src/vdbeInt.h.

   309    309   
   310    310   /*
   311    311   ** An instance of the virtual machine.  This structure contains the complete
   312    312   ** state of the virtual machine.
   313    313   **
   314    314   ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
   315    315   ** is really a pointer to an instance of this structure.
   316         -**
   317         -** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
   318         -** any virtual table method invocations made by the vdbe program. It is
   319         -** set to 2 for xDestroy method calls and 1 for all other methods. This
   320         -** variable is used for two purposes: to allow xDestroy methods to execute
   321         -** "DROP TABLE" statements and to prevent some nasty side effects of
   322         -** malloc failure when SQLite is invoked recursively by a virtual table 
   323         -** method function.
   324    316   */
   325    317   struct Vdbe {
   326    318     sqlite3 *db;            /* The database connection that owns this statement */
   327    319     Op *aOp;                /* Space to hold the virtual machine's program */
   328    320     Mem *aMem;              /* The memory locations */
   329    321     Mem **apArg;            /* Arguments to currently executing user function */
   330    322     Mem *aColName;          /* Column names to return */
................................................................................
   347    339   #ifdef SQLITE_DEBUG
   348    340     int rcApp;              /* errcode set by sqlite3_result_error_code() */
   349    341   #endif
   350    342     u16 nResColumn;         /* Number of columns in one row of the result set */
   351    343     u8 errorAction;         /* Recovery action to do in case of an error */
   352    344     u8 minWriteFileFormat;  /* Minimum file format for writable database files */
   353    345     bft explain:2;          /* True if EXPLAIN present on SQL command */
   354         -  bft inVtabMethod:2;     /* See comments above */
   355    346     bft changeCntOn:1;      /* True to update the change-counter */
   356    347     bft expired:1;          /* True if the VM needs to be recompiled */
   357    348     bft runOnlyOnce:1;      /* Automatically expire on reset */
   358    349     bft usesStmtJournal:1;  /* True if uses a statement journal */
   359    350     bft readOnly:1;         /* True for statements that do not write */
   360    351     bft bIsReader:1;        /* True for statements that read */
   361    352     bft isPrepareV2:1;      /* True if prepared with prepare_v2() */

Changes to src/vdbeaux.c.

  1114   1114           zP4 = "(blob)";
  1115   1115         }
  1116   1116         break;
  1117   1117       }
  1118   1118   #ifndef SQLITE_OMIT_VIRTUALTABLE
  1119   1119       case P4_VTAB: {
  1120   1120         sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
  1121         -      sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
         1121  +      sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p",
         1122  +                       pVtab, pVtab ? pVtab->pModule : (sqlite3_module*)0);
  1122   1123         break;
  1123   1124       }
  1124   1125   #endif
  1125   1126       case P4_INTARRAY: {
  1126   1127         sqlite3_snprintf(nTemp, zTemp, "intarray");
  1127   1128         break;
  1128   1129       }
................................................................................
  1778   1779     }else if( pCx->pCursor ){
  1779   1780       sqlite3BtreeCloseCursor(pCx->pCursor);
  1780   1781     }
  1781   1782   #ifndef SQLITE_OMIT_VIRTUALTABLE
  1782   1783     else if( pCx->pVtabCursor ){
  1783   1784       sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
  1784   1785       const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
  1785         -    p->inVtabMethod = 1;
         1786  +    assert( pVtabCursor->pVtab->nRef>0 );
         1787  +    pVtabCursor->pVtab->nRef--;
  1786   1788       pModule->xClose(pVtabCursor);
  1787         -    p->inVtabMethod = 0;
  1788   1789     }
  1789   1790   #endif
  1790   1791   }
  1791   1792   
  1792   1793   /*
  1793   1794   ** Copy the values stored in the VdbeFrame structure to its Vdbe. This
  1794   1795   ** is used, for example, when a trigger sub-program is halted to restore

Changes to src/vtab.c.

   776    776   */
   777    777   int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
   778    778     int rc = SQLITE_OK;
   779    779     Table *pTab;
   780    780   
   781    781     pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
   782    782     if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
   783         -    VTable *p = vtabDisconnectAll(db, pTab);
   784         -
   785         -    assert( rc==SQLITE_OK );
          783  +    VTable *p;
          784  +    for(p=pTab->pVTable; p; p=p->pNext){
          785  +      assert( p->pVtab );
          786  +      if( p->pVtab->nRef>0 ){
          787  +        return SQLITE_LOCKED;
          788  +      }
          789  +    }
          790  +    p = vtabDisconnectAll(db, pTab);
   786    791       rc = p->pMod->pModule->xDestroy(p->pVtab);
   787         -
   788    792       /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
   789    793       if( rc==SQLITE_OK ){
   790    794         assert( pTab->pVTable==p && p->pNext==0 );
   791    795         p->pVtab = 0;
   792    796         pTab->pVTable = 0;
   793    797         sqlite3VtabUnlock(p);
   794    798       }

Changes to test/vtab1.test.

  1433   1433     } {SQLITE_DONE}
  1434   1434     
  1435   1435     do_test 22.4.2 {
  1436   1436       sqlite3_finalize $stmt
  1437   1437     } {SQLITE_OK}
  1438   1438   }
  1439   1439   
         1440  +
         1441  +#-------------------------------------------------------------------------
         1442  +# The following tests verify that a DROP TABLE command on a virtual
         1443  +# table does not cause other operations to crash.
         1444  +#
         1445  +#   23.1: Dropping a vtab while a SELECT is running on it.
         1446  +#
         1447  +#   23.2: Dropping a vtab while a SELECT that will, but has not yet,
         1448  +#         open a cursor on the vtab, is running. In this case the
         1449  +#         DROP TABLE succeeds and the SELECT hits an error.
         1450  +#   
         1451  +#   23.3: Dropping a vtab from within a user-defined-function callback
         1452  +#         in the middle of an "INSERT INTO vtab SELECT ..." statement.
         1453  +#
         1454  +reset_db
         1455  +load_static_extension db wholenumber
         1456  +load_static_extension db eval
         1457  +register_echo_module db
         1458  +
         1459  +do_test 23.1 {
         1460  +  execsql { CREATE VIRTUAL TABLE t1 USING wholenumber }
         1461  +  set res ""
         1462  +  db eval { SELECT value FROM t1 WHERE value<10 } {
         1463  +    if {$value == 5} {
         1464  +      set res [catchsql { DROP TABLE t1 }]
         1465  +    }
         1466  +  }
         1467  +  set res
         1468  +} {1 {database table is locked}}
         1469  +
         1470  +do_test 23.2 {
         1471  +  execsql { 
         1472  +    CREATE TABLE t2(value);
         1473  +    INSERT INTO t2 VALUES(1), (2), (3);
         1474  +  }
         1475  +
         1476  +  set res2 [list [catch {
         1477  +    db eval {
         1478  +      SELECT value FROM t2 UNION ALL 
         1479  +      SELECT value FROM t1 WHERE value<10
         1480  +    } {
         1481  +      if {$value == 2} { set res1 [catchsql { DROP TABLE t1 }] }
         1482  +    }
         1483  +  } msg] $msg]
         1484  +  list $res1 $res2
         1485  +} {{0 {}} {1 {database table is locked}}}
         1486  +
         1487  +do_test 23.3.1 {
         1488  +  execsql { CREATE VIRTUAL TABLE t1e USING echo(t2) }
         1489  +  execsql { INSERT INTO t1e SELECT 4 }
         1490  +  catchsql { INSERT INTO t1e SELECT eval('DROP TABLE t1e') }
         1491  +} {1 {database table is locked}}
         1492  +do_execsql_test 23.3.2 { SELECT * FROM t1e } {1 2 3 4}
         1493  +
  1440   1494   finish_test