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