1# 2011 March 07 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 session1 22 23do_execsql_test 1.0 { 24 CREATE TABLE t1(x PRIMARY KEY, y); 25 INSERT INTO t1 VALUES('abc', 'def'); 26} 27 28#------------------------------------------------------------------------- 29# Test creating, attaching tables to and deleting session objects. 30# 31do_test 1.1 { sqlite3session S db main } {S} 32do_test 1.2 { S delete } {} 33do_test 1.3 { sqlite3session S db main } {S} 34do_test 1.4 { S attach t1 } {} 35do_test 1.5 { S delete } {} 36do_test 1.6 { sqlite3session S db main } {S} 37do_test 1.7 { S attach t1 ; S attach t2 ; S attach t3 } {} 38do_test 1.8 { S attach t1 ; S attach t2 ; S attach t3 } {} 39do_test 1.9 { S delete } {} 40do_test 1.10 { 41 sqlite3session S db main 42 S attach t1 43 execsql { INSERT INTO t1 VALUES('ghi', 'jkl') } 44} {} 45do_test 1.11 { S delete } {} 46do_test 1.12 { 47 sqlite3session S db main 48 S attach t1 49 execsql { INSERT INTO t1 VALUES('mno', 'pqr') } 50 execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 } 51 execsql { DELETE FROM t1 WHERE rowid = 2 } 52} {} 53do_test 1.13 { 54 S changeset 55 S delete 56} {} 57 58#------------------------------------------------------------------------- 59# Simple changeset tests. Also test the sqlite3changeset_invert() 60# function. 61# 62do_test 2.1.1 { 63 execsql { DELETE FROM t1 } 64 sqlite3session S db main 65 S attach t1 66 execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') } 67 execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') } 68 execsql { INSERT INTO t1 VALUES(3, 'Thonburi') } 69} {} 70do_changeset_test 2.1.2 S { 71 {INSERT t1 0 X. {} {i 1 t Sukhothai}} 72 {INSERT t1 0 X. {} {i 2 t Ayutthaya}} 73 {INSERT t1 0 X. {} {i 3 t Thonburi}} 74} 75do_changeset_invert_test 2.1.3 S { 76 {DELETE t1 0 X. {i 1 t Sukhothai} {}} 77 {DELETE t1 0 X. {i 2 t Ayutthaya} {}} 78 {DELETE t1 0 X. {i 3 t Thonburi} {}} 79} 80do_test 2.1.4 { S delete } {} 81 82do_test 2.2.1 { 83 sqlite3session S db main 84 S attach t1 85 execsql { DELETE FROM t1 WHERE 1 } 86} {} 87do_changeset_test 2.2.2 S { 88 {DELETE t1 0 X. {i 1 t Sukhothai} {}} 89 {DELETE t1 0 X. {i 2 t Ayutthaya} {}} 90 {DELETE t1 0 X. {i 3 t Thonburi} {}} 91} 92do_changeset_invert_test 2.2.3 S { 93 {INSERT t1 0 X. {} {i 1 t Sukhothai}} 94 {INSERT t1 0 X. {} {i 2 t Ayutthaya}} 95 {INSERT t1 0 X. {} {i 3 t Thonburi}} 96} 97do_test 2.2.4 { S delete } {} 98 99do_test 2.3.1 { 100 execsql { DELETE FROM t1 } 101 sqlite3session S db main 102 execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') } 103 execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') } 104 execsql { INSERT INTO t1 VALUES(3, 'Thonburi') } 105 S attach t1 106 execsql { 107 UPDATE t1 SET x = 10 WHERE x = 1; 108 UPDATE t1 SET y = 'Surin' WHERE x = 2; 109 UPDATE t1 SET x = 20, y = 'Thapae' WHERE x = 3; 110 } 111} {} 112 113do_changeset_test 2.3.2 S { 114 {INSERT t1 0 X. {} {i 10 t Sukhothai}} 115 {DELETE t1 0 X. {i 1 t Sukhothai} {}} 116 {UPDATE t1 0 X. {i 2 t Ayutthaya} {{} {} t Surin}} 117 {DELETE t1 0 X. {i 3 t Thonburi} {}} 118 {INSERT t1 0 X. {} {i 20 t Thapae}} 119} 120 121do_changeset_invert_test 2.3.3 S { 122 {DELETE t1 0 X. {i 10 t Sukhothai} {}} 123 {INSERT t1 0 X. {} {i 1 t Sukhothai}} 124 {UPDATE t1 0 X. {i 2 t Surin} {{} {} t Ayutthaya}} 125 {INSERT t1 0 X. {} {i 3 t Thonburi}} 126 {DELETE t1 0 X. {i 20 t Thapae} {}} 127} 128do_test 2.3.4 { S delete } {} 129 130do_test 2.4.1 { 131 sqlite3session S db main 132 S attach t1 133 execsql { INSERT INTO t1 VALUES(100, 'Bangkok') } 134 execsql { DELETE FROM t1 WHERE x = 100 } 135} {} 136do_changeset_test 2.4.2 S {} 137do_changeset_invert_test 2.4.3 S {} 138do_test 2.4.4 { S delete } {} 139 140#------------------------------------------------------------------------- 141# Test the application of simple changesets. These tests also test that 142# the conflict callback is invoked correctly. For these tests, the 143# conflict callback always returns OMIT. 144# 145db close 146forcedelete test.db test.db2 147sqlite3 db test.db 148sqlite3 db2 test.db2 149 150proc xConflict {args} { 151 lappend ::xConflict $args 152 return "" 153} 154 155proc bgerror {args} { set ::background_error $args } 156 157proc do_conflict_test {tn args} { 158 set O(-tables) [list] 159 set O(-sql) [list] 160 set O(-conflicts) [list] 161 162 array set V $args 163 foreach key [array names V] { 164 if {![info exists O($key)]} {error "no such option: $key"} 165 } 166 array set O $args 167 168 sqlite3session S db main 169 foreach t $O(-tables) { S attach $t } 170 execsql $O(-sql) 171 set ::xConflict [list] 172 sqlite3changeset_apply db2 [S changeset] xConflict 173 174 set conflicts [list] 175 foreach c $O(-conflicts) { 176 lappend conflicts $c 177 } 178 179 after 1 {set go 1} 180 vwait go 181 182 uplevel do_test $tn [list { set ::xConflict }] [list $conflicts] 183 S delete 184} 185 186proc do_db2_test {testname sql {result {}}} { 187 uplevel do_test $testname [list "execsql {$sql} db2"] [list [list {*}$result]] 188} 189 190# Test INSERT changesets. 191# 192do_test 3.1.0 { 193 execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) } db2 194 execsql { 195 CREATE TABLE t1(a PRIMARY KEY, b); 196 INSERT INTO t1 VALUES(1, 'one'); 197 INSERT INTO t1 VALUES(2, 'two'); 198 } db 199} {} 200do_db2_test 3.1.1 "INSERT INTO t1 VALUES(6, 'VI')" 201do_conflict_test 3.1.2 -tables t1 -sql { 202 INSERT INTO t1 VALUES(3, 'three'); 203 INSERT INTO t1 VALUES(4, 'four'); 204 INSERT INTO t1 VALUES(5, 'five'); 205 INSERT INTO t1 VALUES(6, 'six'); 206 INSERT INTO t1 VALUES(7, 'seven'); 207 INSERT INTO t1 VALUES(8, NULL); 208} -conflicts { 209 {INSERT t1 CONFLICT {i 6 t six} {i 6 t VI}} 210 {INSERT t1 CONSTRAINT {i 8 n {}}} 211} 212 213do_db2_test 3.1.3 "SELECT * FROM t1" { 214 6 VI 3 three 4 four 5 five 7 seven 215} 216do_execsql_test 3.1.4 "SELECT * FROM t1" { 217 1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 {} 218} 219 220# Test DELETE changesets. 221# 222do_execsql_test 3.2.1 { 223 PRAGMA foreign_keys = on; 224 CREATE TABLE t2(a PRIMARY KEY, b); 225 CREATE TABLE t3(c, d REFERENCES t2); 226 INSERT INTO t2 VALUES(1, 'one'); 227 INSERT INTO t2 VALUES(2, 'two'); 228 INSERT INTO t2 VALUES(3, 'three'); 229 INSERT INTO t2 VALUES(4, 'four'); 230} 231do_db2_test 3.2.2 { 232 PRAGMA foreign_keys = on; 233 CREATE TABLE t2(a PRIMARY KEY, b); 234 CREATE TABLE t3(c, d REFERENCES t2); 235 INSERT INTO t2 VALUES(1, 'one'); 236 INSERT INTO t2 VALUES(2, 'two'); 237 INSERT INTO t2 VALUES(4, 'five'); 238 INSERT INTO t3 VALUES('i', 1); 239} 240do_conflict_test 3.2.3 -tables t2 -sql { 241 DELETE FROM t2 WHERE a = 1; 242 DELETE FROM t2 WHERE a = 2; 243 DELETE FROM t2 WHERE a = 3; 244 DELETE FROM t2 WHERE a = 4; 245} -conflicts { 246 {DELETE t2 NOTFOUND {i 3 t three}} 247 {DELETE t2 DATA {i 4 t four} {i 4 t five}} 248 {FOREIGN_KEY 1} 249} 250do_execsql_test 3.2.4 "SELECT * FROM t2" {} 251do_db2_test 3.2.5 "SELECT * FROM t2" {4 five} 252 253# Test UPDATE changesets. 254# 255do_execsql_test 3.3.1 { 256 CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c)); 257 INSERT INTO t4 VALUES(1, 2, 3); 258 INSERT INTO t4 VALUES(4, 5, 6); 259 INSERT INTO t4 VALUES(7, 8, 9); 260 INSERT INTO t4 VALUES(10, 11, 12); 261} 262do_db2_test 3.3.2 { 263 CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c)); 264 INSERT INTO t4 VALUES(0, 2, 3); 265 INSERT INTO t4 VALUES(4, 5, 7); 266 INSERT INTO t4 VALUES(7, 8, 9); 267 INSERT INTO t4 VALUES(10, 11, 12); 268} 269do_conflict_test 3.3.3 -tables t4 -sql { 270 UPDATE t4 SET a = -1 WHERE b = 2; 271 UPDATE t4 SET a = -1 WHERE b = 5; 272 UPDATE t4 SET a = NULL WHERE c = 9; 273 UPDATE t4 SET a = 'x' WHERE b = 11; 274} -conflicts { 275 {UPDATE t4 DATA {i 1 i 2 i 3} {i -1 {} {} {} {}} {i 0 i 2 i 3}} 276 {UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}} 277 {UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}} 278} 279do_db2_test 3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12} 280do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12} 281 282#------------------------------------------------------------------------- 283# This next block of tests verifies that values returned by the conflict 284# handler are intepreted correctly. 285# 286 287proc test_reset {} { 288 db close 289 db2 close 290 forcedelete test.db test.db2 291 sqlite3 db test.db 292 sqlite3 db2 test.db2 293} 294 295proc xConflict {args} { 296 lappend ::xConflict $args 297 return $::conflict_return 298} 299 300foreach {tn conflict_return after} { 301 1 OMIT {1 2 value1 4 5 7 10 x x} 302 2 REPLACE {1 2 value1 4 5 value2 10 8 9} 303} { 304 test_reset 305 306 do_test 4.$tn.1 { 307 foreach db {db db2} { 308 execsql { 309 CREATE TABLE t1(a, b, c, PRIMARY KEY(a)); 310 INSERT INTO t1 VALUES(1, 2, 3); 311 INSERT INTO t1 VALUES(4, 5, 6); 312 INSERT INTO t1 VALUES(7, 8, 9); 313 } $db 314 } 315 execsql { 316 REPLACE INTO t1 VALUES(4, 5, 7); 317 REPLACE INTO t1 VALUES(10, 'x', 'x'); 318 } db2 319 } {} 320 321 do_conflict_test 4.$tn.2 -tables t1 -sql { 322 UPDATE t1 SET c = 'value1' WHERE a = 1; -- no conflict 323 UPDATE t1 SET c = 'value2' WHERE a = 4; -- DATA conflict 324 UPDATE t1 SET a = 10 WHERE a = 7; -- CONFLICT conflict 325 } -conflicts { 326 {INSERT t1 CONFLICT {i 10 i 8 i 9} {i 10 t x t x}} 327 {UPDATE t1 DATA {i 4 {} {} i 6} {{} {} {} {} t value2} {i 4 i 5 i 7}} 328 } 329 330 do_db2_test 4.$tn.3 "SELECT * FROM t1 ORDER BY a" $after 331} 332 333foreach {tn conflict_return} { 334 1 OMIT 335 2 REPLACE 336} { 337 test_reset 338 339 do_test 5.$tn.1 { 340 # Create an identical schema in both databases. 341 set schema { 342 CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y)); 343 } 344 execsql $schema db 345 execsql $schema db2 346 347 # Add some rows to [db2]. These rows will cause conflicts later 348 # on when the changeset from [db] is applied to it. 349 execsql { 350 INSERT INTO "'foolish name'" VALUES('one', 'one', 'ii'); 351 INSERT INTO "'foolish name'" VALUES('one', 'two', 'i'); 352 INSERT INTO "'foolish name'" VALUES('two', 'two', 'ii'); 353 } db2 354 355 } {} 356 357 do_conflict_test 5.$tn.2 -tables {{'foolish name'}} -sql { 358 INSERT INTO "'foolish name'" VALUES('one', 'two', 2); 359 } -conflicts { 360 {INSERT {'foolish name'} CONFLICT {t one t two i 2} {t one t two t i}} 361 } 362 363 set res(REPLACE) {one one ii one two 2 two two ii} 364 set res(OMIT) {one one ii one two i two two ii} 365 do_db2_test 5.$tn.3 { 366 SELECT * FROM "'foolish name'" ORDER BY x, y 367 } $res($conflict_return) 368 369 370 do_test 5.$tn.1 { 371 set schema { 372 CREATE TABLE d1("z""z" PRIMARY KEY, y); 373 INSERT INTO d1 VALUES(1, 'one'); 374 INSERT INTO d1 VALUES(2, 'two'); 375 } 376 execsql $schema db 377 execsql $schema db2 378 379 execsql { 380 UPDATE d1 SET y = 'TWO' WHERE "z""z" = 2; 381 } db2 382 383 } {} 384 385 do_conflict_test 5.$tn.2 -tables d1 -sql { 386 DELETE FROM d1 WHERE "z""z" = 2; 387 } -conflicts { 388 {DELETE d1 DATA {i 2 t two} {i 2 t TWO}} 389 } 390 391 set res(REPLACE) {1 one} 392 set res(OMIT) {1 one 2 TWO} 393 do_db2_test 5.$tn.3 "SELECT * FROM d1" $res($conflict_return) 394} 395 396#------------------------------------------------------------------------- 397# Test that two tables can be monitored by a single session object. 398# 399test_reset 400set schema { 401 CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b); 402 CREATE TABLE t2(a, b PRIMARY KEY); 403} 404do_test 6.0 { 405 execsql $schema db 406 execsql $schema db2 407 execsql { 408 INSERT INTO t1 VALUES('a', 'b'); 409 INSERT INTO t2 VALUES('a', 'b'); 410 } db2 411} {} 412 413set conflict_return "" 414do_conflict_test 6.1 -tables {t1 t2} -sql { 415 INSERT INTO t1 VALUES('1', '2'); 416 INSERT INTO t1 VALUES('A', 'B'); 417 INSERT INTO t2 VALUES('A', 'B'); 418} -conflicts { 419 {INSERT t1 CONFLICT {t A t B} {t a t b}} 420} 421 422do_db2_test 6.2 "SELECT * FROM t1" {a b 1 2} 423do_db2_test 6.3 "SELECT * FROM t2" {a b A B} 424 425#------------------------------------------------------------------------- 426# Test that session objects are not confused by changes to table in 427# other databases. 428# 429catch { db2 close } 430drop_all_tables 431forcedelete test.db2 432do_iterator_test 7.1 * { 433 ATTACH 'test.db2' AS aux; 434 CREATE TABLE main.t1(x PRIMARY KEY, y); 435 CREATE TABLE aux.t1(x PRIMARY KEY, y); 436 437 INSERT INTO main.t1 VALUES('one', 1); 438 INSERT INTO main.t1 VALUES('two', 2); 439 INSERT INTO aux.t1 VALUES('three', 3); 440 INSERT INTO aux.t1 VALUES('four', 4); 441} { 442 {INSERT t1 0 X. {} {t two i 2}} 443 {INSERT t1 0 X. {} {t one i 1}} 444} 445 446#------------------------------------------------------------------------- 447# Test the sqlite3session_isempty() function. 448# 449do_test 8.1 { 450 execsql { 451 CREATE TABLE t5(x PRIMARY KEY, y); 452 CREATE TABLE t6(x PRIMARY KEY, y); 453 INSERT INTO t5 VALUES('a', 'b'); 454 INSERT INTO t6 VALUES('a', 'b'); 455 } 456 sqlite3session S db main 457 S attach * 458 459 S isempty 460} {1} 461do_test 8.2 { 462 execsql { DELETE FROM t5 } 463 S isempty 464} {0} 465do_test 8.3 { 466 S delete 467 sqlite3session S db main 468 S attach t5 469 execsql { DELETE FROM t5 } 470 S isempty 471} {1} 472do_test 8.4 { S delete } {} 473 474do_test 8.5 { 475 sqlite3session S db main 476 S attach t5 477 S attach t6 478 execsql { INSERT INTO t5 VALUES(1, 2) } 479 S isempty 480} {0} 481 482do_test 8.6 { 483 S delete 484 sqlite3session S db main 485 S attach t5 486 S attach t6 487 execsql { INSERT INTO t6 VALUES(1, 2) } 488 S isempty 489} {0} 490do_test 8.7 { S delete } {} 491 492#------------------------------------------------------------------------- 493# 494do_execsql_test 9.1 { 495 CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g); 496 INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1); 497} 498do_test 9.2 { 499 sqlite3session S db main 500 S attach * 501 execsql { UPDATE t7 SET b=2, d=2 } 502} {} 503do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}} 504S delete 505catch { db2 close } 506 507#------------------------------------------------------------------------- 508# Test a really long table name. 509# 510reset_db 511set tblname [string repeat tblname123 100] 512do_test 10.1.1 { 513 execsql " 514 CREATE TABLE $tblname (a PRIMARY KEY, b); 515 INSERT INTO $tblname VALUES('xyz', 'def'); 516 " 517 sqlite3session S db main 518 S attach $tblname 519 execsql " 520 INSERT INTO $tblname VALUES('uvw', 'abc'); 521 DELETE FROM $tblname WHERE a = 'xyz'; 522 " 523} {} 524breakpoint 525do_changeset_test 10.1.2 S " 526 {INSERT $tblname 0 X. {} {t uvw t abc}} 527 {DELETE $tblname 0 X. {t xyz t def} {}} 528" 529do_test 10.1.4 { S delete } {} 530 531#--------------------------------------------------------------- 532reset_db 533do_execsql_test 11.1 { 534 CREATE TABLE t1(a, b); 535} 536do_test 11.2 { 537 sqlite3session S db main 538 S attach t1 539 execsql { 540 INSERT INTO t1 VALUES(1, 2); 541 } 542 S changeset 543} {} 544 545S delete 546 547 548#------------------------------------------------------------------------- 549# Test a really long table name. 550# 551reset_db 552set tblname [string repeat tblname123 100] 553do_test 10.1.1 { 554 execsql " 555 CREATE TABLE $tblname (a PRIMARY KEY, b); 556 INSERT INTO $tblname VALUES('xyz', 'def'); 557 " 558 sqlite3session S db main 559 S attach $tblname 560 execsql " 561 INSERT INTO $tblname VALUES('uvw', 'abc'); 562 DELETE FROM $tblname WHERE a = 'xyz'; 563 " 564} {} 565breakpoint 566do_changeset_test 10.1.2 S " 567 {INSERT $tblname 0 X. {} {t uvw t abc}} 568 {DELETE $tblname 0 X. {t xyz t def} {}} 569" 570do_test 10.1.4 { S delete } {} 571 572 573finish_test 574