| # 2017 September 19 |
| # |
| # 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=WAL2" mode. |
| # |
| |
| set testdir [file dirname $argv0] |
| source $testdir/tester.tcl |
| source $testdir/lock_common.tcl |
| source $testdir/malloc_common.tcl |
| source $testdir/wal_common.tcl |
| |
| set testprefix wal2simple |
| ifcapable !wal {finish_test ; return } |
| |
| #------------------------------------------------------------------------- |
| # The following tests verify that a client can switch in and out of wal |
| # and wal2 mode. But that it is not possible to change directly from wal |
| # to wal2, or from wal2 to wal mode. |
| # |
| do_execsql_test 1.1.0 { |
| PRAGMA journal_mode = wal2 |
| } {wal2} |
| execsql { SELECT * FROM sqlite_master} |
| do_execsql_test 1.x { |
| PRAGMA journal_mode; |
| PRAGMA main.journal_mode; |
| } {wal2 wal2} |
| db close |
| do_test 1.1.1 { file size test.db } {1024} |
| do_test 1.1.2 { hexio_read test.db 18 2 } 0303 |
| |
| sqlite3 db test.db |
| do_execsql_test 1.2.0 { |
| SELECT * FROM sqlite_master; |
| PRAGMA journal_mode = delete; |
| } {delete} |
| db close |
| do_test 1.2.1 { file size test.db } {1024} |
| do_test 1.2.2 { hexio_read test.db 18 2 } 0101 |
| |
| sqlite3 db test.db |
| do_execsql_test 1.3.0 { |
| SELECT * FROM sqlite_master; |
| PRAGMA journal_mode = wal; |
| } {wal} |
| db close |
| do_test 1.3.1 { file size test.db } {1024} |
| do_test 1.3.2 { hexio_read test.db 18 2 } 0202 |
| |
| sqlite3 db test.db |
| do_catchsql_test 1.4.0 { |
| PRAGMA journal_mode = wal2; |
| } {1 {cannot change from wal to wal2 mode}} |
| do_execsql_test 1.4.1 { |
| PRAGMA journal_mode = wal; |
| PRAGMA journal_mode = delete; |
| PRAGMA journal_mode = wal2; |
| PRAGMA journal_mode = wal2; |
| } {wal delete wal2 wal2} |
| do_catchsql_test 1.4.2 { |
| PRAGMA journal_mode = wal; |
| } {1 {cannot change from wal2 to wal mode}} |
| db close |
| do_test 1.4.3 { hexio_read test.db 18 2 } 0303 |
| |
| #------------------------------------------------------------------------- |
| # Test that recovery in wal2 mode works. |
| # |
| forcedelete test.db test.db-wal test.db-wal2 |
| reset_db |
| do_execsql_test 2.0 { |
| CREATE TABLE t1(a INTEGER PRIMARY KEY, b); |
| PRAGMA journal_mode = wal2; |
| PRAGMA journal_size_limit = 5000; |
| } {wal2 5000} |
| |
| proc wal_hook {DB nm nFrame} { $DB eval { PRAGMA wal_checkpoint } } |
| db wal_hook {wal_hook db} |
| |
| for {set i 1} {$i <= 200} {incr i} { |
| execsql { INSERT INTO t1 VALUES(NULL, randomblob(100)) } |
| set res [db eval { SELECT sum(a), md5sum(b) FROM t1 }] |
| |
| do_test 2.1.$i { |
| foreach f [glob -nocomplain test.db2*] { forcedelete $f } |
| forcecopy test.db test.db2 |
| forcecopy test.db-wal test.db2-wal |
| forcecopy test.db-wal2 test.db2-wal2 |
| |
| sqlite3 db2 test.db2 |
| db2 eval { SELECT sum(a), md5sum(b) FROM t1 } |
| } $res |
| |
| db2 close |
| } |
| |
| #------------------------------------------------------------------------- |
| |
| reset_db |
| do_execsql_test 3.0 { |
| CREATE TABLE t1(x BLOB, y INTEGER PRIMARY KEY); |
| CREATE INDEX i1 ON t1(x); |
| PRAGMA cache_size = 5; |
| PRAGMA journal_mode = wal2; |
| } {wal2} |
| |
| do_test 3.1 { |
| execsql BEGIN |
| for {set i 1} {$i < 1000} {incr i} { |
| execsql { INSERT INTO t1 VALUES(randomblob(800), $i) } |
| } |
| execsql COMMIT |
| } {} |
| |
| do_execsql_test 3.2 { |
| PRAGMA integrity_check; |
| } {ok} |
| |
| #------------------------------------------------------------------------- |
| catch { db close } |
| foreach f [glob -nocomplain test.db*] { forcedelete $f } |
| reset_db |
| do_execsql_test 4.0 { |
| CREATE TABLE t1(x, y); |
| PRAGMA journal_mode = wal2; |
| } {wal2} |
| |
| do_execsql_test 4.1 { |
| SELECT * FROM t1; |
| } {} |
| |
| do_execsql_test 4.2 { |
| INSERT INTO t1 VALUES(1, 2); |
| } {} |
| |
| do_execsql_test 4.3 { |
| SELECT * FROM t1; |
| } {1 2} |
| |
| do_test 4.4 { |
| sqlite3 db2 test.db |
| execsql { SELECT * FROM t1 } db2 |
| } {1 2} |
| |
| do_test 4.5 { |
| lsort [glob test.db*] |
| } {test.db test.db-shm test.db-wal test.db-wal2} |
| |
| do_test 4.6 { |
| db close |
| db2 close |
| sqlite3 db test.db |
| execsql { SELECT * FROM t1 } |
| } {1 2} |
| |
| do_execsql_test 4.7 { |
| PRAGMA journal_size_limit = 4000; |
| INSERT INTO t1 VALUES(3, 4); |
| INSERT INTO t1 VALUES(5, 6); |
| INSERT INTO t1 VALUES(7, 8); |
| INSERT INTO t1 VALUES(9, 10); |
| INSERT INTO t1 VALUES(11, 12); |
| INSERT INTO t1 VALUES(13, 14); |
| INSERT INTO t1 VALUES(15, 16); |
| INSERT INTO t1 VALUES(17, 18); |
| SELECT * FROM t1; |
| } {4000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18} |
| |
| do_test 4.8 { |
| sqlite3 db2 test.db |
| execsql { SELECT * FROM t1 } db2 |
| } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18} |
| |
| do_test 4.9 { |
| db close |
| db2 close |
| lsort [glob test.db*] |
| } {test.db} |
| |
| #------------------------------------------------------------------------- |
| reset_db |
| do_execsql_test 5.0 { |
| CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); |
| CREATE INDEX i1 ON t1(b, c); |
| PRAGMA journal_mode = wal2; |
| PRAGMA journal_size_limit = 4000; |
| } {wal2 4000} |
| |
| proc wal_hook {DB nm nFrame} { |
| $DB eval { PRAGMA wal_checkpoint } |
| } |
| db wal_hook [list wal_hook db] |
| |
| |
| foreach js {4000 8000 12000} { |
| foreach NROW [list 100 200 300 400 500 600 1000] { |
| do_test 5.$js.$NROW.1 { |
| db eval "DELETE FROM t1" |
| db eval "PRAGMA journal_size_limit = $js" |
| set nTotal 0 |
| for {set i 0} {$i < $NROW} {incr i} { |
| db eval { INSERT INTO t1 VALUES($i, $i, randomblob(abs(random()%50))) } |
| incr nTotal $i |
| } |
| set {} {} |
| } {} |
| |
| do_test 5.$js.$NROW.2 { |
| sqlite3 db2 test.db |
| db2 eval { |
| PRAGMA integrity_check; |
| SELECT count(*), sum(b) FROM t1; |
| } |
| } [list ok $NROW $nTotal] |
| |
| db2 close |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------- |
| reset_db |
| do_execsql_test 6.0 { |
| CREATE TABLE tx(x); |
| PRAGMA journal_mode = wal2; |
| PRAGMA journal_size_limit = 3500; |
| } {wal2 3500} |
| |
| do_test 6.1 { |
| for {set i 0} {$i < 10} {incr i} { |
| execsql "CREATE TABLE t$i (x);" |
| } |
| } {} |
| |
| do_test 6.2.1 { |
| foreach f [glob -nocomplain test.db2*] { forcedelete $f } |
| forcecopy test.db-wal2 test.db2-wal2 |
| sqlite3 db2 test.db2 |
| db2 eval { SELECT * FROM sqlite_master } |
| } {} |
| do_test 6.2.2 { |
| db2 eval { |
| PRAGMA journal_mode = wal2; |
| SELECT * FROM sqlite_master; |
| } |
| } {wal2} |
| |
| do_test 6.3.1 { |
| db2 close |
| foreach f [glob -nocomplain test.db2*] { forcedelete $f } |
| forcecopy test.db-wal2 test.db2-wal2 |
| forcecopy test.db test.db2 |
| sqlite3 db2 test.db2 |
| db2 eval { SELECT * FROM sqlite_master } |
| } {table tx tx 2 {CREATE TABLE tx(x)}} |
| do_test 6.3.2 { |
| db2 eval { |
| PRAGMA journal_mode = wal2; |
| SELECT * FROM sqlite_master; |
| } |
| } {wal2 table tx tx 2 {CREATE TABLE tx(x)}} |
| |
| do_test 6.4.1 { |
| db2 close |
| foreach f [glob -nocomplain test.db2*] { forcedelete $f } |
| forcecopy test.db-wal2 test.db2-wal2 |
| forcecopy test.db-wal test.db2-wal |
| sqlite3 db2 test.db2 |
| db2 eval { SELECT * FROM sqlite_master } |
| } {} |
| do_test 6.4.2 { |
| db2 eval { |
| PRAGMA journal_mode = wal2; |
| SELECT * FROM sqlite_master; |
| } |
| } {wal2} |
| db2 close |
| |
| #------------------------------------------------------------------------- |
| reset_db |
| sqlite3 db2 test.db |
| do_execsql_test 7.0 { |
| PRAGMA journal_size_limit = 10000; |
| PRAGMA journal_mode = wal2; |
| PRAGMA wal_autocheckpoint = 0; |
| BEGIN; |
| CREATE TABLE t1(a); |
| INSERT INTO t1 VALUES( randomblob(8000) ); |
| COMMIT; |
| } {10000 wal2 0} |
| |
| do_test 7.1 { |
| list [file size test.db-wal] [file size test.db-wal2] |
| } {9464 0} |
| |
| # Connection db2 is holding a PART1 lock. |
| # |
| # 7.2.2: Test that the PART1 does not prevent db from switching to the |
| # other wal file. |
| # |
| # 7.2.3: Test that the PART1 does prevent a checkpoint of test.db-wal. |
| # |
| # 7.2.4: Test that after the PART1 is released the checkpoint is possible. |
| # |
| do_test 7.2.1 { |
| execsql { |
| BEGIN; |
| SELECT count(*) FROM t1; |
| } db2 |
| } {1} |
| do_test 7.2.2 { |
| execsql { |
| INSERT INTO t1 VALUES( randomblob(800) ); |
| INSERT INTO t1 VALUES( randomblob(800) ); |
| } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {13656 3176 1024} |
| do_test 7.2.3 { |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {13656 3176 1024} |
| do_test 7.2.4 { |
| execsql { END } db2 |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {13656 3176 11264} |
| |
| # Connection db2 is holding a PART2_FULL1 lock. |
| # |
| # 7.3.2: Test that the lock does not prevent checkpointing. |
| # |
| # 7.3.3: Test that the lock does prevent the writer from overwriting |
| # test.db-wal. |
| # |
| # 7.3.4: Test that after the PART2_FULL1 is released the writer can |
| # switch wal files and overwrite test.db-wal |
| # |
| db close |
| db2 close |
| sqlite3 db test.db |
| sqlite3 db2 test.db |
| do_test 7.3.1 { |
| execsql { |
| PRAGMA wal_autocheckpoint = 0; |
| PRAGMA journal_size_limit = 10000; |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| INSERT INTO t1 VALUES(randomblob(500)); |
| } |
| execsql { |
| BEGIN; |
| SELECT count(*) FROM t1; |
| } db2 |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 3176 11264} |
| do_test 7.3.2 { |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 3176 21504} |
| do_test 7.3.3 { |
| execsql { |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| INSERT INTO t1 VALUES(randomblob(500)); |
| } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 18896 21504} |
| do_test 7.3.4 { |
| execsql END db2 |
| execsql { INSERT INTO t1 VALUES(randomblob(5000)); } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 18896 21504} |
| |
| # Connection db2 is holding a PART2 lock. |
| # |
| # 7.4.2: Test that the lock does not prevent writer switching to test.db-wal. |
| # |
| # 7.3.3: Test that the lock does prevent checkpointing of test.db-wal2. |
| # |
| # 7.3.4: Test that after the PART2 is released test.db-wal2 can be |
| # checkpointed. |
| # |
| db close |
| db2 close |
| sqlite3 db test.db |
| sqlite3 db2 test.db |
| do_test 7.4.1 { |
| execsql { |
| PRAGMA wal_autocheckpoint = 0; |
| PRAGMA journal_size_limit = 10000; |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| PRAGMA wal_checkpoint; |
| } |
| execsql { |
| BEGIN; |
| SELECT count(*) FROM t1; |
| } db2 |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 44032} |
| do_test 7.4.2 { |
| execsql { |
| INSERT INTO t1 VALUES(randomblob(5000)); |
| } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 44032} |
| do_test 7.4.3 { |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 44032} |
| do_test 7.4.4 { |
| execsql END db2 |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 54272} |
| |
| # Connection db2 is holding a PART1_FULL2 lock. |
| # |
| # 7.5.2: Test that the lock does not prevent a checkpoint of test.db-wal2. |
| # |
| # 7.5.3: Test that the lock does prevent the writer from overwriting |
| # test.db-wal2. |
| # |
| # 7.5.4: Test that after the PART1_FULL2 lock is released, the writer |
| # can switch to test.db-wal2. |
| # |
| db close |
| db2 close |
| sqlite3 db test.db |
| sqlite3 db2 test.db |
| do_test 7.5.1 { |
| execsql { |
| PRAGMA wal_autocheckpoint = 0; |
| PRAGMA journal_size_limit = 10000; |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| INSERT INTO t1 VALUES(randomblob(10000)); |
| PRAGMA wal_checkpoint; |
| INSERT INTO t1 VALUES(randomblob(5000)); |
| } |
| execsql { |
| BEGIN; |
| SELECT count(*) FROM t1; |
| } db2 |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 64512} |
| do_test 7.5.2 { |
| execsql { PRAGMA wal_checkpoint } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {12608 12608 75776} |
| do_test 7.5.3.1 { |
| execsql { INSERT INTO t1 VALUES(randomblob(5000)) } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {14704 12608 75776} |
| do_test 7.5.3.2 { |
| execsql { INSERT INTO t1 VALUES(randomblob(5000)) } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {22040 12608 75776} |
| do_test 7.5.4 { |
| execsql END db2 |
| execsql { INSERT INTO t1 VALUES(randomblob(5000)) } |
| list [file size test.db-wal] [file size test.db-wal2] [file size test.db] |
| } {22040 12608 75776} |
| |
| |
| finish_test |
| |