1# The author disclaims copyright to this source code. In place of 2# a legal notice, here is a blessing: 3# 4# May you do good and not evil. 5# May you find forgiveness for yourself and forgive others. 6# May you share freely, never taking more than you give. 7# 8#*********************************************************************** 9# 10# This file tests creating and dropping triggers, and interaction thereof 11# with the database COMMIT/ROLLBACK logic. 12# 13# 1. CREATE and DROP TRIGGER tests 14# trig-1.1: Error if table does not exist 15# trig-1.2: Error if trigger already exists 16# trig-1.3: Created triggers are deleted if the transaction is rolled back 17# trig-1.4: DROP TRIGGER removes trigger 18# trig-1.5: Dropped triggers are restored if the transaction is rolled back 19# trig-1.6: Error if dropped trigger doesn't exist 20# trig-1.7: Dropping the table automatically drops all triggers 21# trig-1.8: A trigger created on a TEMP table is not inserted into sqlite_master 22# trig-1.9: Ensure that we cannot create a trigger on sqlite_master 23# trig-1.10: 24# trig-1.11: 25# trig-1.12: Ensure that INSTEAD OF triggers cannot be created on tables 26# trig-1.13: Ensure that AFTER triggers cannot be created on views 27# trig-1.14: Ensure that BEFORE triggers cannot be created on views 28# 29 30set testdir [file dirname $argv0] 31source $testdir/tester.tcl 32ifcapable {!trigger} { 33 finish_test 34 return 35} 36 37do_test trigger1-1.1.1 { 38 catchsql { 39 CREATE TRIGGER trig UPDATE ON no_such_table BEGIN 40 SELECT * from sqlite_master; 41 END; 42 } 43} {1 {no such table: main.no_such_table}} 44 45ifcapable tempdb { 46 do_test trigger1-1.1.2 { 47 catchsql { 48 CREATE TEMP TRIGGER trig UPDATE ON no_such_table BEGIN 49 SELECT * from sqlite_master; 50 END; 51 } 52 } {1 {no such table: no_such_table}} 53} 54 55execsql { 56 CREATE TABLE t1(a); 57} 58do_test trigger1-1.1.3 { 59 catchsql { 60 CREATE TRIGGER trig UPDATE ON t1 FOR EACH STATEMENT BEGIN 61 SELECT * FROM sqlite_master; 62 END; 63 } 64} {1 {near "STATEMENT": syntax error}} 65execsql { 66 CREATE TRIGGER tr1 INSERT ON t1 BEGIN 67 INSERT INTO t1 values(1); 68 END; 69} 70do_test trigger1-1.2.0 { 71 catchsql { 72 CREATE TRIGGER IF NOT EXISTS tr1 DELETE ON t1 BEGIN 73 SELECT * FROM sqlite_master; 74 END 75 } 76} {0 {}} 77do_test trigger1-1.2.1 { 78 catchsql { 79 CREATE TRIGGER tr1 DELETE ON t1 BEGIN 80 SELECT * FROM sqlite_master; 81 END 82 } 83} {1 {trigger tr1 already exists}} 84do_test trigger1-1.2.2 { 85 catchsql { 86 CREATE TRIGGER "tr1" DELETE ON t1 BEGIN 87 SELECT * FROM sqlite_master; 88 END 89 } 90} {1 {trigger "tr1" already exists}} 91do_test trigger1-1.2.3 { 92 catchsql { 93 CREATE TRIGGER [tr1] DELETE ON t1 BEGIN 94 SELECT * FROM sqlite_master; 95 END 96 } 97} {1 {trigger [tr1] already exists}} 98 99do_test trigger1-1.3 { 100 catchsql { 101 BEGIN; 102 CREATE TRIGGER tr2 INSERT ON t1 BEGIN 103 SELECT * from sqlite_master; END; 104 ROLLBACK; 105 CREATE TRIGGER tr2 INSERT ON t1 BEGIN 106 SELECT * from sqlite_master; END; 107 } 108} {0 {}} 109 110do_test trigger1-1.4 { 111 catchsql { 112 DROP TRIGGER IF EXISTS tr1; 113 CREATE TRIGGER tr1 DELETE ON t1 BEGIN 114 SELECT * FROM sqlite_master; 115 END 116 } 117} {0 {}} 118 119do_test trigger1-1.5 { 120 execsql { 121 BEGIN; 122 DROP TRIGGER tr2; 123 ROLLBACK; 124 DROP TRIGGER tr2; 125 } 126} {} 127 128do_test trigger1-1.6.1 { 129 catchsql { 130 DROP TRIGGER IF EXISTS biggles; 131 } 132} {0 {}} 133 134do_test trigger1-1.6.2 { 135 catchsql { 136 DROP TRIGGER biggles; 137 } 138} {1 {no such trigger: biggles}} 139 140do_test trigger1-1.7 { 141 catchsql { 142 DROP TABLE t1; 143 DROP TRIGGER tr1; 144 } 145} {1 {no such trigger: tr1}} 146 147ifcapable tempdb { 148 execsql { 149 CREATE TEMP TABLE temp_table(a); 150 } 151 do_test trigger1-1.8 { 152 execsql { 153 CREATE TRIGGER temp_trig UPDATE ON temp_table BEGIN 154 SELECT * from sqlite_master; 155 END; 156 SELECT count(*) FROM sqlite_master WHERE name = 'temp_trig'; 157 } 158 } {0} 159} 160 161do_test trigger1-1.9 { 162 catchsql { 163 CREATE TRIGGER tr1 AFTER UPDATE ON sqlite_master BEGIN 164 SELECT * FROM sqlite_master; 165 END; 166 } 167} {1 {cannot create trigger on system table}} 168 169# Check to make sure that a DELETE statement within the body of 170# a trigger does not mess up the DELETE that caused the trigger to 171# run in the first place. 172# 173do_test trigger1-1.10 { 174 execsql { 175 create table t1(a,b); 176 insert into t1 values(1,'a'); 177 insert into t1 values(2,'b'); 178 insert into t1 values(3,'c'); 179 insert into t1 values(4,'d'); 180 create trigger r1 after delete on t1 for each row begin 181 delete from t1 WHERE a=old.a+2; 182 end; 183 delete from t1 where a=1 OR a=3; 184 select * from t1; 185 drop table t1; 186 } 187} {2 b 4 d} 188 189do_test trigger1-1.11 { 190 execsql { 191 create table t1(a,b); 192 insert into t1 values(1,'a'); 193 insert into t1 values(2,'b'); 194 insert into t1 values(3,'c'); 195 insert into t1 values(4,'d'); 196 create trigger r1 after update on t1 for each row begin 197 delete from t1 WHERE a=old.a+2; 198 end; 199 update t1 set b='x-' || b where a=1 OR a=3; 200 select * from t1; 201 drop table t1; 202 } 203} {1 x-a 2 b 4 d} 204 205# Ensure that we cannot create INSTEAD OF triggers on tables 206do_test trigger1-1.12 { 207 catchsql { 208 create table t1(a,b); 209 create trigger t1t instead of update on t1 for each row begin 210 delete from t1 WHERE a=old.a+2; 211 end; 212 } 213} {1 {cannot create INSTEAD OF trigger on table: main.t1}} 214 215ifcapable view { 216# Ensure that we cannot create BEFORE triggers on views 217do_test trigger1-1.13 { 218 catchsql { 219 create view v1 as select * from t1; 220 create trigger v1t before update on v1 for each row begin 221 delete from t1 WHERE a=old.a+2; 222 end; 223 } 224} {1 {cannot create BEFORE trigger on view: main.v1}} 225# Ensure that we cannot create AFTER triggers on views 226do_test trigger1-1.14 { 227 catchsql { 228 drop view v1; 229 create view v1 as select * from t1; 230 create trigger v1t AFTER update on v1 for each row begin 231 delete from t1 WHERE a=old.a+2; 232 end; 233 } 234} {1 {cannot create AFTER trigger on view: main.v1}} 235} ;# ifcapable view 236 237# Check for memory leaks in the trigger parser 238# 239do_test trigger1-2.1 { 240 catchsql { 241 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN 242 SELECT * FROM; -- Syntax error 243 END; 244 } 245} {1 {near ";": syntax error}} 246do_test trigger1-2.2 { 247 catchsql { 248 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN 249 SELECT * FROM t1; 250 SELECT * FROM; -- Syntax error 251 END; 252 } 253} {1 {near ";": syntax error}} 254 255# Create a trigger that refers to a table that might not exist. 256# 257ifcapable tempdb { 258 do_test trigger1-3.1 { 259 execsql { 260 CREATE TEMP TABLE t2(x,y); 261 } 262 catchsql { 263 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN 264 INSERT INTO t2 VALUES(NEW.a,NEW.b); 265 END; 266 } 267 } {0 {}} 268 do_test trigger-3.2 { 269 catchsql { 270 INSERT INTO t1 VALUES(1,2); 271 SELECT * FROM t2; 272 } 273 } {1 {no such table: main.t2}} 274 do_test trigger-3.3 { 275 db close 276 set rc [catch {sqlite3 db test.db} err] 277 if {$rc} {lappend rc $err} 278 set rc 279 } {0} 280 do_test trigger-3.4 { 281 catchsql { 282 INSERT INTO t1 VALUES(1,2); 283 SELECT * FROM t2; 284 } 285 } {1 {no such table: main.t2}} 286 do_test trigger-3.5 { 287 catchsql { 288 CREATE TEMP TABLE t2(x,y); 289 INSERT INTO t1 VALUES(1,2); 290 SELECT * FROM t2; 291 } 292 } {1 {no such table: main.t2}} 293 do_test trigger-3.6 { 294 catchsql { 295 DROP TRIGGER r1; 296 CREATE TEMP TRIGGER r1 AFTER INSERT ON t1 BEGIN 297 INSERT INTO t2 VALUES(NEW.a,NEW.b); 298 END; 299 INSERT INTO t1 VALUES(1,2); 300 SELECT * FROM t2; 301 } 302 } {0 {1 2}} 303 do_test trigger-3.7 { 304 execsql { 305 DROP TABLE t2; 306 CREATE TABLE t2(x,y); 307 SELECT * FROM t2; 308 } 309 } {} 310 311 # There are two versions of trigger-3.8 and trigger-3.9. One that uses 312 # compound SELECT statements, and another that does not. 313 ifcapable compound { 314 do_test trigger1-3.8 { 315 execsql { 316 INSERT INTO t1 VALUES(3,4); 317 SELECT * FROM t1 UNION ALL SELECT * FROM t2; 318 } 319 } {1 2 3 4 3 4} 320 do_test trigger1-3.9 { 321 db close 322 sqlite3 db test.db 323 execsql { 324 INSERT INTO t1 VALUES(5,6); 325 SELECT * FROM t1 UNION ALL SELECT * FROM t2; 326 } 327 } {1 2 3 4 5 6 3 4} 328 } ;# ifcapable compound 329 ifcapable !compound { 330 do_test trigger1-3.8 { 331 execsql { 332 INSERT INTO t1 VALUES(3,4); 333 SELECT * FROM t1; 334 SELECT * FROM t2; 335 } 336 } {1 2 3 4 3 4} 337 do_test trigger1-3.9 { 338 db close 339 sqlite3 db test.db 340 execsql { 341 INSERT INTO t1 VALUES(5,6); 342 SELECT * FROM t1; 343 SELECT * FROM t2; 344 } 345 } {1 2 3 4 5 6 3 4} 346 } ;# ifcapable !compound 347 348 do_test trigger1-4.1 { 349 execsql { 350 CREATE TEMP TRIGGER r1 BEFORE INSERT ON t1 BEGIN 351 INSERT INTO t2 VALUES(NEW.a,NEW.b); 352 END; 353 INSERT INTO t1 VALUES(7,8); 354 SELECT * FROM t2; 355 } 356 } {3 4 7 8} 357 do_test trigger1-4.2 { 358 sqlite3 db2 test.db 359 execsql { 360 INSERT INTO t1 VALUES(9,10); 361 } db2; 362 db2 close 363 execsql { 364 SELECT * FROM t2; 365 } 366 } {3 4 7 8} 367 do_test trigger1-4.3 { 368 execsql { 369 DROP TABLE t1; 370 SELECT * FROM t2; 371 }; 372 } {3 4 7 8} 373 do_test trigger1-4.4 { 374 db close 375 sqlite3 db test.db 376 execsql { 377 SELECT * FROM t2; 378 }; 379 } {3 4 7 8} 380} else { 381 execsql { 382 CREATE TABLE t2(x,y); 383 DROP TABLE t1; 384 INSERT INTO t2 VALUES(3, 4); 385 INSERT INTO t2 VALUES(7, 8); 386 } 387} 388 389 390integrity_check trigger1-5.1 391 392# Create a trigger with the same name as a table. Make sure the 393# trigger works. Then drop the trigger. Make sure the table is 394# still there. 395# 396set view_v1 {} 397ifcapable view { 398 set view_v1 {view v1} 399} 400do_test trigger1-6.1 { 401 execsql {SELECT type, name FROM sqlite_master} 402} [concat $view_v1 {table t2}] 403do_test trigger1-6.2 { 404 execsql { 405 CREATE TRIGGER t2 BEFORE DELETE ON t2 BEGIN 406 SELECT RAISE(ABORT,'deletes are not permitted'); 407 END; 408 SELECT type, name FROM sqlite_master; 409 } 410} [concat $view_v1 {table t2 trigger t2}] 411do_test trigger1-6.3 { 412 catchsql {DELETE FROM t2} 413} {1 {deletes are not permitted}} 414do_test trigger1-6.4 { 415 execsql {SELECT * FROM t2} 416} {3 4 7 8} 417do_test trigger1-6.5 { 418 db close 419 sqlite3 db test.db 420 execsql {SELECT type, name FROM sqlite_master} 421} [concat $view_v1 {table t2 trigger t2}] 422do_test trigger1-6.6 { 423 execsql { 424 DROP TRIGGER t2; 425 SELECT type, name FROM sqlite_master; 426 } 427} [concat $view_v1 {table t2}] 428do_test trigger1-6.7 { 429 execsql {SELECT * FROM t2} 430} {3 4 7 8} 431do_test trigger1-6.8 { 432 db close 433 sqlite3 db test.db 434 execsql {SELECT * FROM t2} 435} {3 4 7 8} 436 437integrity_check trigger-7.1 438 439# Check to make sure the name of a trigger can be quoted so that keywords 440# can be used as trigger names. Ticket #468 441# 442do_test trigger1-8.1 { 443 execsql { 444 CREATE TRIGGER 'trigger' AFTER INSERT ON t2 BEGIN SELECT 1; END; 445 SELECT name FROM sqlite_master WHERE type='trigger'; 446 } 447} {trigger} 448do_test trigger1-8.2 { 449 execsql { 450 DROP TRIGGER 'trigger'; 451 SELECT name FROM sqlite_master WHERE type='trigger'; 452 } 453} {} 454do_test trigger1-8.3 { 455 execsql { 456 CREATE TRIGGER "trigger" AFTER INSERT ON t2 BEGIN SELECT 1; END; 457 SELECT name FROM sqlite_master WHERE type='trigger'; 458 } 459} {trigger} 460do_test trigger1-8.4 { 461 execsql { 462 DROP TRIGGER "trigger"; 463 SELECT name FROM sqlite_master WHERE type='trigger'; 464 } 465} {} 466do_test trigger1-8.5 { 467 execsql { 468 CREATE TRIGGER [trigger] AFTER INSERT ON t2 BEGIN SELECT 1; END; 469 SELECT name FROM sqlite_master WHERE type='trigger'; 470 } 471} {trigger} 472do_test trigger1-8.6 { 473 execsql { 474 DROP TRIGGER [trigger]; 475 SELECT name FROM sqlite_master WHERE type='trigger'; 476 } 477} {} 478 479ifcapable conflict { 480 # Make sure REPLACE works inside of triggers. 481 # 482 # There are two versions of trigger-9.1 and trigger-9.2. One that uses 483 # compound SELECT statements, and another that does not. 484 ifcapable compound { 485 do_test trigger1-9.1 { 486 execsql { 487 CREATE TABLE t3(a,b); 488 CREATE TABLE t4(x UNIQUE, b); 489 CREATE TRIGGER r34 AFTER INSERT ON t3 BEGIN 490 REPLACE INTO t4 VALUES(new.a,new.b); 491 END; 492 INSERT INTO t3 VALUES(1,2); 493 SELECT * FROM t3 UNION ALL SELECT 99, 99 UNION ALL SELECT * FROM t4; 494 } 495 } {1 2 99 99 1 2} 496 do_test trigger1-9.2 { 497 execsql { 498 INSERT INTO t3 VALUES(1,3); 499 SELECT * FROM t3 UNION ALL SELECT 99, 99 UNION ALL SELECT * FROM t4; 500 } 501 } {1 2 1 3 99 99 1 3} 502 } else { 503 do_test trigger1-9.1 { 504 execsql { 505 CREATE TABLE t3(a,b); 506 CREATE TABLE t4(x UNIQUE, b); 507 CREATE TRIGGER r34 AFTER INSERT ON t3 BEGIN 508 REPLACE INTO t4 VALUES(new.a,new.b); 509 END; 510 INSERT INTO t3 VALUES(1,2); 511 SELECT * FROM t3; SELECT 99, 99; SELECT * FROM t4; 512 } 513 } {1 2 99 99 1 2} 514 do_test trigger1-9.2 { 515 execsql { 516 INSERT INTO t3 VALUES(1,3); 517 SELECT * FROM t3; SELECT 99, 99; SELECT * FROM t4; 518 } 519 } {1 2 1 3 99 99 1 3} 520 } 521 execsql { 522 DROP TABLE t3; 523 DROP TABLE t4; 524 } 525} 526 527 528# Ticket #764. At one stage TEMP triggers would fail to re-install when the 529# schema was reloaded. The following tests ensure that TEMP triggers are 530# correctly re-installed. 531# 532# Also verify that references within trigger programs are resolved at 533# statement compile time, not trigger installation time. This means, for 534# example, that you can drop and re-create tables referenced by triggers. 535ifcapable tempdb&&attach { 536 do_test trigger1-10.0 { 537 file delete -force test2.db 538 file delete -force test2.db-journal 539 execsql { 540 ATTACH 'test2.db' AS aux; 541 } 542 } {} 543 do_test trigger1-10.1 { 544 execsql { 545 CREATE TABLE main.t4(a, b, c); 546 CREATE TABLE temp.t4(a, b, c); 547 CREATE TABLE aux.t4(a, b, c); 548 CREATE TABLE insert_log(db, a, b, c); 549 } 550 } {} 551 do_test trigger1-10.2 { 552 execsql { 553 CREATE TEMP TRIGGER trig1 AFTER INSERT ON main.t4 BEGIN 554 INSERT INTO insert_log VALUES('main', new.a, new.b, new.c); 555 END; 556 CREATE TEMP TRIGGER trig2 AFTER INSERT ON temp.t4 BEGIN 557 INSERT INTO insert_log VALUES('temp', new.a, new.b, new.c); 558 END; 559 CREATE TEMP TRIGGER trig3 AFTER INSERT ON aux.t4 BEGIN 560 INSERT INTO insert_log VALUES('aux', new.a, new.b, new.c); 561 END; 562 } 563 } {} 564 do_test trigger1-10.3 { 565 execsql { 566 INSERT INTO main.t4 VALUES(1, 2, 3); 567 INSERT INTO temp.t4 VALUES(4, 5, 6); 568 INSERT INTO aux.t4 VALUES(7, 8, 9); 569 } 570 } {} 571 do_test trigger1-10.4 { 572 execsql { 573 SELECT * FROM insert_log; 574 } 575 } {main 1 2 3 temp 4 5 6 aux 7 8 9} 576 do_test trigger1-10.5 { 577 execsql { 578 BEGIN; 579 INSERT INTO main.t4 VALUES(1, 2, 3); 580 INSERT INTO temp.t4 VALUES(4, 5, 6); 581 INSERT INTO aux.t4 VALUES(7, 8, 9); 582 ROLLBACK; 583 } 584 } {} 585 do_test trigger1-10.6 { 586 execsql { 587 SELECT * FROM insert_log; 588 } 589 } {main 1 2 3 temp 4 5 6 aux 7 8 9} 590 do_test trigger1-10.7 { 591 execsql { 592 DELETE FROM insert_log; 593 INSERT INTO main.t4 VALUES(11, 12, 13); 594 INSERT INTO temp.t4 VALUES(14, 15, 16); 595 INSERT INTO aux.t4 VALUES(17, 18, 19); 596 } 597 } {} 598 do_test trigger1-10.8 { 599 execsql { 600 SELECT * FROM insert_log; 601 } 602 } {main 11 12 13 temp 14 15 16 aux 17 18 19} 603 do_test trigger1-10.8 { 604 # Drop and re-create the insert_log table in a different database. Note 605 # that we can change the column names because the trigger programs don't 606 # use them explicitly. 607 execsql { 608 DROP TABLE insert_log; 609 CREATE TABLE aux.insert_log(db, d, e, f); 610 } 611 } {} 612 do_test trigger1-10.10 { 613 execsql { 614 INSERT INTO main.t4 VALUES(21, 22, 23); 615 INSERT INTO temp.t4 VALUES(24, 25, 26); 616 INSERT INTO aux.t4 VALUES(27, 28, 29); 617 } 618 } {} 619 do_test trigger1-10.11 { 620 execsql { 621 SELECT * FROM insert_log; 622 } 623 } {main 21 22 23 temp 24 25 26 aux 27 28 29} 624} 625 626do_test trigger1-11.1 { 627 catchsql {SELECT raise(abort,'message');} 628} {1 {RAISE() may only be used within a trigger-program}} 629 630do_test trigger1-15.1 { 631 execsql { 632 CREATE TABLE tA(a INTEGER PRIMARY KEY, b, c); 633 CREATE TRIGGER tA_trigger BEFORE UPDATE ON "tA" BEGIN SELECT 1; END; 634 INSERT INTO tA VALUES(1, 2, 3); 635 } 636 catchsql { UPDATE tA SET a = 'abc' } 637} {1 {datatype mismatch}} 638do_test trigger1-15.2 { 639 catchsql { INSERT INTO tA VALUES('abc', 2, 3) } 640} {1 {datatype mismatch}} 641 642# Ticket #3947: Do not allow qualified table names on INSERT, UPDATE, and 643# DELETE statements within triggers. Actually, this has never been allowed 644# by the grammar. But the error message is confusing: one simply gets a 645# "syntax error". That has now been changed to give a full error message. 646# 647do_test trigger1-16.1 { 648 db eval { 649 CREATE TABLE t16(a,b,c); 650 CREATE INDEX t16a ON t16(a); 651 CREATE INDEX t16b ON t16(b); 652 } 653 catchsql { 654 CREATE TRIGGER main.t16err1 AFTER INSERT ON tA BEGIN 655 INSERT INTO main.t16 VALUES(1,2,3); 656 END; 657 } 658} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} 659do_test trigger1-16.2 { 660 catchsql { 661 CREATE TRIGGER main.t16err2 AFTER INSERT ON tA BEGIN 662 UPDATE main.t16 SET rowid=rowid+1; 663 END; 664 } 665} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} 666do_test trigger1-16.3 { 667 catchsql { 668 CREATE TRIGGER main.t16err3 AFTER INSERT ON tA BEGIN 669 DELETE FROM main.t16; 670 END; 671 } 672} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} 673do_test trigger1-16.4 { 674 catchsql { 675 CREATE TRIGGER main.t16err4 AFTER INSERT ON tA BEGIN 676 UPDATE t16 NOT INDEXED SET rowid=rowid+1; 677 END; 678 } 679} {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} 680do_test trigger1-16.5 { 681 catchsql { 682 CREATE TRIGGER main.t16err5 AFTER INSERT ON tA BEGIN 683 UPDATE t16 INDEXED BY t16a SET rowid=rowid+1 WHERE a=1; 684 END; 685 } 686} {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} 687do_test trigger1-16.6 { 688 catchsql { 689 CREATE TRIGGER main.t16err6 AFTER INSERT ON tA BEGIN 690 DELETE FROM t16 NOT INDEXED WHERE a=123; 691 END; 692 } 693} {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} 694do_test trigger1-16.7 { 695 catchsql { 696 CREATE TRIGGER main.t16err7 AFTER INSERT ON tA BEGIN 697 DELETE FROM t16 INDEXED BY t16a WHERE a=123; 698 END; 699 } 700} {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} 701 702finish_test 703