]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix more problems with malloc() and IO failures. (CVS 2985)
authordanielk1977 <danielk1977@noemail.net>
Sat, 21 Jan 2006 12:08:54 +0000 (12:08 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sat, 21 Jan 2006 12:08:54 +0000 (12:08 +0000)
FossilOrigin-Name: 29281dea81c909b70b2d914d7061a6df8f388195

manifest
manifest.uuid
src/btree.c
src/pager.c
test/expr.test
test/select5.test
test/shared_err.test
test/tester.tcl

index a076047d112a737d8cda6a666ad6d3b951253890..ec98798423c3206d58fdc0e3c1210afafd5ba307 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C More\scompiler\swarnings\sfixed\s-\sor\sin\ssome\scases\scomments\sare\sadded\sto\sexplain\nthat\sthe\scompiler\sis\swrong.\s(CVS\s2984)
-D 2006-01-20T18:10:57
+C Fix\smore\sproblems\swith\smalloc()\sand\sIO\sfailures.\s(CVS\s2985)
+D 2006-01-21T12:08:54
 F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967
 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -34,7 +34,7 @@ F src/alter.c 90b779cf00489535cab6490df6dc050f40e4e874
 F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
 F src/attach.c 0081040e9a5d13669b6712e947688c10f030bfc1
 F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2
-F src/btree.c a1397e80f1db2d92ed246c8a134c7f0208585270
+F src/btree.c c6ebb78756ec98ded27a3cb6678481e0555b6b13
 F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184
 F src/build.c 15224e2fd348ad32b9044aaa5bdc912e4067da15
 F src/callback.c 1bf497306c32229114f826707054df7ebe10abf2
@@ -59,7 +59,7 @@ F src/os_unix.c 38a55e51fb2c6f32c0ce86d274f5787f6c3668ed
 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
 F src/os_win.c 98e4e38db7d4a00647b2bb1c60d28b7ca5034c03
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 7e124928343134286aac38eba62606b992c44344
+F src/pager.c 0f1565938ca972490ff72a8dc0a90d3a1d563883
 F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f
 F src/parse.y 83df51fea35f68f7e07384d75dce83d1ed30434c
 F src/pragma.c 4496cc77dc35824e1c978c3d1413b8a5a4c777d3
@@ -158,7 +158,7 @@ F test/distinctagg.test 2b89d1c5220d966a30ba4b40430338669301188b
 F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
 F test/enc2.test 0c8d3142c032c4f907b546d99e00b787f9700bb7
 F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
-F test/expr.test a513aceb5d89042232e0d07ac5a1591965cf3963
+F test/expr.test 4e65cade931e14a0194eee41e33707e7af5f397a
 F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
 F test/format4.test 9f31d41d4f926cab97b2ebe6be00a6ab12dece87
 F test/func.test 337888172c054c2de1aa3bacad6115522943dc2c
@@ -222,13 +222,13 @@ F test/select1.test f4ab4b66e7089f0c64b6df954e75bafe05aabc0d
 F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
 F test/select3.test 8fece41cd8f2955131b3f973a7123bec60b6e65e
 F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
-F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b
+F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
 F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4
 F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
 F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
 F test/shared.test 9982a65ccf3f4eee844a19f3ab0bcd7a158a76e5
 F test/shared2.test 909fc0f0277684ed29cc1b36c8e159188aec7f28
-F test/shared_err.test f72c9fbe1802500f0d97e768f947ae5c703c0152
+F test/shared_err.test 32d43ebe6b2a43b27227cc2cd153f5bcf9f0e8ad
 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
 F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
 F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
@@ -237,7 +237,7 @@ F test/table.test 6dc0dfa44dd429520e0e5a0c5e55025f730e9403
 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
 F test/tclsqlite.test 9b5c4a09879a97572e5c84372f5d045dd4703392
 F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
-F test/tester.tcl e207c5008493dee7a03a619f1a5f23d4841ca7d7
+F test/tester.tcl 0a939262ccb0b87449f98d8780396a4c293831b0
 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
 F test/thread2.test 6d7b30102d600f51b4055ee3a5a19228799049fb
 F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
@@ -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 b7bdac0afd99b8dc03749877f675a5f782120295
-R 257f8ebaf1a7df3e818e3ee3377c2e0b
-U drh
-Z cb095a9dd724704d4668f7f90fbf8e42
+P 507653a98cbd096f836a977408e373640c7cdb8f
+R 4645653023c28a7e6aa62dcc72d6f189
+U danielk1977
+Z 226f4ae14f953612ee8b3482130c4818
index a7e4cc50496861c6ed54201ff3b54e1539187f5d..76addcdbf5be5ffc7a7e3461a82536fb0936d77b 100644 (file)
@@ -1 +1 @@
-507653a98cbd096f836a977408e373640c7cdb8f
\ No newline at end of file
+29281dea81c909b70b2d914d7061a6df8f388195
\ No newline at end of file
index e130148166f9ad7d374ec2c0c4de3d13d39142cf..5d00a29720e9ab47229906705a0e143d80602a94 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.305 2006/01/20 18:10:57 drh Exp $
+** $Id: btree.c,v 1.306 2006/01/21 12:08:54 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -541,11 +541,9 @@ static int saveCursorPosition(BtCursor *pCur){
   }
   assert( !pCur->pPage->intKey || !pCur->pKey );
 
-  /* Todo: Should we drop the reference to pCur->pPage here? */
-  releasePage(pCur->pPage);
-  pCur->pPage = 0;
-
   if( rc==SQLITE_OK ){
+    releasePage(pCur->pPage);
+    pCur->pPage = 0;
     pCur->eState = CURSOR_REQUIRESEEK;
   }
 
index 6cc9869150039b71619c2c8c7a31635e9d1cd4fc..7fc5ef05fc70abc073b5c74ea7c9ec35ce953ea2 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.248 2006/01/20 18:10:57 drh Exp $
+** @(#) $Id: pager.c,v 1.249 2006/01/21 12:08:54 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -909,6 +909,8 @@ static int pager_unwritelock(Pager *pPager){
   pPager->state = PAGER_SHARED;
   pPager->origDbSize = 0;
   pPager->setMaster = 0;
+  pPager->needSync = 0;
+  pPager->pFirstSynced = pPager->pFirst;
   return rc;
 }
 
index 6f920980772d7f99e131e587990c3f66f1c951c1..3400f6c56d4c791ec7c497eebf42554d1a199f7b 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing expressions.
 #
-# $Id: expr.test,v 1.49 2006/01/07 14:02:27 danielk1977 Exp $
+# $Id: expr.test,v 1.50 2006/01/21 12:08:54 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -458,6 +458,13 @@ test_expr expr-6.64 {t1='ac', t2=NULL} {t1 GLOB t2} {{}}
 test_expr expr-6.65 {t1=NULL, t2='a*?c'} {t1 NOT GLOB t2} {{}}
 test_expr expr-6.66 {t1='ac', t2=NULL} {t1 NOT GLOB t2} {{}}
 
+# Check that the affinity of a CAST expression is calculated correctly.
+ifcapable cast {
+  test_expr expr-6.67 {t1='01', t2=1} {t1 = t2} 0
+  test_expr expr-6.68 {t1='1', t2=1} {t1 = t2} 1
+  test_expr expr-6.69 {t1='01', t2=1} {CAST(t1 AS INTEGER) = t2} 1
+}
+
 test_expr expr-case.1 {i1=1, i2=2} \
        {CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne
 test_expr expr-case.2 {i1=2, i2=2} \
index f6eff45f99fe78b1e15a67c95c0caf7179b8640e..fe53c7273e5bbd6d09e2b436524eb59ba37500e1 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this file is testing aggregate functions and the
 # GROUP BY and HAVING clauses of SELECT statements.
 #
-# $Id: select5.test,v 1.15 2005/09/20 18:13:25 drh Exp $
+# $Id: select5.test,v 1.16 2006/01/21 12:08:55 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -182,5 +182,11 @@ do_test select5-6.2 {
     SELECT max(x), count(x), y, z FROM t4 GROUP BY y, z ORDER BY 1
   }
 } {1 1 2 {} 2 1 3 {} 3 1 {} 5 4 2 {} 6 5 2 {} {} 6 1 7 8}
-  
+
+do_test select5.7.2 {
+  execsql {
+    SELECT count(*), count(x) as cnt FROM t4 GROUP BY y ORDER BY cnt;
+  }
+} {1 1 1 1 1 1 5 5}
 finish_test
index cdbc98a21fc4d8e719c1391e20829ba76b4f87b9..e070056a2381fe3dbf4f5117ce16b73ca9fe7c7c 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.2 2006/01/20 16:32:05 danielk1977 Exp $
+# $Id: shared_err.test,v 1.3 2006/01/21 12:08:55 danielk1977 Exp $
 
 proc skip {args} {}
 
@@ -28,6 +28,101 @@ ifcapable !shared_cache||!subquery {
 }
 set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
 
+
+# Todo: This is a copy of the [do_malloc_test] proc in malloc.test
+# It would be better if these were consolidated.
+
+# Usage: do_malloc_test <test number> <options...>
+#
+# The first argument, <test number>, is an integer used to name the
+# tests executed by this proc. Options are as follows:
+#
+#     -tclprep          TCL script to run to prepare test.
+#     -sqlprep          SQL script to run to prepare test.
+#     -tclbody          TCL script to run with malloc failure simulation.
+#     -sqlbody          TCL script to run with malloc failure simulation.
+#     -cleanup          TCL script to run after the test.
+#
+# This command runs a series of tests to verify SQLite's ability
+# to handle an out-of-memory condition gracefully. It is assumed
+# that if this condition occurs a malloc() call will return a
+# NULL pointer. Linux, for example, doesn't do that by default. See
+# the "BUGS" section of malloc(3).
+#
+# Each iteration of a loop, the TCL commands in any argument passed
+# to the -tclbody switch, followed by the SQL commands in any argument
+# passed to the -sqlbody switch are executed. Each iteration the
+# Nth call to sqliteMalloc() is made to fail, where N is increased
+# each time the loop runs starting from 1. When all commands execute
+# successfully, the loop ends.
+#
+proc do_malloc_test {tn args} {
+  array unset ::mallocopts 
+  array set ::mallocopts $args
+
+  set ::go 1
+  for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+    do_test shared_malloc-$tn.$::n {
+
+      # Remove all traces of database files test.db and test2.db from the files
+      # system. Then open (empty database) "test.db" with the handle [db].
+      # 
+      sqlite_malloc_fail 0
+      catch {db close} 
+      catch {file delete -force test.db}
+      catch {file delete -force test.db-journal}
+      catch {file delete -force test2.db}
+      catch {file delete -force test2.db-journal}
+      catch {sqlite3 db test.db} 
+      set ::DB [sqlite3_connection_pointer db]
+
+      # Execute any -tclprep and -sqlprep scripts.
+      #
+      if {[info exists ::mallocopts(-tclprep)]} {
+        eval $::mallocopts(-tclprep)
+      }
+      if {[info exists ::mallocopts(-sqlprep)]} {
+        execsql $::mallocopts(-sqlprep)
+      }
+
+      # Now set the ${::n}th malloc() to fail and execute the -tclbody and
+      # -sqlbody scripts.
+      #
+      sqlite_malloc_fail $::n
+      set ::mallocbody {}
+      if {[info exists ::mallocopts(-tclbody)]} {
+        append ::mallocbody "$::mallocopts(-tclbody)\n"
+      }
+      if {[info exists ::mallocopts(-sqlbody)]} {
+        append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
+      }
+      set v [catch $::mallocbody msg]
+
+      set leftover [lindex [sqlite_malloc_stat] 2]
+      if {$leftover>0} {
+        if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v  Message=$msg"}
+        set ::go 0
+        if {$v} {
+          puts "\nError message returned: $msg"
+        } else {
+          set v {1 1}
+        }
+      } else {
+        set v2 [expr {$msg=="" || $msg=="out of memory"}]
+        if {!$v2} {puts "\nError message returned: $msg"}
+        lappend v $v2
+      }
+    } {1 1}
+
+    sqlite_malloc_fail 0
+    if {[info exists ::mallocopts(-cleanup)]} {
+      catch [list uplevel #0 $::mallocopts(-cleanup)] msg
+    }
+  }
+  unset ::mallocopts
+}
+
+
 do_ioerr_test shared_ioerr-1 -tclprep {
   sqlite3 db2 test.db
   execsql {
@@ -134,6 +229,53 @@ do_ioerr_test shared_ioerr-2 -tclprep {
 # "saved" (because another cursor is going to modify the underlying table). 
 # 
 do_ioerr_test shared_ioerr-3 -tclprep {
+  sqlite3 db2 test.db
+  execsql {
+    PRAGMA read_uncommitted = 1;
+    PRAGMA cache_size = 10;
+    BEGIN;
+    CREATE TABLE t1(a, b, UNIQUE(a, b));
+  } db2
+  for {set i 0} {$i < 200} {incr i} {
+    set a [string range [string repeat "[format %03d $i]." 5] 0 end-1]
+
+    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 000.000.000.000
+  sqlite3_step $::STMT       ;# Cursor points at 001.001.001.001
+
+} -tclbody {
+  execsql {
+    INSERT INTO t1 VALUES('201.201.201.201.201', NULL);
+  }
+} -cleanup {
+  do_test shared_ioerr-3.$n.cleanup.1 {
+    sqlite3_step $::STMT
+  } {SQLITE_ROW}
+  do_test shared_ioerr-3.$n.cleanup.2 {
+    sqlite3_column_text $::STMT 0
+  } {002.002.002.002.002}
+  do_test shared_ioerr-3.$n.cleanup.3 {
+    sqlite3_finalize $::STMT
+  } {SQLITE_OK}
+# db2 eval {select * from sqlite_master}
+  db2 close
+}
+
+# Provoke a malloc() failure when a cursor position is being saved. This
+# only happens with index cursors (because they malloc() space to save the
+# current key value). It does not happen with tables, because an integer
+# key does not require a malloc() to store. 
+#
+# 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
+# continue unaffected.
+# 
+do_malloc_test 4 -tclprep {
   sqlite3 db2 test.db
   execsql {
     PRAGMA read_uncommitted = 1;
@@ -155,13 +297,13 @@ do_ioerr_test shared_ioerr-3 -tclprep {
     INSERT INTO t1 VALUES(6, NULL);
   }
 } -cleanup {
-  do_test shared_ioerr-3.$n.cleanup.1 {
+  do_test shared_malloc-4.$::n.cleanup.1 {
     sqlite3_step $::STMT
   } {SQLITE_ROW}
-  do_test shared_ioerr-3.$n.cleanup.2 {
+  do_test shared_malloc-4.$::n.cleanup.2 {
     sqlite3_column_text $::STMT 0
   } {2222222222}
-  do_test shared_ioerr-3.$n.cleanup.3 {
+  do_test shared_malloc-4.$::n.cleanup.3 {
     sqlite3_finalize $::STMT
   } {SQLITE_OK}
 # db2 eval {select * from sqlite_master}
index c83e6f9bee47fbfb7ca4d3af4826a2b96b37080a..8e63d6bcd4e3ad319feb16cdc21818f1b8a81d46 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements some common TCL routines used for regression
 # testing the SQLite library
 #
-# $Id: tester.tcl,v 1.62 2006/01/17 16:10:14 danielk1977 Exp $
+# $Id: tester.tcl,v 1.63 2006/01/21 12:08:55 danielk1977 Exp $
 
 # Make sure tclsqlite3 was compiled correctly.  Abort now with an
 # error message if not.
@@ -398,6 +398,7 @@ proc do_ioerr_test {testname args} {
       } $checksum
     }
 
+    set ::sqlite_io_error_pending 0
     if {[info exists ::ioerropts(-cleanup)]} {
       catch $::ioerropts(-cleanup)
     }