# 2025 Jan 24 # # 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. # #*********************************************************************** # # TESTRUNNER: slow # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix walsetlk2 ifcapable !wal {finish_test ; return } ifcapable !setlk_timeout {finish_test ; return } #------------------------------------------------------------------------- # Check that xShmLock calls are as expected for write transactions in # setlk mode. # reset_db do_execsql_test 1.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); } {wal} db close testvfs tvfs tvfs script xShmLock_callback tvfs filter xShmLock set ::xshmlock [list] proc xShmLock_callback {method path name detail} { lappend ::xshmlock $detail } sqlite3 db test.db -vfs tvfs db timeout 1000 do_execsql_test 1.1 { SELECT * FROM t1 } {1 2 3} do_execsql_test 1.2 { INSERT INTO t1 VALUES(4, 5, 6); } set ::xshmlock [list] do_execsql_test 1.3 { INSERT INTO t1 VALUES(7, 8, 9); } do_test 1.4 { set ::xshmlock } [list \ {0 1 lock exclusive} \ {4 1 lock exclusive} {4 1 unlock exclusive} \ {4 1 lock shared} \ {0 1 unlock exclusive} \ {4 1 unlock shared} ] do_execsql_test 1.5.1 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9} set ::xshmlock [list] do_execsql_test 1.5.2 { INSERT INTO t1 VALUES(10, 11, 12); } do_test 1.5.3 { set ::xshmlock } [list \ {0 1 lock exclusive} \ {4 1 lock shared} \ {0 1 unlock exclusive} \ {4 1 unlock shared} ] db close tvfs delete #------------------------------------------------------------------------- # Check that if sqlite3_setlk_timeout() is used, blocking locks timeout # but other operations do not use the retry mechanism. # reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2), (3, 4); } sqlite3_setlk_timeout db 2000 # Launch a non-blocking testfixture process to write-lock the # database for 2000 ms. testfixture_nb done { sqlite3 db test.db db eval { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(5, 6); } after 2000 db eval { COMMIT } db close } after 500 {set ok 1} vwait ok do_catchsql_test 2.1 { INSERT INTO t1 VALUES(7, 8); } {1 {database is locked}} sqlite3_busy_timeout db 2000 do_catchsql_test 2.2 { INSERT INTO t1 VALUES(7, 8); } {0 {}} do_execsql_test 2.3 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} do_execsql_test 2.4 { PRAGMA journal_mode = wal; } {wal} db close sqlite3 db test.db do_execsql_test 2.5 { INSERT INTO t1 VALUES(9, 10); } if {$::sqlite_options(setlk_timeout)==1} { sqlite3_setlk_timeout db 2000 # Launch a non-blocking testfixture process to write-lock the # database for 2000 ms. testfixture_nb done { sqlite3 db test.db db eval { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(11, 12); } after 2000 db eval { COMMIT } db close } after 500 {set ok 1} vwait ok do_catchsql_test 2.6 { INSERT INTO t1 VALUES(13, 14); } {0 {}} do_execsql_test 2.7 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14} } #------------------------------------------------------------------------- # Check that if sqlite3_setlk_timeout(-1) is called, blocking locks are # enabled and last for a few seconds at least. Difficult to test that they # really do block indefinitely. # reset_db if {$::sqlite_options(setlk_timeout)==1} { do_execsql_test 3.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 'one'), (3, 'three'); } {wal} sqlite3_setlk_timeout db -1 # Launch a non-blocking testfixture process to write-lock the # database for 2000 ms. testfixture_nb done { sqlite3 db test.db db eval { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(5, 'five'); } after 2000 db eval { COMMIT } db close } after 500 {set ok 1} vwait ok breakpoint do_catchsql_test 3.1 { INSERT INTO t1 VALUES(7, 'seven'); } {0 {}} # Launch another non-blocking testfixture process to write-lock the # database for 2000 ms. testfixture_nb done { sqlite3 db test.db db eval { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(9, 'nine'); } after 2000 db eval { COMMIT } db close } after 500 {set ok 1} vwait ok do_catchsql_test 3.2 { INSERT INTO t1 VALUES(9, 'ten'); } {1 {UNIQUE constraint failed: t1.a}} do_execsql_test 3.3 { SELECT * FROM t1 } {1 one 3 three 5 five 7 seven 9 nine} db close # Launch another non-blocking testfixture process to write-lock the # database for 2000 ms. testfixture_nb done { sqlite3 db test.db db eval { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(11, 'eleven'); } after 2000 db eval { COMMIT } } sqlite3 db test.db sqlite3_setlk_timeout db -1 do_catchsql_test 3.4 { INSERT INTO t1 VALUES(13, 'thirteen'); } {0 {}} } finish_test