github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/walro2.test (about) 1 # 2011 May 09 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 # This file contains tests for using WAL databases in read-only mode. 13 # 14 15 set testdir [file dirname $argv0] 16 source $testdir/tester.tcl 17 source $testdir/lock_common.tcl 18 source $testdir/wal_common.tcl 19 set ::testprefix walro2 20 21 # And only if the build is WAL-capable. 22 # 23 ifcapable !wal { 24 finish_test 25 return 26 } 27 28 proc copy_to_test2 {bZeroShm} { 29 forcecopy test.db test.db2 30 forcecopy test.db-wal test.db2-wal 31 if {$bZeroShm} { 32 forcedelete test.db2-shm 33 set fd [open test.db2-shm w] 34 seek $fd [expr [file size test.db-shm]-1] 35 puts -nonewline $fd "\0" 36 close $fd 37 } else { 38 forcecopy test.db-shm test.db2-shm 39 } 40 } 41 42 # Most systems allocate the *-shm file in 32KB trunks. But on UNIX systems 43 # for which the getpagesize() call returns greater than 32K, the *-shm 44 # file is allocated in page-sized units (since you cannot mmap part of 45 # a page). The following code sets variable $MINSHMSZ to the smallest 46 # possible *-shm file (i.e. the greater of 32KB and the system page-size). 47 # 48 do_execsql_test 0.0 { 49 PRAGMA journal_mode = wal; 50 CREATE TABLE t1(x); 51 } {wal} 52 set MINSHMSZ [file size test.db-shm] 53 54 foreach bZeroShm {0 1} { 55 set TN [expr $bZeroShm+1] 56 do_multiclient_test tn { 57 58 # Close all connections and delete the database. 59 # 60 code1 { db close } 61 code2 { db2 close } 62 code3 { db3 close } 63 forcedelete test.db 64 65 # Do not run tests with the connections in the same process. 66 # 67 if {$tn==2} continue 68 69 foreach c {code1 code2 code3} { 70 $c { 71 sqlite3_shutdown 72 sqlite3_config_uri 1 73 } 74 } 75 76 do_test $TN.1.1 { 77 code2 { sqlite3 db2 test.db } 78 sql2 { 79 CREATE TABLE t1(x, y); 80 PRAGMA journal_mode = WAL; 81 INSERT INTO t1 VALUES('a', 'b'); 82 INSERT INTO t1 VALUES('c', 'd'); 83 } 84 file exists test.db-shm 85 } {1} 86 87 do_test $TN.1.2.1 { 88 copy_to_test2 $bZeroShm 89 code1 { 90 sqlite3 db file:test.db2?readonly_shm=1 91 } 92 93 sql1 { SELECT * FROM t1 } 94 } {a b c d} 95 do_test $TN.1.2.2 { 96 sql1 { SELECT * FROM t1 } 97 } {a b c d} 98 99 do_test $TN.1.3.1 { 100 code3 { sqlite3 db3 test.db2 } 101 sql3 { SELECT * FROM t1 } 102 } {a b c d} 103 104 do_test $TN.1.3.2 { 105 sql1 { SELECT * FROM t1 } 106 } {a b c d} 107 108 code1 { db close } 109 code2 { db2 close } 110 code3 { db3 close } 111 112 do_test $TN.2.1 { 113 code2 { sqlite3 db2 test.db } 114 sql2 { 115 INSERT INTO t1 VALUES('e', 'f'); 116 INSERT INTO t1 VALUES('g', 'h'); 117 } 118 file exists test.db-shm 119 } {1} 120 121 do_test $TN.2.2 { 122 copy_to_test2 $bZeroShm 123 code1 { 124 sqlite3 db file:test.db2?readonly_shm=1 125 } 126 sql1 { 127 BEGIN; 128 SELECT * FROM t1; 129 } 130 } {a b c d e f g h} 131 132 do_test $TN.2.3.1 { 133 code3 { sqlite3 db3 test.db2 } 134 sql3 { SELECT * FROM t1 } 135 } {a b c d e f g h} 136 do_test $TN.2.3.2 { 137 sql3 { INSERT INTO t1 VALUES('i', 'j') } 138 code3 { db3 close } 139 sql1 { COMMIT } 140 } {} 141 do_test $TN.2.3.3 { 142 sql1 { SELECT * FROM t1 } 143 } {a b c d e f g h i j} 144 145 146 #----------------------------------------------------------------------- 147 # 3.1.*: That a readonly_shm connection can read a database file if both 148 # the *-wal and *-shm files are zero bytes in size. 149 # 150 # 3.2.*: That it flushes the cache if, between transactions on a db with a 151 # zero byte *-wal file, some other connection modifies the db, then 152 # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file 153 # back to zero bytes in size. 154 # 155 # 3.3.*: That, if between transactions some other process wraps the wal 156 # file, the readonly_shm client reruns recovery. 157 # 158 catch { code1 { db close } } 159 catch { code2 { db2 close } } 160 catch { code3 { db3 close } } 161 do_test $TN.3.1.0 { 162 list [file exists test.db-wal] [file exists test.db-shm] 163 } {0 0} 164 do_test $TN.3.1.1 { 165 close [open test.db-wal w] 166 close [open test.db-shm w] 167 code1 { 168 sqlite3 db file:test.db?readonly_shm=1 169 } 170 sql1 { SELECT * FROM t1 } 171 } {a b c d e f g h} 172 173 do_test $TN.3.2.0 { 174 list [file size test.db-wal] [file size test.db-shm] 175 } {0 0} 176 do_test $TN.3.2.1 { 177 code2 { sqlite3 db2 test.db } 178 sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } 179 code2 { db2 close } 180 sql1 { SELECT * FROM t1 } 181 } {a b c d e f g h 1 2} 182 do_test $TN.3.2.2 { 183 list [file size test.db-wal] [file size test.db-shm] 184 } [list 0 $MINSHMSZ] 185 186 do_test $TN.3.3.0 { 187 code2 { sqlite3 db2 test.db } 188 sql2 { 189 INSERT INTO t1 VALUES(3, 4); 190 INSERT INTO t1 VALUES(5, 6); 191 INSERT INTO t1 VALUES(7, 8); 192 INSERT INTO t1 VALUES(9, 10); 193 } 194 code2 { db2 close } 195 code1 { db close } 196 list [file size test.db-wal] [file size test.db-shm] 197 } [list [wal_file_size 4 1024] $MINSHMSZ] 198 do_test $TN.3.3.1 { 199 code1 { sqlite3 db file:test.db?readonly_shm=1 } 200 sql1 { SELECT * FROM t1 } 201 } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} 202 do_test $TN.3.3.2 { 203 code2 { sqlite3 db2 test.db } 204 sql2 { 205 PRAGMA wal_checkpoint; 206 DELETE FROM t1; 207 INSERT INTO t1 VALUES('i', 'ii'); 208 } 209 code2 { db2 close } 210 list [file size test.db-wal] [file size test.db-shm] 211 } [list [wal_file_size 4 1024] $MINSHMSZ] 212 do_test $TN.3.3.3 { 213 sql1 { SELECT * FROM t1 } 214 } {i ii} 215 216 #----------------------------------------------------------------------- 217 # 218 # 219 catch { code1 { db close } } 220 catch { code2 { db2 close } } 221 catch { code3 { db3 close } } 222 223 do_test $TN.4.0 { 224 code1 { forcedelete test.db } 225 code1 { sqlite3 db test.db } 226 sql1 { 227 PRAGMA journal_mode = wal; 228 CREATE TABLE t1(x); 229 INSERT INTO t1 VALUES('hello'); 230 INSERT INTO t1 VALUES('world'); 231 } 232 233 copy_to_test2 $bZeroShm 234 235 code1 { db close } 236 } {} 237 238 do_test $TN.4.1.1 { 239 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 240 sql2 { SELECT * FROM t1 } 241 } {hello world} 242 243 do_test $TN.4.1.2 { 244 code3 { sqlite3 db3 test.db2 } 245 sql3 { 246 INSERT INTO t1 VALUES('!'); 247 PRAGMA wal_checkpoint = truncate; 248 } 249 code3 { db3 close } 250 } {} 251 do_test $TN.4.1.3 { 252 sql2 { SELECT * FROM t1 } 253 } {hello world !} 254 255 catch { code1 { db close } } 256 catch { code2 { db2 close } } 257 catch { code3 { db3 close } } 258 259 do_test $TN.4.2.1 { 260 code1 { sqlite3 db test.db } 261 sql1 { 262 INSERT INTO t1 VALUES('!'); 263 INSERT INTO t1 VALUES('!'); 264 265 PRAGMA cache_size = 10; 266 CREATE TABLE t2(x); 267 268 BEGIN; 269 WITH s(i) AS ( 270 SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 271 ) 272 INSERT INTO t2 SELECT randomblob(500) FROM s; 273 SELECT count(*) FROM t2; 274 } 275 } {500} 276 set sz [file size test.db-wal] 277 do_test $TN.4.2.2.(sz=$sz) { 278 expr {$sz>400000} 279 } {1} 280 do_test $TN.4.2.4 { 281 file_control_persist_wal db 1; db close 282 283 copy_to_test2 $bZeroShm 284 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 285 sql2 { 286 SELECT * FROM t1; 287 SELECT count(*) FROM t2; 288 } 289 } {hello world ! ! 0} 290 291 #----------------------------------------------------------------------- 292 # 293 # 294 catch { code1 { db close } } 295 catch { code2 { db2 close } } 296 catch { code3 { db3 close } } 297 298 do_test $TN.5.0 { 299 code1 { forcedelete test.db } 300 code1 { sqlite3 db test.db } 301 sql1 { 302 PRAGMA journal_mode = wal; 303 CREATE TABLE t1(x); 304 INSERT INTO t1 VALUES('hello'); 305 INSERT INTO t1 VALUES('world'); 306 INSERT INTO t1 VALUES('!'); 307 INSERT INTO t1 VALUES('world'); 308 INSERT INTO t1 VALUES('hello'); 309 } 310 311 copy_to_test2 $bZeroShm 312 313 code1 { db close } 314 } {} 315 316 do_test $TN.5.1 { 317 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 318 sql2 { 319 SELECT * FROM t1; 320 } 321 } {hello world ! world hello} 322 323 do_test $TN.5.2 { 324 code1 { 325 proc handle_read {op args} { 326 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { 327 set ::res2 [sql2 { SELECT * FROM t1 }] 328 } 329 puts "$msg xRead $args" 330 return "SQLITE_OK" 331 } 332 testvfs tvfs -fullshm 1 333 334 sqlite3 db file:test.db2?vfs=tvfs 335 db eval { SELECT * FROM sqlite_master } 336 337 tvfs filter xRead 338 tvfs script handle_read 339 } 340 sql1 { 341 PRAGMA wal_checkpoint = truncate; 342 } 343 code1 { set ::res2 } 344 } {hello world ! world hello} 345 346 do_test $TN.5.3 { 347 code1 { db close } 348 code1 { tvfs delete } 349 } {} 350 351 #----------------------------------------------------------------------- 352 # 353 # 354 catch { code1 { db close } } 355 catch { code2 { db2 close } } 356 catch { code3 { db3 close } } 357 358 do_test $TN.6.1 { 359 code1 { forcedelete test.db } 360 code1 { sqlite3 db test.db } 361 sql1 { 362 PRAGMA journal_mode = wal; 363 CREATE TABLE t1(x); 364 INSERT INTO t1 VALUES('hello'); 365 INSERT INTO t1 VALUES('world'); 366 INSERT INTO t1 VALUES('!'); 367 INSERT INTO t1 VALUES('world'); 368 INSERT INTO t1 VALUES('hello'); 369 } 370 371 copy_to_test2 $bZeroShm 372 373 code1 { db close } 374 } {} 375 376 do_test $TN.6.2 { 377 code1 { 378 set ::nRem 5 379 proc handle_read {op args} { 380 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { 381 incr ::nRem -1 382 if {$::nRem==0} { 383 code2 { sqlite3 db2 test.db2 } 384 sql2 { PRAGMA wal_checkpoint = truncate } 385 } 386 } 387 return "SQLITE_OK" 388 } 389 testvfs tvfs -fullshm 1 390 391 tvfs filter xRead 392 tvfs script handle_read 393 394 sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs 395 db eval { SELECT * FROM t1 } 396 } 397 } {hello world ! world hello} 398 399 do_test $TN.6.3 { 400 code1 { db close } 401 code1 { tvfs delete } 402 } {} 403 } 404 } ;# foreach bZeroShm 405 406 finish_test