Home | History | Annotate | Download | only in test
      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) >= 100
    239                   THEN RAISE(IGNORE)
    240                   ELSE NULL END;
    241     END;
    242 
    243     INSERT INTO t22 VALUES(1);
    244     SELECT count(*) FROM t22;
    245   }
    246 } {100}
    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>500
    258                   THEN RAISE(IGNORE)
    259                   ELSE NULL END;
    260     END;
    261 
    262     INSERT INTO t23 VALUES(1);
    263     SELECT count(*) FROM t23;
    264   }
    265 } {500}
    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<2000 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(1001);
    308   }
    309 } {0 {}}
    310 do_test triggerC-3.3.2 {
    311   db eval {SELECT count(*), max(x), min(x) FROM t3b}
    312 } {1000 2000 1001}
    313 
    314 do_test triggerC-3.4.1 {
    315   catchsql {
    316     DELETE FROM t3b;
    317     INSERT INTO t3b VALUES(999);
    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 100
    326   catchsql {
    327     INSERT INTO t3b VALUES(1901);
    328   }
    329 } {0 {}}
    330 do_test triggerC-3.5.2 {
    331   db eval {SELECT count(*), max(x), min(x) FROM t3b}
    332 } {100 2000 1901}
    333 
    334 do_test triggerC-3.5.3 {
    335   catchsql {
    336     DELETE FROM t3b;
    337     INSERT INTO t3b VALUES(1900);
    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(2000);
    348   }
    349 } {0 {}}
    350 do_test triggerC-3.6.2 {
    351   db eval {SELECT count(*), max(x), min(x) FROM t3b}
    352 } {1 2000 2000}
    353 
    354 do_test triggerC-3.6.3 {
    355   catchsql {
    356     DELETE FROM t3b;
    357     INSERT INTO t3b VALUES(1999);
    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 1000
    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   file delete -force 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
    955