aboutsummaryrefslogtreecommitdiff
path: root/src/delete.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/delete.c')
-rw-r--r--src/delete.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/src/delete.c b/src/delete.c
index 7e5b7bfc4..a384ade73 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -308,7 +308,7 @@ void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, (pTrigger?1:0), iDb);
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
/* If we are trying to delete from a view, realize that view into
** a ephemeral table.
@@ -341,7 +341,9 @@ void sqlite3DeleteFrom(
** It is easier just to erase the whole table. Prior to version 3.6.5,
** this optimization caused the row change count (the value returned by
** API function sqlite3_count_changes) to be set incorrectly. */
- if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) ){
+ if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
+ && 0==sqlite3FkRequired(pParse, pTab, 0)
+ ){
assert( !isView );
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
pTab->zName, P4_STATIC);
@@ -446,7 +448,7 @@ delete_from_cleanup:
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
-** to be deleted, must be opened as cursor number "base".
+** to be deleted, must be opened as cursor number $iCur.
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
@@ -481,13 +483,13 @@ void sqlite3GenerateRowDelete(
/* If there are any triggers to fire, allocate a range of registers to
** use for the old.* references in the triggers. */
- if( pTrigger ){
+ if( sqlite3FkRequired(pParse, pTab, 0) || pTrigger ){
u32 mask; /* Mask of OLD.* columns in use */
int iCol; /* Iterator used while populating OLD.* */
/* TODO: Could use temporary registers here. Also could attempt to
** avoid copying the contents of the rowid register. */
- mask = sqlite3TriggerOldmask(pParse, pTrigger, TK_DELETE, 0, pTab, onconf);
+ mask = sqlite3TriggerOldmask(pParse, pTrigger, 0, pTab, onconf);
iOld = pParse->nMem+1;
pParse->nMem += (1 + pTab->nCol);
@@ -495,14 +497,14 @@ void sqlite3GenerateRowDelete(
** used by any BEFORE and AFTER triggers that exist. */
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld);
for(iCol=0; iCol<pTab->nCol; iCol++){
- if( mask==0xffffffff || mask&(1<<iCol) ){
+ if( 1 || mask==0xffffffff || mask&(1<<iCol) ){
int iTarget = iOld + iCol + 1;
sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget);
sqlite3ColumnDefault(v, pTab, iCol, iTarget);
}
}
- /* Invoke any BEFORE trigger programs */
+ /* Invoke BEFORE DELETE trigger programs. */
sqlite3CodeRowTrigger(pParse, pTrigger,
TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, iOld, onconf, iLabel
);
@@ -512,6 +514,11 @@ void sqlite3GenerateRowDelete(
** being deleted. Do not attempt to delete the row a second time, and
** do not fire AFTER triggers. */
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, iLabel, iRowid);
+
+ /* Do FK processing. This call checks that any FK constraints that
+ ** refer to this table (i.e. constraints attached to other tables)
+ ** are not violated by deleting this row. */
+ sqlite3FkCheck(pParse, pTab, 0, iOld, 0);
}
/* Delete the index and table entries. Skip this step if pTab is really
@@ -525,12 +532,15 @@ void sqlite3GenerateRowDelete(
}
}
- /* Invoke AFTER triggers. */
- if( pTrigger ){
- sqlite3CodeRowTrigger(pParse, pTrigger,
- TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, iOld, onconf, iLabel
- );
- }
+ /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
+ ** handle rows (possibly in other tables) that refer via a foreign key
+ ** to the row just deleted. */
+ sqlite3FkActions(pParse, pTab, 0, iOld);
+
+ /* Invoke AFTER DELETE trigger programs. */
+ sqlite3CodeRowTrigger(pParse, pTrigger,
+ TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, iOld, onconf, iLabel
+ );
/* Jump here if the row had already been deleted before any BEFORE
** trigger programs were invoked. Or if a trigger program throws a