1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
# 2001 September 15
#
# 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 script is database locks.
#
# $Id: lock.test,v 1.13 2001/10/09 04:19:47 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create an alternative connection to the database
#
do_test lock-1.0 {
sqlite db2 ./test.db
} {}
do_test lock-1.1 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test lock-1.2 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
execsql {CREATE TABLE t1(a int, b int)}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.4 {
catchsql {
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
} db2
} {1 {database schema has changed}}
do_test lock-1.5 {
catchsql {
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
} db2
} {0 t1}
do_test lock-1.6 {
execsql {INSERT INTO t1 VALUES(1,2)}
execsql {SELECT * FROM t1}
} {1 2}
do_test lock-1.7 {
execsql {SELECT * FROM t1} db2
} {1 2}
do_test lock-1.8 {
execsql {UPDATE t1 SET a=b, b=a} db2
execsql {SELECT * FROM t1} db2
} {2 1}
do_test lock-1.9 {
execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.10 {
execsql {BEGIN TRANSACTION}
execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.11 {
catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_test lock-1.12 {
execsql {ROLLBACK}
catchsql {SELECT * FROM t1}
} {0 {2 1}}
do_test lock-1.13 {
execsql {CREATE TABLE t2(x int, y int)}
execsql {INSERT INTO t2 VALUES(8,9)}
execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14 {
catchsql {SELECT * FROM t1} db2
} {1 {database schema has changed}}
do_test lock-1.15 {
catchsql {SELECT * FROM t2} db2
} {0 {8 9}}
do_test lock-1.16 {
db eval {SELECT * FROM t1} qv {
set x [db eval {SELECT * FROM t1}]
}
set x
} {2 1}
do_test lock-1.17 {
db eval {SELECT * FROM t1} qv {
set x [db eval {SELECT * FROM t2}]
}
set x
} {8 9}
# You cannot UPDATE a table from within the callback of a SELECT
# on that same table because the SELECT has the table locked.
#
do_test lock-1.18 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
lappend r $msg
}
set r
} {1 {database table is locked}}
# But you can UPDATE a different table from the one that is used in
# the SELECT.
#
do_test lock-1.19 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
lappend r $msg
}
set r
} {0 {}}
do_test lock-1.20 {
execsql {SELECT * FROM t2}
} {9 8}
# It is possible to do a SELECT of the same table within the
# callback of another SELECT on that same table because two
# or more read-only cursors can be open at once.
#
do_test lock-1.21 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
# Under UNIX you can do two SELECTs at once with different database
# connections, because UNIX supports reader/writer locks. Under windows,
# this is not possible.
#
if {$::tcl_platform(platform)=="unix"} {
do_test lock-1.22 {
db eval {SELECT * FROM t1} qv {
set r [catch {db2 eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
}
# If one thread has a transaction another thread cannot start
# a transaction.
#
do_test lock-2.1 {
execsql {BEGIN TRANSACTION}
set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
lappend r $msg
} {1 {database is locked}}
# Nor can the other thread do a query.
#
do_test lock-2.2 {
set r [catch {execsql {SELECT * FROM t2} db2} msg]
lappend r $msg
} {1 {database is locked}}
# If the other thread (the one that does not hold the transaction)
# tries to start a transaction, we get a busy callback.
#
do_test lock-2.3 {
proc callback {args} {
set ::callback_value $args
break
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {{} 1}}
do_test lock-2.4 {
proc callback {file count} {
lappend ::callback_value $count
if {$count>4} break
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
do_test lock-2.5 {
proc callback {file count} {
lappend ::callback_value $count
if {$count>4} break
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {SELECT * FROM t1} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
# In this test, the 3rd invocation of the busy callback causes
# the first thread to release its transaction. That allows the
# second thread to continue.
#
do_test lock-2.6 {
proc callback {file count} {
lappend ::callback_value $count
if {$count>2} {
execsql {ROLLBACK}
}
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {SELECT * FROM t2} db2} msg]
lappend r $msg
lappend r $::callback_value
} {0 {9 8} {1 2 3}}
do_test lock-2.7 {
execsql {BEGIN TRANSACTION}
proc callback {file count} {
lappend ::callback_value $count
if {$count>2} {
execsql {ROLLBACK}
}
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
execsql {ROLLBACK} db2
lappend r $msg
lappend r $::callback_value
} {0 {} {1 2 3}}
# Try to start two transactions in a row
#
do_test lock-3.1 {
execsql {BEGIN TRANSACTION}
set r [catch {execsql {BEGIN TRANSACTION}} msg]
execsql {ROLLBACK}
lappend r $msg
} {0 {}}
do_test lock-999.1 {
rename db2 {}
} {}
finish_test
|