summaryrefslogtreecommitdiffstats
path: root/test/waloverwrite.test
blob: ff8bc5ab55f456d523f2c10fac3f4fa1677a0d63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# 2010 May 5
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the operation of the library in
# "PRAGMA journal_mode=WAL" mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/wal_common.tcl
set testprefix waloverwrite

ifcapable !wal {finish_test ; return }

# Simple test:
#
# Test cases *.1 - *.6:
#
#   + Create a database of blobs roughly 50 pages in size.
#
#   + Set the db cache size to something much smaller than this (5 pages)
#
#   + Within a transaction, loop through the set of blobs 5 times. Update
#      each blob as it is visited.
#
#   + Test that the wal file is roughly 50 pages in size - even though many
#      database pages have been written to it multiple times.
#
#   + Take a copy of the database and wal file. Test that recovery can
#     be run on it.
#
# Test cases *.7 - *.9:
#
#   + Same thing, but before committing the statement transaction open
#     a SAVEPOINT, update the blobs another 5 times, then roll it back.
#
#   + Check that if recovery is run on the resulting wal file, the rolled
#     back changes from within the SAVEPOINT are not present in the db.
#
# The above is run twice - once where the wal file is empty at the start of
# step 3 (tn==1) and once where it already contains a transaction (tn==2).
#
foreach {tn xtra} {
  1 {}
  2 { UPDATE t1 SET y = randomblob(799) WHERE x=4 }
} {
  reset_db
  do_execsql_test 1.$tn.0 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    CREATE INDEX i1y ON t1(y);
  
    WITH cnt(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<20
    )
    INSERT INTO t1 SELECT i, randomblob(800) FROM cnt;
  } {}
  
  do_test 1.$tn.1 {
    set nPg [db one { PRAGMA page_count } ]
    expr $nPg>40 && $nPg<50
  } {1}
  
  do_test 1.$tn.2 {
    db close
    sqlite3 db test.db
  
    execsql {PRAGMA journal_mode = wal}
    execsql {PRAGMA cache_size = 5}
    execsql $xtra
  
    db transaction {
      for {set i 0} {$i < 5} {incr i} {
        foreach x [db eval {SELECT x FROM t1}] {
          execsql { UPDATE t1 SET y = randomblob(799) WHERE x=$x }
        }
      }
    }
  
    set nPg [wal_frame_count test.db-wal 1024]
    expr $nPg>40 && $nPg<60
  } {1}
  
  do_execsql_test 1.$tn.3 { PRAGMA integrity_check } ok
  
  do_test 1.$tn.4 {
    forcedelete test.db2 test.db2-wal
    forcecopy test.db test.db2
    sqlite3 db2 test.db2
    execsql { SELECT sum(length(y)) FROM t1 } db2
  } [expr 20*800]
  
  do_test 1.$tn.5 {
    db2 close
    forcecopy test.db test.db2
    forcecopy test.db-wal test.db2-wal
    sqlite3 db2 test.db2
    execsql { SELECT sum(length(y)) FROM t1 } db2
  } [expr 20*799]
  
  do_test 1.$tn.6 {
    execsql { PRAGMA integrity_check } db2
  } ok
  db2 close

  do_test 1.$tn.7 {
    execsql { PRAGMA wal_checkpoint }
    db transaction {
      for {set i 0} {$i < 1} {incr i} {
        foreach x [db eval {SELECT x FROM t1}] {
          execsql { UPDATE t1 SET y = randomblob(798) WHERE x=$x }
        }
      }

      execsql {
        WITH cnt(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<20)
        INSERT INTO t2 SELECT i, randomblob(800) FROM cnt;
      }

      execsql {SAVEPOINT abc}
      for {set i 0} {$i < 5} {incr i} {
        foreach x [db eval {SELECT x FROM t1}] {
          execsql { UPDATE t1 SET y = randomblob(797) WHERE x=$x }
        }
      }
      execsql {ROLLBACK TO abc}

    }

    set nPg [wal_frame_count test.db-wal 1024]
    expr $nPg>55 && $nPg<75
  } {1}

  do_test 1.$tn.8 {
    forcedelete test.db2 test.db2-wal
    forcecopy test.db test.db2
    sqlite3 db2 test.db2
    execsql { SELECT sum(length(y)) FROM t1 } db2
  } [expr 20*799]

  do_test 1.$tn.9 {
    db2 close
    forcecopy test.db-wal test.db2-wal
    sqlite3 db2 test.db2
    execsql { SELECT sum(length(y)) FROM t1 } db2
  } [expr 20*798]

  do_test 1.$tn.10 {
    execsql { PRAGMA integrity_check } db2
  } ok
  db2 close
}

finish_test