1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Fix for the sqlite3AbortOtherActiveVdbes() problem. (CVS 4328)

FossilOrigin-Name: e40d40a5d41c491bef852a92e5846b273b206909
This commit is contained in:
drh
2007-08-30 01:19:59 +00:00
parent 107b25f1bd
commit fb98264aab
12 changed files with 147 additions and 64 deletions

View File

@@ -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

View File

@@ -1 +1 @@
35cb63ecfd9d8ca7304aae1b150ee5d1c3498bde
e40d40a5d41c491bef852a92e5846b273b206909

View 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++){

View 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,9 +6829,13 @@ 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 ){
if( pCsr->eState>=CURSOR_REQUIRESEEK ){
if( pCsr->eState==CURSOR_FAULT ){
return pCsr->skip;
}else{
return SQLITE_ABORT;
}
}
/* Check some preconditions:
** (a) the cursor is open for writing,

View 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 */

View 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

View 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);

View 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;

View 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;

View 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*);

View 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;
}

View 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);