From e36d23a85ebff914d74bb541558c2b6082b78edb Mon Sep 17 00:00:00 2001 From: dan miller Date: Sat, 20 Oct 2007 02:49:29 +0000 Subject: sqlite source (unix build) added to libraries --- .../sqlite/unix/sqlite-3.5.1/test/malloc2.test | 366 +++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test') diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test b/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test new file mode 100644 index 0000000..e48a569 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test @@ -0,0 +1,366 @@ +# 2005 March 18 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file attempts to check that the library can recover from a malloc() +# failure when sqlite3_global_recover() is invoked. +# +# (Later:) The sqlite3_global_recover() interface is now a no-op. +# Recovery from malloc() failures is automatic. But we keep these +# tests around because you can never have too many test cases. +# +# $Id: malloc2.test,v 1.8 2007/10/03 08:46:45 danielk1977 Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Only run these tests if memory debugging is turned on. +# +ifcapable !memdebug { + puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." + finish_test + return +} + +sqlite3_extended_result_codes db 1 + +# Generate a checksum based on the contents of the database. If the +# checksum of two databases is the same, and the integrity-check passes +# for both, the two databases are identical. +# +proc cksum {db} { + set ret [list] + ifcapable tempdb { + set sql { + SELECT name FROM sqlite_master WHERE type = 'table' UNION + SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION + SELECT 'sqlite_master' UNION + SELECT 'sqlite_temp_master' + } + } else { + set sql { + SELECT name FROM sqlite_master WHERE type = 'table' UNION + SELECT 'sqlite_master' + } + } + set tbllist [$db eval $sql] + set txt {} + foreach tbl $tbllist { + append txt [$db eval "SELECT * FROM $tbl"] + } + # puts txt=$txt + return [md5 $txt] +} + +proc do_malloc2_test {tn args} { + array set ::mallocopts $args + set sum [cksum db] + + for {set ::n 1} {true} {incr ::n} { + + # Run the SQL. Malloc number $::n is set to fail. A malloc() failure + # may or may not be reported. + sqlite3_memdebug_fail $::n -repeat 1 + do_test malloc2-$tn.$::n.2 { + set res [catchsql [string trim $::mallocopts(-sql)]] + set rc [expr { + 0==[string compare $res {1 {out of memory}}] || + [db errorcode] == 3082 || + 0==[lindex $res 0] + }] + if {$rc!=1} { + puts "Error: $res" + } + set rc + } {1} + + # If $::n is greater than the number of malloc() calls required to + # execute the SQL, then this test is finished. Break out of the loop. + set nFail [sqlite3_memdebug_fail -1] + if {$nFail==0} break + + # Nothing should work now, because the allocator should refuse to + # allocate any memory. + # + # Update: SQLite now automatically recovers from a malloc() failure. + # So the statement in the test below would work. + if 0 { + do_test malloc2-$tn.$::n.3 { + catchsql {SELECT 'nothing should work'} + } {1 {out of memory}} + } + + # Recover from the malloc failure. + # + # Update: The new malloc() failure handling means that a transaction may + # still be active even if a malloc() has failed. But when these tests were + # written this was not the case. So do a manual ROLLBACK here so that the + # tests pass. + do_test malloc2-$tn.$::n.4 { + sqlite3_global_recover + catch { + execsql { + ROLLBACK; + } + } + expr 0 + } {0} + + # Checksum the database. + do_test malloc2-$tn.$::n.5 { + cksum db + } $sum + + integrity_check malloc2-$tn.$::n.6 + if {$::nErr>1} return + } + unset ::mallocopts +} + +do_test malloc2.1.setup { + execsql { + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES(10, 20, 30); + INSERT INTO abc VALUES(40, 50, 60); + CREATE INDEX abc_i ON abc(a, b, c); + } +} {} +do_malloc2_test 1.1 -sql { + SELECT * FROM abc; +} +do_malloc2_test 1.2 -sql { + UPDATE abc SET c = c+10; +} +do_malloc2_test 1.3 -sql { + INSERT INTO abc VALUES(70, 80, 90); +} +do_malloc2_test 1.4 -sql { + DELETE FROM abc; +} +do_test malloc2.1.5 { + execsql { + SELECT * FROM abc; + } +} {} + +do_test malloc2.2.setup { + execsql { + CREATE TABLE def(a, b, c); + CREATE INDEX def_i1 ON def(a); + CREATE INDEX def_i2 ON def(c); + BEGIN; + } + for {set i 0} {$i<20} {incr i} { + execsql { + INSERT INTO def VALUES(randstr(300,300),randstr(300,300),randstr(300,300)); + } + } + execsql { + COMMIT; + } +} {} +do_malloc2_test 2 -sql { + BEGIN; + UPDATE def SET a = randstr(100,100) WHERE (oid%9)==0; + INSERT INTO def SELECT * FROM def WHERE (oid%13)==0; + + CREATE INDEX def_i3 ON def(b); + + UPDATE def SET a = randstr(100,100) WHERE (oid%9)==1; + INSERT INTO def SELECT * FROM def WHERE (oid%13)==1; + + CREATE TABLE def2 AS SELECT * FROM def; + DROP TABLE def; + CREATE TABLE def AS SELECT * FROM def2; + DROP TABLE def2; + + DELETE FROM def WHERE (oid%9)==2; + INSERT INTO def SELECT * FROM def WHERE (oid%13)==2; + COMMIT; +} + +ifcapable tempdb { + do_test malloc2.3.setup { + execsql { + CREATE TEMP TABLE ghi(a, b, c); + BEGIN; + } + for {set i 0} {$i<20} {incr i} { + execsql { + INSERT INTO ghi VALUES(randstr(300,300),randstr(300,300),randstr(300,300)); + } + } + execsql { + COMMIT; + } + } {} + do_malloc2_test 3 -sql { + BEGIN; + CREATE INDEX ghi_i1 ON ghi(a); + UPDATE def SET a = randstr(100,100) WHERE (oid%2)==0; + UPDATE ghi SET a = randstr(100,100) WHERE (oid%2)==0; + COMMIT; + } +} + +############################################################################ +# The test cases below are to increase the code coverage in btree.c and +# pager.c of this test file. The idea is that each malloc() that occurs in +# these two source files should be made to fail at least once. +# +catchsql { + DROP TABLE ghi; +} +do_malloc2_test 4.1 -sql { + SELECT * FROM def ORDER BY oid ASC; + SELECT * FROM def ORDER BY oid DESC; +} +do_malloc2_test 4.2 -sql { + PRAGMA cache_size = 10; + BEGIN; + + -- This will put about 25 pages on the free list. + DELETE FROM def WHERE 1; + + -- Allocate 32 new root pages. This will exercise the 'extract specific + -- page from the freelist' code when in auto-vacuum mode (see the + -- allocatePage() routine in btree.c). + CREATE TABLE t1(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t2(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t3(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t4(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t5(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t6(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t7(a UNIQUE, b UNIQUE, c UNIQUE); + CREATE TABLE t8(a UNIQUE, b UNIQUE, c UNIQUE); + + ROLLBACK; +} + +######################################################################## +# Test that the global linked list of database handles works. An assert() +# will fail if there is some problem. +do_test malloc2-5 { + sqlite3 db1 test.db + sqlite3 db2 test.db + sqlite3 db3 test.db + sqlite3 db4 test.db + sqlite3 db5 test.db + + sqlite3_extended_result_codes db1 1 + sqlite3_extended_result_codes db2 1 + sqlite3_extended_result_codes db3 1 + sqlite3_extended_result_codes db4 1 + sqlite3_extended_result_codes db5 1 + + # Close the head of the list: + db5 close + + # Close the end of the list: + db1 close + + # Close a handle from the middle of the list: + db3 close + + # Close the other two. Then open and close one more database, to make + # sure the head of the list was set back to NULL. + db2 close + db4 close + sqlite db1 test.db + db1 close +} {} + +######################################################################## +# Check that if a statement is active sqlite3_global_recover doesn't reset +# the sqlite3_malloc_failed variable. +# +# Update: There is now no sqlite3_malloc_failed variable, so these tests +# are not run. +# +# do_test malloc2-6.1 { +# set ::STMT [sqlite3_prepare $::DB {SELECT * FROM def} -1 DUMMY] +# sqlite3_step $::STMT +# } {SQLITE_ROW} +# do_test malloc2-6.2 { +# sqlite3 db1 test.db +# sqlite_malloc_fail 100 +# catchsql { +# SELECT * FROM def; +# } db1 +# } {1 {out of memory}} +# do_test malloc2-6.3 { +# sqlite3_global_recover +# } {SQLITE_BUSY} +# do_test malloc2-6.4 { +# catchsql { +# SELECT 'hello'; +# } +# } {1 {out of memory}} +# do_test malloc2-6.5 { +# sqlite3_reset $::STMT +# } {SQLITE_OK} +# do_test malloc2-6.6 { +# sqlite3_global_recover +# } {SQLITE_OK} +# do_test malloc2-6.7 { +# catchsql { +# SELECT 'hello'; +# } +# } {0 hello} +# do_test malloc2-6.8 { +# sqlite3_step $::STMT +# } {SQLITE_ERROR} +# do_test malloc2-6.9 { +# sqlite3_finalize $::STMT +# } {SQLITE_SCHEMA} +# do_test malloc2-6.10 { +# db1 close +# } {} + +######################################################################## +# Check that if an in-memory database is being used it is not possible +# to recover from a malloc() failure. +# +# Update: An in-memory database can now survive a malloc() failure, so these +# tests are not run. +# +# ifcapable memorydb { +# do_test malloc2-7.1 { +# sqlite3 db1 :memory: +# list +# } {} +# do_test malloc2-7.2 { +# sqlite_malloc_fail 100 +# catchsql { +# SELECT * FROM def; +# } +# } {1 {out of memory}} +# do_test malloc2-7.3 { +# sqlite3_global_recover +# } {SQLITE_ERROR} +# do_test malloc2-7.4 { +# catchsql { +# SELECT 'hello'; +# } +# } {1 {out of memory}} +# do_test malloc2-7.5 { +# db1 close +# } {} +# do_test malloc2-7.6 { +# sqlite3_global_recover +# } {SQLITE_OK} +# do_test malloc2-7.7 { +# catchsql { +# SELECT 'hello'; +# } +# } {0 hello} +# } + +finish_test -- cgit v1.1