1 # The author disclaims copyright to this source code. In place of
2 # a legal notice, here is a blessing:
4 # May you do good and not evil.
5 # May you find forgiveness for yourself and forgive others.
6 # May you share freely, never taking more than you give.
8 #***********************************************************************
10 # Regression testing of FOR EACH ROW table triggers
12 # 1. Trigger execution order tests.
13 # These tests ensure that BEFORE and AFTER triggers are fired at the correct
14 # times relative to each other and the triggering statement.
16 # trigger2-1.1.*: ON UPDATE trigger execution model.
17 # trigger2-1.2.*: DELETE trigger execution model.
18 # trigger2-1.3.*: INSERT trigger execution model.
20 # 2. Trigger program execution tests.
21 # These tests ensure that trigger programs execute correctly (ie. that a
22 # trigger program can correctly execute INSERT, UPDATE, DELETE * SELECT
23 # statements, and combinations thereof).
25 # 3. Selective trigger execution
26 # This tests that conditional triggers (ie. UPDATE OF triggers and triggers
27 # with WHEN clauses) are fired only fired when they are supposed to be.
29 # trigger2-3.1: UPDATE OF triggers
30 # trigger2-3.2: WHEN clause
32 # 4. Cascaded trigger execution
33 # Tests that trigger-programs may cause other triggers to fire. Also that a
34 # trigger-program is never executed recursively.
36 # trigger2-4.1: Trivial cascading trigger
37 # trigger2-4.2: Trivial recursive trigger handling
39 # 5. Count changes behaviour.
40 # Verify that rows altered by triggers are not included in the return value
41 # of the "count changes" interface.
43 # 6. ON CONFLICT clause handling
44 # trigger2-6.1[a-f]: INSERT statements
45 # trigger2-6.2[a-f]: UPDATE statements
47 # 7. & 8. Triggers on views fire correctly.
50 set testdir [file dirname $argv0]
51 source $testdir/tester.tcl
52 set testprefix trigger2
53 ifcapable {!trigger} {
58 # The tests in this file were written before SQLite supported recursive
59 # trigger invocation, and some tests depend on that to pass. So disable
60 # recursive triggers for this file.
61 catchsql { pragma recursive_triggers = off }
66 set tbl_definitions [list \
67 {CREATE TABLE tbl (a, b);} \
68 {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \
69 {CREATE TABLE tbl (a, b PRIMARY KEY);} \
70 {CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} \
73 lappend tbl_definitions \
74 {CREATE TEMP TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);}
75 lappend tbl_definitions {CREATE TEMP TABLE tbl (a, b);}
76 lappend tbl_definitions \
77 {CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);}
79 foreach tbl_defn $tbl_definitions {
81 catchsql { DROP INDEX tbl_idx; }
92 INSERT INTO tbl VALUES(1, 2);
93 INSERT INTO tbl VALUES(3, 4);
95 CREATE TABLE rlog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b);
96 CREATE TABLE clog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b);
98 CREATE TRIGGER before_update_row BEFORE UPDATE ON tbl FOR EACH ROW
100 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
102 (SELECT coalesce(sum(a),0) FROM tbl),
103 (SELECT coalesce(sum(b),0) FROM tbl),
107 CREATE TRIGGER after_update_row AFTER UPDATE ON tbl FOR EACH ROW
109 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
111 (SELECT coalesce(sum(a),0) FROM tbl),
112 (SELECT coalesce(sum(b),0) FROM tbl),
116 CREATE TRIGGER conditional_update_row AFTER UPDATE ON tbl FOR EACH ROW
119 INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog),
121 (SELECT coalesce(sum(a),0) FROM tbl),
122 (SELECT coalesce(sum(b),0) FROM tbl),
127 do_test trigger2-1.$ii.1 {
130 UPDATE tbl SET a = a * 10, b = b * 10;
131 SELECT * FROM rlog ORDER BY idx;
132 SELECT * FROM clog ORDER BY idx;
134 lappend r [expr {int($v)}]
137 } [list 1 1 2 4 6 10 20 \
146 INSERT INTO tbl VALUES (100, 100);
147 INSERT INTO tbl VALUES (300, 200);
148 CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW
150 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
152 (SELECT coalesce(sum(a),0) FROM tbl),
153 (SELECT coalesce(sum(b),0) FROM tbl),
157 CREATE TRIGGER delete_after_row AFTER DELETE ON tbl FOR EACH ROW
159 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
161 (SELECT coalesce(sum(a),0) FROM tbl),
162 (SELECT coalesce(sum(b),0) FROM tbl),
166 do_test trigger2-1.$ii.2 {
172 lappend r [expr {int($v)}]
175 } [list 1 100 100 400 300 0 0 \
176 2 100 100 300 200 0 0 \
177 3 300 200 300 200 0 0 \
182 CREATE TRIGGER insert_before_row BEFORE INSERT ON tbl FOR EACH ROW
184 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
186 (SELECT coalesce(sum(a),0) FROM tbl),
187 (SELECT coalesce(sum(b),0) FROM tbl),
191 CREATE TRIGGER insert_after_row AFTER INSERT ON tbl FOR EACH ROW
193 INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog),
195 (SELECT coalesce(sum(a),0) FROM tbl),
196 (SELECT coalesce(sum(b),0) FROM tbl),
200 do_test trigger2-1.$ii.3 {
203 CREATE TABLE other_tbl(a, b);
204 INSERT INTO other_tbl VALUES(1, 2);
205 INSERT INTO other_tbl VALUES(3, 4);
206 -- INSERT INTO tbl SELECT * FROM other_tbl;
207 INSERT INTO tbl VALUES(5, 6);
208 DROP TABLE other_tbl;
212 } [list 1 0 0 0 0 5 6 \
215 integrity_check trigger2-1.$ii.4
221 DROP TABLE other_tbl;
228 {UPDATE tbl SET b = old.b;}
229 {INSERT INTO log VALUES(new.c, 2, 3);}
230 {DELETE FROM log WHERE a = 1;}
231 {INSERT INTO tbl VALUES(500, new.b * 10, 700);
232 UPDATE tbl SET c = old.c;
234 {INSERT INTO log select * from tbl;}
236 foreach test_varset [ list \
238 set statement {UPDATE tbl SET c = 10 WHERE a = 1;}
239 set prep {INSERT INTO tbl VALUES(1, 2, 3);}
248 set statement {DELETE FROM tbl WHERE a = 1;}
249 set prep {INSERT INTO tbl VALUES(1, 2, 3);}
255 set statement {INSERT INTO tbl VALUES(1, 2, 3);}
275 set statement_type [string range $statement 0 5]
276 set tr_program_fixed $tr_program
277 if {$statement_type == "DELETE"} {
278 regsub -all new\.a $tr_program_fixed {''} tr_program_fixed
279 regsub -all new\.b $tr_program_fixed {''} tr_program_fixed
280 regsub -all new\.c $tr_program_fixed {''} tr_program_fixed
282 if {$statement_type == "INSERT"} {
283 regsub -all old\.a $tr_program_fixed {''} tr_program_fixed
284 regsub -all old\.b $tr_program_fixed {''} tr_program_fixed
285 regsub -all old\.c $tr_program_fixed {''} tr_program_fixed
289 set tr_program_cooked $tr_program
290 regsub -all new\.a $tr_program_cooked $newA tr_program_cooked
291 regsub -all new\.b $tr_program_cooked $newB tr_program_cooked
292 regsub -all new\.c $tr_program_cooked $newC tr_program_cooked
293 regsub -all old\.a $tr_program_cooked $oldA tr_program_cooked
294 regsub -all old\.b $tr_program_cooked $oldB tr_program_cooked
295 regsub -all old\.c $tr_program_cooked $oldC tr_program_cooked
303 CREATE TABLE tbl(a PRIMARY KEY, b, c);
304 CREATE TABLE log(a, b, c);
307 set query {SELECT * FROM tbl; SELECT * FROM log;}
308 set prep "$prep; INSERT INTO log VALUES(1, 2, 3);\
309 INSERT INTO log VALUES(10, 20, 30);"
311 # Check execution of BEFORE programs:
313 set before_data [ execsql "$prep $tr_program_cooked $statement $query" ]
315 execsql "DELETE FROM tbl; DELETE FROM log; $prep";
316 execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6]\
317 ON tbl BEGIN $tr_program_fixed END;"
319 do_test trigger2-2.$ii-before "execsql {$statement $query}" $before_data
321 execsql "DROP TRIGGER the_trigger;"
322 execsql "DELETE FROM tbl; DELETE FROM log;"
324 # Check execution of AFTER programs
325 set after_data [ execsql "$prep $statement $tr_program_cooked $query" ]
327 execsql "DELETE FROM tbl; DELETE FROM log; $prep";
328 execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\
329 ON tbl BEGIN $tr_program_fixed END;"
331 do_test trigger2-2.$ii-after "execsql {$statement $query}" $after_data
332 execsql "DROP TRIGGER the_trigger;"
334 integrity_check trigger2-2.$ii-integrity
344 # trigger2-3.1: UPDATE OF triggers
346 CREATE TABLE tbl (a, b, c, d);
347 CREATE TABLE log (a);
348 INSERT INTO log VALUES (0);
349 INSERT INTO tbl VALUES (0, 0, 0, 0);
350 INSERT INTO tbl VALUES (1, 0, 0, 0);
351 CREATE TRIGGER tbl_after_update_cd BEFORE UPDATE OF c, d ON tbl
353 UPDATE log SET a = a + 1;
356 do_test trigger2-3.1 {
358 UPDATE tbl SET b = 1, c = 10; -- 2
359 UPDATE tbl SET b = 10; -- 0
360 UPDATE tbl SET d = 4 WHERE a = 0; --1
361 UPDATE tbl SET a = 4, b = 10; --0
370 # trigger2-3.2: WHEN clause
371 set when_triggers [list {t1 BEFORE INSERT ON tbl WHEN new.a > 20}]
373 lappend when_triggers \
374 {t2 BEFORE INSERT ON tbl WHEN (SELECT count(*) FROM tbl) = 0}
378 CREATE TABLE tbl (a, b, c, d);
379 CREATE TABLE log (a);
380 INSERT INTO log VALUES (0);
383 foreach trig $when_triggers {
384 execsql "CREATE TRIGGER $trig BEGIN UPDATE log set a = a + 1; END;"
392 do_test trigger2-3.2 {
395 INSERT INTO tbl VALUES(0, 0, 0, 0); -- 1 (ifcapable subquery)
397 UPDATE log SET a = 0;
399 INSERT INTO tbl VALUES(0, 0, 0, 0); -- 0
401 UPDATE log SET a = 0;
403 INSERT INTO tbl VALUES(200, 0, 0, 0); -- 1
405 UPDATE log SET a = 0;
412 integrity_check trigger2-3.3
414 # Simple cascaded trigger
416 CREATE TABLE tblA(a, b);
417 CREATE TABLE tblB(a, b);
418 CREATE TABLE tblC(a, b);
420 CREATE TRIGGER tr1 BEFORE INSERT ON tblA BEGIN
421 INSERT INTO tblB values(new.a, new.b);
424 CREATE TRIGGER tr2 BEFORE INSERT ON tblB BEGIN
425 INSERT INTO tblC values(new.a, new.b);
428 do_test trigger2-4.1 {
430 INSERT INTO tblA values(1, 2);
442 # Simple recursive trigger
444 CREATE TABLE tbl(a, b, c);
445 CREATE TRIGGER tbl_trig BEFORE INSERT ON tbl
447 INSERT INTO tbl VALUES (new.a, new.b, new.c);
450 do_test trigger2-4.2 {
452 INSERT INTO tbl VALUES (1, 2, 3);
462 CREATE TABLE tbl(a, b, c);
463 CREATE TRIGGER tbl_trig BEFORE INSERT ON tbl
465 INSERT INTO tbl VALUES (1, 2, 3);
466 INSERT INTO tbl VALUES (2, 2, 3);
467 UPDATE tbl set b = 10 WHERE a = 1;
468 DELETE FROM tbl WHERE a = 1;
474 INSERT INTO tbl VALUES(100, 200, 300);
483 # Handling of ON CONFLICT by INSERT statements inside triggers
485 CREATE TABLE tbl (a primary key, b, c);
486 CREATE TRIGGER ai_tbl AFTER INSERT ON tbl BEGIN
487 INSERT OR IGNORE INTO tbl values (new.a, 0, 0);
490 do_test trigger2-6.1a {
493 INSERT INTO tbl values (1, 2, 3);
497 do_test trigger2-6.1b {
499 INSERT OR ABORT INTO tbl values (2, 2, 3);
501 } {1 {UNIQUE constraint failed: tbl.a}}
502 do_test trigger2-6.1c {
507 do_test trigger2-6.1d {
509 INSERT OR FAIL INTO tbl values (2, 2, 3);
511 } {1 {UNIQUE constraint failed: tbl.a}}
512 do_test trigger2-6.1e {
517 do_test trigger2-6.1f {
519 INSERT OR REPLACE INTO tbl values (2, 2, 3);
523 do_test trigger2-6.1g {
525 INSERT OR ROLLBACK INTO tbl values (3, 2, 3);
527 } {1 {UNIQUE constraint failed: tbl.a}}
528 do_test trigger2-6.1h {
533 execsql {DELETE FROM tbl}
536 # Handling of ON CONFLICT by UPDATE statements inside triggers
538 INSERT INTO tbl values (4, 2, 3);
539 INSERT INTO tbl values (6, 3, 4);
540 CREATE TRIGGER au_tbl AFTER UPDATE ON tbl BEGIN
541 UPDATE OR IGNORE tbl SET a = new.a, c = 10;
544 do_test trigger2-6.2a {
547 UPDATE tbl SET a = 1 WHERE a = 4;
551 do_test trigger2-6.2b {
553 UPDATE OR ABORT tbl SET a = 4 WHERE a = 1;
555 } {1 {UNIQUE constraint failed: tbl.a}}
556 do_test trigger2-6.2c {
561 do_test trigger2-6.2d {
563 UPDATE OR FAIL tbl SET a = 4 WHERE a = 1;
565 } {1 {UNIQUE constraint failed: tbl.a}}
566 do_test trigger2-6.2e {
571 do_test trigger2-6.2f.1 {
573 UPDATE OR REPLACE tbl SET a = 1 WHERE a = 4;
577 do_test trigger2-6.2f.2 {
579 INSERT INTO tbl VALUES (2, 3, 4);
583 do_test trigger2-6.2g {
585 UPDATE OR ROLLBACK tbl SET a = 4 WHERE a = 1;
587 } {1 {UNIQUE constraint failed: tbl.a}}
588 do_test trigger2-6.2h {
596 } ; # ifcapable conflict
598 # 7. Triggers on views
601 do_test trigger2-7.1 {
603 CREATE TABLE ab(a, b);
604 CREATE TABLE cd(c, d);
605 INSERT INTO ab VALUES (1, 2);
606 INSERT INTO ab VALUES (0, 0);
607 INSERT INTO cd VALUES (3, 4);
609 CREATE TABLE tlog(ii INTEGER PRIMARY KEY,
610 olda, oldb, oldc, oldd, newa, newb, newc, newd);
612 CREATE VIEW abcd AS SELECT a, b, c, d FROM ab, cd;
614 CREATE TRIGGER before_update INSTEAD OF UPDATE ON abcd BEGIN
615 INSERT INTO tlog VALUES(NULL,
616 old.a, old.b, old.c, old.d, new.a, new.b, new.c, new.d);
618 CREATE TRIGGER after_update INSTEAD OF UPDATE ON abcd BEGIN
619 INSERT INTO tlog VALUES(NULL,
620 old.a, old.b, old.c, old.d, new.a, new.b, new.c, new.d);
623 CREATE TRIGGER before_delete INSTEAD OF DELETE ON abcd BEGIN
624 INSERT INTO tlog VALUES(NULL,
625 old.a, old.b, old.c, old.d, 0, 0, 0, 0);
627 CREATE TRIGGER after_delete INSTEAD OF DELETE ON abcd BEGIN
628 INSERT INTO tlog VALUES(NULL,
629 old.a, old.b, old.c, old.d, 0, 0, 0, 0);
632 CREATE TRIGGER before_insert INSTEAD OF INSERT ON abcd BEGIN
633 INSERT INTO tlog VALUES(NULL,
634 0, 0, 0, 0, new.a, new.b, new.c, new.d);
636 CREATE TRIGGER after_insert INSTEAD OF INSERT ON abcd BEGIN
637 INSERT INTO tlog VALUES(NULL,
638 0, 0, 0, 0, new.a, new.b, new.c, new.d);
643 do_test trigger2-7.2 {
645 UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1;
646 DELETE FROM abcd WHERE a = 1;
647 INSERT INTO abcd VALUES(10, 20, 30, 40);
650 } [ list 1 1 2 3 4 100 25 3 4 \
651 2 1 2 3 4 100 25 3 4 \
654 5 0 0 0 0 10 20 30 40 \
655 6 0 0 0 0 10 20 30 40 ]
657 do_test trigger2-7.3 {
660 INSERT INTO abcd VALUES(10, 20, 30, 40);
661 UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1;
662 DELETE FROM abcd WHERE a = 1;
666 1 0 0 0 0 10 20 30 40 \
667 2 0 0 0 0 10 20 30 40 \
668 3 1 2 3 4 100 25 3 4 \
669 4 1 2 3 4 100 25 3 4 \
673 do_test trigger2-7.4 {
676 DELETE FROM abcd WHERE a = 1;
677 INSERT INTO abcd VALUES(10, 20, 30, 40);
678 UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1;
684 3 0 0 0 0 10 20 30 40 \
685 4 0 0 0 0 10 20 30 40 \
686 5 1 2 3 4 100 25 3 4 \
687 6 1 2 3 4 100 25 3 4 \
690 do_test trigger2-8.1 {
692 CREATE TABLE t1(a,b,c);
693 INSERT INTO t1 VALUES(1,2,3);
695 SELECT a+b AS x, b+c AS y, a+c AS z FROM t1;
699 do_test trigger2-8.2 {
701 CREATE TABLE v1log(a,b,c,d,e,f);
702 CREATE TRIGGER r1 INSTEAD OF DELETE ON v1 BEGIN
703 INSERT INTO v1log VALUES(OLD.x,NULL,OLD.y,NULL,OLD.z,NULL);
705 DELETE FROM v1 WHERE x=1;
709 do_test trigger2-8.3 {
711 DELETE FROM v1 WHERE x=3;
715 do_test trigger2-8.4 {
717 INSERT INTO t1 VALUES(4,5,6);
719 DELETE FROM v1 WHERE y=11;
723 do_test trigger2-8.5 {
725 CREATE TRIGGER r2 INSTEAD OF INSERT ON v1 BEGIN
726 INSERT INTO v1log VALUES(NULL,NEW.x,NULL,NEW.y,NULL,NEW.z);
729 INSERT INTO v1 VALUES(1,2,3);
733 do_test trigger2-8.6 {
735 CREATE TRIGGER r3 INSTEAD OF UPDATE ON v1 BEGIN
736 INSERT INTO v1log VALUES(OLD.x,NEW.x,OLD.y,NEW.y,OLD.z,NEW.z);
739 UPDATE v1 SET x=x+100, y=y+200, z=z+300;
742 } {3 103 5 205 4 304 9 109 11 211 10 310}
744 # At one point the following was causing a segfault.
745 do_test trigger2-9.1 {
747 CREATE TABLE t3(a TEXT, b TEXT);
748 CREATE VIEW v3 AS SELECT t3.a FROM t3;
749 CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN
752 DELETE FROM v3 WHERE a = 1;
756 integrity_check trigger2-9.99
758 # 2019-11-02 Problem found by TH3, related to generated column support.
761 do_execsql_test trigger2-10.1 {
762 CREATE TABLE t1(a,b,c,d);
763 CREATE VIEW v2(a,b,c,d) AS SELECT * FROM t1;
764 CREATE TRIGGER v2ins INSTEAD OF INSERT ON v2 BEGIN
765 INSERT INTO t1(a,b,c,d) VALUES(new.a, new.b, new.c, new.d);
767 INSERT INTO v2(a,d) VALUES(11,14);
773 #-------------------------------------------------------------------------
775 do_execsql_test 11.1 {
776 CREATE TABLE t1(a INT PRIMARY KEY, b, c REAL, d, e);
777 CREATE TABLE t2(a INT, b, c REAL, d, e, PRIMARY KEY(a,b)) WITHOUT ROWID;
778 CREATE UNIQUE INDEX t2c ON t2(c);
779 CREATE UNIQUE INDEX t2d ON t2(d);
780 CREATE UNIQUE INDEX t2e ON t2(e);
783 do_catchsql_test 11.2 {
784 CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN
785 INSERT INTO t2(a,b,c,d,e) VALUES(91,NULL,93,94,?1)
786 ON CONFLICT(b,a) DO NOTHING
787 ON CONFLICT DO UPDATE SET b=?1;
789 } {1 {trigger cannot use variables}}