1d3f8f946Sdan# 2010 April 13 2d3f8f946Sdan# 3d3f8f946Sdan# The author disclaims copyright to this source code. In place of 4d3f8f946Sdan# a legal notice, here is a blessing: 5d3f8f946Sdan# 6d3f8f946Sdan# May you do good and not evil. 7d3f8f946Sdan# May you find forgiveness for yourself and forgive others. 8d3f8f946Sdan# May you share freely, never taking more than you give. 9d3f8f946Sdan# 10d3f8f946Sdan#*********************************************************************** 11d3f8f946Sdan# This file implements regression tests for SQLite library. The 12d3f8f946Sdan# focus of this file is testing the operation of the library in 13d3f8f946Sdan# "PRAGMA journal_mode=WAL" mode. 14d3f8f946Sdan# 157c24610eSdan 167c24610eSdanset testdir [file dirname $argv0] 177c24610eSdansource $testdir/tester.tcl 18e264d983Sdansource $testdir/lock_common.tcl 19a4a9095eSdansource $testdir/malloc_common.tcl 2010f5a50eSdansource $testdir/wal_common.tcl 217c24610eSdan 22ce8e5ffeSdanset testprefix wal 23ce8e5ffeSdan 245cf53537Sdanifcapable !wal {finish_test ; return } 257416f2edSdrhtest_set_config_pagecache 0 0 265cf53537Sdan 277c24610eSdanproc reopen_db {} { 28b9bf16bfSdan catch { db close } 29fda06befSmistachkin forcedelete test.db test.db-wal test.db-wal-summary 307c24610eSdan sqlite3_wal db test.db 317c24610eSdan} 327c24610eSdan 336703239dSdanset ::blobcnt 0 346703239dSdanproc blob {nByte} { 356703239dSdan incr ::blobcnt 366703239dSdan return [string range [string repeat "${::blobcnt}x" $nByte] 1 $nByte] 376703239dSdan} 386703239dSdan 397c24610eSdanproc sqlite3_wal {args} { 407c24610eSdan eval sqlite3 $args 4165bddc12Sdan [lindex $args 0] eval { PRAGMA auto_vacuum = 0 } 42e04dc88bSdan [lindex $args 0] eval { PRAGMA page_size = 1024 } 437c24610eSdan [lindex $args 0] eval { PRAGMA journal_mode = wal } 446703239dSdan [lindex $args 0] eval { PRAGMA synchronous = normal } 456703239dSdan [lindex $args 0] function blob blob 4658021b23Sdan db timeout 1000 477c24610eSdan} 487c24610eSdan 493de777fdSdanproc log_deleted {logfile} { 503de777fdSdan return [expr [file exists $logfile]==0] 513de777fdSdan} 523de777fdSdan 537c24610eSdan# 547c24610eSdan# These are 'warm-body' tests used while developing the WAL code. They 557c24610eSdan# serve to prove that a few really simple cases work: 567c24610eSdan# 577c24610eSdan# wal-1.*: Read and write the database. 587c24610eSdan# wal-2.*: Test MVCC with one reader, one writer. 597c24610eSdan# wal-3.*: Test transaction rollback. 607c24610eSdan# wal-4.*: Test savepoint/statement rollback. 617c24610eSdan# wal-5.*: Test the temp database. 627c24610eSdan# wal-6.*: Test creating databases with different page sizes. 637c24610eSdan# 64998ad212Sdan# 654bcc4988Sdan# 667c24610eSdando_test wal-0.1 { 6765bddc12Sdan execsql { PRAGMA auto_vacuum = 0 } 686703239dSdan execsql { PRAGMA synchronous = normal } 697c24610eSdan execsql { PRAGMA journal_mode = wal } 707c24610eSdan} {wal} 71e04dc88bSdando_test wal-0.2 { 72e04dc88bSdan file size test.db 73e04dc88bSdan} {1024} 747c24610eSdan 757c24610eSdando_test wal-1.0 { 767c24610eSdan execsql { 777c24610eSdan BEGIN; 787c24610eSdan CREATE TABLE t1(a, b); 797c24610eSdan } 80e04dc88bSdan list [file exists test.db-journal] \ 81e04dc88bSdan [file exists test.db-wal] \ 82e04dc88bSdan [file size test.db] 83e04dc88bSdan} {0 1 1024} 847c24610eSdando_test wal-1.1 { 857c24610eSdan execsql COMMIT 867c24610eSdan list [file exists test.db-journal] [file exists test.db-wal] 877c24610eSdan} {0 1} 887c24610eSdando_test wal-1.2 { 897c24610eSdan # There are now two pages in the log. 907c24610eSdan file size test.db-wal 9110f5a50eSdan} [wal_file_size 2 1024] 927c24610eSdan 937c24610eSdando_test wal-1.3 { 947c24610eSdan execsql { SELECT * FROM sqlite_master } 957c24610eSdan} {table t1 t1 2 {CREATE TABLE t1(a, b)}} 967c24610eSdan 977c24610eSdando_test wal-1.4 { 987c24610eSdan execsql { INSERT INTO t1 VALUES(1, 2) } 997c24610eSdan execsql { INSERT INTO t1 VALUES(3, 4) } 1007c24610eSdan execsql { INSERT INTO t1 VALUES(5, 6) } 1017c24610eSdan execsql { INSERT INTO t1 VALUES(7, 8) } 1027c24610eSdan execsql { INSERT INTO t1 VALUES(9, 10) } 1037c24610eSdan} {} 1047c24610eSdan 1057c24610eSdando_test wal-1.5 { 1067c24610eSdan execsql { SELECT * FROM t1 } 1077c24610eSdan} {1 2 3 4 5 6 7 8 9 10} 1087c24610eSdan 1097c24610eSdando_test wal-2.1 { 1107c24610eSdan sqlite3_wal db2 ./test.db 1117c24610eSdan execsql { BEGIN; SELECT * FROM t1 } db2 1127c24610eSdan} {1 2 3 4 5 6 7 8 9 10} 1137c24610eSdan 1147c24610eSdando_test wal-2.2 { 1157c24610eSdan execsql { INSERT INTO t1 VALUES(11, 12) } 1167c24610eSdan execsql { SELECT * FROM t1 } 1177c24610eSdan} {1 2 3 4 5 6 7 8 9 10 11 12} 1187c24610eSdan 1197c24610eSdando_test wal-2.3 { 1207c24610eSdan execsql { SELECT * FROM t1 } db2 1217c24610eSdan} {1 2 3 4 5 6 7 8 9 10} 1227c24610eSdan 1237c24610eSdando_test wal-2.4 { 1247c24610eSdan execsql { INSERT INTO t1 VALUES(13, 14) } 1257c24610eSdan execsql { SELECT * FROM t1 } 1267c24610eSdan} {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 1277c24610eSdan 1287c24610eSdando_test wal-2.5 { 1297c24610eSdan execsql { SELECT * FROM t1 } db2 1307c24610eSdan} {1 2 3 4 5 6 7 8 9 10} 1317c24610eSdan 1327c24610eSdando_test wal-2.6 { 1337c24610eSdan execsql { COMMIT; SELECT * FROM t1 } db2 1347c24610eSdan} {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 1357c24610eSdan 1367c24610eSdando_test wal-3.1 { 1377c24610eSdan execsql { BEGIN; DELETE FROM t1 } 1387c24610eSdan execsql { SELECT * FROM t1 } 1397c24610eSdan} {} 1407c24610eSdando_test wal-3.2 { 1417c24610eSdan execsql { SELECT * FROM t1 } db2 1427c24610eSdan} {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 1437c24610eSdando_test wal-3.3 { 1447c24610eSdan execsql { ROLLBACK } 1457c24610eSdan execsql { SELECT * FROM t1 } 1467c24610eSdan} {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 1477c24610eSdandb2 close 1487c24610eSdan 14974d6cd88Sdan#------------------------------------------------------------------------- 15074d6cd88Sdan# The following tests, wal-4.*, test that savepoints work with WAL 15174d6cd88Sdan# databases. 15274d6cd88Sdan# 1537c24610eSdando_test wal-4.1 { 1547c24610eSdan execsql { 1557c24610eSdan DELETE FROM t1; 1567c24610eSdan BEGIN; 1577c24610eSdan INSERT INTO t1 VALUES('a', 'b'); 1587c24610eSdan SAVEPOINT sp; 1597c24610eSdan INSERT INTO t1 VALUES('c', 'd'); 1607c24610eSdan SELECT * FROM t1; 1617c24610eSdan } 1627c24610eSdan} {a b c d} 1637c24610eSdando_test wal-4.2 { 1647c24610eSdan execsql { 1657c24610eSdan ROLLBACK TO sp; 1667c24610eSdan SELECT * FROM t1; 1677c24610eSdan } 1687c24610eSdan} {a b} 1697c24610eSdando_test wal-4.3 { 1707c24610eSdan execsql { 1717c24610eSdan COMMIT; 1727c24610eSdan SELECT * FROM t1; 1737c24610eSdan } 1747c24610eSdan} {a b} 1757c24610eSdan 1764cd78b4dSdando_test wal-4.4.1 { 17774d6cd88Sdan db close 17874d6cd88Sdan sqlite3 db test.db 17974d6cd88Sdan db func blob blob 18074d6cd88Sdan list [execsql { SELECT * FROM t1 }] [file size test.db-wal] 18174d6cd88Sdan} {{a b} 0} 1824cd78b4dSdando_test wal-4.4.2 { 18374d6cd88Sdan execsql { PRAGMA cache_size = 10 } 18474d6cd88Sdan execsql { 18574d6cd88Sdan CREATE TABLE t2(a, b); 18674d6cd88Sdan INSERT INTO t2 VALUES(blob(400), blob(400)); 18774d6cd88Sdan SAVEPOINT tr; 18874d6cd88Sdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 2 */ 18974d6cd88Sdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 4 */ 19074d6cd88Sdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 8 */ 19174d6cd88Sdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 16 */ 19274d6cd88Sdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 32 */ 19374d6cd88Sdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 2 */ 19474d6cd88Sdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 4 */ 19574d6cd88Sdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 8 */ 19674d6cd88Sdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 16 */ 19774d6cd88Sdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 32 */ 19874d6cd88Sdan SELECT count(*) FROM t2; 19974d6cd88Sdan } 20074d6cd88Sdan} {32} 2014cd78b4dSdando_test wal-4.4.3 { 20274d6cd88Sdan execsql { ROLLBACK TO tr } 20374d6cd88Sdan} {} 2044cd78b4dSdando_test wal-4.4.4 { 20574d6cd88Sdan set logsize [file size test.db-wal] 20674d6cd88Sdan execsql { 20774d6cd88Sdan INSERT INTO t1 VALUES('x', 'y'); 20874d6cd88Sdan RELEASE tr; 20974d6cd88Sdan } 21074d6cd88Sdan expr { $logsize == [file size test.db-wal] } 21174d6cd88Sdan} {1} 2124cd78b4dSdando_test wal-4.4.5 { 21374d6cd88Sdan execsql { SELECT count(*) FROM t2 } 21474d6cd88Sdan} {1} 2154cd78b4dSdando_test wal-4.4.6 { 216fda06befSmistachkin forcecopy test.db test2.db 217fda06befSmistachkin forcecopy test.db-wal test2.db-wal 21874d6cd88Sdan sqlite3 db2 test2.db 21974d6cd88Sdan execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2 22074d6cd88Sdan} {1 2} 2214cd78b4dSdando_test wal-4.4.7 { 22274d6cd88Sdan execsql { PRAGMA integrity_check } db2 22374d6cd88Sdan} {ok} 22474d6cd88Sdandb2 close 22574d6cd88Sdan 2264cd78b4dSdando_test wal-4.5.1 { 2274cd78b4dSdan reopen_db 2284cd78b4dSdan db func blob blob 2294cd78b4dSdan execsql { 2304cd78b4dSdan PRAGMA journal_mode = WAL; 2314cd78b4dSdan CREATE TABLE t1(a, b); 2324cd78b4dSdan INSERT INTO t1 VALUES('a', 'b'); 2334cd78b4dSdan } 2344cd78b4dSdan sqlite3 db test.db 2354cd78b4dSdan db func blob blob 2364cd78b4dSdan list [execsql { SELECT * FROM t1 }] [file size test.db-wal] 2374cd78b4dSdan} {{a b} 0} 2384cd78b4dSdando_test wal-4.5.2 { 2394cd78b4dSdan execsql { PRAGMA cache_size = 10 } 2404cd78b4dSdan execsql { 2414cd78b4dSdan CREATE TABLE t2(a, b); 2424cd78b4dSdan BEGIN; 2434cd78b4dSdan INSERT INTO t2 VALUES(blob(400), blob(400)); 2444cd78b4dSdan SAVEPOINT tr; 2454cd78b4dSdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 2 */ 2464cd78b4dSdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 4 */ 2474cd78b4dSdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 8 */ 2484cd78b4dSdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 16 */ 2494cd78b4dSdan INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 32 */ 2504cd78b4dSdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 2 */ 2514cd78b4dSdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 4 */ 2524cd78b4dSdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 8 */ 2534cd78b4dSdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 16 */ 2544cd78b4dSdan INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 32 */ 2554cd78b4dSdan SELECT count(*) FROM t2; 2564cd78b4dSdan } 2574cd78b4dSdan} {32} 2584cd78b4dSdando_test wal-4.5.3 { 2594cd78b4dSdan execsql { ROLLBACK TO tr } 2604cd78b4dSdan} {} 2614cd78b4dSdando_test wal-4.5.4 { 2624cd78b4dSdan set logsize [file size test.db-wal] 2634cd78b4dSdan execsql { 2644cd78b4dSdan INSERT INTO t1 VALUES('x', 'y'); 2654cd78b4dSdan RELEASE tr; 2664cd78b4dSdan COMMIT; 2674cd78b4dSdan } 2684cd78b4dSdan expr { $logsize == [file size test.db-wal] } 2694cd78b4dSdan} {1} 2704cd78b4dSdando_test wal-4.5.5 { 2714cd78b4dSdan execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } 2724cd78b4dSdan} {1 2} 2734cd78b4dSdando_test wal-4.5.6 { 274fda06befSmistachkin forcecopy test.db test2.db 275fda06befSmistachkin forcecopy test.db-wal test2.db-wal 2764cd78b4dSdan sqlite3 db2 test2.db 2774cd78b4dSdan execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2 2784cd78b4dSdan} {1 2} 2794cd78b4dSdando_test wal-4.5.7 { 2804cd78b4dSdan execsql { PRAGMA integrity_check } db2 2814cd78b4dSdan} {ok} 2824cd78b4dSdandb2 close 2834cd78b4dSdan 284b7d53f54Sdando_test wal-4.6.1 { 285b7d53f54Sdan execsql { 286b7d53f54Sdan DELETE FROM t2; 287b7d53f54Sdan PRAGMA wal_checkpoint; 288b7d53f54Sdan BEGIN; 289b7d53f54Sdan INSERT INTO t2 VALUES('w', 'x'); 290b7d53f54Sdan SAVEPOINT save; 291b7d53f54Sdan INSERT INTO t2 VALUES('y', 'z'); 292b7d53f54Sdan ROLLBACK TO save; 293b7d53f54Sdan COMMIT; 294b7d53f54Sdan } 295bdd9af0fSdan execsql { SELECT * FROM t2 } 296b7d53f54Sdan} {w x} 297b7d53f54Sdan 2984cd78b4dSdan 29974d6cd88Sdanreopen_db 3007c24610eSdando_test wal-5.1 { 3017c24610eSdan execsql { 3027c24610eSdan CREATE TEMP TABLE t2(a, b); 3037c24610eSdan INSERT INTO t2 VALUES(1, 2); 3047c24610eSdan } 3057c24610eSdan} {} 3067c24610eSdando_test wal-5.2 { 3077c24610eSdan execsql { 3087c24610eSdan BEGIN; 3097c24610eSdan INSERT INTO t2 VALUES(3, 4); 3107c24610eSdan SELECT * FROM t2; 3117c24610eSdan } 3127c24610eSdan} {1 2 3 4} 3137c24610eSdando_test wal-5.3 { 3147c24610eSdan execsql { 3157c24610eSdan ROLLBACK; 3167c24610eSdan SELECT * FROM t2; 3177c24610eSdan } 3187c24610eSdan} {1 2} 3197c24610eSdando_test wal-5.4 { 3207c24610eSdan execsql { 3217c24610eSdan CREATE TEMP TABLE t3(x UNIQUE); 3227c24610eSdan BEGIN; 3237c24610eSdan INSERT INTO t2 VALUES(3, 4); 3247c24610eSdan INSERT INTO t3 VALUES('abc'); 3257c24610eSdan } 3267c24610eSdan catchsql { INSERT INTO t3 VALUES('abc') } 327f9c8ce3cSdrh} {1 {UNIQUE constraint failed: t3.x}} 3287c24610eSdando_test wal-5.5 { 3297c24610eSdan execsql { 3307c24610eSdan COMMIT; 3317c24610eSdan SELECT * FROM t2; 3327c24610eSdan } 3337c24610eSdan} {1 2 3 4} 3347c24610eSdandb close 3357c24610eSdan 3367c24610eSdanforeach sector {512 4096} { 3377c24610eSdan sqlite3_simulate_device -sectorsize $sector 3387c24610eSdan foreach pgsz {512 1024 2048 4096} { 339fda06befSmistachkin forcedelete test.db test.db-wal 3407c24610eSdan do_test wal-6.$sector.$pgsz.1 { 341e04dc88bSdan sqlite3 db test.db -vfs devsym 3427c24610eSdan execsql " 3437c24610eSdan PRAGMA page_size = $pgsz; 34465bddc12Sdan PRAGMA auto_vacuum = 0; 345e04dc88bSdan PRAGMA journal_mode = wal; 3467c24610eSdan " 3477c24610eSdan execsql " 3487c24610eSdan CREATE TABLE t1(a, b); 3497c24610eSdan INSERT INTO t1 VALUES(1, 2); 3507c24610eSdan " 3517c24610eSdan db close 3527c24610eSdan file size test.db 3537c24610eSdan } [expr $pgsz*2] 3547c24610eSdan 3557c24610eSdan do_test wal-6.$sector.$pgsz.2 { 3563de777fdSdan log_deleted test.db-wal 3573de777fdSdan } {1} 3587c24610eSdan } 3597c24610eSdan} 3607c24610eSdan 3617c24610eSdando_test wal-7.1 { 362fda06befSmistachkin forcedelete test.db test.db-wal 3637c24610eSdan sqlite3_wal db test.db 3647c24610eSdan execsql { 3657c24610eSdan PRAGMA page_size = 1024; 3667c24610eSdan CREATE TABLE t1(a, b); 3677c24610eSdan INSERT INTO t1 VALUES(1, 2); 3687c24610eSdan } 3697c24610eSdan list [file size test.db] [file size test.db-wal] 37010f5a50eSdan} [list 1024 [wal_file_size 3 1024]] 3717c24610eSdando_test wal-7.2 { 3725a299f91Sdan execsql { PRAGMA wal_checkpoint } 3737c24610eSdan list [file size test.db] [file size test.db-wal] 37410f5a50eSdan} [list 2048 [wal_file_size 3 1024]] 3757c24610eSdan 3767c24610eSdan# Execute some transactions in auto-vacuum mode to test database file 3777c24610eSdan# truncation. 3787c24610eSdan# 379b9bf16bfSdando_test wal-8.1 { 3807c24610eSdan reopen_db 381e04dc88bSdan catch { db close } 382fda06befSmistachkin forcedelete test.db test.db-wal 383e04dc88bSdan 384e04dc88bSdan sqlite3 db test.db 385e04dc88bSdan db function blob blob 3867c24610eSdan execsql { 3877c24610eSdan PRAGMA auto_vacuum = 1; 388e04dc88bSdan PRAGMA journal_mode = wal; 3897c24610eSdan PRAGMA auto_vacuum; 3907c24610eSdan } 391e04dc88bSdan} {wal 1} 392b9bf16bfSdando_test wal-8.2 { 3937c24610eSdan execsql { 3947c24610eSdan PRAGMA page_size = 1024; 3957c24610eSdan CREATE TABLE t1(x); 3966703239dSdan INSERT INTO t1 VALUES(blob(900)); 3976703239dSdan INSERT INTO t1 VALUES(blob(900)); 3986703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 4 */ 3996703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 8 */ 4006703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 16 */ 4016703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 32 */ 4026703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 64 */ 4035a299f91Sdan PRAGMA wal_checkpoint; 4047c24610eSdan } 4057c24610eSdan file size test.db 40680a1526aSdan} [expr 68*1024] 407b9bf16bfSdando_test wal-8.3 { 4087c24610eSdan execsql { 4097c24610eSdan DELETE FROM t1 WHERE rowid<54; 4105a299f91Sdan PRAGMA wal_checkpoint; 4117c24610eSdan } 4127c24610eSdan file size test.db 4137c24610eSdan} [expr 14*1024] 4147c24610eSdan 4157c24610eSdan# Run some "warm-body" tests to ensure that log-summary files with more 4167c24610eSdan# than 256 entries (log summaries that contain index blocks) work Ok. 4177c24610eSdan# 418b9bf16bfSdando_test wal-9.1 { 4197c24610eSdan reopen_db 4207c24610eSdan execsql { 421d5156605Sdrh PRAGMA cache_size=2000; 4227c24610eSdan CREATE TABLE t1(x PRIMARY KEY); 4236703239dSdan INSERT INTO t1 VALUES(blob(900)); 4246703239dSdan INSERT INTO t1 VALUES(blob(900)); 4256703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 4 */ 4266703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 8 */ 4276703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 16 */ 4286703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 32 */ 4296703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 64 */ 4306703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 128 */ 4316703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; /* 256 */ 4327c24610eSdan } 4337c24610eSdan file size test.db 434e04dc88bSdan} 1024 435b9bf16bfSdando_test wal-9.2 { 4367c24610eSdan sqlite3_wal db2 test.db 4377c24610eSdan execsql {PRAGMA integrity_check } db2 4387c24610eSdan} {ok} 4397c24610eSdan 440b9bf16bfSdando_test wal-9.3 { 441fda06befSmistachkin forcedelete test2.db test2.db-wal 442fda06befSmistachkin copy_file test.db test2.db 443fda06befSmistachkin copy_file test.db-wal test2.db-wal 4447c24610eSdan sqlite3_wal db3 test2.db 4457c24610eSdan execsql {PRAGMA integrity_check } db3 4467c24610eSdan} {ok} 4477c24610eSdandb3 close 4487c24610eSdan 449b9bf16bfSdando_test wal-9.4 { 4505a299f91Sdan execsql { PRAGMA wal_checkpoint } 4517c24610eSdan db2 close 4527c24610eSdan sqlite3_wal db2 test.db 4537c24610eSdan execsql {PRAGMA integrity_check } db2 4547c24610eSdan} {ok} 4557c24610eSdan 45680a1526aSdanforeach handle {db db2 db3} { catch { $handle close } } 45780a1526aSdanunset handle 45880a1526aSdan 459b9bf16bfSdan#------------------------------------------------------------------------- 460b9bf16bfSdan# The following block of tests - wal-10.* - test that the WAL locking 461e264d983Sdan# scheme works in simple cases. This block of tests is run twice. Once 462e264d983Sdan# using multiple connections in the address space of the current process, 463e264d983Sdan# and once with all connections except one running in external processes. 464b9bf16bfSdan# 465a4a9095eSdando_multiclient_test tn { 466e264d983Sdan 467e264d983Sdan # Initialize the database schema and contents. 468e264d983Sdan # 469e264d983Sdan do_test wal-10.$tn.1 { 470b9bf16bfSdan execsql { 4717fa65fbfSdan PRAGMA auto_vacuum = 0; 472a4a9095eSdan PRAGMA journal_mode = wal; 473b9bf16bfSdan CREATE TABLE t1(a, b); 474b9bf16bfSdan INSERT INTO t1 VALUES(1, 2); 475b9bf16bfSdan SELECT * FROM t1; 476e264d983Sdan } 477a4a9095eSdan } {wal 1 2} 478e264d983Sdan 479e264d983Sdan # Open a transaction and write to the database using [db]. Check that [db2] 480e264d983Sdan # is still able to read the snapshot before the transaction was opened. 481e264d983Sdan # 482e264d983Sdan do_test wal-10.$tn.2 { 483e264d983Sdan execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } 484e264d983Sdan sql2 {SELECT * FROM t1} 485e264d983Sdan } {1 2} 486e264d983Sdan 487e264d983Sdan # Have [db] commit the transaction. Check that [db2] is now seeing the 488e264d983Sdan # new, updated snapshot. 489e264d983Sdan # 490e264d983Sdan do_test wal-10.$tn.3 { 491e264d983Sdan execsql { COMMIT } 492e264d983Sdan sql2 {SELECT * FROM t1} 493b9bf16bfSdan } {1 2 3 4} 494e264d983Sdan 495e264d983Sdan # Have [db2] open a read transaction. Then write to the db via [db]. Check 496e264d983Sdan # that [db2] is still seeing the original snapshot. Then read with [db3]. 497e264d983Sdan # [db3] should see the newly committed data. 498e264d983Sdan # 499e264d983Sdan do_test wal-10.$tn.4 { 500e264d983Sdan sql2 { BEGIN ; SELECT * FROM t1} 501e264d983Sdan } {1 2 3 4} 502e264d983Sdan do_test wal-10.$tn.5 { 503e264d983Sdan execsql { INSERT INTO t1 VALUES(5, 6); } 504e264d983Sdan sql2 {SELECT * FROM t1} 505e264d983Sdan } {1 2 3 4} 506e264d983Sdan do_test wal-10.$tn.6 { 507e264d983Sdan sql3 {SELECT * FROM t1} 508e264d983Sdan } {1 2 3 4 5 6} 509e264d983Sdan do_test wal-10.$tn.7 { 510e264d983Sdan sql2 COMMIT 511e264d983Sdan } {} 512e264d983Sdan 513e264d983Sdan # Have [db2] open a write transaction. Then attempt to write to the 514e264d983Sdan # database via [db]. This should fail (writer lock cannot be obtained). 515e264d983Sdan # 516e264d983Sdan # Then open a read-transaction with [db]. Commit the [db2] transaction 517e264d983Sdan # to disk. Verify that [db] still cannot write to the database (because 518e264d983Sdan # it is reading an old snapshot). 519e264d983Sdan # 520e264d983Sdan # Close the current [db] transaction. Open a new one. [db] can now write 521e264d983Sdan # to the database (as it is not locked and [db] is reading the latest 522e264d983Sdan # snapshot). 523e264d983Sdan # 524e264d983Sdan do_test wal-10.$tn.7 { 525e264d983Sdan sql2 { BEGIN; INSERT INTO t1 VALUES(7, 8) ; } 526e264d983Sdan catchsql { INSERT INTO t1 VALUES(9, 10) } 527e264d983Sdan } {1 {database is locked}} 528e264d983Sdan do_test wal-10.$tn.8 { 529e264d983Sdan execsql { BEGIN ; SELECT * FROM t1 } 530e264d983Sdan } {1 2 3 4 5 6} 531e264d983Sdan do_test wal-10.$tn.9 { 532e264d983Sdan sql2 COMMIT 533e264d983Sdan catchsql { INSERT INTO t1 VALUES(9, 10) } 534e264d983Sdan } {1 {database is locked}} 535e264d983Sdan do_test wal-10.$tn.10 { 5367e263728Sdrh execsql { COMMIT } 5377e263728Sdrh execsql { BEGIN } 5387e263728Sdrh execsql { INSERT INTO t1 VALUES(9, 10) } 5397e263728Sdrh execsql { COMMIT } 540e264d983Sdan execsql { SELECT * FROM t1 } 541e264d983Sdan } {1 2 3 4 5 6 7 8 9 10} 542e264d983Sdan 543e264d983Sdan # Open a read transaction with [db2]. Check that this prevents [db] from 544e264d983Sdan # checkpointing the database. But not from writing to it. 545e264d983Sdan # 546e264d983Sdan do_test wal-10.$tn.11 { 547e264d983Sdan sql2 { BEGIN; SELECT * FROM t1 } 548e264d983Sdan } {1 2 3 4 5 6 7 8 9 10} 549e264d983Sdan do_test wal-10.$tn.12 { 5505a299f91Sdan catchsql { PRAGMA wal_checkpoint } 5511eaaf93aSdrh } {0 {0 7 7}} ;# Reader no longer block checkpoints 552e264d983Sdan do_test wal-10.$tn.13 { 553e264d983Sdan execsql { INSERT INTO t1 VALUES(11, 12) } 554e264d983Sdan sql2 {SELECT * FROM t1} 555e264d983Sdan } {1 2 3 4 5 6 7 8 9 10} 556b9bf16bfSdan 55734116eafSdrh # Writers do not block checkpoints any more either. 558b9bf16bfSdan # 559e264d983Sdan do_test wal-10.$tn.14 { 56034116eafSdrh catchsql { PRAGMA wal_checkpoint } 5611eaaf93aSdrh } {0 {0 8 7}} 562b9bf16bfSdan 563a2ac9df1Sdrh # The following series of test cases used to verify another blocking 564a2ac9df1Sdrh # case in WAL - a case which no longer blocks. 565b9bf16bfSdan # 566e264d983Sdan do_test wal-10.$tn.15 { 56734116eafSdrh sql2 { COMMIT; BEGIN; SELECT * FROM t1; } 568e264d983Sdan } {1 2 3 4 5 6 7 8 9 10 11 12} 569e264d983Sdan do_test wal-10.$tn.16 { 5705a299f91Sdan catchsql { PRAGMA wal_checkpoint } 5711eaaf93aSdrh } {0 {0 8 8}} 57249320f85Sdan do_test wal-10.$tn.17 { 5735a299f91Sdan execsql { PRAGMA wal_checkpoint } 5741eaaf93aSdrh } {0 8 8} 57549320f85Sdan do_test wal-10.$tn.18 { 576a2ac9df1Sdrh sql3 { BEGIN; SELECT * FROM t1 } 577e264d983Sdan } {1 2 3 4 5 6 7 8 9 10 11 12} 57849320f85Sdan do_test wal-10.$tn.19 { 579e264d983Sdan catchsql { INSERT INTO t1 VALUES(13, 14) } 580a2ac9df1Sdrh } {0 {}} 58149320f85Sdan do_test wal-10.$tn.20 { 582b9bf16bfSdan execsql { SELECT * FROM t1 } 583a2ac9df1Sdrh } {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 58449320f85Sdan do_test wal-10.$tn.21 { 585e264d983Sdan sql3 COMMIT 586a2ac9df1Sdrh sql2 COMMIT 587b9bf16bfSdan } {} 58849320f85Sdan do_test wal-10.$tn.22 { 589b9bf16bfSdan execsql { SELECT * FROM t1 } 590e264d983Sdan } {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 591b9bf16bfSdan 592a2ac9df1Sdrh # Another series of tests that used to demonstrate blocking behavior 593a2ac9df1Sdrh # but which now work. 59449320f85Sdan # 59549320f85Sdan do_test wal-10.$tn.23 { 5965a299f91Sdan execsql { PRAGMA wal_checkpoint } 5971eaaf93aSdrh } {0 9 9} 59849320f85Sdan do_test wal-10.$tn.24 { 59949320f85Sdan sql2 { BEGIN; SELECT * FROM t1; } 60049320f85Sdan } {1 2 3 4 5 6 7 8 9 10 11 12 13 14} 60149320f85Sdan do_test wal-10.$tn.25 { 6025a299f91Sdan execsql { PRAGMA wal_checkpoint } 6031eaaf93aSdrh } {0 9 9} 60449320f85Sdan do_test wal-10.$tn.26 { 60549320f85Sdan catchsql { INSERT INTO t1 VALUES(15, 16) } 606a2ac9df1Sdrh } {0 {}} 60749320f85Sdan do_test wal-10.$tn.27 { 608a2ac9df1Sdrh sql3 { INSERT INTO t1 VALUES(17, 18) } 60949320f85Sdan } {} 61049320f85Sdan do_test wal-10.$tn.28 { 61149320f85Sdan code3 { 61249320f85Sdan set ::STMT [sqlite3_prepare db3 "SELECT * FROM t1" -1 TAIL] 61349320f85Sdan sqlite3_step $::STMT 61449320f85Sdan } 61549320f85Sdan execsql { SELECT * FROM t1 } 616a2ac9df1Sdrh } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18} 61749320f85Sdan do_test wal-10.$tn.29 { 618a2ac9df1Sdrh execsql { INSERT INTO t1 VALUES(19, 20) } 6195a299f91Sdan catchsql { PRAGMA wal_checkpoint } 6201eaaf93aSdrh } {0 {0 3 0}} 62149320f85Sdan do_test wal-10.$tn.30 { 62249320f85Sdan code3 { sqlite3_finalize $::STMT } 6235a299f91Sdan execsql { PRAGMA wal_checkpoint } 6241eaaf93aSdrh } {0 3 0} 62549320f85Sdan 62649320f85Sdan # At one point, if a reader failed to upgrade to a writer because it 62749320f85Sdan # was reading an old snapshot, the write-locks were not being released. 62849320f85Sdan # Test that this bug has been fixed. 62949320f85Sdan # 63049320f85Sdan do_test wal-10.$tn.31 { 631a2ac9df1Sdrh sql2 COMMIT 63249320f85Sdan execsql { BEGIN ; SELECT * FROM t1 } 633a2ac9df1Sdrh sql2 { INSERT INTO t1 VALUES(21, 22) } 634a2ac9df1Sdrh catchsql { INSERT INTO t1 VALUES(23, 24) } 63549320f85Sdan } {1 {database is locked}} 63649320f85Sdan do_test wal-10.$tn.32 { 63749320f85Sdan # This statement would fail when the bug was present. 638a2ac9df1Sdrh sql2 { INSERT INTO t1 VALUES(23, 24) } 63949320f85Sdan } {} 64049320f85Sdan do_test wal-10.$tn.33 { 64149320f85Sdan execsql { SELECT * FROM t1 ; COMMIT } 642a2ac9df1Sdrh } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20} 64349320f85Sdan do_test wal-10.$tn.34 { 64449320f85Sdan execsql { SELECT * FROM t1 } 645a2ac9df1Sdrh } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24} 64649320f85Sdan 6478b348af8Sdan # Test that if a checkpointer cannot obtain the required locks, it 6488b348af8Sdan # releases all locks before returning a busy error. 6498b348af8Sdan # 6508b348af8Sdan do_test wal-10.$tn.35 { 6518b348af8Sdan execsql { 6528b348af8Sdan DELETE FROM t1; 6538b348af8Sdan INSERT INTO t1 VALUES('a', 'b'); 6548b348af8Sdan INSERT INTO t1 VALUES('c', 'd'); 6558b348af8Sdan } 6568b348af8Sdan sql2 { 6578b348af8Sdan BEGIN; 6588b348af8Sdan SELECT * FROM t1; 6598b348af8Sdan } 6608b348af8Sdan } {a b c d} 6618b348af8Sdan do_test wal-10.$tn.36 { 6625a299f91Sdan catchsql { PRAGMA wal_checkpoint } 6631eaaf93aSdrh } {0 {0 8 8}} 6648b348af8Sdan do_test wal-10.$tn.36 { 6658b348af8Sdan sql3 { INSERT INTO t1 VALUES('e', 'f') } 6668b348af8Sdan sql2 { SELECT * FROM t1 } 6678b348af8Sdan } {a b c d} 6688b348af8Sdan do_test wal-10.$tn.37 { 6698b348af8Sdan sql2 COMMIT 6705a299f91Sdan execsql { PRAGMA wal_checkpoint } 6711eaaf93aSdrh } {0 9 9} 672e264d983Sdan} 673e264d983Sdan 6744cc6fb61Sdan#------------------------------------------------------------------------- 6754cc6fb61Sdan# This block of tests, wal-11.*, test that nothing goes terribly wrong 6764cc6fb61Sdan# if frames must be written to the log file before a transaction is 6774cc6fb61Sdan# committed (in order to free up memory). 6784cc6fb61Sdan# 6794cc6fb61Sdando_test wal-11.1 { 6804cc6fb61Sdan reopen_db 6814cc6fb61Sdan execsql { 6824cc6fb61Sdan PRAGMA cache_size = 10; 6834cc6fb61Sdan PRAGMA page_size = 1024; 6844cc6fb61Sdan CREATE TABLE t1(x PRIMARY KEY); 6854cc6fb61Sdan } 6864cc6fb61Sdan list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] 687e04dc88bSdan} {1 3} 6884cc6fb61Sdando_test wal-11.2 { 6895a299f91Sdan execsql { PRAGMA wal_checkpoint } 69097a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 69110f5a50eSdan} [list 3 [wal_file_size 3 1024]] 6924cc6fb61Sdando_test wal-11.3 { 6936703239dSdan execsql { INSERT INTO t1 VALUES( blob(900) ) } 69497a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 69510f5a50eSdan} [list 3 [wal_file_size 4 1024]] 6964cc6fb61Sdan 6974cc6fb61Sdando_test wal-11.4 { 6984cc6fb61Sdan execsql { 6994cc6fb61Sdan BEGIN; 7006703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; -- 2 7016703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; -- 4 7026703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; -- 8 7036703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; -- 16 7044cc6fb61Sdan } 70597a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 70610f5a50eSdan} [list 3 [wal_file_size 32 1024]] 7074cc6fb61Sdando_test wal-11.5 { 7084cc6fb61Sdan execsql { 7094cc6fb61Sdan SELECT count(*) FROM t1; 7104cc6fb61Sdan PRAGMA integrity_check; 7114cc6fb61Sdan } 7124cc6fb61Sdan} {16 ok} 7134cc6fb61Sdando_test wal-11.6 { 7144cc6fb61Sdan execsql COMMIT 71597a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 716d6f7c979Sdan} [list 3 [wal_file_size 40 1024]] 7174cc6fb61Sdando_test wal-11.7 { 7184cc6fb61Sdan execsql { 7194cc6fb61Sdan SELECT count(*) FROM t1; 7204cc6fb61Sdan PRAGMA integrity_check; 7214cc6fb61Sdan } 7224cc6fb61Sdan} {16 ok} 7234cc6fb61Sdando_test wal-11.8 { 7245a299f91Sdan execsql { PRAGMA wal_checkpoint } 72597a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 726d6f7c979Sdan} [list 37 [wal_file_size 40 1024]] 7274cc6fb61Sdando_test wal-11.9 { 7284cc6fb61Sdan db close 7293de777fdSdan list [expr [file size test.db]/1024] [log_deleted test.db-wal] 7303de777fdSdan} {37 1} 7316703239dSdansqlite3_wal db test.db 732b7c2f86bSdrh 733b7c2f86bSdrh# After adding the capability of WAL to overwrite prior uncommitted 734b7c2f86bSdrh# frame in the WAL-file with revised content, the size of the WAL file 735b7c2f86bSdrh# following cache-spill is smaller. 736b7c2f86bSdrh# 737b7c2f86bSdrh#set nWal 39 738b7c2f86bSdrh#if {[permutation]!="mmap"} {set nWal 37} 739b7c2f86bSdrh#ifcapable !mmap {set nWal 37} 740b7c2f86bSdrhset nWal 34 741b7c2f86bSdrh 7424cc6fb61Sdando_test wal-11.10 { 7434cc6fb61Sdan execsql { 7444cc6fb61Sdan PRAGMA cache_size = 10; 7454cc6fb61Sdan BEGIN; 7466703239dSdan INSERT INTO t1 SELECT blob(900) FROM t1; -- 32 7474cc6fb61Sdan SELECT count(*) FROM t1; 7484cc6fb61Sdan } 74997a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 7507909e54aSdan} [list 37 [wal_file_size $nWal 1024]] 7514cc6fb61Sdando_test wal-11.11 { 7524cc6fb61Sdan execsql { 7534cc6fb61Sdan SELECT count(*) FROM t1; 7544cc6fb61Sdan ROLLBACK; 7554cc6fb61Sdan SELECT count(*) FROM t1; 7564cc6fb61Sdan } 7574cc6fb61Sdan} {32 16} 7584cc6fb61Sdando_test wal-11.12 { 75997a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 7607909e54aSdan} [list 37 [wal_file_size $nWal 1024]] 7614cc6fb61Sdando_test wal-11.13 { 7624cc6fb61Sdan execsql { 7636703239dSdan INSERT INTO t1 VALUES( blob(900) ); 7644cc6fb61Sdan SELECT count(*) FROM t1; 7654cc6fb61Sdan PRAGMA integrity_check; 7664cc6fb61Sdan } 7674cc6fb61Sdan} {17 ok} 7684cc6fb61Sdando_test wal-11.14 { 76997a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 7707909e54aSdan} [list 37 [wal_file_size $nWal 1024]] 7714cc6fb61Sdan 7724cc6fb61Sdan 7734a4b01dcSdan#------------------------------------------------------------------------- 77497a31355Sdan# This block of tests, wal-12.*, tests the fix for a problem that 77597a31355Sdan# could occur if a log that is a prefix of an older log is written 77697a31355Sdan# into a reused log file. 7774a4b01dcSdan# 7784a4b01dcSdanreopen_db 7794a4b01dcSdando_test wal-12.1 { 7804a4b01dcSdan execsql { 7814a4b01dcSdan PRAGMA page_size = 1024; 7824a4b01dcSdan CREATE TABLE t1(x, y); 7834a4b01dcSdan CREATE TABLE t2(x, y); 7844a4b01dcSdan INSERT INTO t1 VALUES('A', 1); 7854a4b01dcSdan } 78697a31355Sdan list [expr [file size test.db]/1024] [file size test.db-wal] 78710f5a50eSdan} [list 1 [wal_file_size 5 1024]] 7884a4b01dcSdando_test wal-12.2 { 7894a4b01dcSdan db close 790e04dc88bSdan sqlite3 db test.db 7914a4b01dcSdan execsql { 792e04dc88bSdan PRAGMA synchronous = normal; 7934a4b01dcSdan UPDATE t1 SET y = 0 WHERE x = 'A'; 7944a4b01dcSdan } 7954a4b01dcSdan list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] 7964a4b01dcSdan} {3 1} 7974a4b01dcSdando_test wal-12.3 { 7984a4b01dcSdan execsql { INSERT INTO t2 VALUES('B', 1) } 7994a4b01dcSdan list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] 8004a4b01dcSdan} {3 2} 8014a4b01dcSdando_test wal-12.4 { 802fda06befSmistachkin forcecopy test.db test2.db 803fda06befSmistachkin forcecopy test.db-wal test2.db-wal 8044a4b01dcSdan sqlite3_wal db2 test2.db 8054a4b01dcSdan execsql { SELECT * FROM t2 } db2 8064a4b01dcSdan} {B 1} 8074a4b01dcSdandb2 close 8084a4b01dcSdando_test wal-12.5 { 8094a4b01dcSdan execsql { 8105a299f91Sdan PRAGMA wal_checkpoint; 8114a4b01dcSdan UPDATE t2 SET y = 2 WHERE x = 'B'; 8125a299f91Sdan PRAGMA wal_checkpoint; 8134a4b01dcSdan UPDATE t1 SET y = 1 WHERE x = 'A'; 8145a299f91Sdan PRAGMA wal_checkpoint; 8154a4b01dcSdan UPDATE t1 SET y = 0 WHERE x = 'A'; 8164a4b01dcSdan } 817bdd9af0fSdan execsql { SELECT * FROM t2 } 8184a4b01dcSdan} {B 2} 819ce4f05f3Sdando_test wal-12.6 { 820fda06befSmistachkin forcecopy test.db test2.db 821fda06befSmistachkin forcecopy test.db-wal test2.db-wal 8224a4b01dcSdan sqlite3_wal db2 test2.db 8234a4b01dcSdan execsql { SELECT * FROM t2 } db2 8244a4b01dcSdan} {B 2} 8254a4b01dcSdandb2 close 826ce4f05f3Sdandb close 827ce4f05f3Sdan 828ce4f05f3Sdan#------------------------------------------------------------------------- 82931c03907Sdan# Check a fun corruption case has been fixed. 83031c03907Sdan# 83131c03907Sdan# The problem was that after performing a checkpoint using a connection 83231c03907Sdan# that had an out-of-date pager-cache, the next time the connection was 83331c03907Sdan# used it did not realize the cache was out-of-date and proceeded to 83431c03907Sdan# operate with an inconsistent cache. Leading to corruption. 83531c03907Sdan# 83631c03907Sdancatch { db close } 83731c03907Sdancatch { db2 close } 83831c03907Sdancatch { db3 close } 839fda06befSmistachkinforcedelete test.db test.db-wal 84031c03907Sdansqlite3 db test.db 84131c03907Sdansqlite3 db2 test.db 84231c03907Sdando_test wal-14 { 84331c03907Sdan execsql { 84431c03907Sdan PRAGMA journal_mode = WAL; 84531c03907Sdan CREATE TABLE t1(a PRIMARY KEY, b); 84631c03907Sdan INSERT INTO t1 VALUES(randomblob(10), randomblob(100)); 84731c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1; 84831c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1; 84931c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1; 85031c03907Sdan } 85131c03907Sdan 85231c03907Sdan db2 eval { 85331c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100); 85431c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100); 85531c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100); 85631c03907Sdan INSERT INTO t1 SELECT randomblob(10), randomblob(100); 85731c03907Sdan } 85831c03907Sdan 8595a299f91Sdan # After executing the "PRAGMA wal_checkpoint", connection [db] was being 86031c03907Sdan # left with an inconsistent cache. Running the CREATE INDEX statement 86131c03907Sdan # in this state led to database corruption. 86231c03907Sdan catchsql { 8635a299f91Sdan PRAGMA wal_checkpoint; 86431c03907Sdan CREATE INDEX i1 on t1(b); 86531c03907Sdan } 86631c03907Sdan 86731c03907Sdan db2 eval { PRAGMA integrity_check } 86831c03907Sdan} {ok} 86931c03907Sdan 870185cca60Sdancatch { db close } 871185cca60Sdancatch { db2 close } 87287c1fe1bSdan 87387c1fe1bSdan#------------------------------------------------------------------------- 87487c1fe1bSdan# The following block of tests - wal-15.* - focus on testing the 87587c1fe1bSdan# implementation of the sqlite3_wal_checkpoint() interface. 87687c1fe1bSdan# 877fda06befSmistachkinforcedelete test.db test.db-wal 87887c1fe1bSdansqlite3 db test.db 87987c1fe1bSdando_test wal-15.1 { 88087c1fe1bSdan execsql { 88165bddc12Sdan PRAGMA auto_vacuum = 0; 88287c1fe1bSdan PRAGMA page_size = 1024; 88387c1fe1bSdan PRAGMA journal_mode = WAL; 88487c1fe1bSdan } 88587c1fe1bSdan execsql { 88687c1fe1bSdan CREATE TABLE t1(a, b); 88787c1fe1bSdan INSERT INTO t1 VALUES(1, 2); 88887c1fe1bSdan } 88987c1fe1bSdan} {} 89087c1fe1bSdan 89187c1fe1bSdan# Test that an error is returned if the database name is not recognized 89287c1fe1bSdan# 89387c1fe1bSdando_test wal-15.2.1 { 89487c1fe1bSdan sqlite3_wal_checkpoint db aux 89587c1fe1bSdan} {SQLITE_ERROR} 89687c1fe1bSdando_test wal-15.2.2 { 89787c1fe1bSdan sqlite3_errcode db 89887c1fe1bSdan} {SQLITE_ERROR} 89987c1fe1bSdando_test wal-15.2.3 { 90087c1fe1bSdan sqlite3_errmsg db 90187c1fe1bSdan} {unknown database: aux} 90287c1fe1bSdan 90387c1fe1bSdan# Test that an error is returned if an attempt is made to checkpoint 90487c1fe1bSdan# if a transaction is open on the database. 90587c1fe1bSdan# 90687c1fe1bSdando_test wal-15.3.1 { 90787c1fe1bSdan execsql { 90887c1fe1bSdan BEGIN; 90987c1fe1bSdan INSERT INTO t1 VALUES(3, 4); 91087c1fe1bSdan } 91187c1fe1bSdan sqlite3_wal_checkpoint db main 91287c1fe1bSdan} {SQLITE_LOCKED} 91387c1fe1bSdando_test wal-15.3.2 { 91487c1fe1bSdan sqlite3_errcode db 91587c1fe1bSdan} {SQLITE_LOCKED} 91687c1fe1bSdando_test wal-15.3.3 { 91787c1fe1bSdan sqlite3_errmsg db 91887c1fe1bSdan} {database table is locked} 91987c1fe1bSdan 920dcb1169fSdan# Earlier versions returned an error is returned if the db cannot be 921dcb1169fSdan# checkpointed because of locks held by another connection. Check that 922dcb1169fSdan# this is no longer the case. 92387c1fe1bSdan# 92487c1fe1bSdansqlite3 db2 test.db 92587c1fe1bSdando_test wal-15.4.1 { 92687c1fe1bSdan execsql { 92787c1fe1bSdan BEGIN; 92887c1fe1bSdan SELECT * FROM t1; 92987c1fe1bSdan } db2 93087c1fe1bSdan} {1 2} 93187c1fe1bSdando_test wal-15.4.2 { 93287c1fe1bSdan execsql { COMMIT } 93387c1fe1bSdan sqlite3_wal_checkpoint db 934dcb1169fSdan} {SQLITE_OK} 93587c1fe1bSdando_test wal-15.4.3 { 93687c1fe1bSdan sqlite3_errmsg db 937dcb1169fSdan} {not an error} 93887c1fe1bSdan 93987c1fe1bSdan# After [db2] drops its lock, [db] may checkpoint the db. 94087c1fe1bSdan# 94187c1fe1bSdando_test wal-15.4.4 { 94287c1fe1bSdan execsql { COMMIT } db2 94387c1fe1bSdan sqlite3_wal_checkpoint db 94487c1fe1bSdan} {SQLITE_OK} 94587c1fe1bSdando_test wal-15.4.5 { 94687c1fe1bSdan sqlite3_errmsg db 94787c1fe1bSdan} {not an error} 94887c1fe1bSdando_test wal-15.4.6 { 94987c1fe1bSdan file size test.db 95087c1fe1bSdan} [expr 1024*2] 95187c1fe1bSdan 95287c1fe1bSdancatch { db2 close } 95387c1fe1bSdancatch { db close } 954af0cfd36Sdan 955af0cfd36Sdan#------------------------------------------------------------------------- 956af0cfd36Sdan# The following block of tests - wal-16.* - test that if a NULL pointer or 957af0cfd36Sdan# an empty string is passed as the second argument of the wal_checkpoint() 958af0cfd36Sdan# API, an attempt is made to checkpoint all attached databases. 959af0cfd36Sdan# 960af0cfd36Sdanforeach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} { 961af0cfd36Sdan 1 {sqlite3_wal_checkpoint db} SQLITE_OK 1 1 962af0cfd36Sdan 2 {sqlite3_wal_checkpoint db ""} SQLITE_OK 1 1 963f2b8dd58Sdan 3 {db eval "PRAGMA wal_checkpoint"} {0 10 10} 1 1 964af0cfd36Sdan 965af0cfd36Sdan 4 {sqlite3_wal_checkpoint db main} SQLITE_OK 1 0 966af0cfd36Sdan 5 {sqlite3_wal_checkpoint db aux} SQLITE_OK 0 1 967af0cfd36Sdan 6 {sqlite3_wal_checkpoint db temp} SQLITE_OK 0 0 968bdd9af0fSdan 7 {db eval "PRAGMA main.wal_checkpoint"} {0 10 10} 1 0 9690774bb59Sdan 8 {db eval "PRAGMA aux.wal_checkpoint"} {0 13 13} 0 1 970bdd9af0fSdan 9 {db eval "PRAGMA temp.wal_checkpoint"} {0 -1 -1} 0 0 971af0cfd36Sdan} { 972af0cfd36Sdan do_test wal-16.$tn.1 { 973fda06befSmistachkin forcedelete test2.db test2.db-wal test2.db-journal 974fda06befSmistachkin forcedelete test.db test.db-wal test.db-journal 975af0cfd36Sdan 976af0cfd36Sdan sqlite3 db test.db 977af0cfd36Sdan execsql { 978af0cfd36Sdan ATTACH 'test2.db' AS aux; 97965bddc12Sdan PRAGMA main.auto_vacuum = 0; 98065bddc12Sdan PRAGMA aux.auto_vacuum = 0; 981af0cfd36Sdan PRAGMA main.journal_mode = WAL; 982af0cfd36Sdan PRAGMA aux.journal_mode = WAL; 9830774bb59Sdan PRAGMA main.synchronous = NORMAL; 9840774bb59Sdan PRAGMA aux.synchronous = NORMAL; 985af0cfd36Sdan } 986af0cfd36Sdan } {wal wal} 987af0cfd36Sdan 988af0cfd36Sdan do_test wal-16.$tn.2 { 989af0cfd36Sdan execsql { 990af0cfd36Sdan CREATE TABLE main.t1(a, b, PRIMARY KEY(a, b)); 991af0cfd36Sdan CREATE TABLE aux.t2(a, b, PRIMARY KEY(a, b)); 992af0cfd36Sdan 993af0cfd36Sdan INSERT INTO t2 VALUES(1, randomblob(1000)); 994af0cfd36Sdan INSERT INTO t2 VALUES(2, randomblob(1000)); 995af0cfd36Sdan INSERT INTO t1 SELECT * FROM t2; 996af0cfd36Sdan } 997af0cfd36Sdan 998af0cfd36Sdan list [file size test.db] [file size test.db-wal] 99910f5a50eSdan } [list [expr 1*1024] [wal_file_size 10 1024]] 1000af0cfd36Sdan do_test wal-16.$tn.3 { 1001af0cfd36Sdan list [file size test2.db] [file size test2.db-wal] 10020774bb59Sdan } [list [expr 1*1024] [wal_file_size 13 1024]] 1003af0cfd36Sdan 1004af0cfd36Sdan do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res 1005af0cfd36Sdan 1006af0cfd36Sdan do_test wal-16.$tn.5 { 1007af0cfd36Sdan list [file size test.db] [file size test.db-wal] 100810f5a50eSdan } [list [expr ($ckpt_main ? 7 : 1)*1024] [wal_file_size 10 1024]] 1009af0cfd36Sdan 1010af0cfd36Sdan do_test wal-16.$tn.6 { 1011af0cfd36Sdan list [file size test2.db] [file size test2.db-wal] 10120774bb59Sdan } [list [expr ($ckpt_aux ? 7 : 1)*1024] [wal_file_size 13 1024]] 1013af0cfd36Sdan 1014af0cfd36Sdan catch { db close } 1015af0cfd36Sdan} 1016af0cfd36Sdan 10178d6ad1ccSdan#------------------------------------------------------------------------- 10188d6ad1ccSdan# The following tests - wal-17.* - attempt to verify that the correct 10198d6ad1ccSdan# number of "padding" frames are appended to the log file when a transaction 10208d6ad1ccSdan# is committed in synchronous=FULL mode. 10218d6ad1ccSdan# 10228d6ad1ccSdan# Do this by creating a database that uses 512 byte pages. Then writing 10238d6ad1ccSdan# a transaction that modifies 171 pages. In synchronous=NORMAL mode, this 10248d6ad1ccSdan# produces a log file of: 10258d6ad1ccSdan# 102610f5a50eSdan# 32 + (24+512)*171 = 90312 bytes. 10278d6ad1ccSdan# 10288d6ad1ccSdan# Slightly larger than 11*8192 = 90112 bytes. 10298d6ad1ccSdan# 10308d6ad1ccSdan# Run the test using various different sector-sizes. In each case, the 10318d6ad1ccSdan# WAL code should write the 90300 bytes of log file containing the 10328d6ad1ccSdan# transaction, then append as may frames as are required to extend the 10338d6ad1ccSdan# log file so that no part of the next transaction will be written into 10348d6ad1ccSdan# a disk-sector used by transaction just committed. 10358d6ad1ccSdan# 10368d6ad1ccSdanset old_pending_byte [sqlite3_test_control_pending_byte 0x10000000] 10378d6ad1ccSdancatch { db close } 103810f5a50eSdanforeach {tn sectorsize logsize} " 103910f5a50eSdan 1 128 [wal_file_size 172 512] 104010f5a50eSdan 2 256 [wal_file_size 172 512] 104110f5a50eSdan 3 512 [wal_file_size 172 512] 104210f5a50eSdan 4 1024 [wal_file_size 172 512] 104310f5a50eSdan 5 2048 [wal_file_size 172 512] 104410f5a50eSdan 6 4096 [wal_file_size 176 512] 104510f5a50eSdan 7 8192 [wal_file_size 184 512] 104610f5a50eSdan" { 1047fda06befSmistachkin forcedelete test.db test.db-wal test.db-journal 10488d6ad1ccSdan sqlite3_simulate_device -sectorsize $sectorsize 10498d6ad1ccSdan sqlite3 db test.db -vfs devsym 10508d6ad1ccSdan 10518d6ad1ccSdan do_test wal-17.$tn.1 { 10528d6ad1ccSdan execsql { 10538d6ad1ccSdan PRAGMA auto_vacuum = 0; 10548d6ad1ccSdan PRAGMA page_size = 512; 1055d5156605Sdrh PRAGMA cache_size = -2000; 10568d6ad1ccSdan PRAGMA journal_mode = WAL; 10578d6ad1ccSdan PRAGMA synchronous = FULL; 10588d6ad1ccSdan } 10598d6ad1ccSdan execsql { 10608d6ad1ccSdan BEGIN; 10618d6ad1ccSdan CREATE TABLE t(x); 10628d6ad1ccSdan } 10638d6ad1ccSdan for {set i 0} {$i<166} {incr i} { 10648d6ad1ccSdan execsql { INSERT INTO t VALUES(randomblob(400)) } 10658d6ad1ccSdan } 10668d6ad1ccSdan execsql COMMIT 10678d6ad1ccSdan 10688d6ad1ccSdan file size test.db-wal 10698d6ad1ccSdan } $logsize 10708d6ad1ccSdan 10718d6ad1ccSdan do_test wal-17.$tn.2 { 10728d6ad1ccSdan file size test.db 10738d6ad1ccSdan } 512 10748d6ad1ccSdan 10758d6ad1ccSdan do_test wal-17.$tn.3 { 10768d6ad1ccSdan db close 10778d6ad1ccSdan file size test.db 10788d6ad1ccSdan } [expr 512*171] 10798d6ad1ccSdan} 10808d6ad1ccSdansqlite3_test_control_pending_byte $old_pending_byte 10818d6ad1ccSdan 1082b6e099a9Sdan#------------------------------------------------------------------------- 1083b6e099a9Sdan# This test - wal-18.* - verifies a couple of specific conditions that 1084b6e099a9Sdan# may be encountered while recovering a log file are handled correctly: 1085b6e099a9Sdan# 1086b6e099a9Sdan# wal-18.1.* When the first 32-bits of a frame checksum is correct but 1087b6e099a9Sdan# the second 32-bits are false, and 1088b6e099a9Sdan# 1089b6e099a9Sdan# wal-18.2.* When the page-size field that occurs at the start of a log 1090b6e099a9Sdan# file is a power of 2 greater than 16384 or smaller than 512. 1091b6e099a9Sdan# 1092fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal 1093b6e099a9Sdando_test wal-18.0 { 1094b6e099a9Sdan sqlite3 db test.db 1095b6e099a9Sdan execsql { 1096b6e099a9Sdan PRAGMA page_size = 1024; 1097b6e099a9Sdan PRAGMA auto_vacuum = 0; 1098b6e099a9Sdan PRAGMA journal_mode = WAL; 1099b6e099a9Sdan PRAGMA synchronous = OFF; 1100b6e099a9Sdan 1101b6e099a9Sdan CREATE TABLE t1(a, b, UNIQUE(a, b)); 1102b6e099a9Sdan INSERT INTO t1 VALUES(0, 0); 1103b6e099a9Sdan PRAGMA wal_checkpoint; 1104b6e099a9Sdan 1105b6e099a9Sdan INSERT INTO t1 VALUES(1, 2); -- frames 1 and 2 1106b6e099a9Sdan INSERT INTO t1 VALUES(3, 4); -- frames 3 and 4 1107b6e099a9Sdan INSERT INTO t1 VALUES(5, 6); -- frames 5 and 6 1108b6e099a9Sdan } 1109b6e099a9Sdan 1110fda06befSmistachkin forcecopy test.db testX.db 1111fda06befSmistachkin forcecopy test.db-wal testX.db-wal 1112b6e099a9Sdan db close 1113b6e099a9Sdan list [file size testX.db] [file size testX.db-wal] 111410f5a50eSdan} [list [expr 3*1024] [wal_file_size 6 1024]] 1115b6e099a9Sdan 1116c9e4665eSdanunset -nocomplain nFrame result 1117b6e099a9Sdanforeach {nFrame result} { 1118b6e099a9Sdan 0 {0 0} 1119b6e099a9Sdan 1 {0 0} 1120b6e099a9Sdan 2 {0 0 1 2} 1121b6e099a9Sdan 3 {0 0 1 2} 1122b6e099a9Sdan 4 {0 0 1 2 3 4} 1123b6e099a9Sdan 5 {0 0 1 2 3 4} 1124b6e099a9Sdan 6 {0 0 1 2 3 4 5 6} 1125b6e099a9Sdan} { 1126b6e099a9Sdan do_test wal-18.1.$nFrame { 1127fda06befSmistachkin forcecopy testX.db test.db 1128fda06befSmistachkin forcecopy testX.db-wal test.db-wal 1129b6e099a9Sdan 113023ea97b6Sdrh hexio_write test.db-wal [expr 24 + $nFrame*(24+1024) + 20] 00000000 1131b6e099a9Sdan 1132b6e099a9Sdan sqlite3 db test.db 1133b6e099a9Sdan execsql { 1134b6e099a9Sdan SELECT * FROM t1; 1135b6e099a9Sdan PRAGMA integrity_check; 1136b6e099a9Sdan } 1137b6e099a9Sdan } [concat $result ok] 1138b6e099a9Sdan db close 1139b6e099a9Sdan} 1140b6e099a9Sdan 1141b6e099a9Sdanproc randomblob {pgsz} { 1142b6e099a9Sdan sqlite3 rbdb :memory: 1143b6e099a9Sdan set blob [rbdb one {SELECT randomblob($pgsz)}] 1144b6e099a9Sdan rbdb close 1145b6e099a9Sdan set blob 1146b6e099a9Sdan} 1147b6e099a9Sdan 1148b6e099a9Sdanproc logcksum {ckv1 ckv2 blob} { 1149b6e099a9Sdan upvar $ckv1 c1 1150b6e099a9Sdan upvar $ckv2 c2 1151b6e099a9Sdan 1152ed1d84e3Sdrh # Since the magic number at the start of the -wal file header is 1153ed1d84e3Sdrh # 931071618 that indicates that the content should always be read as 1154ed1d84e3Sdrh # little-endian. 1155ed1d84e3Sdrh # 1156b8fd6c2fSdan set scanpattern i* 1157b6e099a9Sdan 1158b8fd6c2fSdan binary scan $blob $scanpattern values 11594c1cb6abSdrh foreach {v1 v2} $values { 11604c1cb6abSdrh set c1 [expr {($c1 + $v1 + $c2)&0xFFFFFFFF}] 11614c1cb6abSdrh set c2 [expr {($c2 + $v2 + $c1)&0xFFFFFFFF}] 11624c1cb6abSdrh } 1163b6e099a9Sdan} 1164b6e099a9Sdan 1165fda06befSmistachkinforcecopy test.db testX.db 1166b6e099a9Sdanforeach {tn pgsz works} { 1167b6e099a9Sdan 1 128 0 1168b6e099a9Sdan 2 256 0 1169b6e099a9Sdan 3 512 1 1170b6e099a9Sdan 4 1024 1 1171b6e099a9Sdan 5 2048 1 1172b6e099a9Sdan 6 4096 1 1173b6e099a9Sdan 7 8192 1 1174b6e099a9Sdan 8 16384 1 1175b6e099a9Sdan 9 32768 1 1176b2eced5dSdrh 10 65536 1 1177b2eced5dSdrh 11 131072 0 11784c1cb6abSdrh 11 1016 0 1179b6e099a9Sdan} { 1180b6e099a9Sdan 118165bddc12Sdan if {$::SQLITE_MAX_PAGE_SIZE < $pgsz} { 118265bddc12Sdan set works 0 118365bddc12Sdan } 118465bddc12Sdan 1185b6e099a9Sdan for {set pg 1} {$pg <= 3} {incr pg} { 1186fda06befSmistachkin forcecopy testX.db test.db 1187fda06befSmistachkin forcedelete test.db-wal 1188b6e099a9Sdan 1189b6e099a9Sdan # Check that the database now exists and consists of three pages. And 1190b6e099a9Sdan # that there is no associated wal file. 1191b6e099a9Sdan # 1192b6e099a9Sdan do_test wal-18.2.$tn.$pg.1 { file exists test.db-wal } 0 1193b6e099a9Sdan do_test wal-18.2.$tn.$pg.2 { file exists test.db } 1 1194b6e099a9Sdan do_test wal-18.2.$tn.$pg.3 { file size test.db } [expr 1024*3] 1195b6e099a9Sdan 1196b6e099a9Sdan do_test wal-18.2.$tn.$pg.4 { 1197b6e099a9Sdan 1198b6e099a9Sdan # Create a wal file that contains a single frame (database page 1199b6e099a9Sdan # number $pg) with the commit flag set. The frame checksum is 1200b6e099a9Sdan # correct, but the contents of the database page are corrupt. 1201b6e099a9Sdan # 1202b6e099a9Sdan # The page-size in the log file header is set to $pgsz. If the 1203b6e099a9Sdan # WAL code considers $pgsz to be a valid SQLite database file page-size, 1204b6e099a9Sdan # the database will be corrupt (because the garbage frame contents 1205b6e099a9Sdan # will be treated as valid content). If $pgsz is invalid (too small 1206b6e099a9Sdan # or too large), the db will not be corrupt as the log file will 1207b6e099a9Sdan # be ignored. 1208b6e099a9Sdan # 12097e263728Sdrh set walhdr [binary format IIIIII 931071618 3007000 $pgsz 1234 22 23] 1210b6e099a9Sdan set framebody [randomblob $pgsz] 12117e263728Sdrh set framehdr [binary format IIII $pg 5 22 23] 12127e263728Sdrh set c1 0 12137e263728Sdrh set c2 0 121471d89919Sdan logcksum c1 c2 $walhdr 121510f5a50eSdan 121610f5a50eSdan append walhdr [binary format II $c1 $c2] 121771d89919Sdan logcksum c1 c2 [string range $framehdr 0 7] 1218b6e099a9Sdan logcksum c1 c2 $framebody 12197e263728Sdrh set framehdr [binary format IIIIII $pg 5 22 23 $c1 $c2] 1220b8fd6c2fSdan 1221b6e099a9Sdan set fd [open test.db-wal w] 1222b6e099a9Sdan fconfigure $fd -encoding binary -translation binary 1223b6e099a9Sdan puts -nonewline $fd $walhdr 1224b6e099a9Sdan puts -nonewline $fd $framehdr 1225b6e099a9Sdan puts -nonewline $fd $framebody 1226b6e099a9Sdan close $fd 1227b6e099a9Sdan 1228b6e099a9Sdan file size test.db-wal 122910f5a50eSdan } [wal_file_size 1 $pgsz] 1230b6e099a9Sdan 1231b6e099a9Sdan do_test wal-18.2.$tn.$pg.5 { 1232b6e099a9Sdan sqlite3 db test.db 1233b6e099a9Sdan set rc [catch { db one {PRAGMA integrity_check} } msg] 1234b6e099a9Sdan expr { $rc!=0 || $msg!="ok" } 1235b6e099a9Sdan } $works 1236b6e099a9Sdan 1237b6e099a9Sdan db close 1238b6e099a9Sdan } 1239b6e099a9Sdan} 1240b6e099a9Sdan 1241b7d53f54Sdan#------------------------------------------------------------------------- 1242b7d53f54Sdan# The following test - wal-19.* - fixes a bug that was present during 1243b7d53f54Sdan# development. 1244b7d53f54Sdan# 1245b7d53f54Sdan# When a database connection in WAL mode is closed, it attempts an 1246b7d53f54Sdan# EXCLUSIVE lock on the database file. If the lock is obtained, the 1247b7d53f54Sdan# connection knows that it is the last connection to disconnect from 1248b7d53f54Sdan# the database, so it runs a checkpoint operation. The bug was that 1249b7d53f54Sdan# the connection was not updating its private copy of the wal-index 1250b7d53f54Sdan# header before doing so, meaning that it could checkpoint an old 1251b7d53f54Sdan# snapshot. 1252b7d53f54Sdan# 1253b7d53f54Sdando_test wal-19.1 { 1254fda06befSmistachkin forcedelete test.db test.db-wal test.db-journal 1255b7d53f54Sdan sqlite3 db test.db 1256b7d53f54Sdan sqlite3 db2 test.db 1257b7d53f54Sdan execsql { 1258b7d53f54Sdan PRAGMA journal_mode = WAL; 1259b7d53f54Sdan CREATE TABLE t1(a, b); 1260b7d53f54Sdan INSERT INTO t1 VALUES(1, 2); 1261b7d53f54Sdan INSERT INTO t1 VALUES(3, 4); 1262b7d53f54Sdan } 1263b7d53f54Sdan execsql { SELECT * FROM t1 } db2 1264b7d53f54Sdan} {1 2 3 4} 1265b7d53f54Sdando_test wal-19.2 { 1266b7d53f54Sdan execsql { 1267b7d53f54Sdan INSERT INTO t1 VALUES(5, 6); 1268b7d53f54Sdan SELECT * FROM t1; 1269b7d53f54Sdan } 1270b7d53f54Sdan} {1 2 3 4 5 6} 1271b7d53f54Sdando_test wal-19.3 { 1272b7d53f54Sdan db close 1273b7d53f54Sdan db2 close 1274b7d53f54Sdan file exists test.db-wal 1275b7d53f54Sdan} {0} 1276b7d53f54Sdando_test wal-19.4 { 1277b7d53f54Sdan # When the bug was present, the following was returning {1 2 3 4} only, 1278b7d53f54Sdan # as [db2] had an out-of-date copy of the wal-index header when it was 1279b7d53f54Sdan # closed. 1280b7d53f54Sdan # 1281b7d53f54Sdan sqlite3 db test.db 1282b7d53f54Sdan execsql { SELECT * FROM t1 } 1283b7d53f54Sdan} {1 2 3 4 5 6} 1284b7d53f54Sdan 1285998ad212Sdan#------------------------------------------------------------------------- 1286998ad212Sdan# This test - wal-20.* - uses two connections. One in this process and 1287998ad212Sdan# the other in an external process. The procedure is: 1288998ad212Sdan# 1289998ad212Sdan# 1. Using connection 1, create the database schema. 1290998ad212Sdan# 1291998ad212Sdan# 2. Using connection 2 (in an external process), add so much 1292998ad212Sdan# data to the database without checkpointing that a wal-index 1293998ad212Sdan# larger than 64KB is required. 1294998ad212Sdan# 1295998ad212Sdan# 3. Using connection 1, checkpoint the database. Make sure all 1296998ad212Sdan# the data is present and the database is not corrupt. 1297998ad212Sdan# 1298998ad212Sdan# At one point, SQLite was failing to grow the mapping of the wal-index 1299998ad212Sdan# file in step 3 and the checkpoint was corrupting the database file. 1300998ad212Sdan# 130194e95ea4Sdanif {[permutation]!="unix-excl"} { 1302998ad212Sdan do_test wal-20.1 { 1303a10069ddSshaneh catch {db close} 1304fda06befSmistachkin forcedelete test.db test.db-wal test.db-journal 1305998ad212Sdan sqlite3 db test.db 1306998ad212Sdan execsql { 1307998ad212Sdan PRAGMA journal_mode = WAL; 1308998ad212Sdan CREATE TABLE t1(x); 1309998ad212Sdan INSERT INTO t1 VALUES(randomblob(900)); 1310998ad212Sdan SELECT count(*) FROM t1; 1311998ad212Sdan } 1312998ad212Sdan } {wal 1} 1313998ad212Sdan do_test wal-20.2 { 1314998ad212Sdan set ::buddy [launch_testfixture] 1315998ad212Sdan testfixture $::buddy { 1316998ad212Sdan sqlite3 db test.db 1317998ad212Sdan db transaction { db eval { 1318998ad212Sdan PRAGMA wal_autocheckpoint = 0; 1319998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */ 1320998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */ 1321998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */ 1322998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */ 1323998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */ 1324998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ 1325998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ 1326998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ 1327998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ 1328998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ 1329998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */ 1330998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */ 1331998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */ 1332998ad212Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */ 1333998ad212Sdan } } 1334998ad212Sdan } 1335998ad212Sdan } {0} 1336998ad212Sdan do_test wal-20.3 { 1337998ad212Sdan close $::buddy 1338bdd9af0fSdan execsql { PRAGMA wal_checkpoint } 1339bdd9af0fSdan execsql { SELECT count(*) FROM t1 } 1340998ad212Sdan } {16384} 1341998ad212Sdan do_test wal-20.4 { 1342998ad212Sdan db close 1343998ad212Sdan sqlite3 db test.db 1344998ad212Sdan execsql { SELECT count(*) FROM t1 } 1345998ad212Sdan } {16384} 1346998ad212Sdan integrity_check wal-20.5 134794e95ea4Sdan} 1348998ad212Sdan 1349af0cfd36Sdancatch { db2 close } 1350af0cfd36Sdancatch { db close } 13516e6bd565Sdan 13526e6bd565Sdando_test wal-21.1 { 135310f5a50eSdan faultsim_delete_and_reopen 13546e6bd565Sdan execsql { 13556e6bd565Sdan PRAGMA journal_mode = WAL; 13566e6bd565Sdan CREATE TABLE t1(a, b); 13576e6bd565Sdan INSERT INTO t1 VALUES(1, 2); 13586e6bd565Sdan INSERT INTO t1 VALUES(3, 4); 13596e6bd565Sdan INSERT INTO t1 VALUES(5, 6); 13606e6bd565Sdan INSERT INTO t1 VALUES(7, 8); 13616e6bd565Sdan INSERT INTO t1 VALUES(9, 10); 13626e6bd565Sdan INSERT INTO t1 VALUES(11, 12); 13636e6bd565Sdan } 13646e6bd565Sdan} {wal} 13656e6bd565Sdando_test wal-21.2 { 13666e6bd565Sdan execsql { 13676e6bd565Sdan PRAGMA cache_size = 10; 13686e6bd565Sdan PRAGMA wal_checkpoint; 13696e6bd565Sdan BEGIN; 13706e6bd565Sdan SAVEPOINT s; 13716e6bd565Sdan INSERT INTO t1 SELECT randomblob(900), randomblob(900) FROM t1; 13726e6bd565Sdan ROLLBACK TO s; 13736e6bd565Sdan COMMIT; 13746e6bd565Sdan } 1375bdd9af0fSdan execsql { SELECT * FROM t1 } 13766e6bd565Sdan} {1 2 3 4 5 6 7 8 9 10 11 12} 13776e6bd565Sdando_test wal-21.3 { 13786e6bd565Sdan execsql { PRAGMA integrity_check } 13796e6bd565Sdan} {ok} 13806e6bd565Sdan 13814bcc4988Sdan#------------------------------------------------------------------------- 13824bcc4988Sdan# Test reading and writing of databases with different page-sizes. 13834bcc4988Sdan# 13847da56b4fSdrhincr ::do_not_use_codec 13854bcc4988Sdanforeach pgsz {512 1024 2048 4096 8192 16384 32768 65536} { 13864bcc4988Sdan do_multiclient_test tn [string map [list %PGSZ% $pgsz] { 1387eb8763d7Sdan do_test wal-22.%PGSZ%.$tn.1 { 13884bcc4988Sdan sql1 { 13894bcc4988Sdan PRAGMA main.page_size = %PGSZ%; 13904bcc4988Sdan PRAGMA auto_vacuum = 0; 13914bcc4988Sdan PRAGMA journal_mode = WAL; 13924bcc4988Sdan CREATE TABLE t1(x UNIQUE); 13934bcc4988Sdan INSERT INTO t1 SELECT randomblob(800); 13944bcc4988Sdan INSERT INTO t1 SELECT randomblob(800); 13954bcc4988Sdan INSERT INTO t1 SELECT randomblob(800); 13964bcc4988Sdan } 13974bcc4988Sdan } {wal} 1398eb8763d7Sdan do_test wal-22.%PGSZ%.$tn.2 { sql2 { PRAGMA integrity_check } } {ok} 1399eb8763d7Sdan do_test wal-22.%PGSZ%.$tn.3 { 14004bcc4988Sdan sql1 {PRAGMA wal_checkpoint} 14014bcc4988Sdan expr {[file size test.db] % %PGSZ%} 14024bcc4988Sdan } {0} 14034bcc4988Sdan }] 14044bcc4988Sdan} 14057da56b4fSdrhincr ::do_not_use_codec -1 14064bcc4988Sdan 1407eb8763d7Sdan#------------------------------------------------------------------------- 1408eb8763d7Sdan# Test that when 1 or more pages are recovered from a WAL file, 1409eb8763d7Sdan# sqlite3_log() is invoked to report this to the user. 1410eb8763d7Sdan# 1411c5484654Smistachkinifcapable curdir { 1412f8a78464Smistachkin set walfile [file nativename [file join [get_pwd] test.db-wal]] 1413c5484654Smistachkin} else { 1414c5484654Smistachkin set walfile test.db-wal 1415c5484654Smistachkin} 1416eb8763d7Sdancatch {db close} 1417fda06befSmistachkinforcedelete test.db 1418eb8763d7Sdando_test wal-23.1 { 1419eb8763d7Sdan faultsim_delete_and_reopen 1420eb8763d7Sdan execsql { 1421eb8763d7Sdan CREATE TABLE t1(a, b); 1422eb8763d7Sdan PRAGMA journal_mode = WAL; 1423eb8763d7Sdan INSERT INTO t1 VALUES(1, 2); 1424eb8763d7Sdan INSERT INTO t1 VALUES(3, 4); 1425eb8763d7Sdan } 1426eb8763d7Sdan faultsim_save_and_close 1427eb8763d7Sdan 1428eb8763d7Sdan sqlite3_shutdown 1429eb8763d7Sdan test_sqlite3_log [list lappend ::log] 1430eb8763d7Sdan set ::log [list] 1431eb8763d7Sdan sqlite3 db test.db 1432eb8763d7Sdan execsql { SELECT * FROM t1 } 1433eb8763d7Sdan} {1 2 3 4} 1434eb8763d7Sdando_test wal-23.2 { set ::log } {} 1435eb8763d7Sdan 1436eb8763d7Sdando_test wal-23.3 { 1437eb8763d7Sdan db close 1438eb8763d7Sdan set ::log [list] 1439eb8763d7Sdan faultsim_restore_and_reopen 1440eb8763d7Sdan execsql { SELECT * FROM t1 } 1441eb8763d7Sdan} {1 2 3 4} 1442eb8763d7Sdando_test wal-23.4 { 1443eb8763d7Sdan set ::log 144456749cd1Smistachkin} [list SQLITE_NOTICE_RECOVER_WAL \ 144511f71d6aSdan "recovered 2 frames from WAL file $walfile"] 1446eb8763d7Sdan 1447ce8e5ffeSdan 1448ce8e5ffeSdanifcapable autovacuum { 1449ce8e5ffeSdan # This block tests that if the size of a database is reduced by a 1450ce8e5ffeSdan # transaction (because of an incremental or auto-vacuum), that no 1451ce8e5ffeSdan # data is written to the WAL file for the truncated pages as part 1452ce8e5ffeSdan # of the commit. e.g. if a transaction reduces the size of a database 1453ce8e5ffeSdan # to N pages, data for page N+1 should not be written to the WAL file 1454ce8e5ffeSdan # when committing the transaction. At one point such data was being 1455ce8e5ffeSdan # written. 1456ce8e5ffeSdan # 1457ce8e5ffeSdan catch {db close} 1458ce8e5ffeSdan forcedelete test.db 1459ce8e5ffeSdan sqlite3 db test.db 1460ce8e5ffeSdan do_execsql_test 24.1 { 1461ce8e5ffeSdan PRAGMA auto_vacuum = 2; 1462ce8e5ffeSdan PRAGMA journal_mode = WAL; 1463ce8e5ffeSdan PRAGMA page_size = 1024; 1464ce8e5ffeSdan CREATE TABLE t1(x); 1465ce8e5ffeSdan INSERT INTO t1 VALUES(randomblob(5000)); 1466ce8e5ffeSdan INSERT INTO t1 SELECT * FROM t1; 1467ce8e5ffeSdan INSERT INTO t1 SELECT * FROM t1; 1468ce8e5ffeSdan INSERT INTO t1 SELECT * FROM t1; 1469ce8e5ffeSdan INSERT INTO t1 SELECT * FROM t1; 1470ce8e5ffeSdan } {wal} 1471dc5df0f8Sdan do_test 24.2 { 1472dc5df0f8Sdan execsql { 1473ce8e5ffeSdan DELETE FROM t1; 1474ce8e5ffeSdan PRAGMA wal_checkpoint; 1475dc5df0f8Sdan } 1476ce8e5ffeSdan db close 1477ce8e5ffeSdan sqlite3 db test.db 1478ce8e5ffeSdan file exists test.db-wal 1479ce8e5ffeSdan } 0 1480dc5df0f8Sdan do_test 24.3 { 1481ce8e5ffeSdan file size test.db 1482ce8e5ffeSdan } [expr 84 * 1024] 1483dc5df0f8Sdan do_test 24.4 { 1484ce8e5ffeSdan execsql { 1485b73da5bdSdan PRAGMA cache_size = 200; 1486ce8e5ffeSdan PRAGMA incremental_vacuum; 1487ce8e5ffeSdan PRAGMA wal_checkpoint; 1488ce8e5ffeSdan } 1489ce8e5ffeSdan file size test.db 1490ce8e5ffeSdan } [expr 3 * 1024] 14910774bb59Sdan 14920774bb59Sdan # WAL file now contains a single frame - the new root page for table t1. 14930774bb59Sdan # It would be two frames (the new root page and a padding frame) if the 14940774bb59Sdan # ZERO_DAMAGE flag were not set. 1495dc5df0f8Sdan do_test 24.5 { 1496ce8e5ffeSdan file size test.db-wal 14970774bb59Sdan } [wal_file_size 1 1024] 1498ce8e5ffeSdan} 1499ce8e5ffeSdan 1500eb8763d7Sdandb close 1501eb8763d7Sdansqlite3_shutdown 1502eb8763d7Sdantest_sqlite3_log 1503eb8763d7Sdansqlite3_initialize 1504eb8763d7Sdan 15051fb6a110Sdrh# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in 15061fb6a110Sdrh# all journal modes. 15071fb6a110Sdrh# 15081fb6a110Sdrhforeach mode {OFF MEMORY PERSIST DELETE TRUNCATE WAL} { 15091fb6a110Sdrh delete_file test.db test2.db 15101fb6a110Sdrh sqlite3 db test.db 15111fb6a110Sdrh do_test wal-25.$mode { 15121fb6a110Sdrh db eval "PRAGMA journal_mode=$mode" 15131fb6a110Sdrh db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;} 15141fb6a110Sdrh } {wal} 15151fb6a110Sdrh db close 15161fb6a110Sdrh} 15171fb6a110Sdrh 1518*099b385dSdrh# 2021-03-10 forum post https://sqlite.org/forum/forumpost/a006d86f72 1519*099b385dSdrh# 1520*099b385dSdrhfile delete test.db 1521*099b385dSdrhsqlite3 db test.db 1522*099b385dSdrhdb eval {PRAGMA journal_mode=WAL} 1523*099b385dSdrhfor {set i 0} {$i<$SQLITE_MAX_ATTACHED} {incr i} { 1524*099b385dSdrh do_test wal-26.1.$i { 1525*099b385dSdrh file delete attached-$i.db 1526*099b385dSdrh db eval "ATTACH 'attached-$i.db' AS a$i;" 1527*099b385dSdrh db eval "PRAGMA a$i.journal_mode=WAL;" 1528*099b385dSdrh db eval "CREATE TABLE a$i.t$i (x);" 1529*099b385dSdrh db eval "INSERT INTO t$i VALUES(zeroblob(10000));" 1530*099b385dSdrh db eval "DELETE FROM t$i;" 1531*099b385dSdrh db eval "INSERT INTO t$i VALUES(randomblob(10000));" 1532*099b385dSdrh expr {[file size attached-$i.db-wal]>10000} 1533*099b385dSdrh } {1} 1534*099b385dSdrh} 1535*099b385dSdrhfor {set i [expr {$SQLITE_MAX_ATTACHED-1}]} {$i>=0} {incr i -1} { 1536*099b385dSdrh do_test wal-26.2.$i { 1537*099b385dSdrh db eval "PRAGMA a$i.wal_checkpoint(TRUNCATE);" 1538*099b385dSdrh file size attached-$i.db-wal 1539*099b385dSdrh } {0} 1540*099b385dSdrh for {set j 0} {$j<$i} {incr j} { 1541*099b385dSdrh do_test wal-26.2.$i.$j { 1542*099b385dSdrh expr {[file size attached-$j.db-wal]>10000} 1543*099b385dSdrh } {1} 1544*099b385dSdrh } 1545*099b385dSdrh} 1546*099b385dSdrhdb close 1547*099b385dSdrh 1548*099b385dSdrh 15497416f2edSdrhtest_restore_config_pagecache 15507c24610eSdanfinish_test 1551