xref: /sqlite-3.40.0/test/triggerC.test (revision 175b8f06)
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
1546408354Sdanset testprefix triggerC
16436355a0Sdanifcapable {!trigger} {
17436355a0Sdan  finish_test
18436355a0Sdan  return
19436355a0Sdan}
20436355a0Sdan
212283d46cSdan#-------------------------------------------------------------------------
222283d46cSdan# Test organization:
232283d46cSdan#
242283d46cSdan# triggerC-1.*: Haphazardly designed trigger related tests that were useful
252283d46cSdan#               during an upgrade of the triggers sub-system.
262283d46cSdan#
272283d46cSdan# triggerC-2.*:
282283d46cSdan#
292283d46cSdan# triggerC-3.*:
302283d46cSdan#
312283d46cSdan# triggerC-4.*:
322283d46cSdan#
332283d46cSdan# triggerC-5.*: Test that when recursive triggers are enabled DELETE
342283d46cSdan#               triggers are fired when rows are deleted as part of OR
352283d46cSdan#               REPLACE conflict resolution. And that they are not fired
362283d46cSdan#               if recursive triggers are not enabled.
372283d46cSdan#
38e0af83acSdan# triggerC-6.*: Test that the recursive_triggers pragma returns correct
39e0af83acSdan#               results when invoked without an argument.
40e0af83acSdan#
412283d46cSdan
42436355a0Sdan# Enable recursive triggers for this file.
43436355a0Sdan#
445bde73c4Sdanexecsql { PRAGMA recursive_triggers = on }
45436355a0Sdan
46436355a0Sdan#sqlite3_db_config_lookaside db 0 0 0
47436355a0Sdan
48436355a0Sdan#-------------------------------------------------------------------------
49436355a0Sdan# This block of tests, triggerC-1.*, are not aimed at any specific
50436355a0Sdan# property of the triggers sub-system. They were created to debug
51436355a0Sdan# specific problems while modifying SQLite to support recursive
52436355a0Sdan# triggers. They are left here in case they can help debug the
53436355a0Sdan# same problems again.
54436355a0Sdan#
55436355a0Sdando_test triggerC-1.1 {
56436355a0Sdan  execsql {
57436355a0Sdan    CREATE TABLE t1(a, b, c);
58436355a0Sdan    CREATE TABLE log(t, a1, b1, c1, a2, b2, c2);
59436355a0Sdan    CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN
60436355a0Sdan      INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c);
61436355a0Sdan    END;
62436355a0Sdan    CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN
63436355a0Sdan      INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c);
64436355a0Sdan    END;
65436355a0Sdan    CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN
66436355a0Sdan      INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c);
67436355a0Sdan    END;
68436355a0Sdan    CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN
69436355a0Sdan      INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c);
70436355a0Sdan    END;
71436355a0Sdan
72436355a0Sdan    CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN
73436355a0Sdan      INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL);
74436355a0Sdan    END;
75436355a0Sdan    CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN
76436355a0Sdan      INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL);
77436355a0Sdan    END;
78436355a0Sdan  }
79436355a0Sdan} {}
80436355a0Sdando_test triggerC-1.2 {
81436355a0Sdan  execsql {
82436355a0Sdan    INSERT INTO t1 VALUES('A', 'B', 'C');
83436355a0Sdan    SELECT * FROM log;
84436355a0Sdan  }
85436355a0Sdan} {before {} {} {} A B C after {} {} {} A B C}
86436355a0Sdando_test triggerC-1.3 {
87436355a0Sdan  execsql { SELECT * FROM t1 }
88436355a0Sdan} {A B C}
89436355a0Sdando_test triggerC-1.4 {
90436355a0Sdan  execsql {
91436355a0Sdan    DELETE FROM log;
92436355a0Sdan    UPDATE t1 SET a = 'a';
93436355a0Sdan    SELECT * FROM log;
94436355a0Sdan  }
95436355a0Sdan} {before A B C a B C after A B C a B C}
96436355a0Sdando_test triggerC-1.5 {
97436355a0Sdan  execsql { SELECT * FROM t1 }
98436355a0Sdan} {a B C}
99436355a0Sdando_test triggerC-1.6 {
100436355a0Sdan  execsql {
101436355a0Sdan    DELETE FROM log;
102436355a0Sdan    DELETE FROM t1;
103436355a0Sdan    SELECT * FROM log;
104436355a0Sdan  }
105436355a0Sdan} {before a B C {} {} {} after a B C {} {} {}}
106436355a0Sdando_test triggerC-1.7 {
107436355a0Sdan  execsql { SELECT * FROM t1 }
108436355a0Sdan} {}
109436355a0Sdando_test triggerC-1.8 {
110436355a0Sdan  execsql {
111436355a0Sdan    CREATE TABLE t4(a, b);
112436355a0Sdan    CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN
113436355a0Sdan      SELECT RAISE(ABORT, 'delete is not supported');
114436355a0Sdan    END;
115436355a0Sdan  }
116436355a0Sdan} {}
117436355a0Sdando_test triggerC-1.9 {
118436355a0Sdan  execsql { INSERT INTO t4 VALUES(1, 2) }
119436355a0Sdan  catchsql { DELETE FROM t4 }
120436355a0Sdan} {1 {delete is not supported}}
121436355a0Sdando_test triggerC-1.10 {
122436355a0Sdan  execsql { SELECT * FROM t4 }
123436355a0Sdan} {1 2}
124436355a0Sdando_test triggerC-1.11 {
125436355a0Sdan  execsql {
126436355a0Sdan    CREATE TABLE t5 (a primary key, b, c);
127436355a0Sdan    INSERT INTO t5 values (1, 2, 3);
128436355a0Sdan    CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN
129436355a0Sdan      UPDATE OR IGNORE t5 SET a = new.a, c = 10;
130436355a0Sdan    END;
131436355a0Sdan  }
132436355a0Sdan} {}
133436355a0Sdando_test triggerC-1.12 {
134436355a0Sdan  catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 }
135436355a0Sdan} {1 {too many levels of trigger recursion}}
136436355a0Sdando_test triggerC-1.13 {
137436355a0Sdan  execsql {
138436355a0Sdan    CREATE TABLE t6(a INTEGER PRIMARY KEY, b);
139436355a0Sdan    INSERT INTO t6 VALUES(1, 2);
140436355a0Sdan    create trigger r1 after update on t6 for each row begin
141436355a0Sdan      SELECT 1;
142436355a0Sdan    end;
143436355a0Sdan    UPDATE t6 SET a=a;
144436355a0Sdan  }
145436355a0Sdan} {}
146436355a0Sdando_test triggerC-1.14 {
147436355a0Sdan  execsql {
148436355a0Sdan    DROP TABLE t1;
149436355a0Sdan    CREATE TABLE cnt(n);
150436355a0Sdan    INSERT INTO cnt VALUES(0);
151436355a0Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e);
152436355a0Sdan    CREATE INDEX t1cd ON t1(c,d);
153436355a0Sdan    CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END;
154436355a0Sdan    INSERT INTO t1 VALUES(1,2,3,4,5);
155436355a0Sdan    INSERT INTO t1 VALUES(6,7,8,9,10);
156436355a0Sdan    INSERT INTO t1 VALUES(11,12,13,14,15);
157436355a0Sdan  }
158436355a0Sdan} {}
159436355a0Sdando_test triggerC-1.15 {
160436355a0Sdan  catchsql { UPDATE OR ROLLBACK t1 SET a=100 }
161f9c8ce3cSdrh} {1 {UNIQUE constraint failed: t1.a}}
162436355a0Sdan
163436355a0Sdan
164436355a0Sdan#-------------------------------------------------------------------------
165436355a0Sdan# This block of tests, triggerC-2.*, tests that recursive trigger
166436355a0Sdan# programs (triggers that fire themselves) work. More specifically,
167436355a0Sdan# this block focuses on recursive INSERT triggers.
168436355a0Sdan#
169436355a0Sdando_test triggerC-2.1.0 {
170436355a0Sdan  execsql {
171436355a0Sdan    CREATE TABLE t2(a PRIMARY KEY);
172436355a0Sdan  }
173436355a0Sdan} {}
174436355a0Sdan
175436355a0Sdanforeach {n tdefn rc} {
176436355a0Sdan  1 {
177436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
178436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
179436355a0Sdan    END;
180436355a0Sdan  } {0 {10 9 8 7 6 5 4 3 2 1 0}}
181436355a0Sdan
182436355a0Sdan  2 {
183436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN
184436355a0Sdan      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
185436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
186436355a0Sdan    END;
187436355a0Sdan  } {0 {10 9 8 7 6 5 4 3 2}}
188436355a0Sdan
189436355a0Sdan  3 {
190436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
191436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
192436355a0Sdan    END;
193436355a0Sdan  } {0 {0 1 2 3 4 5 6 7 8 9 10}}
194436355a0Sdan
195436355a0Sdan  4 {
196436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
197436355a0Sdan      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
198436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
199436355a0Sdan    END;
200436355a0Sdan  } {0 {3 4 5 6 7 8 9 10}}
201436355a0Sdan
202436355a0Sdan  5 {
203436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
204436355a0Sdan      INSERT INTO t2 VALUES(new.a - 1);
205436355a0Sdan    END;
206436355a0Sdan  } {1 {too many levels of trigger recursion}}
207436355a0Sdan
208436355a0Sdan  6 {
209436355a0Sdan    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
210436355a0Sdan      INSERT OR IGNORE INTO t2 VALUES(new.a);
211436355a0Sdan    END;
212436355a0Sdan  } {0 10}
213436355a0Sdan
214436355a0Sdan  7 {
215436355a0Sdan    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
216436355a0Sdan      INSERT OR IGNORE INTO t2 VALUES(new.a);
217436355a0Sdan    END;
218436355a0Sdan  } {1 {too many levels of trigger recursion}}
219436355a0Sdan} {
220436355a0Sdan  do_test triggerC-2.1.$n {
221436355a0Sdan    catchsql { DROP TRIGGER t2_trig }
222436355a0Sdan    execsql  { DELETE FROM t2 }
223436355a0Sdan    execsql  $tdefn
224436355a0Sdan    catchsql {
225436355a0Sdan      INSERT INTO t2 VALUES(10);
2263f4d1d1bSdrh      SELECT * FROM t2 ORDER BY rowid;
227436355a0Sdan    }
228436355a0Sdan  } $rc
229436355a0Sdan}
230436355a0Sdan
231436355a0Sdando_test triggerC-2.2 {
232f9032cbcSshaneh  execsql "
233436355a0Sdan    CREATE TABLE t22(x);
234436355a0Sdan
235436355a0Sdan    CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN
236436355a0Sdan      INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22;
237436355a0Sdan    END;
238436355a0Sdan    CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN
239f9032cbcSshaneh      SELECT CASE WHEN (SELECT count(*) FROM t22) >= [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
240436355a0Sdan                  THEN RAISE(IGNORE)
241436355a0Sdan                  ELSE NULL END;
242436355a0Sdan    END;
243436355a0Sdan
244436355a0Sdan    INSERT INTO t22 VALUES(1);
245436355a0Sdan    SELECT count(*) FROM t22;
246f9032cbcSshaneh  "
247f9032cbcSshaneh} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
248436355a0Sdan
249436355a0Sdando_test triggerC-2.3 {
25035913a49Sshaneh  execsql "
251436355a0Sdan    CREATE TABLE t23(x PRIMARY KEY);
252436355a0Sdan
253436355a0Sdan    CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
254436355a0Sdan      INSERT INTO t23 VALUES(new.x + 1);
255436355a0Sdan    END;
256436355a0Sdan
257436355a0Sdan    CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
25835913a49Sshaneh      SELECT CASE WHEN new.x>[expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
259436355a0Sdan                  THEN RAISE(IGNORE)
260436355a0Sdan                  ELSE NULL END;
261436355a0Sdan    END;
262436355a0Sdan
263436355a0Sdan    INSERT INTO t23 VALUES(1);
264436355a0Sdan    SELECT count(*) FROM t23;
26535913a49Sshaneh  "
26635913a49Sshaneh} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
267436355a0Sdan
268436355a0Sdan
269436355a0Sdan#-----------------------------------------------------------------------
270436355a0Sdan# This block of tests, triggerC-3.*, test that SQLite throws an exception
271436355a0Sdan# when it detects excessive recursion.
272436355a0Sdan#
273436355a0Sdando_test triggerC-3.1.1 {
274436355a0Sdan  execsql {
275436355a0Sdan    CREATE TABLE t3(a, b);
276436355a0Sdan    CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN
277436355a0Sdan      DELETE FROM t3 WHERE rowid = new.rowid;
278436355a0Sdan    END;
279436355a0Sdan    CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN
280436355a0Sdan      INSERT INTO t3 VALUES(old.a, old.b);
281436355a0Sdan    END;
282436355a0Sdan  }
283436355a0Sdan} {}
284436355a0Sdando_test triggerC-3.1.2 {
285436355a0Sdan  catchsql { INSERT INTO t3 VALUES(0,0) }
286436355a0Sdan} {1 {too many levels of trigger recursion}}
287436355a0Sdando_test triggerC-3.1.3 {
288436355a0Sdan  execsql { SELECT * FROM t3 }
289436355a0Sdan} {}
290436355a0Sdan
291417168adSdrhdo_test triggerC-3.2.1 {
29235913a49Sshaneh  execsql "
293417168adSdrh    CREATE TABLE t3b(x);
29435913a49Sshaneh    CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<[expr $SQLITE_MAX_TRIGGER_DEPTH * 2] BEGIN
295417168adSdrh      INSERT INTO t3b VALUES(new.x+1);
296417168adSdrh    END;
29735913a49Sshaneh  "
298417168adSdrh  catchsql {
299417168adSdrh    INSERT INTO t3b VALUES(1);
300417168adSdrh  }
301417168adSdrh} {1 {too many levels of trigger recursion}}
302417168adSdrhdo_test triggerC-3.2.2 {
303417168adSdrh  db eval {SELECT * FROM t3b}
304417168adSdrh} {}
305417168adSdrh
306417168adSdrhdo_test triggerC-3.3.1 {
30735913a49Sshaneh  catchsql "
30835913a49Sshaneh    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH + 1]);
30935913a49Sshaneh  "
310417168adSdrh} {0 {}}
311417168adSdrhdo_test triggerC-3.3.2 {
312417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
31335913a49Sshaneh} [list $SQLITE_MAX_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH + 1]]
314417168adSdrh
315417168adSdrhdo_test triggerC-3.4.1 {
31635913a49Sshaneh  catchsql "
317417168adSdrh    DELETE FROM t3b;
31835913a49Sshaneh    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH - 1]);
31935913a49Sshaneh  "
320417168adSdrh} {1 {too many levels of trigger recursion}}
321417168adSdrhdo_test triggerC-3.4.2 {
322417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
323417168adSdrh} {0 {} {}}
324417168adSdrh
325417168adSdrhdo_test triggerC-3.5.1 {
32635913a49Sshaneh  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH  [expr $SQLITE_MAX_TRIGGER_DEPTH / 10]
32735913a49Sshaneh  catchsql "
32835913a49Sshaneh    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]);
32935913a49Sshaneh  "
330417168adSdrh} {0 {}}
331417168adSdrhdo_test triggerC-3.5.2 {
332417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
33335913a49Sshaneh} [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]]
334417168adSdrh
335417168adSdrhdo_test triggerC-3.5.3 {
33635913a49Sshaneh  catchsql "
337417168adSdrh    DELETE FROM t3b;
33835913a49Sshaneh    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10)]);
33935913a49Sshaneh  "
340417168adSdrh} {1 {too many levels of trigger recursion}}
341417168adSdrhdo_test triggerC-3.5.4 {
342417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
343417168adSdrh} {0 {} {}}
344417168adSdrh
345417168adSdrhdo_test triggerC-3.6.1 {
346417168adSdrh  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
34735913a49Sshaneh  catchsql "
34835913a49Sshaneh    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH * 2]);
34935913a49Sshaneh  "
350417168adSdrh} {0 {}}
351417168adSdrhdo_test triggerC-3.6.2 {
352417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
35335913a49Sshaneh} [list 1 [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2]]
354417168adSdrh
355417168adSdrhdo_test triggerC-3.6.3 {
35635913a49Sshaneh  catchsql "
357417168adSdrh    DELETE FROM t3b;
35835913a49Sshaneh    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - 1]);
35935913a49Sshaneh  "
360417168adSdrh} {1 {too many levels of trigger recursion}}
361417168adSdrhdo_test triggerC-3.6.4 {
362417168adSdrh  db eval {SELECT count(*), max(x), min(x) FROM t3b}
363417168adSdrh} {0 {} {}}
36435913a49Sshanehsqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH $SQLITE_MAX_TRIGGER_DEPTH
365417168adSdrh
366417168adSdrh
367436355a0Sdan#-----------------------------------------------------------------------
368436355a0Sdan# This next block of tests, triggerC-4.*, checks that affinity
369436355a0Sdan# transformations and constraint processing is performed at the correct
370436355a0Sdan# times relative to BEFORE and AFTER triggers.
371436355a0Sdan#
372436355a0Sdan# For an INSERT statement, for each row to be inserted:
373436355a0Sdan#
374436355a0Sdan#   1. Apply affinities to non-rowid values to be inserted.
375436355a0Sdan#   2. Fire BEFORE triggers.
376436355a0Sdan#   3. Process constraints.
377436355a0Sdan#   4. Insert new record.
378436355a0Sdan#   5. Fire AFTER triggers.
379436355a0Sdan#
380436355a0Sdan# If the value of the rowid field is to be automatically assigned, it is
381436355a0Sdan# set to -1 in the new.* record. Even if it is explicitly set to NULL
382436355a0Sdan# by the INSERT statement.
383436355a0Sdan#
384436355a0Sdan# For an UPDATE statement, for each row to be deleted:
385436355a0Sdan#
386436355a0Sdan#   1. Apply affinities to non-rowid values to be inserted.
387436355a0Sdan#   2. Fire BEFORE triggers.
388436355a0Sdan#   3. Process constraints.
389436355a0Sdan#   4. Insert new record.
390436355a0Sdan#   5. Fire AFTER triggers.
391436355a0Sdan#
392436355a0Sdan# For a DELETE statement, for each row to be deleted:
393436355a0Sdan#
394436355a0Sdan#   1. Fire BEFORE triggers.
395436355a0Sdan#   2. Remove database record.
396436355a0Sdan#   3. Fire AFTER triggers.
397436355a0Sdan#
398436355a0Sdan# When a numeric value that as an exact integer representation is stored
399436355a0Sdan# in a column with REAL affinity, it is actually stored as an integer.
400436355a0Sdan# These tests check that the typeof() such values is always 'real',
401436355a0Sdan# not 'integer'.
402436355a0Sdan#
403436355a0Sdan# triggerC-4.1.*: Check that affinity transformations are made before
404436355a0Sdan#                 triggers are invoked.
405436355a0Sdan#
406436355a0Sdando_test triggerC-4.1.1 {
407436355a0Sdan  catchsql { DROP TABLE log }
408436355a0Sdan  catchsql { DROP TABLE t4 }
409436355a0Sdan  execsql {
410436355a0Sdan    CREATE TABLE log(t);
411436355a0Sdan    CREATE TABLE t4(a TEXT,b INTEGER,c REAL);
412436355a0Sdan    CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN
413436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
414436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
415436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
416436355a0Sdan                             new.c     || ' ' || typeof(new.c)
417436355a0Sdan      );
418436355a0Sdan    END;
419436355a0Sdan    CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN
420436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
421436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
422436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
423436355a0Sdan                             new.c     || ' ' || typeof(new.c)
424436355a0Sdan      );
425436355a0Sdan    END;
426436355a0Sdan    CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN
427436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
428436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
429436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
430436355a0Sdan                             old.c     || ' ' || typeof(old.c)
431436355a0Sdan      );
432436355a0Sdan    END;
433436355a0Sdan    CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN
434436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
435436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
436436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
437436355a0Sdan                             old.c     || ' ' || typeof(old.c)
438436355a0Sdan      );
439436355a0Sdan    END;
440436355a0Sdan    CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN
441436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
442436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
443436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
444436355a0Sdan                             old.c     || ' ' || typeof(old.c)
445436355a0Sdan      );
446436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
447436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
448436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
449436355a0Sdan                             new.c     || ' ' || typeof(new.c)
450436355a0Sdan      );
451436355a0Sdan    END;
452436355a0Sdan    CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN
453436355a0Sdan      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
454436355a0Sdan                             old.a     || ' ' || typeof(old.a)     || ' ' ||
455436355a0Sdan                             old.b     || ' ' || typeof(old.b)     || ' ' ||
456436355a0Sdan                             old.c     || ' ' || typeof(old.c)
457436355a0Sdan      );
458436355a0Sdan      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
459436355a0Sdan                             new.a     || ' ' || typeof(new.a)     || ' ' ||
460436355a0Sdan                             new.b     || ' ' || typeof(new.b)     || ' ' ||
461436355a0Sdan                             new.c     || ' ' || typeof(new.c)
462436355a0Sdan      );
463436355a0Sdan    END;
464436355a0Sdan  }
465436355a0Sdan} {}
466436355a0Sdanforeach {n insert log} {
467436355a0Sdan
468436355a0Sdan  2 {
469436355a0Sdan   INSERT INTO t4 VALUES('1', '1', '1');
470436355a0Sdan   DELETE FROM t4;
471436355a0Sdan  } {
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     1 integer 1 text 1 integer 1.0 real
476436355a0Sdan  }
477436355a0Sdan
478436355a0Sdan  3 {
479436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45);
480436355a0Sdan   DELETE FROM t4;
481436355a0Sdan  } {
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    45 integer 45 text 45 integer 45.0 real
486436355a0Sdan  }
487436355a0Sdan
488436355a0Sdan  4 {
489436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0);
490436355a0Sdan   DELETE FROM t4;
491436355a0Sdan  } {
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    -42 integer -42.0 text -42 integer -42.0 real
496436355a0Sdan  }
497436355a0Sdan
498436355a0Sdan  5 {
499436355a0Sdan   INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4);
500436355a0Sdan   DELETE FROM t4;
501436355a0Sdan  } {
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     1 integer -42.4 text -42.4 real -42.4 real
506436355a0Sdan  }
507436355a0Sdan
508436355a0Sdan  6 {
509436355a0Sdan   INSERT INTO t4 VALUES(7, 7, 7);
510436355a0Sdan   UPDATE t4 SET a=8, b=8, c=8;
511436355a0Sdan  } {
512436355a0Sdan    -1 integer 7 text 7 integer 7.0 real
513436355a0Sdan     1 integer 7 text 7 integer 7.0 real
514436355a0Sdan     1 integer 7 text 7 integer 7.0 real
515436355a0Sdan     1 integer 8 text 8 integer 8.0 real
516436355a0Sdan     1 integer 7 text 7 integer 7.0 real
517436355a0Sdan     1 integer 8 text 8 integer 8.0 real
518436355a0Sdan  }
519436355a0Sdan
520436355a0Sdan  7 {
521436355a0Sdan   UPDATE t4 SET rowid=2;
522436355a0Sdan  } {
523436355a0Sdan     1 integer 8 text 8 integer 8.0 real
524436355a0Sdan     2 integer 8 text 8 integer 8.0 real
525436355a0Sdan     1 integer 8 text 8 integer 8.0 real
526436355a0Sdan     2 integer 8 text 8 integer 8.0 real
527436355a0Sdan  }
528436355a0Sdan
529436355a0Sdan  8 {
530436355a0Sdan   UPDATE t4 SET a='9', b='9', c='9';
531436355a0Sdan  } {
532436355a0Sdan     2 integer 8 text 8 integer 8.0 real
533436355a0Sdan     2 integer 9 text 9 integer 9.0 real
534436355a0Sdan     2 integer 8 text 8 integer 8.0 real
535436355a0Sdan     2 integer 9 text 9 integer 9.0 real
536436355a0Sdan  }
537436355a0Sdan
538436355a0Sdan  9 {
539436355a0Sdan   UPDATE t4 SET a='9.1', b='9.1', c='9.1';
540436355a0Sdan  } {
541436355a0Sdan     2 integer 9   text 9   integer 9.0 real
542436355a0Sdan     2 integer 9.1 text 9.1 real    9.1 real
543436355a0Sdan     2 integer 9   text 9   integer 9.0 real
544436355a0Sdan     2 integer 9.1 text 9.1 real    9.1 real
545436355a0Sdan  }
546436355a0Sdan} {
547436355a0Sdan  do_test triggerC-4.1.$n {
548436355a0Sdan    eval concat [execsql "
549436355a0Sdan      DELETE FROM log;
550436355a0Sdan      $insert ;
5513f4d1d1bSdrh      SELECT * FROM log ORDER BY rowid;
552436355a0Sdan    "]
553436355a0Sdan  } [join $log " "]
554436355a0Sdan}
555436355a0Sdan
5562283d46cSdan#-------------------------------------------------------------------------
5572283d46cSdan# This block of tests, triggerC-5.*, test that DELETE triggers are fired
5582283d46cSdan# if a row is deleted as a result of OR REPLACE conflict resolution.
5592283d46cSdan#
5602283d46cSdando_test triggerC-5.1.0 {
5612283d46cSdan  execsql {
5622283d46cSdan    DROP TABLE IF EXISTS t5;
5632283d46cSdan    CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
5642283d46cSdan    CREATE UNIQUE INDEX t5i ON t5(b);
5652283d46cSdan    INSERT INTO t5 VALUES(1, 'a');
5662283d46cSdan    INSERT INTO t5 VALUES(2, 'b');
5672283d46cSdan    INSERT INTO t5 VALUES(3, 'c');
5682283d46cSdan
5692283d46cSdan    CREATE TABLE t5g(a, b, c);
5702283d46cSdan    CREATE TRIGGER t5t BEFORE DELETE ON t5 BEGIN
5712283d46cSdan      INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
5722283d46cSdan    END;
5732283d46cSdan  }
5742283d46cSdan} {}
5752283d46cSdanforeach {n dml t5g t5} {
5762283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 3} {1 a 3 c}
5772283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 3} {1 a 2 d 3 c}
5782283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 3} {1 a 2 c}
5792283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 3} {1 a 3 c 4 b}
5802283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 3} {1 a 3 b}
5812283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 3 3 c 2} {1 a 2 c}
5822283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 3 2 b 2} {1 b}
5832283d46cSdan} {
5842283d46cSdan  do_test triggerC-5.1.$n {
5852283d46cSdan    execsql "
5862283d46cSdan      BEGIN;
5872283d46cSdan        $dml ;
5883f4d1d1bSdrh        SELECT * FROM t5g ORDER BY rowid;
5893f4d1d1bSdrh        SELECT * FROM t5 ORDER BY rowid;
5902283d46cSdan      ROLLBACK;
5912283d46cSdan    "
5922283d46cSdan  } [concat $t5g $t5]
5932283d46cSdan}
5942283d46cSdando_test triggerC-5.2.0 {
5952283d46cSdan  execsql {
5962283d46cSdan    DROP TRIGGER t5t;
5972283d46cSdan    CREATE TRIGGER t5t AFTER DELETE ON t5 BEGIN
5982283d46cSdan      INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
5992283d46cSdan    END;
6002283d46cSdan  }
6012283d46cSdan} {}
6022283d46cSdanforeach {n dml t5g t5} {
6032283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
6042283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 2} {1 a 2 d 3 c}
6052283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 2} {1 a 2 c}
6062283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 2} {1 a 3 c 4 b}
6072283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 2} {1 a 3 b}
6082283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 2 3 c 1} {1 a 2 c}
6092283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 2 2 b 1} {1 b}
6102283d46cSdan} {
6112283d46cSdan  do_test triggerC-5.2.$n {
6122283d46cSdan    execsql "
6132283d46cSdan      BEGIN;
6142283d46cSdan        $dml ;
6153f4d1d1bSdrh        SELECT * FROM t5g ORDER BY rowid;
6163f4d1d1bSdrh        SELECT * FROM t5 ORDER BY rowid;
6172283d46cSdan      ROLLBACK;
6182283d46cSdan    "
6192283d46cSdan  } [concat $t5g $t5]
6202283d46cSdan}
6212283d46cSdando_test triggerC-5.3.0 {
6222283d46cSdan  execsql { PRAGMA recursive_triggers = off }
6232283d46cSdan} {}
6242283d46cSdanforeach {n dml t5g t5} {
6252283d46cSdan  1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
6262283d46cSdan  2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {} {1 a 2 d 3 c}
6272283d46cSdan  3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {} {1 a 2 c}
6282283d46cSdan  4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {} {1 a 3 c 4 b}
6292283d46cSdan  5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {} {1 a 3 b}
6302283d46cSdan  6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {} {1 a 2 c}
6312283d46cSdan  7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {} {1 b}
6322283d46cSdan} {
6332283d46cSdan  do_test triggerC-5.3.$n {
6342283d46cSdan    execsql "
6352283d46cSdan      BEGIN;
6362283d46cSdan        $dml ;
6373f4d1d1bSdrh        SELECT * FROM t5g ORDER BY rowid;
6383f4d1d1bSdrh        SELECT * FROM t5 ORDER BY rowid;
6392283d46cSdan      ROLLBACK;
6402283d46cSdan    "
6412283d46cSdan  } [concat $t5g $t5]
6422283d46cSdan}
6432283d46cSdando_test triggerC-5.3.8 {
6442283d46cSdan  execsql { PRAGMA recursive_triggers = on }
6452283d46cSdan} {}
6462283d46cSdan
6472283d46cSdan#-------------------------------------------------------------------------
6482283d46cSdan# This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers"
6492283d46cSdan# statements return the current value of the recursive triggers flag.
6502283d46cSdan#
6512283d46cSdando_test triggerC-6.1 {
6522283d46cSdan  execsql { PRAGMA recursive_triggers }
6532283d46cSdan} {1}
6542283d46cSdando_test triggerC-6.2 {
6552283d46cSdan  execsql {
6562283d46cSdan    PRAGMA recursive_triggers = off;
6572283d46cSdan    PRAGMA recursive_triggers;
6582283d46cSdan  }
6592283d46cSdan} {0}
6602283d46cSdando_test triggerC-6.3 {
6612283d46cSdan  execsql {
6622283d46cSdan    PRAGMA recursive_triggers = on;
6632283d46cSdan    PRAGMA recursive_triggers;
6642283d46cSdan  }
6652283d46cSdan} {1}
6662283d46cSdan
667e0af83acSdan#-------------------------------------------------------------------------
668e0af83acSdan# Test some of the "undefined behaviour" associated with triggers. The
669e0af83acSdan# undefined behaviour occurs when a row being updated or deleted is
670e0af83acSdan# manipulated by a BEFORE trigger.
671e0af83acSdan#
672ae0931edSdando_test triggerC-7.1 {
673ae0931edSdan  execsql {
674ae0931edSdan    CREATE TABLE t8(x);
675ae0931edSdan    CREATE TABLE t7(a, b);
676ae0931edSdan    INSERT INTO t7 VALUES(1, 2);
677ae0931edSdan    INSERT INTO t7 VALUES(3, 4);
678ae0931edSdan    INSERT INTO t7 VALUES(5, 6);
679ae0931edSdan    CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN
680ae0931edSdan      DELETE FROM t7 WHERE a = 1;
681ae0931edSdan    END;
682ae0931edSdan    CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN
683ae0931edSdan      INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid);
684ae0931edSdan    END;
685ae0931edSdan  }
686ae0931edSdan} {}
687ae0931edSdando_test triggerC-7.2 {
688ae0931edSdan  execsql {
689ae0931edSdan    BEGIN;
690ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 5;
691ae0931edSdan      SELECT * FROM t7;
692ae0931edSdan      SELECT * FROM t8;
693ae0931edSdan    ROLLBACK;
694ae0931edSdan  }
695ae0931edSdan} {3 4 5 7 {after fired 3->3}}
696ae0931edSdando_test triggerC-7.3 {
697ae0931edSdan  execsql {
698ae0931edSdan    BEGIN;
699ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 1;
700ae0931edSdan      SELECT * FROM t7;
701ae0931edSdan      SELECT * FROM t8;
702ae0931edSdan    ROLLBACK;
703ae0931edSdan  }
704ae0931edSdan} {3 4 5 6}
705ae0931edSdan
706ae0931edSdando_test triggerC-7.4 {
707ae0931edSdan  execsql {
708ae0931edSdan    DROP TRIGGER t7t;
709ae0931edSdan    CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8)
710ae0931edSdan    BEGIN
711ae0931edSdan      UPDATE t7 set rowid = 8 WHERE rowid=1;
712ae0931edSdan    END;
713ae0931edSdan  }
714ae0931edSdan} {}
715ae0931edSdando_test triggerC-7.5 {
716ae0931edSdan  execsql {
717ae0931edSdan    BEGIN;
718ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 5;
719ae0931edSdan      SELECT rowid, * FROM t7;
720ae0931edSdan      SELECT * FROM t8;
721ae0931edSdan    ROLLBACK;
722ae0931edSdan  }
723ae0931edSdan} {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}}
724ae0931edSdando_test triggerC-7.6 {
725ae0931edSdan  execsql {
726ae0931edSdan    BEGIN;
727ae0931edSdan      UPDATE t7 SET b=7 WHERE a = 1;
728ae0931edSdan      SELECT rowid, * FROM t7;
729ae0931edSdan      SELECT * FROM t8;
730ae0931edSdan    ROLLBACK;
731ae0931edSdan  }
732ae0931edSdan} {2 3 4 3 5 6 8 1 2 {after fired 1->8}}
733ae0931edSdan
734ae0931edSdando_test triggerC-7.7 {
735ae0931edSdan  execsql {
736ae0931edSdan    DROP TRIGGER t7t;
737ae0931edSdan    DROP TRIGGER t7ta;
738ae0931edSdan    CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN
739ae0931edSdan      UPDATE t7 set rowid = 8 WHERE rowid=1;
740ae0931edSdan    END;
741ae0931edSdan    CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN
742ae0931edSdan      INSERT INTO t8 VALUES('after fired ' || old.rowid);
743ae0931edSdan    END;
744ae0931edSdan  }
745ae0931edSdan} {}
746ae0931edSdando_test triggerC-7.8 {
747ae0931edSdan  execsql {
748ae0931edSdan    BEGIN;
749ae0931edSdan      DELETE FROM t7 WHERE a = 3;
750ae0931edSdan      SELECT rowid, * FROM t7;
751ae0931edSdan      SELECT * FROM t8;
752ae0931edSdan    ROLLBACK;
753ae0931edSdan  }
754ae0931edSdan} {3 5 6 8 1 2 {after fired 2}}
755ae0931edSdando_test triggerC-7.9 {
756ae0931edSdan  execsql {
757ae0931edSdan    BEGIN;
758ae0931edSdan      DELETE FROM t7 WHERE a = 1;
759ae0931edSdan      SELECT rowid, * FROM t7;
760ae0931edSdan      SELECT * FROM t8;
761ae0931edSdan    ROLLBACK;
762ae0931edSdan  }
763ae0931edSdan} {2 3 4 3 5 6 8 1 2}
764e0af83acSdan
7653991bb0dSdrh# Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643]
7663991bb0dSdrh#
7673991bb0dSdrhdo_test triggerC-9.1 {
7683991bb0dSdrh  execsql {
7693991bb0dSdrh    CREATE TABLE t9(a,b);
7703991bb0dSdrh    CREATE INDEX t9b ON t9(b);
7713991bb0dSdrh    INSERT INTO t9 VALUES(1,0);
7723991bb0dSdrh    INSERT INTO t9 VALUES(2,1);
7733991bb0dSdrh    INSERT INTO t9 VALUES(3,2);
7743991bb0dSdrh    INSERT INTO t9 SELECT a+3, a+2 FROM t9;
7753991bb0dSdrh    INSERT INTO t9 SELECT a+6, a+5 FROM t9;
7763991bb0dSdrh    SELECT a FROM t9 ORDER BY a;
7773991bb0dSdrh  }
7783991bb0dSdrh} {1 2 3 4 5 6 7 8 9 10 11 12}
7793991bb0dSdrhdo_test triggerC-9.2 {
7803991bb0dSdrh  execsql {
7813991bb0dSdrh    CREATE TRIGGER t9r1 AFTER DELETE ON t9 BEGIN
7823991bb0dSdrh      DELETE FROM t9 WHERE b=old.a;
7833991bb0dSdrh    END;
7843991bb0dSdrh    DELETE FROM t9 WHERE b=4;
7853991bb0dSdrh    SELECT a FROM t9 ORDER BY a;
7863991bb0dSdrh  }
7873991bb0dSdrh} {1 2 3 4}
7883991bb0dSdrh
789bb5f168fSdan# At one point (between versions 3.6.18 and 3.6.20 inclusive), an UPDATE
790bb5f168fSdan# that fired a BEFORE trigger that itself updated the same row as the
791bb5f168fSdan# statement causing it to fire was causing a strange side-effect: The
792bb5f168fSdan# values updated by the statement within the trigger were being overwritten
793bb5f168fSdan# by the values in the new.* array, even if those values were not
794bb5f168fSdan# themselves written by the parent UPDATE statement.
795bb5f168fSdan#
796bb5f168fSdan# Technically speaking this was not a bug. The SQLite documentation says
797bb5f168fSdan# that if a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes the
798bb5f168fSdan# row that the parent statement is operating on the results are undefined.
799bb5f168fSdan# But as of 3.6.21 behaviour is restored to the way it was in versions
800bb5f168fSdan# 3.6.17 and earlier to avoid causing unnecessary difficulties.
801bb5f168fSdan#
802bb5f168fSdando_test triggerC-10.1 {
803bb5f168fSdan  execsql {
804bb5f168fSdan    CREATE TABLE t10(a, updatecnt DEFAULT 0);
805bb5f168fSdan    CREATE TRIGGER t10_bu BEFORE UPDATE OF a ON t10 BEGIN
806bb5f168fSdan      UPDATE t10 SET updatecnt = updatecnt+1 WHERE rowid = old.rowid;
807bb5f168fSdan    END;
808bb5f168fSdan    INSERT INTO t10(a) VALUES('hello');
809bb5f168fSdan  }
8103991bb0dSdrh
811bb5f168fSdan  # Before the problem was fixed, table t10 would contain the tuple
812bb5f168fSdan  # (world, 0) after running the following script (because the value
813bb5f168fSdan  # 1 written to column "updatecnt" was clobbered by the old value 0).
814bb5f168fSdan  #
815bb5f168fSdan  execsql {
816bb5f168fSdan    UPDATE t10 SET a = 'world';
817bb5f168fSdan    SELECT * FROM t10;
818bb5f168fSdan  }
819bb5f168fSdan} {world 1}
820bb5f168fSdan
821bb5f168fSdando_test triggerC-10.2 {
822bb5f168fSdan  execsql {
823bb5f168fSdan    UPDATE t10 SET a = 'tcl', updatecnt = 5;
824bb5f168fSdan    SELECT * FROM t10;
825bb5f168fSdan  }
826bb5f168fSdan} {tcl 5}
827bb5f168fSdan
828bb5f168fSdando_test triggerC-10.3 {
829bb5f168fSdan  execsql {
830bb5f168fSdan    CREATE TABLE t11(
831bb5f168fSdan      c1,   c2,  c3,  c4,  c5,  c6,  c7,  c8,  c9, c10,
832bb5f168fSdan      c11, c12, c13, c14, c15, c16, c17, c18, c19, c20,
833bb5f168fSdan      c21, c22, c23, c24, c25, c26, c27, c28, c29, c30,
834bb5f168fSdan      c31, c32, c33, c34, c35, c36, c37, c38, c39, c40
835bb5f168fSdan    );
836bb5f168fSdan
837bb5f168fSdan    CREATE TRIGGER t11_bu BEFORE UPDATE OF c1 ON t11 BEGIN
838bb5f168fSdan      UPDATE t11 SET c31 = c31+1, c32=c32+1 WHERE rowid = old.rowid;
839bb5f168fSdan    END;
840bb5f168fSdan
841bb5f168fSdan    INSERT INTO t11 VALUES(
842bb5f168fSdan      1,   2,  3,  4,  5,  6,  7,  8,  9, 10,
843bb5f168fSdan      11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
844bb5f168fSdan      21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
845bb5f168fSdan      31, 32, 33, 34, 35, 36, 37, 38, 39, 40
846bb5f168fSdan    );
847bb5f168fSdan  }
848bb5f168fSdan
849bb5f168fSdan  # Before the problem was fixed, table t10 would contain the tuple
850bb5f168fSdan  # (world, 0) after running the following script (because the value
851bb5f168fSdan  # 1 written to column "updatecnt" was clobbered by the old value 0).
852bb5f168fSdan  #
853bb5f168fSdan  execsql {
854bb5f168fSdan    UPDATE t11 SET c4=35, c33=22, c1=5;
855bb5f168fSdan    SELECT * FROM t11;
856bb5f168fSdan  }
857bb5f168fSdan} {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}
8583991bb0dSdrh
8597ba45971Sdan#-------------------------------------------------------------------------
8607ba45971Sdan# Test that bug [371bab5d65] has been fixed. BEFORE INSERT and INSTEAD OF
8617ba45971Sdan# INSERT triggers with the DEFAULT VALUES INSERT syntax.
8627ba45971Sdan#
8637ba45971Sdando_test triggerC-11.0 {
8647ba45971Sdan  catchsql { DROP TABLE log }
8657ba45971Sdan  execsql  { CREATE TABLE log(a, b) }
8667ba45971Sdan} {}
8677ba45971Sdan
8687ba45971Sdanforeach {testno tbl defaults} {
8697ba45971Sdan  1 "CREATE TABLE t1(a, b)"                          {{} {}}
8707ba45971Sdan  2 "CREATE TABLE t1(a DEFAULT 1, b DEFAULT 'abc')"  {1 abc}
8717ba45971Sdan  3 "CREATE TABLE t1(a, b DEFAULT 4.5)"              {{} 4.5}
8727ba45971Sdan} {
8737ba45971Sdan  do_test triggerC-11.$testno.1 {
8747ba45971Sdan    catchsql { DROP TABLE t1 }
8757ba45971Sdan    execsql { DELETE FROM log }
8767ba45971Sdan    execsql $tbl
8777ba45971Sdan    execsql {
8787ba45971Sdan      CREATE TRIGGER tt1 BEFORE INSERT ON t1 BEGIN
8797ba45971Sdan        INSERT INTO log VALUES(new.a, new.b);
8807ba45971Sdan      END;
8817ba45971Sdan      INSERT INTO t1 DEFAULT VALUES;
8827ba45971Sdan      SELECT * FROM log;
8837ba45971Sdan    }
8847ba45971Sdan  } $defaults
8857ba45971Sdan
8867ba45971Sdan  do_test triggerC-11.$testno.2 {
8877ba45971Sdan    execsql { DELETE FROM log }
8887ba45971Sdan    execsql {
8897ba45971Sdan      CREATE TRIGGER tt2 AFTER INSERT ON t1 BEGIN
8907ba45971Sdan        INSERT INTO log VALUES(new.a, new.b);
8917ba45971Sdan      END;
8927ba45971Sdan      INSERT INTO t1 DEFAULT VALUES;
8937ba45971Sdan      SELECT * FROM log;
8947ba45971Sdan    }
8957ba45971Sdan  } [concat $defaults $defaults]
8967ba45971Sdan
8977ba45971Sdan  do_test triggerC-11.$testno.3 {
8987ba45971Sdan    execsql { DROP TRIGGER tt1 }
8997ba45971Sdan    execsql { DELETE FROM log }
9007ba45971Sdan    execsql {
9017ba45971Sdan      INSERT INTO t1 DEFAULT VALUES;
9027ba45971Sdan      SELECT * FROM log;
9037ba45971Sdan    }
9047ba45971Sdan  } $defaults
9057ba45971Sdan}
9067ba45971Sdando_test triggerC-11.4 {
9077ba45971Sdan  catchsql { DROP TABLE t2 }
9087ba45971Sdan  execsql {
9097ba45971Sdan    DELETE FROM log;
9107ba45971Sdan    CREATE TABLE t2(a, b);
9117ba45971Sdan    CREATE VIEW v2 AS SELECT * FROM t2;
9127ba45971Sdan    CREATE TRIGGER tv2 INSTEAD OF INSERT ON v2 BEGIN
9137ba45971Sdan      INSERT INTO log VALUES(new.a, new.b);
9147ba45971Sdan    END;
9157ba45971Sdan    INSERT INTO v2 DEFAULT VALUES;
9167ba45971Sdan    SELECT a, b, a IS NULL, b IS NULL FROM log;
9177ba45971Sdan  }
9187ba45971Sdan} {{} {} 1 1}
9197ba45971Sdan
92098530cacSdando_test triggerC-12.1 {
92198530cacSdan  db close
922fda06befSmistachkin  forcedelete test.db
92398530cacSdan  sqlite3 db test.db
92498530cacSdan
92598530cacSdan  execsql {
92698530cacSdan    CREATE TABLE t1(a, b);
92798530cacSdan    INSERT INTO t1 VALUES(1, 2);
92898530cacSdan    INSERT INTO t1 VALUES(3, 4);
92998530cacSdan    INSERT INTO t1 VALUES(5, 6);
93098530cacSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1 ; END ;
93198530cacSdan    SELECT count(*) FROM sqlite_master;
93298530cacSdan  }
93398530cacSdan} {2}
93498530cacSdando_test triggerC-12.2 {
93598530cacSdan  db eval { SELECT * FROM t1 } {
93698530cacSdan    if {$a == 3} { execsql { DROP TRIGGER tr1 } }
93798530cacSdan  }
93898530cacSdan  execsql { SELECT count(*) FROM sqlite_master }
93998530cacSdan} {1}
94098530cacSdan
94127106570Sdando_execsql_test triggerC-13.1 {
94227106570Sdan  PRAGMA recursive_triggers = ON;
94327106570Sdan  CREATE TABLE t12(a, b);
94427106570Sdan  INSERT INTO t12 VALUES(1, 2);
94527106570Sdan  CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN
94627106570Sdan    UPDATE t12 SET a=new.a+1, b=new.b+1;
94727106570Sdan  END;
94827106570Sdan} {}
94927106570Sdando_catchsql_test triggerC-13.2 {
95027106570Sdan  UPDATE t12 SET a=a+1, b=b+1;
95127106570Sdan} {1 {too many levels of trigger recursion}}
95227106570Sdan
953f78baafeSdan#-------------------------------------------------------------------------
954f78baafeSdan# The following tests seek to verify that constant values (i.e. literals)
955f78baafeSdan# are not factored out of loops within trigger programs. SQLite does
956f78baafeSdan# not factor constants out of loops within trigger programs as it may only
957f78baafeSdan# do so in code generated before the first table or index is opened. And
958f78baafeSdan# by the time a trigger program is coded, at least one table or index has
959f78baafeSdan# always been opened.
960f78baafeSdan#
961f78baafeSdan# At one point, due to a bug allowing constant factoring within triggers,
962f78baafeSdan# the following SQL would produce the wrong result.
963f78baafeSdan#
964f78baafeSdanset SQL {
965f78baafeSdan  CREATE TABLE t1(a, b, c);
966f78baafeSdan  CREATE INDEX i1 ON t1(a, c);
967f78baafeSdan  CREATE INDEX i2 ON t1(b, c);
968f78baafeSdan  INSERT INTO t1 VALUES(1, 2, 3);
9697ba45971Sdan
970f78baafeSdan  CREATE TABLE t2(e, f);
971f78baafeSdan  CREATE INDEX i3 ON t2(e);
972f78baafeSdan  INSERT INTO t2 VALUES(1234567, 3);
973f78baafeSdan
974f78baafeSdan  CREATE TABLE empty(x);
975f78baafeSdan  CREATE TABLE not_empty(x);
976f78baafeSdan  INSERT INTO not_empty VALUES(2);
977f78baafeSdan
978f78baafeSdan  CREATE TABLE t4(x);
979f78baafeSdan  CREATE TABLE t5(g, h, i);
980f78baafeSdan
981f78baafeSdan  CREATE TRIGGER trig BEFORE INSERT ON t4 BEGIN
982f78baafeSdan    INSERT INTO t5 SELECT * FROM t1 WHERE
983f78baafeSdan        (a IN (SELECT x FROM empty) OR b IN (SELECT x FROM not_empty))
984f78baafeSdan        AND c IN (SELECT f FROM t2 WHERE e=1234567);
985f78baafeSdan  END;
986f78baafeSdan
987f78baafeSdan  INSERT INTO t4 VALUES(0);
988f78baafeSdan  SELECT * FROM t5;
989f78baafeSdan}
990f78baafeSdan
991f78baafeSdanreset_db
992f78baafeSdando_execsql_test triggerC-14.1 $SQL {1 2 3}
993f78baafeSdanreset_db
994f78baafeSdanoptimization_control db factor-constants 0
995f78baafeSdando_execsql_test triggerC-14.2 $SQL {1 2 3}
9962283d46cSdan
99746408354Sdan#-------------------------------------------------------------------------
99846408354Sdan# Check that table names used by trigger programs are dequoted exactly
99946408354Sdan# once.
100046408354Sdan#
100146408354Sdando_execsql_test 15.1.1 {
100246408354Sdan  PRAGMA recursive_triggers = 1;
100346408354Sdan  CREATE TABLE node(
100446408354Sdan      id int not null primary key,
100546408354Sdan      pid int not null default 0 references node,
100646408354Sdan      key varchar not null,
100746408354Sdan      path varchar default '',
100846408354Sdan      unique(pid, key)
100946408354Sdan      );
101046408354Sdan  CREATE TRIGGER node_delete_referencing AFTER DELETE ON "node"
101146408354Sdan    BEGIN
101246408354Sdan    DELETE FROM "node" WHERE pid = old."id";
101346408354Sdan  END;
101446408354Sdan}
101546408354Sdando_execsql_test 15.1.2 {
101646408354Sdan  INSERT INTO node(id, pid, key) VALUES(9, 0, 'test');
101746408354Sdan  INSERT INTO node(id, pid, key) VALUES(90, 9, 'test1');
101846408354Sdan  INSERT INTO node(id, pid, key) VALUES(900, 90, 'test2');
101946408354Sdan  DELETE FROM node WHERE id=9;
102046408354Sdan  SELECT * FROM node;
102146408354Sdan}
102246408354Sdan
102346408354Sdando_execsql_test 15.2.1 {
102446408354Sdan  CREATE TABLE   x1  (x);
102546408354Sdan
102646408354Sdan  CREATE TABLE   x2  (a, b);
102746408354Sdan  CREATE TABLE '"x2"'(a, b);
102846408354Sdan
102946408354Sdan  INSERT INTO x2 VALUES(1, 2);
103046408354Sdan  INSERT INTO x2 VALUES(3, 4);
103146408354Sdan  INSERT INTO '"x2"' SELECT * FROM x2;
103246408354Sdan
103346408354Sdan  CREATE TRIGGER x1ai AFTER INSERT ON x1 BEGIN
103446408354Sdan    INSERT INTO """x2""" VALUES('x', 'y');
103546408354Sdan    DELETE FROM """x2""" WHERE a=1;
103646408354Sdan    UPDATE """x2""" SET b = 11 WHERE a = 3;
103746408354Sdan  END;
103846408354Sdan
103946408354Sdan  INSERT INTO x1 VALUES('go!');
104046408354Sdan}
104146408354Sdan
104246408354Sdando_execsql_test 15.2.2 { SELECT * FROM x2;       } {1 2 3 4}
104346408354Sdando_execsql_test 15.2.3 { SELECT * FROM """x2"""; } {3 11 x y}
104446408354Sdan
104516dd3985Sdan#-------------------------------------------------------------------------
104616dd3985Sdan# At one point queries such as the following were causing segfaults.
104716dd3985Sdan#
104816dd3985Sdando_catchsql_test 16.1 {
104916dd3985Sdan  SELECT raise(ABORT, 'msg') FROM sqlite_master
105016dd3985Sdan  UNION SELECT 1
105116dd3985Sdan  ORDER BY raise(IGNORE);
105216dd3985Sdan} {1 {1st ORDER BY term does not match any column in the result set}}
105316dd3985Sdan
105416dd3985Sdando_catchsql_test 16.2 {
105516dd3985Sdan  SELECT count(*) FROM sqlite_master
105616dd3985Sdan  GROUP BY raise(IGNORE)
105716dd3985Sdan  HAVING raise(ABORT, 'msg');
105816dd3985Sdan} {1 {RAISE() may only be used within a trigger-program}}
105916dd3985Sdan
1060*b84b38fdSdan#-------------------------------------------------------------------------
1061*b84b38fdSdan# Datatype mismatch on IPK when there are BEFORE triggers.
1062*b84b38fdSdan#
1063*b84b38fdSdando_execsql_test 17.0 {
1064*b84b38fdSdan  CREATE TABLE xyz(x INTEGER PRIMARY KEY, y, z);
1065*b84b38fdSdan  CREATE TRIGGER xyz_tr BEFORE INSERT ON xyz BEGIN
1066*b84b38fdSdan    SELECT new.x;
1067*b84b38fdSdan  END;
1068*b84b38fdSdan}
1069*b84b38fdSdando_catchsql_test 17.1 {
1070*b84b38fdSdan  INSERT INTO xyz VALUES('hello', 2, 3);
1071*b84b38fdSdan} {1 {datatype mismatch}}
1072*b84b38fdSdan
1073*b84b38fdSdan
1074436355a0Sdanfinish_test
1075