gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/e_walhook.test (about) 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}} 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-57445-43425 Note that the sqlite3_wal_autocheckpoint() 165 # interface and the wal_autocheckpoint pragma both invoke 166 # sqlite3_wal_hook() and will overwrite any prior sqlite3_wal_hook() 167 # 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