aboutsummaryrefslogtreecommitdiff
path: root/src/btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/btree.c')
-rw-r--r--src/btree.c76
1 files changed, 60 insertions, 16 deletions
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: