-C Fix\sminor\sproblems\son\svarious\stests.\s\sThis\sis\sa\ssnapshot\sprior\sto\spossible\nmajor\schanges\sin\sorder\sto\sfix\sthe\ssqlite3AbortOtherActiveVdbes\sproblem.\s(CVS\s4327)
-D 2007-08-29T19:15:08
+C Fix\sfor\sthe\ssqlite3AbortOtherActiveVdbes()\sproblem.\s(CVS\s4328)
+D 2007-08-30T01:19:59
F Makefile.in bfcc303429a5d9dcd552d807ee016c77427418c3
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/analyze.c 49b4bd45eb286d833793ed6bf72355a5c1974865
F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3
-F src/btmutex.c abc2eda085ff7729c4093db8b4e5357e932f082c
-F src/btree.c 91b362f7366f1c3f3c62458c4367fbf4e1ee7b16
-F src/btree.h a90328ee4d7aa49a1ec4309c94a9fae65f39d969
-F src/btreeInt.h 1fa6510aa8601dc0358a5240d191335236d3cf76
-F src/build.c 830d1a6b2de157fc4d4dd08d4433066ad83f8b72
+F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c
+F src/btree.c f22955f6d04f045d72882c10f70f1a2fb9d21f54
+F src/btree.h 32fad0f06a280e007c31b089a0e1c63e858084ce
+F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c
+F src/build.c f8eeec5c71e8bab41b6cfcac79d56c9103a26a91
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e
F src/pager.c f9830adfd3752c860a4024da5b871df5af4ed8a4
F src/pager.h 1ac4468049348ec72df09d138fc1d7e3a9d0d3a6
F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590
-F src/pragma.c 9b989506a1b7c8aecd6befb8235e2f57a4aba7e5
+F src/pragma.c 65109b3d6a62f9a0d64e739653b76afa1122a00d
F src/prepare.c 1506fd279824b1f4bac97514966d0370101f9a6b
F src/printf.c e8cb99691b8370d0b721e2618db0ad01550e9b98
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
F src/utf.c 4af6259d5906b5a1bf3035cc387c4d7907bdd56e
F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367
F src/vacuum.c 38745037c63246d1b0669038257890cf89fc4578
-F src/vdbe.c 9f2ef520614425016881234965b8146ac771d7dc
-F src/vdbe.h 498e9ddade4baf70f2fc39e585670131dde07caa
+F src/vdbe.c 9d22f69c813e5a2a4c14c33cb89b7fd4edc0f462
+F src/vdbe.h 03a0fa17f6753a24d6cb585d7a362944a2c115aa
F src/vdbeInt.h 630145b9bfaa19190ab491f52658a7db550f2247
F src/vdbeapi.c 9c2d681b75e4b90c28b9dd01a3f2e5905267f884
-F src/vdbeaux.c 77db89679834d55ff026c6311c34d2964bf46431
-F src/vdbeblob.c 4da667be7dff5e197b3b986d6f2095cf97a22917
+F src/vdbeaux.c 0e92ed38fe905131f1a95011d67cea67cd973ff2
+F src/vdbeblob.c 82f51cdf9b0c0af729732fde48c824e498c0a1ca
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 246d434fa60bde6553490eb686adfd86adcd6712
F src/vtab.c ace9b41a088f6ad55d2e39084d92180a2bee3276
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 5201fa4f8310ffc8b6881d96b152581d74e2df6b
-R 562e94af4a79ce02beef7330814d555d
+P 35cb63ecfd9d8ca7304aae1b150ee5d1c3498bde
+R 29b78abcd06801b9626610a433b86a61
U drh
-Z 261f9a43e26799d1b991384722e003d4
+Z 1ee4e75dc5784f54890a8213aed8fba0
-35cb63ecfd9d8ca7304aae1b150ee5d1c3498bde
\ No newline at end of file
+e40d40a5d41c491bef852a92e5846b273b206909
\ No newline at end of file
**
*************************************************************************
**
-** $Id: btmutex.c,v 1.6 2007/08/29 17:43:20 drh Exp $
+** $Id: btmutex.c,v 1.7 2007/08/30 01:19:59 drh Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
int i, j;
BtShared *pBt;
- if( pBtree->sharable==0 ) return;
+ if( pBtree==0 || pBtree->sharable==0 ) return;
#ifndef NDEBUG
{
for(i=0; i<pArray->nMutex; i++){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.419 2007/08/29 19:15:08 drh Exp $
+** $Id: btree.c,v 1.420 2007/08/30 01:19:59 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){
int rc;
assert( cursorHoldsMutex(pCur) );
- assert( pCur->eState==CURSOR_REQUIRESEEK );
+ assert( pCur->eState>=CURSOR_REQUIRESEEK );
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
#ifndef SQLITE_OMIT_INCRBLOB
if( pCur->isIncrblobHandle ){
return SQLITE_ABORT;
}
#define restoreOrClearCursorPosition(p) \
- (p->eState==CURSOR_REQUIRESEEK ? \
+ (p->eState>=CURSOR_REQUIRESEEK ? \
sqlite3BtreeRestoreOrClearCursorPosition(p) : \
SQLITE_OK)
** Return the number of write-cursors open on this handle. This is for use
** in assert() expressions, so it is only compiled if NDEBUG is not
** defined.
+**
+** For the purposes of this routine, a write-cursor is any cursor that
+** is capable of writing to the databse. That means the cursor was
+** originally opened for writing and the cursor has not be disabled
+** by having its state changed to CURSOR_FAULT.
*/
static int countWriteCursors(BtShared *pBt){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->wrFlag ) r++;
+ if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
#endif
+/*
+** This routine sets the state to CURSOR_FAULT and the error
+** code to errCode for every cursor on BtShared that pBtree
+** references.
+**
+** Every cursor is tripped, including cursors that belong
+** to other database connections that happen to be sharing
+** the cache with pBtree.
+**
+** This routine gets called when a rollback occurs.
+** All cursors using the same cache must be tripped
+** to prevent them from trying to use the btree after
+** the rollback. The rollback may have deleted tables
+** or moved root pages, so it is not sufficient to
+** save the state of the cursor. The cursor must be
+** invalidated.
+*/
+void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
+ BtCursor *p;
+ sqlite3BtreeEnter(pBtree);
+ for(p=pBtree->pBt->pCursor; p; p=p->pNext){
+ clearCursorPosition(p);
+ p->eState = CURSOR_FAULT;
+ p->skip = errCode;
+ }
+ sqlite3BtreeLeave(pBtree);
+}
+
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
** we cannot simply return the error to the caller. Instead, abort
** all queries that may be using any of the cursors that failed to save.
*/
- while( pBt->pCursor ){
- sqlite3 *db = pBt->pCursor->pBtree->pSqlite;
- if( db ){
- /**** FIX ME: This can deadlock ****/
- sqlite3_mutex_enter(db->mutex);
- sqlite3AbortOtherActiveVdbes(db, 0);
- sqlite3_mutex_leave(db->mutex);
- }
- }
+ sqlite3BtreeTripAllCursors(p, rc);
}
#endif
btreeIntegrity(p);
BtShared *pBt = p->pBt;
assert( cursorHoldsMutex(pCur) );
- if( pCur->eState==CURSOR_REQUIRESEEK ){
+ assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
+ assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
+ assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
clearCursorPosition(pCur);
}
pRoot = pCur->pPage;
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
/* Save the positions of any other cursors open on this table */
clearCursorPosition(pCur);
return rc;
}
assert( !pBt->readOnly );
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR; /* The cursor is not pointing to anything */
}
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->pSqlite->mutex) );
assert(pCsr->isIncrblobHandle);
- if( pCsr->eState==CURSOR_REQUIRESEEK ){
- return SQLITE_ABORT;
+ if( pCsr->eState>=CURSOR_REQUIRESEEK ){
+ if( pCsr->eState==CURSOR_FAULT ){
+ return pCsr->skip;
+ }else{
+ return SQLITE_ABORT;
+ }
}
/* Check some preconditions:
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
-** @(#) $Id: btree.h,v 1.91 2007/08/29 17:43:20 drh Exp $
+** @(#) $Id: btree.h,v 1.92 2007/08/30 01:19:59 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
int sqlite3BtreeClearTable(Btree*, int);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
+void sqlite3BtreeTripAllCursors(Btree*, int);
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btreeInt.h,v 1.12 2007/08/29 00:33:07 drh Exp $
+** $Id: btreeInt.h,v 1.13 2007/08/30 01:19:59 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreOrClearCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
+**
+** CURSOR_FAULT:
+** A unrecoverable error (an I/O error or a malloc failure) has occurred
+** on a different connection that shares the BtShared cache with this
+** cursor. The error has left the cache in an inconsistent state.
+** Do nothing else with this cursor. Any attempt to use the cursor
+** should return the error code stored in BtCursor.skip
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2
+#define CURSOR_FAULT 3
/*
** The TRACE macro will print high-level status information about the
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.442 2007/08/29 14:06:23 danielk1977 Exp $
+** $Id: build.c,v 1.443 2007/08/30 01:19:59 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue;
- sqlite3VdbeUsesBtree(v, iDb, db->aDb[iDb].pBt);
+ sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
** set them now.
*/
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */
+ sqlite3VdbeUsesBtree(v, iDb);
lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, lbl);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
+ sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
if( type!=TK_DEFERRED ){
for(i=0; i<db->nDb; i++){
sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
+ sqlite3VdbeUsesBtree(v, i);
}
}
sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.146 2007/08/21 10:44:16 drh Exp $
+** $Id: pragma.c,v 1.147 2007/08/30 01:19:59 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
sqlite3VdbeChangeP1(v, iAddr+5, iDb);
+ sqlite3VdbeUsesBtree(v, iDb);
}
}
}
){
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
+ sqlite3VdbeUsesBtree(v, iDb);
switch( zLeft[0] ){
case 's': case 'S':
iCookie = 0;
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.647 2007/08/29 12:31:28 danielk1977 Exp $
+** $Id: vdbe.c,v 1.648 2007/08/30 01:19:59 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
Btree *pBt;
if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){
assert( sqlite3BtreeIsInTrans(pBt) );
+ assert( (p->btreeMask & (1<<i))!=0 );
if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt);
p->openedStatement = 1;
Btree *pBt;
assert( i>=0 && i<db->nDb );
+ assert( (p->btreeMask & (1<<i))!=0 );
pBt = db->aDb[i].pBt;
if( pBt ){
}
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
+ assert( (p->btreeMask & (1<<iDb))!=0 );
/* The indexing of meta values at the schema layer is off by one from
** the indexing in the btree layer. The btree considers meta[0] to
** be the number of free pages in the database (a read-only value)
Db *pDb;
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
assert( pTos>=p->aStack );
int iMeta;
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pBt = db->aDb[pOp->p1].pBt;
if( pBt ){
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
assert( iDb>=0 && iDb<db->nDb );
+ assert( (p->btreeMask & (1<<iDb))!=0 );
pDb = &db->aDb[iDb];
pX = pDb->pBt;
assert( pX!=0 );
rc = SQLITE_LOCKED;
}else{
assert( iCnt==1 );
+ assert( (p->btreeMask & (1<<pOp->p2))!=0 );
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
pTos++;
pTos->flags = MEM_Int;
}
}
#endif
+ assert( (p->btreeMask & (1<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
int flags;
Db *pDb;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
aRoot[j] = 0;
popStack(&pTos, nRoot);
pTos++;
+ assert( pOp->p2>=0 && pOp->p2<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p2))!=0 );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
pnErr->u.i, &nErr);
pnErr->u.i -= nErr;
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(pBt);
if( rc==SQLITE_DONE ){
if( isWriteLock ){
p1 = (-1*p1)-1;
}
+ assert( p1>=0 && p1<db->nDb );
+ assert( (p->btreeMask & (1<<p1))!=0 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( rc==SQLITE_LOCKED ){
const char *z = (const char *)pOp->p3;
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.112 2007/08/28 22:24:35 drh Exp $
+** $Id: vdbe.h,v 1.113 2007/08/30 01:19:59 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
-void sqlite3VdbeUsesBtree(Vdbe*, int, Btree*);
+void sqlite3VdbeUsesBtree(Vdbe*, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
*/
-void sqlite3VdbeUsesBtree(Vdbe *p, int i, Btree *pBtree){
+void sqlite3VdbeUsesBtree(Vdbe *p, int i){
+ int mask;
assert( i>=0 && i<p->db->nDb );
assert( i<sizeof(p->btreeMask)*8 );
- assert( p->db->aDb[i].pBt==pBtree );
- p->btreeMask |= 1<<i;
- sqlite3BtreeMutexArrayInsert(&p->aMutex, pBtree);
+ mask = 1<<i;
+ if( (p->btreeMask & mask)==0 ){
+ p->btreeMask |= mask;
+ sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
+ }
}
#endif
/*
-** Find every active VM other than pVdbe and change its status to
-** aborted. This happens when one VM causes a rollback due to an
-** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
-** aborted so that they do not have data rolled out from underneath
-** them leading to a segfault.
+** For every Btree that in database connection db which
+** has been modified, "trip" or invalidate each cursor in
+** that Btree might have been modified so that the cursor
+** can never be used again. This happens when a rollback
+*** occurs. We have to trip all the other cursors, even
+** cursor from other VMs in different database connections,
+** so that none of them try to use the data at which they
+** were pointing and which now may have been changed due
+** to the rollback.
+**
+** Remember that a rollback can delete tables complete and
+** reorder rootpages. So it is not sufficient just to save
+** the state of the cursor. We have to invalidate the cursor
+** so that it is never used again.
*/
-void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
- Vdbe *pOther;
- for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
- if( pOther==pExcept ) continue;
- if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
- checkActiveVdbeCnt(db);
- closeAllCursorsExceptActiveVtabs(pOther);
- checkActiveVdbeCnt(db);
- pOther->aborted = 1;
+void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *p = db->aDb[i].pBt;
+ if( p && sqlite3BtreeIsInTrans(p) ){
+ sqlite3BtreeTripAllCursors(p, SQLITE_ABORT);
+ }
}
}
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
- sqlite3AbortOtherActiveVdbes(db, p);
+ invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
}else{
- sqlite3AbortOtherActiveVdbes(db, p);
+ invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
**
** This file contains code used to implement incremental BLOB I/O.
**
-** $Id: vdbeblob.c,v 1.15 2007/08/29 17:43:20 drh Exp $
+** $Id: vdbeblob.c,v 1.16 2007/08/30 01:19:59 drh Exp $
*/
#include "sqliteInt.h"
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
/* Make sure a mutex is held on the table to be accessed */
- sqlite3VdbeUsesBtree(v, iDb, db->aDb[iDb].pBt);
+ sqlite3VdbeUsesBtree(v, iDb);
/* Configure the db number pushed onto the stack */
sqlite3VdbeChangeP1(v, 2, iDb);