gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/backcompat.test (about) 1 # 2010 August 19 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. The 12 # focus of this file is testing that the current version of SQLite 13 # is capable of reading and writing databases created by previous 14 # versions, and vice-versa. 15 # 16 # To use this test, old versions of the testfixture process should be 17 # copied into the working directory alongside the new version. The old 18 # versions should be named "testfixtureXXX" (or testfixtureXXX.exe on 19 # windows), where XXX can be any string. 20 # 21 # This test file uses the tcl code for controlling a second testfixture 22 # process located in lock_common.tcl. See the commments in lock_common.tcl 23 # for documentation of the available commands. 24 # 25 26 set testdir [file dirname $argv0] 27 source $testdir/tester.tcl 28 source $testdir/lock_common.tcl 29 source $testdir/malloc_common.tcl 30 source $testdir/bc_common.tcl 31 db close 32 33 if {"" == [bc_find_binaries backcompat.test]} { 34 finish_test 35 return 36 } 37 38 proc do_backcompat_test {rv bin1 bin2 script} { 39 40 forcedelete test.db 41 42 if {$bin1 != ""} { set ::bc_chan1 [launch_testfixture $bin1] } 43 set ::bc_chan2 [launch_testfixture $bin2] 44 45 if { $rv } { 46 proc code2 {tcl} { uplevel #0 $tcl } 47 if {$bin1 != ""} { proc code2 {tcl} { testfixture $::bc_chan1 $tcl } } 48 proc code1 {tcl} { testfixture $::bc_chan2 $tcl } 49 } else { 50 proc code1 {tcl} { uplevel #0 $tcl } 51 if {$bin1 != ""} { proc code1 {tcl} { testfixture $::bc_chan1 $tcl } } 52 proc code2 {tcl} { testfixture $::bc_chan2 $tcl } 53 } 54 55 proc sql1 sql { code1 [list db eval $sql] } 56 proc sql2 sql { code2 [list db eval $sql] } 57 58 code1 { sqlite3 db test.db } 59 code2 { sqlite3 db test.db } 60 61 foreach c {code1 code2} { 62 $c { 63 set v [split [db version] .] 64 if {[llength $v]==3} {lappend v 0} 65 set ::sqlite_libversion [format \ 66 "%d%.2d%.2d%.2d" [lindex $v 0] [lindex $v 1] [lindex $v 2] [lindex $v 3] 67 ] 68 } 69 } 70 71 uplevel $script 72 73 catch { code1 { db close } } 74 catch { code2 { db close } } 75 catch { close $::bc_chan2 } 76 catch { close $::bc_chan1 } 77 78 79 } 80 81 array set ::incompatible [list] 82 proc do_allbackcompat_test {script} { 83 84 foreach bin $::BC(binaries) { 85 set nErr [set_test_counter errors] 86 foreach dir {0 1} { 87 88 set bintag $bin 89 regsub {.*testfixture\.} $bintag {} bintag 90 set bintag [string map {\.exe {}} $bintag] 91 if {$bintag == ""} {set bintag self} 92 set ::bcname ".$bintag.$dir." 93 94 rename do_test _do_test 95 proc do_test {nm sql res} { 96 set nm [regsub {\.} $nm $::bcname] 97 uplevel [list _do_test $nm $sql $res] 98 } 99 100 do_backcompat_test $dir {} $bin $script 101 102 rename do_test {} 103 rename _do_test do_test 104 } 105 if { $nErr < [set_test_counter errors] } { 106 set ::incompatible([get_version $bin]) 1 107 } 108 } 109 } 110 111 proc read_file {zFile} { 112 set zData {} 113 if {[file exists $zFile]} { 114 set fd [open $zFile] 115 fconfigure $fd -translation binary -encoding binary 116 117 if {[file size $zFile]<=$::sqlite_pending_byte || $zFile != "test.db"} { 118 set zData [read $fd] 119 } else { 120 set zData [read $fd $::sqlite_pending_byte] 121 append zData [string repeat x 512] 122 seek $fd [expr $::sqlite_pending_byte+512] start 123 append zData [read $fd] 124 } 125 126 close $fd 127 } 128 return $zData 129 } 130 proc write_file {zFile zData} { 131 set fd [open $zFile w] 132 fconfigure $fd -translation binary -encoding binary 133 puts -nonewline $fd $zData 134 close $fd 135 } 136 proc read_file_system {} { 137 set ret [list] 138 foreach f {test.db test.db-journal test.db-wal} { lappend ret [read_file $f] } 139 set ret 140 } 141 proc write_file_system {data} { 142 foreach f {test.db test.db-journal test.db-wal} d $data { 143 if {[string length $d] == 0} { 144 forcedelete $f 145 } else { 146 write_file $f $d 147 } 148 } 149 } 150 151 #------------------------------------------------------------------------- 152 # Actual tests begin here. 153 # 154 # This first block of tests checks to see that the same database and 155 # journal files can be used by old and new versions. WAL and wal-index 156 # files are tested separately below. 157 # 158 do_allbackcompat_test { 159 160 # Test that database files are backwards compatible. 161 # 162 do_test backcompat-1.1.1 { sql1 { 163 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); 164 INSERT INTO t1 VALUES('abc', 'def'); 165 } } {} 166 do_test backcompat-1.1.2 { sql2 { SELECT * FROM t1; } } {abc def} 167 do_test backcompat-1.1.3 { sql2 { INSERT INTO t1 VALUES('ghi', 'jkl'); } } {} 168 do_test backcompat-1.1.4 { sql1 { SELECT * FROM t1; } } {abc def ghi jkl} 169 do_test backcompat-1.1.5 { sql1 { PRAGMA integrity_check } } {ok} 170 do_test backcompat-1.1.6 { sql2 { PRAGMA integrity_check } } {ok} 171 172 # Test that one version can roll back a hot-journal file left in the 173 # file-system by the other version. 174 # 175 # Each test case is named "backcompat-1.X...", where X is either 0 or 176 # 1. If it is 0, then the current version creates a journal file that 177 # the old versions try to read. Otherwise, if X is 1, then the old version 178 # creates the journal file and we try to read it with the current version. 179 # 180 do_test backcompat-1.2.1 { sql1 { 181 PRAGMA cache_size = 10; 182 BEGIN; 183 INSERT INTO t1 VALUES(randomblob(400), randomblob(400)); 184 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1; 185 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1; 186 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1; 187 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1; 188 COMMIT; 189 } } {} 190 set cksum1 [sql1 {SELECT md5sum(a), md5sum(b) FROM t1}] 191 set cksum2 [sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] 192 do_test backcompat-1.2.2 [list string compare $cksum1 $cksum2] 0 193 194 do_test backcompat-1.2.3 { sql1 { 195 BEGIN; 196 UPDATE t1 SET a = randomblob(500); 197 } } {} 198 set data [read_file_system] 199 200 do_test backcompat-1.2.4 { sql1 { COMMIT } } {} 201 202 set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}] 203 do_test backcompat-1.2.5 [list set {} $same] 0 204 205 code1 { db close } 206 code2 { db close } 207 write_file_system $data 208 code1 { sqlite3 db test.db } 209 code2 { sqlite3 db test.db } 210 211 set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}] 212 do_test backcompat-1.2.6 [list set {} $same] 1 213 214 do_test backcompat-1.2.7 { sql1 { PRAGMA integrity_check } } {ok} 215 do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok} 216 217 do_test backcompat-2.1 { 218 sql1 { 219 CREATE TABLE t2(a UNIQUE, b PRIMARY KEY, c UNIQUE); 220 INSERT INTO t2 VALUES(1,9,5); 221 INSERT INTO t2 VALUES(5,5,1); 222 INSERT INTO t2 VALUES(9,1,9); 223 SELECT * FROM t2 ORDER BY a; 224 } 225 } {1 9 5 5 5 1 9 1 9} 226 do_test backcompat-2.2 { 227 sql2 { 228 SELECT * FROM sqlite_master WHERE rootpage=-1; 229 SELECT * FROM t2 ORDER BY a; 230 } 231 } {1 9 5 5 5 1 9 1 9} 232 do_test backcompat-2.3 { 233 sql1 { 234 SELECT * FROM t2 ORDER BY b; 235 } 236 } {9 1 9 5 5 1 1 9 5} 237 do_test backcompat-2.4 { 238 sql2 { 239 SELECT * FROM t2 ORDER BY b; 240 } 241 } {9 1 9 5 5 1 1 9 5} 242 do_test backcompat-2.5 { 243 sql1 { 244 SELECT * FROM t2 ORDER BY c; 245 } 246 } {5 5 1 1 9 5 9 1 9} 247 do_test backcompat-2.6 { 248 sql2 { 249 SELECT * FROM t2 ORDER BY c; 250 } 251 } {5 5 1 1 9 5 9 1 9} 252 } 253 foreach k [lsort [array names ::incompatible]] { 254 puts "ERROR: Detected journal incompatibility with version $k" 255 } 256 unset ::incompatible 257 258 259 #------------------------------------------------------------------------- 260 # Test that WAL and wal-index files may be shared between different 261 # SQLite versions. 262 # 263 do_allbackcompat_test { 264 if {[code1 {sqlite3 -version}] >= "3.7.0" 265 && [code1 {set ::sqlite_options(wal)}] 266 && [code2 {sqlite3 -version}] >= "3.7.0" 267 && [code2 {set ::sqlite_options(wal)}] 268 } { 269 270 do_test backcompat-2.1.1 { sql1 { 271 PRAGMA journal_mode = WAL; 272 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); 273 INSERT INTO t1 VALUES('I', 1); 274 INSERT INTO t1 VALUES('II', 2); 275 INSERT INTO t1 VALUES('III', 3); 276 SELECT * FROM t1; 277 } } {wal I 1 II 2 III 3} 278 do_test backcompat-2.1.2 { sql2 { 279 SELECT * FROM t1; 280 } } {I 1 II 2 III 3} 281 282 set data [read_file_system] 283 code1 {db close} 284 code2 {db close} 285 write_file_system $data 286 code1 {sqlite3 db test.db} 287 code2 {sqlite3 db test.db} 288 289 # The WAL file now in the file-system was created by the [code1] 290 # process. Check that the [code2] process can recover the log. 291 # 292 do_test backcompat-2.1.3 { sql2 { 293 SELECT * FROM t1; 294 } } {I 1 II 2 III 3} 295 do_test backcompat-2.1.4 { sql1 { 296 SELECT * FROM t1; 297 } } {I 1 II 2 III 3} 298 } 299 } 300 301 #------------------------------------------------------------------------- 302 # Test that FTS3 tables may be read/written by different versions of 303 # SQLite. 304 # 305 ifcapable fts3 { 306 set contents { 307 CREATE VIRTUAL TABLE t1 USING fts3(a, b); 308 } 309 foreach {num doc} { 310 one "jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf" 311 two "jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh" 312 three "wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw" 313 four "gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh" 314 five "zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm" 315 six "sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju" 316 seven "vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj" 317 eight "zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk" 318 nine "zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk" 319 } { 320 append contents "INSERT INTO t1 VALUES('$num', '$doc');" 321 } 322 do_allbackcompat_test { 323 if {[code1 {set ::sqlite_options(fts3)}] 324 && [code2 {set ::sqlite_options(fts3)}] 325 } { 326 327 do_test backcompat-3.1 { sql1 $contents } {} 328 329 foreach {n q} { 330 1 "SELECT * FROM t1 ORDER BY a, b" 331 2 "SELECT rowid FROM t1 WHERE a MATCH 'five'" 332 3 "SELECT * FROM t1 WHERE a MATCH 'five'" 333 4 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'" 334 5 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'" 335 } { 336 do_test backcompat-3.2 [list sql1 $q] [sql2 $q] 337 } 338 339 do_test backcompat-3.3 { sql1 { 340 INSERT INTO t1 SELECT * FROM t1; 341 INSERT INTO t1 SELECT * FROM t1; 342 INSERT INTO t1 SELECT * FROM t1; 343 INSERT INTO t1 SELECT * FROM t1; 344 INSERT INTO t1 SELECT * FROM t1; 345 INSERT INTO t1 SELECT * FROM t1; 346 INSERT INTO t1 SELECT * FROM t1; 347 INSERT INTO t1 SELECT * FROM t1; 348 } } {} 349 350 foreach {n q} { 351 1 "SELECT * FROM t1 ORDER BY a, b" 352 2 "SELECT rowid FROM t1 WHERE a MATCH 'five'" 353 3 "SELECT * FROM t1 WHERE a MATCH 'five'" 354 4 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'" 355 5 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'" 356 } { 357 do_test backcompat-3.4 [list sql1 $q] [sql2 $q] 358 } 359 360 set alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4" 361 for {set i 0} {$i < 900} {incr i} { 362 set term "[lindex $alphabet [expr $i/30]][lindex $alphabet [expr $i%30]] " 363 sql1 "INSERT INTO t1 VALUES($i, '[string repeat $term 14]')" 364 } 365 366 foreach {n q} { 367 1 "SELECT * FROM t1 ORDER BY a, b" 368 2 "SELECT rowid FROM t1 WHERE a MATCH 'five'" 369 3 "SELECT * FROM t1 WHERE a MATCH 'five'" 370 4 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'" 371 5 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'" 372 373 6 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'" 374 7 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'" 375 8 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'" 376 } { 377 do_test backcompat-3.5 [list sql1 $q] [sql2 $q] 378 } 379 380 do_test backcompat-3.6 { 381 sql1 "SELECT optimize(t1) FROM t1 LIMIT 1" 382 } {{Index optimized}} 383 384 foreach {n q} { 385 1 "SELECT * FROM t1 ORDER BY a, b" 386 2 "SELECT rowid FROM t1 WHERE a MATCH 'five'" 387 3 "SELECT * FROM t1 WHERE a MATCH 'five'" 388 4 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'" 389 5 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'" 390 391 6 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'" 392 7 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'" 393 8 "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'" 394 } { 395 do_test backcompat-3.7 [list sql1 $q] [sql2 $q] 396 } 397 398 # Now test that an incremental merge can be started by one version 399 # and finished by another. And that the integrity-check still 400 # passes. 401 do_test backcompat-3.8 { 402 sql1 { 403 DROP TABLE IF EXISTS t1; 404 DROP TABLE IF EXISTS t2; 405 CREATE TABLE t1(docid, words); 406 CREATE VIRTUAL TABLE t2 USING fts3(words); 407 } 408 code1 [list source $testdir/genesis.tcl] 409 code1 { fts_kjv_genesis } 410 sql1 { 411 INSERT INTO t2 SELECT words FROM t1; 412 INSERT INTO t2 SELECT words FROM t1; 413 INSERT INTO t2 SELECT words FROM t1; 414 INSERT INTO t2 SELECT words FROM t1; 415 INSERT INTO t2 SELECT words FROM t1; 416 INSERT INTO t2 SELECT words FROM t1; 417 SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level; 418 } 419 } {0 {0 1 2 3 4 5}} 420 421 if {[code1 { set ::sqlite_libversion }] >=3071200 422 && [code2 { set ::sqlite_libversion }] >=3071200 423 } { 424 if {[code1 { set ::sqlite_libversion }]<3120000} { 425 set res {0 {0 1} 1 0} 426 } else { 427 set res {1 0} 428 } 429 430 do_test backcompat-3.9 { 431 sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } 432 sql2 { INSERT INTO t2(t2) VALUES('merge=100,4'); } 433 sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } 434 sql2 { INSERT INTO t2(t2) VALUES('merge=2500,4'); } 435 sql2 { 436 SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level; 437 } 438 } $res 439 440 do_test backcompat-3.10 { 441 sql1 { INSERT INTO t2(t2) VALUES('integrity-check') } 442 sql2 { INSERT INTO t2(t2) VALUES('integrity-check') } 443 } {} 444 } 445 } 446 } 447 } 448 449 #------------------------------------------------------------------------- 450 # Test that Rtree tables may be read/written by different versions of 451 # SQLite. 452 # 453 ifcapable rtree { 454 set contents { 455 CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2); 456 } 457 foreach {id x1 x2 y1 y2} { 458 1 -47.64 43.87 33.86 34.42 2 -21.51 17.32 2.05 31.04 459 3 -43.67 -38.33 -19.79 3.43 4 32.41 35.16 9.12 19.82 460 5 33.28 34.87 14.78 28.26 6 49.31 116.59 -9.87 75.09 461 7 -14.93 34.51 -17.64 64.09 8 -43.05 23.43 -1.19 69.44 462 9 44.79 133.56 28.09 80.30 10 -2.66 81.47 -41.38 -10.46 463 11 -42.89 -3.54 15.76 71.63 12 -3.50 84.96 -11.64 64.95 464 13 -45.69 26.25 11.14 55.06 14 -44.09 11.23 17.52 44.45 465 15 36.23 133.49 -19.38 53.67 16 -17.89 81.54 14.64 50.61 466 17 -41.97 -24.04 -39.43 28.95 18 -5.85 7.76 -6.38 47.02 467 19 18.82 27.10 42.82 100.09 20 39.17 113.45 26.14 73.47 468 21 22.31 103.17 49.92 106.05 22 -43.06 40.38 -1.75 76.08 469 23 2.43 57.27 -14.19 -3.83 24 -47.57 -4.35 8.93 100.06 470 25 -37.47 49.14 -29.11 8.81 26 -7.86 75.72 49.34 107.42 471 27 1.53 45.49 20.36 49.74 28 -48.48 32.54 28.81 54.45 472 29 2.67 39.77 -4.05 13.67 30 4.11 62.88 -47.44 -5.72 473 31 -21.47 51.75 37.25 116.09 32 45.59 111.37 -6.43 43.64 474 33 35.23 48.29 23.54 113.33 34 16.61 68.35 -14.69 65.97 475 35 13.98 16.60 48.66 102.87 36 19.74 23.84 31.15 77.27 476 37 -27.61 24.43 7.96 94.91 38 -34.77 12.05 -22.60 -6.29 477 39 -25.83 8.71 -13.48 -12.53 40 -17.11 -1.01 18.06 67.89 478 41 14.13 71.72 -3.78 39.25 42 23.75 76.00 -16.30 8.23 479 43 -39.15 28.63 38.12 125.88 44 48.62 86.09 36.49 102.95 480 45 -31.39 -21.98 2.52 89.78 46 5.65 56.04 15.94 89.10 481 47 18.28 95.81 46.46 143.08 48 30.93 102.82 -20.08 37.36 482 49 -20.78 -3.48 -5.58 35.46 50 49.85 90.58 -24.48 46.29 483 } { 484 if {$x1 >= $x2 || $y1 >= $y2} { error "$x1 $x2 $y1 $y2" } 485 append contents "INSERT INTO t1 VALUES($id, $x1, $x2, $y1, $y2);" 486 } 487 set queries { 488 1 "SELECT id FROM t1 WHERE x1>10 AND x2<44" 489 2 "SELECT id FROM t1 WHERE y1<100" 490 3 "SELECT id FROM t1 WHERE y1<100 AND x1>0" 491 4 "SELECT id FROM t1 WHERE y1>10 AND x1>0 AND x2<50 AND y2<550" 492 } 493 do_allbackcompat_test { 494 if {[code1 {set ::sqlite_options(fts3)}] 495 && [code2 {set ::sqlite_options(fts3)}] 496 } { 497 498 do_test backcompat-4.1 { sql1 $contents } {} 499 500 foreach {n q} $::queries { 501 do_test backcompat-4.2.$n [list sql1 $q] [sql2 $q] 502 } 503 504 do_test backcompat-4.3 { sql1 { 505 INSERT INTO t1 SELECT id+100, x1+10.0, x2+10.0, y1-10.0, y2-10.0 FROM t1; 506 } } {} 507 508 foreach {n q} $::queries { 509 do_test backcompat-4.4.$n [list sql1 $q] [sql2 $q] 510 } 511 512 do_test backcompat-4.5 { sql2 { 513 INSERT INTO t1 SELECT id+200, x1+20.0, x2+20.0, y1-20.0, y2-20.0 FROM t1; 514 } } {} 515 516 foreach {n q} $::queries { 517 do_test backcompat-4.6.$n [list sql1 $q] [sql2 $q] 518 } 519 520 } 521 } 522 } 523 524 finish_test