18d69a581Sdan# 2018 December 23 28d69a581Sdan# 38d69a581Sdan# The author disclaims copyright to this source code. In place of 48d69a581Sdan# a legal notice, here is a blessing: 58d69a581Sdan# 68d69a581Sdan# May you do good and not evil. 78d69a581Sdan# May you find forgiveness for yourself and forgive others. 88d69a581Sdan# May you share freely, never taking more than you give. 98d69a581Sdan# 108d69a581Sdan#*********************************************************************** 118d69a581Sdan# This file implements regression tests for SQLite library. The 128d69a581Sdan# focus of this file is testing the operation of the library in 138d69a581Sdan# "PRAGMA journal_mode=WAL" mode. 148d69a581Sdan# 15*cf2ad7aeSdan# TESTRUNNER: slow 168d69a581Sdan 178d69a581Sdanset testdir [file dirname $argv0] 188d69a581Sdansource $testdir/tester.tcl 198d69a581Sdansource $testdir/lock_common.tcl 208d69a581Sdansource $testdir/malloc_common.tcl 218d69a581Sdansource $testdir/wal_common.tcl 228d69a581Sdanset testprefix walvfs 238d69a581Sdan 248d69a581Sdanifcapable !wal {finish_test ; return } 258d69a581Sdan 268d69a581Sdandb close 278d69a581Sdantestvfs tvfs 288d69a581Sdantvfs script xSync 298d69a581Sdantvfs filter xSync 308d69a581Sdanset ::sync_count 0 318d69a581Sdanproc xSync {method file args} { 328d69a581Sdan if {[file tail $file]=="test.db-wal"} { 338d69a581Sdan incr ::sync_count 348d69a581Sdan } 358d69a581Sdan} 368d69a581Sdan 3789dec01eSdan 388d69a581Sdan#------------------------------------------------------------------------- 398d69a581Sdan# Test that if IOCAP_SEQUENTIAL is set, the wal-header is not synced to 408d69a581Sdan# disk immediately after it is written. 418d69a581Sdan# 428d69a581Sdansqlite3 db test.db -vfs tvfs 438d69a581Sdando_execsql_test 1.0 { 448d69a581Sdan PRAGMA auto_vacuum = 0; 458d69a581Sdan PRAGMA journal_mode = wal; 468d69a581Sdan PRAGMA synchronous = normal; 478d69a581Sdan CREATE TABLE t1(a, b, c); 488d69a581Sdan INSERT INTO t1 VALUES(1, 2, 3); 498d69a581Sdan INSERT INTO t1 VALUES(4, 5, 6); 508d69a581Sdan INSERT INTO t1 VALUES(7, 8, 9); 518d69a581Sdan PRAGMA wal_checkpoint; 528d69a581Sdan} {wal 0 5 5} 538d69a581Sdan 548d69a581Sdanset ::sync_count 0 558d69a581Sdando_test 1.1 { 568d69a581Sdan execsql { INSERT INTO t1 VALUES(10, 11, 12) } 578d69a581Sdan set ::sync_count 588d69a581Sdan} 1 598d69a581Sdan 608d69a581Sdandb close 618d69a581Sdantvfs devchar sequential 628d69a581Sdansqlite3 db test.db -vfs tvfs 638d69a581Sdando_execsql_test 1.2 { 648d69a581Sdan PRAGMA synchronous = normal; 658d69a581Sdan INSERT INTO t1 VALUES(13, 14, 15); 668d69a581Sdan INSERT INTO t1 VALUES(16, 17, 18); 678d69a581Sdan PRAGMA wal_checkpoint; 688d69a581Sdan} {0 4 4} 698d69a581Sdan 708d69a581Sdanset ::sync_count 0 718d69a581Sdando_test 1.3 { 728d69a581Sdan execsql { INSERT INTO t1 VALUES(10, 11, 12) } 738d69a581Sdan set ::sync_count 748d69a581Sdan} 0 758d69a581Sdan 768d69a581Sdan#------------------------------------------------------------------------- 778d69a581Sdan# Test that "PRAGMA journal_size_limit" works in wal mode. 788d69a581Sdan# 798d69a581Sdanreset_db 808d69a581Sdando_execsql_test 2.0 { 818d69a581Sdan PRAGMA journal_size_limit = 10000; 828d69a581Sdan CREATE TABLE t1(x); 838d69a581Sdan PRAGMA journal_mode = wal; 848d69a581Sdan WITH s(i) AS ( 858d69a581Sdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 868d69a581Sdan ) 878d69a581Sdan INSERT INTO t1 SELECT randomblob(750) FROM s; 888d69a581Sdan} {10000 wal} 898d69a581Sdando_test 2.1 { 908d69a581Sdan expr [file size test.db-wal]>12000 918d69a581Sdan} {1} 928d69a581Sdando_test 2.2 { 938d69a581Sdan execsql { 948d69a581Sdan PRAGMA wal_checkpoint; 958d69a581Sdan INSERT INTO t1 VALUES(randomblob(750)); 968d69a581Sdan } 978d69a581Sdan file size test.db-wal 988d69a581Sdan} {10000} 998d69a581Sdando_test 2.3 { 1008d69a581Sdan execsql { 1018d69a581Sdan PRAGMA journal_size_limit = 8000; 1028d69a581Sdan PRAGMA wal_checkpoint; 1038d69a581Sdan INSERT INTO t1 VALUES(randomblob(750)); 1048d69a581Sdan } 1058d69a581Sdan file size test.db-wal 1068d69a581Sdan} {8000} 1078d69a581Sdan 1088d69a581Sdan#------------------------------------------------------------------------- 1098d69a581Sdan# Test that a checkpoint may be interrupted using sqlite3_interrupt(). 11089dec01eSdan# And that the error code is SQLITE_NOMEM, not SQLITE_INTERRUPT, if 11189dec01eSdan# an OOM error occurs just before the sqlite3_interrupt() call. 1128d69a581Sdan# 1138d69a581Sdanreset_db 1148d69a581Sdandb close 1158d69a581Sdansqlite3 db test.db -vfs tvfs 1168d69a581Sdantvfs filter {} 1178d69a581Sdan 1188d69a581Sdando_execsql_test 3.0 { 1198d69a581Sdan CREATE TABLE t1(x); 1208d69a581Sdan PRAGMA journal_mode = wal; 1218d69a581Sdan WITH s(i) AS ( 1228d69a581Sdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 1238d69a581Sdan ) 1248d69a581Sdan INSERT INTO t1 SELECT randomblob(750) FROM s; 1258d69a581Sdan} {wal} 1268d69a581Sdan 1278d69a581Sdantvfs filter xWrite 1288d69a581Sdantvfs script xWrite 1298d69a581Sdanset ::cnt 2 1308d69a581Sdanproc xWrite {method file args} { 1318d69a581Sdan if {[file tail $file]=="test.db"} { 1328d69a581Sdan incr ::cnt -1 1338d69a581Sdan if {$::cnt==0} { 1348d69a581Sdan sqlite3_interrupt db 1358d69a581Sdan } 1368d69a581Sdan } 1378d69a581Sdan return SQLITE_OK 1388d69a581Sdan} 1398d69a581Sdan 1408d69a581Sdando_catchsql_test 3.1 { 1418d69a581Sdan PRAGMA wal_checkpoint 1428d69a581Sdan} {1 interrupted} 1438d69a581Sdan 14489dec01eSdanset ::cnt 2 14589dec01eSdanproc xWrite {method file args} { 14689dec01eSdan if {[file tail $file]=="test.db"} { 14789dec01eSdan incr ::cnt -1 14889dec01eSdan if {$::cnt==0} { 149ed0af52cSdan sqlite3_memdebug_fail 1 -repeat 0 150ee822185Sdan # For this test to pass, the following statement must call malloc() at 151ee822185Sdan # least once. Even if the lookaside is enabled. 152ee822185Sdan set ::xwrite_stmt_res [catchsql { SELECT hex(randomblob(4000)) }] 15389dec01eSdan sqlite3_interrupt db 15489dec01eSdan } 15589dec01eSdan } 15689dec01eSdan return SQLITE_OK 15789dec01eSdan} 15889dec01eSdan 159ee822185Sdanset ::xwrite_stmt_res "" 16089dec01eSdando_catchsql_test 3.2 { 16189dec01eSdan PRAGMA wal_checkpoint 16289dec01eSdan} {1 {out of memory}} 163ee822185Sdando_test 3.2.2 { 164ee822185Sdan set ::xwrite_stmt_res 165ee822185Sdan} {1 {out of memory}} 166ee822185Sdanunset ::xwrite_stmt_res 16789dec01eSdan 1688d69a581Sdan#------------------------------------------------------------------------- 1698d69a581Sdan# 1708d69a581Sdanreset_db 1718d69a581Sdandb close 1728d69a581Sdando_test 4.0 { 1738d69a581Sdan sqlite3 db test.db -vfs tvfs 1748d69a581Sdan execsql { 1758d69a581Sdan CREATE TABLE t1(x); 1768d69a581Sdan PRAGMA journal_mode = wal; 1778d69a581Sdan WITH s(i) AS ( 1788d69a581Sdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 1798d69a581Sdan ) 1808d69a581Sdan INSERT INTO t1 SELECT randomblob(750) FROM s; 1818d69a581Sdan } db 1828d69a581Sdan} {wal} 1838d69a581Sdandb close 1848d69a581Sdan 1858d69a581Sdantvfs filter xShmMap 1868d69a581Sdantvfs script xShmMap 1878d69a581Sdanproc xShmMap {method file args} { 1888d69a581Sdan return SQLITE_READONLY 1898d69a581Sdan} 1908d69a581Sdansqlite3 db test.db -vfs tvfs 1918d69a581Sdando_catchsql_test 4.1 { 1928d69a581Sdan SELECT count(*) FROM t1 1938d69a581Sdan} {1 {attempt to write a readonly database}} 1948d69a581Sdan 1958d69a581Sdanset ::cnt 5 1968d69a581Sdantvfs filter {xShmMap xShmLock} 1978d69a581Sdanproc xShmMap {method file name args} { 1988d69a581Sdan switch -- $method { 1998d69a581Sdan xShmMap { return SQLITE_READONLY } 2008d69a581Sdan xShmLock { 2018d69a581Sdan if {$args == "{0 1 lock shared}"} { 2028d69a581Sdan incr ::cnt -1 2038d69a581Sdan if {$::cnt>0} { return SQLITE_BUSY } 2048d69a581Sdan } 2058d69a581Sdan } 2068d69a581Sdan } 2078d69a581Sdan return SQLITE_OK 2088d69a581Sdan} 2098d69a581Sdando_catchsql_test 4.2 { 2108d69a581Sdan SELECT count(*) FROM t1 2118d69a581Sdan} {1 {attempt to write a readonly database}} 2128d69a581Sdan 21376e4990bSdan#------------------------------------------------------------------------- 21476e4990bSdan# 21576e4990bSdanreset_db 21676e4990bSdandb close 21776e4990bSdansqlite3 db test.db -vfs tvfs 21876e4990bSdantvfs filter {} 21976e4990bSdando_execsql_test 5.0 { 22076e4990bSdan PRAGMA auto_vacuum = 0; 22176e4990bSdan PRAGMA page_size = 1024; 22276e4990bSdan CREATE TABLE t1(x); 22376e4990bSdan PRAGMA journal_mode = wal; 22476e4990bSdan WITH s(i) AS ( 22576e4990bSdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 22676e4990bSdan ) 22776e4990bSdan INSERT INTO t1 SELECT randomblob(750) FROM s; 22876e4990bSdan} {wal} 22976e4990bSdan 23076e4990bSdando_execsql_test 5.1 { 23176e4990bSdan SELECT count(*) FROM t1 23276e4990bSdan} {20} 23376e4990bSdan 23476e4990bSdando_test 5.2 { 23576e4990bSdan vfs_set_readmark db main 1 100 23676e4990bSdan vfs_set_readmark db main 2 100 23776e4990bSdan vfs_set_readmark db main 3 100 23876e4990bSdan vfs_set_readmark db main 4 100 23976e4990bSdan} {100} 24076e4990bSdan 24176e4990bSdando_execsql_test 5.3 { 24276e4990bSdan SELECT count(*) FROM t1 24376e4990bSdan} {20} 24476e4990bSdan 24576e4990bSdando_test 5.3 { 24676e4990bSdan list [vfs_set_readmark db main 1] \ 24776e4990bSdan [vfs_set_readmark db main 2] \ 24876e4990bSdan [vfs_set_readmark db main 3] \ 24976e4990bSdan [vfs_set_readmark db main 4] 25076e4990bSdan} {24 100 100 100} 25176e4990bSdan 25276e4990bSdantvfs script xShmLock 25376e4990bSdantvfs filter xShmLock 25476e4990bSdanset ::cnt 20 25576e4990bSdanproc xShmLock {args} { 25676e4990bSdan incr ::cnt -1 25776e4990bSdan if {$::cnt>0} { return SQLITE_BUSY } 25876e4990bSdan return SQLITE_OK 25976e4990bSdan} 26076e4990bSdan 26176e4990bSdando_test 5.4 { 26276e4990bSdan vfs_set_readmark db main 1 100 26376e4990bSdan execsql { SELECT count(*) FROM t1 } 26476e4990bSdan} {20} 26576e4990bSdan 26689dec01eSdanvfs_set_readmark db main 1 100 26789dec01eSdanvfs_set_readmark db main 2 100 26889dec01eSdanvfs_set_readmark db main 3 100 26989dec01eSdanvfs_set_readmark db main 4 100 27089dec01eSdan 27189dec01eSdantvfs script xShmMapLock 27289dec01eSdantvfs filter {xShmLock xShmMap} 27389dec01eSdanproc xShmMapLock {method args} { 27489dec01eSdan if {$method=="xShmMap"} { 27589dec01eSdan return "SQLITE_READONLY" 27689dec01eSdan } 27789dec01eSdan return SQLITE_BUSY 27889dec01eSdan} 27989dec01eSdan 28089dec01eSdansqlite3 db2 test.db -vfs tvfs 28189dec01eSdanbreakpoint 28289dec01eSdando_test 5.5 { 28389dec01eSdan list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg 28489dec01eSdan} {1 {attempt to write a readonly database}} 28589dec01eSdan 28689dec01eSdantvfs filter {} 28789dec01eSdanvfs_set_readmark db main 1 1 28889dec01eSdan 28989dec01eSdando_test 5.6 { 29089dec01eSdan list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg 29189dec01eSdan} {0 20} 29289dec01eSdandb2 close 29389dec01eSdandb close 29489dec01eSdan 29576e4990bSdan#------------------------------------------------------------------------- 29676e4990bSdan# Cause an SQLITE_PROTOCOL while attempting to restart the wal file. 29792107a38Sdan# 29876e4990bSdanreset_db 29976e4990bSdantvfs filter {} 30076e4990bSdandb close 30176e4990bSdansqlite3 db test.db -vfs tvfs 30276e4990bSdando_execsql_test 6.0 { 30376e4990bSdan PRAGMA auto_vacuum = 0; 30476e4990bSdan PRAGMA page_size = 1024; 30576e4990bSdan CREATE TABLE t1(x); 30676e4990bSdan PRAGMA journal_mode = wal; 30776e4990bSdan WITH s(i) AS ( 30876e4990bSdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 30976e4990bSdan ) 31076e4990bSdan INSERT INTO t1 SELECT randomblob(750) FROM s; 31176e4990bSdan} {wal} 31276e4990bSdan 31376e4990bSdando_test 6.1 { 31476e4990bSdan execsql { PRAGMA wal_checkpoint } 31576e4990bSdan set {} {} 31676e4990bSdan} {} 31776e4990bSdan 31876e4990bSdantvfs filter xShmLock 31989dec01eSdantvfs script xShmLock 32076e4990bSdanset ::flag 0 32176e4990bSdanproc xShmLock {method file handle spec} { 32276e4990bSdan if {$::flag && [lrange $spec 2 end]=="lock shared"} { 32376e4990bSdan return SQLITE_BUSY 32476e4990bSdan } 32576e4990bSdan if {$spec=="3 1 unlock shared"} { 32676e4990bSdan set ::flag 1 32776e4990bSdan } 32876e4990bSdan return SQLITE_OK 32976e4990bSdan} 33076e4990bSdan 33176e4990bSdanputs "# WARNING: This next test takes around 12 seconds" 33276e4990bSdando_catchsql_test 6.2 { 33376e4990bSdan INSERT INTO t1 VALUES(1); 33476e4990bSdan} {1 {locking protocol}} 33576e4990bSdan 33692107a38Sdan#------------------------------------------------------------------------- 33792107a38Sdan# Check that a checkpoint fails if it cannot get the CHECKPOINTER lock 33892107a38Sdan# 33992107a38Sdanreset_db 34092107a38Sdantvfs filter {} 34192107a38Sdandb close 34292107a38Sdansqlite3 db test.db -vfs tvfs 34392107a38Sdando_execsql_test 7.0 { 34492107a38Sdan PRAGMA auto_vacuum = 0; 34592107a38Sdan PRAGMA page_size = 1024; 34692107a38Sdan CREATE TABLE t1(x); 34792107a38Sdan PRAGMA journal_mode = wal; 34892107a38Sdan WITH s(i) AS ( 34992107a38Sdan SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 35092107a38Sdan ) 35192107a38Sdan INSERT INTO t1 SELECT randomblob(750) FROM s; 35292107a38Sdan} {wal} 35392107a38Sdan 35492107a38Sdantvfs script xShmLock 35592107a38Sdantvfs filter xShmLock 35692107a38Sdanproc xShmLock {method file handle spec} { 35792107a38Sdan if {$spec=="1 1 lock exclusive"} { 35892107a38Sdan return SQLITE_BUSY 35992107a38Sdan } 36092107a38Sdan return SQLITE_OK 36192107a38Sdan} 36292107a38Sdan 36392107a38Sdando_execsql_test 7.1 { 36492107a38Sdan PRAGMA wal_checkpoint 36592107a38Sdan} {1 -1 -1} 36692107a38Sdan 36789dec01eSdan#------------------------------------------------------------------------- 36889dec01eSdan# Check that the page cache is correctly flushed if a checkpointer using 36989dec01eSdan# a version 2 VFS makes a checkpoint with an out-of-date cache. 37089dec01eSdan# 37189dec01eSdanreset_db 37289dec01eSdantestvfs tvfs2 -iversion 2 3738d69a581Sdandb close 37489dec01eSdansqlite3 db test.db -vfs tvfs2 37589dec01eSdando_execsql_test 8.0 { 37689dec01eSdan PRAGMA auto_vacuum = 0; 37789dec01eSdan PRAGMA page_size = 1024; 37889dec01eSdan CREATE TABLE t1(x); 37989dec01eSdan PRAGMA journal_mode = wal; 38089dec01eSdan WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) 38189dec01eSdan INSERT INTO t1 SELECT randomblob(75) FROM s; 38289dec01eSdan} {wal} 38389dec01eSdan 38489dec01eSdando_execsql_test 8.1 { SELECT count(*) FROM t1 } {20} 38589dec01eSdan 38689dec01eSdando_test 8.2 { 38789dec01eSdan sqlite3 db2 test.db -vfs tvfs2 38889dec01eSdan execsql { 38989dec01eSdan INSERT INTO t1 VALUES(randomblob(75)); 39089dec01eSdan } db2 39189dec01eSdan db2 close 39289dec01eSdan} {} 39389dec01eSdan 39489dec01eSdando_execsql_test 8.3 { 39589dec01eSdan PRAGMA wal_checkpoint; 39689dec01eSdan SELECT count(*) FROM t1 39789dec01eSdan} {0 5 5 21} 39883420823Sdandb close 39989dec01eSdantvfs2 delete 40089dec01eSdan 40189dec01eSdan#------------------------------------------------------------------------- 40289dec01eSdanreset_db 40389dec01eSdandb close 40489dec01eSdansqlite3 db test.db -vfs tvfs 40589dec01eSdando_execsql_test 9.0 { 40689dec01eSdan PRAGMA auto_vacuum = 0; 40789dec01eSdan PRAGMA page_size = 1024; 40889dec01eSdan CREATE TABLE t1(x); 40989dec01eSdan PRAGMA journal_mode = wal; 41089dec01eSdan WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) 41189dec01eSdan INSERT INTO t1 SELECT randomblob(75) FROM s; 41289dec01eSdan} {wal} 41389dec01eSdan 41489dec01eSdansqlite3 db2 test.db -vfs tvfs 41589dec01eSdantvfs filter {xShmMap xShmLock} 41689dec01eSdantvfs script xShmMap 41789dec01eSdanproc xShmMap {method file handle args} { 41889dec01eSdan switch -- $method { 41989dec01eSdan xShmMap { 42089dec01eSdan return "SQLITE_READONLY_CANTINIT" 42189dec01eSdan } 42289dec01eSdan xShmLock { 42389dec01eSdan if {$args=="{3 1 lock shared}"} { 42489dec01eSdan return "SQLITE_IOERR" 42589dec01eSdan } 42689dec01eSdan } 42789dec01eSdan } 42889dec01eSdan} 42989dec01eSdan 43089dec01eSdando_test 9.1 { 43189dec01eSdan catchsql { SELECT count(*) FROM t1 } db2 43289dec01eSdan} {1 {disk I/O error}} 43389dec01eSdan 43489dec01eSdandb close 43589dec01eSdandb2 close 4368d69a581Sdantvfs delete 4378d69a581Sdanfinish_test 438