Handle errors in saving cursor positions during a rollback by aborting all active statements. (CVS 3027)
FossilOrigin-Name: 5df9f022bfb22976f22b996bda169635354b825c
diff --git a/src/btree.c b/src/btree.c
index 895d075..f0e7493 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.310 2006/01/24 14:21:24 danielk1977 Exp $
+** $Id: btree.c,v 1.311 2006/01/24 16:37:58 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -1693,9 +1693,6 @@
ThreadData *pTsd;
#endif
- /* Drop any table-locks */
- unlockAllTables(p);
-
/* Close all cursors opened via this handle. */
pCur = pBt->pCursor;
while( pCur ){
@@ -1706,7 +1703,10 @@
}
}
- /* Rollback any active transaction and free the handle structure */
+ /* Rollback any active transaction and free the handle structure.
+ ** The call to sqlite3BtreeRollback() drops any table-locks held by
+ ** this handle.
+ */
sqlite3BtreeRollback(p);
sqliteFree(p);
@@ -2538,21 +2538,40 @@
** are no active cursors, it also releases the read lock.
*/
int sqlite3BtreeRollback(Btree *p){
- int rc = SQLITE_OK;
+ int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
rc = saveAllCursors(pBt, 0, 0);
+#ifndef SQLITE_OMIT_SHARED_CACHE
if( rc!=SQLITE_OK ){
- return rc;
+ /* This is a horrible situation. An IO or malloc() error occured whilst
+ ** trying to save cursor positions. If this is an automatic rollback (as
+ ** the result of a constraint, malloc() failure or IO error) then
+ ** the cache may be internally inconsistent (not contain valid trees) so
+ ** 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 ){
+ sqlite3AbortOtherActiveVdbes(db, 0);
+ }
+ }
}
+#endif
btreeIntegrity(p);
unlockAllTables(p);
if( p->inTrans==TRANS_WRITE ){
- assert( TRANS_WRITE==pBt->inTransaction );
+ int rc2;
- rc = sqlite3pager_rollback(pBt->pPager);
+ assert( TRANS_WRITE==pBt->inTransaction );
+ rc2 = sqlite3pager_rollback(pBt->pPager);
+ if( rc2!=SQLITE_OK ){
+ rc = rc2;
+ }
+
/* The rollback may have destroyed the pPage1->aData value. So
** call getPage() on page 1 again to make sure pPage1->aData is
** set correctly. */
diff --git a/src/main.c b/src/main.c
index bbb2c05..7daadf6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.330 2006/01/24 13:09:33 danielk1977 Exp $
+** $Id: main.c,v 1.331 2006/01/24 16:37:58 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -131,9 +131,6 @@
return SQLITE_ERROR;
}
- /* sqlite3_close() may not invoke sqliteMalloc(). */
- sqlite3MallocDisallow();
-
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
@@ -177,7 +174,6 @@
*/
sqliteFree(db->aDb[1].pSchema);
sqliteFree(db);
- sqlite3MallocAllow();
sqlite3ReleaseThreadData();
return SQLITE_OK;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 759eb68..20bf1c5 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.478 2006/01/23 13:28:54 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.479 2006/01/24 16:37:58 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1747,6 +1747,7 @@
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3MallocFailed(void);
void sqlite3FailedMalloc(void);
+void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
#ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3TableLock(Parse *, int, int, u8, const char *);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index cf0c2ad..5758b80 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1101,10 +1101,10 @@
** aborted so that they do not have data rolled out from underneath
** them leading to a segfault.
*/
-static void abortOtherActiveVdbes(Vdbe *pVdbe){
+void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
Vdbe *pOther;
- for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
- if( pOther==pVdbe ) continue;
+ for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
+ if( pOther==pExcept ) continue;
if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
closeAllCursors(pOther);
pOther->aborted = 1;
@@ -1237,7 +1237,7 @@
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
- abortOtherActiveVdbes(p);
+ sqlite3AbortOtherActiveVdbes(db, p);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
@@ -1274,7 +1274,7 @@
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
}else{
- abortOtherActiveVdbes(p);
+ sqlite3AbortOtherActiveVdbes(db, p);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}