Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add some tests that involve BEFORE UPDATE or BEFORE DELETE triggers messing with the row being updated or deleted. SQLite behaviour in this scenario is undefined, so the tests just check that the behaviour is relatively sane and there are no crashes. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9a4c59a2ddd0df2d9425097004b450a6 |
User & Date: | dan 2009-09-09 15:06:11.000 |
Context
2009-09-09
| ||
15:29 | Bug fix in the SQLITE_OPEN_PRIVATECACHE option added a few minutes ago. (check-in: f3a0f23bc7 user: drh tags: trunk) | |
15:06 | Add some tests that involve BEFORE UPDATE or BEFORE DELETE triggers messing with the row being updated or deleted. SQLite behaviour in this scenario is undefined, so the tests just check that the behaviour is relatively sane and there are no crashes. (check-in: 9a4c59a2dd user: dan tags: trunk) | |
14:48 | Update the README file to state that TCL is required in order to run the makefiles for SQLite. Ticket [7d96113ff]. (check-in: ba20091ae8 user: drh tags: trunk) | |
Changes
Changes to src/update.c.
︙ | ︙ | |||
424 425 426 427 428 429 430 431 432 433 434 435 436 437 | /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( pTrigger ){ sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, -1, regOldRowid, onError, addr); } if( !isView ){ /* Do constraint checks. */ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid, aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0); | > > > > > > > | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( pTrigger ){ sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, -1, regOldRowid, onError, addr); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are ** required. This behaviour - what happens when the row being updated ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); } if( !isView ){ /* Do constraint checks. */ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid, aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4725 4726 4727 4728 4729 4730 4731 | SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ pProgram = pOp->p4.pProgram; pRt = &p->aMem[pOp->p3]; assert( pProgram->nOp>0 ); | | | | 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 | SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ pProgram = pOp->p4.pProgram; pRt = &p->aMem[pOp->p3]; assert( pProgram->nOp>0 ); /* If the SQLITE_RecTriggers flag is clear, then recursive invocation of ** triggers is disabled for backwards compatibility (flag set/cleared by ** the "PRAGMA recursive_triggers" command). ** ** It is recursive invocation of triggers, at the SQL level, that is ** disabled. In some cases a single trigger may generate more than one ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a ** single trigger all have the same value for the SubProgram.token ** variable. |
︙ | ︙ |
Changes to test/triggerC.test.
︙ | ︙ | |||
663 664 665 666 667 668 669 | } } {1} #------------------------------------------------------------------------- # Test some of the "undefined behaviour" associated with triggers. The # undefined behaviour occurs when a row being updated or deleted is # manipulated by a BEFORE trigger. | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | } } {1} #------------------------------------------------------------------------- # Test some of the "undefined behaviour" associated with triggers. The # undefined behaviour occurs when a row being updated or deleted is # manipulated by a BEFORE trigger. # do_test triggerC-7.1 { execsql { CREATE TABLE t8(x); CREATE TABLE t7(a, b); INSERT INTO t7 VALUES(1, 2); INSERT INTO t7 VALUES(3, 4); INSERT INTO t7 VALUES(5, 6); CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN DELETE FROM t7 WHERE a = 1; END; CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid); END; } } {} do_test triggerC-7.2 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 5; SELECT * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 4 5 7 {after fired 3->3}} do_test triggerC-7.3 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 1; SELECT * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 4 5 6} do_test triggerC-7.4 { execsql { DROP TRIGGER t7t; CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8) BEGIN UPDATE t7 set rowid = 8 WHERE rowid=1; END; } } {} do_test triggerC-7.5 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 5; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}} do_test triggerC-7.6 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 1; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 6 8 1 2 {after fired 1->8}} do_test triggerC-7.7 { execsql { DROP TRIGGER t7t; DROP TRIGGER t7ta; CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN UPDATE t7 set rowid = 8 WHERE rowid=1; END; CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN INSERT INTO t8 VALUES('after fired ' || old.rowid); END; } } {} do_test triggerC-7.8 { execsql { BEGIN; DELETE FROM t7 WHERE a = 3; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 5 6 8 1 2 {after fired 2}} do_test triggerC-7.9 { execsql { BEGIN; DELETE FROM t7 WHERE a = 1; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 6 8 1 2} finish_test |