107cb560bSdanielk1977# 2005 December 30 207cb560bSdanielk1977# 307cb560bSdanielk1977# The author disclaims copyright to this source code. In place of 407cb560bSdanielk1977# a legal notice, here is a blessing: 507cb560bSdanielk1977# 607cb560bSdanielk1977# May you do good and not evil. 707cb560bSdanielk1977# May you find forgiveness for yourself and forgive others. 807cb560bSdanielk1977# May you share freely, never taking more than you give. 907cb560bSdanielk1977# 1007cb560bSdanielk1977#*********************************************************************** 1107cb560bSdanielk1977# 1207cb560bSdanielk1977# The focus of the tests in this file are IO errors that occur in a shared 1307cb560bSdanielk1977# cache context. What happens to connection B if one connection A encounters 1407cb560bSdanielk1977# an IO-error whilst reading or writing the file-system? 1507cb560bSdanielk1977# 16*b94bf855Sdanielk1977# $Id: shared_err.test,v 1.10 2007/03/19 13:53:38 danielk1977 Exp $ 1707cb560bSdanielk1977 1807cb560bSdanielk1977proc skip {args} {} 1907cb560bSdanielk1977 2007cb560bSdanielk1977 2107cb560bSdanielk1977set testdir [file dirname $argv0] 2207cb560bSdanielk1977source $testdir/tester.tcl 2307cb560bSdanielk1977db close 2407cb560bSdanielk1977 2507cb560bSdanielk1977ifcapable !shared_cache||!subquery { 2607cb560bSdanielk1977 finish_test 2707cb560bSdanielk1977 return 2807cb560bSdanielk1977} 2907cb560bSdanielk1977set ::enable_shared_cache [sqlite3_enable_shared_cache 1] 3007cb560bSdanielk1977 31c4da5b9fSdanielk1977# Todo: This is a copy of the [do_malloc_test] proc in malloc.test 32c4da5b9fSdanielk1977# It would be better if these were consolidated. 33c4da5b9fSdanielk1977 34c4da5b9fSdanielk1977# Usage: do_malloc_test <test number> <options...> 35c4da5b9fSdanielk1977# 36c4da5b9fSdanielk1977# The first argument, <test number>, is an integer used to name the 37c4da5b9fSdanielk1977# tests executed by this proc. Options are as follows: 38c4da5b9fSdanielk1977# 39c4da5b9fSdanielk1977# -tclprep TCL script to run to prepare test. 40c4da5b9fSdanielk1977# -sqlprep SQL script to run to prepare test. 41c4da5b9fSdanielk1977# -tclbody TCL script to run with malloc failure simulation. 42c4da5b9fSdanielk1977# -sqlbody TCL script to run with malloc failure simulation. 43c4da5b9fSdanielk1977# -cleanup TCL script to run after the test. 44c4da5b9fSdanielk1977# 45c4da5b9fSdanielk1977# This command runs a series of tests to verify SQLite's ability 46c4da5b9fSdanielk1977# to handle an out-of-memory condition gracefully. It is assumed 47c4da5b9fSdanielk1977# that if this condition occurs a malloc() call will return a 48c4da5b9fSdanielk1977# NULL pointer. Linux, for example, doesn't do that by default. See 49c4da5b9fSdanielk1977# the "BUGS" section of malloc(3). 50c4da5b9fSdanielk1977# 51c4da5b9fSdanielk1977# Each iteration of a loop, the TCL commands in any argument passed 52c4da5b9fSdanielk1977# to the -tclbody switch, followed by the SQL commands in any argument 53c4da5b9fSdanielk1977# passed to the -sqlbody switch are executed. Each iteration the 54c4da5b9fSdanielk1977# Nth call to sqliteMalloc() is made to fail, where N is increased 55c4da5b9fSdanielk1977# each time the loop runs starting from 1. When all commands execute 56c4da5b9fSdanielk1977# successfully, the loop ends. 57c4da5b9fSdanielk1977# 58c4da5b9fSdanielk1977proc do_malloc_test {tn args} { 59c4da5b9fSdanielk1977 array unset ::mallocopts 60c4da5b9fSdanielk1977 array set ::mallocopts $args 61c4da5b9fSdanielk1977 62c4da5b9fSdanielk1977 set ::go 1 63c4da5b9fSdanielk1977 for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { 64c4da5b9fSdanielk1977 do_test shared_malloc-$tn.$::n { 65c4da5b9fSdanielk1977 66c4da5b9fSdanielk1977 # Remove all traces of database files test.db and test2.db from the files 67c4da5b9fSdanielk1977 # system. Then open (empty database) "test.db" with the handle [db]. 68c4da5b9fSdanielk1977 # 69c4da5b9fSdanielk1977 sqlite_malloc_fail 0 70c4da5b9fSdanielk1977 catch {db close} 71c4da5b9fSdanielk1977 catch {file delete -force test.db} 72c4da5b9fSdanielk1977 catch {file delete -force test.db-journal} 73c4da5b9fSdanielk1977 catch {file delete -force test2.db} 74c4da5b9fSdanielk1977 catch {file delete -force test2.db-journal} 75c4da5b9fSdanielk1977 catch {sqlite3 db test.db} 76c4da5b9fSdanielk1977 set ::DB [sqlite3_connection_pointer db] 77c4da5b9fSdanielk1977 78c4da5b9fSdanielk1977 # Execute any -tclprep and -sqlprep scripts. 79c4da5b9fSdanielk1977 # 80c4da5b9fSdanielk1977 if {[info exists ::mallocopts(-tclprep)]} { 81c4da5b9fSdanielk1977 eval $::mallocopts(-tclprep) 82c4da5b9fSdanielk1977 } 83c4da5b9fSdanielk1977 if {[info exists ::mallocopts(-sqlprep)]} { 84c4da5b9fSdanielk1977 execsql $::mallocopts(-sqlprep) 85c4da5b9fSdanielk1977 } 86c4da5b9fSdanielk1977 87c4da5b9fSdanielk1977 # Now set the ${::n}th malloc() to fail and execute the -tclbody and 88c4da5b9fSdanielk1977 # -sqlbody scripts. 89c4da5b9fSdanielk1977 # 90c4da5b9fSdanielk1977 sqlite_malloc_fail $::n 91c4da5b9fSdanielk1977 set ::mallocbody {} 92c4da5b9fSdanielk1977 if {[info exists ::mallocopts(-tclbody)]} { 93c4da5b9fSdanielk1977 append ::mallocbody "$::mallocopts(-tclbody)\n" 94c4da5b9fSdanielk1977 } 95c4da5b9fSdanielk1977 if {[info exists ::mallocopts(-sqlbody)]} { 96c4da5b9fSdanielk1977 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" 97c4da5b9fSdanielk1977 } 98c4da5b9fSdanielk1977 set v [catch $::mallocbody msg] 99c4da5b9fSdanielk1977 100c4da5b9fSdanielk1977 set leftover [lindex [sqlite_malloc_stat] 2] 101c4da5b9fSdanielk1977 if {$leftover>0} { 102c4da5b9fSdanielk1977 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} 103c4da5b9fSdanielk1977 set ::go 0 104c4da5b9fSdanielk1977 if {$v} { 105c4da5b9fSdanielk1977 puts "\nError message returned: $msg" 106c4da5b9fSdanielk1977 } else { 107c4da5b9fSdanielk1977 set v {1 1} 108c4da5b9fSdanielk1977 } 109c4da5b9fSdanielk1977 } else { 110c4da5b9fSdanielk1977 set v2 [expr {$msg=="" || $msg=="out of memory"}] 111c4da5b9fSdanielk1977 if {!$v2} {puts "\nError message returned: $msg"} 112c4da5b9fSdanielk1977 lappend v $v2 113c4da5b9fSdanielk1977 } 114c4da5b9fSdanielk1977 } {1 1} 115c4da5b9fSdanielk1977 116c4da5b9fSdanielk1977 sqlite_malloc_fail 0 117c4da5b9fSdanielk1977 if {[info exists ::mallocopts(-cleanup)]} { 118c4da5b9fSdanielk1977 catch [list uplevel #0 $::mallocopts(-cleanup)] msg 119c4da5b9fSdanielk1977 } 120c4da5b9fSdanielk1977 } 121c4da5b9fSdanielk1977 unset ::mallocopts 122c4da5b9fSdanielk1977} 123c4da5b9fSdanielk1977 124c4da5b9fSdanielk1977 12507cb560bSdanielk1977do_ioerr_test shared_ioerr-1 -tclprep { 12607cb560bSdanielk1977 sqlite3 db2 test.db 12707cb560bSdanielk1977 execsql { 12807cb560bSdanielk1977 PRAGMA read_uncommitted = 1; 12907cb560bSdanielk1977 CREATE TABLE t1(a,b,c); 13007cb560bSdanielk1977 BEGIN; 13107cb560bSdanielk1977 SELECT * FROM sqlite_master; 13207cb560bSdanielk1977 } db2 13307cb560bSdanielk1977} -sqlbody { 13407cb560bSdanielk1977 SELECT * FROM sqlite_master; 13507cb560bSdanielk1977 INSERT INTO t1 VALUES(1,2,3); 13607cb560bSdanielk1977 BEGIN TRANSACTION; 13707cb560bSdanielk1977 INSERT INTO t1 VALUES(1,2,3); 13807cb560bSdanielk1977 INSERT INTO t1 VALUES(4,5,6); 13907cb560bSdanielk1977 ROLLBACK; 14007cb560bSdanielk1977 SELECT * FROM t1; 14107cb560bSdanielk1977 BEGIN TRANSACTION; 14207cb560bSdanielk1977 INSERT INTO t1 VALUES(1,2,3); 14307cb560bSdanielk1977 INSERT INTO t1 VALUES(4,5,6); 14407cb560bSdanielk1977 COMMIT; 14507cb560bSdanielk1977 SELECT * FROM t1; 14607cb560bSdanielk1977 DELETE FROM t1 WHERE a<100; 14707cb560bSdanielk1977} -cleanup { 14897a227c9Sdanielk1977 do_test shared_ioerr-1.$n.cleanup.1 { 14907cb560bSdanielk1977 set res [catchsql { 15007cb560bSdanielk1977 SELECT * FROM t1; 15107cb560bSdanielk1977 } db2] 15207cb560bSdanielk1977 set possible_results [list \ 15307cb560bSdanielk1977 "1 {disk I/O error}" \ 15407cb560bSdanielk1977 "0 {1 2 3}" \ 15507cb560bSdanielk1977 "0 {1 2 3 1 2 3 4 5 6}" \ 15607cb560bSdanielk1977 "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \ 15707cb560bSdanielk1977 "0 {}" \ 15807cb560bSdanielk1977 ] 15907cb560bSdanielk1977 set rc [expr [lsearch -exact $possible_results $res] >= 0] 16007cb560bSdanielk1977 if {$rc != 1} { 16107cb560bSdanielk1977 puts "" 16207cb560bSdanielk1977 puts "Result: $res" 16307cb560bSdanielk1977 } 16407cb560bSdanielk1977 set rc 16507cb560bSdanielk1977 } {1} 16607cb560bSdanielk1977 db2 close 16707cb560bSdanielk1977} 16807cb560bSdanielk1977 16907cb560bSdanielk1977do_ioerr_test shared_ioerr-2 -tclprep { 17007cb560bSdanielk1977 sqlite3 db2 test.db 17107cb560bSdanielk1977 execsql { 17207cb560bSdanielk1977 PRAGMA read_uncommitted = 1; 17307cb560bSdanielk1977 BEGIN; 17407cb560bSdanielk1977 CREATE TABLE t1(a, b); 17507cb560bSdanielk1977 INSERT INTO t1(oid) VALUES(NULL); 17607cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 17707cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 17807cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 17907cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18007cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18107cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18207cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18307cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18407cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18507cb560bSdanielk1977 INSERT INTO t1(oid) SELECT NULL FROM t1; 18607cb560bSdanielk1977 UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789'; 18707cb560bSdanielk1977 CREATE INDEX i1 ON t1(a); 18807cb560bSdanielk1977 COMMIT; 18907cb560bSdanielk1977 BEGIN; 19007cb560bSdanielk1977 SELECT * FROM sqlite_master; 19107cb560bSdanielk1977 } db2 19207cb560bSdanielk1977} -tclbody { 19307cb560bSdanielk1977 set ::residx 0 19407cb560bSdanielk1977 execsql {DELETE FROM t1 WHERE 0 = (a % 2);} 19507cb560bSdanielk1977 incr ::residx 19607cb560bSdanielk1977 19707cb560bSdanielk1977 # When this transaction begins the table contains 512 entries. The 19807cb560bSdanielk1977 # two statements together add 512+146 more if it succeeds. 19907cb560bSdanielk1977 # (1024/7==146) 20007cb560bSdanielk1977 execsql {BEGIN;} 20107cb560bSdanielk1977 execsql {INSERT INTO t1 SELECT a+1, b FROM t1;} 20207cb560bSdanielk1977 execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);} 20307cb560bSdanielk1977 execsql {COMMIT;} 20407cb560bSdanielk1977 20507cb560bSdanielk1977 incr ::residx 20607cb560bSdanielk1977} -cleanup { 20707cb560bSdanielk1977 do_test shared_ioerr-2.$n.cleanup.1 { 20807cb560bSdanielk1977 set res [catchsql { 20907cb560bSdanielk1977 SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a); 21007cb560bSdanielk1977 } db2] 21107cb560bSdanielk1977 set possible_results [list \ 21207cb560bSdanielk1977 {0 {1024 1 1024}} \ 21307cb560bSdanielk1977 {0 {1023 1 512}} \ 21407cb560bSdanielk1977 {0 {string994 1 1170}} \ 21507cb560bSdanielk1977 ] 21607cb560bSdanielk1977 set idx [lsearch -exact $possible_results $res] 21707cb560bSdanielk1977 set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}] 21807cb560bSdanielk1977 if {!$success} { 21907cb560bSdanielk1977 puts "" 22007cb560bSdanielk1977 puts "Result: \"$res\" ($::residx)" 22107cb560bSdanielk1977 } 22207cb560bSdanielk1977 set success 22307cb560bSdanielk1977 } {1} 22407cb560bSdanielk1977 db2 close 22507cb560bSdanielk1977} 22607cb560bSdanielk1977 22797a227c9Sdanielk1977# This test is designed to provoke an IO error when a cursor position is 22897a227c9Sdanielk1977# "saved" (because another cursor is going to modify the underlying table). 22997a227c9Sdanielk1977# 23097a227c9Sdanielk1977do_ioerr_test shared_ioerr-3 -tclprep { 23197a227c9Sdanielk1977 sqlite3 db2 test.db 23297a227c9Sdanielk1977 execsql { 23397a227c9Sdanielk1977 PRAGMA read_uncommitted = 1; 234c4da5b9fSdanielk1977 PRAGMA cache_size = 10; 235c4da5b9fSdanielk1977 BEGIN; 236c4da5b9fSdanielk1977 CREATE TABLE t1(a, b, UNIQUE(a, b)); 237c4da5b9fSdanielk1977 } db2 238c4da5b9fSdanielk1977 for {set i 0} {$i < 200} {incr i} { 239c4da5b9fSdanielk1977 set a [string range [string repeat "[format %03d $i]." 5] 0 end-1] 240c4da5b9fSdanielk1977 241c4da5b9fSdanielk1977 set b [string repeat $i 2000] 242c4da5b9fSdanielk1977 execsql {INSERT INTO t1 VALUES($a, $b)} db2 243c4da5b9fSdanielk1977 } 244c4da5b9fSdanielk1977 execsql {COMMIT} db2 245c4da5b9fSdanielk1977 set ::DB2 [sqlite3_connection_pointer db2] 246c4da5b9fSdanielk1977 set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] 247c4da5b9fSdanielk1977 sqlite3_step $::STMT ;# Cursor points at 000.000.000.000 248c4da5b9fSdanielk1977 sqlite3_step $::STMT ;# Cursor points at 001.001.001.001 249c4da5b9fSdanielk1977 250c4da5b9fSdanielk1977} -tclbody { 251c4da5b9fSdanielk1977 execsql { 25275bab7d6Sdanielk1977 BEGIN; 253c4da5b9fSdanielk1977 INSERT INTO t1 VALUES('201.201.201.201.201', NULL); 25475bab7d6Sdanielk1977 UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%'; 25575bab7d6Sdanielk1977 COMMIT; 256c4da5b9fSdanielk1977 } 257c4da5b9fSdanielk1977} -cleanup { 258*b94bf855Sdanielk1977 set ::steprc [sqlite3_step $::STMT] 259*b94bf855Sdanielk1977 set ::column [sqlite3_column_text $::STMT 0] 260*b94bf855Sdanielk1977 set ::finalrc [sqlite3_finalize $::STMT] 261*b94bf855Sdanielk1977 262*b94bf855Sdanielk1977 # There are three possible outcomes here (assuming persistent IO errors): 263*b94bf855Sdanielk1977 # 264*b94bf855Sdanielk1977 # 1. If the [sqlite3_step] did not require any IO (required pages in 265*b94bf855Sdanielk1977 # the cache), then the next row ("002...") may be retrieved 266*b94bf855Sdanielk1977 # successfully. 267*b94bf855Sdanielk1977 # 268*b94bf855Sdanielk1977 # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns 269*b94bf855Sdanielk1977 # SQLITE_ERROR and [sqlite3_finalize] returns IOERR. 270*b94bf855Sdanielk1977 # 271*b94bf855Sdanielk1977 # 3. If, after the initial IO error, SQLite tried to rollback the 272*b94bf855Sdanielk1977 # active transaction and a second IO error was encountered, then 273*b94bf855Sdanielk1977 # statement $::STMT will have been aborted. This means [sqlite3_stmt] 274*b94bf855Sdanielk1977 # returns SQLITE_ABORT, and the statement cursor does not move. i.e. 275*b94bf855Sdanielk1977 # [sqlite3_column] still returns the current row ("001...") and 276*b94bf855Sdanielk1977 # [sqlite3_finalize] returns SQLITE_OK. 277*b94bf855Sdanielk1977 # 278*b94bf855Sdanielk1977 279c4da5b9fSdanielk1977 do_test shared_ioerr-3.$n.cleanup.1 { 280*b94bf855Sdanielk1977 expr { 281*b94bf855Sdanielk1977 $::steprc eq "SQLITE_ROW" || 282*b94bf855Sdanielk1977 $::steprc eq "SQLITE_ERROR" || 283*b94bf855Sdanielk1977 $::steprc eq "SQLITE_ABORT" 284*b94bf855Sdanielk1977 } 285*b94bf855Sdanielk1977 } {1} 286c4da5b9fSdanielk1977 do_test shared_ioerr-3.$n.cleanup.2 { 287*b94bf855Sdanielk1977 expr { 288*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ROW" && $::column eq "002.002.002.002.002") || 289*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ERROR" && $::column eq "") || 290*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ABORT" && $::column eq "001.001.001.001.001") 291*b94bf855Sdanielk1977 } 292*b94bf855Sdanielk1977 } {1} 293c4da5b9fSdanielk1977 do_test shared_ioerr-3.$n.cleanup.3 { 294*b94bf855Sdanielk1977 expr { 295*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") || 296*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") || 297*b94bf855Sdanielk1977 ($::steprc eq "SQLITE_ABORT" && $::finalrc eq "SQLITE_OK") 298*b94bf855Sdanielk1977 } 299*b94bf855Sdanielk1977 } {1} 300*b94bf855Sdanielk1977 301c4da5b9fSdanielk1977# db2 eval {select * from sqlite_master} 302c4da5b9fSdanielk1977 db2 close 303c4da5b9fSdanielk1977} 304c4da5b9fSdanielk1977 3057b3822b3Sdrh# Only run these tests if memory debugging is turned on. 3067b3822b3Sdrh# 3077b3822b3Sdrhif {[info command sqlite_malloc_stat]==""} { 3087b3822b3Sdrh puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." 30980d56827Sdrh db close 31080d56827Sdrh sqlite3_enable_shared_cache $::enable_shared_cache 3117b3822b3Sdrh finish_test 3127b3822b3Sdrh return 3137b3822b3Sdrh} 3147b3822b3Sdrh 315c4da5b9fSdanielk1977# Provoke a malloc() failure when a cursor position is being saved. This 316c4da5b9fSdanielk1977# only happens with index cursors (because they malloc() space to save the 317c4da5b9fSdanielk1977# current key value). It does not happen with tables, because an integer 318c4da5b9fSdanielk1977# key does not require a malloc() to store. 319c4da5b9fSdanielk1977# 320c4da5b9fSdanielk1977# The library should return an SQLITE_NOMEM to the caller. The query that 321c4da5b9fSdanielk1977# owns the cursor (the one for which the position is not saved) should 322c4da5b9fSdanielk1977# continue unaffected. 323c4da5b9fSdanielk1977# 324c4da5b9fSdanielk1977do_malloc_test 4 -tclprep { 325c4da5b9fSdanielk1977 sqlite3 db2 test.db 326c4da5b9fSdanielk1977 execsql { 327c4da5b9fSdanielk1977 PRAGMA read_uncommitted = 1; 32897a227c9Sdanielk1977 BEGIN; 32997a227c9Sdanielk1977 CREATE TABLE t1(a, b, UNIQUE(a, b)); 33097a227c9Sdanielk1977 } db2 33197a227c9Sdanielk1977 for {set i 0} {$i < 5} {incr i} { 33297a227c9Sdanielk1977 set a [string repeat $i 10] 33397a227c9Sdanielk1977 set b [string repeat $i 2000] 33497a227c9Sdanielk1977 execsql {INSERT INTO t1 VALUES($a, $b)} db2 33597a227c9Sdanielk1977 } 33697a227c9Sdanielk1977 execsql {COMMIT} db2 33797a227c9Sdanielk1977 set ::DB2 [sqlite3_connection_pointer db2] 33897a227c9Sdanielk1977 set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] 33997a227c9Sdanielk1977 sqlite3_step $::STMT ;# Cursor points at 0000000000 34097a227c9Sdanielk1977 sqlite3_step $::STMT ;# Cursor points at 1111111111 34197a227c9Sdanielk1977} -tclbody { 34297a227c9Sdanielk1977 execsql { 34397a227c9Sdanielk1977 INSERT INTO t1 VALUES(6, NULL); 34497a227c9Sdanielk1977 } 34597a227c9Sdanielk1977} -cleanup { 346c4da5b9fSdanielk1977 do_test shared_malloc-4.$::n.cleanup.1 { 3478d34dfd6Sdanielk1977 set ::rc [sqlite3_step $::STMT] 3488d34dfd6Sdanielk1977 expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ABORT"} 3498d34dfd6Sdanielk1977 } {1} 3508d34dfd6Sdanielk1977 if {$::rc=="SQLITE_ROW"} { 351c4da5b9fSdanielk1977 do_test shared_malloc-4.$::n.cleanup.2 { 35297a227c9Sdanielk1977 sqlite3_column_text $::STMT 0 35397a227c9Sdanielk1977 } {2222222222} 3548d34dfd6Sdanielk1977 } 355c4da5b9fSdanielk1977 do_test shared_malloc-4.$::n.cleanup.3 { 35697a227c9Sdanielk1977 sqlite3_finalize $::STMT 35797a227c9Sdanielk1977 } {SQLITE_OK} 35897a227c9Sdanielk1977# db2 eval {select * from sqlite_master} 35997a227c9Sdanielk1977 db2 close 36097a227c9Sdanielk1977} 36197a227c9Sdanielk1977 3624b202ae2Sdanielk1977do_malloc_test 5 -tclbody { 3634b202ae2Sdanielk1977 sqlite3 dbX test.db 3644b202ae2Sdanielk1977 sqlite3 dbY test.db 3654b202ae2Sdanielk1977 dbX close 3664b202ae2Sdanielk1977 dbY close 3674b202ae2Sdanielk1977} -cleanup { 3684b202ae2Sdanielk1977 catch {dbX close} 3694b202ae2Sdanielk1977 catch {dbY close} 3704b202ae2Sdanielk1977} 3714b202ae2Sdanielk1977 3727246f5b9Sdanielk1977do_malloc_test 6 -tclbody { 3737246f5b9Sdanielk1977 catch {db close} 3747246f5b9Sdanielk1977 sqlite3_thread_cleanup 3757246f5b9Sdanielk1977 sqlite3_enable_shared_cache 0 3767246f5b9Sdanielk1977} -cleanup { 3777246f5b9Sdanielk1977 sqlite3_enable_shared_cache 1 3787246f5b9Sdanielk1977} 3797246f5b9Sdanielk1977 3807246f5b9Sdanielk1977do_test shared_misuse-7.1 { 3817246f5b9Sdanielk1977 sqlite3 db test.db 3827246f5b9Sdanielk1977 catch { 3837246f5b9Sdanielk1977 sqlite3_enable_shared_cache 0 3847246f5b9Sdanielk1977 } msg 3857246f5b9Sdanielk1977 set msg 3867246f5b9Sdanielk1977} {library routine called out of sequence} 3877246f5b9Sdanielk1977 3888d34dfd6Sdanielk1977# Again provoke a malloc() failure when a cursor position is being saved, 3898d34dfd6Sdanielk1977# this time during a ROLLBACK operation by some other handle. 3908d34dfd6Sdanielk1977# 3918d34dfd6Sdanielk1977# The library should return an SQLITE_NOMEM to the caller. The query that 3928d34dfd6Sdanielk1977# owns the cursor (the one for which the position is not saved) should 3938d34dfd6Sdanielk1977# be aborted. 3948d34dfd6Sdanielk1977# 3958d34dfd6Sdanielk1977set ::aborted 0 3968d34dfd6Sdanielk1977do_malloc_test 8 -tclprep { 3978d34dfd6Sdanielk1977 sqlite3 db2 test.db 3988d34dfd6Sdanielk1977 execsql { 3998d34dfd6Sdanielk1977 PRAGMA read_uncommitted = 1; 4008d34dfd6Sdanielk1977 BEGIN; 4018d34dfd6Sdanielk1977 CREATE TABLE t1(a, b, UNIQUE(a, b)); 4028d34dfd6Sdanielk1977 } db2 4038d34dfd6Sdanielk1977 for {set i 0} {$i < 2} {incr i} { 4048d34dfd6Sdanielk1977 set a [string repeat $i 10] 4058d34dfd6Sdanielk1977 set b [string repeat $i 2000] 4068d34dfd6Sdanielk1977 execsql {INSERT INTO t1 VALUES($a, $b)} db2 4078d34dfd6Sdanielk1977 } 4088d34dfd6Sdanielk1977 execsql {COMMIT} db2 4098d34dfd6Sdanielk1977 set ::DB2 [sqlite3_connection_pointer db2] 4108d34dfd6Sdanielk1977 set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] 4118d34dfd6Sdanielk1977 sqlite3_step $::STMT ;# Cursor points at 0000000000 4128d34dfd6Sdanielk1977 sqlite3_step $::STMT ;# Cursor points at 1111111111 4138d34dfd6Sdanielk1977} -tclbody { 4148d34dfd6Sdanielk1977 execsql { 4158d34dfd6Sdanielk1977 BEGIN; 4168d34dfd6Sdanielk1977 INSERT INTO t1 VALUES(6, NULL); 4178d34dfd6Sdanielk1977 ROLLBACK; 4188d34dfd6Sdanielk1977 } 4198d34dfd6Sdanielk1977} -cleanup { 4208d34dfd6Sdanielk1977 do_test shared_malloc-8.$::n.cleanup.1 { 4218d34dfd6Sdanielk1977 lrange [execsql { 4228d34dfd6Sdanielk1977 SELECT a FROM t1; 4238d34dfd6Sdanielk1977 } db2] 0 1 4248d34dfd6Sdanielk1977 } {0000000000 1111111111} 4258d34dfd6Sdanielk1977 do_test shared_malloc-8.$::n.cleanup.2 { 4268d34dfd6Sdanielk1977 set rc1 [sqlite3_step $::STMT] 4278d34dfd6Sdanielk1977 set rc2 [sqlite3_finalize $::STMT] 4288d34dfd6Sdanielk1977 if {$rc1=="SQLITE_ABORT"} { 4298d34dfd6Sdanielk1977 incr ::aborted 4308d34dfd6Sdanielk1977 } 4318d34dfd6Sdanielk1977 expr { 4328d34dfd6Sdanielk1977 ($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") || 4338d34dfd6Sdanielk1977 ($rc1=="SQLITE_ABORT" && $rc2=="SQLITE_OK") 4348d34dfd6Sdanielk1977 } 4358d34dfd6Sdanielk1977 } {1} 4368d34dfd6Sdanielk1977 db2 close 4378d34dfd6Sdanielk1977} 4388d34dfd6Sdanielk1977do_test shared_malloc-8.X { 4398d34dfd6Sdanielk1977 # Test that one or more queries were aborted due to the malloc() failure. 4408d34dfd6Sdanielk1977 expr $::aborted>=1 4418d34dfd6Sdanielk1977} {1} 4428d34dfd6Sdanielk1977 44307cb560bSdanielk1977catch {db close} 44407cb560bSdanielk1977sqlite3_enable_shared_cache $::enable_shared_cache 44507cb560bSdanielk1977finish_test 446