Merge branch 'prerelease' of ssh://github.com/sqlcipher/sqlcipher into prerelease
[sqlcipher.git] / test / triggerC.test
blob12a5e4ac0881c28802d4b5c0ce45137ab4786f7f
1 # 2009 August 24
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice', here is a blessing:
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.
10 #***********************************************************************
13 set testdir [file dirname $argv0]
14 source $testdir/tester.tcl
15 ifcapable {!trigger} {
16   finish_test
17   return
20 #-------------------------------------------------------------------------
21 # Test organization:
23 # triggerC-1.*: Haphazardly designed trigger related tests that were useful
24 #               during an upgrade of the triggers sub-system.
25
26 # triggerC-2.*:
28 # triggerC-3.*:
30 # triggerC-4.*:
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.
37 # triggerC-6.*: Test that the recursive_triggers pragma returns correct
38 #               results when invoked without an argument.
41 # Enable recursive triggers for this file.
43 execsql { PRAGMA recursive_triggers = on }
45 #sqlite3_db_config_lookaside db 0 0 0
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.
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;
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}}
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.
168 do_test triggerC-2.1.0 {
169   execsql {
170     CREATE TABLE t2(a PRIMARY KEY);
171   }
172 } {}
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}}
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}}
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}}
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}}
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}}
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}
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
230 do_test triggerC-2.2 {
231   execsql "
232     CREATE TABLE t22(x);
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) >= [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
239                   THEN RAISE(IGNORE)
240                   ELSE NULL END;
241     END;
243     INSERT INTO t22 VALUES(1);
244     SELECT count(*) FROM t22;
245   "
246 } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
248 do_test triggerC-2.3 {
249   execsql "
250     CREATE TABLE t23(x PRIMARY KEY);
252     CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
253       INSERT INTO t23 VALUES(new.x + 1);
254     END;
256     CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
257       SELECT CASE WHEN new.x>[expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
258                   THEN RAISE(IGNORE)
259                   ELSE NULL END;
260     END;
262     INSERT INTO t23 VALUES(1);
263     SELECT count(*) FROM t23;
264   "
265 } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
268 #-----------------------------------------------------------------------
269 # This block of tests, triggerC-3.*, test that SQLite throws an exception
270 # when it detects excessive recursion.
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 } {}
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<[expr $SQLITE_MAX_TRIGGER_DEPTH * 2] 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 } {}
305 do_test triggerC-3.3.1 {
306   catchsql "
307     INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH + 1]);
308   "
309 } {0 {}}
310 do_test triggerC-3.3.2 {
311   db eval {SELECT count(*), max(x), min(x) FROM t3b}
312 } [list $SQLITE_MAX_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH + 1]]
314 do_test triggerC-3.4.1 {
315   catchsql "
316     DELETE FROM t3b;
317     INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH - 1]);
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 {} {}}
324 do_test triggerC-3.5.1 {
325   sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH  [expr $SQLITE_MAX_TRIGGER_DEPTH / 10]
326   catchsql "
327     INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]);
328   "
329 } {0 {}}
330 do_test triggerC-3.5.2 {
331   db eval {SELECT count(*), max(x), min(x) FROM t3b}
332 } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 10] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]]
334 do_test triggerC-3.5.3 {
335   catchsql "
336     DELETE FROM t3b;
337     INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10)]);
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 {} {}}
344 do_test triggerC-3.6.1 {
345   sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
346   catchsql "
347     INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH * 2]);
348   "
349 } {0 {}}
350 do_test triggerC-3.6.2 {
351   db eval {SELECT count(*), max(x), min(x) FROM t3b}
352 } [list 1 [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2]]
354 do_test triggerC-3.6.3 {
355   catchsql "
356     DELETE FROM t3b;
357     INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - 1]);
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 $SQLITE_MAX_TRIGGER_DEPTH
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.
371 # For an INSERT statement, for each row to be inserted:
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.
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.
383 # For an UPDATE statement, for each row to be deleted:
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.
391 # For a DELETE statement, for each row to be deleted:
393 #   1. Fire BEFORE triggers.
394 #   2. Remove database record.
395 #   3. Fire AFTER triggers.
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'.
402 # triggerC-4.1.*: Check that affinity transformations are made before
403 #                 triggers are invoked.
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} {
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   }
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   }
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   }
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   }
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   }
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   }
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   }
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 " "]
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.
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');
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]
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]
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]
642 do_test triggerC-5.3.8 {
643   execsql { PRAGMA recursive_triggers = on }
644 } {}
646 #-------------------------------------------------------------------------
647 # This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers"
648 # statements return the current value of the recursive triggers flag.
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}
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.
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}
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}}
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}
764 # Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643]
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}
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.
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.
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   }
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}
820 do_test triggerC-10.2 {
821   execsql {
822     UPDATE t10 SET a = 'tcl', updatecnt = 5;
823     SELECT * FROM t10;
824   }
825 } {tcl 5}
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     );
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;
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   }
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}
858 #-------------------------------------------------------------------------
859 # Test that bug [371bab5d65] has been fixed. BEFORE INSERT and INSTEAD OF
860 # INSERT triggers with the DEFAULT VALUES INSERT syntax.
862 do_test triggerC-11.0 {
863   catchsql { DROP TABLE log }
864   execsql  { CREATE TABLE log(a, b) }
865 } {}
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
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]
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
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}
919 do_test triggerC-12.1 {
920   db close
921   forcedelete test.db
922   sqlite3 db test.db
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}
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}}
954 finish_test