diff options
Diffstat (limited to 'src/delete.c')
-rw-r--r-- | src/delete.c | 101 |
1 files changed, 32 insertions, 69 deletions
diff --git a/src/delete.c b/src/delete.c index abf7e0c74..1425fea83 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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); |