123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- # 2018 March 14
- #
- # The author disclaims copyright to this source code. In place of
- # a legal notice, here is a blessing:
- #
- # May you do good and not evil.
- # May you find forgiveness for yourself and forgive others.
- # May you share freely, never taking more than you give.
- #
- #***********************************************************************
- # This file implements regression tests for SQLite library.
- #
- if {![info exists testdir]} {
- set testdir [file join [file dirname [info script]] .. .. test]
- }
- source [file join [file dirname [info script]] session_common.tcl]
- source $testdir/tester.tcl
- ifcapable !session {finish_test; return}
- set testprefix sessionrebase
- set ::lConflict [list]
- proc xConflict {args} {
- set res [lindex $::lConflict 0]
- set ::lConflict [lrange $::lConflict 1 end]
- return $res
- }
- #-------------------------------------------------------------------------
- # The following test cases - 1.* - test that the rebase blobs output by
- # sqlite3_changeset_apply_v2 look correct in some simple cases. The blob
- # is itself a changeset, containing records determined as follows:
- #
- # * For each conflict resolved with REPLACE, the rebase blob contains
- # a DELETE record. All fields other than the PK fields are undefined.
- #
- # * For each conflict resolved with OMIT, the rebase blob contains an
- # INSERT record. For an INSERT or UPDATE operation, the indirect flag
- # is clear and all updated fields are defined. For a DELETE operation,
- # the indirect flag is set and all non-PK fields left undefined.
- #
- proc do_apply_v2_test {tn sql modsql conflict_handler res} {
-
- execsql BEGIN
- sqlite3session S db main
- S attach *
- execsql $sql
- set changeset [S changeset]
- S delete
- execsql ROLLBACK
- execsql BEGIN
- execsql $modsql
- set ::lConflict $conflict_handler
- set blob [sqlite3changeset_apply_v2 db $changeset xConflict]
- execsql ROLLBACK
- uplevel [list do_test $tn [list changeset_to_list $blob] [list {*}$res]]
- }
- set ::lConflict [list]
- proc xConflict {args} {
- set res [lindex $::lConflict 0]
- set ::lConflict [lrange $::lConflict 1 end]
- return $res
- }
- # Take a copy of database test.db in file test.db2. Execute $sql1
- # against test.db and $sql2 against test.db2. Capture a changeset
- # for each. Then send the test.db2 changeset to test.db and apply
- # it with the conflict handlers in $conflict_handler. Patch the
- # test.db changeset and then execute it against test.db2. Test that
- # the two databases come out the same.
- #
- proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
- for {set i 1} {$i <= 2} {incr i} {
- forcedelete test.db2 test.db2-journal test.db2-wal
- forcecopy test.db test.db2
- sqlite3 db2 test.db2
- db eval BEGIN
- sqlite3session S1 db main
- S1 object_config rowid 1
- S1 attach *
- execsql $sql1 db
- set c1 [S1 changeset]
- S1 delete
- if {$i==1} {
- sqlite3session S2 db2 main
- S2 object_config rowid 1
- S2 attach *
- execsql $sql2 db2
- set c2 [S2 changeset]
- S2 delete
- } else {
- set c2 [list]
- foreach sql [split $sql2 ";"] {
- if {[string is space $sql]} continue
- sqlite3session S2 db2 main
- S2 object_config rowid 1
- S2 attach *
- execsql $sql db2
- lappend c2 [S2 changeset]
- S2 delete
- }
- }
- set ::lConflict $conflict_handler
- set rebase [list]
- if {$i==1} {
- lappend rebase [sqlite3changeset_apply_v2 db $c2 xConflict]
- } else {
- foreach c $c2 {
- #puts "apply_v2: [changeset_to_list $c]"
- lappend rebase [sqlite3changeset_apply_v2 db $c xConflict]
- }
- #puts "llength: [llength $rebase]"
- }
- #if {$tn=="2.1.4"} { puts [changeset_to_list $rebase] ; breakpoint }
- #puts [changeset_to_list [lindex $rebase 0]] ; breakpoint
- #puts [llength $rebase]
-
- sqlite3rebaser_create R
- foreach r $rebase {
- #puts [changeset_to_list $r]
- R configure $r
- }
- set c1r [R rebase $c1]
- R delete
- #if {$tn=="2.1.4"} { puts [changeset_to_list $c1r] }
-
- sqlite3changeset_apply_v2 db2 $c1r xConflictAbort
-
- if {[string range $tn end end]!="*"} {
- uplevel [list do_test $tn.$i.1 [list compare_db db db2] {}]
- }
- db2 close
-
- if {$testsql!=""} {
- uplevel [list do_execsql_test $tn.$i.2 $testsql $testres]
- }
-
- db eval ROLLBACK
- }
- }
- do_execsql_test 1.0 {
- CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
- INSERT INTO t1 VALUES(1, 'value A');
- }
- do_apply_v2_test 1.1.1 {
- UPDATE t1 SET b = 'value B' WHERE a=1;
- } {
- UPDATE t1 SET b = 'value C' WHERE a=1;
- } {
- OMIT
- } {
- {INSERT t1 0 X. {} {i 1 t {value B}}}
- }
- do_apply_v2_test 1.1.2 {
- UPDATE t1 SET b = 'value B' WHERE a=1;
- } {
- UPDATE t1 SET b = 'value C' WHERE a=1;
- } {
- REPLACE
- } {
- {INSERT t1 1 X. {} {i 1 t {value B}}}
- }
- do_apply_v2_test 1.2.1 {
- INSERT INTO t1 VALUES(2, 'first');
- } {
- INSERT INTO t1 VALUES(2, 'second');
- } {
- OMIT
- } {
- {INSERT t1 0 X. {} {i 2 t first}}
- }
- do_apply_v2_test 1.2.2 {
- INSERT INTO t1 VALUES(2, 'first');
- } {
- INSERT INTO t1 VALUES(2, 'second');
- } {
- REPLACE
- } {
- {INSERT t1 1 X. {} {i 2 t first}}
- }
- do_apply_v2_test 1.3.1 {
- DELETE FROM t1 WHERE a=1;
- } {
- UPDATE t1 SET b='value D' WHERE a=1;
- } {
- OMIT
- } {
- {DELETE t1 0 X. {i 1 t {value A}} {}}
- }
- do_apply_v2_test 1.3.2 {
- DELETE FROM t1 WHERE a=1;
- } {
- UPDATE t1 SET b='value D' WHERE a=1;
- } {
- REPLACE
- } {
- {DELETE t1 1 X. {i 1 t {value A}} {}}
- }
- #-------------------------------------------------------------------------
- # Test cases 2.* - simple tests of rebasing actual changesets.
- #
- # 2.1.1 - 1u2u1r
- # 2.1.2 - 1u2u2r
- # 2.1.3 - 1d2d
- # 2.1.4 - 1d2u1r
- # 2.1.5 - 1d2u2r !!
- # 2.1.6 - 1u2d1r
- # 2.1.7 - 1u2d2r
- #
- # 2.1.8 - 1i2i2r
- # 2.1.9 - 1i2i1r
- #
- proc xConflictAbort {args} {
- return "ABORT"
- }
- reset_db
- do_execsql_test 2.1.0 {
- CREATE TABLE t1 (a INTEGER PRIMARY KEY, b TEXT);
- INSERT INTO t1 VALUES(1, 'one');
- INSERT INTO t1 VALUES(2, 'two');
- INSERT INTO t1 VALUES(3, 'three');
- }
- do_rebase_test 2.1.1 {
- UPDATE t1 SET b = 'two.1' WHERE a=2
- } {
- UPDATE t1 SET b = 'two.2' WHERE a=2;
- } {
- OMIT
- } { SELECT * FROM t1 } {1 one 2 two.1 3 three}
- do_rebase_test 2.1.2 {
- UPDATE t1 SET b = 'two.1' WHERE a=2
- } {
- UPDATE t1 SET b = 'two.2' WHERE a=2;
- } {
- REPLACE
- } { SELECT * FROM t1 } {1 one 2 two.2 3 three}
- do_rebase_test 2.1.3 {
- DELETE FROM t1 WHERE a=3
- } {
- DELETE FROM t1 WHERE a=3;
- } {
- OMIT
- } { SELECT * FROM t1 } {1 one 2 two}
- do_rebase_test 2.1.4 {
- DELETE FROM t1 WHERE a=1
- } {
- UPDATE t1 SET b='one.2' WHERE a=1
- } {
- OMIT
- } { SELECT * FROM t1 } {2 two 3 three}
- #do_rebase_test 2.1.5 {
- # DELETE FROM t1 WHERE a=1;
- #} {
- # UPDATE t1 SET b='one.2' WHERE a=1
- #} {
- # REPLACE
- #} { SELECT * FROM t1 } {2 two 3 three}
- do_rebase_test 2.1.6 {
- UPDATE t1 SET b='three.1' WHERE a=3
- } {
- DELETE FROM t1 WHERE a=3;
- } {
- OMIT
- } { SELECT * FROM t1 } {1 one 2 two 3 three.1}
- do_rebase_test 2.1.7 {
- UPDATE t1 SET b='three.1' WHERE a=3
- } {
- DELETE FROM t1 WHERE a=3;
- } {
- REPLACE
- } { SELECT * FROM t1 } {1 one 2 two}
- do_rebase_test 2.1.8 {
- INSERT INTO t1 VALUES(4, 'four.1')
- } {
- INSERT INTO t1 VALUES(4, 'four.2');
- } {
- REPLACE
- } { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.2}
- do_rebase_test 2.1.9 {
- INSERT INTO t1 VALUES(4, 'four.1')
- } {
- INSERT INTO t1 VALUES(4, 'four.2');
- } {
- OMIT
- } { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.1}
- do_execsql_test 2.2.0 {
- CREATE TABLE t2(x, y, z PRIMARY KEY);
- INSERT INTO t2 VALUES('i', 'a', 'A');
- INSERT INTO t2 VALUES('ii', 'b', 'B');
- INSERT INTO t2 VALUES('iii', 'c', 'C');
- CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
- INSERT INTO t3 VALUES(-1, 'z', 'Z');
- INSERT INTO t3 VALUES(-2, 'y', 'Y');
- }
- do_rebase_test 2.2.1 {
- UPDATE t2 SET x=1 WHERE z='A'
- } {
- UPDATE t2 SET y='one' WHERE z='A';
- } {
- } { SELECT * FROM t2 WHERE z='A' } { 1 one A }
- do_rebase_test 2.2.2 {
- UPDATE t2 SET x=1, y='one' WHERE z='B'
- } {
- UPDATE t2 SET y='two' WHERE z='B';
- } {
- REPLACE
- } { SELECT * FROM t2 WHERE z='B' } { 1 two B }
- do_rebase_test 2.2.3 {
- UPDATE t2 SET x=1, y='one' WHERE z='B'
- } {
- UPDATE t2 SET y='two' WHERE z='B';
- } {
- OMIT
- } { SELECT * FROM t2 WHERE z='B' } { 1 one B }
- reset_db
- do_execsql_test 2.3.0 {
- CREATE TABLE t1 (b TEXT);
- INSERT INTO t1(rowid, b) VALUES(1, 'one');
- INSERT INTO t1(rowid, b) VALUES(2, 'two');
- INSERT INTO t1(rowid, b) VALUES(3, 'three');
- }
- do_rebase_test 2.3.1 {
- UPDATE t1 SET b = 'two.1' WHERE rowid=2
- } {
- UPDATE t1 SET b = 'two.2' WHERE rowid=2;
- } {
- OMIT
- } { SELECT rowid, * FROM t1 } {1 one 2 two.1 3 three}
- do_rebase_test 2.3.2 {
- UPDATE t1 SET b = 'two.1' WHERE rowid=2
- } {
- UPDATE t1 SET b = 'two.2' WHERE rowid=2;
- } {
- REPLACE
- } { SELECT rowid, * FROM t1 } {1 one 2 two.2 3 three}
- do_rebase_test 2.3.3 {
- DELETE FROM t1 WHERE rowid=3
- } {
- DELETE FROM t1 WHERE rowid=3;
- } {
- OMIT
- } { SELECT rowid, * FROM t1 } {1 one 2 two}
- do_rebase_test 2.3.4 {
- DELETE FROM t1 WHERE rowid=1
- } {
- UPDATE t1 SET b='one.2' WHERE rowid=1
- } {
- OMIT
- } { SELECT rowid, * FROM t1 } {2 two 3 three}
- do_rebase_test 2.3.6 {
- UPDATE t1 SET b='three.1' WHERE rowid=3
- } {
- DELETE FROM t1 WHERE rowid=3;
- } {
- OMIT
- } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three.1}
- do_rebase_test 2.3.7 {
- UPDATE t1 SET b='three.1' WHERE rowid=3
- } {
- DELETE FROM t1 WHERE rowid=3;
- } {
- REPLACE
- } { SELECT rowid, * FROM t1 } {1 one 2 two}
- do_rebase_test 2.3.8 {
- INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
- } {
- INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
- } {
- REPLACE
- } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.2}
- do_rebase_test 2.3.9 {
- INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
- } {
- INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
- } {
- OMIT
- } { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.1}
- #-------------------------------------------------------------------------
- reset_db
- do_execsql_test 3.0 {
- CREATE TABLE t3(a, b, c, PRIMARY KEY(b, c));
- CREATE TABLE abcdefghijkl(x PRIMARY KEY, y, z);
- INSERT INTO t3 VALUES(1, 2, 3);
- INSERT INTO t3 VALUES(4, 2, 5);
- INSERT INTO t3 VALUES(7, 2, 9);
- INSERT INTO abcdefghijkl VALUES('a', 'b', 'c');
- INSERT INTO abcdefghijkl VALUES('d', 'e', 'f');
- INSERT INTO abcdefghijkl VALUES('g', 'h', 'i');
- }
- breakpoint
- # do_rebase_test 3.6.tn {
- # UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d';
- # } {
- # UPDATE abcdefghijkl SET y=1 WHERE x='d';
- # UPDATE abcdefghijkl SET z=1 WHERE x='d';
- # } [list REPLACE REPLACE REPLACE]
- foreach {tn p} {
- 1 OMIT 2 REPLACE
- } {
- do_rebase_test 3.1.$tn {
- INSERT INTO t3 VALUES(1, 1, 1);
- UPDATE abcdefghijkl SET y=2;
- } {
- INSERT INTO t3 VALUES(4, 1, 1);
- DELETE FROM abcdefghijkl;
- } [list $p $p $p $p $p $p $p $p]
- do_rebase_test 3.2.$tn {
- INSERT INTO abcdefghijkl SELECT * FROM t3;
- UPDATE t3 SET b=b+1;
- } {
- INSERT INTO t3 VALUES(3, 3, 3);
- INSERT INTO abcdefghijkl SELECT * FROM t3;
- } [list $p $p $p $p $p $p $p $p]
- do_rebase_test 3.3.$tn {
- INSERT INTO abcdefghijkl VALUES(22, 23, 24);
- } {
- INSERT INTO abcdefghijkl VALUES(22, 25, 26);
- UPDATE abcdefghijkl SET y=400 WHERE x=22;
- } [list $p $p $p $p $p $p $p $p]
- do_rebase_test 3.4.$tn {
- INSERT INTO abcdefghijkl VALUES(22, 23, 24);
- } {
- INSERT INTO abcdefghijkl VALUES(22, 25, 26);
- UPDATE abcdefghijkl SET y=400 WHERE x=22;
- } [list REPLACE $p]
- do_rebase_test 3.5.$tn* {
- UPDATE abcdefghijkl SET y='X' WHERE x='d';
- } {
- DELETE FROM abcdefghijkl WHERE x='d';
- INSERT INTO abcdefghijkl VALUES('d', NULL, NULL);
- } [list $p $p $p]
- do_rebase_test 3.5.$tn {
- UPDATE abcdefghijkl SET y='X' WHERE x='d';
- } {
- DELETE FROM abcdefghijkl WHERE x='d';
- INSERT INTO abcdefghijkl VALUES('d', NULL, NULL);
- } [list REPLACE $p $p]
- do_rebase_test 3.6.$tn {
- UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d';
- } {
- UPDATE abcdefghijkl SET y=1 WHERE x='d';
- UPDATE abcdefghijkl SET z=1 WHERE x='d';
- } [list REPLACE $p $p]
- }
- #-------------------------------------------------------------------------
- # Check that apply_v2() does not create a rebase buffer for a patchset.
- # And that it is not possible to rebase a patchset.
- #
- do_execsql_test 4.0 {
- CREATE TABLE t5(o PRIMARY KEY, p, q);
- INSERT INTO t5 VALUES(1, 2, 3);
- INSERT INTO t5 VALUES(4, 5, 6);
- }
- foreach {tn cmd rebasable} {
- 1 patchset 0
- 2 changeset 1
- } {
- proc xConflict {args} { return "OMIT" }
- do_test 4.1.$tn {
- execsql {
- BEGIN;
- DELETE FROM t5 WHERE o=4;
- }
- sqlite3session S db main
- S attach *
- execsql {
- INSERT INTO t5 VALUES(4, 'five', 'six');
- }
- set P [S $cmd]
- S delete
- execsql ROLLBACK;
- set ::rebase [sqlite3changeset_apply_v2 db $P xConflict]
- expr [llength $::rebase]>0
- } $rebasable
- }
- foreach {tn cmd rebasable} {
- 1 patchset 0
- 2 changeset 1
- } {
- do_test 4.2.$tn {
- sqlite3session S db main
- S attach *
- execsql {
- INSERT INTO t5 VALUES(5+$tn, 'five', 'six');
- }
- set P [S $cmd]
- S delete
- sqlite3rebaser_create R
- R configure $::rebase
- expr [catch {R rebase $P}]==0
- } $rebasable
- catch { R delete }
- }
- finish_test
|