xref: /sqlite-3.40.0/test/triggerC.test (revision 07fcc268)
1436355a0Sdan# 2009 August 24
2436355a0Sdan#
3436355a0Sdan# The author disclaims copyright to this source code.  In place of
4436355a0Sdan# a legal notice', here is a blessing:
5436355a0Sdan#
6436355a0Sdan#    May you do good and not evil.
7436355a0Sdan#    May you find forgiveness for yourself and forgive others.
8436355a0Sdan#    May you share freely, never taking more than you give.
9436355a0Sdan#
10436355a0Sdan#***********************************************************************
11436355a0Sdan#
12436355a0Sdan
13436355a0Sdanset testdir [file dirname $argv0]
14436355a0Sdansource $testdir/tester.tcl
15436355a0Sdanifcapable {!trigger} {
16436355a0Sdan  finish_test
17436355a0Sdan  return
18436355a0Sdan}
19436355a0Sdan
202283d46cSdan#-------------------------------------------------------------------------
212283d46cSdan# Test organization:
222283d46cSdan#
232283d46cSdan# triggerC-1.*: Haphazardly designed trigger related tests that were useful
242283d46cSdan#               during an upgrade of the triggers sub-system.
252283d46cSdan#
262283d46cSdan# triggerC-2.*:
272283d46cSdan#
282283d46cSdan# triggerC-3.*:
292283d46cSdan#
302283d46cSdan# triggerC-4.*:
312283d46cSdan#
322283d46cSdan# triggerC-5.*: Test that when recursive triggers are enabled DELETE
332283d46cSdan#               triggers are fired when rows are deleted as part of OR
342283d46cSdan#               REPLACE conflict resolution. And that they are not fired
352283d46cSdan#               if recursive triggers are not enabled.
362283d46cSdan#
37e0af83acSdan# triggerC-6.*: Test that the recursive_triggers pragma returns correct
38e0af83acSdan#               results when invoked without an argument.
39e0af83acSdan#
402283d46cSdan
41436355a0Sdan# Enable recursive triggers for this file.
42436355a0Sdan#
435bde73c4Sdanexecsql { PRAGMA recursive_triggers = on }
44436355a0Sdan
45436355a0Sdan#sqlite3_db_config_lookaside db 0 0 0
46436355a0Sdan
47436355a0Sdan#-------------------------------------------------------------------------
48436355a0Sdan# This block of tests, triggerC-1.*, are not aimed at any specific
49436355a0Sdan# property of the triggers sub-system. They were created to debug
50436355a0Sdan# specific problems while modifying SQLite to support recursive
51436355a0Sdan# triggers. They are left here in case they can help debug the
52436355a0Sdan# same problems again.
53436355a0Sdan#
54436355a0Sdando_test triggerC-1.1 {
55436355a0Sdan  execsql {
56436355a0Sdan    CREATE TABLE t1(a, b, c);
57436355a0Sdan    CREATE TABLE log(t, a1, b1, c1, a2, b2, c2);
58436355a0Sdan    CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN
59436355a0Sdan      INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c);
60436355a0Sdan    END;
61436355a0Sdan    CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN
62436355a0Sdan      INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c);
63436355a0Sdan    END;
64436355a0Sdan    CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN
65436355a0Sdan      INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c);
66436355a0Sdan    END;
67436355a0Sdan    CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN
68436355a0Sdan      INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c);
69436355a0Sdan    END;
70436355a0Sdan
71436355a0Sdan    CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN
72436355a0Sdan      INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL);
73436355a0Sdan    END;
74436355a0Sdan    CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN
75436355a0Sdan      INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL);
76436355a0Sdan    END;
77436355a0Sdan  }
78436355a0Sdan} {}
79436355a0Sdando_test triggerC-1.2 {
80436355a0Sdan  execsql {
81436355a0Sdan    INSERT INTO t1 VALUES('A', 'B', 'C');
82436355a0Sdan    SELECT * FROM log;
83436355a0Sdan  }
84436355a0Sdan} {before {} {} {} A B C after {} {} {} A B C}
85436355a0Sdando_test triggerC-1.3 {
86436355a0Sdan  execsql { SELECT * FROM t1 }
87436355a0Sdan} {A B C}
88436355a0Sdando_test triggerC-1.4 {
89436355a0Sdan  execsql {
90436355a0Sdan    DELETE FROM log;
91436355a0Sdan    UPDATE t1 SET a = 'a';
92436355a0Sdan    SELECT * FROM log;
93436355a0Sdan  }
94436355a0Sdan} {before A B C a B C after A B C a B C}
95436355a0Sdando_test triggerC-1.5 {
96436355a0Sdan  execsql { SELECT * FROM t1 }
97436355a0Sdan} {a B C}
98436355a0Sdando_test triggerC-1.6 {
99436355a0Sdan  execsql {
100436355a0Sdan    DELETE FROM log;
101436355a0Sdan    DELETE FROM t1;
102436355a0Sdan    SELECT * FROM log;
103436355a0Sdan  }
104436355a0Sdan} {before a B C {} {} {} after a B C {} {} {}}
105436355a0Sdando_test triggerC-1.7 {
106436355a0Sdan  execsql { SELECT * FROM t1 }
107436355a0Sdan} {}
108436355a0Sdando_test triggerC-1.8 {
109436355a0Sdan  execsql {
110436355a0Sdan    CREATE TABLE t4(a, b);
111436355a0Sdan    CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN
112436355a0Sdan      SELECT RAISE(ABORT, 'delete is not supported');
113436355a0Sdan    END;
114436355a0Sdan  }
115436355a0Sdan} {}
116436355a0Sdando_test triggerC-1.9 {
117436355a0Sdan  execsql { INSERT INTO t4 VALUES(1, 2) }
118436355a0Sdan  catchsql { DELETE FROM t4 }
119436355a0Sdan} {1 {delete is not supported}}
120436355a0Sdando_test triggerC-1.10 {
121436355a0Sdan  execsql { SELECT * FROM t4 }
122436355a0Sdan} {1 2}
123436355a0Sdando_test triggerC-1.11 {
124436355a0Sdan  execsql {
125436355a0Sdan    CREATE TABLE t5 (a primary key, b, c);
126436355a0Sdan    INSERT INTO t5 values (1, 2, 3);
127436355a0Sdan    CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN
128436355a0Sdan      UPDATE OR IGNORE t5 SET a = new.a, c = 10;
129436355a0Sdan    END;
130436355a0Sdan  }
131436355a0Sdan} {}
132436355a0Sdando_test triggerC-1.12 {
133436355a0Sdan  catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 }
134436355a0Sdan} {1 {too many levels of trigger recursion}}
135436355a0Sdando_test triggerC-1.13 {
136436355a0Sdan  execsql {
137436355a0Sdan    CREATE TABLE t6(a INTEGER PRIMARY KEY, b);
138436355a0Sdan    INSERT INTO t6 VALUES(1, 2);
139436355a0Sdan    create trigger r1 after update on t6 for each row begin
140436355a0Sdan      SELECT 1;
141436355a0Sdan    end;
142436355a0Sdan    UPDATE t6 SET a=a;
143436355a0Sdan  }
144436355a0Sdan} {}
145436355a0Sdando_test triggerC-1.14 {
146436355a0Sdan  execsql {
147436355a0Sdan    DROP TABLE t1;
148436355a0Sdan    CREATE TABLE cnt(n);
149436355a0Sdan    INSERT INTO cnt VALUES(0);
150436355a0Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e);
151436355a0Sdan    CREATE INDEX t1cd ON t1(c,d);
152436355a0Sdan    CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END;
153436355a0Sdan    INSERT INTO t1 VALUES(1,2,3,4,5);
154436355a0Sdan    INSERT INTO t1 VALUES(6,7,8,9,10);
155436355a0Sdan    INSERT INTO t1 VALUES(11,12,13,14,15);
156436355a0Sdan  }
157436355a0Sdan} {}
158436355a0Sdando_test triggerC-1.15 {
159436355a0Sdan  catchsql { UPDATE OR ROLLBACK t1 SET a=100 }
160436355a0Sdan} {1 {PRIMARY KEY must be unique}}
161436355a0Sdan
162436355a0Sdan
163436355a0Sdan#-------------------------------------------------------------------------
164436355a0Sdan# This block of tests, triggerC-2.*, tests that recursive trigger
165436355a0Sdan# programs (triggers that fire themselves) work. More specifically,
166436355a0Sdan# this block focuses on recursive INSERT triggers.
167436355a0Sdan#
168436355a0Sdando_test triggerC-2.1.0 {
169436355a0Sdan  execsql {
170436355a0Sdan    CREATE TABLE t2(a PRIMARY KEY);
171436355a0Sdan  }
172436355a0Sdan} {}
173436355a0Sdan
174436355a0Sdanforeach {n tdefn rc} {
175436355a0Sdan  1 {
176436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
177436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
178436355a0Sdan    END;
179436355a0Sdan  } {0 {10 9 8 7 6 5 4 3 2 1 0}}
180436355a0Sdan
181436355a0Sdan  2 {
182436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN
183436355a0Sdan      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
184436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
185436355a0Sdan    END;
186436355a0Sdan  } {0 {10 9 8 7 6 5 4 3 2}}
187436355a0Sdan
188436355a0Sdan  3 {
189436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
190436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
191436355a0Sdan    END;
192436355a0Sdan  } {0 {0 1 2 3 4 5 6 7 8 9 10}}
193436355a0Sdan
194436355a0Sdan  4 {
195436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
196436355a0Sdan      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
197436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
198436355a0Sdan    END;
199436355a0Sdan  } {0 {3 4 5 6 7 8 9 10}}
200436355a0Sdan
201436355a0Sdan  5 {
202436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
203436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
204436355a0Sdan    END;
205436355a0Sdan  } {1 {too many levels of trigger recursion}}
206436355a0Sdan
207436355a0Sdan  6 {
208436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
209436355a0Sdan      INSERT OR IGNORE INTO t2 VALUES(new.a);
210436355a0Sdan    END;
211436355a0Sdan  } {0 10}
212436355a0Sdan
213436355a0Sdan  7 {
214436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
215436355a0Sdan      INSERT OR IGNORE INTO t2 VALUES(new.a);
216436355a0Sdan    END;
217436355a0Sdan  } {1 {too many levels of trigger recursion}}
218436355a0Sdan} {
219436355a0Sdan  do_test triggerC-2.1.$n {
220436355a0Sdan    catchsql { DROP TRIGGER t2_trig }
221436355a0Sdan    execsql  { DELETE FROM t2 }
222436355a0Sdan    execsql  $tdefn
223436355a0Sdan    catchsql {
224436355a0Sdan      INSERT INTO t2 VALUES(10);
225436355a0Sdan      SELECT * FROM t2;
226436355a0Sdan    }
227436355a0Sdan  } $rc
228436355a0Sdan}
229436355a0Sdan
230436355a0Sdando_test triggerC-2.2 {
231436355a0Sdan  execsql {
232436355a0Sdan    CREATE TABLE t22(x);
233436355a0Sdan
234436355a0Sdan    CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN
235436355a0Sdan      INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22;
236436355a0Sdan    END;
237436355a0Sdan    CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN
238436355a0Sdan      SELECT CASE WHEN (SELECT count(*) FROM t22) >= 100
239436355a0Sdan                  THEN RAISE(IGNORE)
240436355a0Sdan                  ELSE NULL END;
241436355a0Sdan    END;
242436355a0Sdan
243436355a0Sdan    INSERT INTO t22 VALUES(1);
244436355a0Sdan    SELECT count(*) FROM t22;
245436355a0Sdan  }
246436355a0Sdan} {100}
247436355a0Sdan
248436355a0Sdando_test triggerC-2.3 {
249436355a0Sdan  execsql {
250436355a0Sdan    CREATE TABLE t23(x PRIMARY KEY);
251436355a0Sdan
252436355a0Sdan    CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
253436355a0Sdan      INSERT INTO t23 VALUES(new.x + 1);
254436355a0Sdan    END;
255436355a0Sdan
256436355a0Sdan    CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
257436355a0Sdan      SELECT CASE WHEN new.x>500
258436355a0Sdan                  THEN RAISE(IGNORE)
259436355a0Sdan                  ELSE NULL END;
260436355a0Sdan    END;
261436355a0Sdan
262436355a0Sdan    INSERT INTO t23 VALUES(1);
263436355a0Sdan    SELECT count(*) FROM t23;
264436355a0Sdan  }
265436355a0Sdan} {500}
266436355a0Sdan
267436355a0Sdan
268436355a0Sdan#-----------------------------------------------------------------------
269436355a0Sdan# This block of tests, triggerC-3.*, test that SQLite throws an exception
270436355a0Sdan# when it detects excessive recursion.
271436355a0Sdan#
272436355a0Sdando_test triggerC-3.1.1 {
273436355a0Sdan  execsql {
274436355a0Sdan    CREATE TABLE t3(a, b);
275436355a0Sdan    CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN
276436355a0Sdan      DELETE FROM t3 WHERE rowid = new.rowid;
277436355a0Sdan    END;
278436355a0Sdan    CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN
279436355a0Sdan      INSERT INTO t3 VALUES(old.a, old.b);
280436355a0Sdan    END;
281436355a0Sdan  }
282436355a0Sdan} {}
283436355a0Sdando_test triggerC-3.1.2 {
284436355a0Sdan  catchsql { INSERT INTO t3 VALUES(0,0) }
285436355a0Sdan} {1 {too many levels of trigger recursion}}
286436355a0Sdando_test triggerC-3.1.3 {
287436355a0Sdan  execsql { SELECT * FROM t3 }
288436355a0Sdan} {}
289436355a0Sdan
290417168adSdrhdo_test triggerC-3.2.1 {
291417168adSdrh  execsql {
292417168adSdrh    CREATE TABLE t3b(x);
293417168adSdrh    CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<2000 BEGIN
294417168adSdrh      INSERT INTO t3b VALUES(new.x+1);
295417168adSdrh    END;
296417168adSdrh  }
297417168adSdrh  catchsql {
298417168adSdrh    INSERT INTO t3b VALUES(1);
299417168adSdrh  }
300417168adSdrh} {1 {too many levels of trigger recursion}}
301417168adSdrhdo_test triggerC-3.2.2 {
302417168adSdrh  db eval {SELECT * FROM t3b}
303417168adSdrh} {}
304417168adSdrh
305417168adSdrhdo_test triggerC-3.3.1 {
306417168adSdrh  catchsql {
307*07fcc268Sdan    INSERT INTO t3b VALUES(1001);
308417168adSdrh  }
309417168adSdrh} {0 {}}
310417168adSdrhdo_test triggerC-3.3.2 {
311417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
312*07fcc268Sdan} {1000 2000 1001}
313417168adSdrh
314417168adSdrhdo_test triggerC-3.4.1 {
315417168adSdrh  catchsql {
316417168adSdrh    DELETE FROM t3b;
317417168adSdrh    INSERT INTO t3b VALUES(999);
318417168adSdrh  }
319417168adSdrh} {1 {too many levels of trigger recursion}}
320417168adSdrhdo_test triggerC-3.4.2 {
321417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
322417168adSdrh} {0 {} {}}
323417168adSdrh
324417168adSdrhdo_test triggerC-3.5.1 {
325417168adSdrh  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 100
326417168adSdrh  catchsql {
327*07fcc268Sdan    INSERT INTO t3b VALUES(1901);
328417168adSdrh  }
329417168adSdrh} {0 {}}
330417168adSdrhdo_test triggerC-3.5.2 {
331417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
332*07fcc268Sdan} {100 2000 1901}
333417168adSdrh
334417168adSdrhdo_test triggerC-3.5.3 {
335417168adSdrh  catchsql {
336417168adSdrh    DELETE FROM t3b;
337*07fcc268Sdan    INSERT INTO t3b VALUES(1900);
338417168adSdrh  }
339417168adSdrh} {1 {too many levels of trigger recursion}}
340417168adSdrhdo_test triggerC-3.5.4 {
341417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
342417168adSdrh} {0 {} {}}
343417168adSdrh
344417168adSdrhdo_test triggerC-3.6.1 {
345417168adSdrh  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
346417168adSdrh  catchsql {
347*07fcc268Sdan    INSERT INTO t3b VALUES(2000);
348417168adSdrh  }
349417168adSdrh} {0 {}}
350417168adSdrhdo_test triggerC-3.6.2 {
351417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
352*07fcc268Sdan} {1 2000 2000}
353417168adSdrh
354417168adSdrhdo_test triggerC-3.6.3 {
355417168adSdrh  catchsql {
356417168adSdrh    DELETE FROM t3b;
357*07fcc268Sdan    INSERT INTO t3b VALUES(1999);
358417168adSdrh  }
359417168adSdrh} {1 {too many levels of trigger recursion}}
360417168adSdrhdo_test triggerC-3.6.4 {
361417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
362417168adSdrh} {0 {} {}}
363417168adSdrhsqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000
364417168adSdrh
365417168adSdrh
366436355a0Sdan#-----------------------------------------------------------------------
367436355a0Sdan# This next block of tests, triggerC-4.*, checks that affinity
368436355a0Sdan# transformations and constraint processing is performed at the correct
369436355a0Sdan# times relative to BEFORE and AFTER triggers.
370436355a0Sdan#
371436355a0Sdan# For an INSERT statement, for each row to be inserted:
372436355a0Sdan#
373436355a0Sdan#   1. Apply affinities to non-rowid values to be inserted.
374436355a0Sdan#   2. Fire BEFORE triggers.
375436355a0Sdan#   3. Process constraints.
376436355a0Sdan#   4. Insert new record.
377436355a0Sdan#   5. Fire AFTER triggers.
378436355a0Sdan#
379436355a0Sdan# If the value of the rowid field is to be automatically assigned, it is
380436355a0Sdan# set to -1 in the new.* record. Even if it is explicitly set to NULL
381436355a0Sdan# by the INSERT statement.
382436355a0Sdan#
383436355a0Sdan# For an UPDATE statement, for each row to be deleted:
384436355a0Sdan#
385436355a0Sdan#   1. Apply affinities to non-rowid values to be inserted.
386436355a0Sdan#   2. Fire BEFORE triggers.
387436355a0Sdan#   3. Process constraints.
388436355a0Sdan#   4. Insert new record.
389436355a0Sdan#   5. Fire AFTER triggers.
390436355a0Sdan#
391436355a0Sdan# For a DELETE statement, for each row to be deleted:
392436355a0Sdan#
393436355a0Sdan#   1. Fire BEFORE triggers.
394436355a0Sdan#   2. Remove database record.
395436355a0Sdan#   3. Fire AFTER triggers.
396436355a0Sdan#
397436355a0Sdan# When a numeric value that as an exact integer representation is stored
398436355a0Sdan# in a column with REAL affinity, it is actually stored as an integer.
399436355a0Sdan# These tests check that the typeof() such values is always 'real',
400436355a0Sdan# not 'integer'.
401436355a0Sdan#
402436355a0Sdan# triggerC-4.1.*: Check that affinity transformations are made before
403436355a0Sdan#                 triggers are invoked.
404436355a0Sdan#
405436355a0Sdando_test triggerC-4.1.1 {
406436355a0Sdan  catchsql { DROP TABLE log }
407436355a0Sdan  catchsql { DROP TABLE t4 }
408436355a0Sdan  execsql {
409436355a0Sdan    CREATE TABLE log(t);
410436355a0Sdan    CREATE TABLE t4(a TEXT,b INTEGER,c REAL);
411436355a0Sdan    CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN
412436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
413436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
414436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
415436355a0Sdan                             new.c     || ' ' || typeof(new.c)
416436355a0Sdan      );
417436355a0Sdan    END;
418436355a0Sdan    CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN
419436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
420436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
421436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
422436355a0Sdan                             new.c     || ' ' || typeof(new.c)
423436355a0Sdan      );
424436355a0Sdan    END;
425436355a0Sdan    CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN
426436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
427436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
428436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
429436355a0Sdan                             old.c     || ' ' || typeof(old.c)
430436355a0Sdan      );
431436355a0Sdan    END;
432436355a0Sdan    CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN
433436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
434436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
435436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
436436355a0Sdan                             old.c     || ' ' || typeof(old.c)
437436355a0Sdan      );
438436355a0Sdan    END;
439436355a0Sdan    CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN
440436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
441436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
442436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
443436355a0Sdan                             old.c     || ' ' || typeof(old.c)
444436355a0Sdan      );
445436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
446436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
447436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
448436355a0Sdan                             new.c     || ' ' || typeof(new.c)
449436355a0Sdan      );
450436355a0Sdan    END;
451436355a0Sdan    CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN
452436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
453436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
454436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
455436355a0Sdan                             old.c     || ' ' || typeof(old.c)
456436355a0Sdan      );
457436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
458436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
459436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
460436355a0Sdan                             new.c     || ' ' || typeof(new.c)
461436355a0Sdan      );
462436355a0Sdan    END;
463436355a0Sdan  }
464436355a0Sdan} {}
465436355a0Sdanforeach {n insert log} {
466436355a0Sdan
467436355a0Sdan  2 {
468436355a0Sdan   INSERT INTO t4 VALUES('1', '1', '1');
469436355a0Sdan   DELETE FROM t4;
470436355a0Sdan  } {
471436355a0Sdan    -1 integer 1 text 1 integer 1.0 real
472436355a0Sdan     1 integer 1 text 1 integer 1.0 real
473436355a0Sdan     1 integer 1 text 1 integer 1.0 real
474436355a0Sdan     1 integer 1 text 1 integer 1.0 real
475436355a0Sdan  }
476436355a0Sdan
477436355a0Sdan  3 {
478436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45);
479436355a0Sdan   DELETE FROM t4;
480436355a0Sdan  } {
481436355a0Sdan    45 integer 45 text 45 integer 45.0 real
482436355a0Sdan    45 integer 45 text 45 integer 45.0 real
483436355a0Sdan    45 integer 45 text 45 integer 45.0 real
484436355a0Sdan    45 integer 45 text 45 integer 45.0 real
485436355a0Sdan  }
486436355a0Sdan
487436355a0Sdan  4 {
488436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0);
489436355a0Sdan   DELETE FROM t4;
490436355a0Sdan  } {
491436355a0Sdan    -42 integer -42.0 text -42 integer -42.0 real
492436355a0Sdan    -42 integer -42.0 text -42 integer -42.0 real
493436355a0Sdan    -42 integer -42.0 text -42 integer -42.0 real
494436355a0Sdan    -42 integer -42.0 text -42 integer -42.0 real
495436355a0Sdan  }
496436355a0Sdan
497436355a0Sdan  5 {
498436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4);
499436355a0Sdan   DELETE FROM t4;
500436355a0Sdan  } {
501436355a0Sdan    -1 integer -42.4 text -42.4 real -42.4 real
502436355a0Sdan     1 integer -42.4 text -42.4 real -42.4 real
503436355a0Sdan     1 integer -42.4 text -42.4 real -42.4 real
504436355a0Sdan     1 integer -42.4 text -42.4 real -42.4 real
505436355a0Sdan  }
506436355a0Sdan
507436355a0Sdan  6 {
508436355a0Sdan   INSERT INTO t4 VALUES(7, 7, 7);
509436355a0Sdan   UPDATE t4 SET a=8, b=8, c=8;
510436355a0Sdan  } {
511436355a0Sdan    -1 integer 7 text 7 integer 7.0 real
512436355a0Sdan     1 integer 7 text 7 integer 7.0 real
513436355a0Sdan     1 integer 7 text 7 integer 7.0 real
514436355a0Sdan     1 integer 8 text 8 integer 8.0 real
515436355a0Sdan     1 integer 7 text 7 integer 7.0 real
516436355a0Sdan     1 integer 8 text 8 integer 8.0 real
517436355a0Sdan  }
518436355a0Sdan
519436355a0Sdan  7 {
520436355a0Sdan   UPDATE t4 SET rowid=2;
521436355a0Sdan  } {
522436355a0Sdan     1 integer 8 text 8 integer 8.0 real
523436355a0Sdan     2 integer 8 text 8 integer 8.0 real
524436355a0Sdan     1 integer 8 text 8 integer 8.0 real
525436355a0Sdan     2 integer 8 text 8 integer 8.0 real
526436355a0Sdan  }
527436355a0Sdan
528436355a0Sdan  8 {
529436355a0Sdan   UPDATE t4 SET a='9', b='9', c='9';
530436355a0Sdan  } {
531436355a0Sdan     2 integer 8 text 8 integer 8.0 real
532436355a0Sdan     2 integer 9 text 9 integer 9.0 real
533436355a0Sdan     2 integer 8 text 8 integer 8.0 real
534436355a0Sdan     2 integer 9 text 9 integer 9.0 real
535436355a0Sdan  }
536436355a0Sdan
537436355a0Sdan  9 {
538436355a0Sdan   UPDATE t4 SET a='9.1', b='9.1', c='9.1';
539436355a0Sdan  } {
540436355a0Sdan     2 integer 9   text 9   integer 9.0 real
541436355a0Sdan     2 integer 9.1 text 9.1 real    9.1 real
542436355a0Sdan     2 integer 9   text 9   integer 9.0 real
543436355a0Sdan     2 integer 9.1 text 9.1 real    9.1 real
544436355a0Sdan  }
545436355a0Sdan} {
546436355a0Sdan  do_test triggerC-4.1.$n {
547436355a0Sdan    eval concat [execsql "
548436355a0Sdan      DELETE FROM log;
549436355a0Sdan      $insert ;
550436355a0Sdan      SELECT * FROM log;
551436355a0Sdan    "]
552436355a0Sdan  } [join $log " "]
553436355a0Sdan}
554436355a0Sdan
5552283d46cSdan#-------------------------------------------------------------------------
5562283d46cSdan# This block of tests, triggerC-5.*, test that DELETE triggers are fired
5572283d46cSdan# if a row is deleted as a result of OR REPLACE conflict resolution.
5582283d46cSdan#
5592283d46cSdando_test triggerC-5.1.0 {
5602283d46cSdan  execsql {
5612283d46cSdan    DROP TABLE IF EXISTS t5;
5622283d46cSdan    CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
5632283d46cSdan    CREATE UNIQUE INDEX t5i ON t5(b);
5642283d46cSdan    INSERT INTO t5 VALUES(1, 'a');
5652283d46cSdan    INSERT INTO t5 VALUES(2, 'b');
5662283d46cSdan    INSERT INTO t5 VALUES(3, 'c');
5672283d46cSdan
5682283d46cSdan    CREATE TABLE t5g(a, b, c);
5692283d46cSdan    CREATE TRIGGER t5t BEFORE DELETE ON t5 BEGIN
5702283d46cSdan      INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
5712283d46cSdan    END;
5722283d46cSdan  }
5732283d46cSdan} {}
5742283d46cSdanforeach {n dml t5g t5} {
5752283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 3} {1 a 3 c}
5762283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 3} {1 a 2 d 3 c}
5772283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 3} {1 a 2 c}
5782283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 3} {1 a 3 c 4 b}
5792283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 3} {1 a 3 b}
5802283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 3 3 c 2} {1 a 2 c}
5812283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 3 2 b 2} {1 b}
5822283d46cSdan} {
5832283d46cSdan  do_test triggerC-5.1.$n {
5842283d46cSdan    execsql "
5852283d46cSdan      BEGIN;
5862283d46cSdan        $dml ;
5872283d46cSdan        SELECT * FROM t5g;
5882283d46cSdan        SELECT * FROM t5;
5892283d46cSdan      ROLLBACK;
5902283d46cSdan    "
5912283d46cSdan  } [concat $t5g $t5]
5922283d46cSdan}
5932283d46cSdando_test triggerC-5.2.0 {
5942283d46cSdan  execsql {
5952283d46cSdan    DROP TRIGGER t5t;
5962283d46cSdan    CREATE TRIGGER t5t AFTER DELETE ON t5 BEGIN
5972283d46cSdan      INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
5982283d46cSdan    END;
5992283d46cSdan  }
6002283d46cSdan} {}
6012283d46cSdanforeach {n dml t5g t5} {
6022283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
6032283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 2} {1 a 2 d 3 c}
6042283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 2} {1 a 2 c}
6052283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 2} {1 a 3 c 4 b}
6062283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 2} {1 a 3 b}
6072283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 2 3 c 1} {1 a 2 c}
6082283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 2 2 b 1} {1 b}
6092283d46cSdan} {
6102283d46cSdan  do_test triggerC-5.2.$n {
6112283d46cSdan    execsql "
6122283d46cSdan      BEGIN;
6132283d46cSdan        $dml ;
6142283d46cSdan        SELECT * FROM t5g;
6152283d46cSdan        SELECT * FROM t5;
6162283d46cSdan      ROLLBACK;
6172283d46cSdan    "
6182283d46cSdan  } [concat $t5g $t5]
6192283d46cSdan}
6202283d46cSdando_test triggerC-5.3.0 {
6212283d46cSdan  execsql { PRAGMA recursive_triggers = off }
6222283d46cSdan} {}
6232283d46cSdanforeach {n dml t5g t5} {
6242283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
6252283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {} {1 a 2 d 3 c}
6262283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {} {1 a 2 c}
6272283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {} {1 a 3 c 4 b}
6282283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {} {1 a 3 b}
6292283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {} {1 a 2 c}
6302283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {} {1 b}
6312283d46cSdan} {
6322283d46cSdan  do_test triggerC-5.3.$n {
6332283d46cSdan    execsql "
6342283d46cSdan      BEGIN;
6352283d46cSdan        $dml ;
6362283d46cSdan        SELECT * FROM t5g;
6372283d46cSdan        SELECT * FROM t5;
6382283d46cSdan      ROLLBACK;
6392283d46cSdan    "
6402283d46cSdan  } [concat $t5g $t5]
6412283d46cSdan}
6422283d46cSdando_test triggerC-5.3.8 {
6432283d46cSdan  execsql { PRAGMA recursive_triggers = on }
6442283d46cSdan} {}
6452283d46cSdan
6462283d46cSdan#-------------------------------------------------------------------------
6472283d46cSdan# This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers"
6482283d46cSdan# statements return the current value of the recursive triggers flag.
6492283d46cSdan#
6502283d46cSdando_test triggerC-6.1 {
6512283d46cSdan  execsql { PRAGMA recursive_triggers }
6522283d46cSdan} {1}
6532283d46cSdando_test triggerC-6.2 {
6542283d46cSdan  execsql {
6552283d46cSdan    PRAGMA recursive_triggers = off;
6562283d46cSdan    PRAGMA recursive_triggers;
6572283d46cSdan  }
6582283d46cSdan} {0}
6592283d46cSdando_test triggerC-6.3 {
6602283d46cSdan  execsql {
6612283d46cSdan    PRAGMA recursive_triggers = on;
6622283d46cSdan    PRAGMA recursive_triggers;
6632283d46cSdan  }
6642283d46cSdan} {1}
6652283d46cSdan
666e0af83acSdan#-------------------------------------------------------------------------
667e0af83acSdan# Test some of the "undefined behaviour" associated with triggers. The
668e0af83acSdan# undefined behaviour occurs when a row being updated or deleted is
669e0af83acSdan# manipulated by a BEFORE trigger.
670e0af83acSdan#
671ae0931edSdando_test triggerC-7.1 {
672ae0931edSdan  execsql {
673ae0931edSdan    CREATE TABLE t8(x);
674ae0931edSdan    CREATE TABLE t7(a, b);
675ae0931edSdan    INSERT INTO t7 VALUES(1, 2);
676ae0931edSdan    INSERT INTO t7 VALUES(3, 4);
677ae0931edSdan    INSERT INTO t7 VALUES(5, 6);
678ae0931edSdan    CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN
679ae0931edSdan      DELETE FROM t7 WHERE a = 1;
680ae0931edSdan    END;
681ae0931edSdan    CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN
682ae0931edSdan      INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid);
683ae0931edSdan    END;
684ae0931edSdan  }
685ae0931edSdan} {}
686ae0931edSdando_test triggerC-7.2 {
687ae0931edSdan  execsql {
688ae0931edSdan    BEGIN;
689ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 5;
690ae0931edSdan      SELECT * FROM t7;
691ae0931edSdan      SELECT * FROM t8;
692ae0931edSdan    ROLLBACK;
693ae0931edSdan  }
694ae0931edSdan} {3 4 5 7 {after fired 3->3}}
695ae0931edSdando_test triggerC-7.3 {
696ae0931edSdan  execsql {
697ae0931edSdan    BEGIN;
698ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 1;
699ae0931edSdan      SELECT * FROM t7;
700ae0931edSdan      SELECT * FROM t8;
701ae0931edSdan    ROLLBACK;
702ae0931edSdan  }
703ae0931edSdan} {3 4 5 6}
704ae0931edSdan
705ae0931edSdando_test triggerC-7.4 {
706ae0931edSdan  execsql {
707ae0931edSdan    DROP TRIGGER t7t;
708ae0931edSdan    CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8)
709ae0931edSdan    BEGIN
710ae0931edSdan      UPDATE t7 set rowid = 8 WHERE rowid=1;
711ae0931edSdan    END;
712ae0931edSdan  }
713ae0931edSdan} {}
714ae0931edSdando_test triggerC-7.5 {
715ae0931edSdan  execsql {
716ae0931edSdan    BEGIN;
717ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 5;
718ae0931edSdan      SELECT rowid, * FROM t7;
719ae0931edSdan      SELECT * FROM t8;
720ae0931edSdan    ROLLBACK;
721ae0931edSdan  }
722ae0931edSdan} {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}}
723ae0931edSdando_test triggerC-7.6 {
724ae0931edSdan  execsql {
725ae0931edSdan    BEGIN;
726ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 1;
727ae0931edSdan      SELECT rowid, * FROM t7;
728ae0931edSdan      SELECT * FROM t8;
729ae0931edSdan    ROLLBACK;
730ae0931edSdan  }
731ae0931edSdan} {2 3 4 3 5 6 8 1 2 {after fired 1->8}}
732ae0931edSdan
733ae0931edSdando_test triggerC-7.7 {
734ae0931edSdan  execsql {
735ae0931edSdan    DROP TRIGGER t7t;
736ae0931edSdan    DROP TRIGGER t7ta;
737ae0931edSdan    CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN
738ae0931edSdan      UPDATE t7 set rowid = 8 WHERE rowid=1;
739ae0931edSdan    END;
740ae0931edSdan    CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN
741ae0931edSdan      INSERT INTO t8 VALUES('after fired ' || old.rowid);
742ae0931edSdan    END;
743ae0931edSdan  }
744ae0931edSdan} {}
745ae0931edSdando_test triggerC-7.8 {
746ae0931edSdan  execsql {
747ae0931edSdan    BEGIN;
748ae0931edSdan      DELETE FROM t7 WHERE a = 3;
749ae0931edSdan      SELECT rowid, * FROM t7;
750ae0931edSdan      SELECT * FROM t8;
751ae0931edSdan    ROLLBACK;
752ae0931edSdan  }
753ae0931edSdan} {3 5 6 8 1 2 {after fired 2}}
754ae0931edSdando_test triggerC-7.9 {
755ae0931edSdan  execsql {
756ae0931edSdan    BEGIN;
757ae0931edSdan      DELETE FROM t7 WHERE a = 1;
758ae0931edSdan      SELECT rowid, * FROM t7;
759ae0931edSdan      SELECT * FROM t8;
760ae0931edSdan    ROLLBACK;
761ae0931edSdan  }
762ae0931edSdan} {2 3 4 3 5 6 8 1 2}
763e0af83acSdan
7643991bb0dSdrh# Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643]
7653991bb0dSdrh#
7663991bb0dSdrhdo_test triggerC-9.1 {
7673991bb0dSdrh  execsql {
7683991bb0dSdrh    CREATE TABLE t9(a,b);
7693991bb0dSdrh    CREATE INDEX t9b ON t9(b);
7703991bb0dSdrh    INSERT INTO t9 VALUES(1,0);
7713991bb0dSdrh    INSERT INTO t9 VALUES(2,1);
7723991bb0dSdrh    INSERT INTO t9 VALUES(3,2);
7733991bb0dSdrh    INSERT INTO t9 SELECT a+3, a+2 FROM t9;
7743991bb0dSdrh    INSERT INTO t9 SELECT a+6, a+5 FROM t9;
7753991bb0dSdrh    SELECT a FROM t9 ORDER BY a;
7763991bb0dSdrh  }
7773991bb0dSdrh} {1 2 3 4 5 6 7 8 9 10 11 12}
7783991bb0dSdrhdo_test triggerC-9.2 {
7793991bb0dSdrh  execsql {
7803991bb0dSdrh    CREATE TRIGGER t9r1 AFTER DELETE ON t9 BEGIN
7813991bb0dSdrh      DELETE FROM t9 WHERE b=old.a;
7823991bb0dSdrh    END;
7833991bb0dSdrh    DELETE FROM t9 WHERE b=4;
7843991bb0dSdrh    SELECT a FROM t9 ORDER BY a;
7853991bb0dSdrh  }
7863991bb0dSdrh} {1 2 3 4}
7873991bb0dSdrh
7883991bb0dSdrh
7893991bb0dSdrh
7902283d46cSdan
791436355a0Sdanfinish_test
792