d764c7de25
FossilOrigin-Name: b813233d7604a5fd91e1af91d5d812032eec700a
264 lines
7.4 KiB
Plaintext
264 lines
7.4 KiB
Plaintext
# 2010 April 13
|
|
#
|
|
# 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/lock_common.tcl
|
|
source $testdir/wal_common.tcl
|
|
source $testdir/malloc_common.tcl
|
|
ifcapable !wal {finish_test ; return }
|
|
|
|
set a_string_counter 1
|
|
proc a_string {n} {
|
|
global a_string_counter
|
|
incr a_string_counter
|
|
string range [string repeat "${a_string_counter}." $n] 1 $n
|
|
}
|
|
db func a_string a_string
|
|
|
|
#-------------------------------------------------------------------------
|
|
# When a rollback or savepoint rollback occurs, the client may remove
|
|
# elements from one of the hash tables in the wal-index. This block
|
|
# of test cases tests that nothing appears to go wrong when this is
|
|
# done.
|
|
#
|
|
do_test wal3-1.0 {
|
|
execsql {
|
|
PRAGMA page_size = 1024;
|
|
PRAGMA auto_vacuum = off;
|
|
PRAGMA synchronous = normal;
|
|
PRAGMA journal_mode = WAL;
|
|
PRAGMA wal_autocheckpoint = 0;
|
|
BEGIN;
|
|
CREATE TABLE t1(x);
|
|
INSERT INTO t1 VALUES( a_string(800) ); /* 1 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 64 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 128*/
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 256 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 512 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 1024 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2048 */
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 2000; /* 4048 */
|
|
COMMIT;
|
|
PRAGMA cache_size = 10;
|
|
}
|
|
wal_frame_count test.db-wal 1024
|
|
} 4086
|
|
|
|
for {set i 1} {$i < 20} {incr i} {
|
|
|
|
do_test wal3-1.$i.1 {
|
|
set str [a_string 800]
|
|
execsql { UPDATE t1 SET x = $str WHERE rowid = $i }
|
|
lappend L [wal_frame_count test.db-wal 1024]
|
|
execsql {
|
|
BEGIN;
|
|
INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 100;
|
|
ROLLBACK;
|
|
PRAGMA integrity_check;
|
|
}
|
|
} {ok}
|
|
|
|
# Check that everything looks OK from the point of view of an
|
|
# external connection.
|
|
#
|
|
sqlite3 db2 test.db
|
|
do_test wal3-1.$i.2 {
|
|
execsql { SELECT count(*) FROM t1 } db2
|
|
} 4048
|
|
do_test wal3-1.$i.3 {
|
|
execsql { SELECT x FROM t1 WHERE rowid = $i }
|
|
} $str
|
|
do_test wal3-1.$i.4 {
|
|
execsql { PRAGMA integrity_check } db2
|
|
} {ok}
|
|
db2 close
|
|
|
|
# Check that the file-system in its current state can be recovered.
|
|
#
|
|
file copy -force test.db test2.db
|
|
file copy -force test.db-wal test2.db-wal
|
|
file delete -force test2.db-journal
|
|
sqlite3 db2 test2.db
|
|
do_test wal3-1.$i.5 {
|
|
execsql { SELECT count(*) FROM t1 } db2
|
|
} 4048
|
|
do_test wal3-1.$i.6 {
|
|
execsql { SELECT x FROM t1 WHERE rowid = $i }
|
|
} $str
|
|
do_test wal3-1.$i.7 {
|
|
execsql { PRAGMA integrity_check } db2
|
|
} {ok}
|
|
db2 close
|
|
}
|
|
|
|
db close
|
|
foreach code [list {
|
|
proc code2 {tcl} { uplevel #0 $tcl }
|
|
proc code3 {tcl} { uplevel #0 $tcl }
|
|
set tn singleproc
|
|
} {
|
|
set ::code2_chan [launch_testfixture]
|
|
set ::code3_chan [launch_testfixture]
|
|
proc code2 {tcl} { testfixture $::code2_chan $tcl }
|
|
proc code3 {tcl} { testfixture $::code3_chan $tcl }
|
|
set tn multiproc
|
|
}] {
|
|
file delete -force test.db test.db-wal test.db-journal
|
|
sqlite3 db test.db
|
|
eval $code
|
|
|
|
# Open connections [db2] and [db3]. Depending on which iteration this
|
|
# is, the connections may be created in this interpreter, or in
|
|
# interpreters running in other OS processes. As such, the [db2] and [db3]
|
|
# commands should only be accessed within [code2] and [code3] blocks,
|
|
# respectively.
|
|
#
|
|
code2 { sqlite3 db2 test.db ; db2 eval { PRAGMA journal_mode = WAL } }
|
|
code3 { sqlite3 db3 test.db ; db3 eval { PRAGMA journal_mode = WAL } }
|
|
|
|
# Shorthand commands. Execute SQL using database connection [db], [db2]
|
|
# or [db3]. Return the results.
|
|
#
|
|
proc sql {sql} { db eval $sql }
|
|
proc sql2 {sql} { code2 [list db2 eval $sql] }
|
|
proc sql3 {sql} { code3 [list db3 eval $sql] }
|
|
|
|
do_test wal3-2.$tn.1 {
|
|
sql {
|
|
PRAGMA page_size = 1024;
|
|
PRAGMA auto_vacuum = OFF;
|
|
PRAGMA journal_mode = WAL;
|
|
}
|
|
sql {
|
|
CREATE TABLE t1(a, b);
|
|
INSERT INTO t1 VALUES(1, 'one');
|
|
BEGIN;
|
|
SELECT * FROM t1;
|
|
}
|
|
} {1 one}
|
|
do_test wal3-2.$tn.2 {
|
|
sql2 {
|
|
CREATE TABLE t2(a, b);
|
|
INSERT INTO t2 VALUES(2, 'two');
|
|
BEGIN;
|
|
SELECT * FROM t2;
|
|
}
|
|
} {2 two}
|
|
do_test wal3-2.$tn.3 {
|
|
sql3 {
|
|
CREATE TABLE t3(a, b);
|
|
INSERT INTO t3 VALUES(3, 'three');
|
|
BEGIN;
|
|
SELECT * FROM t3;
|
|
}
|
|
} {3 three}
|
|
|
|
# Try to checkpoint the database using [db]. It should be possible to
|
|
# checkpoint everything except the table added by [db3] (checkpointing
|
|
# these frames would clobber the snapshot currently being used by [db2]).
|
|
#
|
|
# After [db2] has committed, a checkpoint can copy the entire log to the
|
|
# database file. Checkpointing after [db3] has committed is therefore a
|
|
# no-op, as the entire log has already been backfilled.
|
|
#
|
|
do_test wal3-2.$tn.4 {
|
|
sql {
|
|
COMMIT;
|
|
PRAGMA wal_checkpoint;
|
|
}
|
|
file size test.db
|
|
} [expr 3*1024]
|
|
do_test wal3-2.$tn.5 {
|
|
sql2 {
|
|
COMMIT;
|
|
PRAGMA wal_checkpoint;
|
|
}
|
|
file size test.db
|
|
} [expr 4*1024]
|
|
do_test wal3-2.$tn.6 {
|
|
sql3 {
|
|
COMMIT;
|
|
PRAGMA wal_checkpoint;
|
|
}
|
|
file size test.db
|
|
} [expr 4*1024]
|
|
|
|
catch { db close }
|
|
catch { code2 { db2 close } }
|
|
catch { code3 { db3 close } }
|
|
catch { close $::code2_chan }
|
|
catch { close $::code3_chan }
|
|
}
|
|
catch {db close}
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Test that that for the simple test:
|
|
#
|
|
# CREATE TABLE x(y);
|
|
# INSERT INTO x VALUES('z');
|
|
# PRAGMA wal_checkpoint;
|
|
#
|
|
# in WAL mode the xSync method is invoked as expected for each of
|
|
# synchronous=off, synchronous=normal and synchronous=full.
|
|
#
|
|
foreach {tn syncmode synccount} {
|
|
1 off
|
|
{}
|
|
2 normal
|
|
{test.db-wal normal test.db normal}
|
|
3 full
|
|
{test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
|
|
} {
|
|
|
|
proc sync_counter {args} {
|
|
foreach {method filename id flags} $args break
|
|
lappend ::syncs [file tail $filename] $flags
|
|
}
|
|
do_test wal3-3.$tn {
|
|
file delete -force test.db test.db-wal test.db-journal
|
|
|
|
testvfs T
|
|
T filter {}
|
|
T script sync_counter
|
|
sqlite3 db test.db -vfs T
|
|
|
|
execsql "PRAGMA synchronous = $syncmode"
|
|
execsql { PRAGMA journal_mode = WAL }
|
|
|
|
set ::syncs [list]
|
|
T filter xSync
|
|
execsql {
|
|
CREATE TABLE x(y);
|
|
INSERT INTO x VALUES('z');
|
|
PRAGMA wal_checkpoint;
|
|
}
|
|
T filter {}
|
|
set ::syncs
|
|
} $synccount
|
|
|
|
db close
|
|
T delete
|
|
}
|
|
|
|
finish_test
|
|
|
|
|