Handle errors in saving cursor positions during a rollback by aborting all active statements. (CVS 3027)

FossilOrigin-Name: 5df9f022bfb22976f22b996bda169635354b825c
diff --git a/test/shared_err.test b/test/shared_err.test
index 30fa24d..0fe0220 100644
--- a/test/shared_err.test
+++ b/test/shared_err.test
@@ -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 @@
   }
 } -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 @@
   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