1*c5c4113dSnw141292 2*c5c4113dSnw141292#pragma ident "%Z%%M% %I% %E% SMI" 3*c5c4113dSnw141292 4*c5c4113dSnw141292# 2001 September 15 5*c5c4113dSnw141292# 6*c5c4113dSnw141292# The author disclaims copyright to this source code. In place of 7*c5c4113dSnw141292# a legal notice, here is a blessing: 8*c5c4113dSnw141292# 9*c5c4113dSnw141292# May you do good and not evil. 10*c5c4113dSnw141292# May you find forgiveness for yourself and forgive others. 11*c5c4113dSnw141292# May you share freely, never taking more than you give. 12*c5c4113dSnw141292# 13*c5c4113dSnw141292#*********************************************************************** 14*c5c4113dSnw141292# This file implements regression tests for SQLite library. The 15*c5c4113dSnw141292# focus of this script is database locks. 16*c5c4113dSnw141292# 17*c5c4113dSnw141292# $Id: lock.test,v 1.20 2004/02/14 16:31:04 drh Exp $ 18*c5c4113dSnw141292 19*c5c4113dSnw141292 20*c5c4113dSnw141292set testdir [file dirname $argv0] 21*c5c4113dSnw141292source $testdir/tester.tcl 22*c5c4113dSnw141292 23*c5c4113dSnw141292# Create an alternative connection to the database 24*c5c4113dSnw141292# 25*c5c4113dSnw141292do_test lock-1.0 { 26*c5c4113dSnw141292 sqlite db2 ./test.db 27*c5c4113dSnw141292 set dummy {} 28*c5c4113dSnw141292} {} 29*c5c4113dSnw141292do_test lock-1.1 { 30*c5c4113dSnw141292 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} 31*c5c4113dSnw141292} {} 32*c5c4113dSnw141292do_test lock-1.2 { 33*c5c4113dSnw141292 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2 34*c5c4113dSnw141292} {} 35*c5c4113dSnw141292do_test lock-1.3 { 36*c5c4113dSnw141292 execsql {CREATE TABLE t1(a int, b int)} 37*c5c4113dSnw141292 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} 38*c5c4113dSnw141292} {t1} 39*c5c4113dSnw141292#do_test lock-1.4 { 40*c5c4113dSnw141292# catchsql { 41*c5c4113dSnw141292# SELECT name FROM sqlite_master WHERE type='table' ORDER BY name 42*c5c4113dSnw141292# } db2 43*c5c4113dSnw141292#} {1 {database schema has changed}} 44*c5c4113dSnw141292do_test lock-1.5 { 45*c5c4113dSnw141292 catchsql { 46*c5c4113dSnw141292 SELECT name FROM sqlite_master WHERE type='table' ORDER BY name 47*c5c4113dSnw141292 } db2 48*c5c4113dSnw141292} {0 t1} 49*c5c4113dSnw141292 50*c5c4113dSnw141292do_test lock-1.6 { 51*c5c4113dSnw141292 execsql {INSERT INTO t1 VALUES(1,2)} 52*c5c4113dSnw141292 execsql {SELECT * FROM t1} 53*c5c4113dSnw141292} {1 2} 54*c5c4113dSnw141292do_test lock-1.7 { 55*c5c4113dSnw141292 execsql {SELECT * FROM t1} db2 56*c5c4113dSnw141292} {1 2} 57*c5c4113dSnw141292do_test lock-1.8 { 58*c5c4113dSnw141292 execsql {UPDATE t1 SET a=b, b=a} db2 59*c5c4113dSnw141292 execsql {SELECT * FROM t1} db2 60*c5c4113dSnw141292} {2 1} 61*c5c4113dSnw141292do_test lock-1.9 { 62*c5c4113dSnw141292 execsql {SELECT * FROM t1} 63*c5c4113dSnw141292} {2 1} 64*c5c4113dSnw141292do_test lock-1.10 { 65*c5c4113dSnw141292 execsql {BEGIN TRANSACTION} 66*c5c4113dSnw141292 execsql {SELECT * FROM t1} 67*c5c4113dSnw141292} {2 1} 68*c5c4113dSnw141292do_test lock-1.11 { 69*c5c4113dSnw141292 catchsql {SELECT * FROM t1} db2 70*c5c4113dSnw141292} {1 {database is locked}} 71*c5c4113dSnw141292do_test lock-1.12 { 72*c5c4113dSnw141292 execsql {ROLLBACK} 73*c5c4113dSnw141292 catchsql {SELECT * FROM t1} 74*c5c4113dSnw141292} {0 {2 1}} 75*c5c4113dSnw141292 76*c5c4113dSnw141292do_test lock-1.13 { 77*c5c4113dSnw141292 execsql {CREATE TABLE t2(x int, y int)} 78*c5c4113dSnw141292 execsql {INSERT INTO t2 VALUES(8,9)} 79*c5c4113dSnw141292 execsql {SELECT * FROM t2} 80*c5c4113dSnw141292} {8 9} 81*c5c4113dSnw141292do_test lock-1.14.1 { 82*c5c4113dSnw141292 catchsql {SELECT * FROM t2} db2 83*c5c4113dSnw141292} {1 {no such table: t2}} 84*c5c4113dSnw141292do_test lock-1.14.2 { 85*c5c4113dSnw141292 catchsql {SELECT * FROM t1} db2 86*c5c4113dSnw141292} {0 {2 1}} 87*c5c4113dSnw141292do_test lock-1.15 { 88*c5c4113dSnw141292 catchsql {SELECT * FROM t2} db2 89*c5c4113dSnw141292} {0 {8 9}} 90*c5c4113dSnw141292 91*c5c4113dSnw141292do_test lock-1.16 { 92*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 93*c5c4113dSnw141292 set x [db eval {SELECT * FROM t1}] 94*c5c4113dSnw141292 } 95*c5c4113dSnw141292 set x 96*c5c4113dSnw141292} {2 1} 97*c5c4113dSnw141292do_test lock-1.17 { 98*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 99*c5c4113dSnw141292 set x [db eval {SELECT * FROM t2}] 100*c5c4113dSnw141292 } 101*c5c4113dSnw141292 set x 102*c5c4113dSnw141292} {8 9} 103*c5c4113dSnw141292 104*c5c4113dSnw141292# You cannot UPDATE a table from within the callback of a SELECT 105*c5c4113dSnw141292# on that same table because the SELECT has the table locked. 106*c5c4113dSnw141292# 107*c5c4113dSnw141292do_test lock-1.18 { 108*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 109*c5c4113dSnw141292 set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg] 110*c5c4113dSnw141292 lappend r $msg 111*c5c4113dSnw141292 } 112*c5c4113dSnw141292 set r 113*c5c4113dSnw141292} {1 {database table is locked}} 114*c5c4113dSnw141292 115*c5c4113dSnw141292# But you can UPDATE a different table from the one that is used in 116*c5c4113dSnw141292# the SELECT. 117*c5c4113dSnw141292# 118*c5c4113dSnw141292do_test lock-1.19 { 119*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 120*c5c4113dSnw141292 set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg] 121*c5c4113dSnw141292 lappend r $msg 122*c5c4113dSnw141292 } 123*c5c4113dSnw141292 set r 124*c5c4113dSnw141292} {0 {}} 125*c5c4113dSnw141292do_test lock-1.20 { 126*c5c4113dSnw141292 execsql {SELECT * FROM t2} 127*c5c4113dSnw141292} {9 8} 128*c5c4113dSnw141292 129*c5c4113dSnw141292# It is possible to do a SELECT of the same table within the 130*c5c4113dSnw141292# callback of another SELECT on that same table because two 131*c5c4113dSnw141292# or more read-only cursors can be open at once. 132*c5c4113dSnw141292# 133*c5c4113dSnw141292do_test lock-1.21 { 134*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 135*c5c4113dSnw141292 set r [catch {db eval {SELECT a FROM t1}} msg] 136*c5c4113dSnw141292 lappend r $msg 137*c5c4113dSnw141292 } 138*c5c4113dSnw141292 set r 139*c5c4113dSnw141292} {0 2} 140*c5c4113dSnw141292 141*c5c4113dSnw141292# Under UNIX you can do two SELECTs at once with different database 142*c5c4113dSnw141292# connections, because UNIX supports reader/writer locks. Under windows, 143*c5c4113dSnw141292# this is not possible. 144*c5c4113dSnw141292# 145*c5c4113dSnw141292if {$::tcl_platform(platform)=="unix"} { 146*c5c4113dSnw141292 do_test lock-1.22 { 147*c5c4113dSnw141292 db eval {SELECT * FROM t1} qv { 148*c5c4113dSnw141292 set r [catch {db2 eval {SELECT a FROM t1}} msg] 149*c5c4113dSnw141292 lappend r $msg 150*c5c4113dSnw141292 } 151*c5c4113dSnw141292 set r 152*c5c4113dSnw141292 } {0 2} 153*c5c4113dSnw141292} 154*c5c4113dSnw141292integrity_check lock-1.23 155*c5c4113dSnw141292 156*c5c4113dSnw141292# If one thread has a transaction another thread cannot start 157*c5c4113dSnw141292# a transaction. 158*c5c4113dSnw141292# 159*c5c4113dSnw141292do_test lock-2.1 { 160*c5c4113dSnw141292 execsql {BEGIN TRANSACTION} 161*c5c4113dSnw141292 set r [catch {execsql {BEGIN TRANSACTION} db2} msg] 162*c5c4113dSnw141292 lappend r $msg 163*c5c4113dSnw141292} {1 {database is locked}} 164*c5c4113dSnw141292 165*c5c4113dSnw141292# Nor can the other thread do a query. 166*c5c4113dSnw141292# 167*c5c4113dSnw141292do_test lock-2.2 { 168*c5c4113dSnw141292 set r [catch {execsql {SELECT * FROM t2} db2} msg] 169*c5c4113dSnw141292 lappend r $msg 170*c5c4113dSnw141292} {1 {database is locked}} 171*c5c4113dSnw141292 172*c5c4113dSnw141292# If the other thread (the one that does not hold the transaction) 173*c5c4113dSnw141292# tries to start a transaction, we get a busy callback. 174*c5c4113dSnw141292# 175*c5c4113dSnw141292do_test lock-2.3 { 176*c5c4113dSnw141292 proc callback {args} { 177*c5c4113dSnw141292 set ::callback_value $args 178*c5c4113dSnw141292 break 179*c5c4113dSnw141292 } 180*c5c4113dSnw141292 set ::callback_value {} 181*c5c4113dSnw141292 db2 busy callback 182*c5c4113dSnw141292 set r [catch {execsql {BEGIN TRANSACTION} db2} msg] 183*c5c4113dSnw141292 lappend r $msg 184*c5c4113dSnw141292 lappend r $::callback_value 185*c5c4113dSnw141292} {1 {database is locked} {{} 1}} 186*c5c4113dSnw141292do_test lock-2.4 { 187*c5c4113dSnw141292 proc callback {file count} { 188*c5c4113dSnw141292 lappend ::callback_value $count 189*c5c4113dSnw141292 if {$count>4} break 190*c5c4113dSnw141292 } 191*c5c4113dSnw141292 set ::callback_value {} 192*c5c4113dSnw141292 db2 busy callback 193*c5c4113dSnw141292 set r [catch {execsql {BEGIN TRANSACTION} db2} msg] 194*c5c4113dSnw141292 lappend r $msg 195*c5c4113dSnw141292 lappend r $::callback_value 196*c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}} 197*c5c4113dSnw141292do_test lock-2.5 { 198*c5c4113dSnw141292 proc callback {file count} { 199*c5c4113dSnw141292 lappend ::callback_value $count 200*c5c4113dSnw141292 if {$count>4} break 201*c5c4113dSnw141292 } 202*c5c4113dSnw141292 set ::callback_value {} 203*c5c4113dSnw141292 db2 busy callback 204*c5c4113dSnw141292 set r [catch {execsql {SELECT * FROM t1} db2} msg] 205*c5c4113dSnw141292 lappend r $msg 206*c5c4113dSnw141292 lappend r $::callback_value 207*c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}} 208*c5c4113dSnw141292 209*c5c4113dSnw141292# In this test, the 3rd invocation of the busy callback causes 210*c5c4113dSnw141292# the first thread to release its transaction. That allows the 211*c5c4113dSnw141292# second thread to continue. 212*c5c4113dSnw141292# 213*c5c4113dSnw141292do_test lock-2.6 { 214*c5c4113dSnw141292 proc callback {file count} { 215*c5c4113dSnw141292 lappend ::callback_value $count 216*c5c4113dSnw141292 if {$count>2} { 217*c5c4113dSnw141292 execsql {ROLLBACK} 218*c5c4113dSnw141292 } 219*c5c4113dSnw141292 } 220*c5c4113dSnw141292 set ::callback_value {} 221*c5c4113dSnw141292 db2 busy callback 222*c5c4113dSnw141292 set r [catch {execsql {SELECT * FROM t2} db2} msg] 223*c5c4113dSnw141292 lappend r $msg 224*c5c4113dSnw141292 lappend r $::callback_value 225*c5c4113dSnw141292} {0 {9 8} {1 2 3}} 226*c5c4113dSnw141292do_test lock-2.7 { 227*c5c4113dSnw141292 execsql {BEGIN TRANSACTION} 228*c5c4113dSnw141292 proc callback {file count} { 229*c5c4113dSnw141292 lappend ::callback_value $count 230*c5c4113dSnw141292 if {$count>2} { 231*c5c4113dSnw141292 execsql {ROLLBACK} 232*c5c4113dSnw141292 } 233*c5c4113dSnw141292 } 234*c5c4113dSnw141292 set ::callback_value {} 235*c5c4113dSnw141292 db2 busy callback 236*c5c4113dSnw141292 set r [catch {execsql {BEGIN TRANSACTION} db2} msg] 237*c5c4113dSnw141292 execsql {ROLLBACK} db2 238*c5c4113dSnw141292 lappend r $msg 239*c5c4113dSnw141292 lappend r $::callback_value 240*c5c4113dSnw141292} {0 {} {1 2 3}} 241*c5c4113dSnw141292 242*c5c4113dSnw141292# Test the built-in busy timeout handler 243*c5c4113dSnw141292# 244*c5c4113dSnw141292do_test lock-2.8 { 245*c5c4113dSnw141292 db2 timeout 400 246*c5c4113dSnw141292 execsql BEGIN 247*c5c4113dSnw141292 catchsql BEGIN db2 248*c5c4113dSnw141292} {1 {database is locked}} 249*c5c4113dSnw141292do_test lock-2.9 { 250*c5c4113dSnw141292 db2 timeout 0 251*c5c4113dSnw141292 execsql COMMIT 252*c5c4113dSnw141292} {} 253*c5c4113dSnw141292integrity_check lock-2.10 254*c5c4113dSnw141292 255*c5c4113dSnw141292# Try to start two transactions in a row 256*c5c4113dSnw141292# 257*c5c4113dSnw141292do_test lock-3.1 { 258*c5c4113dSnw141292 execsql {BEGIN TRANSACTION} 259*c5c4113dSnw141292 set r [catch {execsql {BEGIN TRANSACTION}} msg] 260*c5c4113dSnw141292 execsql {ROLLBACK} 261*c5c4113dSnw141292 lappend r $msg 262*c5c4113dSnw141292} {1 {cannot start a transaction within a transaction}} 263*c5c4113dSnw141292integrity_check lock-3.2 264*c5c4113dSnw141292 265*c5c4113dSnw141292# Make sure the busy handler and error messages work when 266*c5c4113dSnw141292# opening a new pointer to the database while another pointer 267*c5c4113dSnw141292# has the database locked. 268*c5c4113dSnw141292# 269*c5c4113dSnw141292do_test lock-4.1 { 270*c5c4113dSnw141292 db2 close 271*c5c4113dSnw141292 catch {db eval ROLLBACK} 272*c5c4113dSnw141292 db eval BEGIN 273*c5c4113dSnw141292 sqlite db2 ./test.db 274*c5c4113dSnw141292 set rc [catch {db2 eval {SELECT * FROM t1}} msg] 275*c5c4113dSnw141292 lappend rc $msg 276*c5c4113dSnw141292} {1 {database is locked}} 277*c5c4113dSnw141292do_test lock-4.2 { 278*c5c4113dSnw141292 set ::callback_value {} 279*c5c4113dSnw141292 set rc [catch {db2 eval {SELECT * FROM t1}} msg] 280*c5c4113dSnw141292 lappend rc $msg $::callback_value 281*c5c4113dSnw141292} {1 {database is locked} {}} 282*c5c4113dSnw141292do_test lock-4.3 { 283*c5c4113dSnw141292 proc callback {file count} { 284*c5c4113dSnw141292 lappend ::callback_value $count 285*c5c4113dSnw141292 if {$count>4} break 286*c5c4113dSnw141292 } 287*c5c4113dSnw141292 db2 busy callback 288*c5c4113dSnw141292 set rc [catch {db2 eval {SELECT * FROM t1}} msg] 289*c5c4113dSnw141292 lappend rc $msg $::callback_value 290*c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}} 291*c5c4113dSnw141292execsql {ROLLBACK} 292*c5c4113dSnw141292 293*c5c4113dSnw141292# When one thread is writing, other threads cannot read. Except if the 294*c5c4113dSnw141292# writing thread is writing to its temporary tables, the other threads 295*c5c4113dSnw141292# can still read. 296*c5c4113dSnw141292# 297*c5c4113dSnw141292proc tx_exec {sql} { 298*c5c4113dSnw141292 db2 eval $sql 299*c5c4113dSnw141292} 300*c5c4113dSnw141292do_test lock-5.1 { 301*c5c4113dSnw141292 execsql { 302*c5c4113dSnw141292 SELECT * FROM t1 303*c5c4113dSnw141292 } 304*c5c4113dSnw141292} {2 1} 305*c5c4113dSnw141292do_test lock-5.2 { 306*c5c4113dSnw141292 db function tx_exec tx_exec 307*c5c4113dSnw141292 catchsql { 308*c5c4113dSnw141292 INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1'); 309*c5c4113dSnw141292 } 310*c5c4113dSnw141292} {1 {database is locked}} 311*c5c4113dSnw141292do_test lock-5.3 { 312*c5c4113dSnw141292 execsql { 313*c5c4113dSnw141292 CREATE TEMP TABLE t3(x); 314*c5c4113dSnw141292 SELECT * FROM t3; 315*c5c4113dSnw141292 } 316*c5c4113dSnw141292} {} 317*c5c4113dSnw141292do_test lock-5.4 { 318*c5c4113dSnw141292 catchsql { 319*c5c4113dSnw141292 INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1'); 320*c5c4113dSnw141292 } 321*c5c4113dSnw141292} {0 {}} 322*c5c4113dSnw141292do_test lock-5.5 { 323*c5c4113dSnw141292 execsql { 324*c5c4113dSnw141292 SELECT * FROM t3; 325*c5c4113dSnw141292 } 326*c5c4113dSnw141292} {8} 327*c5c4113dSnw141292do_test lock-5.6 { 328*c5c4113dSnw141292 catchsql { 329*c5c4113dSnw141292 UPDATE t1 SET a=tx_exec('SELECT x FROM t2'); 330*c5c4113dSnw141292 } 331*c5c4113dSnw141292} {1 {database is locked}} 332*c5c4113dSnw141292do_test lock-5.7 { 333*c5c4113dSnw141292 execsql { 334*c5c4113dSnw141292 SELECT * FROM t1; 335*c5c4113dSnw141292 } 336*c5c4113dSnw141292} {2 1} 337*c5c4113dSnw141292do_test lock-5.8 { 338*c5c4113dSnw141292 catchsql { 339*c5c4113dSnw141292 UPDATE t3 SET x=tx_exec('SELECT x FROM t2'); 340*c5c4113dSnw141292 } 341*c5c4113dSnw141292} {0 {}} 342*c5c4113dSnw141292do_test lock-5.9 { 343*c5c4113dSnw141292 execsql { 344*c5c4113dSnw141292 SELECT * FROM t3; 345*c5c4113dSnw141292 } 346*c5c4113dSnw141292} {9} 347*c5c4113dSnw141292 348*c5c4113dSnw141292do_test lock-999.1 { 349*c5c4113dSnw141292 rename db2 {} 350*c5c4113dSnw141292} {} 351*c5c4113dSnw141292 352*c5c4113dSnw141292finish_test 353