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