xref: /onnv-gate/usr/src/lib/libsqlite/test/interrupt.test (revision 4520:7dbeadedd7fe)
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