| OLD | NEW |
| (Empty) |
| 1 # 2014 December 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 # | |
| 12 | |
| 13 set testdir [file dirname $argv0] | |
| 14 source $testdir/tester.tcl | |
| 15 source $testdir/wal_common.tcl | |
| 16 set testprefix e_walhook | |
| 17 | |
| 18 | |
| 19 # EVIDENCE-OF: R-00752-43975 The sqlite3_wal_hook() function is used to | |
| 20 # register a callback that is invoked each time data is committed to a | |
| 21 # database in wal mode. | |
| 22 # | |
| 23 # 1.1: shows that the wal-hook is not invoked in rollback mode. | |
| 24 # 1.2: but is invoked in wal mode. | |
| 25 # | |
| 26 set ::wal_hook_count 0 | |
| 27 proc my_wal_hook {args} { | |
| 28 incr ::wal_hook_count | |
| 29 return 0 | |
| 30 } | |
| 31 | |
| 32 do_test 1.1.1 { | |
| 33 db wal_hook my_wal_hook | |
| 34 execsql { | |
| 35 CREATE TABLE t1(x); | |
| 36 INSERT INTO t1 VALUES(1); | |
| 37 } | |
| 38 set ::wal_hook_count | |
| 39 } 0 | |
| 40 do_test 1.1.2 { | |
| 41 execsql { PRAGMA journal_mode = wal } | |
| 42 set ::wal_hook_count | |
| 43 } 0 | |
| 44 | |
| 45 do_test 1.3 { | |
| 46 execsql { INSERT INTO t1 VALUES(2) } | |
| 47 set wal_hook_count | |
| 48 } 1 | |
| 49 | |
| 50 do_test 1.4 { | |
| 51 execsql { | |
| 52 BEGIN; | |
| 53 INSERT INTO t1 VALUES(3); | |
| 54 INSERT INTO t1 VALUES(4); | |
| 55 COMMIT; | |
| 56 } | |
| 57 set wal_hook_count | |
| 58 } 2 | |
| 59 | |
| 60 # EVIDENCE-OF: R-65366-15139 The callback is invoked by SQLite after the | |
| 61 # commit has taken place and the associated write-lock on the database | |
| 62 # released | |
| 63 # | |
| 64 set ::read_ok 0 | |
| 65 proc my_wal_hook {args} { | |
| 66 sqlite3 db2 test.db | |
| 67 if {[db2 eval { SELECT * FROM t1 }] == "1 2 3 4 5"} { | |
| 68 set ::read_ok 1 | |
| 69 } | |
| 70 db2 close | |
| 71 } | |
| 72 do_test 2.1 { | |
| 73 execsql { INSERT INTO t1 VALUES(5) } | |
| 74 set ::read_ok | |
| 75 } 1 | |
| 76 | |
| 77 # EVIDENCE-OF: R-44294-52863 The third parameter is the name of the | |
| 78 # database that was written to - either "main" or the name of an | |
| 79 # ATTACH-ed database. | |
| 80 # | |
| 81 # EVIDENCE-OF: R-18913-19355 The fourth parameter is the number of pages | |
| 82 # currently in the write-ahead log file, including those that were just | |
| 83 # committed. | |
| 84 # | |
| 85 set ::wal_hook_args [list] | |
| 86 proc my_wal_hook {dbname nEntry} { | |
| 87 set ::wal_hook_args [list $dbname $nEntry] | |
| 88 } | |
| 89 forcedelete test.db2 | |
| 90 do_test 3.0 { | |
| 91 execsql { | |
| 92 ATTACH 'test.db2' AS aux; | |
| 93 CREATE TABLE aux.t2(x); | |
| 94 PRAGMA aux.journal_mode = wal; | |
| 95 } | |
| 96 } {wal} | |
| 97 | |
| 98 # Database "aux" | |
| 99 do_test 3.1.1 { | |
| 100 set wal_hook_args [list] | |
| 101 execsql { INSERT INTO t2 VALUES('a') } | |
| 102 } {} | |
| 103 do_test 3.1.2 { | |
| 104 set wal_hook_args | |
| 105 } [list aux [wal_frame_count test.db2-wal 1024]] | |
| 106 | |
| 107 # Database "main" | |
| 108 do_test 3.2.1 { | |
| 109 set wal_hook_args [list] | |
| 110 execsql { INSERT INTO t1 VALUES(6) } | |
| 111 } {} | |
| 112 do_test 3.1.2 { | |
| 113 set wal_hook_args | |
| 114 } [list main [wal_frame_count test.db-wal 1024]] | |
| 115 | |
| 116 # EVIDENCE-OF: R-14034-00929 If an error code is returned, that error | |
| 117 # will propagate back up through the SQLite code base to cause the | |
| 118 # statement that provoked the callback to report an error, though the | |
| 119 # commit will have still occurred. | |
| 120 # | |
| 121 proc my_wal_hook {args} { return 1 ;# SQLITE_ERROR } | |
| 122 do_catchsql_test 4.1 { | |
| 123 INSERT INTO t1 VALUES(7) | |
| 124 } {1 {SQL logic error or missing database}} | |
| 125 | |
| 126 proc my_wal_hook {args} { return 5 ;# SQLITE_BUSY } | |
| 127 do_catchsql_test 4.2 { | |
| 128 INSERT INTO t1 VALUES(8) | |
| 129 } {1 {database is locked}} | |
| 130 | |
| 131 proc my_wal_hook {args} { return 14 ;# SQLITE_CANTOPEN } | |
| 132 do_catchsql_test 4.3 { | |
| 133 INSERT INTO t1 VALUES(9) | |
| 134 } {1 {unable to open database file}} | |
| 135 | |
| 136 do_execsql_test 4.4 { | |
| 137 SELECT * FROM t1 | |
| 138 } {1 2 3 4 5 6 7 8 9} | |
| 139 | |
| 140 # EVIDENCE-OF: R-10466-53920 Calling sqlite3_wal_hook() replaces any | |
| 141 # previously registered write-ahead log callback. | |
| 142 set ::old_wal_hook 0 | |
| 143 proc my_old_wal_hook {args} { | |
| 144 incr ::old_wal_hook | |
| 145 return 0 | |
| 146 } | |
| 147 db wal_hook my_old_wal_hook | |
| 148 do_test 5.1 { | |
| 149 execsql { INSERT INTO t1 VALUES(10) } | |
| 150 set ::old_wal_hook | |
| 151 } {1} | |
| 152 | |
| 153 # Replace old_wal_hook. Observe that it is not invoked after it has | |
| 154 # been replaced. | |
| 155 proc my_new_wal_hook {args} { return 0 } | |
| 156 db wal_hook my_new_wal_hook | |
| 157 do_test 5.2 { | |
| 158 execsql { INSERT INTO t1 VALUES(11) } | |
| 159 set ::old_wal_hook | |
| 160 } {1} | |
| 161 | |
| 162 | |
| 163 | |
| 164 # EVIDENCE-OF: R-42842-27162 Note that the sqlite3_wal_autocheckpoint() | |
| 165 # interface and the wal_autocheckpoint pragma both invoke | |
| 166 # sqlite3_wal_hook() and will those overwrite any prior | |
| 167 # sqlite3_wal_hook() settings. | |
| 168 # | |
| 169 set ::old_wal_hook 0 | |
| 170 proc my_old_wal_hook {args} { incr ::old_wal_hook ; return 0 } | |
| 171 db wal_hook my_old_wal_hook | |
| 172 do_test 6.1.1 { | |
| 173 execsql { INSERT INTO t1 VALUES(12) } | |
| 174 set ::old_wal_hook | |
| 175 } {1} | |
| 176 do_test 6.1.2 { | |
| 177 execsql { PRAGMA wal_autocheckpoint = 1000 } | |
| 178 execsql { INSERT INTO t1 VALUES(12) } | |
| 179 set ::old_wal_hook | |
| 180 } {1} | |
| 181 | |
| 182 # EVIDENCE-OF: R-52629-38967 The first parameter passed to the callback | |
| 183 # function when it is invoked is a copy of the third parameter passed to | |
| 184 # sqlite3_wal_hook() when registering the callback. | |
| 185 # | |
| 186 # This is tricky to test using the tcl interface. However, the | |
| 187 # mechanism used to invoke the tcl script registered as a wal-hook | |
| 188 # depends on the context pointer being correctly passed through. And | |
| 189 # since multiple different wal-hook scripts have been successfully | |
| 190 # invoked by this test script, consider this tested. | |
| 191 # | |
| 192 # EVIDENCE-OF: R-23378-42536 The second is a copy of the database | |
| 193 # handle. | |
| 194 # | |
| 195 # There is an assert() in the C wal-hook used by tclsqlite.c to | |
| 196 # prove this. And that hook has been invoked multiple times when | |
| 197 # running this script. So consider this requirement tested as well. | |
| 198 # | |
| 199 | |
| 200 finish_test | |
| OLD | NEW |