diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/interrupt.test')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/test/interrupt.test | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/interrupt.test b/libraries/sqlite/unix/sqlite-3.5.1/test/interrupt.test new file mode 100644 index 0000000..b348baa --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/interrupt.test | |||
@@ -0,0 +1,198 @@ | |||
1 | # 2004 Feb 8 | ||
2 | # | ||
3 | # The author disclaims copyright to this source code. In place of | ||
4 | # 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. The | ||
12 | # focus of this script is the sqlite_interrupt() API. | ||
13 | # | ||
14 | # $Id: interrupt.test,v 1.15 2007/06/13 16:49:49 danielk1977 Exp $ | ||
15 | |||
16 | |||
17 | set testdir [file dirname $argv0] | ||
18 | source $testdir/tester.tcl | ||
19 | set DB [sqlite3_connection_pointer db] | ||
20 | |||
21 | # Compute a checksum on the entire database. | ||
22 | # | ||
23 | proc cksum {{db db}} { | ||
24 | set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n | ||
25 | foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] { | ||
26 | append txt [$db eval "SELECT * FROM $tbl"]\n | ||
27 | } | ||
28 | foreach prag {default_synchronous default_cache_size} { | ||
29 | append txt $prag-[$db eval "PRAGMA $prag"]\n | ||
30 | } | ||
31 | set cksum [string length $txt]-[md5 $txt] | ||
32 | # puts $cksum-[file size test.db] | ||
33 | return $cksum | ||
34 | } | ||
35 | |||
36 | # This routine attempts to execute the sql in $sql. It triggers an | ||
37 | # interrupt at progressively later and later points during the processing | ||
38 | # and checks to make sure SQLITE_INTERRUPT is returned. Eventually, | ||
39 | # the routine completes successfully. | ||
40 | # | ||
41 | proc interrupt_test {testid sql result {initcnt 0}} { | ||
42 | set orig_sum [cksum] | ||
43 | set i $initcnt | ||
44 | while 1 { | ||
45 | incr i | ||
46 | set ::sqlite_interrupt_count $i | ||
47 | do_test $testid.$i.1 [format { | ||
48 | set ::r [catchsql %s] | ||
49 | set ::code [db errorcode] | ||
50 | expr {$::code==0 || $::code==9} | ||
51 | } [list $sql]] 1 | ||
52 | if {$::code==9} { | ||
53 | do_test $testid.$i.2 { | ||
54 | cksum | ||
55 | } $orig_sum | ||
56 | } else { | ||
57 | do_test $testid.$i.99 { | ||
58 | set ::r | ||
59 | } [list 0 $result] | ||
60 | break | ||
61 | } | ||
62 | } | ||
63 | set ::sqlite_interrupt_count 0 | ||
64 | } | ||
65 | |||
66 | do_test interrupt-1.1 { | ||
67 | execsql { | ||
68 | CREATE TABLE t1(a,b); | ||
69 | SELECT name FROM sqlite_master; | ||
70 | } | ||
71 | } {t1} | ||
72 | interrupt_test interrupt-1.2 {DROP TABLE t1} {} | ||
73 | do_test interrupt-1.3 { | ||
74 | execsql { | ||
75 | SELECT name FROM sqlite_master; | ||
76 | } | ||
77 | } {} | ||
78 | integrity_check interrupt-1.4 | ||
79 | |||
80 | do_test interrrupt-2.1 { | ||
81 | execsql { | ||
82 | BEGIN; | ||
83 | CREATE TABLE t1(a,b); | ||
84 | INSERT INTO t1 VALUES(1,randstr(300,400)); | ||
85 | INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1; | ||
86 | INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1; | ||
87 | INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1; | ||
88 | INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1; | ||
89 | INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1; | ||
90 | INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1; | ||
91 | COMMIT; | ||
92 | UPDATE t1 SET b=substr(b,-5,5); | ||
93 | SELECT count(*) from t1; | ||
94 | } | ||
95 | } 64 | ||
96 | set origsize [file size test.db] | ||
97 | set cksum [db eval {SELECT md5sum(a || b) FROM t1}] | ||
98 | ifcapable {vacuum} { | ||
99 | interrupt_test interrupt-2.2 {VACUUM} {} 100 | ||
100 | } | ||
101 | do_test interrupt-2.3 { | ||
102 | execsql { | ||
103 | SELECT md5sum(a || b) FROM t1; | ||
104 | } | ||
105 | } $cksum | ||
106 | ifcapable {vacuum && !default_autovacuum} { | ||
107 | do_test interrupt-2.4 { | ||
108 | expr {$::origsize>[file size test.db]} | ||
109 | } 1 | ||
110 | } | ||
111 | ifcapable {explain} { | ||
112 | do_test interrupt-2.5 { | ||
113 | set sql {EXPLAIN SELECT max(a,b), a, b FROM t1} | ||
114 | execsql $sql | ||
115 | set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg] | ||
116 | lappend rc $msg | ||
117 | } {1 interrupted} | ||
118 | } | ||
119 | integrity_check interrupt-2.6 | ||
120 | |||
121 | # Ticket #594. If an interrupt occurs in the middle of a transaction | ||
122 | # and that transaction is later rolled back, the internal schema tables do | ||
123 | # not reset. | ||
124 | # | ||
125 | # UPDATE: Interrupting a DML statement in the middle of a transaction now | ||
126 | # causes the transaction to roll back. Leaving the transaction open after | ||
127 | # an SQL statement was interrupted halfway through risks database corruption. | ||
128 | # | ||
129 | ifcapable tempdb { | ||
130 | for {set i 1} {$i<50} {incr i 5} { | ||
131 | do_test interrupt-3.$i.1 { | ||
132 | execsql { | ||
133 | BEGIN; | ||
134 | CREATE TEMP TABLE t2(x,y); | ||
135 | SELECT name FROM sqlite_temp_master; | ||
136 | } | ||
137 | } {t2} | ||
138 | do_test interrupt-3.$i.2 { | ||
139 | set ::sqlite_interrupt_count $::i | ||
140 | catchsql { | ||
141 | INSERT INTO t2 SELECT * FROM t1; | ||
142 | } | ||
143 | } {1 interrupted} | ||
144 | do_test interrupt-3.$i.3 { | ||
145 | execsql { | ||
146 | SELECT name FROM sqlite_temp_master; | ||
147 | } | ||
148 | } {} | ||
149 | do_test interrupt-3.$i.4 { | ||
150 | catchsql { | ||
151 | ROLLBACK | ||
152 | } | ||
153 | } {1 {cannot rollback - no transaction is active}} | ||
154 | do_test interrupt-3.$i.5 { | ||
155 | catchsql {SELECT name FROM sqlite_temp_master}; | ||
156 | execsql { | ||
157 | SELECT name FROM sqlite_temp_master; | ||
158 | } | ||
159 | } {} | ||
160 | } | ||
161 | } | ||
162 | |||
163 | # There are reports of a memory leak if an interrupt occurs during | ||
164 | # the beginning of a complex query - before the first callback. We | ||
165 | # will try to reproduce it here: | ||
166 | # | ||
167 | execsql { | ||
168 | CREATE TABLE t2(a,b,c); | ||
169 | INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1; | ||
170 | } | ||
171 | set sql { | ||
172 | SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a; | ||
173 | } | ||
174 | set sqlite_interrupt_count 1000000 | ||
175 | execsql $sql | ||
176 | set max_count [expr {1000000-$sqlite_interrupt_count}] | ||
177 | for {set i 1} {$i<$max_count-5} {incr i 1} { | ||
178 | do_test interrupt-4.$i.1 { | ||
179 | set ::sqlite_interrupt_count $::i | ||
180 | catchsql $sql | ||
181 | } {1 interrupted} | ||
182 | } | ||
183 | |||
184 | # Interrupt during parsing | ||
185 | # | ||
186 | do_test interrupt-5.1 { | ||
187 | proc fake_interrupt {args} { | ||
188 | db collate fake_collation no-op | ||
189 | sqlite3_interrupt db | ||
190 | return SQLITE_OK | ||
191 | } | ||
192 | db collation_needed fake_interrupt | ||
193 | catchsql { | ||
194 | CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC); | ||
195 | } | ||
196 | } {1 interrupt} | ||
197 | |||
198 | finish_test | ||