AryaWu/sqlite
0
1# 2008 June 92#3# The author disclaims copyright to this source code. In place of4# 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 single13# blob object.14#15# $Id: incrblob2.test,v 1.11 2009/06/29 06:00:37 danielk1977 Exp $16#17 18set testdir [file dirname $argv0]19source $testdir/tester.tcl20 21ifcapable {!autovacuum || !pragma || !incrblob} {22 finish_test23 return24}25 26do_test incrblob2-1.0 {27 execsql {28 CREATE TABLE blobs(id INTEGER PRIMARY KEY, data BLOB);29 INSERT INTO blobs VALUES(NULL, zeroblob(5000));30 INSERT INTO blobs VALUES(NULL, zeroblob(5000));31 INSERT INTO blobs VALUES(NULL, zeroblob(5000));32 INSERT INTO blobs VALUES(NULL, zeroblob(5000));33 }34} {}35 36foreach iOffset [list 0 256 4094] {37 do_test incrblob2-1.$iOffset.1 {38 set fd [db incrblob blobs data 1]39 puts $fd "[string repeat x $iOffset]SQLite version 3.6.0"40 close $fd41 } {}42 43 do_test incrblob2-1.$iOffset.2 {44 set fd1 [db incrblob blobs data 1]45 set fd2 [db incrblob blobs data 1]46 fconfigure $fd1 -buffering none47 fconfigure $fd2 -buffering none48 if {$iOffset != 0} {49 seek $fd2 $iOffset start50 seek $fd1 $iOffset start51 }52 read $fd1 653 } {SQLite}54 55 do_test incrblob2-1.$iOffset.3 {56 read $fd2 657 } {SQLite}58 59 do_test incrblob2-1.$iOffset.4 {60 seek $fd2 $iOffset start61 seek $fd1 $iOffset start62 puts -nonewline $fd2 "etiLQS"63 } {}64 65 66 do_test incrblob2-1.$iOffset.5 {67 seek $fd1 $iOffset start68 read $fd1 669 } {etiLQS}70 71 do_test incrblob2-1.$iOffset.6 {72 seek $fd2 $iOffset start73 read $fd2 674 } {etiLQS}75 76 do_test incrblob2-1.$iOffset.7 {77 seek $fd1 $iOffset start78 read $fd1 679 } {etiLQS}80 81 do_test incrblob2-1.$iOffset.8 {82 close $fd183 close $fd284 } {}85}86 87#--------------------------------------------------------------------------88 89foreach iOffset [list 0 256 4094] {90 91 do_test incrblob2-2.$iOffset.1 {92 set fd1 [db incrblob blobs data 1]93 seek $fd1 [expr $iOffset - 5000] end94 fconfigure $fd1 -buffering none95 96 set fd2 [db incrblob blobs data 1]97 seek $fd2 [expr $iOffset - 5000] end98 fconfigure $fd2 -buffering none99 100 puts -nonewline $fd1 "123456"101 } {}102 103 do_test incrblob2-2.$iOffset.2 {104 read $fd2 6105 } {123456}106 107 do_test incrblob2-2.$iOffset.3 {108 close $fd1109 close $fd2110 } {}111}112 113do_test incrblob2-3.1 {114 set fd1 [db incrblob blobs data 1]115 fconfigure $fd1 -buffering none116} {}117do_test incrblob2-3.2 {118 execsql {119 INSERT INTO blobs VALUES(5, zeroblob(10240));120 }121} {}122do_test incrblob2-3.3 {123 set rc [catch { read $fd1 6 } msg]124 list $rc $msg125} {0 123456}126do_test incrblob2-3.4 {127 close $fd1128} {}129 130#--------------------------------------------------------------------------131# The following tests - incrblob2-4.* - test that blob handles are 132# invalidated at the correct times.133#134do_test incrblob2-4.1 {135 unset -nocomplain data136 db eval BEGIN137 db eval { CREATE TABLE t1(id INTEGER PRIMARY KEY, data BLOB); }138 for {set ii 1} {$ii < 100} {incr ii} {139 set data [string repeat "blob$ii" 500]140 db eval { INSERT INTO t1 VALUES($ii, $data) }141 }142 db eval COMMIT143} {}144 145proc aborted_handles {} {146 global handles147 148 set aborted {}149 for {set ii 1} {$ii < 100} {incr ii} {150 set str "blob$ii"151 set nByte [string length $str]152 set iOffset [expr $nByte * $ii * 2]153 154 set rc [catch {sqlite3_blob_read $handles($ii) $iOffset $nByte} msg]155 if {$rc && $msg eq "SQLITE_ABORT"} {156 lappend aborted $ii157 } else {158 if {$rc || $msg ne $str} {159 error "blob $ii: $msg"160 }161 }162 }163 set aborted164}165 166do_test incrblob2-4.2 {167 for {set ii 1} {$ii < 100} {incr ii} {168 set handles($ii) [db incrblob t1 data $ii]169 }170 aborted_handles171} {}172 173# Update row 3. This should abort handle 3 but leave all others untouched.174#175do_test incrblob2-4.3 {176 db eval {UPDATE t1 SET data = data || '' WHERE id = 3}177 aborted_handles178} {3}179 180# Test that a write to handle 3 also returns SQLITE_ABORT.181#182do_test incrblob2-4.3.1 {183 set rc [catch {sqlite3_blob_write $::handles(3) 10 HELLO} msg]184 list $rc $msg185} {1 SQLITE_ABORT}186 187# Delete row 14. This should abort handle 6 but leave all others untouched.188#189do_test incrblob2-4.4 {190 db eval {DELETE FROM t1 WHERE id = 14}191 aborted_handles192} {3 14}193 194# Change the rowid of row 15 to 102. Should abort handle 15.195#196do_test incrblob2-4.5 {197 db eval {UPDATE t1 SET id = 102 WHERE id = 15}198 aborted_handles199} {3 14 15}200 201# Clobber row 92 using INSERT OR REPLACE.202#203do_test incrblob2-4.6 {204 db eval {INSERT OR REPLACE INTO t1 VALUES(92, zeroblob(1000))}205 aborted_handles206} {3 14 15 92}207 208# Clobber row 65 using UPDATE OR REPLACE on row 35. This should abort 209# handles 35 and 65.210#211do_test incrblob2-4.7 {212 db eval {UPDATE OR REPLACE t1 SET id = 65 WHERE id = 35}213 aborted_handles214} {3 14 15 35 65 92}215 216# Insert a couple of new rows. This should not invalidate any handles.217#218do_test incrblob2-4.9 {219 db eval {INSERT INTO t1 SELECT NULL, data FROM t1}220 aborted_handles221} {3 14 15 35 65 92}222 223# Delete all rows from 1 to 25. This should abort all handles up to 25.224#225do_test incrblob2-4.9 {226 db eval {DELETE FROM t1 WHERE id >=1 AND id <= 25}227 aborted_handles228} {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}229 230# Delete the whole table (this will use sqlite3BtreeClearTable()). All handles231# should now be aborted.232#233do_test incrblob2-4.10 {234 db eval {DELETE FROM t1}235 aborted_handles236} {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}237 238do_test incrblob2-4.1.X {239 for {set ii 1} {$ii < 100} {incr ii} {240 close $handles($ii) 241 }242} {}243 244#--------------------------------------------------------------------------245# The following tests - incrblob2-5.* - test that in shared cache an open246# blob handle counts as a read-lock on its table.247#248ifcapable shared_cache {249 db close250 set ::enable_shared_cache [sqlite3_enable_shared_cache 1]251 252 do_test incrblob2-5.1 {253 sqlite3 db test.db254 sqlite3 db2 test.db255 256 execsql {257 INSERT INTO t1 VALUES(1, 'abcde');258 }259 } {}260 261 do_test incrblob2-5.2 {262 catchsql { INSERT INTO t1 VALUES(2, 'fghij') } db2263 } {0 {}}264 265 do_test incrblob2-5.3 {266 set blob [db incrblob t1 data 1]267 catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2268 } {1 {database table is locked}}269 270 do_test incrblob2-5.4 {271 close $blob272 execsql BEGIN db2273 catchsql { INSERT INTO t1 VALUES(4, 'pqrst') } db2274 } {0 {}}275 276 do_test incrblob2-5.5 {277 set rc [catch { db incrblob -readonly t1 data 1 } msg]278 list $rc $msg279 } {1 {database table is locked: t1}}280 281 do_test incrblob2-5.6 {282 execsql { PRAGMA read_uncommitted=1 }283 set blob [db incrblob -readonly t1 data 4]284 read $blob285 } {pqrst}286 287 do_test incrblob2-5.7 {288 catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2289 } {0 {}}290 291 do_test incrblob2-5.8 {292 close $blob293 } {}294 295 db2 close296 db close297 sqlite3_enable_shared_cache $::enable_shared_cache298}299 300#--------------------------------------------------------------------------301# The following tests - incrblob2-6.* - test a specific scenario that might302# be causing an error.303#304sqlite3 db test.db305do_test incrblob2-6.1 {306 execsql {307 DELETE FROM t1;308 INSERT INTO t1 VALUES(1, zeroblob(100));309 }310 311 set rdHandle [db incrblob -readonly t1 data 1]312 set wrHandle [db incrblob t1 data 1]313 314 sqlite3_blob_read $rdHandle 0 100315 316 sqlite3_blob_write $wrHandle 0 ABCDEF317 318 close $wrHandle319 close $rdHandle320} {}321 322do_test incrblob2-6.2 {323 set rdHandle [db incrblob -readonly t1 data 1]324 sqlite3_blob_read $rdHandle 0 2325} {AB}326 327if {$::tcl_platform(pointerSize)>=8} {328 do_test incrblob2-6.2b {329 set rc [catch {330 # Prior to 2015-02-07, the following caused a segfault due to331 # integer overflow.332 sqlite3_blob_read $rdHandle 2147483647 2147483647333 } errmsg]334 if {[string match {out of memory in *test_blob.c} $errmsg]} {335 set errmsg SQLITE_ERROR336 }337 lappend rc $errmsg338 } {1 SQLITE_ERROR}339}340do_test incrblob2-6.2c {341 set rc [catch {342 # Prior to 2015-02-07, the following caused a segfault due to343 # integer overflow.344 sqlite3_blob_read $rdHandle 2147483647 100345 } errmsg]346 lappend rc $errmsg347} {1 SQLITE_ERROR}348 349do_test incrblob2-6.3 {350 set wrHandle [db incrblob t1 data 1]351 sqlite3_blob_write $wrHandle 0 ZZZZZZZZZZ352 sqlite3_blob_read $rdHandle 2 4353} {ZZZZ}354 355do_test incrblob2-6.3b {356 set rc [catch {357 # Prior to 2015-02-07, the following caused a segfault due to358 # integer overflow.359 sqlite3_blob_write $wrHandle 2147483647 YYYYYYYYYYYYYYYYYY360 } errmsg]361 lappend rc $errmsg362} {1 SQLITE_ERROR}363do_test incrblob2-6.3c {364 sqlite3_blob_read $rdHandle 2 4365} {ZZZZ}366 367 368do_test incrblob2-6.4 {369 close $wrHandle370 close $rdHandle371} {}372 373sqlite3_memory_highwater 1374do_test incrblob2-7.1 {375 db eval {376 CREATE TABLE t2(B BLOB);377 INSERT INTO t2 VALUES(zeroblob(10 * 1024 * 1024)); 378 }379 expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}380} {1}381 382do_test incrblob2-7.2 {383 set h [db incrblob t2 B 1]384 expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}385} {1}386 387do_test incrblob2-7.3 {388 seek $h 0 end389 tell $h390} [expr 10 * 1024 * 1024]391 392do_test incrblob2-7.4 {393 expr {[sqlite3_memory_highwater]<(5 * 1024 * 1024)}394} {1}395 396do_test incrblob2-7.5 {397 close $h398} {}399 400#---------------------------------------------------------------------------401# The following tests, incrblob2-8.*, test that nothing terrible happens402# when a statement transaction is rolled back while there are open 403# incremental-blob handles. At one point an assert() was failing when404# this was attempted.405#406do_test incrblob2-8.1 {407 execsql BEGIN408 set h [db incrblob t2 B 1]409 set rc [catch {410 db eval {SELECT rowid FROM t2} { execsql "DROP TABLE t2" }411 } msg] 412 list $rc $msg413} {1 {database table is locked}}414do_test incrblob2-8.2 {415 close $h416 execsql COMMIT417} {}418do_test incrblob2-8.3 {419 execsql {420 CREATE TABLE t3(a INTEGER UNIQUE, b TEXT);421 INSERT INTO t3 VALUES(1, 'aaaaaaaaaaaaaaaaaaaa');422 INSERT INTO t3 VALUES(2, 'bbbbbbbbbbbbbbbbbbbb');423 INSERT INTO t3 VALUES(3, 'cccccccccccccccccccc');424 INSERT INTO t3 VALUES(4, 'dddddddddddddddddddd');425 INSERT INTO t3 VALUES(5, 'eeeeeeeeeeeeeeeeeeee');426 }427} {}428do_test incrblob2-8.4 {429 execsql BEGIN430 set h [db incrblob t3 b 3]431 sqlite3_blob_read $h 0 20432} {cccccccccccccccccccc}433do_test incrblob2-8.5 {434 catchsql {UPDATE t3 SET a = 6 WHERE a > 3}435} {1 {UNIQUE constraint failed: t3.a}}436do_test incrblob2-8.6 {437 catchsql {UPDATE t3 SET a = 6 WHERE a > 3}438} {1 {UNIQUE constraint failed: t3.a}}439do_test incrblob2-8.7 {440 sqlite3_blob_read $h 0 20441} {cccccccccccccccccccc}442do_test incrblob2-8.8 {443 catchsql {UPDATE t3 SET a = 6 WHERE a = 3 OR a = 5}444} {1 {UNIQUE constraint failed: t3.a}}445do_test incrblob2-8.9 {446 set rc [catch {sqlite3_blob_read $h 0 20} msg]447 list $rc $msg448} {1 SQLITE_ABORT}449do_test incrblob2-8.X {450 close $h451} {}452 453finish_test454 