Fixes default log output to console for macOS
[sqlcipher.git] / ext / session / sessionrebase.test
blob033348f9ce28e3d94edca4fec1937a4d5bafa0fb
1 # 2018 March 14
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library.
14 if {![info exists testdir]} {
15   set testdir [file join [file dirname [info script]] .. .. test]
16
17 source [file join [file dirname [info script]] session_common.tcl]
18 source $testdir/tester.tcl
19 ifcapable !session {finish_test; return}
21 set testprefix sessionrebase
23 set ::lConflict [list]
24 proc xConflict {args} {
25   set res [lindex $::lConflict 0]
26   set ::lConflict [lrange $::lConflict 1 end]
27   return $res
30 #-------------------------------------------------------------------------
31 # The following test cases - 1.* - test that the rebase blobs output by
32 # sqlite3_changeset_apply_v2 look correct in some simple cases. The blob
33 # is itself a changeset, containing records determined as follows:
35 #   * For each conflict resolved with REPLACE, the rebase blob contains
36 #     a DELETE record. All fields other than the PK fields are undefined.
38 #   * For each conflict resolved with OMIT, the rebase blob contains an
39 #     INSERT record. For an INSERT or UPDATE operation, the indirect flag
40 #     is clear and all updated fields are defined. For a DELETE operation,
41 #     the indirect flag is set and all non-PK fields left undefined.
43 proc do_apply_v2_test {tn sql modsql conflict_handler res} {
44   
45   execsql BEGIN
46   sqlite3session S db main
47   S attach *
48   execsql $sql
49   set changeset [S changeset]
50   S delete
51   execsql ROLLBACK
53   execsql BEGIN
54   execsql $modsql
55   set ::lConflict $conflict_handler
56   set blob [sqlite3changeset_apply_v2 db $changeset xConflict]
57   execsql ROLLBACK
59   uplevel [list do_test $tn [list changeset_to_list $blob] [list {*}$res]]
63 set ::lConflict [list]
64 proc xConflict {args} {
65   set res [lindex $::lConflict 0]
66   set ::lConflict [lrange $::lConflict 1 end]
67   return $res
70 # Take a copy of database test.db in file test.db2. Execute $sql1
71 # against test.db and $sql2 against test.db2. Capture a changeset
72 # for each. Then send the test.db2 changeset to test.db and apply
73 # it with the conflict handlers in $conflict_handler. Patch the
74 # test.db changeset and then execute it against test.db2. Test that
75 # the two databases come out the same.
77 proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
79   for {set i 1} {$i <= 2} {incr i} {
80     forcedelete test.db2 test.db2-journal test.db2-wal
81     forcecopy test.db test.db2
82     sqlite3 db2 test.db2
84     db eval BEGIN
86     sqlite3session S1 db main
87     S1 object_config rowid 1
88     S1 attach *
89     execsql $sql1 db
90     set c1 [S1 changeset]
91     S1 delete
93     if {$i==1} {
94       sqlite3session S2 db2 main
95       S2 object_config rowid 1
96       S2 attach *
97       execsql $sql2 db2
98       set c2 [S2 changeset]
99       S2 delete
100     } else {
101       set c2 [list]
102       foreach sql [split $sql2 ";"] {
103         if {[string is space $sql]} continue
104         sqlite3session S2 db2 main
105         S2 object_config rowid 1
106         S2 attach *
107         execsql $sql db2
108         lappend c2 [S2 changeset]
109         S2 delete
110       }
111     }
113     set ::lConflict $conflict_handler
114     set rebase [list]
115     if {$i==1} {
116       lappend rebase [sqlite3changeset_apply_v2 db $c2 xConflict]
117     } else {
118       foreach c $c2 {
119 #puts "apply_v2: [changeset_to_list $c]"
120         lappend rebase [sqlite3changeset_apply_v2 db $c xConflict]
121       }
122       #puts "llength: [llength $rebase]"
123     }
124     #if {$tn=="2.1.4"} { puts [changeset_to_list $rebase] ; breakpoint }
125     #puts [changeset_to_list [lindex $rebase 0]] ; breakpoint
126     #puts [llength $rebase]
127   
128     sqlite3rebaser_create R
129     foreach r $rebase {
130 #puts [changeset_to_list $r]
131       R configure $r
132     }
133     set c1r [R rebase $c1]
134     R delete
135     #if {$tn=="2.1.4"} { puts [changeset_to_list $c1r] }
136   
137     sqlite3changeset_apply_v2 db2 $c1r xConflictAbort
138   
139     if {[string range $tn end end]!="*"} {
140       uplevel [list do_test $tn.$i.1 [list compare_db db db2] {}]
141     }
142     db2 close
143   
144     if {$testsql!=""} {
145       uplevel [list do_execsql_test $tn.$i.2 $testsql $testres]
146     }
147   
148     db eval ROLLBACK
149   }
152 do_execsql_test 1.0 {
153   CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
154   INSERT INTO t1 VALUES(1, 'value A');
157 do_apply_v2_test 1.1.1 {
158   UPDATE t1 SET b = 'value B' WHERE a=1;
159 } {
160   UPDATE t1 SET b = 'value C' WHERE a=1;
161 } {
162   OMIT
163 } {
164   {INSERT t1 0 X. {} {i 1 t {value B}}}
167 do_apply_v2_test 1.1.2 {
168   UPDATE t1 SET b = 'value B' WHERE a=1;
169 } {
170   UPDATE t1 SET b = 'value C' WHERE a=1;
171 } {
172   REPLACE
173 } {
174   {INSERT t1 1 X. {} {i 1 t {value B}}}
177 do_apply_v2_test 1.2.1 {
178   INSERT INTO t1 VALUES(2, 'first');
179 } {
180   INSERT INTO t1 VALUES(2, 'second');
181 } {
182   OMIT
183 } {
184   {INSERT t1 0 X. {} {i 2 t first}}
186 do_apply_v2_test 1.2.2 {
187   INSERT INTO t1 VALUES(2, 'first');
188 } {
189   INSERT INTO t1 VALUES(2, 'second');
190 } {
191   REPLACE
192 } {
193   {INSERT t1 1 X. {} {i 2 t first}}
196 do_apply_v2_test 1.3.1 {
197   DELETE FROM t1 WHERE a=1;
198 } {
199   UPDATE t1 SET b='value D' WHERE a=1;
200 } {
201   OMIT
202 } {
203   {DELETE t1 0 X. {i 1 t {value A}} {}}
205 do_apply_v2_test 1.3.2 {
206   DELETE FROM t1 WHERE a=1;
207 } {
208   UPDATE t1 SET b='value D' WHERE a=1;
209 } {
210   REPLACE
211 } {
212   {DELETE t1 1 X. {i 1 t {value A}} {}}
215 #-------------------------------------------------------------------------
216 # Test cases 2.* - simple tests of rebasing actual changesets.
218 #    2.1.1 - 1u2u1r
219 #    2.1.2 - 1u2u2r
220 #    2.1.3 - 1d2d
221 #    2.1.4 - 1d2u1r
222 #    2.1.5 - 1d2u2r !!
223 #    2.1.6 - 1u2d1r
224 #    2.1.7 - 1u2d2r
226 #    2.1.8 - 1i2i2r
227 #    2.1.9 - 1i2i1r
230 proc xConflictAbort {args} {
231   return "ABORT"
234 reset_db
235 do_execsql_test 2.1.0 {
236   CREATE TABLE t1 (a INTEGER PRIMARY KEY, b TEXT);
237   INSERT INTO t1 VALUES(1, 'one');
238   INSERT INTO t1 VALUES(2, 'two');
239   INSERT INTO t1 VALUES(3, 'three');
241 do_rebase_test 2.1.1 {
242   UPDATE t1 SET b = 'two.1' WHERE a=2
243 } {
244   UPDATE t1 SET b = 'two.2' WHERE a=2;
245 } {
246   OMIT
247 } { SELECT * FROM t1 } {1 one 2 two.1 3 three}
249 do_rebase_test 2.1.2 {
250   UPDATE t1 SET b = 'two.1' WHERE a=2
251 } {
252   UPDATE t1 SET b = 'two.2' WHERE a=2;
253 } {
254   REPLACE
255 } { SELECT * FROM t1 } {1 one 2 two.2 3 three}
257 do_rebase_test 2.1.3 {
258   DELETE FROM t1 WHERE a=3
259 } {
260   DELETE FROM t1 WHERE a=3;
261 } {
262   OMIT
263 } { SELECT * FROM t1 } {1 one 2 two}
265 do_rebase_test 2.1.4 {
266   DELETE FROM t1 WHERE a=1
267 } {
268   UPDATE t1 SET b='one.2' WHERE a=1
269 } {
270   OMIT
271 } { SELECT * FROM t1 } {2 two 3 three}
273 #do_rebase_test 2.1.5 {
274 #  DELETE FROM t1 WHERE a=1;
275 #} {
276 #  UPDATE t1 SET b='one.2' WHERE a=1
277 #} {
278 #  REPLACE
279 #} { SELECT * FROM t1 } {2 two 3 three}
281 do_rebase_test 2.1.6 {
282   UPDATE t1 SET b='three.1' WHERE a=3
283 } {
284   DELETE FROM t1 WHERE a=3;
285 } {
286   OMIT
287 } { SELECT * FROM t1 } {1 one 2 two 3 three.1}
289 do_rebase_test 2.1.7 {
290   UPDATE t1 SET b='three.1' WHERE a=3
291 } {
292   DELETE FROM t1 WHERE a=3;
293 } {
294   REPLACE
295 } { SELECT * FROM t1 } {1 one 2 two}
297 do_rebase_test 2.1.8 {
298   INSERT INTO t1 VALUES(4, 'four.1')
299 } {
300   INSERT INTO t1 VALUES(4, 'four.2');
301 } {
302   REPLACE
303 } { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.2}
305 do_rebase_test 2.1.9 {
306   INSERT INTO t1 VALUES(4, 'four.1')
307 } {
308   INSERT INTO t1 VALUES(4, 'four.2');
309 } {
310   OMIT
311 } { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.1}
313 do_execsql_test 2.2.0 {
314   CREATE TABLE t2(x, y, z PRIMARY KEY);
315   INSERT INTO t2 VALUES('i', 'a', 'A');
316   INSERT INTO t2 VALUES('ii', 'b', 'B');
317   INSERT INTO t2 VALUES('iii', 'c', 'C');
319   CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
320   INSERT INTO t3 VALUES(-1, 'z', 'Z');
321   INSERT INTO t3 VALUES(-2, 'y', 'Y');
324 do_rebase_test 2.2.1 {
325   UPDATE t2 SET x=1 WHERE z='A'
326 } {
327   UPDATE t2 SET y='one' WHERE z='A';
328 } {
329 } { SELECT * FROM t2 WHERE z='A' } { 1 one A }
331 do_rebase_test 2.2.2 {
332   UPDATE t2 SET x=1, y='one' WHERE z='B'
333 } {
334   UPDATE t2 SET y='two' WHERE z='B';
335 } {
336   REPLACE
337 } { SELECT * FROM t2 WHERE z='B' } { 1 two B }
339 do_rebase_test 2.2.3 {
340   UPDATE t2 SET x=1, y='one' WHERE z='B'
341 } {
342   UPDATE t2 SET y='two' WHERE z='B';
343 } {
344   OMIT
345 } { SELECT * FROM t2 WHERE z='B' } { 1 one B }
348 reset_db
349 do_execsql_test 2.3.0 {
350   CREATE TABLE t1 (b TEXT);
351   INSERT INTO t1(rowid, b) VALUES(1, 'one');
352   INSERT INTO t1(rowid, b) VALUES(2, 'two');
353   INSERT INTO t1(rowid, b) VALUES(3, 'three');
355 do_rebase_test 2.3.1 {
356   UPDATE t1 SET b = 'two.1' WHERE rowid=2
357 } {
358   UPDATE t1 SET b = 'two.2' WHERE rowid=2;
359 } {
360   OMIT
361 } { SELECT rowid, * FROM t1 } {1 one 2 two.1 3 three}
363 do_rebase_test 2.3.2 {
364   UPDATE t1 SET b = 'two.1' WHERE rowid=2
365 } {
366   UPDATE t1 SET b = 'two.2' WHERE rowid=2;
367 } {
368   REPLACE
369 } { SELECT rowid, * FROM t1 } {1 one 2 two.2 3 three}
371 do_rebase_test 2.3.3 {
372   DELETE FROM t1 WHERE rowid=3
373 } {
374   DELETE FROM t1 WHERE rowid=3;
375 } {
376   OMIT
377 } { SELECT rowid, * FROM t1 } {1 one 2 two}
379 do_rebase_test 2.3.4 {
380   DELETE FROM t1 WHERE rowid=1
381 } {
382   UPDATE t1 SET b='one.2' WHERE rowid=1
383 } {
384   OMIT
385 } { SELECT rowid, * FROM t1 } {2 two 3 three}
387 do_rebase_test 2.3.6 {
388   UPDATE t1 SET b='three.1' WHERE rowid=3
389 } {
390   DELETE FROM t1 WHERE rowid=3;
391 } {
392   OMIT
393 } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three.1}
395 do_rebase_test 2.3.7 {
396   UPDATE t1 SET b='three.1' WHERE rowid=3
397 } {
398   DELETE FROM t1 WHERE rowid=3;
399 } {
400   REPLACE
401 } { SELECT rowid, * FROM t1 } {1 one 2 two}
403 do_rebase_test 2.3.8 {
404   INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
405 } {
406   INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
407 } {
408   REPLACE
409 } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.2}
411 do_rebase_test 2.3.9 {
412   INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
413 } {
414   INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
415 } {
416   OMIT
417 } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.1}
420 #-------------------------------------------------------------------------
421 reset_db
422 do_execsql_test 3.0 {
423   CREATE TABLE t3(a, b, c, PRIMARY KEY(b, c));
424   CREATE TABLE abcdefghijkl(x PRIMARY KEY, y, z);
426   INSERT INTO t3 VALUES(1, 2, 3);
427   INSERT INTO t3 VALUES(4, 2, 5);
428   INSERT INTO t3 VALUES(7, 2, 9);
430   INSERT INTO abcdefghijkl VALUES('a', 'b', 'c');
431   INSERT INTO abcdefghijkl VALUES('d', 'e', 'f');
432   INSERT INTO abcdefghijkl VALUES('g', 'h', 'i');
435 breakpoint
436 #  do_rebase_test 3.6.tn {
437 #    UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d';
438 #  } {
439 #    UPDATE abcdefghijkl SET y=1 WHERE x='d';
440 #    UPDATE abcdefghijkl SET z=1 WHERE x='d';
441 #  } [list REPLACE REPLACE REPLACE]
443 foreach {tn p} {
444     1 OMIT 2 REPLACE
445 } {
446   do_rebase_test 3.1.$tn {
447     INSERT INTO t3 VALUES(1, 1, 1);
448     UPDATE abcdefghijkl SET y=2;
449   } {
450     INSERT INTO t3 VALUES(4, 1, 1);
451     DELETE FROM abcdefghijkl;
452   } [list $p $p $p $p $p $p $p $p]
454   do_rebase_test 3.2.$tn {
455     INSERT INTO abcdefghijkl SELECT * FROM t3;
456     UPDATE t3 SET b=b+1;
457   } {
458     INSERT INTO t3 VALUES(3, 3, 3);
459     INSERT INTO abcdefghijkl SELECT * FROM t3;
460   } [list $p $p $p $p $p $p $p $p]
462   do_rebase_test 3.3.$tn {
463     INSERT INTO abcdefghijkl VALUES(22, 23, 24);
464   } {
465     INSERT INTO abcdefghijkl VALUES(22, 25, 26);
466     UPDATE abcdefghijkl SET y=400 WHERE x=22;
467   } [list $p $p $p $p $p $p $p $p]
469   do_rebase_test 3.4.$tn {
470     INSERT INTO abcdefghijkl VALUES(22, 23, 24);
471   } {
472     INSERT INTO abcdefghijkl VALUES(22, 25, 26);
473     UPDATE abcdefghijkl SET y=400 WHERE x=22;
474   } [list REPLACE $p]
476   do_rebase_test 3.5.$tn* {
477     UPDATE abcdefghijkl SET y='X' WHERE x='d';
478   } {
479     DELETE FROM abcdefghijkl WHERE x='d';
480     INSERT INTO abcdefghijkl VALUES('d', NULL, NULL);
481   } [list $p $p $p]
482   do_rebase_test 3.5.$tn {
483     UPDATE abcdefghijkl SET y='X' WHERE x='d';
484   } {
485     DELETE FROM abcdefghijkl WHERE x='d';
486     INSERT INTO abcdefghijkl VALUES('d', NULL, NULL);
487   } [list REPLACE $p $p]
489   do_rebase_test 3.6.$tn {
490     UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d';
491   } {
492     UPDATE abcdefghijkl SET y=1 WHERE x='d';
493     UPDATE abcdefghijkl SET z=1 WHERE x='d';
494   } [list REPLACE $p $p]
497 #-------------------------------------------------------------------------
498 # Check that apply_v2() does not create a rebase buffer for a patchset.
499 # And that it is not possible to rebase a patchset.
501 do_execsql_test 4.0 {
502   CREATE TABLE t5(o PRIMARY KEY, p, q);
503   INSERT INTO t5 VALUES(1, 2, 3);
504   INSERT INTO t5 VALUES(4, 5, 6);
506 foreach {tn cmd rebasable} {
507   1 patchset 0
508   2 changeset 1
509 } {
510   proc xConflict {args} { return "OMIT" }
511   do_test 4.1.$tn {
512     execsql {
513       BEGIN;
514       DELETE FROM t5 WHERE o=4;
515     }
517     sqlite3session S db main
518     S attach *
519     execsql {
520       INSERT INTO t5 VALUES(4, 'five', 'six');
521     }
522     set P [S $cmd]
523     S delete
525     execsql ROLLBACK;
527     set ::rebase [sqlite3changeset_apply_v2 db $P xConflict]
528     expr [llength $::rebase]>0
529   } $rebasable
532 foreach {tn cmd rebasable} {
533   1 patchset 0
534   2 changeset 1
535 } {
536   do_test 4.2.$tn {
537     sqlite3session S db main
538     S attach *
539     execsql {
540       INSERT INTO t5 VALUES(5+$tn, 'five', 'six');
541     }
542     set P [S $cmd]
543     S delete
545     sqlite3rebaser_create R
546     R configure $::rebase
547     expr [catch {R rebase $P}]==0
548   } $rebasable
550   catch { R delete }
552 finish_test