1#
2# 2001 September 15
3#
4# The author disclaims copyright to this source code.  In place of
5# a legal notice, here is a blessing:
6#
7#    May you do good and not evil.
8#    May you find forgiveness for yourself and forgive others.
9#    May you share freely, never taking more than you give.
10#
11#***********************************************************************
12# This file implements regression tests for SQLite library.  The
13# focus of this script is in-memory database backend.
14#
15# $Id: memdb.test,v 1.6 2003/08/05 13:13:39 drh Exp $
16
17
18set testdir [file dirname $argv0]
19source $testdir/tester.tcl
20
21# In the following sequence of tests, compute the MD5 sum of the content
22# of a table, make lots of modifications to that table, then do a rollback.
23# Verify that after the rollback, the MD5 checksum is unchanged.
24#
25# These tests were browed from trans.tcl.
26#
27do_test memdb-1.1 {
28  db close
29  sqlite db :memory:
30  # sqlite db test.db
31  execsql {
32    BEGIN;
33    CREATE TABLE t3(x TEXT);
34    INSERT INTO t3 VALUES(randstr(10,400));
35    INSERT INTO t3 VALUES(randstr(10,400));
36    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
37    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
38    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
39    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
40    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
41    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
42    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
43    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
44    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
45    COMMIT;
46    SELECT count(*) FROM t3;
47  }
48} {1024}
49
50# The following procedure computes a "signature" for table "t3".  If
51# T3 changes in any way, the signature should change.
52#
53# This is used to test ROLLBACK.  We gather a signature for t3, then
54# make lots of changes to t3, then rollback and take another signature.
55# The two signatures should be the same.
56#
57proc signature {{fn {}}} {
58  set rx [db eval {SELECT x FROM t3}]
59  # set r1 [md5 $rx\n]
60  if {$fn!=""} {
61    # set fd [open $fn w]
62    # puts $fd $rx
63    # close $fd
64  }
65  # set r [db eval {SELECT count(*), md5sum(x) FROM t3}]
66  # puts "SIG($fn)=$r1"
67  return [list [string length $rx] $rx]
68}
69
70# Do rollbacks.  Make sure the signature does not change.
71#
72set limit 10
73for {set i 2} {$i<=$limit} {incr i} {
74  set ::sig [signature one]
75  # puts "sig=$sig"
76  set cnt [lindex $::sig 0]
77  set ::journal_format [expr {($i%3)+1}]
78  if {$i%2==0} {
79    execsql {PRAGMA synchronous=FULL}
80  } else {
81    execsql {PRAGMA synchronous=NORMAL}
82  }
83  do_test memdb-1.$i.1-$cnt {
84     execsql {
85       BEGIN;
86       DELETE FROM t3 WHERE random()%10!=0;
87       INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
88       INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
89       ROLLBACK;
90     }
91     set sig2 [signature two]
92  } $sig
93  # puts "sig2=$sig2"
94  # if {$sig2!=$sig} exit
95  do_test memdb-1.$i.2-$cnt {
96     execsql {
97       BEGIN;
98       DELETE FROM t3 WHERE random()%10!=0;
99       INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
100       DELETE FROM t3 WHERE random()%10!=0;
101       INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
102       ROLLBACK;
103     }
104     signature
105  } $sig
106  if {$i<$limit} {
107    do_test memdb-1.$i.9-$cnt {
108       execsql {
109         INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0;
110       }
111    } {}
112  }
113  set ::pager_old_format 0
114}
115
116do_test memdb-2.1 {
117  execsql {
118    PRAGMA integrity_check
119  }
120} {ok}
121
122do_test memdb-3.1 {
123  execsql {
124    CREATE TABLE t4(a,b,c,d);
125    BEGIN;
126    INSERT INTO t4 VALUES(1,2,3,4);
127    SELECT * FROM t4;
128  }
129} {1 2 3 4}
130do_test memdb-3.2 {
131  execsql {
132    SELECT name FROM sqlite_master WHERE type='table';
133  }
134} {t3 t4}
135do_test memdb-3.3 {
136  execsql {
137    DROP TABLE t4;
138    SELECT name FROM sqlite_master WHERE type='table';
139  }
140} {t3}
141do_test memdb-3.4 {
142  execsql {
143    ROLLBACK;
144    SELECT name FROM sqlite_master WHERE type='table';
145  }
146} {t3 t4}
147
148# Create tables for the first group of tests.
149#
150do_test memdb-4.0 {
151  execsql {
152    CREATE TABLE t1(a, b, c, UNIQUE(a,b));
153    CREATE TABLE t2(x);
154    SELECT c FROM t1 ORDER BY c;
155  }
156} {}
157
158# Six columns of configuration data as follows:
159#
160#   i      The reference number of the test
161#   conf   The conflict resolution algorithm on the BEGIN statement
162#   cmd    An INSERT or REPLACE command to execute against table t1
163#   t0     True if there is an error from $cmd
164#   t1     Content of "c" column of t1 assuming no error in $cmd
165#   t2     Content of "x" column of t2
166#
167foreach {i conf cmd t0 t1 t2} {
168  1 {}       INSERT                  1 {}  1
169  2 {}       {INSERT OR IGNORE}      0 3   1
170  3 {}       {INSERT OR REPLACE}     0 4   1
171  4 {}       REPLACE                 0 4   1
172  5 {}       {INSERT OR FAIL}        1 {}  1
173  6 {}       {INSERT OR ABORT}       1 {}  1
174  7 {}       {INSERT OR ROLLBACK}    1 {}  {}
175  8 IGNORE   INSERT                  0 3   1
176  9 IGNORE   {INSERT OR IGNORE}      0 3   1
177 10 IGNORE   {INSERT OR REPLACE}     0 4   1
178 11 IGNORE   REPLACE                 0 4   1
179 12 IGNORE   {INSERT OR FAIL}        1 {}  1
180 13 IGNORE   {INSERT OR ABORT}       1 {}  1
181 14 IGNORE   {INSERT OR ROLLBACK}    1 {}  {}
182 15 REPLACE  INSERT                  0 4   1
183 16 FAIL     INSERT                  1 {}  1
184 17 ABORT    INSERT                  1 {}  1
185 18 ROLLBACK INSERT                  1 {}  {}
186} {
187  do_test memdb-4.$i {
188    if {$conf!=""} {set conf "ON CONFLICT $conf"}
189    set r0 [catch {execsql [subst {
190      DELETE FROM t1;
191      DELETE FROM t2;
192      INSERT INTO t1 VALUES(1,2,3);
193      BEGIN $conf;
194      INSERT INTO t2 VALUES(1);
195      $cmd INTO t1 VALUES(1,2,4);
196    }]} r1]
197    catch {execsql {COMMIT}}
198    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
199    set r2 [execsql {SELECT x FROM t2}]
200    list $r0 $r1 $r2
201  } [list $t0 $t1 $t2]
202}
203
204do_test memdb-5.0 {
205  execsql {
206    DROP TABLE t2;
207    DROP TABLE t3;
208    CREATE TABLE t2(a,b,c);
209    INSERT INTO t2 VALUES(1,2,1);
210    INSERT INTO t2 VALUES(2,3,2);
211    INSERT INTO t2 VALUES(3,4,1);
212    INSERT INTO t2 VALUES(4,5,4);
213    SELECT c FROM t2 ORDER BY b;
214    CREATE TABLE t3(x);
215    INSERT INTO t3 VALUES(1);
216  }
217} {1 2 1 4}
218
219# Six columns of configuration data as follows:
220#
221#   i      The reference number of the test
222#   conf1  The conflict resolution algorithm on the UNIQUE constraint
223#   conf2  The conflict resolution algorithm on the BEGIN statement
224#   cmd    An UPDATE command to execute against table t1
225#   t0     True if there is an error from $cmd
226#   t1     Content of "b" column of t1 assuming no error in $cmd
227#   t2     Content of "x" column of t3
228#
229foreach {i conf1 conf2 cmd t0 t1 t2} {
230  1 {}       {}       UPDATE                  1 {6 7 8 9}  1
231  2 REPLACE  {}       UPDATE                  0 {7 6 9}    1
232  3 IGNORE   {}       UPDATE                  0 {6 7 3 9}  1
233  4 FAIL     {}       UPDATE                  1 {6 7 3 4}  1
234  5 ABORT    {}       UPDATE                  1 {1 2 3 4}  1
235  6 ROLLBACK {}       UPDATE                  1 {1 2 3 4}  0
236  7 REPLACE  {}       {UPDATE OR IGNORE}      0 {6 7 3 9}  1
237  8 IGNORE   {}       {UPDATE OR REPLACE}     0 {7 6 9}    1
238  9 FAIL     {}       {UPDATE OR IGNORE}      0 {6 7 3 9}  1
239 10 ABORT    {}       {UPDATE OR REPLACE}     0 {7 6 9}    1
240 11 ROLLBACK {}       {UPDATE OR IGNORE}      0 {6 7 3 9}   1
241 12 {}       {}       {UPDATE OR IGNORE}      0 {6 7 3 9}  1
242 13 {}       {}       {UPDATE OR REPLACE}     0 {7 6 9}    1
243 14 {}       {}       {UPDATE OR FAIL}        1 {6 7 3 4}  1
244 15 {}       {}       {UPDATE OR ABORT}       1 {1 2 3 4}  1
245 16 {}       {}       {UPDATE OR ROLLBACK}    1 {1 2 3 4}  0
246 17 {}       IGNORE   UPDATE                  0 {6 7 3 9}  1
247 18 {}       REPLACE  UPDATE                  0 {7 6 9}    1
248 19 {}       FAIL     UPDATE                  1 {6 7 3 4}  1
249 20 {}       ABORT    UPDATE                  1 {1 2 3 4}  1
250 21 {}       ROLLBACK UPDATE                  1 {1 2 3 4}  0
251 22 REPLACE  IGNORE   UPDATE                  0 {6 7 3 9}  1
252 23 IGNORE   REPLACE  UPDATE                  0 {7 6 9}    1
253 24 REPLACE  FAIL     UPDATE                  1 {6 7 3 4}  1
254 25 IGNORE   ABORT    UPDATE                  1 {1 2 3 4}  1
255 26 REPLACE  ROLLBACK UPDATE                  1 {1 2 3 4}  0
256} {
257  if {$t0} {set t1 {column a is not unique}}
258  do_test memdb-5.$i {
259    if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
260    if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"}
261    set r0 [catch {execsql [subst {
262      DROP TABLE t1;
263      CREATE TABLE t1(a,b,c, UNIQUE(a) $conf1);
264      INSERT INTO t1 SELECT * FROM t2;
265      UPDATE t3 SET x=0;
266      BEGIN $conf2;
267      $cmd t3 SET x=1;
268      $cmd t1 SET b=b*2;
269      $cmd t1 SET a=c+5;
270    }]} r1]
271    catch {execsql {COMMIT}}
272    if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]}
273    set r2 [execsql {SELECT x FROM t3}]
274    list $r0 $r1 $r2
275  } [list $t0 $t1 $t2]
276}
277
278do_test memdb-6.1 {
279  execsql {
280    SELECT * FROM t2;
281  }
282} {1 2 1 2 3 2 3 4 1 4 5 4}
283do_test memdb-6.2 {
284  execsql {
285    BEGIN;
286    DROP TABLE t2;
287    SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1;
288  }
289} {t1 t3 t4}
290do_test memdb-6.3 {
291  execsql {
292    ROLLBACK;
293    SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1;
294  }
295} {t1 t2 t3 t4}
296do_test memdb-6.4 {
297  execsql {
298    SELECT * FROM t2;
299  }
300} {1 2 1 2 3 2 3 4 1 4 5 4}
301do_test memdb-6.5 {
302  execsql {
303    SELECT a FROM t2 UNION SELECT b FROM t2 ORDER BY 1;
304  }
305} {1 2 3 4 5}
306do_test memdb-6.6 {
307  execsql {
308    CREATE INDEX i2 ON t2(c);
309    SELECT a FROM t2 ORDER BY c;
310  }
311} {1 3 2 4}
312do_test memdb-6.6 {
313  execsql {
314    SELECT a FROM t2 ORDER BY c DESC;
315  }
316} {4 2 3 1}
317do_test memdb-6.7 {
318  execsql {
319    BEGIN;
320    CREATE TABLE t5(x,y);
321    INSERT INTO t5 VALUES(1,2);
322    SELECT * FROM t5;
323  }
324} {1 2}
325do_test memdb-6.8 {
326  execsql {
327    SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1;
328  }
329} {t1 t2 t3 t4 t5}
330do_test memdb-6.9 {
331  execsql {
332    ROLLBACK;
333    SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1;
334  }
335} {t1 t2 t3 t4}
336do_test memdb-6.10 {
337  execsql {
338    CREATE TABLE t5(x PRIMARY KEY, y UNIQUE);
339    SELECT * FROM t5;
340  }
341} {}
342do_test memdb-6.11 {
343  execsql {
344    SELECT * FROM t5 ORDER BY y DESC;
345  }
346} {}
347do_test memdb-6.12 {
348  execsql {
349    INSERT INTO t5 VALUES(1,2);
350    INSERT INTO t5 VALUES(3,4);
351    REPLACE INTO t5 VALUES(1,4);
352    SELECT rowid,* FROM t5;
353  }
354} {3 1 4}
355do_test memdb-6.13 {
356  execsql {
357    DELETE FROM t5 WHERE x>5;
358    SELECT * FROM t5;
359  }
360} {1 4}
361do_test memdb-6.14 {
362  execsql {
363    DELETE FROM t5 WHERE y<3;
364    SELECT * FROM t5;
365  }
366} {1 4}
367do_test memdb-6.15 {
368  execsql {
369    DELETE FROM t5 WHERE x>0;
370    SELECT * FROM t5;
371  }
372} {}
373
374do_test memdb-7.1 {
375  execsql {
376    CREATE TABLE t6(x);
377    INSERT INTO t6 VALUES(1);
378    INSERT INTO t6 SELECT x+1 FROM t6;
379    INSERT INTO t6 SELECT x+2 FROM t6;
380    INSERT INTO t6 SELECT x+4 FROM t6;
381    INSERT INTO t6 SELECT x+8 FROM t6;
382    INSERT INTO t6 SELECT x+16 FROM t6;
383    INSERT INTO t6 SELECT x+32 FROM t6;
384    INSERT INTO t6 SELECT x+64 FROM t6;
385    INSERT INTO t6 SELECT x+128 FROM t6;
386    SELECT count(*) FROM (SELECT DISTINCT x FROM t6);
387  }
388} {256}
389for {set i 1} {$i<=256} {incr i} {
390  do_test memdb-7.2.$i {
391     execsql "DELETE FROM t6 WHERE x=\
392              (SELECT x FROM t6 ORDER BY random() LIMIT 1)"
393     execsql {SELECT count(*) FROM t6}
394  } [expr {256-$i}]
395}
396
397finish_test
398