xref: /sqlite-3.40.0/ext/session/session5.test (revision f1a08ad8)
1# 2011 April 13
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 the session module.
12# Specifically, for the sqlite3changeset_concat() command.
13#
14
15if {![info exists testdir]} {
16  set testdir [file join [file dirname [info script]] .. .. test]
17}
18source [file join [file dirname [info script]] session_common.tcl]
19source $testdir/tester.tcl
20ifcapable !session {finish_test; return}
21
22set testprefix session5
23
24# Organization of tests:
25#
26#   session5-1.*: Simple tests to check the concat() function produces
27#                 correct results.
28#
29#   session5-2.*: More complicated tests.
30#
31#   session5-3.*: Schema mismatch errors.
32#
33#   session5-4.*: Test the concat cases that indicate that the database
34#                 was modified in between recording of the two changesets
35#                 being concatenated (i.e. two changesets that INSERT rows
36#                 with the same PK values).
37#
38
39proc do_concat_test {tn args} {
40
41  set subtest 0
42  foreach sql $args {
43    incr subtest
44    sqlite3session S db main ; S attach *
45    execsql $sql
46
47    set c [S changeset]
48    if {[info commands s_prev] != ""} {
49      set c_concat [sqlite3changeset_concat $c_prev $c]
50      set c_two [s_prev changeset]
51      s_prev delete
52
53      set h_concat [changeset_to_list $c_concat]
54      set h_two [changeset_to_list $c_two]
55
56      do_test $tn.$subtest [list set {} $h_concat] $h_two
57    }
58    set c_prev $c
59    rename S s_prev
60  }
61
62  catch { s_prev delete }
63}
64
65#-------------------------------------------------------------------------
66# Test cases session5-1.* - simple tests.
67#
68do_execsql_test 1.0 {
69  CREATE TABLE t1(a PRIMARY KEY, b);
70}
71
72do_concat_test 1.1.1 {
73  INSERT INTO t1 VALUES(1, 'one');
74} {
75  INSERT INTO t1 VALUES(2, 'two');
76}
77
78do_concat_test 1.1.2 {
79  UPDATE t1 SET b = 'five' WHERE a = 1;
80} {
81  UPDATE t1 SET b = 'six' WHERE a = 2;
82}
83
84do_concat_test 1.1.3 {
85  DELETE FROM t1 WHERE a = 1;
86} {
87  DELETE FROM t1 WHERE a = 2;
88}
89
90
91# 1.2.1:    INSERT + DELETE                     -> (none)
92# 1.2.2:    INSERT + UPDATE                     -> INSERT
93#
94# 1.2.3:    DELETE + INSERT (matching data)     -> (none)
95# 1.2.4:    DELETE + INSERT (non-matching data) -> UPDATE
96#
97# 1.2.5:    UPDATE + UPDATE (matching data)     -> (none)
98# 1.2.6:    UPDATE + UPDATE (non-matching data) -> UPDATE
99# 1.2.7:    UPDATE + DELETE                     -> DELETE
100#
101do_concat_test 1.2.1 {
102  INSERT INTO t1 VALUES('x', 'y');
103} {
104  DELETE FROM t1 WHERE a = 'x';
105}
106do_concat_test 1.2.2 {
107  INSERT INTO t1 VALUES(5.0, 'five');
108} {
109  UPDATE t1 SET b = 'six' WHERE a = 5.0;
110}
111
112do_execsql_test 1.2.3.1 "INSERT INTO t1 VALUES('I', 'one')"
113do_concat_test 1.2.3.2 {
114  DELETE FROM t1 WHERE a = 'I';
115} {
116  INSERT INTO t1 VALUES('I', 'one');
117}
118do_concat_test 1.2.4 {
119  DELETE FROM t1 WHERE a = 'I';
120} {
121  INSERT INTO t1 VALUES('I', 'two');
122}
123do_concat_test 1.2.5 {
124  UPDATE t1 SET b = 'five' WHERE a = 'I';
125} {
126  UPDATE t1 SET b = 'two' WHERE a = 'I';
127}
128do_concat_test 1.2.6 {
129  UPDATE t1 SET b = 'six' WHERE a = 'I';
130} {
131  UPDATE t1 SET b = 'seven' WHERE a = 'I';
132}
133do_concat_test 1.2.7 {
134  UPDATE t1 SET b = 'eight' WHERE a = 'I';
135} {
136  DELETE FROM t1 WHERE a = 'I';
137}
138
139
140#-------------------------------------------------------------------------
141# Test cases session5-2.* - more complex tests.
142#
143db function indirect indirect
144proc indirect {{x -1}} {
145  S indirect $x
146  s_prev indirect $x
147}
148do_concat_test 2.1 {
149  CREATE TABLE abc(a, b, c PRIMARY KEY);
150  INSERT INTO abc VALUES(NULL, NULL, 1);
151  INSERT INTO abc VALUES('abcdefghijkl', NULL, 2);
152} {
153  DELETE FROM abc WHERE c = 1;
154  UPDATE abc SET c = 1 WHERE c = 2;
155} {
156  INSERT INTO abc VALUES('abcdefghijkl', NULL, 2);
157  INSERT INTO abc VALUES(1.0, 2.0, 3);
158} {
159  UPDATE abc SET a = a-1;
160} {
161  CREATE TABLE def(d, e, f, PRIMARY KEY(e, f));
162  INSERT INTO def VALUES('x', randomblob(11000), 67);
163  INSERT INTO def SELECT d, e, f+1 FROM def;
164  INSERT INTO def SELECT d, e, f+2 FROM def;
165  INSERT INTO def SELECT d, e, f+4 FROM def;
166} {
167  DELETE FROM def WHERE rowid>4;
168} {
169  INSERT INTO def SELECT d, e, f+4 FROM def;
170} {
171  INSERT INTO abc VALUES(22, 44, -1);
172} {
173  UPDATE abc SET c=-2 WHERE c=-1;
174  UPDATE abc SET c=-3 WHERE c=-2;
175} {
176  UPDATE abc SET c=-4 WHERE c=-3;
177} {
178  UPDATE abc SET a=a+1 WHERE c=-3;
179  UPDATE abc SET a=a+1 WHERE c=-3;
180} {
181  UPDATE abc SET a=a+1 WHERE c=-3;
182  UPDATE abc SET a=a+1 WHERE c=-3;
183} {
184  INSERT INTO abc VALUES('one', 'two', 'three');
185} {
186  SELECT indirect(1);
187  UPDATE abc SET a='one point five' WHERE c = 'three';
188} {
189  SELECT indirect(0);
190  UPDATE abc SET a='one point six' WHERE c = 'three';
191} {
192  CREATE TABLE x1(a, b, PRIMARY KEY(a));
193  SELECT indirect(1);
194  INSERT INTO x1 VALUES(1, 2);
195} {
196  SELECT indirect(1);
197  UPDATE x1 SET b = 3 WHERE a = 1;
198}
199
200catch {db close}
201forcedelete test.db
202sqlite3 db test.db
203do_concat_test 2.2 {
204  CREATE TABLE t1(a, b, PRIMARY KEY(b));
205  CREATE TABLE t2(a PRIMARY KEY, b);
206  INSERT INTO t1 VALUES('string', 1);
207  INSERT INTO t1 VALUES(4, 2);
208  INSERT INTO t1 VALUES(X'FFAAFFAAFFAA', 3);
209} {
210  INSERT INTO t2 VALUES('one', 'two');
211  INSERT INTO t2 VALUES(1, NULL);
212  UPDATE t1 SET a = 5 WHERE a = 2;
213} {
214  DELETE FROM t2 WHERE a = 1;
215  UPDATE t1 SET a = 4 WHERE a = 2;
216  INSERT INTO t2 VALUES('x', 'y');
217}
218
219do_test 2.3.0 {
220  catch {db close}
221  forcedelete test.db
222  sqlite3 db test.db
223
224  set sql1 ""
225  set sql2 ""
226  for {set i 1} {$i < 120} {incr i} {
227    append sql1 "INSERT INTO x1 VALUES($i*4, $i);"
228  }
229  for {set i 1} {$i < 120} {incr i} {
230    append sql2 "DELETE FROM x1 WHERE a = $i*4;"
231  }
232  set {} {}
233} {}
234do_concat_test 2.3 {
235  CREATE TABLE x1(a PRIMARY KEY, b)
236} $sql1 $sql2 $sql1 $sql2
237
238do_concat_test 2.4 {
239  CREATE TABLE x2(a PRIMARY KEY, b);
240  CREATE TABLE x3(a PRIMARY KEY, b);
241
242  INSERT INTO x2 VALUES('a', 'b');
243  INSERT INTO x2 VALUES('x', 'y');
244  INSERT INTO x3 VALUES('a', 'b');
245} {
246  INSERT INTO x2 VALUES('c', 'd');
247  INSERT INTO x3 VALUES('e', 'f');
248  INSERT INTO x3 VALUES('x', 'y');
249}
250
251do_concat_test 2.5 {
252  UPDATE x3 SET b = 'Y' WHERE a = 'x'
253} {
254  DELETE FROM x3 WHERE a = 'x'
255} {
256  DELETE FROM x2 WHERE a = 'a'
257} {
258  INSERT INTO x2 VALUES('a', 'B');
259}
260
261for {set k 1} {$k <=10} {incr k} {
262  do_test 2.6.$k.1 {
263    drop_all_tables
264    set sql1 ""
265    set sql2 ""
266    for {set i 1} {$i < 120} {incr i} {
267      append sql1 "INSERT INTO x1 VALUES(randomblob(20+(random()%10)), $i);"
268    }
269    for {set i 1} {$i < 120} {incr i} {
270      append sql2 "DELETE FROM x1 WHERE rowid = $i;"
271    }
272    set {} {}
273  } {}
274  do_concat_test 2.6.$k {
275    CREATE TABLE x1(a PRIMARY KEY, b)
276  } $sql1 $sql2 $sql1 $sql2
277}
278
279for {set k 1} {$k <=10} {incr k} {
280  do_test 2.7.$k.1 {
281    drop_all_tables
282    set sql1 ""
283    set sql2 ""
284    for {set i 1} {$i < 120} {incr i} {
285      append sql1 {
286        INSERT INTO x1 VALUES(
287         CASE WHEN random()%2 THEN random() ELSE randomblob(20+random()%10) END,
288         CASE WHEN random()%2 THEN random() ELSE randomblob(20+random()%10) END
289        );
290      }
291    }
292    for {set i 1} {$i < 120} {incr i} {
293      append sql2 "DELETE FROM x1 WHERE rowid = $i;"
294    }
295    set {} {}
296  } {}
297  do_concat_test 2.7.$k {
298    CREATE TABLE x1(a PRIMARY KEY, b)
299  } $sql1 $sql2 $sql1 $sql2
300}
301
302
303#-------------------------------------------------------------------------
304# Test that schema incompatibilities are detected correctly.
305#
306#   session5-3.1: Incompatible number of columns.
307#   session5-3.2: Incompatible PK definition.
308#
309
310do_test 3.1 {
311  db close
312  forcedelete test.db
313  sqlite3 db test.db
314
315  execsql { CREATE TABLE t1(a PRIMARY KEY, b) }
316  set c1 [changeset_from_sql { INSERT INTO t1 VALUES(1, 2) }]
317  execsql {
318    DROP TABLE t1;
319    CREATE TABLE t1(a PRIMARY KEY, b, c);
320  }
321  set c2 [changeset_from_sql { INSERT INTO t1 VALUES(2, 3, 4) }]
322
323  list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg
324} {1 SQLITE_SCHEMA}
325
326do_test 3.2 {
327  db close
328  forcedelete test.db
329  sqlite3 db test.db
330
331  execsql { CREATE TABLE t1(a PRIMARY KEY, b) }
332  set c1 [changeset_from_sql { INSERT INTO t1 VALUES(1, 2) }]
333  execsql {
334    DROP TABLE t1;
335    CREATE TABLE t1(a, b PRIMARY KEY);
336  }
337  set c2 [changeset_from_sql { INSERT INTO t1 VALUES(2, 3) }]
338
339  list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg
340} {1 SQLITE_SCHEMA}
341
342#-------------------------------------------------------------------------
343# Test that concat() handles these properly:
344#
345#   session5-4.1: INSERT + INSERT
346#   session5-4.2: UPDATE + INSERT
347#   session5-4.3: DELETE + UPDATE
348#   session5-4.4: DELETE + DELETE
349#
350
351proc do_concat_test2 {tn sql1 sqlX sql2 expected} {
352  sqlite3session S db main ; S attach *
353  execsql $sql1
354  set ::c1 [S changeset]
355  S delete
356
357  execsql $sqlX
358
359  sqlite3session S db main ; S attach *
360  execsql $sql2
361  set ::c2 [S changeset]
362  S delete
363
364  uplevel do_test $tn [list {
365    changeset_to_list [sqlite3changeset_concat $::c1 $::c2]
366  }] [list [normalize_list $expected]]
367}
368
369drop_all_tables db
370do_concat_test2 4.1 {
371  CREATE TABLE t1(a PRIMARY KEY, b);
372  INSERT INTO t1 VALUES('key', 'value');
373} {
374  DELETE FROM t1 WHERE a = 'key';
375} {
376  INSERT INTO t1 VALUES('key', 'xxx');
377} {
378  {INSERT t1 0 X. {} {t key t value}}
379}
380do_concat_test2 4.2 {
381  UPDATE t1 SET b = 'yyy';
382} {
383  DELETE FROM t1 WHERE a = 'key';
384} {
385  INSERT INTO t1 VALUES('key', 'value');
386} {
387  {UPDATE t1 0 X. {t key t xxx} {{} {} t yyy}}
388}
389do_concat_test2 4.3 {
390  DELETE FROM t1 WHERE a = 'key';
391} {
392  INSERT INTO t1 VALUES('key', 'www');
393} {
394  UPDATE t1 SET b = 'valueX' WHERE a = 'key';
395} {
396  {DELETE t1 0 X. {t key t value} {}}
397}
398do_concat_test2 4.4 {
399  DELETE FROM t1 WHERE a = 'key';
400} {
401  INSERT INTO t1 VALUES('key', 'ttt');
402} {
403  DELETE FROM t1 WHERE a = 'key';
404} {
405  {DELETE t1 0 X. {t key t valueX} {}}
406}
407
408finish_test
409