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 62 63set ::lConflict [list] 64proc xConflict {args} { 65 set res [lindex $::lConflict 0] 66 set ::lConflict [lrange $::lConflict 1 end] 67 return $res 68} 69 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. 76# 77proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} { 78 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 83 84 db eval BEGIN 85 86 sqlite3session S1 db main 87 S1 attach * 88 execsql $sql1 db 89 set c1 [S1 changeset] 90 S1 delete 91 92 if {$i==1} { 93 sqlite3session S2 db2 main 94 S2 attach * 95 execsql $sql2 db2 96 set c2 [S2 changeset] 97 S2 delete 98 } else { 99 set c2 [list] 100 foreach sql [split $sql2 ";"] { 101 if {[string is space $sql]} continue 102 sqlite3session S2 db2 main 103 S2 attach * 104 execsql $sql db2 105 lappend c2 [S2 changeset] 106 S2 delete 107 } 108 } 109 110 set ::lConflict $conflict_handler 111 set rebase [list] 112 if {$i==1} { 113 lappend rebase [sqlite3changeset_apply_v2 db $c2 xConflict] 114 } else { 115 foreach c $c2 { 116#puts "apply_v2: [changeset_to_list $c]" 117 lappend rebase [sqlite3changeset_apply_v2 db $c xConflict] 118 } 119 #puts "llength: [llength $rebase]" 120 } 121 #if {$tn=="2.1.4"} { puts [changeset_to_list $rebase] ; breakpoint } 122 #puts [changeset_to_list [lindex $rebase 0]] ; breakpoint 123 #puts [llength $rebase] 124 125 sqlite3rebaser_create R 126 foreach r $rebase { 127#puts [changeset_to_list $r] 128 R configure $r 129 } 130 set c1r [R rebase $c1] 131 R delete 132 #if {$tn=="2.1.4"} { puts [changeset_to_list $c1r] } 133 134 sqlite3changeset_apply_v2 db2 $c1r xConflictAbort 135 136 if {[string range $tn end end]!="*"} { 137 uplevel [list do_test $tn.$i.1 [list compare_db db db2] {}] 138 } 139 db2 close 140 141 if {$testsql!=""} { 142 uplevel [list do_execsql_test $tn.$i.2 $testsql $testres] 143 } 144 145 db eval ROLLBACK 146 } 147} 148 149do_execsql_test 1.0 { 150 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 151 INSERT INTO t1 VALUES(1, 'value A'); 152} 153 154do_apply_v2_test 1.1.1 { 155 UPDATE t1 SET b = 'value B' WHERE a=1; 156} { 157 UPDATE t1 SET b = 'value C' WHERE a=1; 158} { 159 OMIT 160} { 161 {INSERT t1 0 X. {} {i 1 t {value B}}} 162} 163 164do_apply_v2_test 1.1.2 { 165 UPDATE t1 SET b = 'value B' WHERE a=1; 166} { 167 UPDATE t1 SET b = 'value C' WHERE a=1; 168} { 169 REPLACE 170} { 171 {INSERT t1 1 X. {} {i 1 t {value B}}} 172} 173 174do_apply_v2_test 1.2.1 { 175 INSERT INTO t1 VALUES(2, 'first'); 176} { 177 INSERT INTO t1 VALUES(2, 'second'); 178} { 179 OMIT 180} { 181 {INSERT t1 0 X. {} {i 2 t first}} 182} 183do_apply_v2_test 1.2.2 { 184 INSERT INTO t1 VALUES(2, 'first'); 185} { 186 INSERT INTO t1 VALUES(2, 'second'); 187} { 188 REPLACE 189} { 190 {INSERT t1 1 X. {} {i 2 t first}} 191} 192 193do_apply_v2_test 1.3.1 { 194 DELETE FROM t1 WHERE a=1; 195} { 196 UPDATE t1 SET b='value D' WHERE a=1; 197} { 198 OMIT 199} { 200 {DELETE t1 0 X. {i 1 t {value A}} {}} 201} 202do_apply_v2_test 1.3.2 { 203 DELETE FROM t1 WHERE a=1; 204} { 205 UPDATE t1 SET b='value D' WHERE a=1; 206} { 207 REPLACE 208} { 209 {DELETE t1 1 X. {i 1 t {value A}} {}} 210} 211 212#------------------------------------------------------------------------- 213# Test cases 2.* - simple tests of rebasing actual changesets. 214# 215# 2.1.1 - 1u2u1r 216# 2.1.2 - 1u2u2r 217# 2.1.3 - 1d2d 218# 2.1.4 - 1d2u1r 219# 2.1.5 - 1d2u2r !! 220# 2.1.6 - 1u2d1r 221# 2.1.7 - 1u2d2r 222# 223# 2.1.8 - 1i2i2r 224# 2.1.9 - 1i2i1r 225# 226 227proc xConflictAbort {args} { 228 return "ABORT" 229} 230 231reset_db 232do_execsql_test 2.1.0 { 233 CREATE TABLE t1 (a INTEGER PRIMARY KEY, b TEXT); 234 INSERT INTO t1 VALUES(1, 'one'); 235 INSERT INTO t1 VALUES(2, 'two'); 236 INSERT INTO t1 VALUES(3, 'three'); 237} 238do_rebase_test 2.1.1 { 239 UPDATE t1 SET b = 'two.1' WHERE a=2 240} { 241 UPDATE t1 SET b = 'two.2' WHERE a=2; 242} { 243 OMIT 244} { SELECT * FROM t1 } {1 one 2 two.1 3 three} 245 246do_rebase_test 2.1.2 { 247 UPDATE t1 SET b = 'two.1' WHERE a=2 248} { 249 UPDATE t1 SET b = 'two.2' WHERE a=2; 250} { 251 REPLACE 252} { SELECT * FROM t1 } {1 one 2 two.2 3 three} 253 254do_rebase_test 2.1.3 { 255 DELETE FROM t1 WHERE a=3 256} { 257 DELETE FROM t1 WHERE a=3; 258} { 259 OMIT 260} { SELECT * FROM t1 } {1 one 2 two} 261 262do_rebase_test 2.1.4 { 263 DELETE FROM t1 WHERE a=1 264} { 265 UPDATE t1 SET b='one.2' WHERE a=1 266} { 267 OMIT 268} { SELECT * FROM t1 } {2 two 3 three} 269 270#do_rebase_test 2.1.5 { 271# DELETE FROM t1 WHERE a=1; 272#} { 273# UPDATE t1 SET b='one.2' WHERE a=1 274#} { 275# REPLACE 276#} { SELECT * FROM t1 } {2 two 3 three} 277 278do_rebase_test 2.1.6 { 279 UPDATE t1 SET b='three.1' WHERE a=3 280} { 281 DELETE FROM t1 WHERE a=3; 282} { 283 OMIT 284} { SELECT * FROM t1 } {1 one 2 two 3 three.1} 285 286do_rebase_test 2.1.7 { 287 UPDATE t1 SET b='three.1' WHERE a=3 288} { 289 DELETE FROM t1 WHERE a=3; 290} { 291 REPLACE 292} { SELECT * FROM t1 } {1 one 2 two} 293 294do_rebase_test 2.1.8 { 295 INSERT INTO t1 VALUES(4, 'four.1') 296} { 297 INSERT INTO t1 VALUES(4, 'four.2'); 298} { 299 REPLACE 300} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.2} 301 302do_rebase_test 2.1.9 { 303 INSERT INTO t1 VALUES(4, 'four.1') 304} { 305 INSERT INTO t1 VALUES(4, 'four.2'); 306} { 307 OMIT 308} { SELECT * FROM t1 } {1 one 2 two 3 three 4 four.1} 309 310do_execsql_test 2.2.0 { 311 CREATE TABLE t2(x, y, z PRIMARY KEY); 312 INSERT INTO t2 VALUES('i', 'a', 'A'); 313 INSERT INTO t2 VALUES('ii', 'b', 'B'); 314 INSERT INTO t2 VALUES('iii', 'c', 'C'); 315 316 CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); 317 INSERT INTO t3 VALUES(-1, 'z', 'Z'); 318 INSERT INTO t3 VALUES(-2, 'y', 'Y'); 319} 320 321do_rebase_test 2.2.1 { 322 UPDATE t2 SET x=1 WHERE z='A' 323} { 324 UPDATE t2 SET y='one' WHERE z='A'; 325} { 326} { SELECT * FROM t2 WHERE z='A' } { 1 one A } 327 328do_rebase_test 2.2.2 { 329 UPDATE t2 SET x=1, y='one' WHERE z='B' 330} { 331 UPDATE t2 SET y='two' WHERE z='B'; 332} { 333 REPLACE 334} { SELECT * FROM t2 WHERE z='B' } { 1 two B } 335 336do_rebase_test 2.2.3 { 337 UPDATE t2 SET x=1, y='one' WHERE z='B' 338} { 339 UPDATE t2 SET y='two' WHERE z='B'; 340} { 341 OMIT 342} { SELECT * FROM t2 WHERE z='B' } { 1 one B } 343 344#------------------------------------------------------------------------- 345reset_db 346do_execsql_test 3.0 { 347 CREATE TABLE t3(a, b, c, PRIMARY KEY(b, c)); 348 CREATE TABLE abcdefghijkl(x PRIMARY KEY, y, z); 349 350 INSERT INTO t3 VALUES(1, 2, 3); 351 INSERT INTO t3 VALUES(4, 2, 5); 352 INSERT INTO t3 VALUES(7, 2, 9); 353 354 INSERT INTO abcdefghijkl VALUES('a', 'b', 'c'); 355 INSERT INTO abcdefghijkl VALUES('d', 'e', 'f'); 356 INSERT INTO abcdefghijkl VALUES('g', 'h', 'i'); 357} 358 359breakpoint 360# do_rebase_test 3.6.tn { 361# UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d'; 362# } { 363# UPDATE abcdefghijkl SET y=1 WHERE x='d'; 364# UPDATE abcdefghijkl SET z=1 WHERE x='d'; 365# } [list REPLACE REPLACE REPLACE] 366 367foreach {tn p} { 368 1 OMIT 2 REPLACE 369} { 370 do_rebase_test 3.1.$tn { 371 INSERT INTO t3 VALUES(1, 1, 1); 372 UPDATE abcdefghijkl SET y=2; 373 } { 374 INSERT INTO t3 VALUES(4, 1, 1); 375 DELETE FROM abcdefghijkl; 376 } [list $p $p $p $p $p $p $p $p] 377 378 do_rebase_test 3.2.$tn { 379 INSERT INTO abcdefghijkl SELECT * FROM t3; 380 UPDATE t3 SET b=b+1; 381 } { 382 INSERT INTO t3 VALUES(3, 3, 3); 383 INSERT INTO abcdefghijkl SELECT * FROM t3; 384 } [list $p $p $p $p $p $p $p $p] 385 386 do_rebase_test 3.3.$tn { 387 INSERT INTO abcdefghijkl VALUES(22, 23, 24); 388 } { 389 INSERT INTO abcdefghijkl VALUES(22, 25, 26); 390 UPDATE abcdefghijkl SET y=400 WHERE x=22; 391 } [list $p $p $p $p $p $p $p $p] 392 393 do_rebase_test 3.4.$tn { 394 INSERT INTO abcdefghijkl VALUES(22, 23, 24); 395 } { 396 INSERT INTO abcdefghijkl VALUES(22, 25, 26); 397 UPDATE abcdefghijkl SET y=400 WHERE x=22; 398 } [list REPLACE $p] 399 400 do_rebase_test 3.5.$tn* { 401 UPDATE abcdefghijkl SET y='X' WHERE x='d'; 402 } { 403 DELETE FROM abcdefghijkl WHERE x='d'; 404 INSERT INTO abcdefghijkl VALUES('d', NULL, NULL); 405 } [list $p $p $p] 406 do_rebase_test 3.5.$tn { 407 UPDATE abcdefghijkl SET y='X' WHERE x='d'; 408 } { 409 DELETE FROM abcdefghijkl WHERE x='d'; 410 INSERT INTO abcdefghijkl VALUES('d', NULL, NULL); 411 } [list REPLACE $p $p] 412 413 do_rebase_test 3.6.$tn { 414 UPDATE abcdefghijkl SET z='X', y='X' WHERE x='d'; 415 } { 416 UPDATE abcdefghijkl SET y=1 WHERE x='d'; 417 UPDATE abcdefghijkl SET z=1 WHERE x='d'; 418 } [list REPLACE $p $p] 419} 420 421#------------------------------------------------------------------------- 422# Check that apply_v2() does not create a rebase buffer for a patchset. 423# And that it is not possible to rebase a patchset. 424# 425do_execsql_test 4.0 { 426 CREATE TABLE t5(o PRIMARY KEY, p, q); 427 INSERT INTO t5 VALUES(1, 2, 3); 428 INSERT INTO t5 VALUES(4, 5, 6); 429} 430foreach {tn cmd rebasable} { 431 1 patchset 0 432 2 changeset 1 433} { 434 proc xConflict {args} { return "OMIT" } 435 do_test 4.1.$tn { 436 execsql { 437 BEGIN; 438 DELETE FROM t5 WHERE o=4; 439 } 440 441 sqlite3session S db main 442 S attach * 443 execsql { 444 INSERT INTO t5 VALUES(4, 'five', 'six'); 445 } 446 set P [S $cmd] 447 S delete 448 449 execsql ROLLBACK; 450 451 set ::rebase [sqlite3changeset_apply_v2 db $P xConflict] 452 expr [llength $::rebase]>0 453 } $rebasable 454} 455 456foreach {tn cmd rebasable} { 457 1 patchset 0 458 2 changeset 1 459} { 460 do_test 4.2.$tn { 461 sqlite3session S db main 462 S attach * 463 execsql { 464 INSERT INTO t5 VALUES(5+$tn, 'five', 'six'); 465 } 466 set P [S $cmd] 467 S delete 468 469 sqlite3rebaser_create R 470 R configure $::rebase 471 expr [catch {R rebase $P}]==0 472 } $rebasable 473 474 catch { R delete } 475} 476finish_test 477