| OLD | NEW |
| 1 # 2004 Jan 14 | 1 # 2004 Jan 14 |
| 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 do_test hook-3.6 { | 67 do_test hook-3.6 { |
| 68 set commit_cnt {} | 68 set commit_cnt {} |
| 69 proc commit_hook {} { | 69 proc commit_hook {} { |
| 70 set ::commit_cnt [execsql {SELECT * FROM t2}] | 70 set ::commit_cnt [execsql {SELECT * FROM t2}] |
| 71 return 1 | 71 return 1 |
| 72 } | 72 } |
| 73 catchsql { | 73 catchsql { |
| 74 INSERT INTO t2 VALUES(6,7); | 74 INSERT INTO t2 VALUES(6,7); |
| 75 } | 75 } |
| 76 } {1 {constraint failed}} | 76 } {1 {constraint failed}} |
| 77 verify_ex_errcode hook-3.6b SQLITE_CONSTRAINT_COMMITHOOK |
| 77 do_test hook-3.7 { | 78 do_test hook-3.7 { |
| 78 set ::commit_cnt | 79 set ::commit_cnt |
| 79 } {1 2 2 3 3 4 4 5 5 6 6 7} | 80 } {1 2 2 3 3 4 4 5 5 6 6 7} |
| 80 do_test hook-3.8 { | 81 do_test hook-3.8 { |
| 81 execsql {SELECT * FROM t2} | 82 execsql {SELECT * FROM t2} |
| 82 } {1 2 2 3 3 4 4 5 5 6} | 83 } {1 2 2 3 3 4 4 5 5 6} |
| 83 | 84 |
| 84 # Test turnning off the commit hook | 85 # Test turnning off the commit hook |
| 85 # | 86 # |
| 86 do_test hook-3.9 { | 87 do_test hook-3.9 { |
| 87 db commit_hook {} | 88 db commit_hook {} |
| 88 set ::commit_cnt {} | 89 set ::commit_cnt {} |
| 89 execsql { | 90 execsql { |
| 90 INSERT INTO t2 VALUES(7,8); | 91 INSERT INTO t2 VALUES(7,8); |
| 91 } | 92 } |
| 92 set ::commit_cnt | 93 set ::commit_cnt |
| 93 } {} | 94 } {} |
| 94 | 95 |
| 95 # Ticket #3564. | 96 # Ticket #3564. |
| 96 # | 97 # |
| 97 do_test hook-3.10 { | 98 do_test hook-3.10 { |
| 98 file delete -force test2.db test2.db-journal | 99 forcedelete test2.db test2.db-journal |
| 99 sqlite3 db2 test2.db | 100 sqlite3 db2 test2.db |
| 100 proc commit_hook {} { | 101 proc commit_hook {} { |
| 101 set y [db2 one {SELECT y FROM t3 WHERE y>10}] | 102 set y [db2 one {SELECT y FROM t3 WHERE y>10}] |
| 102 return [expr {$y>10}] | 103 return [expr {$y>10}] |
| 103 } | 104 } |
| 104 db2 eval {CREATE TABLE t3(x,y)} | 105 db2 eval {CREATE TABLE t3(x,y)} |
| 105 db2 commit_hook commit_hook | 106 db2 commit_hook commit_hook |
| 106 catchsql {INSERT INTO t3 VALUES(1,2)} db2 | 107 catchsql {INSERT INTO t3 VALUES(1,2)} db2 |
| 107 catchsql {INSERT INTO t3 VALUES(11,12)} db2 | 108 catchsql {INSERT INTO t3 VALUES(11,12)} db2 |
| 108 catchsql {INSERT INTO t3 VALUES(3,4)} db2 | 109 catchsql {INSERT INTO t3 VALUES(3,4)} db2 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 119 # 4.1.* - Very simple tests. Test that the update hook is invoked correctly | 120 # 4.1.* - Very simple tests. Test that the update hook is invoked correctly |
| 120 # for INSERT, DELETE and UPDATE statements, including DELETE | 121 # for INSERT, DELETE and UPDATE statements, including DELETE |
| 121 # statements with no WHERE clause. | 122 # statements with no WHERE clause. |
| 122 # 4.2.* - Check that the update-hook is invoked for rows modified by trigger | 123 # 4.2.* - Check that the update-hook is invoked for rows modified by trigger |
| 123 # bodies. Also that the database name is correctly reported when | 124 # bodies. Also that the database name is correctly reported when |
| 124 # an attached database is modified. | 125 # an attached database is modified. |
| 125 # 4.3.* - Do some sorting, grouping, compound queries, population and | 126 # 4.3.* - Do some sorting, grouping, compound queries, population and |
| 126 # depopulation of indices, to make sure the update-hook is not | 127 # depopulation of indices, to make sure the update-hook is not |
| 127 # invoked incorrectly. | 128 # invoked incorrectly. |
| 128 # | 129 # |
| 130 # EVIDENCE-OF: R-21999-45122 The sqlite3_update_hook() interface |
| 131 # registers a callback function with the database connection identified |
| 132 # by the first argument to be invoked whenever a row is updated, |
| 133 # inserted or deleted in a rowid table. |
| 129 | 134 |
| 130 # Simple tests | 135 # Simple tests |
| 131 do_test hook-4.1.1 { | 136 do_test hook-4.1.1a { |
| 132 catchsql { | 137 catchsql { |
| 133 DROP TABLE t1; | 138 DROP TABLE t1; |
| 134 } | 139 } |
| 140 unset -nocomplain ::update_hook |
| 141 set ::update_hook {} |
| 142 db update_hook [list lappend ::update_hook] |
| 143 # |
| 144 # EVIDENCE-OF: R-52223-27275 The update hook is not invoked when |
| 145 # internal system tables are modified (i.e. sqlite_master and |
| 146 # sqlite_sequence). |
| 147 # |
| 135 execsql { | 148 execsql { |
| 136 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); | 149 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); |
| 150 CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID; |
| 151 } |
| 152 set ::update_hook |
| 153 } {} |
| 154 do_test hook-4.1.1b { |
| 155 execsql { |
| 137 INSERT INTO t1 VALUES(1, 'one'); | 156 INSERT INTO t1 VALUES(1, 'one'); |
| 138 INSERT INTO t1 VALUES(2, 'two'); | 157 INSERT INTO t1 VALUES(2, 'two'); |
| 139 INSERT INTO t1 VALUES(3, 'three'); | 158 INSERT INTO t1 VALUES(3, 'three'); |
| 159 INSERT INTO t1w SELECT * FROM t1; |
| 140 } | 160 } |
| 141 db update_hook [list lappend ::update_hook] | |
| 142 } {} | 161 } {} |
| 162 |
| 163 # EVIDENCE-OF: R-15506-57666 The second callback argument is one of |
| 164 # SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE, depending on the |
| 165 # operation that caused the callback to be invoked. |
| 166 # |
| 167 # EVIDENCE-OF: R-29213-61195 The third and fourth arguments to the |
| 168 # callback contain pointers to the database and table name containing |
| 169 # the affected row. |
| 170 # |
| 171 # EVIDENCE-OF: R-30809-57812 The final callback parameter is the rowid |
| 172 # of the row. |
| 173 # |
| 143 do_test hook-4.1.2 { | 174 do_test hook-4.1.2 { |
| 175 set ::update_hook {} |
| 144 execsql { | 176 execsql { |
| 145 INSERT INTO t1 VALUES(4, 'four'); | 177 INSERT INTO t1 VALUES(4, 'four'); |
| 146 DELETE FROM t1 WHERE b = 'two'; | 178 DELETE FROM t1 WHERE b = 'two'; |
| 147 UPDATE t1 SET b = '' WHERE a = 1 OR a = 3; | 179 UPDATE t1 SET b = '' WHERE a = 1 OR a = 3; |
| 148 DELETE FROM t1 WHERE 1; -- Avoid the truncate optimization (for now) | 180 DELETE FROM t1 WHERE 1; -- Avoid the truncate optimization (for now) |
| 149 } | 181 } |
| 150 set ::update_hook | 182 set ::update_hook |
| 151 } [list \ | 183 } [list \ |
| 152 INSERT main t1 4 \ | 184 INSERT main t1 4 \ |
| 153 DELETE main t1 2 \ | 185 DELETE main t1 2 \ |
| 154 UPDATE main t1 1 \ | 186 UPDATE main t1 1 \ |
| 155 UPDATE main t1 3 \ | 187 UPDATE main t1 3 \ |
| 156 DELETE main t1 1 \ | 188 DELETE main t1 1 \ |
| 157 DELETE main t1 3 \ | 189 DELETE main t1 3 \ |
| 158 DELETE main t1 4 \ | 190 DELETE main t1 4 \ |
| 159 ] | 191 ] |
| 160 | 192 |
| 193 # EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does |
| 194 # not fire callbacks for changes to a WITHOUT ROWID table. |
| 195 # |
| 196 # EVIDENCE-OF: R-33257-44249 The update hook is not invoked when WITHOUT |
| 197 # ROWID tables are modified. |
| 198 # |
| 199 do_test hook-4.1.2w { |
| 200 set ::update_hook {} |
| 201 execsql { |
| 202 INSERT INTO t1w VALUES(4, 'four'); |
| 203 DELETE FROM t1w WHERE b = 'two'; |
| 204 UPDATE t1w SET b = '' WHERE a = 1 OR a = 3; |
| 205 DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now) |
| 206 } |
| 207 set ::update_hook |
| 208 } {} |
| 209 |
| 161 ifcapable trigger { | 210 ifcapable trigger { |
| 162 # Update hook is not invoked for changes to sqlite_master | 211 # Update hook is not invoked for changes to sqlite_master |
| 163 # | 212 # |
| 164 do_test hook-4.1.3 { | 213 do_test hook-4.1.3 { |
| 165 set ::update_hook {} | 214 set ::update_hook {} |
| 166 execsql { | 215 execsql { |
| 167 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT RAISE(IGNORE); END; | 216 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT RAISE(IGNORE); END; |
| 168 } | 217 } |
| 169 set ::update_hook | 218 set ::update_hook |
| 170 } {} | 219 } {} |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 execsql { | 259 execsql { |
| 211 INSERT INTO t1 VALUES(1, 'one'); | 260 INSERT INTO t1 VALUES(1, 'one'); |
| 212 INSERT INTO t1 VALUES(2, 'two'); | 261 INSERT INTO t1 VALUES(2, 'two'); |
| 213 } | 262 } |
| 214 } | 263 } |
| 215 | 264 |
| 216 # Update-hook + ATTACH | 265 # Update-hook + ATTACH |
| 217 set ::update_hook {} | 266 set ::update_hook {} |
| 218 ifcapable attach { | 267 ifcapable attach { |
| 219 do_test hook-4.2.3 { | 268 do_test hook-4.2.3 { |
| 220 file delete -force test2.db | 269 forcedelete test2.db |
| 221 execsql { | 270 execsql { |
| 222 ATTACH 'test2.db' AS aux; | 271 ATTACH 'test2.db' AS aux; |
| 223 CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b); | 272 CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b); |
| 224 INSERT INTO aux.t3 SELECT * FROM t1; | 273 INSERT INTO aux.t3 SELECT * FROM t1; |
| 225 UPDATE t3 SET b = 'two or so' WHERE a = 2; | 274 UPDATE t3 SET b = 'two or so' WHERE a = 2; |
| 226 DELETE FROM t3 WHERE 1; -- Avoid the truncate optimization (for now) | 275 DELETE FROM t3 WHERE 1; -- Avoid the truncate optimization (for now) |
| 227 } | 276 } |
| 228 set ::update_hook | 277 set ::update_hook |
| 229 } [list \ | 278 } [list \ |
| 230 INSERT aux t3 1 \ | 279 INSERT aux t3 1 \ |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 SELECT * FROM t1 UNION SELECT * FROM t3; | 316 SELECT * FROM t1 UNION SELECT * FROM t3; |
| 268 SELECT * FROM t1 UNION ALL SELECT * FROM t3; | 317 SELECT * FROM t1 UNION ALL SELECT * FROM t3; |
| 269 SELECT * FROM t1 INTERSECT SELECT * FROM t3; | 318 SELECT * FROM t1 INTERSECT SELECT * FROM t3; |
| 270 SELECT * FROM t1 EXCEPT SELECT * FROM t3; | 319 SELECT * FROM t1 EXCEPT SELECT * FROM t3; |
| 271 SELECT * FROM t1 ORDER BY b; | 320 SELECT * FROM t1 ORDER BY b; |
| 272 SELECT * FROM t1 GROUP BY b; | 321 SELECT * FROM t1 GROUP BY b; |
| 273 } | 322 } |
| 274 set ::update_hook | 323 set ::update_hook |
| 275 } [list] | 324 } [list] |
| 276 } | 325 } |
| 326 |
| 327 do_test hook-4.4 { |
| 328 execsql { |
| 329 CREATE TABLE t4(a UNIQUE, b); |
| 330 INSERT INTO t4 VALUES(1, 'a'); |
| 331 INSERT INTO t4 VALUES(2, 'b'); |
| 332 } |
| 333 set ::update_hook [list] |
| 334 execsql { |
| 335 REPLACE INTO t4 VALUES(1, 'c'); |
| 336 } |
| 337 set ::update_hook |
| 338 } [list INSERT main t4 3 ] |
| 339 do_execsql_test hook-4.4.1 { |
| 340 SELECT * FROM t4 ORDER BY a; |
| 341 } {1 c 2 b} |
| 342 do_test hook-4.4.2 { |
| 343 set ::update_hook [list] |
| 344 execsql { |
| 345 PRAGMA recursive_triggers = on; |
| 346 REPLACE INTO t4 VALUES(1, 'd'); |
| 347 } |
| 348 set ::update_hook |
| 349 } [list INSERT main t4 4 ] |
| 350 do_execsql_test hook-4.4.3 { |
| 351 SELECT * FROM t4 ORDER BY a; |
| 352 } {1 d 2 b} |
| 353 |
| 277 db update_hook {} | 354 db update_hook {} |
| 278 # | 355 # |
| 279 #---------------------------------------------------------------------------- | 356 #---------------------------------------------------------------------------- |
| 280 | 357 |
| 281 #---------------------------------------------------------------------------- | 358 #---------------------------------------------------------------------------- |
| 282 # Test the rollback-hook. The rollback-hook is a bit more complicated than | 359 # Test the rollback-hook. The rollback-hook is a bit more complicated than |
| 283 # either the commit or update hooks because a rollback can happen | 360 # either the commit or update hooks because a rollback can happen |
| 284 # explicitly (an sql ROLLBACK statement) or implicitly (a constraint or | 361 # explicitly (an sql ROLLBACK statement) or implicitly (a constraint or |
| 285 # error condition). | 362 # error condition). |
| 286 # | 363 # |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 COMMIT; | 432 COMMIT; |
| 356 } | 433 } |
| 357 execsql { SELECT * FROM t1 } | 434 execsql { SELECT * FROM t1 } |
| 358 } {one I} | 435 } {one I} |
| 359 do_test hook-6.2 { | 436 do_test hook-6.2 { |
| 360 set ::hooks | 437 set ::hooks |
| 361 } {COMMIT ROLLBACK} | 438 } {COMMIT ROLLBACK} |
| 362 unset ::hooks | 439 unset ::hooks |
| 363 | 440 |
| 364 finish_test | 441 finish_test |
| OLD | NEW |