| OLD | NEW |
| 1 # 2007 May 1 | 1 # 2007 May 1 |
| 2 # | 2 # |
| 3 # The author disclaims copyright to this source code. In place of | 3 # The author disclaims copyright to this source code. In place of |
| 4 # a legal notice, here is a blessing: | 4 # a legal notice, here is a blessing: |
| 5 # | 5 # |
| 6 # May you do good and not evil. | 6 # May you do good and not evil. |
| 7 # May you find forgiveness for yourself and forgive others. | 7 # May you find forgiveness for yourself and forgive others. |
| 8 # May you share freely, never taking more than you give. | 8 # May you share freely, never taking more than you give. |
| 9 # | 9 # |
| 10 #*********************************************************************** | 10 #*********************************************************************** |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 113 |
| 114 foreach AutoVacuumMode [list 0 1] { | 114 foreach AutoVacuumMode [list 0 1] { |
| 115 | 115 |
| 116 if {$AutoVacuumMode>0} { | 116 if {$AutoVacuumMode>0} { |
| 117 ifcapable !autovacuum { | 117 ifcapable !autovacuum { |
| 118 break | 118 break |
| 119 } | 119 } |
| 120 } | 120 } |
| 121 | 121 |
| 122 db close | 122 db close |
| 123 file delete -force test.db test.db-journal | 123 forcedelete test.db test.db-journal |
| 124 | 124 |
| 125 sqlite3 db test.db | 125 sqlite3 db test.db |
| 126 execsql "PRAGMA mmap_size = 0" |
| 126 execsql "PRAGMA auto_vacuum = $AutoVacuumMode" | 127 execsql "PRAGMA auto_vacuum = $AutoVacuumMode" |
| 127 | 128 |
| 128 do_test incrblob-2.$AutoVacuumMode.1 { | 129 do_test incrblob-2.$AutoVacuumMode.1 { |
| 129 set ::str [string repeat abcdefghij 2900] | 130 set ::str [string repeat abcdefghij 2900] |
| 130 execsql { | 131 execsql { |
| 131 BEGIN; | 132 BEGIN; |
| 132 CREATE TABLE blobs(k PRIMARY KEY, v BLOB, i INTEGER); | 133 CREATE TABLE blobs(k PRIMARY KEY, v BLOB, i INTEGER); |
| 133 DELETE FROM blobs; | 134 DELETE FROM blobs; |
| 134 INSERT INTO blobs VALUES('one', $::str || randstr(500,500), 45); | 135 INSERT INTO blobs VALUES('one', $::str || randstr(500,500), 45); |
| 135 COMMIT; | 136 COMMIT; |
| 136 } | 137 } |
| 137 expr [file size test.db]/1024 | 138 expr [file size test.db]/1024 |
| 138 } [expr 31 + $AutoVacuumMode] | 139 } [expr 31 + $AutoVacuumMode] |
| 139 | 140 |
| 140 ifcapable autovacuum { | 141 ifcapable autovacuum { |
| 141 do_test incrblob-2.$AutoVacuumMode.2 { | 142 do_test incrblob-2.$AutoVacuumMode.2 { |
| 142 execsql { | 143 execsql { |
| 143 PRAGMA auto_vacuum; | 144 PRAGMA auto_vacuum; |
| 144 } | 145 } |
| 145 } $AutoVacuumMode | 146 } $AutoVacuumMode |
| 146 } | 147 } |
| 147 | 148 |
| 148 do_test incrblob-2.$AutoVacuumMode.3 { | 149 do_test incrblob-2.$AutoVacuumMode.3 { |
| 149 # Open and close the db to make sure the page cache is empty. | 150 # Open and close the db to make sure the page cache is empty. |
| 150 db close | 151 db close |
| 151 sqlite3 db test.db | 152 sqlite3 db test.db |
| 153 execsql "PRAGMA mmap_size = 0" |
| 152 | 154 |
| 153 # Read the last 20 bytes of the blob via a blob handle. | 155 # Read the last 20 bytes of the blob via a blob handle. |
| 154 set ::blob [db incrblob blobs v 1] | 156 set ::blob [db incrblob blobs v 1] |
| 155 seek $::blob -20 end | 157 seek $::blob -20 end |
| 156 set ::fragment [read $::blob] | 158 set ::fragment [read $::blob] |
| 157 close $::blob | 159 close $::blob |
| 158 | 160 |
| 159 # If the database is not in auto-vacuum mode, the whole of | 161 # If the database is not in auto-vacuum mode, the whole of |
| 160 # the overflow-chain must be scanned. In auto-vacuum mode, | 162 # the overflow-chain must be scanned. In auto-vacuum mode, |
| 161 # sqlite uses the ptrmap pages to avoid reading the other pages. | 163 # sqlite uses the ptrmap pages to avoid reading the other pages. |
| 162 # | 164 # |
| 163 nRead db | 165 nRead db |
| 164 } [expr $AutoVacuumMode ? 4 : 30] | 166 } [expr $AutoVacuumMode ? 4 : 30] |
| 165 | 167 |
| 166 do_test incrblob-2.$AutoVacuumMode.4 { | 168 do_test incrblob-2.$AutoVacuumMode.4 { |
| 167 string range [db one {SELECT v FROM blobs}] end-19 end | 169 string range [db one {SELECT v FROM blobs}] end-19 end |
| 168 } $::fragment | 170 } $::fragment |
| 169 | 171 |
| 170 do_test incrblob-2.$AutoVacuumMode.5 { | 172 do_test incrblob-2.$AutoVacuumMode.5 { |
| 171 # Open and close the db to make sure the page cache is empty. | 173 # Open and close the db to make sure the page cache is empty. |
| 172 db close | 174 db close |
| 173 sqlite3 db test.db | 175 sqlite3 db test.db |
| 176 execsql "PRAGMA mmap_size = 0" |
| 174 | 177 |
| 175 # Write the second-to-last 20 bytes of the blob via a blob handle. | 178 # Write the second-to-last 20 bytes of the blob via a blob handle. |
| 176 # | 179 # |
| 177 set ::blob [db incrblob blobs v 1] | 180 set ::blob [db incrblob blobs v 1] |
| 178 seek $::blob -40 end | 181 seek $::blob -40 end |
| 179 puts -nonewline $::blob "1234567890abcdefghij" | 182 puts -nonewline $::blob "1234567890abcdefghij" |
| 180 flush $::blob | 183 flush $::blob |
| 181 | 184 |
| 182 # If the database is not in auto-vacuum mode, the whole of | 185 # If the database is not in auto-vacuum mode, the whole of |
| 183 # the overflow-chain must be scanned. In auto-vacuum mode, | 186 # the overflow-chain must be scanned. In auto-vacuum mode, |
| 184 # sqlite uses the ptrmap pages to avoid reading the other pages. | 187 # sqlite uses the ptrmap pages to avoid reading the other pages. |
| 185 # | 188 # |
| 186 nRead db | 189 nRead db |
| 187 } [expr $AutoVacuumMode ? 4 : 30] | 190 } [expr $AutoVacuumMode ? 4 : 30] |
| 188 | 191 |
| 189 # Pages 1 (the write-counter) and 32 (the blob data) were written. | 192 # Pages 1 (the write-counter) and 32 (the blob data) were written. |
| 190 do_test incrblob-2.$AutoVacuumMode.6 { | 193 do_test incrblob-2.$AutoVacuumMode.6 { |
| 191 close $::blob | 194 close $::blob |
| 192 nWrite db | 195 nWrite db |
| 193 } 2 | 196 } 2 |
| 194 | 197 |
| 195 do_test incrblob-2.$AutoVacuumMode.7 { | 198 do_test incrblob-2.$AutoVacuumMode.7 { |
| 196 string range [db one {SELECT v FROM blobs}] end-39 end-20 | 199 string range [db one {SELECT v FROM blobs}] end-39 end-20 |
| 197 } "1234567890abcdefghij" | 200 } "1234567890abcdefghij" |
| 198 | 201 |
| 199 do_test incrblob-2.$AutoVacuumMode.8 { | 202 do_test incrblob-2.$AutoVacuumMode.8 { |
| 200 # Open and close the db to make sure the page cache is empty. | 203 # Open and close the db to make sure the page cache is empty. |
| 201 db close | 204 db close |
| 202 sqlite3 db test.db | 205 sqlite3 db test.db |
| 206 execsql { PRAGMA mmap_size = 0 } |
| 203 | 207 |
| 204 execsql { SELECT i FROM blobs } | 208 execsql { SELECT i FROM blobs } |
| 205 } {45} | 209 } {45} |
| 206 | 210 |
| 207 do_test incrblob-2.$AutoVacuumMode.9 { | 211 do_test incrblob-2.$AutoVacuumMode.9 { |
| 208 nRead db | 212 nRead db |
| 209 } [expr $AutoVacuumMode ? 4 : 30] | 213 } [expr $AutoVacuumMode ? 4 : 30] |
| 210 } | 214 } |
| 211 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) | 215 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) |
| 212 | 216 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 } | 376 } |
| 373 | 377 |
| 374 | 378 |
| 375 #------------------------------------------------------------------------ | 379 #------------------------------------------------------------------------ |
| 376 # incrblob-5.*: | 380 # incrblob-5.*: |
| 377 # | 381 # |
| 378 # Test that opening a blob in an attached database works. | 382 # Test that opening a blob in an attached database works. |
| 379 # | 383 # |
| 380 ifcapable attach { | 384 ifcapable attach { |
| 381 do_test incrblob-5.1 { | 385 do_test incrblob-5.1 { |
| 382 file delete -force test2.db test2.db-journal | 386 forcedelete test2.db test2.db-journal |
| 383 set ::size [expr [file size [info script]]] | 387 set ::size [expr [file size [info script]]] |
| 384 execsql { | 388 execsql { |
| 385 ATTACH 'test2.db' AS aux; | 389 ATTACH 'test2.db' AS aux; |
| 386 CREATE TABLE aux.files(name, text); | 390 CREATE TABLE aux.files(name, text); |
| 387 INSERT INTO aux.files VALUES('this one', zeroblob($::size)); | 391 INSERT INTO aux.files VALUES('this one', zeroblob($::size)); |
| 388 } | 392 } |
| 389 set fd [db incrblob aux files text 1] | 393 set fd [db incrblob aux files text 1] |
| 390 fconfigure $fd -translation binary | 394 fconfigure $fd -translation binary |
| 391 set fd2 [open [info script]] | 395 set fd2 [open [info script]] |
| 392 fconfigure $fd2 -translation binary | 396 fconfigure $fd2 -translation binary |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 if {[permutation] != "memsubsys1"} { | 434 if {[permutation] != "memsubsys1"} { |
| 431 do_test incrblob-6.1 { | 435 do_test incrblob-6.1 { |
| 432 sqlite3 db2 test.db | 436 sqlite3 db2 test.db |
| 433 execsql { | 437 execsql { |
| 434 BEGIN; | 438 BEGIN; |
| 435 INSERT INTO blobs(k, v, i) VALUES('a', 'different', 'connection'); | 439 INSERT INTO blobs(k, v, i) VALUES('a', 'different', 'connection'); |
| 436 } db2 | 440 } db2 |
| 437 } {} | 441 } {} |
| 438 do_test incrblob-6.2 { | 442 do_test incrblob-6.2 { |
| 439 execsql { | 443 execsql { |
| 440 SELECT rowid FROM blobs | 444 SELECT rowid FROM blobs ORDER BY rowid |
| 441 } | 445 } |
| 442 } {1 2 3} | 446 } {1 2 3} |
| 443 do_test incrblob-6.3 { | 447 do_test incrblob-6.3 { |
| 444 set rc [catch { | 448 set rc [catch { |
| 445 db incrblob blobs v 1 | 449 db incrblob blobs v 1 |
| 446 } msg] | 450 } msg] |
| 447 list $rc $msg | 451 list $rc $msg |
| 448 } {1 {database is locked}} | 452 } {1 {database is locked}} |
| 449 do_test incrblob-6.4 { | 453 do_test incrblob-6.4 { |
| 450 set rc [catch { | 454 set rc [catch { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 466 } {connection} | 470 } {connection} |
| 467 do_test incrblob-6.8 { | 471 do_test incrblob-6.8 { |
| 468 tell $::blob | 472 tell $::blob |
| 469 } {10} | 473 } {10} |
| 470 do_test incrblob-6.9 { | 474 do_test incrblob-6.9 { |
| 471 seek $::blob 0 | 475 seek $::blob 0 |
| 472 puts -nonewline $::blob "invocation" | 476 puts -nonewline $::blob "invocation" |
| 473 flush $::blob | 477 flush $::blob |
| 474 } {} | 478 } {} |
| 475 | 479 |
| 476 # At this point rollback should be illegal (because | 480 # At this point commit should be illegal (because |
| 477 # there is an open blob channel). But commit is also illegal because | 481 # there is an open blob channel). |
| 478 # the open blob is read-write. | |
| 479 # | 482 # |
| 480 do_test incrblob-6.10 { | |
| 481 catchsql { | |
| 482 ROLLBACK; | |
| 483 } db2 | |
| 484 } {1 {cannot rollback transaction - SQL statements in progress}} | |
| 485 do_test incrblob-6.11 { | 483 do_test incrblob-6.11 { |
| 486 catchsql { | 484 catchsql { |
| 487 COMMIT; | 485 COMMIT; |
| 488 } db2 | 486 } db2 |
| 489 } {1 {cannot commit transaction - SQL statements in progress}} | 487 } {1 {cannot commit transaction - SQL statements in progress}} |
| 490 | 488 |
| 491 do_test incrblob-6.12 { | 489 do_test incrblob-6.12 { |
| 492 execsql { | 490 execsql { |
| 493 SELECT * FROM blobs WHERE rowid = 4; | 491 SELECT * FROM blobs WHERE rowid = 4; |
| 494 } | 492 } |
| 495 } {} | 493 } {} |
| 496 do_test incrblob-6.13 { | 494 do_test incrblob-6.13 { |
| 497 close $::blob | 495 close $::blob |
| 498 } {} | 496 } {} |
| 499 do_test incrblob-6.14 { | 497 do_test incrblob-6.14 { |
| 500 catchsql { | 498 catchsql { |
| 501 COMMIT; | 499 COMMIT; |
| 502 } db2 | 500 } db2 |
| 503 } {0 {}} | 501 } {0 {}} |
| 504 do_test incrblob-6.15 { | 502 do_test incrblob-6.15 { |
| 505 execsql { | 503 execsql { |
| 506 SELECT * FROM blobs WHERE rowid = 4; | 504 SELECT * FROM blobs WHERE rowid = 4; |
| 507 } | 505 } |
| 508 } {a different invocation} | 506 } {a different invocation} |
| 509 db2 close | 507 db2 close |
| 510 } | 508 } |
| 511 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) | 509 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) |
| 512 | 510 |
| 513 #----------------------------------------------------------------------- | 511 #----------------------------------------------------------------------- |
| 514 # The following tests verify the behaviour of the incremental IO | 512 # The following tests verify the behavior of the incremental IO |
| 515 # APIs in the following cases: | 513 # APIs in the following cases: |
| 516 # | 514 # |
| 517 # 7.1 A row that containing an open blob is modified. | 515 # 7.1 A row that containing an open blob is modified. |
| 518 # | 516 # |
| 519 # 7.2 A CREATE TABLE requires that an overflow page that is part | 517 # 7.2 A CREATE TABLE requires that an overflow page that is part |
| 520 # of an open blob is moved. | 518 # of an open blob is moved. |
| 521 # | 519 # |
| 522 # 7.3 An INCREMENTAL VACUUM moves an overflow page that is part | 520 # 7.3 An INCREMENTAL VACUUM moves an overflow page that is part |
| 523 # of an open blob. | 521 # of an open blob. |
| 524 # | 522 # |
| 525 # In the first case above, correct behaviour is for all subsequent | 523 # In the first case above, correct behavior is for all subsequent |
| 526 # read/write operations on the blob-handle to return SQLITE_ABORT. | 524 # read/write operations on the blob-handle to return SQLITE_ABORT. |
| 527 # More accurately, blob-handles are invalidated whenever the table | 525 # More accurately, blob-handles are invalidated whenever the table |
| 528 # they belong to is written to. | 526 # they belong to is written to. |
| 529 # | 527 # |
| 530 # The second two cases have no external effect. They are testing | 528 # The second two cases have no external effect. They are testing |
| 531 # that the internal cache of overflow page numbers is correctly | 529 # that the internal cache of overflow page numbers is correctly |
| 532 # invalidated. | 530 # invalidated. |
| 533 # | 531 # |
| 534 do_test incrblob-7.1.0 { | 532 do_test incrblob-7.1.0 { |
| 535 execsql { | 533 execsql { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 } {15} | 575 } {15} |
| 578 | 576 |
| 579 } | 577 } |
| 580 | 578 |
| 581 set fd [open [info script]] | 579 set fd [open [info script]] |
| 582 fconfigure $fd -translation binary | 580 fconfigure $fd -translation binary |
| 583 set ::data [read $fd 14000] | 581 set ::data [read $fd 14000] |
| 584 close $fd | 582 close $fd |
| 585 | 583 |
| 586 db close | 584 db close |
| 587 file delete -force test.db test.db-journal | 585 forcedelete test.db test.db-journal |
| 588 sqlite3 db test.db | 586 sqlite3 db test.db |
| 589 | 587 |
| 590 do_test incrblob-7.2.1 { | 588 do_test incrblob-7.2.1 { |
| 591 execsql { | 589 execsql { |
| 592 PRAGMA auto_vacuum = "incremental"; | 590 PRAGMA auto_vacuum = "incremental"; |
| 593 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); -- root@page3 | 591 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); -- root@page3 |
| 594 INSERT INTO t1 VALUES(123, $::data); | 592 INSERT INTO t1 VALUES(123, $::data); |
| 595 } | 593 } |
| 596 set ::b [db incrblob -readonly t1 b 123] | 594 set ::b [db incrblob -readonly t1 b 123] |
| 597 fconfigure $::b -translation binary | 595 fconfigure $::b -translation binary |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 # an error message was set using a call similar to sqlite3_mprintf(zErr), | 679 # an error message was set using a call similar to sqlite3_mprintf(zErr), |
| 682 # where zErr is an arbitrary string. This is no good if the string contains | 680 # where zErr is an arbitrary string. This is no good if the string contains |
| 683 # characters that can be mistaken for printf() formatting directives. | 681 # characters that can be mistaken for printf() formatting directives. |
| 684 # | 682 # |
| 685 do_test incrblob-9.1 { | 683 do_test incrblob-9.1 { |
| 686 list [catch { db incrblob t1 "A tricky column name %s%s" 1 } msg] $msg | 684 list [catch { db incrblob t1 "A tricky column name %s%s" 1 } msg] $msg |
| 687 } {1 {no such column: "A tricky column name %s%s"}} | 685 } {1 {no such column: "A tricky column name %s%s"}} |
| 688 | 686 |
| 689 | 687 |
| 690 finish_test | 688 finish_test |
| OLD | NEW |