193581642Sdrh# 2004 Feb 8 293581642Sdrh# 393581642Sdrh# The author disclaims copyright to this source code. In place of 493581642Sdrh# a legal notice, here is a blessing: 593581642Sdrh# 693581642Sdrh# May you do good and not evil. 793581642Sdrh# May you find forgiveness for yourself and forgive others. 893581642Sdrh# May you share freely, never taking more than you give. 993581642Sdrh# 1093581642Sdrh#*********************************************************************** 1193581642Sdrh# This file implements regression tests for SQLite library. The 1293581642Sdrh# focus of this script is the sqlite_interrupt() API. 1393581642Sdrh# 1493aed5a1Sdrh# $Id: interrupt.test,v 1.16 2008/01/16 17:46:38 drh Exp $ 1593581642Sdrh 1693581642Sdrh 1793581642Sdrhset testdir [file dirname $argv0] 1893581642Sdrhsource $testdir/tester.tcl 19dddca286Sdrhset DB [sqlite3_connection_pointer db] 2093581642Sdrh 2193581642Sdrh# This routine attempts to execute the sql in $sql. It triggers an 22f11bded5Sdrh# interrupt at progressively later and later points during the processing 2393581642Sdrh# and checks to make sure SQLITE_INTERRUPT is returned. Eventually, 2493581642Sdrh# the routine completes successfully. 2593581642Sdrh# 2693581642Sdrhproc interrupt_test {testid sql result {initcnt 0}} { 2793581642Sdrh set orig_sum [cksum] 2893581642Sdrh set i $initcnt 2993581642Sdrh while 1 { 3093581642Sdrh incr i 3193581642Sdrh set ::sqlite_interrupt_count $i 3293581642Sdrh do_test $testid.$i.1 [format { 3393581642Sdrh set ::r [catchsql %s] 3493581642Sdrh set ::code [db errorcode] 3593581642Sdrh expr {$::code==0 || $::code==9} 3693581642Sdrh } [list $sql]] 1 3793581642Sdrh if {$::code==9} { 3893581642Sdrh do_test $testid.$i.2 { 3993581642Sdrh cksum 4093581642Sdrh } $orig_sum 4193581642Sdrh } else { 4293581642Sdrh do_test $testid.$i.99 { 4393581642Sdrh set ::r 4493581642Sdrh } [list 0 $result] 4593581642Sdrh break 4693581642Sdrh } 4793581642Sdrh } 4893581642Sdrh set ::sqlite_interrupt_count 0 4993581642Sdrh} 5093581642Sdrh 5193581642Sdrhdo_test interrupt-1.1 { 5293581642Sdrh execsql { 5393581642Sdrh CREATE TABLE t1(a,b); 5493581642Sdrh SELECT name FROM sqlite_master; 5593581642Sdrh } 5693581642Sdrh} {t1} 5793581642Sdrhinterrupt_test interrupt-1.2 {DROP TABLE t1} {} 5893581642Sdrhdo_test interrupt-1.3 { 5993581642Sdrh execsql { 6093581642Sdrh SELECT name FROM sqlite_master; 6193581642Sdrh } 6293581642Sdrh} {} 6393581642Sdrhintegrity_check interrupt-1.4 6493581642Sdrh 6593581642Sdrhdo_test interrrupt-2.1 { 6693581642Sdrh execsql { 6793581642Sdrh BEGIN; 6893581642Sdrh CREATE TABLE t1(a,b); 6993581642Sdrh INSERT INTO t1 VALUES(1,randstr(300,400)); 7093581642Sdrh INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1; 7193581642Sdrh INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1; 7293581642Sdrh INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1; 7393581642Sdrh INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1; 7493581642Sdrh INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1; 7593581642Sdrh INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1; 7693581642Sdrh COMMIT; 7793581642Sdrh UPDATE t1 SET b=substr(b,-5,5); 7893581642Sdrh SELECT count(*) from t1; 7993581642Sdrh } 8093581642Sdrh} 64 8193581642Sdrhset origsize [file size test.db] 8293581642Sdrhset cksum [db eval {SELECT md5sum(a || b) FROM t1}] 83798da52cSdrhifcapable {vacuum} { 8493581642Sdrh interrupt_test interrupt-2.2 {VACUUM} {} 100 85798da52cSdrh} 8693581642Sdrhdo_test interrupt-2.3 { 8793581642Sdrh execsql { 8893581642Sdrh SELECT md5sum(a || b) FROM t1; 8993581642Sdrh } 9093581642Sdrh} $cksum 915436dc2dSdrhifcapable {vacuum && !default_autovacuum} { 9293581642Sdrh do_test interrupt-2.4 { 9393581642Sdrh expr {$::origsize>[file size test.db]} 9493581642Sdrh } 1 9527d258a3Sdrh} 96c5cdca61Sdrhifcapable {explain} { 97c5cdca61Sdrh do_test interrupt-2.5 { 98c5cdca61Sdrh set sql {EXPLAIN SELECT max(a,b), a, b FROM t1} 99c5cdca61Sdrh execsql $sql 100c5cdca61Sdrh set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg] 101c5cdca61Sdrh lappend rc $msg 102c5cdca61Sdrh } {1 interrupted} 103c5cdca61Sdrh} 104c5cdca61Sdrhintegrity_check interrupt-2.6 10593581642Sdrh 1068ef83ffeSdrh# Ticket #594. If an interrupt occurs in the middle of a transaction 1078ef83ffeSdrh# and that transaction is later rolled back, the internal schema tables do 1088ef83ffeSdrh# not reset. 1098ef83ffeSdrh# 1103fe11f30Sdanielk1977# UPDATE: Interrupting a DML statement in the middle of a transaction now 1113fe11f30Sdanielk1977# causes the transaction to roll back. Leaving the transaction open after 1123fe11f30Sdanielk1977# an SQL statement was interrupted halfway through risks database corruption. 1133fe11f30Sdanielk1977# 11453c0f748Sdanielk1977ifcapable tempdb { 1158ef83ffeSdrh for {set i 1} {$i<50} {incr i 5} { 1168ef83ffeSdrh do_test interrupt-3.$i.1 { 1178ef83ffeSdrh execsql { 1188ef83ffeSdrh BEGIN; 1198ef83ffeSdrh CREATE TEMP TABLE t2(x,y); 1208ef83ffeSdrh SELECT name FROM sqlite_temp_master; 1218ef83ffeSdrh } 1228ef83ffeSdrh } {t2} 1238ef83ffeSdrh do_test interrupt-3.$i.2 { 1248ef83ffeSdrh set ::sqlite_interrupt_count $::i 1258ef83ffeSdrh catchsql { 1268ef83ffeSdrh INSERT INTO t2 SELECT * FROM t1; 1278ef83ffeSdrh } 1288ef83ffeSdrh } {1 interrupted} 1298ef83ffeSdrh do_test interrupt-3.$i.3 { 1308ef83ffeSdrh execsql { 131*e0a04a36Sdrh SELECT name FROM temp.sqlite_master; 1328ef83ffeSdrh } 1333fe11f30Sdanielk1977 } {} 1348ef83ffeSdrh do_test interrupt-3.$i.4 { 1358ef83ffeSdrh catchsql { 1368ef83ffeSdrh ROLLBACK 1378ef83ffeSdrh } 1383fe11f30Sdanielk1977 } {1 {cannot rollback - no transaction is active}} 1398ef83ffeSdrh do_test interrupt-3.$i.5 { 1408ef83ffeSdrh catchsql {SELECT name FROM sqlite_temp_master}; 1418ef83ffeSdrh execsql { 142*e0a04a36Sdrh SELECT name FROM temp.sqlite_master; 1438ef83ffeSdrh } 1448ef83ffeSdrh } {} 1458ef83ffeSdrh } 14653c0f748Sdanielk1977} 14793581642Sdrh 14823068027Sdrh# There are reports of a memory leak if an interrupt occurs during 14923068027Sdrh# the beginning of a complex query - before the first callback. We 15023068027Sdrh# will try to reproduce it here: 15123068027Sdrh# 15223068027Sdrhexecsql { 1539cbe7ca7Sdrh CREATE TABLE t2(a,b,c); 1549cbe7ca7Sdrh INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1; 15523068027Sdrh} 15623068027Sdrhset sql { 1579cbe7ca7Sdrh SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a; 15823068027Sdrh} 15923068027Sdrhset sqlite_interrupt_count 1000000 16023068027Sdrhexecsql $sql 16123068027Sdrhset max_count [expr {1000000-$sqlite_interrupt_count}] 16223068027Sdrhfor {set i 1} {$i<$max_count-5} {incr i 1} { 16323068027Sdrh do_test interrupt-4.$i.1 { 16423068027Sdrh set ::sqlite_interrupt_count $::i 1659cbe7ca7Sdrh catchsql $sql 16623068027Sdrh } {1 interrupted} 16723068027Sdrh} 16823068027Sdrh 169580c8c18Sdrhif {0} { # This doesn't work anymore since the collation factor is 170580c8c18Sdrh # no longer called during schema parsing. 17148e5aa27Sdrh# Interrupt during parsing 17248e5aa27Sdrh# 17348e5aa27Sdrhdo_test interrupt-5.1 { 1747e326c09Sdrh proc fake_interrupt {args} { 1757e326c09Sdrh db collate fake_collation no-op 1767e326c09Sdrh sqlite3_interrupt db 1777e326c09Sdrh return SQLITE_OK 17848e5aa27Sdrh } 179f11bded5Sdrh db collation_needed fake_interrupt 180f11bded5Sdrh catchsql { 181f11bded5Sdrh CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC); 182f11bded5Sdrh } 183f11bded5Sdrh} {1 interrupt} 184580c8c18Sdrh} 18593581642Sdrhfinish_test 186