1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-06 15:49:35 +03:00

Changes to support recursive triggers.

FossilOrigin-Name: 9b9c19211593d5ff7b39254a29c284560a8bcedb
This commit is contained in:
dan
2009-08-28 18:53:45 +00:00
parent e408edac16
commit 165921a742
25 changed files with 889 additions and 581 deletions

View File

@@ -228,7 +228,6 @@ void sqlite3DeleteFrom(
int iCur; /* VDBE Cursor number for pTab */
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */
int iDb; /* Database number */
int memCnt = -1; /* Memory cell used for change counting */
@@ -238,11 +237,6 @@ void sqlite3DeleteFrom(
int isView; /* True if attempting to delete from a view */
Trigger *pTrigger; /* List of table triggers, if required */
#endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
int iBeginBeforeTrigger = 0; /* Address of before trigger program */
int iEndBeforeTrigger = 0; /* Exit of before trigger program */
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
memset(&sContext, 0, sizeof(sContext));
db = pParse->db;
@@ -293,12 +287,6 @@ void sqlite3DeleteFrom(
}
assert(!isView || pTrigger);
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( pTrigger ){
oldIdx = pParse->nTab++;
}
/* Assign cursor number to the table and all its indices.
*/
assert( pTabList->nSrc==1 );
@@ -322,24 +310,6 @@ void sqlite3DeleteFrom(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, (pTrigger?1:0), iDb);
if( pTrigger ){
int orconf = ((pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
int iGoto = sqlite3VdbeAddOp0(v, OP_Goto);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_BEFORE, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndBeforeTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_AFTER, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndAfterTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, iGoto);
}
/* If we are trying to delete from a view, realize that view into
** a ephemeral table.
*/
@@ -385,8 +355,9 @@ void sqlite3DeleteFrom(
** the table and pick which records to delete.
*/
{
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
int regOld = pParse->nMem + 1; /* Start of array for old.* (if triggers) */
int regRowid; /* Actual register containing rowids */
/* Collect rowids of every row to be deleted.
@@ -401,35 +372,31 @@ void sqlite3DeleteFrom(
}
sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( pTrigger ){
sqlite3VdbeAddOp3(v, OP_OpenPseudo, oldIdx, 0, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
** because deleting an item can change the scan order. */
end = sqlite3VdbeMakeLabel(v);
/* Unless this is a view, open cursors for the table we are
** deleting from and all its indices. If this is a view, then the
** only effect this statement has is to fire the INSTEAD OF
** triggers. */
if( !isView ){
/* Open cursors for the table we are deleting from and
** all its indices.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
}
/* This is the beginning of the delete loop. If a trigger encounters
** an IGNORE constraint, it jumps back to here.
*/
if( pTrigger ){
sqlite3VdbeResolveLabel(v, addr);
}
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
/* If there are triggers, populate an array of registers with the
** data required by the old.* references in the trigger bodies. */
if( pTrigger ){
int iData = ++pParse->nMem; /* For storing row data of OLD table */
u32 mask = 0; /* Mask of OLD.* columns in use */
u32 dummy = 0; /* Unused. Initialized to prevent valgrind error. */
pParse->nMem += pTab->nCol;
/* Open the pseudo-table used to store OLD if there are triggers. */
sqlite3TriggerUses(
pParse, pTrigger, TK_DELETE, 0, pTab, OE_Default, &mask, &dummy);
/* If the record is no longer present in the table, jump to the
** next iteration of the loop through the contents of the fifo.
@@ -437,16 +404,16 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
/* Populate the OLD.* pseudo-table */
if( old_col_mask ){
sqlite3VdbeAddOp2(v, OP_RowData, iCur, iData);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, iData);
assert( regOld==iRowid+1 );
for(i=0; i<pTab->nCol; i++){
if( mask==0xffffffff || mask&(1<<i) ){
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
}
}
sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, iData, iRowid);
/* Jump back and run the BEFORE triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
sqlite3CodeRowTrigger(pParse, pTrigger,
TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, regOld, OE_Default, addr
);
}
if( !isView ){
@@ -463,21 +430,17 @@ void sqlite3DeleteFrom(
}
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( pTrigger ){
/* Jump back and run the AFTER triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
/* Code the AFTER triggers. This is a no-op if there are no triggers. */
sqlite3CodeRowTrigger(pParse,
pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, regOld, OE_Default, addr
);
/* End of the delete loop */
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
if( !isView && !IsVirtual(pTab) ){
/* Close the cursors open on the table and its indexes. */
if( !isView && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
}
@@ -489,7 +452,7 @@ void sqlite3DeleteFrom(
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
if( pParse->nested==0 && pParse->trigStack==0 ){
if( pParse->nested==0 && pParse->pTriggerTab==0 ){
sqlite3AutoincrementEnd(pParse);
}
@@ -498,7 +461,7 @@ void sqlite3DeleteFrom(
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);