mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
Check in implementation of foreign key constraints.
FossilOrigin-Name: d5d399811876391642937edeb9e8434dd9e356f5
This commit is contained in:
36
src/delete.c
36
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
|
||||
|
||||
Reference in New Issue
Block a user