📄 malloc2.test
字号:
# 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.## $Id: malloc2.test,v 1.5 2006/09/04 18:54:14 drh Exp $set testdir [file dirname $argv0]source $testdir/tester.tcl# Only run these tests if memory debugging is turned on.#if {[info command sqlite_malloc_stat]==""} { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG=1" finish_test return}ifcapable !globalrecover { finish_test return}# 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. sqlite_malloc_fail $::n do_test malloc2-$tn.$::n.2 { set res [catchsql [string trim $::mallocopts(-sql)]] set rc [expr { 0==[string compare $res {1 {out of memory}}] || 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. if {[lindex [sqlite_malloc_stat] 2]>0} { sqlite_malloc_fail -1 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 # 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -