xref: /sqlite-3.40.0/test/wal.test (revision 099b385d)
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