Index: third_party/sqlite/src/src/delete.c |
diff --git a/third_party/sqlite/src/src/delete.c b/third_party/sqlite/src/src/delete.c |
index 7e5b7bfc4f643f9e30a90c51b7df2b93e8081dec..e5389e2b6a743fada5ffecdb04dd080603be31a5 100644 |
--- a/third_party/sqlite/src/src/delete.c |
+++ b/third_party/sqlite/src/src/delete.c |
@@ -11,22 +11,29 @@ |
************************************************************************* |
** This file contains C code routines that are called by the parser |
** in order to generate code for DELETE FROM statements. |
-** |
-** $Id: delete.c,v 1.207 2009/08/08 18:01:08 drh Exp $ |
*/ |
#include "sqliteInt.h" |
/* |
-** Look up every table that is named in pSrc. If any table is not found, |
-** add an error message to pParse->zErrMsg and return NULL. If all tables |
-** are found, return a pointer to the last table. |
+** While a SrcList can in general represent multiple tables and subqueries |
+** (as in the FROM clause of a SELECT statement) in this case it contains |
+** the name of a single table, as one might find in an INSERT, DELETE, |
+** or UPDATE statement. Look up that table in the symbol table and |
+** return a pointer. Set an error message and return NULL if the table |
+** name is not found or if any other error occurs. |
+** |
+** The following fields are initialized appropriate in pSrc: |
+** |
+** pSrc->a[0].pTab Pointer to the Table object |
+** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one |
+** |
*/ |
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ |
struct SrcList_item *pItem = pSrc->a; |
Table *pTab; |
assert( pItem && pSrc->nSrc==1 ); |
pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase); |
- sqlite3DeleteTable(pItem->pTab); |
+ sqlite3DeleteTable(pParse->db, pItem->pTab); |
pItem->pTab = pTab; |
if( pTab ){ |
pTab->nRef++; |
@@ -308,7 +315,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 +348,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, 0) |
+ ){ |
assert( !isView ); |
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, |
pTab->zName, P4_STATIC); |
@@ -364,7 +373,7 @@ void sqlite3DeleteFrom( |
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); |
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK); |
if( pWInfo==0 ) goto delete_from_cleanup; |
- regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0); |
+ regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid); |
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid); |
if( db->flags & SQLITE_CountRows ){ |
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); |
@@ -437,6 +446,15 @@ delete_from_cleanup: |
sqlite3ExprDelete(db, pWhere); |
return; |
} |
+/* Make sure "isView" and other macros defined above are undefined. Otherwise |
+** thely may interfere with compilation of other functions in this file |
+** (or in another file, if this file becomes part of the amalgamation). */ |
+#ifdef isView |
+ #undef isView |
+#endif |
+#ifdef pTrigger |
+ #undef pTrigger |
+#endif |
/* |
** This routine generates VDBE code that causes a single row of a |
@@ -446,7 +464,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 +499,16 @@ 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, 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 = sqlite3TriggerColmask( |
+ pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf |
+ ); |
+ mask |= sqlite3FkOldmask(pParse, pTab); |
iOld = pParse->nMem+1; |
pParse->nMem += (1 + pTab->nCol); |
@@ -496,15 +517,13 @@ void sqlite3GenerateRowDelete( |
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld); |
for(iCol=0; iCol<pTab->nCol; iCol++){ |
if( mask==0xffffffff || mask&(1<<iCol) ){ |
- int iTarget = iOld + iCol + 1; |
- sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget); |
- sqlite3ColumnDefault(v, pTab, iCol, iTarget); |
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1); |
} |
} |
- /* Invoke any BEFORE trigger programs */ |
+ /* Invoke BEFORE DELETE trigger programs. */ |
sqlite3CodeRowTrigger(pParse, pTrigger, |
- TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, iOld, onconf, iLabel |
+ TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel |
); |
/* Seek the cursor to the row to be deleted again. It may be that |
@@ -512,6 +531,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, iOld, 0); |
} |
/* Delete the index and table entries. Skip this step if pTab is really |
@@ -521,16 +545,19 @@ void sqlite3GenerateRowDelete( |
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0); |
sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); |
if( count ){ |
- sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); |
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT); |
} |
} |
- /* 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, 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 |
@@ -609,14 +636,8 @@ int sqlite3GenerateIndexKey( |
} |
if( doMakeRec ){ |
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); |
- sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0); |
- sqlite3ExprCacheAffinityChange(pParse, regBase, nCol+1); |
+ sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); |
} |
sqlite3ReleaseTempRange(pParse, regBase, nCol+1); |
return regBase; |
} |
- |
-/* Make sure "isView" gets undefined in case this file becomes part of |
-** the amalgamation - so that subsequent files do not see isView as a |
-** macro. */ |
-#undef isView |