1# 2010 October 29 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# 12 13set testdir [file dirname $argv0] 14source $testdir/tester.tcl 15source $testdir/malloc_common.tcl 16 17set g_chunk_size 2147483648 18set g_max_chunks 32 19 20# This handles appending the chunk number 21# to the end of the filename. if 22# SQLITE_MULTIPLEX_EXT_OVWR is defined, then 23# it overwrites the last 2 bytes of the 24# file name with the chunk number. 25proc multiplex_name {name chunk} { 26 if {$chunk==0} { return $name } 27 set num [format "%02d" $chunk] 28 ifcapable {multiplex_ext_overwrite} { 29 set name [string range $name 0 [expr [string length $name]-2-1]] 30 } 31 return $name$num 32} 33 34# This saves off the parameters and calls the 35# underlying sqlite3_multiplex_set() API. 36proc multiplex_set {chunk_size max_chunks} { 37 global g_chunk_size 38 global g_max_chunks 39 set g_chunk_size $chunk_size 40 set g_max_chunks $max_chunks 41 sqlite3_multiplex_set $chunk_size $max_chunks 42} 43 44# This attempts to delete the base file and 45# and files with the chunk extension. 46proc multiplex_delete {name} { 47 global g_max_chunks 48 for {set i 0} {$i<$g_max_chunks} {incr i} { 49 forcedelete [multiplex_name $name $i] 50 forcedelete [multiplex_name $name-journal $i] 51 forcedelete [multiplex_name $name-wal $i] 52 } 53} 54 55db close 56 57multiplex_delete test.db 58multiplex_delete test2.db 59 60#------------------------------------------------------------------------- 61# multiplex-1.1.*: Test initialize and shutdown. 62 63do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR} 64do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} 65do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 } {SQLITE_MISUSE} 66do_test multiplex-1.4 { sqlite3_multiplex_shutdown } {SQLITE_OK} 67 68do_test multiplex-1.5 { sqlite3_multiplex_initialize "" 0 } {SQLITE_OK} 69do_test multiplex-1.6 { sqlite3_multiplex_shutdown } {SQLITE_OK} 70do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} 71do_test multiplex-1.8 { sqlite3_multiplex_shutdown } {SQLITE_OK} 72 73do_test multiplex-1.9 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} 74do_test multiplex-1.10.1 { multiplex_set 32768 16 } {SQLITE_OK} 75do_test multiplex-1.10.2 { multiplex_set 32768 -1 } {SQLITE_MISUSE} 76do_test multiplex-1.10.3 { multiplex_set -1 16 } {SQLITE_MISUSE} 77do_test multiplex-1.10.4 { multiplex_set 31 16 } {SQLITE_MISUSE} 78do_test multiplex-1.10.5 { multiplex_set 32768 100 } {SQLITE_MISUSE} 79do_test multiplex-1.11 { sqlite3_multiplex_shutdown } {SQLITE_OK} 80 81 82#------------------------------------------------------------------------- 83# Some simple warm-body tests with a single database file in rollback 84# mode: 85# 86# multiplex-2.1.*: Test simple writing to a multiplex file. 87# 88# multiplex-2.2.*: More writing. 89# 90# multiplex-2.3.*: Open and close a second db. 91# 92# multiplex-2.4.*: Try to shutdown the multiplex system before closing the db 93# file. Check that this fails and the multiplex system still works 94# afterwards. Then close the database and successfully shut 95# down the multiplex system. 96# 97# multiplex-2.5.*: More reading/writing. 98# 99# multiplex-2.6.*: More reading/writing with varying small chunk sizes, as 100# well as varying journal mode. 101 102sqlite3_multiplex_initialize "" 1 103multiplex_set 32768 16 104 105do_test multiplex-2.1.2 { 106 sqlite3 db test.db 107 execsql { 108 PRAGMA page_size=1024; 109 PRAGMA auto_vacuum=OFF; 110 PRAGMA journal_mode=DELETE; 111 } 112 execsql { 113 CREATE TABLE t1(a, b); 114 INSERT INTO t1 VALUES(1, randomblob(1100)); 115 INSERT INTO t1 VALUES(2, randomblob(1100)); 116 } 117} {} 118do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096} 119do_test multiplex-2.1.4 { 120 execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 121} {} 122 123do_test multiplex-2.2.1 { 124 execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 125} {} 126do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144} 127 128do_test multiplex-2.3.1 { 129 sqlite3 db2 test2.db 130 db2 close 131} {} 132 133do_test multiplex-2.4.1 { 134 sqlite3_multiplex_shutdown 135} {SQLITE_MISUSE} 136do_test multiplex-2.4.2 { 137 execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 138} {} 139do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168} 140do_test multiplex-2.4.99 { 141 db close 142 sqlite3_multiplex_shutdown 143} {SQLITE_OK} 144 145 146do_test multiplex-2.5.1 { 147 multiplex_delete test.db 148 sqlite3_multiplex_initialize "" 1 149 multiplex_set 4096 16 150} {SQLITE_OK} 151 152do_test multiplex-2.5.2 { 153 sqlite3 db test.db 154 execsql { 155 PRAGMA page_size = 1024; 156 PRAGMA journal_mode = delete; 157 PRAGMA auto_vacuum = off; 158 CREATE TABLE t1(a PRIMARY KEY, b); 159 } 160} {delete} 161 162do_test multiplex-2.5.3 { 163 execsql { 164 INSERT INTO t1 VALUES(1, 'one'); 165 INSERT INTO t1 VALUES(2, randomblob(4000)); 166 INSERT INTO t1 VALUES(3, 'three'); 167 INSERT INTO t1 VALUES(4, randomblob(4000)); 168 INSERT INTO t1 VALUES(5, 'five') 169 } 170} {} 171 172do_test multiplex-2.5.4 { 173 db eval {SELECT * FROM t1 WHERE a=1} 174} {1 one} 175 176do_test multiplex-2.5.5 { 177 db eval {SELECT * FROM t1 WHERE a=3} 178} {3 three} 179 180do_test multiplex-2.5.6 { 181 db eval {SELECT * FROM t1 WHERE a=5} 182} {5 five} 183 184do_test multiplex-2.5.7 { 185 db eval {SELECT a,length(b) FROM t1 WHERE a=2} 186} {2 4000} 187 188do_test multiplex-2.5.8 { 189 db eval {SELECT a,length(b) FROM t1 WHERE a=4} 190} {4 4000} 191 192do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size] 193do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size] 194 195do_test multiplex-2.5.99 { 196 db close 197 sqlite3_multiplex_shutdown 198} {SQLITE_OK} 199 200 201set all_journal_modes {delete persist truncate memory off} 202foreach jmode $all_journal_modes { 203 for {set sz 151} {$sz<8000} {set sz [expr $sz+419]} { 204 205 do_test multiplex-2.6.1.$sz.$jmode { 206 multiplex_delete test.db 207 sqlite3_multiplex_initialize "" 1 208 multiplex_set $sz 32 209 } {SQLITE_OK} 210 211 do_test multiplex-2.6.2.$sz.$jmode { 212 sqlite3 db test.db 213 db eval { 214 PRAGMA page_size = 1024; 215 PRAGMA auto_vacuum = off; 216 } 217 db eval "PRAGMA journal_mode = $jmode;" 218 } $jmode 219 220 do_test multiplex-2.6.3.$sz.$jmode { 221 execsql { 222 CREATE TABLE t1(a PRIMARY KEY, b); 223 INSERT INTO t1 VALUES(1, 'one'); 224 INSERT INTO t1 VALUES(2, randomblob($g_chunk_size)); 225 } 226 } {} 227 228 do_test multiplex-2.6.4.$sz.$jmode { 229 db eval {SELECT b FROM t1 WHERE a=1} 230 } {one} 231 232 do_test multiplex-2.6.5.$sz.$jmode { 233 db eval {SELECT length(b) FROM t1 WHERE a=2} 234 } [list $g_chunk_size] 235 236 do_test multiplex-2.6.6.$sz.$jmode { file size [multiplex_name test.db 0] } [list $g_chunk_size] 237 238 do_test multiplex-2.6.99.$sz.$jmode { 239 db close 240 sqlite3_multiplex_shutdown 241 } {SQLITE_OK} 242 243 } 244} 245 246#------------------------------------------------------------------------- 247# Try some tests with more than one connection to a database file. Still 248# in rollback mode. 249# 250# multiplex-3.1.*: Two connections to a single database file. 251# 252# multiplex-3.2.*: Two connections to each of several database files (that 253# are in the same multiplex group). 254# 255do_test multiplex-3.1.1 { 256 multiplex_delete test.db 257 sqlite3_multiplex_initialize "" 1 258 multiplex_set 32768 16 259} {SQLITE_OK} 260do_test multiplex-3.1.2 { 261 sqlite3 db test.db 262 execsql { 263 PRAGMA page_size = 1024; 264 PRAGMA journal_mode = delete; 265 PRAGMA auto_vacuum = off; 266 CREATE TABLE t1(a PRIMARY KEY, b); 267 INSERT INTO t1 VALUES(1, 'one'); 268 } 269 file size [multiplex_name test.db 0] 270} {3072} 271do_test multiplex-3.1.3 { 272 sqlite3 db2 test.db 273 execsql { CREATE TABLE t2(a, b) } db2 274} {} 275do_test multiplex-3.1.4 { 276 execsql { CREATE TABLE t3(a, b) } 277} {} 278do_test multiplex-3.1.5 { 279 catchsql { CREATE TABLE t3(a, b) } 280} {1 {table t3 already exists}} 281do_test multiplex-3.1.6 { 282 db close 283 db2 close 284} {} 285 286do_test multiplex-3.2.1a { 287 288 multiplex_delete test.db 289 multiplex_delete test2.db 290 291 sqlite3 db1a test.db 292 sqlite3 db2a test2.db 293 294 foreach db {db1a db2a} { 295 execsql { 296 PRAGMA page_size = 1024; 297 PRAGMA journal_mode = delete; 298 PRAGMA auto_vacuum = off; 299 CREATE TABLE t1(a, b); 300 } $db 301 } 302 303 list [file size [multiplex_name test.db 0]] [file size [multiplex_name test2.db 0]] 304} {2048 2048} 305 306do_test multiplex-3.2.1b { 307 sqlite3 db1b test.db 308 sqlite3 db2b test2.db 309} {} 310 311do_test multiplex-3.2.2 { execsql { INSERT INTO t1 VALUES('x', 'y') } db1a } {} 312do_test multiplex-3.2.3 { execsql { INSERT INTO t1 VALUES('v', 'w') } db1b } {} 313do_test multiplex-3.2.4 { execsql { INSERT INTO t1 VALUES('t', 'u') } db2a } {} 314do_test multiplex-3.2.5 { execsql { INSERT INTO t1 VALUES('r', 's') } db2b } {} 315 316do_test multiplex-3.2.6 { 317 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a 318} {} 319do_test multiplex-3.2.7 { 320 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b 321} {} 322do_test multiplex-3.2.8 { 323 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a 324} {} 325do_test multiplex-3.2.9 { 326 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b 327} {} 328 329do_test multiplex-3.3.1 { 330 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a 331 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b 332 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a 333 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b 334} {} 335 336do_test multiplex-3.2.X { 337 foreach db {db1a db2a db2b db1b} { catch { $db close } } 338} {} 339 340#------------------------------------------------------------------------- 341# 342 343sqlite3_multiplex_initialize "" 1 344multiplex_set 32768 16 345 346# Return a list of all currently defined multiplexs. 347proc multiplex_list {} { 348 set allq {} 349 foreach q [sqlite3_multiplex_dump] { 350 lappend allq [lindex $q 0] 351 } 352 return [lsort $allq] 353} 354 355do_test multiplex-4.1.6 { 356 multiplex_delete test2.db 357 sqlite3 db test2.db 358 db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');} 359 set res [multiplex_list] 360 list [regexp {test2.db} $res] 361} {1} 362do_test multiplex-4.1.6a { 363 sqlite3 db2 test2.db 364 db2 eval {SELECT * FROM t2} 365} {tab-t2} 366do_test multiplex-4.1.7 { 367 execsql {INSERT INTO t2 VALUES(zeroblob(200000))} 368} {} 369do_test multiplex-4.1.8 { 370 sqlite3 db2 test2.db 371 db2 eval {SELECT count(*) FROM t2} 372} {2} 373do_test multiplex-4.1.8a { 374 db2 eval { DELETE FROM t2 WHERE x = 'tab-t2' } 375} {} 376do_test multiplex-4.1.8b { 377 sqlite3 db2 test2.db 378 db2 eval {SELECT count(*) FROM t2} 379} {1} 380 381 382do_test multiplex-4.1.9 { 383 execsql {INSERT INTO t2 VALUES(zeroblob(200000))} 384} {} 385do_test multiplex-4.1.10 { 386 set res [multiplex_list] 387 list [regexp {test2.db} $res] 388} {1} 389do_test multiplex-4.1.11 { 390 db2 close 391 set res [multiplex_list] 392 list [regexp {test2.db} $res] 393} {1} 394do_test multiplex-4.1.12 { 395 db close 396 multiplex_list 397} {} 398 399 400#------------------------------------------------------------------------- 401# The following tests test that the multiplex VFS handles malloc and IO 402# errors. 403# 404 405sqlite3_multiplex_initialize "" 1 406multiplex_set 32768 16 407 408do_faultsim_test multiplex-5.1 -prep { 409 catch {db close} 410} -body { 411 sqlite3 db test2.db 412} 413do_faultsim_test multiplex-5.2 -prep { 414 catch {db close} 415} -body { 416 sqlite3 db test.db 417} 418 419catch { db close } 420multiplex_delete test.db 421multiplex_delete test2.db 422 423do_test multiplex-5.3.prep { 424 sqlite3 db test.db 425 execsql { 426 PRAGMA auto_vacuum = 1; 427 PRAGMA page_size = 1024; 428 CREATE TABLE t1(a, b); 429 INSERT INTO t1 VALUES(10, zeroblob(1200)); 430 } 431 faultsim_save_and_close 432} {} 433do_faultsim_test multiplex-5.3 -prep { 434 faultsim_restore_and_reopen 435} -body { 436 execsql { DELETE FROM t1 } 437} 438 439do_test multiplex-5.4.1 { 440 catch { db close } 441 multiplex_delete test.db 442 file mkdir test.db 443 list [catch { sqlite3 db test.db } msg] $msg 444} {1 {unable to open database file}} 445catch { file delete test.db } 446 447do_faultsim_test multiplex-5.5 -prep { 448 catch { sqlite3_multiplex_shutdown } 449} -body { 450 sqlite3_multiplex_initialize "" 1 451 multiplex_set 32768 16 452} 453 454# test that mismatch filesize is detected 455# 456# Do not run this test if $::G(perm:presql) is set. If it is set, then the 457# expected IO error will occur within the Tcl [sqlite3] wrapper, not within 458# the first SQL statement executed below. This breaks the test case. 459# 460if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} { 461 set all_journal_modes {delete persist truncate memory off} 462 foreach jmode $all_journal_modes { 463 do_test multiplex-5.6.1.$jmode { 464 sqlite3_multiplex_shutdown 465 multiplex_delete test.db 466 sqlite3 db test.db 467 db eval { 468 PRAGMA page_size = 1024; 469 PRAGMA auto_vacuum = off; 470 } 471 db eval "PRAGMA journal_mode = $jmode;" 472 } $jmode 473 do_test multiplex-5.6.2.$jmode { 474 execsql { 475 CREATE TABLE t1(a, b); 476 INSERT INTO t1 VALUES(1, randomblob(1100)); 477 INSERT INTO t1 VALUES(2, randomblob(1100)); 478 INSERT INTO t1 VALUES(3, randomblob(1100)); 479 INSERT INTO t1 VALUES(4, randomblob(1100)); 480 INSERT INTO t1 VALUES(5, randomblob(1100)); 481 } 482 db close 483 sqlite3_multiplex_initialize "" 1 484 multiplex_set 4096 16 485 sqlite3 db test.db 486 } {} 487 do_test multiplex-5.6.3.$jmode { 488 catchsql { 489 INSERT INTO t1 VALUES(6, randomblob(1100)); 490 } 491 } {1 {disk I/O error}} 492 do_test multiplex-5.6.4.$jmode { 493 db close 494 } {} 495 } 496} 497 498catch { sqlite3_multiplex_shutdown } 499finish_test 500