From: drh <> Date: Thu, 20 Jan 2022 02:04:53 +0000 (+0000) Subject: Fix the ability to read read-only WAL-mode database when -shm is present, X-Git-Tag: version-3.38.0~103 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d6b44ec32a5709cb56cc6f9d9a80c1a336f1a53c;p=thirdparty%2Fsqlite.git Fix the ability to read read-only WAL-mode database when -shm is present, ([00ec95fcd02bb415|check-in 00ec95fcd02bb415]) so that it works for the case of 64K page size. FossilOrigin-Name: f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd --- diff --git a/manifest b/manifest index 01dc783a6f..7cf6470469 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stest\sresult\sfor\salterauth2.test\sdue\sto\sthe\srecent\sfix\sto\sauthorizer\ncalls\sfor\sALTER\sTABLE\sDROP\sCOLUMN. -D 2022-01-19T18:31:43.542 +C Fix\sthe\sability\sto\sread\sread-only\sWAL-mode\sdatabase\swhen\s-shm\sis\spresent,\n([00ec95fcd02bb415|check-in\s00ec95fcd02bb415])\sso\sthat\sit\sworks\nfor\sthe\scase\sof\s64K\spage\ssize. +D 2022-01-20T02:04:53.654 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -635,7 +635,7 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028 +F src/wal.c c55ef660f9ee91e1331ced61f312aae81179ff9ec8632639136bcb252ce86e1b F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7 @@ -1753,7 +1753,7 @@ F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6 F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20 -F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768 +F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 F test/walsetlk.test 3185bebc90557e0d611442c8d64f7a0cb7b06f8e156eea37a4a7358f722715be F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 -R 49af707cd669468ece46f1dd370b2f63 +P e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 +R a570f2b782808526402854b4e442ef9f U drh -Z 256bb3763483caaf79af6f149c662bf0 +Z ad5c72d40960b0db8c967cbfe55162e8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 672d9b9c73..d86b834717 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 \ No newline at end of file +f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index a0ec91965c..37930f89e2 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2520,6 +2520,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ volatile void *pDummy; /* Dummy argument for xShmMap */ int rc; /* Return code */ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */ + int szPage; /* Page size */ assert( pWal->bShmUnreliable ); assert( pWal->readOnly & WAL_SHM_RDONLY ); @@ -2603,7 +2604,8 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ } /* Allocate a buffer to read frames into */ - szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE; + szPage = walPagesize(pWal); + szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -2617,7 +2619,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ ** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; - for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); + for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){ diff --git a/test/walro2.test b/test/walro2.test index 34408c1695..1eb9d1c3ee 100644 --- a/test/walro2.test +++ b/test/walro2.test @@ -50,357 +50,362 @@ do_execsql_test 0.0 { CREATE TABLE t1(x); } {wal} set MINSHMSZ [file size test.db-shm] +set dfltpgsz [db one {PRAGMA page_size}] foreach bZeroShm {0 1} { -set TN [expr $bZeroShm+1] -do_multiclient_test tn { - - # Close all connections and delete the database. - # - code1 { db close } - code2 { db2 close } - code3 { db3 close } - forcedelete test.db - - # Do not run tests with the connections in the same process. - # - if {$tn==2} continue - - foreach c {code1 code2 code3} { - $c { - sqlite3_shutdown - sqlite3_config_uri 1 - } - } - - do_test $TN.1.1 { - code2 { sqlite3 db2 test.db } - sql2 { - CREATE TABLE t1(x, y); - PRAGMA journal_mode = WAL; - INSERT INTO t1 VALUES('a', 'b'); - INSERT INTO t1 VALUES('c', 'd'); - } - file exists test.db-shm - } {1} - - do_test $TN.1.2.1 { - copy_to_test2 $bZeroShm - code1 { - sqlite3 db file:test.db2?readonly_shm=1 - } - - sql1 { SELECT * FROM t1 } - } {a b c d} - do_test $TN.1.2.2 { - sql1 { SELECT * FROM t1 } - } {a b c d} - - do_test $TN.1.3.1 { - code3 { sqlite3 db3 test.db2 } - sql3 { SELECT * FROM t1 } - } {a b c d} - - do_test $TN.1.3.2 { - sql1 { SELECT * FROM t1 } - } {a b c d} - - code1 { db close } - code2 { db2 close } - code3 { db3 close } - - do_test $TN.2.1 { - code2 { sqlite3 db2 test.db } - sql2 { - INSERT INTO t1 VALUES('e', 'f'); - INSERT INTO t1 VALUES('g', 'h'); - } - file exists test.db-shm - } {1} - - do_test $TN.2.2 { - copy_to_test2 $bZeroShm - code1 { - sqlite3 db file:test.db2?readonly_shm=1 - } - sql1 { - BEGIN; - SELECT * FROM t1; - } - } {a b c d e f g h} - - do_test $TN.2.3.1 { - code3 { sqlite3 db3 test.db2 } - sql3 { SELECT * FROM t1 } - } {a b c d e f g h} - do_test $TN.2.3.2 { - sql3 { INSERT INTO t1 VALUES('i', 'j') } - code3 { db3 close } - sql1 { COMMIT } - } {} - do_test $TN.2.3.3 { - sql1 { SELECT * FROM t1 } - } {a b c d e f g h i j} - - - #----------------------------------------------------------------------- - # 3.1.*: That a readonly_shm connection can read a database file if both - # the *-wal and *-shm files are zero bytes in size. - # - # 3.2.*: That it flushes the cache if, between transactions on a db with a - # zero byte *-wal file, some other connection modifies the db, then - # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file - # back to zero bytes in size. - # - # 3.3.*: That, if between transactions some other process wraps the wal - # file, the readonly_shm client reruns recovery. - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - do_test $TN.3.1.0 { - list [file exists test.db-wal] [file exists test.db-shm] - } {0 0} - do_test $TN.3.1.1 { - close [open test.db-wal w] - close [open test.db-shm w] - code1 { - sqlite3 db file:test.db?readonly_shm=1 - } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h} - - do_test $TN.3.2.0 { - list [file size test.db-wal] [file size test.db-shm] - } {0 0} - do_test $TN.3.2.1 { - code2 { sqlite3 db2 test.db } - sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } - code2 { db2 close } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h 1 2} - do_test $TN.3.2.2 { - list [file size test.db-wal] [file size test.db-shm] - } [list 0 $MINSHMSZ] - - do_test $TN.3.3.0 { - code2 { sqlite3 db2 test.db } - sql2 { - INSERT INTO t1 VALUES(3, 4); - INSERT INTO t1 VALUES(5, 6); - INSERT INTO t1 VALUES(7, 8); - INSERT INTO t1 VALUES(9, 10); - } - code2 { db2 close } - code1 { db close } - list [file size test.db-wal] [file size test.db-shm] - } [list [wal_file_size 4 1024] $MINSHMSZ] - do_test $TN.3.3.1 { - code1 { sqlite3 db file:test.db?readonly_shm=1 } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} - do_test $TN.3.3.2 { - code2 { sqlite3 db2 test.db } - sql2 { - PRAGMA wal_checkpoint; - DELETE FROM t1; - INSERT INTO t1 VALUES('i', 'ii'); - } - code2 { db2 close } - list [file size test.db-wal] [file size test.db-shm] - } [list [wal_file_size 4 1024] $MINSHMSZ] - do_test $TN.3.3.3 { - sql1 { SELECT * FROM t1 } - } {i ii} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.4.0 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - } - - copy_to_test2 $bZeroShm - - code1 { db close } - } {} - - do_test $TN.4.1.1 { - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { SELECT * FROM t1 } - } {hello world} - - do_test $TN.4.1.2 { - code3 { sqlite3 db3 test.db2 } - sql3 { - INSERT INTO t1 VALUES('!'); - PRAGMA wal_checkpoint = truncate; - } - code3 { db3 close } - } {} - do_test $TN.4.1.3 { - sql2 { SELECT * FROM t1 } - } {hello world !} - - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.4.2.1 { - code1 { sqlite3 db test.db } - sql1 { - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('!'); - - PRAGMA cache_size = 10; - CREATE TABLE t2(x); - - BEGIN; - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 - ) - INSERT INTO t2 SELECT randomblob(500) FROM s; - SELECT count(*) FROM t2; - } - } {500} - set sz [file size test.db-wal] - do_test $TN.4.2.2.(sz=$sz) { - expr {$sz>400000} - } {1} - do_test $TN.4.2.4 { - file_control_persist_wal db 1; db close - - copy_to_test2 $bZeroShm - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { - SELECT * FROM t1; - SELECT count(*) FROM t2; - } - } {hello world ! ! 0} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.5.0 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('hello'); - } - - copy_to_test2 $bZeroShm + for {set pgsz 512} {$pgsz<=65536} {set pgsz [expr {$pgsz*2}]} { + set TN [expr $bZeroShm+1]-$pgsz + do_multiclient_test tn { + + # Close all connections and delete the database. + # + code1 { db close } + code2 { db2 close } + code3 { db3 close } + forcedelete test.db + + # Do not run tests with the connections in the same process. + # + if {$tn==2} continue - code1 { db close } - } {} - - do_test $TN.5.1 { - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { - SELECT * FROM t1; - } - } {hello world ! world hello} - - do_test $TN.5.2 { - code1 { - proc handle_read {op args} { - if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { - set ::res2 [sql2 { SELECT * FROM t1 }] + foreach c {code1 code2 code3} { + $c { + sqlite3_shutdown + sqlite3_config_uri 1 } - puts "$msg xRead $args" - return "SQLITE_OK" } - testvfs tvfs -fullshm 1 - - sqlite3 db file:test.db2?vfs=tvfs - db eval { SELECT * FROM sqlite_master } - - tvfs filter xRead - tvfs script handle_read - } - sql1 { - PRAGMA wal_checkpoint = truncate; - } - code1 { set ::res2 } - } {hello world ! world hello} - - do_test $TN.5.3 { - code1 { db close } - code1 { tvfs delete } - } {} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.6.1 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('hello'); - } - - copy_to_test2 $bZeroShm - code1 { db close } - } {} - - do_test $TN.6.2 { - code1 { - set ::nRem 5 - proc handle_read {op args} { - if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { - incr ::nRem -1 - if {$::nRem==0} { - code2 { sqlite3 db2 test.db2 } - sql2 { PRAGMA wal_checkpoint = truncate } + do_test $TN.1.1 { + code2 { sqlite3 db2 test.db } + sql2 "PRAGMA page_size=$::pgsz" + sql2 { + CREATE TABLE t1(x, y); + PRAGMA journal_mode = WAL; + INSERT INTO t1 VALUES('a', 'b'); + INSERT INTO t1 VALUES('c', 'd'); + } + file exists test.db-shm + } {1} + + do_test $TN.1.2.1 { + copy_to_test2 $bZeroShm + code1 { + sqlite3 db file:test.db2?readonly_shm=1 + } + + sql1 { SELECT * FROM t1 } + } {a b c d} + do_test $TN.1.2.2 { + sql1 { SELECT * FROM t1 } + } {a b c d} + + do_test $TN.1.3.1 { + code3 { sqlite3 db3 test.db2 } + sql3 { SELECT * FROM t1 } + } {a b c d} + + do_test $TN.1.3.2 { + sql1 { SELECT * FROM t1 } + } {a b c d} + + code1 { db close } + code2 { db2 close } + code3 { db3 close } + + do_test $TN.2.1 { + code2 { sqlite3 db2 test.db } + sql2 "PRAGMA page_size=$::pgsz;" + sql2 { + INSERT INTO t1 VALUES('e', 'f'); + INSERT INTO t1 VALUES('g', 'h'); + } + file exists test.db-shm + } {1} + + do_test $TN.2.2 { + copy_to_test2 $bZeroShm + code1 { + sqlite3 db file:test.db2?readonly_shm=1 + } + sql1 { + BEGIN; + SELECT * FROM t1; + } + } {a b c d e f g h} + + do_test $TN.2.3.1 { + code3 { sqlite3 db3 test.db2 } + sql3 { SELECT * FROM t1 } + } {a b c d e f g h} + do_test $TN.2.3.2 { + sql3 { INSERT INTO t1 VALUES('i', 'j') } + code3 { db3 close } + sql1 { COMMIT } + } {} + do_test $TN.2.3.3 { + sql1 { SELECT * FROM t1 } + } {a b c d e f g h i j} + + + #----------------------------------------------------------------------- + # 3.1.*: That a readonly_shm connection can read a database file if both + # the *-wal and *-shm files are zero bytes in size. + # + # 3.2.*: That it flushes the cache if, between transactions on a db with a + # zero byte *-wal file, some other connection modifies the db, then + # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file + # back to zero bytes in size. + # + # 3.3.*: That, if between transactions some other process wraps the wal + # file, the readonly_shm client reruns recovery. + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + do_test $TN.3.1.0 { + list [file exists test.db-wal] [file exists test.db-shm] + } {0 0} + do_test $TN.3.1.1 { + close [open test.db-wal w] + close [open test.db-shm w] + code1 { + sqlite3 db file:test.db?readonly_shm=1 + } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h} + + do_test $TN.3.2.0 { + list [file size test.db-wal] [file size test.db-shm] + } {0 0} + do_test $TN.3.2.1 { + code2 { sqlite3 db2 test.db } + sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } + code2 { db2 close } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h 1 2} + if {$pgsz!=$dfltpgsz} continue + do_test $TN.3.2.2 { + list [file size test.db-wal] [file size test.db-shm] + } [list 0 $MINSHMSZ] + do_test $TN.3.3.0 { + code2 { sqlite3 db2 test.db } + sql2 { + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + INSERT INTO t1 VALUES(7, 8); + INSERT INTO t1 VALUES(9, 10); + } + code2 { db2 close } + code1 { db close } + list [file size test.db-wal] [file size test.db-shm] + } [list [wal_file_size 4 1024] $MINSHMSZ] + do_test $TN.3.3.1 { + code1 { sqlite3 db file:test.db?readonly_shm=1 } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} + do_test $TN.3.3.2 { + code2 { sqlite3 db2 test.db } + sql2 { + PRAGMA wal_checkpoint; + DELETE FROM t1; + INSERT INTO t1 VALUES('i', 'ii'); + } + code2 { db2 close } + list [file size test.db-wal] [file size test.db-shm] + } [list [wal_file_size 4 1024] $MINSHMSZ] + do_test $TN.3.3.3 { + sql1 { SELECT * FROM t1 } + } {i ii} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.4.0 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.4.1.1 { + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { SELECT * FROM t1 } + } {hello world} + + do_test $TN.4.1.2 { + code3 { sqlite3 db3 test.db2 } + sql3 { + INSERT INTO t1 VALUES('!'); + PRAGMA wal_checkpoint = truncate; + } + code3 { db3 close } + } {} + do_test $TN.4.1.3 { + sql2 { SELECT * FROM t1 } + } {hello world !} + + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.4.2.1 { + code1 { sqlite3 db test.db } + sql1 { + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('!'); + + PRAGMA cache_size = 10; + CREATE TABLE t2(x); + + BEGIN; + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 + ) + INSERT INTO t2 SELECT randomblob(500) FROM s; + SELECT count(*) FROM t2; + } + } {500} + set sz [file size test.db-wal] + do_test $TN.4.2.2.(sz=$sz) { + expr {$sz>400000} + } {1} + do_test $TN.4.2.4 { + file_control_persist_wal db 1; db close + + copy_to_test2 $bZeroShm + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { + SELECT * FROM t1; + SELECT count(*) FROM t2; + } + } {hello world ! ! 0} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.5.0 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('hello'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.5.1 { + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { + SELECT * FROM t1; + } + } {hello world ! world hello} + + do_test $TN.5.2 { + code1 { + proc handle_read {op args} { + if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { + set ::res2 [sql2 { SELECT * FROM t1 }] + } + puts "$msg xRead $args" + return "SQLITE_OK" } + testvfs tvfs -fullshm 1 + + sqlite3 db file:test.db2?vfs=tvfs + db eval { SELECT * FROM sqlite_master } + + tvfs filter xRead + tvfs script handle_read } - return "SQLITE_OK" - } - testvfs tvfs -fullshm 1 - - tvfs filter xRead - tvfs script handle_read - - sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs - db eval { SELECT * FROM t1 } + sql1 { + PRAGMA wal_checkpoint = truncate; + } + code1 { set ::res2 } + } {hello world ! world hello} + + do_test $TN.5.3 { + code1 { db close } + code1 { tvfs delete } + } {} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.6.1 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('hello'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.6.2 { + code1 { + set ::nRem 5 + proc handle_read {op args} { + if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { + incr ::nRem -1 + if {$::nRem==0} { + code2 { sqlite3 db2 test.db2 } + sql2 { PRAGMA wal_checkpoint = truncate } + } + } + return "SQLITE_OK" + } + testvfs tvfs -fullshm 1 + + tvfs filter xRead + tvfs script handle_read + + sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs + db eval { SELECT * FROM t1 } + } + } {hello world ! world hello} + + do_test $TN.6.3 { + code1 { db close } + code1 { tvfs delete } + } {} } - } {hello world ! world hello} - - do_test $TN.6.3 { - code1 { db close } - code1 { tvfs delete } - } {} -} + } ;# for pgsz } ;# foreach bZeroShm finish_test