diff --git a/manifest b/manifest index b0516dd718..788ee742d3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 @@ -80,11 +80,11 @@ F src/alter.c c9f30b4d6fbf7eff7c5518b002a217d4ecd13bcf 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 @@ -123,7 +123,7 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b 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 @@ -162,12 +162,12 @@ F src/update.c e89b980b443d44b68bfc0b1746cdb6308e049ac9 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 @@ -567,7 +567,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 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 diff --git a/manifest.uuid b/manifest.uuid index e0ee1f80d4..0ff5f1b9d4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -35cb63ecfd9d8ca7304aae1b150ee5d1c3498bde \ No newline at end of file +e40d40a5d41c491bef852a92e5846b273b206909 \ No newline at end of file diff --git a/src/btmutex.c b/src/btmutex.c index 61644a8af8..1f63434231 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $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 @@ -239,7 +239,7 @@ int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){ 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; inMutex; i++){ diff --git a/src/btree.c b/src/btree.c index abbef41c63..bda46fbadc 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** 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. @@ -356,7 +356,10 @@ static void clearCursorPosition(BtCursor *pCur){ 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; @@ -373,7 +376,7 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ } #define restoreOrClearCursorPosition(p) \ - (p->eState==CURSOR_REQUIRESEEK ? \ + (p->eState>=CURSOR_REQUIRESEEK ? \ sqlite3BtreeRestoreOrClearCursorPosition(p) : \ SQLITE_OK) @@ -2394,17 +2397,50 @@ int sqlite3BtreeCommit(Btree *p){ ** 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 @@ -2430,15 +2466,7 @@ int sqlite3BtreeRollback(Btree *p){ ** 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); @@ -3343,7 +3371,13 @@ static int moveToRoot(BtCursor *pCur){ 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; @@ -5514,6 +5548,9 @@ int sqlite3BtreeInsert( 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); @@ -5592,6 +5629,9 @@ int sqlite3BtreeDelete(BtCursor *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 */ } @@ -6789,8 +6829,12 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ 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: diff --git a/src/btree.h b/src/btree.h index 032ce9f285..26418990db 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** 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_ @@ -125,6 +125,7 @@ int sqlite3BtreeDropTable(Btree*, int, int*); 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 */ diff --git a/src/btreeInt.h b/src/btreeInt.h index 6ce4052fab..09f1474239 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** 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 @@ -466,10 +466,18 @@ struct BtCursor { ** 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 diff --git a/src/build.c b/src/build.c index 430fe00707..c8f50e07b7 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** 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 @@ -164,7 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); for(iDb=0, mask=1; iDbnDb; 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]); } @@ -847,6 +847,7 @@ void sqlite3StartTable( ** 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 ? @@ -2693,6 +2694,7 @@ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ 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); @@ -3089,6 +3091,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){ if( type!=TK_DEFERRED ){ for(i=0; inDb; i++){ sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + sqlite3VdbeUsesBtree(v, i); } } sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0); diff --git a/src/pragma.c b/src/pragma.c index 13eee48485..873c76140a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** 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 @@ -300,6 +300,7 @@ void sqlite3Pragma( }; 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); @@ -455,6 +456,7 @@ void sqlite3Pragma( sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); sqlite3VdbeChangeP1(v, iAddr+5, iDb); + sqlite3VdbeUsesBtree(v, iDb); } } } @@ -1043,6 +1045,7 @@ void sqlite3Pragma( ){ int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */ + sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ case 's': case 'S': iCookie = 0; diff --git a/src/vdbe.c b/src/vdbe.c index d0baf886b0..f01a7930ea 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** 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 @@ -2421,6 +2421,7 @@ case OP_Statement: { /* no-push */ Btree *pBt; if( i>=0 && inDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){ assert( sqlite3BtreeIsInTrans(pBt) ); + assert( (p->btreeMask & (1<openedStatement = 1; @@ -2511,6 +2512,7 @@ case OP_Transaction: { /* no-push */ Btree *pBt; assert( i>=0 && inDb ); + assert( (p->btreeMask & (1<aDb[i].pBt; if( pBt ){ @@ -2557,6 +2559,7 @@ case OP_ReadCookie: { } assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); + assert( (p->btreeMask & (1<p2p1>=0 && pOp->p1nDb ); + assert( (p->btreeMask & (1<p1))!=0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( pTos>=p->aStack ); @@ -2629,6 +2633,7 @@ case OP_VerifyCookie: { /* no-push */ int iMeta; Btree *pBt; assert( pOp->p1>=0 && pOp->p1nDb ); + assert( (p->btreeMask & (1<p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta); @@ -2720,6 +2725,7 @@ case OP_OpenWrite: { /* no-push */ assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; assert( iDb>=0 && iDbnDb ); + assert( (p->btreeMask & (1<aDb[iDb]; pX = pDb->pBt; assert( pX!=0 ); @@ -4075,6 +4081,7 @@ case OP_Destroy: { rc = SQLITE_LOCKED; }else{ assert( iCnt==1 ); + assert( (p->btreeMask & (1<p2))!=0 ); rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); pTos++; pTos->flags = MEM_Int; @@ -4136,6 +4143,7 @@ case OP_Clear: { /* no-push */ } } #endif + assert( (p->btreeMask & (1<p2))!=0 ); rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); break; } @@ -4166,6 +4174,7 @@ case OP_CreateTable: { int flags; Db *pDb; assert( pOp->p1>=0 && pOp->p1nDb ); + assert( (p->btreeMask & (1<p1))!=0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); if( pOp->opcode==OP_CreateTable ){ @@ -4327,6 +4336,8 @@ case OP_IntegrityCk: { aRoot[j] = 0; popStack(&pTos, nRoot); pTos++; + assert( pOp->p2>=0 && pOp->p2nDb ); + assert( (p->btreeMask & (1<p2))!=0 ); z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot, pnErr->u.i, &nErr); pnErr->u.i -= nErr; @@ -4701,6 +4712,7 @@ case OP_IncrVacuum: { /* no-push */ Btree *pBt; assert( pOp->p1>=0 && pOp->p1nDb ); + assert( (p->btreeMask & (1<p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); if( rc==SQLITE_DONE ){ @@ -4752,6 +4764,8 @@ case OP_TableLock: { /* no-push */ if( isWriteLock ){ p1 = (-1*p1)-1; } + assert( p1>=0 && p1nDb ); + assert( (p->btreeMask & (1<aDb[p1].pBt, pOp->p2, isWriteLock); if( rc==SQLITE_LOCKED ){ const char *z = (const char *)pOp->p3; diff --git a/src/vdbe.h b/src/vdbe.h index 1811213858..75f186cb07 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** 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_ @@ -120,7 +120,7 @@ void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); 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*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index b0dd09ee9d..4af63d2fc6 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -660,12 +660,15 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){ ** 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 && idb->nDb ); assert( ibtreeMask)*8 ); - assert( p->db->aDb[i].pBt==pBtree ); - p->btreeMask |= 1<aMutex, pBtree); + mask = 1<btreeMask & mask)==0 ){ + p->btreeMask |= mask; + sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt); + } } @@ -1301,21 +1304,28 @@ static void checkActiveVdbeCnt(sqlite3 *db){ #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; inDb; i++){ + Btree *p = db->aDb[i].pBt; + if( p && sqlite3BtreeIsInTrans(p) ){ + sqlite3BtreeTripAllCursors(p, SQLITE_ABORT); + } } } @@ -1440,7 +1450,7 @@ int sqlite3VdbeHalt(Vdbe *p){ /* 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; } @@ -1480,7 +1490,7 @@ int sqlite3VdbeHalt(Vdbe *p){ }else if( p->errorAction==OE_Abort ){ xFunc = sqlite3BtreeRollbackStmt; }else{ - sqlite3AbortOtherActiveVdbes(db, p); + invalidateCursorsOnModifiedBtrees(db); sqlite3RollbackAll(db); db->autoCommit = 1; } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 161242db5b..d56fbd127d 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -12,7 +12,7 @@ ** ** 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" @@ -164,7 +164,7 @@ int sqlite3_blob_open( 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);