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