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