1
0

notify1.test 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. # 2009 March 04
  2. #
  3. # The author disclaims copyright to this source code. In place of
  4. # a legal notice, here is a blessing:
  5. #
  6. # May you do good and not evil.
  7. # May you find forgiveness for yourself and forgive others.
  8. # May you share freely, never taking more than you give.
  9. #
  10. #***********************************************************************
  11. # This file implements regression tests for SQLite library. The
  12. # focus of this file is testing the sqlite3_unlock_notify() API.
  13. #
  14. # $Id: notify1.test,v 1.4 2009/06/05 17:09:12 drh Exp $
  15. set testdir [file dirname $argv0]
  16. source $testdir/tester.tcl
  17. ifcapable !unlock_notify||!shared_cache {
  18. finish_test
  19. return
  20. }
  21. db close
  22. set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
  23. #-------------------------------------------------------------------------
  24. # Warm body test. Test that an unlock-notify callback can be registered
  25. # and that it is invoked.
  26. #
  27. do_test notify1-1.1 {
  28. sqlite3 db test.db
  29. sqlite3 db2 test.db
  30. execsql { CREATE TABLE t1(a, b) }
  31. } {}
  32. do_test notify1-1.2 {
  33. execsql {
  34. BEGIN;
  35. INSERT INTO t1 VALUES(1, 2);
  36. }
  37. catchsql { INSERT INTO t1 VALUES(3, 4) } db2
  38. } {1 {database table is locked}}
  39. do_test notify1-1.3 {
  40. set zScript ""
  41. db2 unlock_notify {
  42. set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }"
  43. }
  44. execsql { SELECT * FROM t1 }
  45. } {1 2}
  46. do_test notify1-1.4 {
  47. set zScript
  48. } {}
  49. do_test notify1-1.5 {
  50. execsql { COMMIT }
  51. eval $zScript
  52. execsql { SELECT * FROM t1 }
  53. } {1 2 3 4}
  54. #-------------------------------------------------------------------------
  55. # Verify that invoking the "unlock_notify" method with no arguments
  56. # (which is the equivalent of invoking sqlite3_unlock_notify() with
  57. # a NULL xNotify argument) cancels a pending notify callback.
  58. #
  59. do_test notify1-1.11 {
  60. execsql { DROP TABLE t1; CREATE TABLE t1(a, b) }
  61. } {}
  62. do_test notify1-1.12 {
  63. execsql {
  64. BEGIN;
  65. INSERT INTO t1 VALUES(1, 2);
  66. }
  67. catchsql { INSERT INTO t1 VALUES(3, 4) } db2
  68. } {1 {database table is locked}}
  69. do_test notify1-1.13 {
  70. set zScript ""
  71. db2 unlock_notify {
  72. set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }"
  73. }
  74. execsql { SELECT * FROM t1 }
  75. } {1 2}
  76. do_test notify1-1.14 {
  77. set zScript
  78. } {}
  79. do_test notify1-1.15 {
  80. db2 unlock_notify
  81. execsql { COMMIT }
  82. eval $zScript
  83. execsql { SELECT * FROM t1 }
  84. } {1 2}
  85. #-------------------------------------------------------------------------
  86. # The following tests, notify1-2.*, test that deadlock is detected
  87. # correctly.
  88. #
  89. do_test notify1-2.1 {
  90. execsql {
  91. CREATE TABLE t2(a, b);
  92. INSERT INTO t2 VALUES('I', 'II');
  93. }
  94. } {}
  95. #
  96. # Test for simple deadlock involving two database connections.
  97. #
  98. # 1. Grab a write-lock on t1 with [db]. Then grab a read-lock on t2 with [db2].
  99. # 2. Try to grab a read-lock on t1 with [db2] (fails).
  100. # 3. Have [db2] wait on the read-lock it failed to obtain in step 2.
  101. # 4. Try to grab a write-lock on t2 with [db] (fails).
  102. # 5. Try to have [db] wait on the lock from step 4. Fails, as the system
  103. # would be deadlocked (since [db2] is already waiting on [db], and this
  104. # operation would have [db] wait on [db2]).
  105. #
  106. do_test notify1-2.2.1 {
  107. execsql {
  108. BEGIN;
  109. INSERT INTO t1 VALUES(5, 6);
  110. }
  111. execsql {
  112. BEGIN;
  113. SELECT * FROM t2;
  114. } db2
  115. } {I II}
  116. do_test notify1-2.2.2 {
  117. catchsql { SELECT * FROM t1 } db2
  118. } {1 {database table is locked: t1}}
  119. do_test notify1-2.2.3 {
  120. db2 unlock_notify {lappend unlock_notify db2}
  121. } {}
  122. do_test notify1-2.2.4 {
  123. catchsql { INSERT INTO t2 VALUES('III', 'IV') }
  124. } {1 {database table is locked: t2}}
  125. do_test notify1-2.2.5 {
  126. set rc [catch { db unlock_notify {lappend unlock_notify db} } msg]
  127. list $rc $msg
  128. } {1 {database is deadlocked}}
  129. #
  130. # Test for slightly more complex deadlock involving three database
  131. # connections: db, db2 and db3.
  132. #
  133. do_test notify1-2.3.1 {
  134. db close
  135. db2 close
  136. forcedelete test.db test2.db test3.db
  137. foreach con {db db2 db3} {
  138. sqlite3 $con test.db
  139. $con eval { ATTACH 'test2.db' AS aux2 }
  140. $con eval { ATTACH 'test3.db' AS aux3 }
  141. }
  142. execsql {
  143. CREATE TABLE main.t1(a, b);
  144. CREATE TABLE aux2.t2(a, b);
  145. CREATE TABLE aux3.t3(a, b);
  146. }
  147. } {}
  148. do_test notify1-2.3.2 {
  149. execsql { BEGIN ; INSERT INTO t1 VALUES(1, 2) } db
  150. execsql { BEGIN ; INSERT INTO t2 VALUES(1, 2) } db2
  151. execsql { BEGIN ; INSERT INTO t3 VALUES(1, 2) } db3
  152. } {}
  153. do_test notify1-2.3.3 {
  154. catchsql { SELECT * FROM t2 } db
  155. } {1 {database table is locked: t2}}
  156. do_test notify1-2.3.4 {
  157. catchsql { SELECT * FROM t3 } db2
  158. } {1 {database table is locked: t3}}
  159. do_test notify1-2.3.5 {
  160. catchsql { SELECT * FROM t1 } db3
  161. } {1 {database table is locked: t1}}
  162. do_test notify1-2.3.6 {
  163. set lUnlock [list]
  164. db unlock_notify {lappend lUnlock db}
  165. db2 unlock_notify {lappend lUnlock db2}
  166. } {}
  167. do_test notify1-2.3.7 {
  168. set rc [catch { db3 unlock_notify {lappend lUnlock db3} } msg]
  169. list $rc $msg
  170. } {1 {database is deadlocked}}
  171. do_test notify1-2.3.8 {
  172. execsql { COMMIT }
  173. set lUnlock
  174. } {}
  175. do_test notify1-2.3.9 {
  176. db3 unlock_notify {lappend lUnlock db3}
  177. set lUnlock
  178. } {db3}
  179. do_test notify1-2.3.10 {
  180. execsql { COMMIT } db2
  181. set lUnlock
  182. } {db3 db}
  183. do_test notify1-2.3.11 {
  184. execsql { COMMIT } db3
  185. set lUnlock
  186. } {db3 db db2}
  187. catch { db3 close }
  188. catch { db2 close }
  189. catch { db close }
  190. #-------------------------------------------------------------------------
  191. # The following tests, notify1-3.* and notify1-4.*, test that callbacks
  192. # can be issued when there are many (>16) connections waiting on a single
  193. # unlock event.
  194. #
  195. foreach {tn nConn} {3 20 4 76} {
  196. do_test notify1-$tn.1 {
  197. sqlite3 db test.db
  198. execsql {
  199. BEGIN;
  200. INSERT INTO t1 VALUES('a', 'b');
  201. }
  202. } {}
  203. set lUnlock [list]
  204. set lUnlockFinal [list]
  205. for {set ii 1} {$ii <= $nConn} {incr ii} {
  206. do_test notify1-$tn.2.$ii.1 {
  207. set cmd "db$ii"
  208. sqlite3 $cmd test.db
  209. catchsql { SELECT * FROM t1 } $cmd
  210. } {1 {database table is locked: t1}}
  211. do_test notify1-$tn.2.$ii.2 {
  212. $cmd unlock_notify "lappend lUnlock $ii"
  213. } {}
  214. lappend lUnlockFinal $ii
  215. }
  216. do_test notify1-$tn.3 {
  217. set lUnlock
  218. } {}
  219. do_test notify1-$tn.4 {
  220. execsql {COMMIT}
  221. lsort -integer $lUnlock
  222. } $lUnlockFinal
  223. do_test notify1-$tn.5 {
  224. for {set ii 1} {$ii <= $nConn} {incr ii} {
  225. "db$ii" close
  226. }
  227. } {}
  228. }
  229. db close
  230. #-------------------------------------------------------------------------
  231. # These tests, notify1-5.*, test that a malloc() failure that occurs while
  232. # allocating an array to use as an argument to an unlock-notify callback
  233. # is handled correctly.
  234. #
  235. source $testdir/malloc_common.tcl
  236. do_malloc_test notify1-5 -tclprep {
  237. set ::lUnlock [list]
  238. execsql {
  239. CREATE TABLE t1(a, b);
  240. BEGIN;
  241. INSERT INTO t1 VALUES('a', 'b');
  242. }
  243. for {set ii 1} {$ii <= 60} {incr ii} {
  244. set cmd "db$ii"
  245. sqlite3 $cmd test.db
  246. catchsql { SELECT * FROM t1 } $cmd
  247. $cmd unlock_notify "lappend ::lUnlock $ii"
  248. }
  249. } -sqlbody {
  250. COMMIT;
  251. } -cleanup {
  252. # One of two things should have happened:
  253. #
  254. # 1) The transaction opened by [db] was not committed. No unlock-notify
  255. # callbacks were invoked, OR
  256. # 2) The transaction opened by [db] was committed and 60 unlock-notify
  257. # callbacks were invoked.
  258. #
  259. do_test notify1-5.systemstate {
  260. expr { ([llength $::lUnlock]==0 && [sqlite3_get_autocommit db]==0)
  261. || ([llength $::lUnlock]==60 && [sqlite3_get_autocommit db]==1)
  262. }
  263. } {1}
  264. for {set ii 1} {$ii <= 60} {incr ii} { "db$ii" close }
  265. }
  266. #-------------------------------------------------------------------------
  267. # Test cases notify1-6.* test cases where the following occur:
  268. #
  269. # notify1-6.1.*: Test encountering an SQLITE_LOCKED error when the
  270. # "blocking connection" has already been set by a previous
  271. # SQLITE_LOCKED.
  272. #
  273. # notify1-6.2.*: Test encountering an SQLITE_LOCKED error when already
  274. # waiting on an unlock-notify callback.
  275. #
  276. # notify1-6.3.*: Test that if an SQLITE_LOCKED error is encountered while
  277. # already waiting on an unlock-notify callback, and then
  278. # the blocker that caused the SQLITE_LOCKED commits its
  279. # transaction, the unlock-notify callback is not invoked.
  280. #
  281. # notify1-6.4.*: Like 6.3.*, except that instead of the second blocker
  282. # committing its transaction, the first does. The
  283. # unlock-notify callback is therefore invoked.
  284. #
  285. db close
  286. do_test notify1-6.1.1 {
  287. forcedelete test.db test2.db
  288. foreach conn {db db2 db3} {
  289. sqlite3 $conn test.db
  290. execsql { ATTACH 'test2.db' AS two } $conn
  291. }
  292. execsql {
  293. CREATE TABLE t1(a, b);
  294. CREATE TABLE two.t2(a, b);
  295. }
  296. execsql {
  297. BEGIN;
  298. INSERT INTO t1 VALUES(1, 2);
  299. } db2
  300. execsql {
  301. BEGIN;
  302. INSERT INTO t2 VALUES(1, 2);
  303. } db3
  304. } {}
  305. do_test notify1-6.1.2 {
  306. catchsql { SELECT * FROM t2 }
  307. } {1 {database table is locked: t2}}
  308. do_test notify1-6.1.3 {
  309. catchsql { SELECT * FROM t1 }
  310. } {1 {database table is locked: t1}}
  311. do_test notify1-6.2.1 {
  312. set unlocked 0
  313. db unlock_notify {set unlocked 1}
  314. set unlocked
  315. } {0}
  316. do_test notify1-6.2.2 {
  317. catchsql { SELECT * FROM t2 }
  318. } {1 {database table is locked: t2}}
  319. do_test notify1-6.2.3 {
  320. execsql { COMMIT } db2
  321. set unlocked
  322. } {1}
  323. do_test notify1-6.3.1 {
  324. execsql {
  325. BEGIN;
  326. INSERT INTO t1 VALUES(3, 4);
  327. } db2
  328. } {}
  329. do_test notify1-6.3.2 {
  330. catchsql { SELECT * FROM t1 }
  331. } {1 {database table is locked: t1}}
  332. do_test notify1-6.3.3 {
  333. set unlocked 0
  334. db unlock_notify {set unlocked 1}
  335. set unlocked
  336. } {0}
  337. do_test notify1-6.3.4 {
  338. catchsql { SELECT * FROM t2 }
  339. } {1 {database table is locked: t2}}
  340. do_test notify1-6.3.5 {
  341. execsql { COMMIT } db3
  342. set unlocked
  343. } {0}
  344. do_test notify1-6.4.1 {
  345. execsql {
  346. BEGIN;
  347. INSERT INTO t2 VALUES(3, 4);
  348. } db3
  349. catchsql { SELECT * FROM t2 }
  350. } {1 {database table is locked: t2}}
  351. do_test notify1-6.4.2 {
  352. execsql { COMMIT } db2
  353. set unlocked
  354. } {1}
  355. do_test notify1-6.4.3 {
  356. execsql { COMMIT } db3
  357. } {}
  358. db close
  359. db2 close
  360. db3 close
  361. #-------------------------------------------------------------------------
  362. # Test cases notify1-7.* tests that when more than one distinct
  363. # unlock-notify function is registered, all are invoked correctly.
  364. #
  365. proc unlock_notify {} {
  366. incr ::unlock_notify
  367. }
  368. do_test notify1-7.1 {
  369. foreach conn {db db2 db3} {
  370. sqlite3 $conn test.db
  371. }
  372. execsql {
  373. BEGIN;
  374. INSERT INTO t1 VALUES(5, 6);
  375. }
  376. } {}
  377. do_test notify1-7.2 {
  378. catchsql { SELECT * FROM t1 } db2
  379. } {1 {database table is locked: t1}}
  380. do_test notify1-7.3 {
  381. catchsql { SELECT * FROM t1 } db3
  382. } {1 {database table is locked: t1}}
  383. do_test notify1-7.4 {
  384. set unlock_notify 0
  385. db2 unlock_notify unlock_notify
  386. sqlite3_unlock_notify db3
  387. } {SQLITE_OK}
  388. do_test notify1-7.5 {
  389. set unlock_notify
  390. } {0}
  391. do_test notify1-7.6 {
  392. execsql { COMMIT }
  393. set unlock_notify
  394. } {2}
  395. #-------------------------------------------------------------------------
  396. # Test cases notify1-8.* tests that the correct SQLITE_LOCKED extended
  397. # error code is returned in various scenarios.
  398. #
  399. do_test notify1-8.1 {
  400. execsql {
  401. BEGIN;
  402. INSERT INTO t1 VALUES(7, 8);
  403. }
  404. catchsql { SELECT * FROM t1 } db2
  405. } {1 {database table is locked: t1}}
  406. do_test notify1-8.2 {
  407. sqlite3_extended_errcode db2
  408. } {SQLITE_LOCKED_SHAREDCACHE}
  409. do_test notify1-8.3 {
  410. execsql {
  411. COMMIT;
  412. BEGIN EXCLUSIVE;
  413. }
  414. catchsql { SELECT * FROM t1 } db2
  415. } {1 {database schema is locked: main}}
  416. do_test notify1-8.4 {
  417. sqlite3_extended_errcode db2
  418. } {SQLITE_LOCKED_SHAREDCACHE}
  419. do_test notify1-8.X {
  420. execsql { COMMIT }
  421. } {}
  422. #-------------------------------------------------------------------------
  423. # Test cases notify1-9.* test the shared-cache 'pending-lock' feature.
  424. #
  425. do_test notify1-9.1 {
  426. execsql {
  427. CREATE TABLE t2(a, b);
  428. BEGIN;
  429. SELECT * FROM t1;
  430. } db2
  431. } {1 2 3 4 5 6 7 8}
  432. do_test notify1-9.2 {
  433. execsql { SELECT * FROM t1 } db3
  434. } {1 2 3 4 5 6 7 8}
  435. do_test notify1-9.3 {
  436. catchsql {
  437. BEGIN;
  438. INSERT INTO t1 VALUES(9, 10);
  439. }
  440. } {1 {database table is locked: t1}}
  441. do_test notify1-9.4 {
  442. catchsql { SELECT * FROM t2 } db3
  443. } {1 {database table is locked}}
  444. do_test notify1-9.5 {
  445. execsql { COMMIT } db2
  446. execsql { SELECT * FROM t2 } db3
  447. } {}
  448. do_test notify1-9.6 {
  449. execsql { COMMIT }
  450. } {}
  451. do_test notify1-9.7 {
  452. execsql {
  453. BEGIN;
  454. SELECT * FROM t1;
  455. } db2
  456. } {1 2 3 4 5 6 7 8}
  457. do_test notify1-9.8 {
  458. execsql { SELECT * FROM t1 } db3
  459. } {1 2 3 4 5 6 7 8}
  460. do_test notify1-9.9 {
  461. catchsql {
  462. BEGIN;
  463. INSERT INTO t1 VALUES(9, 10);
  464. }
  465. } {1 {database table is locked: t1}}
  466. do_test notify1-9.10 {
  467. catchsql { SELECT * FROM t2 } db3
  468. } {1 {database table is locked}}
  469. do_test notify1-9.11 {
  470. execsql { COMMIT }
  471. execsql { SELECT * FROM t2 } db3
  472. } {}
  473. do_test notify1-9.12 {
  474. execsql { COMMIT } db2
  475. } {}
  476. db close
  477. db2 close
  478. db3 close
  479. sqlite3_enable_shared_cache $::enable_shared_cache
  480. finish_test