1 # 2009 August 24 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 ifcapable {!trigger} { 16 finish_test 17 return 18 } 19 20 #------------------------------------------------------------------------- 21 # Test organization: 22 # 23 # triggerC-1.*: Haphazardly designed trigger related tests that were useful 24 # during an upgrade of the triggers sub-system. 25 # 26 # triggerC-2.*: 27 # 28 # triggerC-3.*: 29 # 30 # triggerC-4.*: 31 # 32 # triggerC-5.*: Test that when recursive triggers are enabled DELETE 33 # triggers are fired when rows are deleted as part of OR 34 # REPLACE conflict resolution. And that they are not fired 35 # if recursive triggers are not enabled. 36 # 37 # triggerC-6.*: Test that the recursive_triggers pragma returns correct 38 # results when invoked without an argument. 39 # 40 41 # Enable recursive triggers for this file. 42 # 43 execsql { PRAGMA recursive_triggers = on } 44 45 #sqlite3_db_config_lookaside db 0 0 0 46 47 #------------------------------------------------------------------------- 48 # This block of tests, triggerC-1.*, are not aimed at any specific 49 # property of the triggers sub-system. They were created to debug 50 # specific problems while modifying SQLite to support recursive 51 # triggers. They are left here in case they can help debug the 52 # same problems again. 53 # 54 do_test triggerC-1.1 { 55 execsql { 56 CREATE TABLE t1(a, b, c); 57 CREATE TABLE log(t, a1, b1, c1, a2, b2, c2); 58 CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN 59 INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c); 60 END; 61 CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN 62 INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c); 63 END; 64 CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN 65 INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c); 66 END; 67 CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN 68 INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c); 69 END; 70 71 CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN 72 INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL); 73 END; 74 CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN 75 INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL); 76 END; 77 } 78 } {} 79 do_test triggerC-1.2 { 80 execsql { 81 INSERT INTO t1 VALUES('A', 'B', 'C'); 82 SELECT * FROM log; 83 } 84 } {before {} {} {} A B C after {} {} {} A B C} 85 do_test triggerC-1.3 { 86 execsql { SELECT * FROM t1 } 87 } {A B C} 88 do_test triggerC-1.4 { 89 execsql { 90 DELETE FROM log; 91 UPDATE t1 SET a = 'a'; 92 SELECT * FROM log; 93 } 94 } {before A B C a B C after A B C a B C} 95 do_test triggerC-1.5 { 96 execsql { SELECT * FROM t1 } 97 } {a B C} 98 do_test triggerC-1.6 { 99 execsql { 100 DELETE FROM log; 101 DELETE FROM t1; 102 SELECT * FROM log; 103 } 104 } {before a B C {} {} {} after a B C {} {} {}} 105 do_test triggerC-1.7 { 106 execsql { SELECT * FROM t1 } 107 } {} 108 do_test triggerC-1.8 { 109 execsql { 110 CREATE TABLE t4(a, b); 111 CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN 112 SELECT RAISE(ABORT, 'delete is not supported'); 113 END; 114 } 115 } {} 116 do_test triggerC-1.9 { 117 execsql { INSERT INTO t4 VALUES(1, 2) } 118 catchsql { DELETE FROM t4 } 119 } {1 {delete is not supported}} 120 do_test triggerC-1.10 { 121 execsql { SELECT * FROM t4 } 122 } {1 2} 123 do_test triggerC-1.11 { 124 execsql { 125 CREATE TABLE t5 (a primary key, b, c); 126 INSERT INTO t5 values (1, 2, 3); 127 CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN 128 UPDATE OR IGNORE t5 SET a = new.a, c = 10; 129 END; 130 } 131 } {} 132 do_test triggerC-1.12 { 133 catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 } 134 } {1 {too many levels of trigger recursion}} 135 do_test triggerC-1.13 { 136 execsql { 137 CREATE TABLE t6(a INTEGER PRIMARY KEY, b); 138 INSERT INTO t6 VALUES(1, 2); 139 create trigger r1 after update on t6 for each row begin 140 SELECT 1; 141 end; 142 UPDATE t6 SET a=a; 143 } 144 } {} 145 do_test triggerC-1.14 { 146 execsql { 147 DROP TABLE t1; 148 CREATE TABLE cnt(n); 149 INSERT INTO cnt VALUES(0); 150 CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e); 151 CREATE INDEX t1cd ON t1(c,d); 152 CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END; 153 INSERT INTO t1 VALUES(1,2,3,4,5); 154 INSERT INTO t1 VALUES(6,7,8,9,10); 155 INSERT INTO t1 VALUES(11,12,13,14,15); 156 } 157 } {} 158 do_test triggerC-1.15 { 159 catchsql { UPDATE OR ROLLBACK t1 SET a=100 } 160 } {1 {PRIMARY KEY must be unique}} 161 162 163 #------------------------------------------------------------------------- 164 # This block of tests, triggerC-2.*, tests that recursive trigger 165 # programs (triggers that fire themselves) work. More specifically, 166 # this block focuses on recursive INSERT triggers. 167 # 168 do_test triggerC-2.1.0 { 169 execsql { 170 CREATE TABLE t2(a PRIMARY KEY); 171 } 172 } {} 173 174 foreach {n tdefn rc} { 175 1 { 176 CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN 177 INSERT INTO t2 VALUES(new.a - 1); 178 END; 179 } {0 {10 9 8 7 6 5 4 3 2 1 0}} 180 181 2 { 182 CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN 183 SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END; 184 INSERT INTO t2 VALUES(new.a - 1); 185 END; 186 } {0 {10 9 8 7 6 5 4 3 2}} 187 188 3 { 189 CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN 190 INSERT INTO t2 VALUES(new.a - 1); 191 END; 192 } {0 {0 1 2 3 4 5 6 7 8 9 10}} 193 194 4 { 195 CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN 196 SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END; 197 INSERT INTO t2 VALUES(new.a - 1); 198 END; 199 } {0 {3 4 5 6 7 8 9 10}} 200 201 5 { 202 CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN 203 INSERT INTO t2 VALUES(new.a - 1); 204 END; 205 } {1 {too many levels of trigger recursion}} 206 207 6 { 208 CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN 209 INSERT OR IGNORE INTO t2 VALUES(new.a); 210 END; 211 } {0 10} 212 213 7 { 214 CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN 215 INSERT OR IGNORE INTO t2 VALUES(new.a); 216 END; 217 } {1 {too many levels of trigger recursion}} 218 } { 219 do_test triggerC-2.1.$n { 220 catchsql { DROP TRIGGER t2_trig } 221 execsql { DELETE FROM t2 } 222 execsql $tdefn 223 catchsql { 224 INSERT INTO t2 VALUES(10); 225 SELECT * FROM t2; 226 } 227 } $rc 228 } 229 230 do_test triggerC-2.2 { 231 execsql { 232 CREATE TABLE t22(x); 233 234 CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN 235 INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22; 236 END; 237 CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN 238 SELECT CASE WHEN (SELECT count(*) FROM t22) >= 100 239 THEN RAISE(IGNORE) 240 ELSE NULL END; 241 END; 242 243 INSERT INTO t22 VALUES(1); 244 SELECT count(*) FROM t22; 245 } 246 } {100} 247 248 do_test triggerC-2.3 { 249 execsql { 250 CREATE TABLE t23(x PRIMARY KEY); 251 252 CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN 253 INSERT INTO t23 VALUES(new.x + 1); 254 END; 255 256 CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN 257 SELECT CASE WHEN new.x>500 258 THEN RAISE(IGNORE) 259 ELSE NULL END; 260 END; 261 262 INSERT INTO t23 VALUES(1); 263 SELECT count(*) FROM t23; 264 } 265 } {500} 266 267 268 #----------------------------------------------------------------------- 269 # This block of tests, triggerC-3.*, test that SQLite throws an exception 270 # when it detects excessive recursion. 271 # 272 do_test triggerC-3.1.1 { 273 execsql { 274 CREATE TABLE t3(a, b); 275 CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN 276 DELETE FROM t3 WHERE rowid = new.rowid; 277 END; 278 CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN 279 INSERT INTO t3 VALUES(old.a, old.b); 280 END; 281 } 282 } {} 283 do_test triggerC-3.1.2 { 284 catchsql { INSERT INTO t3 VALUES(0,0) } 285 } {1 {too many levels of trigger recursion}} 286 do_test triggerC-3.1.3 { 287 execsql { SELECT * FROM t3 } 288 } {} 289 290 do_test triggerC-3.2.1 { 291 execsql { 292 CREATE TABLE t3b(x); 293 CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<2000 BEGIN 294 INSERT INTO t3b VALUES(new.x+1); 295 END; 296 } 297 catchsql { 298 INSERT INTO t3b VALUES(1); 299 } 300 } {1 {too many levels of trigger recursion}} 301 do_test triggerC-3.2.2 { 302 db eval {SELECT * FROM t3b} 303 } {} 304 305 do_test triggerC-3.3.1 { 306 catchsql { 307 INSERT INTO t3b VALUES(1001); 308 } 309 } {0 {}} 310 do_test triggerC-3.3.2 { 311 db eval {SELECT count(*), max(x), min(x) FROM t3b} 312 } {1000 2000 1001} 313 314 do_test triggerC-3.4.1 { 315 catchsql { 316 DELETE FROM t3b; 317 INSERT INTO t3b VALUES(999); 318 } 319 } {1 {too many levels of trigger recursion}} 320 do_test triggerC-3.4.2 { 321 db eval {SELECT count(*), max(x), min(x) FROM t3b} 322 } {0 {} {}} 323 324 do_test triggerC-3.5.1 { 325 sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 100 326 catchsql { 327 INSERT INTO t3b VALUES(1901); 328 } 329 } {0 {}} 330 do_test triggerC-3.5.2 { 331 db eval {SELECT count(*), max(x), min(x) FROM t3b} 332 } {100 2000 1901} 333 334 do_test triggerC-3.5.3 { 335 catchsql { 336 DELETE FROM t3b; 337 INSERT INTO t3b VALUES(1900); 338 } 339 } {1 {too many levels of trigger recursion}} 340 do_test triggerC-3.5.4 { 341 db eval {SELECT count(*), max(x), min(x) FROM t3b} 342 } {0 {} {}} 343 344 do_test triggerC-3.6.1 { 345 sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1 346 catchsql { 347 INSERT INTO t3b VALUES(2000); 348 } 349 } {0 {}} 350 do_test triggerC-3.6.2 { 351 db eval {SELECT count(*), max(x), min(x) FROM t3b} 352 } {1 2000 2000} 353 354 do_test triggerC-3.6.3 { 355 catchsql { 356 DELETE FROM t3b; 357 INSERT INTO t3b VALUES(1999); 358 } 359 } {1 {too many levels of trigger recursion}} 360 do_test triggerC-3.6.4 { 361 db eval {SELECT count(*), max(x), min(x) FROM t3b} 362 } {0 {} {}} 363 sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000 364 365 366 #----------------------------------------------------------------------- 367 # This next block of tests, triggerC-4.*, checks that affinity 368 # transformations and constraint processing is performed at the correct 369 # times relative to BEFORE and AFTER triggers. 370 # 371 # For an INSERT statement, for each row to be inserted: 372 # 373 # 1. Apply affinities to non-rowid values to be inserted. 374 # 2. Fire BEFORE triggers. 375 # 3. Process constraints. 376 # 4. Insert new record. 377 # 5. Fire AFTER triggers. 378 # 379 # If the value of the rowid field is to be automatically assigned, it is 380 # set to -1 in the new.* record. Even if it is explicitly set to NULL 381 # by the INSERT statement. 382 # 383 # For an UPDATE statement, for each row to be deleted: 384 # 385 # 1. Apply affinities to non-rowid values to be inserted. 386 # 2. Fire BEFORE triggers. 387 # 3. Process constraints. 388 # 4. Insert new record. 389 # 5. Fire AFTER triggers. 390 # 391 # For a DELETE statement, for each row to be deleted: 392 # 393 # 1. Fire BEFORE triggers. 394 # 2. Remove database record. 395 # 3. Fire AFTER triggers. 396 # 397 # When a numeric value that as an exact integer representation is stored 398 # in a column with REAL affinity, it is actually stored as an integer. 399 # These tests check that the typeof() such values is always 'real', 400 # not 'integer'. 401 # 402 # triggerC-4.1.*: Check that affinity transformations are made before 403 # triggers are invoked. 404 # 405 do_test triggerC-4.1.1 { 406 catchsql { DROP TABLE log } 407 catchsql { DROP TABLE t4 } 408 execsql { 409 CREATE TABLE log(t); 410 CREATE TABLE t4(a TEXT,b INTEGER,c REAL); 411 CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN 412 INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || 413 new.a || ' ' || typeof(new.a) || ' ' || 414 new.b || ' ' || typeof(new.b) || ' ' || 415 new.c || ' ' || typeof(new.c) 416 ); 417 END; 418 CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN 419 INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || 420 new.a || ' ' || typeof(new.a) || ' ' || 421 new.b || ' ' || typeof(new.b) || ' ' || 422 new.c || ' ' || typeof(new.c) 423 ); 424 END; 425 CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN 426 INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || 427 old.a || ' ' || typeof(old.a) || ' ' || 428 old.b || ' ' || typeof(old.b) || ' ' || 429 old.c || ' ' || typeof(old.c) 430 ); 431 END; 432 CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN 433 INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || 434 old.a || ' ' || typeof(old.a) || ' ' || 435 old.b || ' ' || typeof(old.b) || ' ' || 436 old.c || ' ' || typeof(old.c) 437 ); 438 END; 439 CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN 440 INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || 441 old.a || ' ' || typeof(old.a) || ' ' || 442 old.b || ' ' || typeof(old.b) || ' ' || 443 old.c || ' ' || typeof(old.c) 444 ); 445 INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || 446 new.a || ' ' || typeof(new.a) || ' ' || 447 new.b || ' ' || typeof(new.b) || ' ' || 448 new.c || ' ' || typeof(new.c) 449 ); 450 END; 451 CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN 452 INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || 453 old.a || ' ' || typeof(old.a) || ' ' || 454 old.b || ' ' || typeof(old.b) || ' ' || 455 old.c || ' ' || typeof(old.c) 456 ); 457 INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || 458 new.a || ' ' || typeof(new.a) || ' ' || 459 new.b || ' ' || typeof(new.b) || ' ' || 460 new.c || ' ' || typeof(new.c) 461 ); 462 END; 463 } 464 } {} 465 foreach {n insert log} { 466 467 2 { 468 INSERT INTO t4 VALUES('1', '1', '1'); 469 DELETE FROM t4; 470 } { 471 -1 integer 1 text 1 integer 1.0 real 472 1 integer 1 text 1 integer 1.0 real 473 1 integer 1 text 1 integer 1.0 real 474 1 integer 1 text 1 integer 1.0 real 475 } 476 477 3 { 478 INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45); 479 DELETE FROM t4; 480 } { 481 45 integer 45 text 45 integer 45.0 real 482 45 integer 45 text 45 integer 45.0 real 483 45 integer 45 text 45 integer 45.0 real 484 45 integer 45 text 45 integer 45.0 real 485 } 486 487 4 { 488 INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0); 489 DELETE FROM t4; 490 } { 491 -42 integer -42.0 text -42 integer -42.0 real 492 -42 integer -42.0 text -42 integer -42.0 real 493 -42 integer -42.0 text -42 integer -42.0 real 494 -42 integer -42.0 text -42 integer -42.0 real 495 } 496 497 5 { 498 INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4); 499 DELETE FROM t4; 500 } { 501 -1 integer -42.4 text -42.4 real -42.4 real 502 1 integer -42.4 text -42.4 real -42.4 real 503 1 integer -42.4 text -42.4 real -42.4 real 504 1 integer -42.4 text -42.4 real -42.4 real 505 } 506 507 6 { 508 INSERT INTO t4 VALUES(7, 7, 7); 509 UPDATE t4 SET a=8, b=8, c=8; 510 } { 511 -1 integer 7 text 7 integer 7.0 real 512 1 integer 7 text 7 integer 7.0 real 513 1 integer 7 text 7 integer 7.0 real 514 1 integer 8 text 8 integer 8.0 real 515 1 integer 7 text 7 integer 7.0 real 516 1 integer 8 text 8 integer 8.0 real 517 } 518 519 7 { 520 UPDATE t4 SET rowid=2; 521 } { 522 1 integer 8 text 8 integer 8.0 real 523 2 integer 8 text 8 integer 8.0 real 524 1 integer 8 text 8 integer 8.0 real 525 2 integer 8 text 8 integer 8.0 real 526 } 527 528 8 { 529 UPDATE t4 SET a='9', b='9', c='9'; 530 } { 531 2 integer 8 text 8 integer 8.0 real 532 2 integer 9 text 9 integer 9.0 real 533 2 integer 8 text 8 integer 8.0 real 534 2 integer 9 text 9 integer 9.0 real 535 } 536 537 9 { 538 UPDATE t4 SET a='9.1', b='9.1', c='9.1'; 539 } { 540 2 integer 9 text 9 integer 9.0 real 541 2 integer 9.1 text 9.1 real 9.1 real 542 2 integer 9 text 9 integer 9.0 real 543 2 integer 9.1 text 9.1 real 9.1 real 544 } 545 } { 546 do_test triggerC-4.1.$n { 547 eval concat [execsql " 548 DELETE FROM log; 549 $insert ; 550 SELECT * FROM log; 551 "] 552 } [join $log " "] 553 } 554 555 #------------------------------------------------------------------------- 556 # This block of tests, triggerC-5.*, test that DELETE triggers are fired 557 # if a row is deleted as a result of OR REPLACE conflict resolution. 558 # 559 do_test triggerC-5.1.0 { 560 execsql { 561 DROP TABLE IF EXISTS t5; 562 CREATE TABLE t5(a INTEGER PRIMARY KEY, b); 563 CREATE UNIQUE INDEX t5i ON t5(b); 564 INSERT INTO t5 VALUES(1, 'a'); 565 INSERT INTO t5 VALUES(2, 'b'); 566 INSERT INTO t5 VALUES(3, 'c'); 567 568 CREATE TABLE t5g(a, b, c); 569 CREATE TRIGGER t5t BEFORE DELETE ON t5 BEGIN 570 INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5)); 571 END; 572 } 573 } {} 574 foreach {n dml t5g t5} { 575 1 "DELETE FROM t5 WHERE a=2" {2 b 3} {1 a 3 c} 576 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {2 b 3} {1 a 2 d 3 c} 577 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {2 b 3} {1 a 2 c} 578 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {2 b 3} {1 a 3 c 4 b} 579 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {2 b 3} {1 a 3 b} 580 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {2 b 3 3 c 2} {1 a 2 c} 581 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 3 2 b 2} {1 b} 582 } { 583 do_test triggerC-5.1.$n { 584 execsql " 585 BEGIN; 586 $dml ; 587 SELECT * FROM t5g; 588 SELECT * FROM t5; 589 ROLLBACK; 590 " 591 } [concat $t5g $t5] 592 } 593 do_test triggerC-5.2.0 { 594 execsql { 595 DROP TRIGGER t5t; 596 CREATE TRIGGER t5t AFTER DELETE ON t5 BEGIN 597 INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5)); 598 END; 599 } 600 } {} 601 foreach {n dml t5g t5} { 602 1 "DELETE FROM t5 WHERE a=2" {2 b 2} {1 a 3 c} 603 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {2 b 2} {1 a 2 d 3 c} 604 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {2 b 2} {1 a 2 c} 605 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {2 b 2} {1 a 3 c 4 b} 606 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {2 b 2} {1 a 3 b} 607 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {2 b 2 3 c 1} {1 a 2 c} 608 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 2 2 b 1} {1 b} 609 } { 610 do_test triggerC-5.2.$n { 611 execsql " 612 BEGIN; 613 $dml ; 614 SELECT * FROM t5g; 615 SELECT * FROM t5; 616 ROLLBACK; 617 " 618 } [concat $t5g $t5] 619 } 620 do_test triggerC-5.3.0 { 621 execsql { PRAGMA recursive_triggers = off } 622 } {} 623 foreach {n dml t5g t5} { 624 1 "DELETE FROM t5 WHERE a=2" {2 b 2} {1 a 3 c} 625 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {} {1 a 2 d 3 c} 626 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {} {1 a 2 c} 627 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {} {1 a 3 c 4 b} 628 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {} {1 a 3 b} 629 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {} {1 a 2 c} 630 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {} {1 b} 631 } { 632 do_test triggerC-5.3.$n { 633 execsql " 634 BEGIN; 635 $dml ; 636 SELECT * FROM t5g; 637 SELECT * FROM t5; 638 ROLLBACK; 639 " 640 } [concat $t5g $t5] 641 } 642 do_test triggerC-5.3.8 { 643 execsql { PRAGMA recursive_triggers = on } 644 } {} 645 646 #------------------------------------------------------------------------- 647 # This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers" 648 # statements return the current value of the recursive triggers flag. 649 # 650 do_test triggerC-6.1 { 651 execsql { PRAGMA recursive_triggers } 652 } {1} 653 do_test triggerC-6.2 { 654 execsql { 655 PRAGMA recursive_triggers = off; 656 PRAGMA recursive_triggers; 657 } 658 } {0} 659 do_test triggerC-6.3 { 660 execsql { 661 PRAGMA recursive_triggers = on; 662 PRAGMA recursive_triggers; 663 } 664 } {1} 665 666 #------------------------------------------------------------------------- 667 # Test some of the "undefined behaviour" associated with triggers. The 668 # undefined behaviour occurs when a row being updated or deleted is 669 # manipulated by a BEFORE trigger. 670 # 671 do_test triggerC-7.1 { 672 execsql { 673 CREATE TABLE t8(x); 674 CREATE TABLE t7(a, b); 675 INSERT INTO t7 VALUES(1, 2); 676 INSERT INTO t7 VALUES(3, 4); 677 INSERT INTO t7 VALUES(5, 6); 678 CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN 679 DELETE FROM t7 WHERE a = 1; 680 END; 681 CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN 682 INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid); 683 END; 684 } 685 } {} 686 do_test triggerC-7.2 { 687 execsql { 688 BEGIN; 689 UPDATE t7 SET b=7 WHERE a = 5; 690 SELECT * FROM t7; 691 SELECT * FROM t8; 692 ROLLBACK; 693 } 694 } {3 4 5 7 {after fired 3->3}} 695 do_test triggerC-7.3 { 696 execsql { 697 BEGIN; 698 UPDATE t7 SET b=7 WHERE a = 1; 699 SELECT * FROM t7; 700 SELECT * FROM t8; 701 ROLLBACK; 702 } 703 } {3 4 5 6} 704 705 do_test triggerC-7.4 { 706 execsql { 707 DROP TRIGGER t7t; 708 CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8) 709 BEGIN 710 UPDATE t7 set rowid = 8 WHERE rowid=1; 711 END; 712 } 713 } {} 714 do_test triggerC-7.5 { 715 execsql { 716 BEGIN; 717 UPDATE t7 SET b=7 WHERE a = 5; 718 SELECT rowid, * FROM t7; 719 SELECT * FROM t8; 720 ROLLBACK; 721 } 722 } {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}} 723 do_test triggerC-7.6 { 724 execsql { 725 BEGIN; 726 UPDATE t7 SET b=7 WHERE a = 1; 727 SELECT rowid, * FROM t7; 728 SELECT * FROM t8; 729 ROLLBACK; 730 } 731 } {2 3 4 3 5 6 8 1 2 {after fired 1->8}} 732 733 do_test triggerC-7.7 { 734 execsql { 735 DROP TRIGGER t7t; 736 DROP TRIGGER t7ta; 737 CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN 738 UPDATE t7 set rowid = 8 WHERE rowid=1; 739 END; 740 CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN 741 INSERT INTO t8 VALUES('after fired ' || old.rowid); 742 END; 743 } 744 } {} 745 do_test triggerC-7.8 { 746 execsql { 747 BEGIN; 748 DELETE FROM t7 WHERE a = 3; 749 SELECT rowid, * FROM t7; 750 SELECT * FROM t8; 751 ROLLBACK; 752 } 753 } {3 5 6 8 1 2 {after fired 2}} 754 do_test triggerC-7.9 { 755 execsql { 756 BEGIN; 757 DELETE FROM t7 WHERE a = 1; 758 SELECT rowid, * FROM t7; 759 SELECT * FROM t8; 760 ROLLBACK; 761 } 762 } {2 3 4 3 5 6 8 1 2} 763 764 # Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643] 765 # 766 do_test triggerC-9.1 { 767 execsql { 768 CREATE TABLE t9(a,b); 769 CREATE INDEX t9b ON t9(b); 770 INSERT INTO t9 VALUES(1,0); 771 INSERT INTO t9 VALUES(2,1); 772 INSERT INTO t9 VALUES(3,2); 773 INSERT INTO t9 SELECT a+3, a+2 FROM t9; 774 INSERT INTO t9 SELECT a+6, a+5 FROM t9; 775 SELECT a FROM t9 ORDER BY a; 776 } 777 } {1 2 3 4 5 6 7 8 9 10 11 12} 778 do_test triggerC-9.2 { 779 execsql { 780 CREATE TRIGGER t9r1 AFTER DELETE ON t9 BEGIN 781 DELETE FROM t9 WHERE b=old.a; 782 END; 783 DELETE FROM t9 WHERE b=4; 784 SELECT a FROM t9 ORDER BY a; 785 } 786 } {1 2 3 4} 787 788 # At one point (between versions 3.6.18 and 3.6.20 inclusive), an UPDATE 789 # that fired a BEFORE trigger that itself updated the same row as the 790 # statement causing it to fire was causing a strange side-effect: The 791 # values updated by the statement within the trigger were being overwritten 792 # by the values in the new.* array, even if those values were not 793 # themselves written by the parent UPDATE statement. 794 # 795 # Technically speaking this was not a bug. The SQLite documentation says 796 # that if a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes the 797 # row that the parent statement is operating on the results are undefined. 798 # But as of 3.6.21 behaviour is restored to the way it was in versions 799 # 3.6.17 and earlier to avoid causing unnecessary difficulties. 800 # 801 do_test triggerC-10.1 { 802 execsql { 803 CREATE TABLE t10(a, updatecnt DEFAULT 0); 804 CREATE TRIGGER t10_bu BEFORE UPDATE OF a ON t10 BEGIN 805 UPDATE t10 SET updatecnt = updatecnt+1 WHERE rowid = old.rowid; 806 END; 807 INSERT INTO t10(a) VALUES('hello'); 808 } 809 810 # Before the problem was fixed, table t10 would contain the tuple 811 # (world, 0) after running the following script (because the value 812 # 1 written to column "updatecnt" was clobbered by the old value 0). 813 # 814 execsql { 815 UPDATE t10 SET a = 'world'; 816 SELECT * FROM t10; 817 } 818 } {world 1} 819 820 do_test triggerC-10.2 { 821 execsql { 822 UPDATE t10 SET a = 'tcl', updatecnt = 5; 823 SELECT * FROM t10; 824 } 825 } {tcl 5} 826 827 do_test triggerC-10.3 { 828 execsql { 829 CREATE TABLE t11( 830 c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, 831 c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, 832 c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, 833 c31, c32, c33, c34, c35, c36, c37, c38, c39, c40 834 ); 835 836 CREATE TRIGGER t11_bu BEFORE UPDATE OF c1 ON t11 BEGIN 837 UPDATE t11 SET c31 = c31+1, c32=c32+1 WHERE rowid = old.rowid; 838 END; 839 840 INSERT INTO t11 VALUES( 841 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 842 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 843 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 844 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 845 ); 846 } 847 848 # Before the problem was fixed, table t10 would contain the tuple 849 # (world, 0) after running the following script (because the value 850 # 1 written to column "updatecnt" was clobbered by the old value 0). 851 # 852 execsql { 853 UPDATE t11 SET c4=35, c33=22, c1=5; 854 SELECT * FROM t11; 855 } 856 } {5 2 3 35 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 32 33 22 34 35 36 37 38 39 40} 857 858 #------------------------------------------------------------------------- 859 # Test that bug [371bab5d65] has been fixed. BEFORE INSERT and INSTEAD OF 860 # INSERT triggers with the DEFAULT VALUES INSERT syntax. 861 # 862 do_test triggerC-11.0 { 863 catchsql { DROP TABLE log } 864 execsql { CREATE TABLE log(a, b) } 865 } {} 866 867 foreach {testno tbl defaults} { 868 1 "CREATE TABLE t1(a, b)" {{} {}} 869 2 "CREATE TABLE t1(a DEFAULT 1, b DEFAULT 'abc')" {1 abc} 870 3 "CREATE TABLE t1(a, b DEFAULT 4.5)" {{} 4.5} 871 } { 872 do_test triggerC-11.$testno.1 { 873 catchsql { DROP TABLE t1 } 874 execsql { DELETE FROM log } 875 execsql $tbl 876 execsql { 877 CREATE TRIGGER tt1 BEFORE INSERT ON t1 BEGIN 878 INSERT INTO log VALUES(new.a, new.b); 879 END; 880 INSERT INTO t1 DEFAULT VALUES; 881 SELECT * FROM log; 882 } 883 } $defaults 884 885 do_test triggerC-11.$testno.2 { 886 execsql { DELETE FROM log } 887 execsql { 888 CREATE TRIGGER tt2 AFTER INSERT ON t1 BEGIN 889 INSERT INTO log VALUES(new.a, new.b); 890 END; 891 INSERT INTO t1 DEFAULT VALUES; 892 SELECT * FROM log; 893 } 894 } [concat $defaults $defaults] 895 896 do_test triggerC-11.$testno.3 { 897 execsql { DROP TRIGGER tt1 } 898 execsql { DELETE FROM log } 899 execsql { 900 INSERT INTO t1 DEFAULT VALUES; 901 SELECT * FROM log; 902 } 903 } $defaults 904 } 905 do_test triggerC-11.4 { 906 catchsql { DROP TABLE t2 } 907 execsql { 908 DELETE FROM log; 909 CREATE TABLE t2(a, b); 910 CREATE VIEW v2 AS SELECT * FROM t2; 911 CREATE TRIGGER tv2 INSTEAD OF INSERT ON v2 BEGIN 912 INSERT INTO log VALUES(new.a, new.b); 913 END; 914 INSERT INTO v2 DEFAULT VALUES; 915 SELECT a, b, a IS NULL, b IS NULL FROM log; 916 } 917 } {{} {} 1 1} 918 919 do_test triggerC-12.1 { 920 db close 921 file delete -force test.db 922 sqlite3 db test.db 923 924 execsql { 925 CREATE TABLE t1(a, b); 926 INSERT INTO t1 VALUES(1, 2); 927 INSERT INTO t1 VALUES(3, 4); 928 INSERT INTO t1 VALUES(5, 6); 929 CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1 ; END ; 930 SELECT count(*) FROM sqlite_master; 931 } 932 } {2} 933 do_test triggerC-12.2 { 934 db eval { SELECT * FROM t1 } { 935 if {$a == 3} { execsql { DROP TRIGGER tr1 } } 936 } 937 execsql { SELECT count(*) FROM sqlite_master } 938 } {1} 939 940 do_execsql_test triggerC-13.1 { 941 PRAGMA recursive_triggers = ON; 942 CREATE TABLE t12(a, b); 943 INSERT INTO t12 VALUES(1, 2); 944 CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN 945 UPDATE t12 SET a=new.a+1, b=new.b+1; 946 END; 947 } {} 948 do_catchsql_test triggerC-13.2 { 949 UPDATE t12 SET a=a+1, b=b+1; 950 } {1 {too many levels of trigger recursion}} 951 952 953 954 finish_test 955