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