176ed3bc0Sdan# 2010 May 03 276ed3bc0Sdan# 376ed3bc0Sdan# The author disclaims copyright to this source code. In place of 476ed3bc0Sdan# a legal notice, here is a blessing: 576ed3bc0Sdan# 676ed3bc0Sdan# May you do good and not evil. 776ed3bc0Sdan# May you find forgiveness for yourself and forgive others. 876ed3bc0Sdan# May you share freely, never taking more than you give. 976ed3bc0Sdan# 1076ed3bc0Sdan#*********************************************************************** 1176ed3bc0Sdan# This file implements regression tests for SQLite library. The 1276ed3bc0Sdan# focus of this file is testing the operation of the library in 1376ed3bc0Sdan# "PRAGMA journal_mode=WAL" mode. 1476ed3bc0Sdan# 1576ed3bc0Sdan 1676ed3bc0Sdanset testdir [file dirname $argv0] 1776ed3bc0Sdansource $testdir/tester.tcl 1876ed3bc0Sdansource $testdir/malloc_common.tcl 1976ed3bc0Sdan 2076ed3bc0Sdanifcapable !wal {finish_test ; return } 2176ed3bc0Sdan 2276ed3bc0Sdando_malloc_test walfault-oom-1 -sqlbody { 2376ed3bc0Sdan PRAGMA journal_mode = WAL; 2476ed3bc0Sdan CREATE TABLE t1(a, b); 2576ed3bc0Sdan INSERT INTO t1 VALUES(1, 2); 26ef378025Sdan PRAGMA wal_checkpoint; 2776ed3bc0Sdan} 2876ed3bc0Sdan 295e9e482fSdando_malloc_test walfault-oom-2 -tclprep { 305e9e482fSdan execsql { 315e9e482fSdan PRAGMA journal_mode = WAL; 325e9e482fSdan BEGIN; 335e9e482fSdan CREATE TABLE x(y, z, UNIQUE(y, z)); 345e9e482fSdan INSERT INTO x VALUES(randomblob(100), randomblob(100)); 355e9e482fSdan COMMIT; 365e9e482fSdan PRAGMA wal_checkpoint; 375e9e482fSdan 385e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 395e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 405e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 415e9e482fSdan } 425e9e482fSdan file copy -force test.db testX.db 435e9e482fSdan file copy -force test.db-wal testX.db-wal 445e9e482fSdan db close 455e9e482fSdan file rename -force testX.db test.db 465e9e482fSdan file rename -force testX.db-wal test.db-wal 475e9e482fSdan 485e9e482fSdan sqlite3 db test.db 495e9e482fSdan sqlite3_extended_result_codes db 1 505e9e482fSdan sqlite3_db_config_lookaside db 0 0 0 515e9e482fSdan} -sqlbody { 525e9e482fSdan SELECT count(*) FROM x; 535e9e482fSdan} 545e9e482fSdan 559a6b4e9aSdando_ioerr_test walfault-ioerr-1 -sqlprep { 569a6b4e9aSdan PRAGMA auto_vacuum = 1; 579a6b4e9aSdan PRAGMA journal_mode = WAL; 589a6b4e9aSdan CREATE TABLE abc(a PRIMARY KEY); 599a6b4e9aSdan INSERT INTO abc VALUES(randomblob(1500)); 609a6b4e9aSdan} -sqlbody { 619a6b4e9aSdan DELETE FROM abc; 629a6b4e9aSdan PRAGMA wal_checkpoint; 639a6b4e9aSdan} 64*a10069ddSshanehcatch {db close} 659a6b4e9aSdan 66c7991bdfSdan# A [testvfs] callback for the VFS created by [do_shmfault_test]. This 678f6097c2Sdan# callback injects SQLITE_IOERR faults into methods for which an entry 688f6097c2Sdan# in array ::shmfault_ioerr_methods is defined. For example, to enable 698f6097c2Sdan# errors in xShmOpen: 70c7991bdfSdan# 718f6097c2Sdan# set ::shmfault_ioerr_methods(xShmOpen) 1 72c7991bdfSdan# 73c7991bdfSdan# Faults are not injected into xShmRelease, xShmClose or xShmLock method 74c7991bdfSdan# calls. The global tcl variables used are: 75c7991bdfSdan# 76c7991bdfSdan# $::shmfault_ioerr_countdown 77c7991bdfSdan# $::shmfault_ioerr_persist 788f6097c2Sdan# $::shmfault_ioerr_methods 79c7991bdfSdan# 80c7991bdfSdanproc shmfault_vfs_cb {method args} { 81c7991bdfSdan 82c7991bdfSdan # If ::shmfault_ioerr_countdown is not set, always return SQLITE_OK. 83c7991bdfSdan # 84c7991bdfSdan if {[info exists ::shmfault_ioerr_countdown]==0} { return SQLITE_OK } 85c7991bdfSdan 868f6097c2Sdan if {[info exists ::shmfault_ioerr_methods($method)]} { 87c7991bdfSdan incr ::shmfault_ioerr_countdown -1 88c7991bdfSdan if { ($::shmfault_ioerr_countdown==0) 89c7991bdfSdan || ($::shmfault_ioerr_countdown<=0 && $::shmfault_ioerr_persist) 90c7991bdfSdan } { 91c7991bdfSdan return SQLITE_IOERR 92c7991bdfSdan } 93c7991bdfSdan } 94c7991bdfSdan return SQLITE_OK 95c7991bdfSdan} 96c7991bdfSdan 978f6097c2Sdan# Options are: 988f6097c2Sdan# 998f6097c2Sdan# -tclprep TCL 1008f6097c2Sdan# -sqlprep SQL 1018f6097c2Sdan# -sqlbody SQL 1028f6097c2Sdan# 103c7991bdfSdanproc do_shmfault_test {name args} { 1048f6097c2Sdan 1058f6097c2Sdan set A(-tclprep) "sqlite3 db test.db -vfs shmfault" 1068f6097c2Sdan set A(-sqlprep) "" 1078f6097c2Sdan set A(-sqlbody) "" 1088f6097c2Sdan set A(-methods) [list xShmGet xShmOpen xShmSize] 109d41a29a6Sdan set A(-coverageonly) 0 110c7991bdfSdan array set A $args 111c7991bdfSdan 112c7991bdfSdan # Create a VFS to use: 113c7991bdfSdan testvfs shmfault shmfault_vfs_cb 114c7991bdfSdan 1158f6097c2Sdan unset -nocomplain ::shmfault_ioerr_methods 1168f6097c2Sdan foreach m $A(-methods) { set ::shmfault_ioerr_methods($m) 1 } 1178f6097c2Sdan 118c7991bdfSdan foreach mode {transient persistent} { 119c7991bdfSdan set ::shmfault_ioerr_persist [expr {$mode == "persistent"}] 1208f6097c2Sdan 121c7991bdfSdan for {set nDelay 1} {$nDelay < 10000} {incr nDelay} { 122c7991bdfSdan 123c7991bdfSdan file delete -force test.db test.db-wal test.db-journal 124c7991bdfSdan 1258f6097c2Sdan eval $A(-tclprep) 1268f6097c2Sdan db eval $A(-sqlprep) 1278f6097c2Sdan 1288f6097c2Sdan set ::shmfault_ioerr_countdown $nDelay 1298f6097c2Sdan set rc [catch { db eval $A(-sqlbody) } msg] 130c7991bdfSdan set hit_error [expr {$::shmfault_ioerr_countdown<=0}] 131c7991bdfSdan unset ::shmfault_ioerr_countdown 1328f6097c2Sdan 133c7991bdfSdan catch { db close } 134c7991bdfSdan 135d41a29a6Sdan if {$A(-coverageonly)} { set rc $hit_error } 136c7991bdfSdan do_test $name-$mode.$nDelay.1 [list set {} $hit_error] $rc 137c7991bdfSdan 138c7991bdfSdan if {$hit_error==0} break 139c7991bdfSdan } 140c7991bdfSdan } 141c7991bdfSdan 142c7991bdfSdan shmfault delete 143c7991bdfSdan} 144c7991bdfSdan 145c7991bdfSdando_shmfault_test walfault-shm-1 -sqlbody { 146c7991bdfSdan PRAGMA journal_mode = WAL; 147c7991bdfSdan CREATE TABLE t1(a PRIMARY KEY, b); 148c7991bdfSdan INSERT INTO t1 VALUES('a', 'b'); 149c7991bdfSdan PRAGMA wal_checkpoint; 150c7991bdfSdan} 15176ed3bc0Sdan 1528f6097c2Sdando_shmfault_test walfault-shm-2 -methods xShmSize -sqlprep { 1538f6097c2Sdan PRAGMA page_size = 512; 1548f6097c2Sdan PRAGMA journal_mode = WAL; 1558f6097c2Sdan PRAGMA wal_autocheckpoint = 0; 1568f6097c2Sdan} -sqlbody { 1578f6097c2Sdan CREATE TABLE t1(x); 1588f6097c2Sdan BEGIN; 1598f6097c2Sdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 1608f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 1618f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 1628f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 1638f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 1648f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 1658f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 1668f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 1678f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 1688f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 1698f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 1708f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 1718f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 1728f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 1738f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 1748f6097c2Sdan COMMIT; 1758f6097c2Sdan} 1768f6097c2Sdan 1778f6097c2Sdando_shmfault_test walfault-shm-3 -methods xShmSize -tclprep { 1788f6097c2Sdan sqlite3 db test.db -vfs shmfault 1798f6097c2Sdan unset -nocomplain ::shmfault_ioerr_countdown 1808f6097c2Sdan db eval { 1818f6097c2Sdan PRAGMA page_size = 512; 1828f6097c2Sdan PRAGMA journal_mode = WAL; 1838f6097c2Sdan PRAGMA wal_autocheckpoint = 0; 1848f6097c2Sdan CREATE TABLE t1(x); 1858f6097c2Sdan BEGIN; 1868f6097c2Sdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 1878f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 1888f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 1898f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 1908f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 1918f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 1928f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 1938f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 1948f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 1958f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 1968f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 1978f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 1988f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 1998f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 2008f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 2018f6097c2Sdan COMMIT; 2028f6097c2Sdan } 2038f6097c2Sdan 2048f6097c2Sdan set ::shmfault_ioerr_countdown 1 2058f6097c2Sdan set ::shmfault_ioerr_methods(xShmGet) 1 2068f6097c2Sdan db close 2078f6097c2Sdan unset ::shmfault_ioerr_methods(xShmGet) 2088f6097c2Sdan if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"} 2098f6097c2Sdan 2108f6097c2Sdan sqlite3 db test.db -vfs shmfault 2118f6097c2Sdan} -sqlbody { 2128f6097c2Sdan SELECT count(*) FROM t1; 2138f6097c2Sdan} 2148f6097c2Sdan 215a861469aSdando_shmfault_test walfault-shm-4 -tclprep { 216a861469aSdan sqlite3 db test.db -vfs shmfault 217a861469aSdan unset -nocomplain ::shmfault_ioerr_countdown 218a861469aSdan db eval { 219a861469aSdan PRAGMA page_size = 512; 220a861469aSdan PRAGMA journal_mode = WAL; 221a861469aSdan PRAGMA wal_autocheckpoint = 0; 222a861469aSdan CREATE TABLE t1(x); 223a861469aSdan BEGIN; 224a861469aSdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 225a861469aSdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 226a861469aSdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 227a861469aSdan COMMIT; 228a861469aSdan } 229a861469aSdan 230a861469aSdan set ::shmfault_ioerr_countdown 1 231a861469aSdan set ::shmfault_ioerr_methods(xShmGet) 1 232a861469aSdan db close 233a861469aSdan unset ::shmfault_ioerr_methods(xShmGet) 234a861469aSdan if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"} 235a861469aSdan sqlite3 db test.db -vfs shmfault 236a861469aSdan} -sqlbody { 237a861469aSdan SELECT count(*) FROM t1; 238a861469aSdan} 239a861469aSdan 240d41a29a6Sdando_shmfault_test walfault-shm-5 -coverageonly 1 -sqlprep { 241d41a29a6Sdan PRAGMA cache_size = 10; 242d41a29a6Sdan PRAGMA journal_mode = WAL; 243d41a29a6Sdan CREATE TABLE abc(a PRIMARY KEY); 244d41a29a6Sdan INSERT INTO abc VALUES(randomblob(900)); 245d41a29a6Sdan} -sqlbody { 246d41a29a6Sdan BEGIN; 247d41a29a6Sdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 248d41a29a6Sdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 249d41a29a6Sdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 250d41a29a6Sdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 251d41a29a6Sdan ROLLBACK; 252d41a29a6Sdan} 253d41a29a6Sdan 25465f2ac58Sdan#------------------------------------------------------------------------- 25565f2ac58Sdan# When a database is checkpointed, SQLite does the following: 25665f2ac58Sdan# 25765f2ac58Sdan# 1. xShmLock(CHECKPOINT) to lock the WAL. 25865f2ac58Sdan# 2. xShmGet(-1) to get a mapping to read the wal-index header. 25965f2ac58Sdan# 3. If the mapping obtained in (2) is not large enough to cover the 26065f2ac58Sdan# entire wal-index, call xShmGet(nReq) to get a larger mapping. 26165f2ac58Sdan# 4. Do the checkpoint. 26265f2ac58Sdan# 5. Release the lock and mapping. 26365f2ac58Sdan# 26465f2ac58Sdan# This test case tests the outcome of an IO error in step 2. 26565f2ac58Sdan# 26665f2ac58Sdanproc shmfault_vfs_cb_6 {method args} { 26765f2ac58Sdan switch -- $::shm_state { 26865f2ac58Sdan 0 { return SQLITE_OK } 26965f2ac58Sdan 1 { 27065f2ac58Sdan if {$method == "xShmGet"} { 27165f2ac58Sdan set ::wal_index [tvfs shm [lindex $args 0]] 27265f2ac58Sdan tvfs shm [lindex $args 0] [string range $::wal_index 0 65535] 27365f2ac58Sdan set ::shm_state 2 27465f2ac58Sdan } 27565f2ac58Sdan } 27665f2ac58Sdan 2 { 27765f2ac58Sdan if {$method == "xShmGet"} { 27865f2ac58Sdan tvfs shm [lindex $args 0] $::wal_index 27965f2ac58Sdan return SQLITE_IOERR 28065f2ac58Sdan } 28165f2ac58Sdan } 28265f2ac58Sdan } 28365f2ac58Sdan return SQLITE_OK 28465f2ac58Sdan} 28565f2ac58Sdando_test walfault-shm-6.1 { 28665f2ac58Sdan set ::shm_state 0 28765f2ac58Sdan testvfs tvfs shmfault_vfs_cb_6 28865f2ac58Sdan 28965f2ac58Sdan sqlite3 db test.db -vfs tvfs 29065f2ac58Sdan sqlite3 db2 test.db -vfs tvfs 29165f2ac58Sdan 29265f2ac58Sdan execsql { 29365f2ac58Sdan PRAGMA journal_mode = WAL; 29465f2ac58Sdan PRAGMA wal_autocheckpoint = 0; 29565f2ac58Sdan CREATE TABLE t1(x); 29665f2ac58Sdan INSERT INTO t1 VALUES(randomblob(900)); 29765f2ac58Sdan } 29865f2ac58Sdan} {wal 0} 29965f2ac58Sdando_test walfault-shm-6.2 { 30065f2ac58Sdan execsql { 30165f2ac58Sdan PRAGMA wal_autocheckpoint = 0; 30265f2ac58Sdan BEGIN; 30365f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */ 30465f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */ 30565f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */ 30665f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */ 30765f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */ 30865f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ 30965f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ 31065f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ 31165f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ 31265f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ 31365f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */ 31465f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */ 31565f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */ 31665f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */ 31765f2ac58Sdan COMMIT; 31865f2ac58Sdan } db2 31965f2ac58Sdan} {0} 32065f2ac58Sdando_test walfault-shm-6.3 { 32165f2ac58Sdan set ::shm_state 1 32265f2ac58Sdan catchsql { PRAGMA wal_checkpoint } db2 32365f2ac58Sdan} {1 {disk I/O error}} 32465f2ac58Sdanset ::shm_state 0 32565f2ac58Sdandb close 32665f2ac58Sdandb2 close 32765f2ac58Sdantvfs delete 32865f2ac58Sdanunset -nocomplain ::wal_index ::shm_state 32965f2ac58Sdan 33076ed3bc0Sdanfinish_test 331c7991bdfSdan 332