xref: /sqlite-3.40.0/test/exclusive2.test (revision d47e1ccb)
1ded6f4b2Sdanielk1977# 2007 March 24
2ded6f4b2Sdanielk1977#
3ded6f4b2Sdanielk1977# The author disclaims copyright to this source code.  In place of
4ded6f4b2Sdanielk1977# a legal notice, here is a blessing:
5ded6f4b2Sdanielk1977#
6ded6f4b2Sdanielk1977#    May you do good and not evil.
7ded6f4b2Sdanielk1977#    May you find forgiveness for yourself and forgive others.
8ded6f4b2Sdanielk1977#    May you share freely, never taking more than you give.
9ded6f4b2Sdanielk1977#
10ded6f4b2Sdanielk1977#***********************************************************************
11ded6f4b2Sdanielk1977# This file implements regression tests for SQLite library.
12ded6f4b2Sdanielk1977#
13c5053fb9Sdrh# $Id: exclusive2.test,v 1.10 2008/11/27 02:22:11 drh Exp $
14ded6f4b2Sdanielk1977
15ded6f4b2Sdanielk1977set testdir [file dirname $argv0]
16ded6f4b2Sdanielk1977source $testdir/tester.tcl
17ded6f4b2Sdanielk1977
18ae23162eSshaneh# Do not use a codec for tests in this file, as the database file is
19ae23162eSshaneh# manipulated directly using tcl scripts (using the [hexio_write] command).
20ae23162eSshaneh#
21ae23162eSshanehdo_not_use_codec
22ae23162eSshaneh
23ded6f4b2Sdanielk1977ifcapable {!pager_pragmas} {
24ded6f4b2Sdanielk1977  finish_test
25ded6f4b2Sdanielk1977  return
26ded6f4b2Sdanielk1977}
27ded6f4b2Sdanielk1977
285d8a1372Sdan# Tests in this file verify that locking_mode=exclusive causes SQLite to
295d8a1372Sdan# use cached pages even if the database is changed on disk. This doesn't
305d8a1372Sdan# work with mmap.
319b4c59faSdrhif {[permutation]=="mmap"} {
325d8a1372Sdan  finish_test
335d8a1372Sdan  return
345d8a1372Sdan}
355d8a1372Sdan
363aefabafSdrh# This module does not work right if the cache spills at unexpected
373aefabafSdrh# moments.  So disable the soft-heap-limit.
383aefabafSdrh#
393aefabafSdrhsqlite3_soft_heap_limit 0
403aefabafSdrh
41831045ddSaswiftproc pagerChangeCounter {filename new {fd ""}} {
42831045ddSaswift  if {$fd==""} {
43e6895112Sdrh    set fd [open $filename RDWR]
44ded6f4b2Sdanielk1977    fconfigure $fd -translation binary -encoding binary
45831045ddSaswift    set needClose 1
46831045ddSaswift  } else {
47831045ddSaswift    set needClose 0
48831045ddSaswift  }
49ded6f4b2Sdanielk1977  if {$new ne ""} {
50ded6f4b2Sdanielk1977    seek $fd 24
51ded6f4b2Sdanielk1977    set a [expr {($new&0xFF000000)>>24}]
52ded6f4b2Sdanielk1977    set b [expr {($new&0x00FF0000)>>16}]
53ded6f4b2Sdanielk1977    set c [expr {($new&0x0000FF00)>>8}]
54ded6f4b2Sdanielk1977    set d [expr {($new&0x000000FF)}]
553fb79c83Sdanielk1977    puts -nonewline $fd [binary format cccc $a $b $c $d]
563fb79c83Sdanielk1977    flush $fd
57ded6f4b2Sdanielk1977  }
58ded6f4b2Sdanielk1977
59ded6f4b2Sdanielk1977  seek $fd 24
60ded6f4b2Sdanielk1977  foreach {a b c d} [list 0 0 0 0] {}
61ded6f4b2Sdanielk1977  binary scan [read $fd 4] cccc a b c d
62ded6f4b2Sdanielk1977  set  ret [expr ($a&0x000000FF)<<24]
63ded6f4b2Sdanielk1977  incr ret [expr ($b&0x000000FF)<<16]
64ded6f4b2Sdanielk1977  incr ret [expr ($c&0x000000FF)<<8]
65ded6f4b2Sdanielk1977  incr ret [expr ($d&0x000000FF)<<0]
66ded6f4b2Sdanielk1977
67831045ddSaswift  if {$needClose} {close $fd}
68ded6f4b2Sdanielk1977  return $ret
69ded6f4b2Sdanielk1977}
70ded6f4b2Sdanielk1977
71f6f426beSaswiftproc readPagerChangeCounter {filename} {
72f6f426beSaswift  set fd [open $filename RDONLY]
73f6f426beSaswift  fconfigure $fd -translation binary -encoding binary
74f6f426beSaswift
75f6f426beSaswift  seek $fd 24
76f6f426beSaswift  foreach {a b c d} [list 0 0 0 0] {}
77f6f426beSaswift  binary scan [read $fd 4] cccc a b c d
78f6f426beSaswift  set  ret [expr ($a&0x000000FF)<<24]
79f6f426beSaswift  incr ret [expr ($b&0x000000FF)<<16]
80f6f426beSaswift  incr ret [expr ($c&0x000000FF)<<8]
81f6f426beSaswift  incr ret [expr ($d&0x000000FF)<<0]
82f6f426beSaswift
83f6f426beSaswift  close $fd
84f6f426beSaswift  return $ret
85f6f426beSaswift}
86f6f426beSaswift
87f6f426beSaswift
88ded6f4b2Sdanielk1977proc t1sig {{db db}} {
89ded6f4b2Sdanielk1977  execsql {SELECT count(*), md5sum(a) FROM t1} $db
90ded6f4b2Sdanielk1977}
91ded6f4b2Sdanielk1977do_test exclusive2-1.0 {
92f6f426beSaswift  readPagerChangeCounter test.db
93ded6f4b2Sdanielk1977} {0}
94ded6f4b2Sdanielk1977
95ded6f4b2Sdanielk1977#-----------------------------------------------------------------------
96ded6f4b2Sdanielk1977# The following tests - exclusive2-1.X - check that:
97ded6f4b2Sdanielk1977#
98ded6f4b2Sdanielk1977# 1-3:   Build a database with connection 1, calculate a signature.
99fa2a4772Sdan# 4-7:   Modify the database using a second connection in a way that
10086a88114Sdrh#        does not modify the freelist, then reset the pager change-counter
10186a88114Sdrh#        to the value it had before the modifications.
102ded6f4b2Sdanielk1977# 8:     Check that using the first connection, the database signature
103ded6f4b2Sdanielk1977#        is still the same. This is because it uses the in-memory cache.
104ded6f4b2Sdanielk1977#        It can't tell the db has changed because we reset the change-counter.
105ded6f4b2Sdanielk1977# 9:     Increment the change-counter.
106ded6f4b2Sdanielk1977# 10:    Ensure that the first connection now sees the updated database. It
107ded6f4b2Sdanielk1977#        sees the change-counter has been incremented and discards the
108ded6f4b2Sdanielk1977#        invalid in-memory cache.
109ded6f4b2Sdanielk1977#
11068a6b5ecSdanielk1977# This will only work if the database cache is large enough to hold
11168a6b5ecSdanielk1977# the entire database. In the case of 1024 byte pages, this means
11268a6b5ecSdanielk1977# the cache size must be at least 17. Otherwise, some pages will be
11368a6b5ecSdanielk1977# loaded from the database file in step 8.
11468a6b5ecSdanielk1977#
115fa2a4772Sdan# For similar reasons, this test does not work with the memsubsys1 permutation.
116fa2a4772Sdan# Permutation memsubsys1 configures the pcache subsystem to use a static
117fa2a4772Sdan# allocation of 24 pages (shared between all pagers). This is not enough for
118fa2a4772Sdan# this test.
119fa2a4772Sdan#
120ded6f4b2Sdanielk1977do_test exclusive2-1.1 {
121ded6f4b2Sdanielk1977  execsql {
122ded6f4b2Sdanielk1977    BEGIN;
12386a88114Sdrh    CREATE TABLE t1(a, b);
124*d47e1ccbSdan    INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);
125*d47e1ccbSdan    INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);
126*d47e1ccbSdan    INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
127*d47e1ccbSdan    INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
128*d47e1ccbSdan    INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
129*d47e1ccbSdan    INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
130*d47e1ccbSdan    INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
131ded6f4b2Sdanielk1977    COMMIT;
132ded6f4b2Sdanielk1977    SELECT count(*) FROM t1;
133ded6f4b2Sdanielk1977  }
134ded6f4b2Sdanielk1977} {64}
13568a6b5ecSdanielk1977do_test exclusive2-1.2.1 {
13668a6b5ecSdanielk1977  # Make sure the pager cache is large enough to store the
13768a6b5ecSdanielk1977  # entire database.
13868a6b5ecSdanielk1977  set nPage [expr [file size test.db]/1024]
13968a6b5ecSdanielk1977  if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
14068a6b5ecSdanielk1977    execsql "PRAGMA cache_size = $nPage"
14168a6b5ecSdanielk1977  }
14268a6b5ecSdanielk1977  expr {[execsql {PRAGMA cache_size}] >= $nPage}
14368a6b5ecSdanielk1977} {1}
144ded6f4b2Sdanielk1977do_test exclusive2-1.2 {
145ded6f4b2Sdanielk1977  set ::sig [t1sig]
146f6f426beSaswift  readPagerChangeCounter test.db
147ded6f4b2Sdanielk1977} {1}
148ded6f4b2Sdanielk1977do_test exclusive2-1.3 {
149ded6f4b2Sdanielk1977  t1sig
150ded6f4b2Sdanielk1977} $::sig
151ded6f4b2Sdanielk1977do_test exclusive2-1.4 {
152ded6f4b2Sdanielk1977  sqlite3 db2 test.db
153ded6f4b2Sdanielk1977  t1sig db2
154ded6f4b2Sdanielk1977} $::sig
155ded6f4b2Sdanielk1977do_test exclusive2-1.5 {
156ded6f4b2Sdanielk1977  execsql {
157*d47e1ccbSdan    UPDATE t1 SET b=a, a=0;
158ded6f4b2Sdanielk1977  } db2
159ded6f4b2Sdanielk1977  expr {[t1sig db2] eq $::sig}
160ded6f4b2Sdanielk1977} 0
161ded6f4b2Sdanielk1977do_test exclusive2-1.6 {
162f6f426beSaswift  readPagerChangeCounter test.db
163ded6f4b2Sdanielk1977} {2}
164ded6f4b2Sdanielk1977do_test exclusive2-1.7 {
165ded6f4b2Sdanielk1977  pagerChangeCounter test.db 1
166ded6f4b2Sdanielk1977} {1}
167fa2a4772Sdanif {[permutation] != "memsubsys1"} {
168ded6f4b2Sdanielk1977  do_test exclusive2-1.9 {
169ded6f4b2Sdanielk1977    t1sig
170ded6f4b2Sdanielk1977    expr {[t1sig] eq $::sig}
171ded6f4b2Sdanielk1977  } {1}
172fa2a4772Sdan}
173ded6f4b2Sdanielk1977do_test exclusive2-1.10 {
174ded6f4b2Sdanielk1977  pagerChangeCounter test.db 2
175ded6f4b2Sdanielk1977} {2}
176ded6f4b2Sdanielk1977do_test exclusive2-1.11 {
177ded6f4b2Sdanielk1977  expr {[t1sig] eq $::sig}
178ded6f4b2Sdanielk1977} {0}
1797cfbeb7fSdandb2 close
180ded6f4b2Sdanielk1977
181ded6f4b2Sdanielk1977#--------------------------------------------------------------------
182ded6f4b2Sdanielk1977# These tests - exclusive2-2.X - are similar to exclusive2-1.X,
183ded6f4b2Sdanielk1977# except that they are run with locking_mode=EXCLUSIVE.
184ded6f4b2Sdanielk1977#
185ded6f4b2Sdanielk1977# 1-3:   Build a database with exclusive-access connection 1,
186ded6f4b2Sdanielk1977#        calculate a signature.
187ded6f4b2Sdanielk1977# 4:     Corrupt the database by writing 10000 bytes of garbage
188ded6f4b2Sdanielk1977#        starting at the beginning of page 2. Check that connection 1
189ded6f4b2Sdanielk1977#        still works. It should be accessing the in-memory cache.
190ded6f4b2Sdanielk1977# 5-6:   Modify the dataase change-counter. Connection 1 still works
191ded6f4b2Sdanielk1977#        entirely from in-memory cache, because it doesn't check the
192ded6f4b2Sdanielk1977#        change-counter.
193ded6f4b2Sdanielk1977# 7-8    Set the locking-mode back to normal. After the db is unlocked,
194ded6f4b2Sdanielk1977#        SQLite detects the modified change-counter and discards the
195ded6f4b2Sdanielk1977#        in-memory cache. Then it finds the corruption caused in step 4....
196ded6f4b2Sdanielk1977#
19768a6b5ecSdanielk1977# As above, this test is only applicable if the pager cache is
19868a6b5ecSdanielk1977# large enough to hold the entire database. With 1024 byte pages,
1993aefabafSdrh# this means 19 pages.  We also need to disable the soft-heap-limit
2003aefabafSdrh# to prevent memory-induced cache spills.
20168a6b5ecSdanielk1977#
202ded6f4b2Sdanielk1977do_test exclusive2-2.1 {
203c5053fb9Sdrh  execsql {PRAGMA cache_size=1000;}
204ded6f4b2Sdanielk1977  execsql {PRAGMA locking_mode = exclusive;}
205ded6f4b2Sdanielk1977  execsql {
206ded6f4b2Sdanielk1977    BEGIN;
20786a88114Sdrh    DELETE FROM t1;
20886a88114Sdrh    INSERT INTO t1(a) VALUES(randstr(10, 400));
20986a88114Sdrh    INSERT INTO t1(a) VALUES(randstr(10, 400));
21086a88114Sdrh    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
21186a88114Sdrh    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
21286a88114Sdrh    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
21386a88114Sdrh    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
21486a88114Sdrh    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
215ded6f4b2Sdanielk1977    COMMIT;
216ded6f4b2Sdanielk1977    SELECT count(*) FROM t1;
217ded6f4b2Sdanielk1977  }
218ded6f4b2Sdanielk1977} {64}
21968a6b5ecSdanielk1977do_test exclusive2-2.2.1 {
22068a6b5ecSdanielk1977  # Make sure the pager cache is large enough to store the
22168a6b5ecSdanielk1977  # entire database.
22268a6b5ecSdanielk1977  set nPage [expr [file size test.db]/1024]
22368a6b5ecSdanielk1977  if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
22468a6b5ecSdanielk1977    execsql "PRAGMA cache_size = $nPage"
22568a6b5ecSdanielk1977  }
22668a6b5ecSdanielk1977  expr {[execsql {PRAGMA cache_size}] >= $nPage}
22768a6b5ecSdanielk1977} {1}
228ded6f4b2Sdanielk1977do_test exclusive2-2.2 {
229ded6f4b2Sdanielk1977  set ::sig [t1sig]
230f6f426beSaswift  readPagerChangeCounter test.db
231ded6f4b2Sdanielk1977} {3}
232ded6f4b2Sdanielk1977do_test exclusive2-2.3 {
233ded6f4b2Sdanielk1977  t1sig
234ded6f4b2Sdanielk1977} $::sig
235ded6f4b2Sdanielk1977
236ded6f4b2Sdanielk1977do_test exclusive2-2.4 {
237831045ddSaswift  set ::fd [open test.db RDWR]
238831045ddSaswift  fconfigure $::fd -translation binary
239831045ddSaswift  seek $::fd 1024
240831045ddSaswift  puts -nonewline $::fd [string repeat [binary format c 0] 10000]
241831045ddSaswift  flush $::fd
242ded6f4b2Sdanielk1977  t1sig
243ded6f4b2Sdanielk1977} $::sig
244ded6f4b2Sdanielk1977
245ded6f4b2Sdanielk1977do_test exclusive2-2.5 {
246831045ddSaswift  pagerChangeCounter test.db 5 $::fd
247ded6f4b2Sdanielk1977} {5}
248ded6f4b2Sdanielk1977do_test exclusive2-2.6 {
249ded6f4b2Sdanielk1977  t1sig
250ded6f4b2Sdanielk1977} $::sig
251ded6f4b2Sdanielk1977do_test exclusive2-2.7 {
252ded6f4b2Sdanielk1977  execsql {PRAGMA locking_mode = normal}
253ded6f4b2Sdanielk1977  t1sig
254ded6f4b2Sdanielk1977} $::sig
255ded6f4b2Sdanielk1977
256ded6f4b2Sdanielk1977do_test exclusive2-2.8 {
257ded6f4b2Sdanielk1977  set rc [catch {t1sig} msg]
258ded6f4b2Sdanielk1977  list $rc $msg
259ded6f4b2Sdanielk1977} {1 {database disk image is malformed}}
260ded6f4b2Sdanielk1977
261ded6f4b2Sdanielk1977#--------------------------------------------------------------------
262ded6f4b2Sdanielk1977# These tests - exclusive2-3.X - verify that the pager change-counter
263ded6f4b2Sdanielk1977# is only incremented by the first change when in exclusive access
264ded6f4b2Sdanielk1977# mode. In normal mode, the change-counter is incremented once
265ded6f4b2Sdanielk1977# per write-transaction.
266ded6f4b2Sdanielk1977#
267ded6f4b2Sdanielk1977
268ded6f4b2Sdanielk1977db close
269831045ddSaswiftcatch {close $::fd}
270fda06befSmistachkinforcedelete test.db
271fda06befSmistachkinforcedelete test.db-journal
272ded6f4b2Sdanielk1977
273ded6f4b2Sdanielk1977do_test exclusive2-3.0 {
274ded6f4b2Sdanielk1977  sqlite3 db test.db
275ded6f4b2Sdanielk1977  execsql {
276ded6f4b2Sdanielk1977    BEGIN;
277ded6f4b2Sdanielk1977    CREATE TABLE t1(a UNIQUE);
2787cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
2797cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
280ded6f4b2Sdanielk1977    COMMIT;
281ded6f4b2Sdanielk1977  }
282f6f426beSaswift  readPagerChangeCounter test.db
283ded6f4b2Sdanielk1977} {1}
284ded6f4b2Sdanielk1977do_test exclusive2-3.1 {
285ded6f4b2Sdanielk1977  execsql {
2867cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
287ded6f4b2Sdanielk1977  }
288f6f426beSaswift  readPagerChangeCounter test.db
289ded6f4b2Sdanielk1977} {2}
290ded6f4b2Sdanielk1977do_test exclusive2-3.2 {
291ded6f4b2Sdanielk1977  execsql {
2927cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
293ded6f4b2Sdanielk1977  }
294f6f426beSaswift  readPagerChangeCounter test.db
295ded6f4b2Sdanielk1977} {3}
296ded6f4b2Sdanielk1977do_test exclusive2-3.3 {
297ded6f4b2Sdanielk1977  execsql {
298ded6f4b2Sdanielk1977    PRAGMA locking_mode = exclusive;
2997cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
300ded6f4b2Sdanielk1977  }
301f6f426beSaswift  readPagerChangeCounter test.db
302ded6f4b2Sdanielk1977} {4}
303ded6f4b2Sdanielk1977do_test exclusive2-3.4 {
304ded6f4b2Sdanielk1977  execsql {
3057cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
306ded6f4b2Sdanielk1977  }
307f6f426beSaswift  readPagerChangeCounter test.db
308ded6f4b2Sdanielk1977} {4}
309ded6f4b2Sdanielk1977do_test exclusive2-3.5 {
310ded6f4b2Sdanielk1977  execsql {
311ded6f4b2Sdanielk1977    PRAGMA locking_mode = normal;
3127cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
3137cfbeb7fSdan  }
3147cfbeb7fSdan  readPagerChangeCounter test.db
3157cfbeb7fSdan} {4}
3167cfbeb7fSdando_test exclusive2-3.6 {
3177cfbeb7fSdan  execsql {
3187cfbeb7fSdan    INSERT INTO t1 VALUES(randstr(200, 200));
319ded6f4b2Sdanielk1977  }
320f6f426beSaswift  readPagerChangeCounter test.db
321d40d7ec7Sdrh} {5}
322c1a60c51Sdansqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
323ded6f4b2Sdanielk1977
324ded6f4b2Sdanielk1977finish_test
325