]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Handle errors in saving cursor positions during a rollback by aborting all active...
authordanielk1977 <danielk1977@noemail.net>
Tue, 24 Jan 2006 16:37:57 +0000 (16:37 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 24 Jan 2006 16:37:57 +0000 (16:37 +0000)
FossilOrigin-Name: 5df9f022bfb22976f22b996bda169635354b825c

manifest
manifest.uuid
src/btree.c
src/main.c
src/sqliteInt.h
src/vdbeaux.c
test/shared_err.test

index bfc95388a884cebbfe2bc6315d063466e293b60d..49d8a52a9aba14685dfb88d42a201d9d9a1fc5a1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Save\sthe\sposition\sof\sany\sopen\scursors\sbefore\sa\srollback.\s(CVS\s3026)
-D 2006-01-24T14:21:24
+C Handle\serrors\sin\ssaving\scursor\spositions\sduring\sa\srollback\sby\saborting\sall\sactive\sstatements.\s(CVS\s3027)
+D 2006-01-24T16:37:58
 F Makefile.in 53841eb72e9eeb6030a8ce28c2595a92f440fd10
 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -34,7 +34,7 @@ F src/alter.c 90b779cf00489535cab6490df6dc050f40e4e874
 F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
 F src/attach.c d73a3505de3fb9e373d0a158978116c4212031d0
 F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2
-F src/btree.c 5b71740985d4845f3a6ac7e0bb809e41d25830d4
+F src/btree.c f45f57e6cbd3b3db947cdd699db64e5215d20b2a
 F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184
 F src/build.c feaa61e769d7887ffeaa060d746638c7b3e994ef
 F src/callback.c 1bf497306c32229114f826707054df7ebe10abf2
@@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
 F src/insert.c 7e931b7f06afbcefcbbaab175c02eff8268db33f
 F src/legacy.c 86b669707b3cefd570e34154e2f6457547d1df4f
-F src/main.c dc3fc9b02b1a022574d6e12d25abe58b93b85b1f
+F src/main.c 2693776249865dc69b97904205638e84a34a059c
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235
 F src/os.h 93035a0e3b9dd05cdd0aaef32ea28ca28e02fe78
@@ -70,7 +70,7 @@ F src/select.c daee9b20702ba51cf3807fc1b130edd8846e3e48
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
 F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3
-F src/sqliteInt.h 35a3c3556abfca796cf44fea83c9f04385efcfb6
+F src/sqliteInt.h 0121298397ac14eb468ab1ba9d488ac7ed7d88a1
 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
 F src/tclsqlite.c 7764ab34df617b3d3cfd5f0fdf3444ed219c11d6
 F src/test1.c ce715e15c8045c598fe83a17f862ddeedf60c057
@@ -91,7 +91,7 @@ F src/vdbe.c 799e6280aef25bae55d2da21b5a6dbdda5e76e36
 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
 F src/vdbeInt.h eb3f86ab08ef11635bc78eb88c3ff13f923c233b
 F src/vdbeapi.c dcb2636f49b4807e34960d52a2fc257b3a751140
-F src/vdbeaux.c 0c27d3b3bd8dda7ed73eb8fcfa74350ca6633895
+F src/vdbeaux.c bc90137791c9442ddd9e81453f10a23688d19dbf
 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
 F src/vdbemem.c 2034e93b32c14bda6e306bb54e3a8e930b963027
 F src/where.c 8409e00fa2cb5fce873b4c911165cfed097e9c49
@@ -228,7 +228,7 @@ F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
 F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
 F test/shared.test 0ed247941236788c255b3b29b5a82d5ca71b6432
 F test/shared2.test 3466dc54ca69a3c50ac259e106fb5cd067b8cd53
-F test/shared_err.test 162ad76d510370e4d3878cb6c376e1292db06005
+F test/shared_err.test 299a9180a6376b2089e8e0d469f383fe91bfa4ff
 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
 F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
 F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
@@ -344,7 +344,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P c30705a00d7d9d61fb9cb47a1019b1a186d690a7
-R 6675c7ec185eda4043b15c5e61211396
+P 32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
+R bfc84cb6ae1c5988a33aa090aaeb35d5
 U danielk1977
-Z 32002e918852056122387d8fed3cdfe2
+Z b319ec5ca674b878a1973ce33be953dd
index 0129a576c6efe43a1d767eb847def732ecff8bf0..9044aca99bff693bf157f71d4e3983ddd45ce50a 100644 (file)
@@ -1 +1 @@
-32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
\ No newline at end of file
+5df9f022bfb22976f22b996bda169635354b825c
\ No newline at end of file
index 895d075648499218b1fdd04af0acea6a58fcab4c..f0e749302f1f8c1bfd496de89d99ccc84c5dd719 100644 (file)
@@ -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 @@ int sqlite3BtreeClose(Btree *p){
   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 @@ int sqlite3BtreeClose(Btree *p){
     }
   }
 
-  /* 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 @@ void sqlite3BtreeCursorList(Btree *p){
 ** 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 ){
+    int rc2;
+
     assert( TRANS_WRITE==pBt->inTransaction );
+    rc2 = sqlite3pager_rollback(pBt->pPager);
+    if( rc2!=SQLITE_OK ){
+      rc = rc2;
+    }
 
-    rc = sqlite3pager_rollback(pBt->pPager);
     /* The rollback may have destroyed the pPage1->aData value.  So
     ** call getPage() on page 1 again to make sure pPage1->aData is
     ** set correctly. */
index bbb2c05f4f162b04f04fbdf0eb0d5c14720b8d69..7daadf6936fd42a9272ac230cff91a6492fe8a7e 100644 (file)
@@ -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 @@ int sqlite3_close(sqlite3 *db){
     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 @@ int sqlite3_close(sqlite3 *db){
   */
   sqliteFree(db->aDb[1].pSchema);
   sqliteFree(db);
-  sqlite3MallocAllow();
   sqlite3ReleaseThreadData();
   return SQLITE_OK;
 }
index 759eb68f1b43fe876dc0c529656cb8b020d43ad1..20bf1c5e8b4031be242e4f610a44343a72db6e71 100644 (file)
@@ -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 sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
 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 *);
index cf0c2ad35b8c662f0c12e712dffb20dd30da687b..5758b8007ab791833fbd4cc3941cb64fabfe66be 100644 (file)
@@ -1101,10 +1101,10 @@ static int vdbeCommit(sqlite3 *db){
 ** 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 @@ 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.
           */
-          abortOtherActiveVdbes(p);
+          sqlite3AbortOtherActiveVdbes(db, p);
           sqlite3RollbackAll(db);
           db->autoCommit = 1;
         }
@@ -1274,7 +1274,7 @@ int sqlite3VdbeHalt(Vdbe *p){
       }else if( p->errorAction==OE_Abort ){
         xFunc = sqlite3BtreeRollbackStmt;
       }else{
-        abortOtherActiveVdbes(p);
+        sqlite3AbortOtherActiveVdbes(db, p);
         sqlite3RollbackAll(db);
         db->autoCommit = 1;
       }
index 30fa24d37a3321fe50660176c4a26bea0a41ca5a..0fe0220eac08226d6798a61fc584a9354a39fa86 100644 (file)
@@ -13,7 +13,7 @@
 # cache context. What happens to connection B if one connection A encounters
 # an IO-error whilst reading or writing the file-system?
 #
-# $Id: shared_err.test,v 1.8 2006/01/24 11:30:27 danielk1977 Exp $
+# $Id: shared_err.test,v 1.9 2006/01/24 16:37:59 danielk1977 Exp $
 
 proc skip {args} {}
 
@@ -311,11 +311,14 @@ do_malloc_test 4 -tclprep {
   }
 } -cleanup {
   do_test shared_malloc-4.$::n.cleanup.1 {
-    sqlite3_step $::STMT
-  } {SQLITE_ROW}
-  do_test shared_malloc-4.$::n.cleanup.2 {
-    sqlite3_column_text $::STMT 0
-  } {2222222222}
+    set ::rc [sqlite3_step $::STMT]
+    expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ABORT"}
+  } {1}
+  if {$::rc=="SQLITE_ROW"} {
+    do_test shared_malloc-4.$::n.cleanup.2 {
+      sqlite3_column_text $::STMT 0
+    } {2222222222}
+  }
   do_test shared_malloc-4.$::n.cleanup.3 {
     sqlite3_finalize $::STMT
   } {SQLITE_OK}
@@ -349,6 +352,61 @@ do_test shared_misuse-7.1 {
   set msg
 } {library routine called out of sequence}
 
+# Again provoke a malloc() failure when a cursor position is being saved, 
+# this time during a ROLLBACK operation by some other handle. 
+#
+# The library should return an SQLITE_NOMEM to the caller. The query that
+# owns the cursor (the one for which the position is not saved) should
+# be aborted.
+# 
+set ::aborted 0
+do_malloc_test 8 -tclprep {
+  sqlite3 db2 test.db
+  execsql {
+    PRAGMA read_uncommitted = 1;
+    BEGIN;
+    CREATE TABLE t1(a, b, UNIQUE(a, b));
+  } db2
+  for {set i 0} {$i < 2} {incr i} {
+    set a [string repeat $i 10]
+    set b [string repeat $i 2000]
+    execsql {INSERT INTO t1 VALUES($a, $b)} db2
+  }
+  execsql {COMMIT} db2
+  set ::DB2 [sqlite3_connection_pointer db2]
+  set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
+  sqlite3_step $::STMT       ;# Cursor points at 0000000000
+  sqlite3_step $::STMT       ;# Cursor points at 1111111111
+} -tclbody {
+  execsql {
+    BEGIN;
+    INSERT INTO t1 VALUES(6, NULL);
+    ROLLBACK;
+  }
+} -cleanup {
+  do_test shared_malloc-8.$::n.cleanup.1 {
+    lrange [execsql {
+      SELECT a FROM t1;
+    } db2] 0 1
+  } {0000000000 1111111111}
+  do_test shared_malloc-8.$::n.cleanup.2 {
+    set rc1 [sqlite3_step $::STMT]
+    set rc2 [sqlite3_finalize $::STMT]
+    if {$rc1=="SQLITE_ABORT"} {
+      incr ::aborted
+    }
+    expr {
+      ($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") || 
+      ($rc1=="SQLITE_ABORT" && $rc2=="SQLITE_OK")
+    }
+  } {1}
+  db2 close
+}
+do_test shared_malloc-8.X {
+  # Test that one or more queries were aborted due to the malloc() failure.
+  expr $::aborted>=1
+} {1}
+
 catch {db close}
 sqlite3_enable_shared_cache $::enable_shared_cache
 finish_test