AryaWu/sqlite
0
1# 2004 Feb 82#3# The author disclaims copyright to this source code. In place of4# a legal notice, here is a blessing:5#6# May you do good and not evil.7# May you find forgiveness for yourself and forgive others.8# May you share freely, never taking more than you give.9#10#***********************************************************************11# This file implements regression tests for SQLite library. The12# focus of this script is the sqlite_interrupt() API.13#14# $Id: interrupt.test,v 1.16 2008/01/16 17:46:38 drh Exp $15 16 17set testdir [file dirname $argv0]18source $testdir/tester.tcl19set DB [sqlite3_connection_pointer db]20 21# This routine attempts to execute the sql in $sql. It triggers an22# interrupt at progressively later and later points during the processing23# and checks to make sure SQLITE_INTERRUPT is returned. Eventually,24# the routine completes successfully.25#26proc interrupt_test {testid sql result {initcnt 0}} {27 set orig_sum [cksum]28 set i $initcnt29 while 1 {30 incr i31 set ::sqlite_interrupt_count $i32 do_test $testid.$i.1 [format {33 set ::r [catchsql %s]34 set ::code [db errorcode]35 expr {$::code==0 || $::code==9}36 } [list $sql]] 137 if {$::code==9} {38 do_test $testid.$i.2 {39 cksum40 } $orig_sum41 } else {42 do_test $testid.$i.99 {43 set ::r44 } [list 0 $result]45 break46 }47 }48 set ::sqlite_interrupt_count 049}50 51do_test interrupt-1.1 {52 execsql {53 CREATE TABLE t1(a,b);54 SELECT name FROM sqlite_master;55 }56} {t1}57interrupt_test interrupt-1.2 {DROP TABLE t1} {}58do_test interrupt-1.3 {59 execsql {60 SELECT name FROM sqlite_master;61 }62} {}63integrity_check interrupt-1.464 65do_test interrrupt-2.1 {66 execsql {67 BEGIN;68 CREATE TABLE t1(a,b);69 INSERT INTO t1 VALUES(1,randstr(300,400));70 INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;71 INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;72 INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;73 INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;74 INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;75 INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;76 COMMIT;77 UPDATE t1 SET b=substr(b,-5,5);78 SELECT count(*) from t1;79 }80} 6481set origsize [file size test.db]82set cksum [db eval {SELECT md5sum(a || b) FROM t1}]83ifcapable {vacuum} {84 interrupt_test interrupt-2.2 {VACUUM} {} 10085}86do_test interrupt-2.3 {87 execsql {88 SELECT md5sum(a || b) FROM t1;89 }90} $cksum91ifcapable {vacuum && !default_autovacuum} {92 do_test interrupt-2.4 {93 expr {$::origsize>[file size test.db]}94 } 195}96ifcapable {explain} {97 do_test interrupt-2.5.1 {98 sqlite3_is_interrupted $DB99 } {0}100 do_test interrupt-2.5.2 {101 unset -nocomplain ::interrupt_count102 set ::interrupt_count 0103 set sql {EXPLAIN SELECT max(a,b), a, b FROM t1}104 execsql $sql105 set rc [catch {db eval $sql {106 sqlite3_interrupt $DB;107 incr ::interrupt_count [sqlite3_is_interrupted $DB];108 }} msg]109 lappend rc $msg110 } {1 interrupted}111 do_test interrupt-2.5.3 {112 set ::interrupt_count113 } {1}114}115integrity_check interrupt-2.6116do_test interrupt-2.7 {117 sqlite3_is_interrupted $DB118} {0}119 120# Ticket #594. If an interrupt occurs in the middle of a transaction121# and that transaction is later rolled back, the internal schema tables do122# not reset.123#124# UPDATE: Interrupting a DML statement in the middle of a transaction now125# causes the transaction to roll back. Leaving the transaction open after126# an SQL statement was interrupted halfway through risks database corruption.127#128ifcapable tempdb {129 for {set i 1} {$i<50} {incr i 5} {130 do_test interrupt-3.$i.1 {131 execsql {132 BEGIN;133 CREATE TEMP TABLE t2(x,y);134 SELECT name FROM sqlite_temp_master;135 }136 } {t2}137 do_test interrupt-3.$i.2 {138 set ::sqlite_interrupt_count $::i139 catchsql {140 INSERT INTO t2 SELECT * FROM t1;141 }142 } {1 interrupted}143 do_test interrupt-3.$i.3 {144 execsql {145 SELECT name FROM temp.sqlite_master;146 }147 } {}148 do_test interrupt-3.$i.4 {149 catchsql {150 ROLLBACK151 }152 } {1 {cannot rollback - no transaction is active}}153 do_test interrupt-3.$i.5 {154 catchsql {SELECT name FROM sqlite_temp_master};155 execsql {156 SELECT name FROM temp.sqlite_master;157 }158 } {}159 }160}161 162# There are reports of a memory leak if an interrupt occurs during163# the beginning of a complex query - before the first callback. We164# will try to reproduce it here:165#166execsql {167 CREATE TABLE t2(a,b,c);168 INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1;169}170set sql {171 SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a;172}173set sqlite_interrupt_count 1000000174execsql $sql175set max_count [expr {1000000-$sqlite_interrupt_count}]176for {set i 1} {$i<$max_count-5} {incr i 1} {177 do_test interrupt-4.$i.1 {178 set ::sqlite_interrupt_count $::i179 catchsql $sql180 } {1 interrupted}181}182 183if {0} { # This doesn't work anymore since the collation factor is184 # no longer called during schema parsing.185# Interrupt during parsing186#187do_test interrupt-5.1 {188 proc fake_interrupt {args} {189 db collate fake_collation no-op190 sqlite3_interrupt db191 return SQLITE_OK192 }193 db collation_needed fake_interrupt194 catchsql {195 CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);196 }197} {1 interrupt}198}199finish_test200 