Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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. Cherrypick of [cbeb9a1aed8c]. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | branch-3.8.6 |
Files: | files | file ages | folders |
SHA1: |
b3bb660af9472e2c511d1fe87b519325 |
User & Date: | dan 2015-05-21 17:24:32.265 |
Context
2017-07-21
| ||
03:23 | Add new interfaces sqlite3_result_pointer(), and sqlite3_value_pointer() and use them to transfer the eponymous FTS3 column pointer to the snippet() and offsets() routines. This is a cherry-pick of [f0f492245e95], which is in turn inspired by check-in [72de49f2]. (Leaf check-in: a66a5b397b user: drh tags: branch-3.8.6) | |
2015-05-21
| ||
17:24 | 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. Cherrypick of [cbeb9a1aed8c]. (check-in: b3bb660af9 user: dan tags: branch-3.8.6) | |
17:21 | Avoid ever writing before the start of an allocated buffer in the DIRECT_OVERFLOW_READ code. Fix for [e3a290961a6]. Cherrypick of [c3c15d20c691]. (check-in: 31b13eb528 user: dan tags: branch-3.8.6) | |
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) | |
Changes
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5494 5495 5496 5497 5498 5499 5500 | ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. ^After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ | | | 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 | ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. ^After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ int nRef; /* Number of open cursors */ char *zErrMsg; /* Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Virtual Table Cursor Object ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ void (*xTrace)(void*,const char*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ void *pCommitArg; /* Argument to xCommitCallback() */ | > | 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 | u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ void (*xTrace)(void*,const char*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ void *pCommitArg; /* Argument to xCommitCallback() */ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4942 4943 4944 4945 4946 4947 4948 | ** the last one in the database) then a zero is stored in register P2. ** If AUTOVACUUM is disabled then a zero is stored in register P2. ** ** See also: Clear */ case OP_Destroy: { /* out2-prerelease */ int iMoved; | < < < < < < < < < < < < < < | < | 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 | ** the last one in the database) then a zero is stored in register P2. ** If AUTOVACUUM is disabled then a zero is stored in register P2. ** ** See also: Clear */ case OP_Destroy: { /* out2-prerelease */ int iMoved; int iDb; assert( p->readOnly==0 ); pOut->flags = MEM_Null; if( db->nVdbeRead > db->nVDestroy+1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; }else{ iDb = pOp->p3; assert( DbMaskTest(p->btreeMask, iDb) ); iMoved = 0; /* Not needed. Only to silence a warning. */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); pOut->flags = MEM_Int; pOut->u.i = iMoved; #ifndef SQLITE_OMIT_AUTOVACUUM if( rc==SQLITE_OK && iMoved!=0 ){ |
︙ | ︙ | |||
6003 6004 6005 6006 6007 6008 6009 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VDestroy P1 * * P4 * ** ** P4 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ case OP_VDestroy: { | | | | | > > > | > | 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VDestroy P1 * * P4 * ** ** P4 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ case OP_VOpen: { VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; const sqlite3_module *pModule; assert( p->bIsReader ); pCur = 0; pVtabCursor = 0; pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; break; } pModule = pVtab->pModule; rc = pModule->xOpen(pVtab, &pVtabCursor); sqlite3VtabImportErrmsg(p, pVtab); if( SQLITE_OK==rc ){ /* Initialize sqlite3_vtab_cursor base class */ pVtabCursor->pVtab = pVtab; /* Initialize vdbe cursor object */ pCur = allocateCursor(p, pOp->p1, 0, -1, 0); if( pCur ){ pCur->pVtabCursor = pVtabCursor; pVtab->nRef++; }else{ db->mallocFailed = 1; pModule->xClose(pVtabCursor); } } break; } |
︙ | ︙ | |||
6104 6105 6106 6107 6108 6109 6110 | { res = 0; apArg = p->apArg; for(i = 0; i<nArg; i++){ apArg[i] = &pArgc[i+1]; } | < < | 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 | { res = 0; apArg = p->apArg; for(i = 0; i<nArg; i++){ apArg[i] = &pArgc[i+1]; } rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; |
︙ | ︙ | |||
6209 6210 6211 6212 6213 6214 6215 | /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ | < < | 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 | /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ rc = pModule->xNext(pCur->pVtabCursor); sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ |
︙ | ︙ | |||
6286 6287 6288 6289 6290 6291 6292 | ** is set to the value of the rowid for the row just inserted. ** ** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to ** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; | | > > > > | | 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 | ** is set to the value of the rowid for the row just inserted. ** ** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to ** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; Mem **apArg; Mem *pX; assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; break; } pModule = pVtab->pModule; nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); if( ALWAYS(pModule->xUpdate) ){ u8 vtabOnConflict = db->vtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; for(i=0; i<nArg; i++){ |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
296 297 298 299 300 301 302 | /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. | < < < < < < < < | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ Op *aOp; /* Space to hold the virtual machine's program */ Mem *aMem; /* The memory locations */ Mem **apArg; /* Arguments to currently executing user function */ Mem *aColName; /* Column names to return */ |
︙ | ︙ | |||
331 332 333 334 335 336 337 | u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ bft explain:2; /* True if EXPLAIN present on SQL command */ | < | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft changeCntOn:1; /* True to update the change-counter */ bft expired:1; /* True if the VM needs to be recompiled */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ bft isPrepareV2:1; /* True if prepared with prepare_v2() */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 | zP4 = "(blob)"; } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; | | | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | zP4 = "(blob)"; } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab); break; } #endif case P4_INTARRAY: { sqlite3_snprintf(nTemp, zTemp, "intarray"); break; } |
︙ | ︙ | |||
1745 1746 1747 1748 1749 1750 1751 | }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; | > | < | 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 | }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; assert( pVtabCursor->pVtab->nRef>0 ); pVtabCursor->pVtab->nRef--; pModule->xClose(pVtabCursor); } #endif } /* ** Copy the values stored in the VdbeFrame structure to its Vdbe. This ** is used, for example, when a trigger sub-program is halted to restore |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
774 775 776 777 778 779 780 | */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ | | > > > > | < < | > > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ VTable *p; for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); rc = p->pMod->pModule->xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->pVTable==p && p->pNext==0 ); p->pVtab = 0; pTab->pVTable = 0; sqlite3VtabUnlock(p); } |
︙ | ︙ |
Changes to test/vtab1.test.
︙ | ︙ | |||
1391 1392 1393 1394 1395 1396 1397 1398 | SELECT * FROM t9v WHERE a<b; } {1 2 3} do_execsql_test 21.3 { SELECT * FROM t9v WHERE a=b; } {2 2 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 | SELECT * FROM t9v WHERE a<b; } {1 2 3} do_execsql_test 21.3 { SELECT * FROM t9v WHERE a=b; } {2 2 2} #------------------------------------------------------------------------- # The following tests verify that a DROP TABLE command on a virtual # table does not cause other operations to crash. # # 23.1: Dropping a vtab while a SELECT is running on it. # # 23.2: Dropping a vtab while a SELECT that will, but has not yet, # open a cursor on the vtab, is running. In this case the # DROP TABLE succeeds and the SELECT hits an error. # # 23.3: Dropping a vtab from within a user-defined-function callback # in the middle of an "INSERT INTO vtab SELECT ..." statement. # reset_db load_static_extension db wholenumber #load_static_extension db eval db func execsql execsql register_echo_module db do_test 23.1 { execsql { CREATE VIRTUAL TABLE t1 USING wholenumber } set res "" db eval { SELECT value FROM t1 WHERE value<10 } { if {$value == 5} { set res [catchsql { DROP TABLE t1 }] } } set res } {1 {database table is locked}} do_test 23.2 { execsql { CREATE TABLE t2(value); INSERT INTO t2 VALUES(1), (2), (3); } set res2 [list [catch { db eval { SELECT value FROM t2 UNION ALL SELECT value FROM t1 WHERE value<10 } { if {$value == 2} { set res1 [catchsql { DROP TABLE t1 }] } } } msg] $msg] list $res1 $res2 } {{0 {}} {1 {database table is locked}}} do_test 23.3.1 { execsql { CREATE VIRTUAL TABLE t1e USING echo(t2) } execsql { INSERT INTO t1e SELECT 4 } catchsql { INSERT INTO t1e SELECT execsql('DROP TABLE t1e') } } {1 {database table is locked}} do_execsql_test 23.3.2 { SELECT * FROM t1e } {1 2 3 4} finish_test |