aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btmutex.c4
-rw-r--r--src/btree.c76
-rw-r--r--src/btree.h3
-rw-r--r--src/btreeInt.h10
-rw-r--r--src/build.c7
-rw-r--r--src/pragma.c5
-rw-r--r--src/vdbe.c16
-rw-r--r--src/vdbe.h4
-rw-r--r--src/vdbeaux.c50
-rw-r--r--src/vdbeblob.c4
10 files changed, 131 insertions, 48 deletions
diff --git a/src/btmutex.c b/src/btmutex.c
index 61644a8af..1f6343423 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; i<pArray->nMutex; i++){
diff --git a/src/btree.c b/src/btree.c
index abbef41c6..bda46fbad 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,18 +2397,51 @@ 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
** that was open at the beginning of this operation will result
@@ -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 032ce9f28..26418990d 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 6ce4052fa..09f147423 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 430fe0070..c8f50e07b 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 <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);
diff --git a/src/pragma.c b/src/pragma.c
index 13eee4848..873c76140 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 <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;
diff --git a/src/vdbe.c b/src/vdbe.c
index d0baf886b..f01a7930e 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 <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;
diff --git a/src/vdbe.h b/src/vdbe.h
index 181121385..75f186cb0 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 b0dd09ee9..4af63d2fc 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 && 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;
}
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 161242db5..d56fbd127 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);