]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for the sqlite3AbortOtherActiveVdbes() problem. (CVS 4328)
authordrh <drh@noemail.net>
Thu, 30 Aug 2007 01:19:59 +0000 (01:19 +0000)
committerdrh <drh@noemail.net>
Thu, 30 Aug 2007 01:19:59 +0000 (01:19 +0000)
FossilOrigin-Name: e40d40a5d41c491bef852a92e5846b273b206909

12 files changed:
manifest
manifest.uuid
src/btmutex.c
src/btree.c
src/btree.h
src/btreeInt.h
src/build.c
src/pragma.c
src/vdbe.c
src/vdbe.h
src/vdbeaux.c
src/vdbeblob.c

index b0516dd7182220581b7113e9e3c24bb35301757e..788ee742d3b5344c9c855a27920c0998a9aab38f 100644 (file)
--- 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
index e0ee1f80d49c9ee94e2c94804930650fb0fbe55f..0ff5f1b9d46962c986dd423cd7f81d78f96d3684 100644 (file)
@@ -1 +1 @@
-35cb63ecfd9d8ca7304aae1b150ee5d1c3498bde
\ No newline at end of file
+e40d40a5d41c491bef852a92e5846b273b206909
\ No newline at end of file
index 61644a8af85a8496b106e33fa93a213aa3725655..1f6343423125876e8b2a47f73a378122756ee9a4 100644 (file)
@@ -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; i<pArray->nMutex; i++){
index abbef41c63f2180f362d63df1557529f65371e25..bda46fbadcd8eed2fee530b5c04707e91635e7c0 100644 (file)
@@ -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: 
index 032ce9f28525e685b5ccf71470be792a852c49bd..26418990db2835c49fdef94eaf4823e7880298ed 100644 (file)
@@ -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 */
index 6ce4052fab092947beb2c909e6d37088a8c13537..09f14742390dec5e1d2d7e92c276c9d8bd25fa98 100644 (file)
@@ -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
index 430fe0070773a34ebfc935f151a48ed55d68cd47..c8f50e07b7fd1793d9de16107c66212f820d53d6 100644 (file)
@@ -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 <ctype.h>
@@ -164,7 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){
       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]);
       }
@@ -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; i<db->nDb; i++){
       sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
+      sqlite3VdbeUsesBtree(v, i);
     }
   }
   sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
index 13eee4848550985f768ef8ad4d12a5b936d55774..873c76140a7ad1c51527b0f6806233b4eaf76cbd 100644 (file)
@@ -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 <ctype.h>
@@ -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;
index d0baf886b0a4ab35bef576ea5b66b2dcca258597..f01a7930ea3e501050414f4f58d8e917f399d978 100644 (file)
@@ -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 <ctype.h>
@@ -2421,6 +2421,7 @@ case OP_Statement: {       /* no-push */
   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;
@@ -2511,6 +2512,7 @@ case OP_Transaction: {       /* no-push */
   Btree *pBt;
 
   assert( i>=0 && i<db->nDb );
+  assert( (p->btreeMask & (1<<i))!=0 );
   pBt = db->aDb[i].pBt;
 
   if( pBt ){
@@ -2557,6 +2559,7 @@ case OP_ReadCookie: {
   }
   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)
@@ -2585,6 +2588,7 @@ case OP_SetCookie: {       /* no-push */
   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 );
@@ -2629,6 +2633,7 @@ case OP_VerifyCookie: {       /* no-push */
   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);
@@ -2720,6 +2725,7 @@ case OP_OpenWrite: {       /* no-push */
   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 );
@@ -4075,6 +4081,7 @@ case OP_Destroy: {
     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;
@@ -4136,6 +4143,7 @@ case OP_Clear: {        /* no-push */
     }
   }
 #endif
+  assert( (p->btreeMask & (1<<pOp->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->p1<db->nDb );
+  assert( (p->btreeMask & (1<<pOp->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->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;
@@ -4701,6 +4712,7 @@ case OP_IncrVacuum: {        /* no-push */
   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 ){
@@ -4752,6 +4764,8 @@ case OP_TableLock: {        /* no-push */
   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;
index 1811213858ba38d9447eed45f4c0eb8fec28484e..75f186cb07c9a1a8ec1edeeada71e3960024d350 100644 (file)
@@ -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*);
index b0dd09ee9df0bdc032f3c26d004aba807ebfee27..4af63d2fc6f79f47a3e54c25ee41f56da16555cd 100644 (file)
@@ -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 && 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);
+  }
 }
 
 
@@ -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; i<db->nDb; 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;
       }
index 161242db5b5b966759ab41cd527bf4ddf9543d68..d56fbd127dd96ed248ba44bd1fdb712926737930 100644 (file)
@@ -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);