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>