diff options
author | dan <dan@noemail.net> | 2009-09-19 17:00:31 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2009-09-19 17:00:31 +0000 |
commit | 1da40a381fcf28953cd914aa1cff2d4d2f30ffb0 (patch) | |
tree | 499fd358c9173002d540833d9a7a77c3421119d4 /src/delete.c | |
parent | 3991bb0deec345af79e0346bc0b29a0f8a594a3a (diff) | |
download | sqlite-1da40a381fcf28953cd914aa1cff2d4d2f30ffb0.tar.gz sqlite-1da40a381fcf28953cd914aa1cff2d4d2f30ffb0.zip |
Check in implementation of foreign key constraints.
FossilOrigin-Name: d5d399811876391642937edeb9e8434dd9e356f5
Diffstat (limited to 'src/delete.c')
-rw-r--r-- | src/delete.c | 36 |
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 |