1*4520Snw141292 2*4520Snw141292#pragma ident "%Z%%M% %I% %E% SMI" 3*4520Snw141292 4*4520Snw141292# 2004 Feb 8 5*4520Snw141292# 6*4520Snw141292# The author disclaims copyright to this source code. In place of 7*4520Snw141292# a legal notice, here is a blessing: 8*4520Snw141292# 9*4520Snw141292# May you do good and not evil. 10*4520Snw141292# May you find forgiveness for yourself and forgive others. 11*4520Snw141292# May you share freely, never taking more than you give. 12*4520Snw141292# 13*4520Snw141292#*********************************************************************** 14*4520Snw141292# This file implements regression tests for SQLite library. The 15*4520Snw141292# focus of this script is the sqlite_interrupt() API. 16*4520Snw141292# 17*4520Snw141292# $Id: interrupt.test,v 1.4.2.1 2004/05/10 20:27:42 drh Exp $ 18*4520Snw141292 19*4520Snw141292 20*4520Snw141292set testdir [file dirname $argv0] 21*4520Snw141292source $testdir/tester.tcl 22*4520Snw141292 23*4520Snw141292# Compute a checksum on the entire database. 24*4520Snw141292# 25*4520Snw141292proc cksum {{db db}} { 26*4520Snw141292 set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n 27*4520Snw141292 foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] { 28*4520Snw141292 append txt [$db eval "SELECT * FROM $tbl"]\n 29*4520Snw141292 } 30*4520Snw141292 foreach prag {default_synchronous default_cache_size} { 31*4520Snw141292 append txt $prag-[$db eval "PRAGMA $prag"]\n 32*4520Snw141292 } 33*4520Snw141292 set cksum [string length $txt]-[md5 $txt] 34*4520Snw141292 # puts $cksum-[file size test.db] 35*4520Snw141292 return $cksum 36*4520Snw141292} 37*4520Snw141292 38*4520Snw141292# This routine attempts to execute the sql in $sql. It triggers an 39*4520Snw141292# interrupt a progressively later and later points during the processing 40*4520Snw141292# and checks to make sure SQLITE_INTERRUPT is returned. Eventually, 41*4520Snw141292# the routine completes successfully. 42*4520Snw141292# 43*4520Snw141292proc interrupt_test {testid sql result {initcnt 0} {maxcnt 1000000}} { 44*4520Snw141292 set orig_sum [cksum] 45*4520Snw141292 set i $initcnt 46*4520Snw141292 global sqlite_interrupt_count 47*4520Snw141292 while {$i<$maxcnt} { 48*4520Snw141292 incr i 49*4520Snw141292 set sqlite_interrupt_count $i 50*4520Snw141292 do_test $testid.$i.1 [format { 51*4520Snw141292 set ::r [catchsql %s] 52*4520Snw141292 set ::code [db errorcode] 53*4520Snw141292 expr {$::code==0 || $::code==9} 54*4520Snw141292 } [list $sql]] 1 55*4520Snw141292 if {$::code==9} { 56*4520Snw141292 do_test $testid.$i.2 { 57*4520Snw141292 cksum 58*4520Snw141292 } $orig_sum 59*4520Snw141292 } elseif {$sqlite_interrupt_count>0} { 60*4520Snw141292 do_test $testid.$i.99 { 61*4520Snw141292 set ::r 62*4520Snw141292 } [list 0 $result] 63*4520Snw141292 break 64*4520Snw141292 } 65*4520Snw141292 } 66*4520Snw141292 set sqlite_interrupt_count 0 67*4520Snw141292} 68*4520Snw141292 69*4520Snw141292do_test interrupt-1.1 { 70*4520Snw141292 execsql { 71*4520Snw141292 CREATE TABLE t1(a,b); 72*4520Snw141292 SELECT name FROM sqlite_master; 73*4520Snw141292 } 74*4520Snw141292} {t1} 75*4520Snw141292interrupt_test interrupt-1.2 {DROP TABLE t1} {} 1 14 76*4520Snw141292do_test interrupt-1.3 { 77*4520Snw141292 execsql { 78*4520Snw141292 SELECT name FROM sqlite_master; 79*4520Snw141292 } 80*4520Snw141292} {} 81*4520Snw141292integrity_check interrupt-1.4 82*4520Snw141292 83*4520Snw141292do_test interrrupt-2.1 { 84*4520Snw141292 execsql { 85*4520Snw141292 BEGIN; 86*4520Snw141292 CREATE TABLE t1(a,b); 87*4520Snw141292 INSERT INTO t1 VALUES(1,randstr(300,400)); 88*4520Snw141292 INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1; 89*4520Snw141292 INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1; 90*4520Snw141292 INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1; 91*4520Snw141292 INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1; 92*4520Snw141292 INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1; 93*4520Snw141292 INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1; 94*4520Snw141292 COMMIT; 95*4520Snw141292 UPDATE t1 SET b=substr(b,-5,5); 96*4520Snw141292 SELECT count(*) from t1; 97*4520Snw141292 } 98*4520Snw141292} 64 99*4520Snw141292set origsize [file size test.db] 100*4520Snw141292set cksum [db eval {SELECT md5sum(a || b) FROM t1}] 101*4520Snw141292interrupt_test interrupt-2.2 {VACUUM} {} 100 102*4520Snw141292do_test interrupt-2.3 { 103*4520Snw141292 execsql { 104*4520Snw141292 SELECT md5sum(a || b) FROM t1; 105*4520Snw141292 } 106*4520Snw141292} $cksum 107*4520Snw141292do_test interrupt-2.4 { 108*4520Snw141292 expr {$::origsize>[file size test.db]} 109*4520Snw141292} 1 110*4520Snw141292integrity_check interrupt-2.5 111*4520Snw141292 112*4520Snw141292# Ticket #594. If an interrupt occurs in the middle of a transaction 113*4520Snw141292# and that transaction is later rolled back, the internal schema tables do 114*4520Snw141292# not reset. 115*4520Snw141292# 116*4520Snw141292for {set i 1} {$i<50} {incr i 5} { 117*4520Snw141292 do_test interrupt-3.$i.1 { 118*4520Snw141292 execsql { 119*4520Snw141292 BEGIN; 120*4520Snw141292 CREATE TEMP TABLE t2(x,y); 121*4520Snw141292 SELECT name FROM sqlite_temp_master; 122*4520Snw141292 } 123*4520Snw141292 } {t2} 124*4520Snw141292 do_test interrupt-3.$i.2 { 125*4520Snw141292 set ::sqlite_interrupt_count $::i 126*4520Snw141292 catchsql { 127*4520Snw141292 INSERT INTO t2 SELECT * FROM t1; 128*4520Snw141292 } 129*4520Snw141292 } {1 interrupted} 130*4520Snw141292 do_test interrupt-3.$i.3 { 131*4520Snw141292 execsql { 132*4520Snw141292 SELECT name FROM sqlite_temp_master; 133*4520Snw141292 } 134*4520Snw141292 } {t2} 135*4520Snw141292 do_test interrupt-3.$i.4 { 136*4520Snw141292 catchsql { 137*4520Snw141292 ROLLBACK 138*4520Snw141292 } 139*4520Snw141292 } {0 {}} 140*4520Snw141292 do_test interrupt-3.$i.5 { 141*4520Snw141292 catchsql {SELECT name FROM sqlite_temp_master}; 142*4520Snw141292 execsql { 143*4520Snw141292 SELECT name FROM sqlite_temp_master; 144*4520Snw141292 } 145*4520Snw141292 } {} 146*4520Snw141292} 147*4520Snw141292 148*4520Snw141292# There are reports of a memory leak if an interrupt occurs during 149*4520Snw141292# the beginning of a complex query - before the first callback. We 150*4520Snw141292# will try to reproduce it here: 151*4520Snw141292# 152*4520Snw141292execsql { 153*4520Snw141292 CREATE TABLE t2(a,b,c); 154*4520Snw141292 INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1; 155*4520Snw141292} 156*4520Snw141292set sql { 157*4520Snw141292 SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a; 158*4520Snw141292} 159*4520Snw141292set sqlite_interrupt_count 1000000 160*4520Snw141292execsql $sql 161*4520Snw141292set max_count [expr {1000000-$sqlite_interrupt_count}] 162*4520Snw141292for {set i 1} {$i<$max_count-5} {incr i 1} { 163*4520Snw141292 do_test interrupt-4.$i.1 { 164*4520Snw141292 set ::sqlite_interrupt_count $::i 165*4520Snw141292 catchsql $sql 166*4520Snw141292 } {1 interrupted} 167*4520Snw141292} 168*4520Snw141292 169*4520Snw141292 170*4520Snw141292finish_test 171