incrblob2.test 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. # 2008 June 9
  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. #
  12. # Test that it is possible to have two open blob handles on a single
  13. # blob object.
  14. #
  15. # $Id: incrblob2.test,v 1.11 2009/06/29 06:00:37 danielk1977 Exp $
  16. #
  17. set testdir [file dirname $argv0]
  18. source $testdir/tester.tcl
  19. ifcapable {!autovacuum || !pragma || !incrblob} {
  20. finish_test
  21. return
  22. }
  23. do_test incrblob2-1.0 {
  24. execsql {
  25. CREATE TABLE blobs(id INTEGER PRIMARY KEY, data BLOB);
  26. INSERT INTO blobs VALUES(NULL, zeroblob(5000));
  27. INSERT INTO blobs VALUES(NULL, zeroblob(5000));
  28. INSERT INTO blobs VALUES(NULL, zeroblob(5000));
  29. INSERT INTO blobs VALUES(NULL, zeroblob(5000));
  30. }
  31. } {}
  32. foreach iOffset [list 0 256 4094] {
  33. do_test incrblob2-1.$iOffset.1 {
  34. set fd [db incrblob blobs data 1]
  35. puts $fd "[string repeat x $iOffset]SQLite version 3.6.0"
  36. close $fd
  37. } {}
  38. do_test incrblob2-1.$iOffset.2 {
  39. set fd1 [db incrblob blobs data 1]
  40. set fd2 [db incrblob blobs data 1]
  41. fconfigure $fd1 -buffering none
  42. fconfigure $fd2 -buffering none
  43. if {$iOffset != 0} {
  44. seek $fd2 $iOffset start
  45. seek $fd1 $iOffset start
  46. }
  47. read $fd1 6
  48. } {SQLite}
  49. do_test incrblob2-1.$iOffset.3 {
  50. read $fd2 6
  51. } {SQLite}
  52. do_test incrblob2-1.$iOffset.4 {
  53. seek $fd2 $iOffset start
  54. seek $fd1 $iOffset start
  55. puts -nonewline $fd2 "etiLQS"
  56. } {}
  57. do_test incrblob2-1.$iOffset.5 {
  58. seek $fd1 $iOffset start
  59. read $fd1 6
  60. } {etiLQS}
  61. do_test incrblob2-1.$iOffset.6 {
  62. seek $fd2 $iOffset start
  63. read $fd2 6
  64. } {etiLQS}
  65. do_test incrblob2-1.$iOffset.7 {
  66. seek $fd1 $iOffset start
  67. read $fd1 6
  68. } {etiLQS}
  69. do_test incrblob2-1.$iOffset.8 {
  70. close $fd1
  71. close $fd2
  72. } {}
  73. }
  74. #--------------------------------------------------------------------------
  75. foreach iOffset [list 0 256 4094] {
  76. do_test incrblob2-2.$iOffset.1 {
  77. set fd1 [db incrblob blobs data 1]
  78. seek $fd1 [expr $iOffset - 5000] end
  79. fconfigure $fd1 -buffering none
  80. set fd2 [db incrblob blobs data 1]
  81. seek $fd2 [expr $iOffset - 5000] end
  82. fconfigure $fd2 -buffering none
  83. puts -nonewline $fd1 "123456"
  84. } {}
  85. do_test incrblob2-2.$iOffset.2 {
  86. read $fd2 6
  87. } {123456}
  88. do_test incrblob2-2.$iOffset.3 {
  89. close $fd1
  90. close $fd2
  91. } {}
  92. }
  93. do_test incrblob2-3.1 {
  94. set fd1 [db incrblob blobs data 1]
  95. fconfigure $fd1 -buffering none
  96. } {}
  97. do_test incrblob2-3.2 {
  98. execsql {
  99. INSERT INTO blobs VALUES(5, zeroblob(10240));
  100. }
  101. } {}
  102. do_test incrblob2-3.3 {
  103. set rc [catch { read $fd1 6 } msg]
  104. list $rc $msg
  105. } {0 123456}
  106. do_test incrblob2-3.4 {
  107. close $fd1
  108. } {}
  109. #--------------------------------------------------------------------------
  110. # The following tests - incrblob2-4.* - test that blob handles are
  111. # invalidated at the correct times.
  112. #
  113. do_test incrblob2-4.1 {
  114. unset -nocomplain data
  115. db eval BEGIN
  116. db eval { CREATE TABLE t1(id INTEGER PRIMARY KEY, data BLOB); }
  117. for {set ii 1} {$ii < 100} {incr ii} {
  118. set data [string repeat "blob$ii" 500]
  119. db eval { INSERT INTO t1 VALUES($ii, $data) }
  120. }
  121. db eval COMMIT
  122. } {}
  123. proc aborted_handles {} {
  124. global handles
  125. set aborted {}
  126. for {set ii 1} {$ii < 100} {incr ii} {
  127. set str "blob$ii"
  128. set nByte [string length $str]
  129. set iOffset [expr $nByte * $ii * 2]
  130. set rc [catch {sqlite3_blob_read $handles($ii) $iOffset $nByte} msg]
  131. if {$rc && $msg eq "SQLITE_ABORT"} {
  132. lappend aborted $ii
  133. } else {
  134. if {$rc || $msg ne $str} {
  135. error "blob $ii: $msg"
  136. }
  137. }
  138. }
  139. set aborted
  140. }
  141. do_test incrblob2-4.2 {
  142. for {set ii 1} {$ii < 100} {incr ii} {
  143. set handles($ii) [db incrblob t1 data $ii]
  144. }
  145. aborted_handles
  146. } {}
  147. # Update row 3. This should abort handle 3 but leave all others untouched.
  148. #
  149. do_test incrblob2-4.3 {
  150. db eval {UPDATE t1 SET data = data || '' WHERE id = 3}
  151. aborted_handles
  152. } {3}
  153. # Test that a write to handle 3 also returns SQLITE_ABORT.
  154. #
  155. do_test incrblob2-4.3.1 {
  156. set rc [catch {sqlite3_blob_write $::handles(3) 10 HELLO} msg]
  157. list $rc $msg
  158. } {1 SQLITE_ABORT}
  159. # Delete row 14. This should abort handle 6 but leave all others untouched.
  160. #
  161. do_test incrblob2-4.4 {
  162. db eval {DELETE FROM t1 WHERE id = 14}
  163. aborted_handles
  164. } {3 14}
  165. # Change the rowid of row 15 to 102. Should abort handle 15.
  166. #
  167. do_test incrblob2-4.5 {
  168. db eval {UPDATE t1 SET id = 102 WHERE id = 15}
  169. aborted_handles
  170. } {3 14 15}
  171. # Clobber row 92 using INSERT OR REPLACE.
  172. #
  173. do_test incrblob2-4.6 {
  174. db eval {INSERT OR REPLACE INTO t1 VALUES(92, zeroblob(1000))}
  175. aborted_handles
  176. } {3 14 15 92}
  177. # Clobber row 65 using UPDATE OR REPLACE on row 35. This should abort
  178. # handles 35 and 65.
  179. #
  180. do_test incrblob2-4.7 {
  181. db eval {UPDATE OR REPLACE t1 SET id = 65 WHERE id = 35}
  182. aborted_handles
  183. } {3 14 15 35 65 92}
  184. # Insert a couple of new rows. This should not invalidate any handles.
  185. #
  186. do_test incrblob2-4.9 {
  187. db eval {INSERT INTO t1 SELECT NULL, data FROM t1}
  188. aborted_handles
  189. } {3 14 15 35 65 92}
  190. # Delete all rows from 1 to 25. This should abort all handles up to 25.
  191. #
  192. do_test incrblob2-4.9 {
  193. db eval {DELETE FROM t1 WHERE id >=1 AND id <= 25}
  194. aborted_handles
  195. } {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 35 65 92}
  196. # Delete the whole table (this will use sqlite3BtreeClearTable()). All handles
  197. # should now be aborted.
  198. #
  199. do_test incrblob2-4.10 {
  200. db eval {DELETE FROM t1}
  201. aborted_handles
  202. } {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}
  203. do_test incrblob2-4.1.X {
  204. for {set ii 1} {$ii < 100} {incr ii} {
  205. close $handles($ii)
  206. }
  207. } {}
  208. #--------------------------------------------------------------------------
  209. # The following tests - incrblob2-5.* - test that in shared cache an open
  210. # blob handle counts as a read-lock on its table.
  211. #
  212. ifcapable shared_cache {
  213. db close
  214. set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
  215. do_test incrblob2-5.1 {
  216. sqlite3 db test.db
  217. sqlite3 db2 test.db
  218. execsql {
  219. INSERT INTO t1 VALUES(1, 'abcde');
  220. }
  221. } {}
  222. do_test incrblob2-5.2 {
  223. catchsql { INSERT INTO t1 VALUES(2, 'fghij') } db2
  224. } {0 {}}
  225. do_test incrblob2-5.3 {
  226. set blob [db incrblob t1 data 1]
  227. catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2
  228. } {1 {database table is locked}}
  229. do_test incrblob2-5.4 {
  230. close $blob
  231. execsql BEGIN db2
  232. catchsql { INSERT INTO t1 VALUES(4, 'pqrst') } db2
  233. } {0 {}}
  234. do_test incrblob2-5.5 {
  235. set rc [catch { db incrblob -readonly t1 data 1 } msg]
  236. list $rc $msg
  237. } {1 {database table is locked: t1}}
  238. do_test incrblob2-5.6 {
  239. execsql { PRAGMA read_uncommitted=1 }
  240. set blob [db incrblob -readonly t1 data 4]
  241. read $blob
  242. } {pqrst}
  243. do_test incrblob2-5.7 {
  244. catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2
  245. } {0 {}}
  246. do_test incrblob2-5.8 {
  247. close $blob
  248. } {}
  249. db2 close
  250. db close
  251. sqlite3_enable_shared_cache $::enable_shared_cache
  252. }
  253. #--------------------------------------------------------------------------
  254. # The following tests - incrblob2-6.* - test a specific scenario that might
  255. # be causing an error.
  256. #
  257. sqlite3 db test.db
  258. do_test incrblob2-6.1 {
  259. execsql {
  260. DELETE FROM t1;
  261. INSERT INTO t1 VALUES(1, zeroblob(100));
  262. }
  263. set rdHandle [db incrblob -readonly t1 data 1]
  264. set wrHandle [db incrblob t1 data 1]
  265. sqlite3_blob_read $rdHandle 0 100
  266. sqlite3_blob_write $wrHandle 0 ABCDEF
  267. close $wrHandle
  268. close $rdHandle
  269. } {}
  270. do_test incrblob2-6.2 {
  271. set rdHandle [db incrblob -readonly t1 data 1]
  272. sqlite3_blob_read $rdHandle 0 2
  273. } {AB}
  274. do_test incrblob2-6.3 {
  275. set wrHandle [db incrblob t1 data 1]
  276. sqlite3_blob_write $wrHandle 0 ZZZZZZZZZZ
  277. sqlite3_blob_read $rdHandle 2 4
  278. } {ZZZZ}
  279. do_test incrblob2-6.4 {
  280. close $wrHandle
  281. close $rdHandle
  282. } {}
  283. sqlite3_memory_highwater 1
  284. do_test incrblob2-7.1 {
  285. db eval {
  286. CREATE TABLE t2(B BLOB);
  287. INSERT INTO t2 VALUES(zeroblob(10 * 1024 * 1024));
  288. }
  289. expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}
  290. } {1}
  291. do_test incrblob2-7.2 {
  292. set h [db incrblob t2 B 1]
  293. expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}
  294. } {1}
  295. do_test incrblob2-7.3 {
  296. seek $h 0 end
  297. tell $h
  298. } [expr 10 * 1024 * 1024]
  299. do_test incrblob2-7.4 {
  300. expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}
  301. } {1}
  302. do_test incrblob2-7.5 {
  303. close $h
  304. } {}
  305. #---------------------------------------------------------------------------
  306. # The following tests, incrblob2-8.*, test that nothing terrible happens
  307. # when a statement transaction is rolled back while there are open
  308. # incremental-blob handles. At one point an assert() was failing when
  309. # this was attempted.
  310. #
  311. do_test incrblob2-8.1 {
  312. execsql BEGIN
  313. set h [db incrblob t2 B 1]
  314. set rc [catch {
  315. db eval {SELECT rowid FROM t2} { execsql "DROP TABLE t2" }
  316. } msg]
  317. list $rc $msg
  318. } {1 {database table is locked}}
  319. do_test incrblob2-8.2 {
  320. close $h
  321. execsql COMMIT
  322. } {}
  323. do_test incrblob2-8.3 {
  324. execsql {
  325. CREATE TABLE t3(a INTEGER UNIQUE, b TEXT);
  326. INSERT INTO t3 VALUES(1, 'aaaaaaaaaaaaaaaaaaaa');
  327. INSERT INTO t3 VALUES(2, 'bbbbbbbbbbbbbbbbbbbb');
  328. INSERT INTO t3 VALUES(3, 'cccccccccccccccccccc');
  329. INSERT INTO t3 VALUES(4, 'dddddddddddddddddddd');
  330. INSERT INTO t3 VALUES(5, 'eeeeeeeeeeeeeeeeeeee');
  331. }
  332. } {}
  333. do_test incrblob2-8.4 {
  334. execsql BEGIN
  335. set h [db incrblob t3 b 3]
  336. sqlite3_blob_read $h 0 20
  337. } {cccccccccccccccccccc}
  338. do_test incrblob2-8.5 {
  339. catchsql {UPDATE t3 SET a = 6 WHERE a > 3}
  340. } {1 {column a is not unique}}
  341. do_test incrblob2-8.6 {
  342. catchsql {UPDATE t3 SET a = 6 WHERE a > 3}
  343. } {1 {column a is not unique}}
  344. do_test incrblob2-8.7 {
  345. sqlite3_blob_read $h 0 20
  346. } {cccccccccccccccccccc}
  347. do_test incrblob2-8.8 {
  348. catchsql {UPDATE t3 SET a = 6 WHERE a = 3 OR a = 5}
  349. } {1 {column a is not unique}}
  350. do_test incrblob2-8.9 {
  351. set rc [catch {sqlite3_blob_read $h 0 20} msg]
  352. list $rc $msg
  353. } {1 SQLITE_ABORT}
  354. do_test incrblob2-8.X {
  355. close $h
  356. } {}
  357. finish_test