1# 2018 March 14 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 SQLite library. 12# 13 14if {![info exists testdir]} { 15 set testdir [file join [file dirname [info script]] .. .. test] 16} 17source [file join [file dirname [info script]] session_common.tcl] 18source $testdir/tester.tcl 19ifcapable !session {finish_test; return} 20 21set testprefix sessionrebase 22 23set ::lConflict [list] 24proc xConflict {args} { 25 set res [lindex $::lConflict 0] 26 set ::lConflict [lrange $::lConflict 1 end] 27 return $res 28} 29 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: 34# 35# * For each conflict resolved with REPLACE, the rebase blob contains 36# a DELETE record. All fields other than the PK fields are undefined. 37# 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. 42# 43proc 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 52 53 execsql BEGIN 54 execsql $modsql 55 set ::lConflict $conflict_handler 56 set blob [sqlite3changeset_apply_v2 db $changeset xConflict] 57 execsql ROLLBACK 58 59 uplevel [list do_test $tn [list changeset_to_list $blob] [list {*}$res]] 60} 61 62do_execsql_test 1.0 { 63 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 64 INSERT INTO t1 VALUES(1, 'value A'); 65} 66 67do_apply_v2_test 1.1.1 { 68 UPDATE t1 SET b = 'value B' WHERE a=1; 69} { 70 UPDATE t1 SET b = 'value C' WHERE a=1; 71} { 72 OMIT 73} { 74 {INSERT t1 0 X. {} {i 1 t {value B}}} 75} 76 77do_apply_v2_test 1.1.2 { 78 UPDATE t1 SET b = 'value B' WHERE a=1; 79} { 80 UPDATE t1 SET b = 'value C' WHERE a=1; 81} { 82 REPLACE 83} { 84 {INSERT t1 1 X. {} {i 1 t {value B}}} 85} 86 87do_apply_v2_test 1.2.1 { 88 INSERT INTO t1 VALUES(2, 'first'); 89} { 90 INSERT INTO t1 VALUES(2, 'second'); 91} { 92 OMIT 93} { 94 {INSERT t1 0 X. {} {i 2 t first}} 95} 96do_apply_v2_test 1.2.2 { 97 INSERT INTO t1 VALUES(2, 'first'); 98} { 99 INSERT INTO t1 VALUES(2, 'second'); 100} { 101 REPLACE 102} { 103 {INSERT t1 1 X. {} {i 2 t first}} 104} 105 106do_apply_v2_test 1.3.1 { 107 DELETE FROM t1 WHERE a=1; 108} { 109 UPDATE t1 SET b='value D' WHERE a=1; 110} { 111 OMIT 112} { 113 {DELETE t1 0 X. {i 1 t {value A}} {}} 114} 115do_apply_v2_test 1.3.2 { 116 DELETE FROM t1 WHERE a=1; 117} { 118 UPDATE t1 SET b='value D' WHERE a=1; 119} { 120 REPLACE 121} { 122 {DELETE t1 1 X. {i 1 t {value A}} {}} 123} 124 125#------------------------------------------------------------------------- 126# Test cases 2.* - simple tests of rebasing actual changesets. 127# 128# 2.1.1 - 1u2u1r 129# 2.1.2 - 1u2u2r 130# 2.1.3 - 1d2d 131# 2.1.4 - 1d2u1r 132# 2.1.5 - 1d2u2r !! 133# 2.1.6 - 1u2d1r 134# 2.1.7 - 1u2d2r 135# 136# 2.1.8 - 1i2i2r 137# 2.1.9 - 1i2i1r 138# 139 140proc xConflictAbort {args} { 141 return "ABORT" 142} 143 144# Take a copy of database test.db in file test.db2. Execute $sql1 145# against test.db and $sql2 against test.db2. Capture a changeset 146# for each. Then send the test.db2 changeset to test.db and apply 147# it with the conflict handlers in $conflict_handler. Patch the 148# test.db changeset and then execute it against test.db2. Test that 149# the two databases come out the same. 150# 151proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} { 152 153 forcedelete test.db2 test.db2-journal test.db2-wal 154 forcecopy test.db test.db2 155 sqlite3 db2 test.db2 156 157 db eval BEGIN 158 159 sqlite3session S1 db main 160 S1 attach * 161 execsql $sql1 db 162 set c1 [S1 changeset] 163 S1 delete 164 165 sqlite3session S2 db2 main 166 S2 attach * 167 execsql $sql2 db2 168 set c2 [S2 changeset] 169 S2 delete 170 171 set ::lConflict $conflict_handler 172 set rebase [sqlite3changeset_apply_v2 db $c2 xConflict] 173 #if {$tn=="2.1.4"} { puts [changeset_to_list $rebase] ; breakpoint } 174 175 sqlite3rebaser_create R 176 R configure $rebase 177 set c1r [R rebase $c1] 178 R delete 179 #if {$tn=="2.1.4"} { puts [changeset_to_list $c1r] } 180 181 sqlite3changeset_apply_v2 db2 $c1r xConflictAbort 182 183 uplevel [list do_test $tn.1 [list compare_db db db2] {}] 184 db2 close 185 186 if {$testsql!=""} { 187 uplevel [list do_execsql_test $tn.2 $testsql $testres] 188 } 189 190 db eval ROLLBACK 191} 192 193reset_db 194do_execsql_test 2.1.0 { 195 CREATE TABLE t1 (a INTEGER PRIMARY KEY, b TEXT); 196 INSERT INTO t1 VALUES(1, 'one'); 197 INSERT INTO t1 VALUES(2, 'two'); 198 INSERT INTO t1 VALUES(3, 'three'); 199} 200do_rebase_test 2.1.1 { 201 UPDATE t1 SET b = 'two.1' WHERE a=2; 202} { 203 UPDATE t1 SET b = 'two.2' WHERE a=2; 204} { 205 OMIT 206} { SELECT * FROM t1 } {1 one 2 two.1 3 three} 207 208do_rebase_test 2.1.2 { 209 UPDATE t1 SET b = 'two.1' WHERE a=2; 210} { 211 UPDATE t1 SET b = 'two.2' WHERE a=2; 212} { 213 REPLACE 214} { SELECT * FROM t1 } {1 one 2 two.2 3 three} 215 216do_rebase_test 2.1.3 { 217 DELETE FROM t1 WHERE a=3; 218} { 219 DELETE FROM t1 WHERE a=3; 220} { 221 OMIT 222} { SELECT * FROM t1 } {1 one 2 two} 223 224do_rebase_test 2.1.4 { 225 DELETE FROM t1 WHERE a=1; 226} { 227 UPDATE t1 SET b='one.2' WHERE a=1 228} { 229 OMIT 230} { SELECT * FROM t1 } {2 two 3 three} 231 232#do_rebase_test 2.1.5 { 233# DELETE FROM t1 WHERE a=1; 234#} { 235# UPDATE t1 SET b='one.2' WHERE a=1 236#} { 237# REPLACE 238#} { SELECT * FROM t1 } {2 two 3 three} 239 240do_rebase_test 2.1.6 { 241 UPDATE t1 SET b='three.1' WHERE a=3; 242} { 243 DELETE FROM t1 WHERE a=3; 244} { 245 OMIT 246} { SELECT * FROM t1 } {1 one 2 two 3 three.1} 247 248do_rebase_test 2.1.7 { 249 UPDATE t1 SET b='three.1' WHERE a=3; 250} { 251 DELETE FROM t1 WHERE a=3; 252} { 253 REPLACE 254} { SELECT * FROM t1 } {1 one 2 two} 255 256do_rebase_test 2.1.8 { 257 INSERT INTO t1 VALUES(4, 'four.1'); 258} { 259 INSERT INTO t1 VALUES(4, 'four.2'); 260} { 261 REPLACE 262} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.2} 263 264do_rebase_test 2.1.9 { 265 INSERT INTO t1 VALUES(4, 'four.1'); 266} { 267 INSERT INTO t1 VALUES(4, 'four.2'); 268} { 269 OMIT 270} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.1} 271 272do_execsql_test 2.2.0 { 273 CREATE TABLE t2(x, y, z PRIMARY KEY); 274 INSERT INTO t2 VALUES('i', 'a', 'A'); 275 INSERT INTO t2 VALUES('ii', 'b', 'B'); 276 INSERT INTO t2 VALUES('iii', 'c', 'C'); 277 278 CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); 279 INSERT INTO t3 VALUES(-1, 'z', 'Z'); 280 INSERT INTO t3 VALUES(-2, 'y', 'Y'); 281} 282 283do_rebase_test 2.2.1 { 284 UPDATE t2 SET x=1 WHERE z='A'; 285} { 286 UPDATE t2 SET y='one' WHERE z='A'; 287} { 288} { SELECT * FROM t2 WHERE z='A' } { 1 one A } 289 290do_rebase_test 2.2.2 { 291 UPDATE t2 SET x=1, y='one' WHERE z='B'; 292} { 293 UPDATE t2 SET y='two' WHERE z='B'; 294} { 295 REPLACE 296} { SELECT * FROM t2 WHERE z='B' } { 1 two B } 297 298do_rebase_test 2.2.3 { 299 UPDATE t2 SET x=1, y='one' WHERE z='B'; 300} { 301 UPDATE t2 SET y='two' WHERE z='B'; 302} { 303 OMIT 304} { SELECT * FROM t2 WHERE z='B' } { 1 one B } 305 306finish_test 307 308