1# 2011 April 13 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 the session module. 12# Specifically, for the sqlite3changeset_concat() command. 13# 14 15if {![info exists testdir]} { 16 set testdir [file join [file dirname [info script]] .. .. test] 17} 18source [file join [file dirname [info script]] session_common.tcl] 19source $testdir/tester.tcl 20ifcapable !session {finish_test; return} 21 22set testprefix session5 23 24# Organization of tests: 25# 26# session5-1.*: Simple tests to check the concat() function produces 27# correct results. 28# 29# session5-2.*: More complicated tests. 30# 31# session5-3.*: Schema mismatch errors. 32# 33# session5-4.*: Test the concat cases that indicate that the database 34# was modified in between recording of the two changesets 35# being concatenated (i.e. two changesets that INSERT rows 36# with the same PK values). 37# 38 39proc do_concat_test {tn args} { 40 41 set subtest 0 42 foreach sql $args { 43 incr subtest 44 sqlite3session S db main ; S attach * 45 execsql $sql 46 47 set c [S changeset] 48 if {[info commands s_prev] != ""} { 49 set c_concat [sqlite3changeset_concat $c_prev $c] 50 set c_two [s_prev changeset] 51 s_prev delete 52 53 set h_concat [changeset_to_list $c_concat] 54 set h_two [changeset_to_list $c_two] 55 56 do_test $tn.$subtest [list set {} $h_concat] $h_two 57 } 58 set c_prev $c 59 rename S s_prev 60 } 61 62 catch { s_prev delete } 63} 64 65#------------------------------------------------------------------------- 66# Test cases session5-1.* - simple tests. 67# 68do_execsql_test 1.0 { 69 CREATE TABLE t1(a PRIMARY KEY, b); 70} 71 72do_concat_test 1.1.1 { 73 INSERT INTO t1 VALUES(1, 'one'); 74} { 75 INSERT INTO t1 VALUES(2, 'two'); 76} 77 78do_concat_test 1.1.2 { 79 UPDATE t1 SET b = 'five' WHERE a = 1; 80} { 81 UPDATE t1 SET b = 'six' WHERE a = 2; 82} 83 84do_concat_test 1.1.3 { 85 DELETE FROM t1 WHERE a = 1; 86} { 87 DELETE FROM t1 WHERE a = 2; 88} 89 90 91# 1.2.1: INSERT + DELETE -> (none) 92# 1.2.2: INSERT + UPDATE -> INSERT 93# 94# 1.2.3: DELETE + INSERT (matching data) -> (none) 95# 1.2.4: DELETE + INSERT (non-matching data) -> UPDATE 96# 97# 1.2.5: UPDATE + UPDATE (matching data) -> (none) 98# 1.2.6: UPDATE + UPDATE (non-matching data) -> UPDATE 99# 1.2.7: UPDATE + DELETE -> DELETE 100# 101do_concat_test 1.2.1 { 102 INSERT INTO t1 VALUES('x', 'y'); 103} { 104 DELETE FROM t1 WHERE a = 'x'; 105} 106do_concat_test 1.2.2 { 107 INSERT INTO t1 VALUES(5.0, 'five'); 108} { 109 UPDATE t1 SET b = 'six' WHERE a = 5.0; 110} 111 112do_execsql_test 1.2.3.1 "INSERT INTO t1 VALUES('I', 'one')" 113do_concat_test 1.2.3.2 { 114 DELETE FROM t1 WHERE a = 'I'; 115} { 116 INSERT INTO t1 VALUES('I', 'one'); 117} 118do_concat_test 1.2.4 { 119 DELETE FROM t1 WHERE a = 'I'; 120} { 121 INSERT INTO t1 VALUES('I', 'two'); 122} 123do_concat_test 1.2.5 { 124 UPDATE t1 SET b = 'five' WHERE a = 'I'; 125} { 126 UPDATE t1 SET b = 'two' WHERE a = 'I'; 127} 128do_concat_test 1.2.6 { 129 UPDATE t1 SET b = 'six' WHERE a = 'I'; 130} { 131 UPDATE t1 SET b = 'seven' WHERE a = 'I'; 132} 133do_concat_test 1.2.7 { 134 UPDATE t1 SET b = 'eight' WHERE a = 'I'; 135} { 136 DELETE FROM t1 WHERE a = 'I'; 137} 138 139 140#------------------------------------------------------------------------- 141# Test cases session5-2.* - more complex tests. 142# 143db function indirect indirect 144proc indirect {{x -1}} { 145 S indirect $x 146 s_prev indirect $x 147} 148do_concat_test 2.1 { 149 CREATE TABLE abc(a, b, c PRIMARY KEY); 150 INSERT INTO abc VALUES(NULL, NULL, 1); 151 INSERT INTO abc VALUES('abcdefghijkl', NULL, 2); 152} { 153 DELETE FROM abc WHERE c = 1; 154 UPDATE abc SET c = 1 WHERE c = 2; 155} { 156 INSERT INTO abc VALUES('abcdefghijkl', NULL, 2); 157 INSERT INTO abc VALUES(1.0, 2.0, 3); 158} { 159 UPDATE abc SET a = a-1; 160} { 161 CREATE TABLE def(d, e, f, PRIMARY KEY(e, f)); 162 INSERT INTO def VALUES('x', randomblob(11000), 67); 163 INSERT INTO def SELECT d, e, f+1 FROM def; 164 INSERT INTO def SELECT d, e, f+2 FROM def; 165 INSERT INTO def SELECT d, e, f+4 FROM def; 166} { 167 DELETE FROM def WHERE rowid>4; 168} { 169 INSERT INTO def SELECT d, e, f+4 FROM def; 170} { 171 INSERT INTO abc VALUES(22, 44, -1); 172} { 173 UPDATE abc SET c=-2 WHERE c=-1; 174 UPDATE abc SET c=-3 WHERE c=-2; 175} { 176 UPDATE abc SET c=-4 WHERE c=-3; 177} { 178 UPDATE abc SET a=a+1 WHERE c=-3; 179 UPDATE abc SET a=a+1 WHERE c=-3; 180} { 181 UPDATE abc SET a=a+1 WHERE c=-3; 182 UPDATE abc SET a=a+1 WHERE c=-3; 183} { 184 INSERT INTO abc VALUES('one', 'two', 'three'); 185} { 186 SELECT indirect(1); 187 UPDATE abc SET a='one point five' WHERE c = 'three'; 188} { 189 SELECT indirect(0); 190 UPDATE abc SET a='one point six' WHERE c = 'three'; 191} { 192 CREATE TABLE x1(a, b, PRIMARY KEY(a)); 193 SELECT indirect(1); 194 INSERT INTO x1 VALUES(1, 2); 195} { 196 SELECT indirect(1); 197 UPDATE x1 SET b = 3 WHERE a = 1; 198} 199 200catch {db close} 201forcedelete test.db 202sqlite3 db test.db 203do_concat_test 2.2 { 204 CREATE TABLE t1(a, b, PRIMARY KEY(b)); 205 CREATE TABLE t2(a PRIMARY KEY, b); 206 INSERT INTO t1 VALUES('string', 1); 207 INSERT INTO t1 VALUES(4, 2); 208 INSERT INTO t1 VALUES(X'FFAAFFAAFFAA', 3); 209} { 210 INSERT INTO t2 VALUES('one', 'two'); 211 INSERT INTO t2 VALUES(1, NULL); 212 UPDATE t1 SET a = 5 WHERE a = 2; 213} { 214 DELETE FROM t2 WHERE a = 1; 215 UPDATE t1 SET a = 4 WHERE a = 2; 216 INSERT INTO t2 VALUES('x', 'y'); 217} 218 219do_test 2.3.0 { 220 catch {db close} 221 forcedelete test.db 222 sqlite3 db test.db 223 224 set sql1 "" 225 set sql2 "" 226 for {set i 1} {$i < 120} {incr i} { 227 append sql1 "INSERT INTO x1 VALUES($i*4, $i);" 228 } 229 for {set i 1} {$i < 120} {incr i} { 230 append sql2 "DELETE FROM x1 WHERE a = $i*4;" 231 } 232 set {} {} 233} {} 234do_concat_test 2.3 { 235 CREATE TABLE x1(a PRIMARY KEY, b) 236} $sql1 $sql2 $sql1 $sql2 237 238do_concat_test 2.4 { 239 CREATE TABLE x2(a PRIMARY KEY, b); 240 CREATE TABLE x3(a PRIMARY KEY, b); 241 242 INSERT INTO x2 VALUES('a', 'b'); 243 INSERT INTO x2 VALUES('x', 'y'); 244 INSERT INTO x3 VALUES('a', 'b'); 245} { 246 INSERT INTO x2 VALUES('c', 'd'); 247 INSERT INTO x3 VALUES('e', 'f'); 248 INSERT INTO x3 VALUES('x', 'y'); 249} 250 251do_concat_test 2.5 { 252 UPDATE x3 SET b = 'Y' WHERE a = 'x' 253} { 254 DELETE FROM x3 WHERE a = 'x' 255} { 256 DELETE FROM x2 WHERE a = 'a' 257} { 258 INSERT INTO x2 VALUES('a', 'B'); 259} 260 261for {set k 1} {$k <=10} {incr k} { 262 do_test 2.6.$k.1 { 263 drop_all_tables 264 set sql1 "" 265 set sql2 "" 266 for {set i 1} {$i < 120} {incr i} { 267 append sql1 "INSERT INTO x1 VALUES(randomblob(20+(random()%10)), $i);" 268 } 269 for {set i 1} {$i < 120} {incr i} { 270 append sql2 "DELETE FROM x1 WHERE rowid = $i;" 271 } 272 set {} {} 273 } {} 274 do_concat_test 2.6.$k { 275 CREATE TABLE x1(a PRIMARY KEY, b) 276 } $sql1 $sql2 $sql1 $sql2 277} 278 279for {set k 1} {$k <=10} {incr k} { 280 do_test 2.7.$k.1 { 281 drop_all_tables 282 set sql1 "" 283 set sql2 "" 284 for {set i 1} {$i < 120} {incr i} { 285 append sql1 { 286 INSERT INTO x1 VALUES( 287 CASE WHEN random()%2 THEN random() ELSE randomblob(20+random()%10) END, 288 CASE WHEN random()%2 THEN random() ELSE randomblob(20+random()%10) END 289 ); 290 } 291 } 292 for {set i 1} {$i < 120} {incr i} { 293 append sql2 "DELETE FROM x1 WHERE rowid = $i;" 294 } 295 set {} {} 296 } {} 297 do_concat_test 2.7.$k { 298 CREATE TABLE x1(a PRIMARY KEY, b) 299 } $sql1 $sql2 $sql1 $sql2 300} 301 302 303#------------------------------------------------------------------------- 304# Test that schema incompatibilities are detected correctly. 305# 306# session5-3.1: Incompatible number of columns. 307# session5-3.2: Incompatible PK definition. 308# 309 310do_test 3.1 { 311 db close 312 forcedelete test.db 313 sqlite3 db test.db 314 315 execsql { CREATE TABLE t1(a PRIMARY KEY, b) } 316 set c1 [changeset_from_sql { INSERT INTO t1 VALUES(1, 2) }] 317 execsql { 318 DROP TABLE t1; 319 CREATE TABLE t1(a PRIMARY KEY, b, c); 320 } 321 set c2 [changeset_from_sql { INSERT INTO t1 VALUES(2, 3, 4) }] 322 323 list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg 324} {1 SQLITE_SCHEMA} 325 326do_test 3.2 { 327 db close 328 forcedelete test.db 329 sqlite3 db test.db 330 331 execsql { CREATE TABLE t1(a PRIMARY KEY, b) } 332 set c1 [changeset_from_sql { INSERT INTO t1 VALUES(1, 2) }] 333 execsql { 334 DROP TABLE t1; 335 CREATE TABLE t1(a, b PRIMARY KEY); 336 } 337 set c2 [changeset_from_sql { INSERT INTO t1 VALUES(2, 3) }] 338 339 list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg 340} {1 SQLITE_SCHEMA} 341 342#------------------------------------------------------------------------- 343# Test that concat() handles these properly: 344# 345# session5-4.1: INSERT + INSERT 346# session5-4.2: UPDATE + INSERT 347# session5-4.3: DELETE + UPDATE 348# session5-4.4: DELETE + DELETE 349# 350 351proc do_concat_test2 {tn sql1 sqlX sql2 expected} { 352 sqlite3session S db main ; S attach * 353 execsql $sql1 354 set ::c1 [S changeset] 355 S delete 356 357 execsql $sqlX 358 359 sqlite3session S db main ; S attach * 360 execsql $sql2 361 set ::c2 [S changeset] 362 S delete 363 364 uplevel do_test $tn [list { 365 changeset_to_list [sqlite3changeset_concat $::c1 $::c2] 366 }] [list [normalize_list $expected]] 367} 368 369drop_all_tables db 370do_concat_test2 4.1 { 371 CREATE TABLE t1(a PRIMARY KEY, b); 372 INSERT INTO t1 VALUES('key', 'value'); 373} { 374 DELETE FROM t1 WHERE a = 'key'; 375} { 376 INSERT INTO t1 VALUES('key', 'xxx'); 377} { 378 {INSERT t1 0 X. {} {t key t value}} 379} 380do_concat_test2 4.2 { 381 UPDATE t1 SET b = 'yyy'; 382} { 383 DELETE FROM t1 WHERE a = 'key'; 384} { 385 INSERT INTO t1 VALUES('key', 'value'); 386} { 387 {UPDATE t1 0 X. {t key t xxx} {{} {} t yyy}} 388} 389do_concat_test2 4.3 { 390 DELETE FROM t1 WHERE a = 'key'; 391} { 392 INSERT INTO t1 VALUES('key', 'www'); 393} { 394 UPDATE t1 SET b = 'valueX' WHERE a = 'key'; 395} { 396 {DELETE t1 0 X. {t key t value} {}} 397} 398do_concat_test2 4.4 { 399 DELETE FROM t1 WHERE a = 'key'; 400} { 401 INSERT INTO t1 VALUES('key', 'ttt'); 402} { 403 DELETE FROM t1 WHERE a = 'key'; 404} { 405 {DELETE t1 0 X. {t key t valueX} {}} 406} 407 408finish_test 409