xref: /sqlite-3.40.0/src/delete.c (revision ededfd5e)
1cce7d176Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
3cce7d176Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
6cce7d176Sdrh **
7b19a2bc6Sdrh **    May you do good and not evil.
8b19a2bc6Sdrh **    May you find forgiveness for yourself and forgive others.
9b19a2bc6Sdrh **    May you share freely, never taking more than you give.
10cce7d176Sdrh **
11cce7d176Sdrh *************************************************************************
12cce7d176Sdrh ** This file contains C code routines that are called by the parser
13cce7d176Sdrh ** to handle DELETE FROM statements.
14cce7d176Sdrh **
15*ededfd5eSdanielk1977 ** $Id: delete.c,v 1.75 2004/06/17 07:53:02 danielk1977 Exp $
16cce7d176Sdrh */
17cce7d176Sdrh #include "sqliteInt.h"
18cce7d176Sdrh 
19a76b5dfcSdrh /*
20812d7a21Sdrh ** Look up every table that is named in pSrc.  If any table is not found,
21812d7a21Sdrh ** add an error message to pParse->zErrMsg and return NULL.  If all tables
22812d7a21Sdrh ** are found, return a pointer to the last table.
23a76b5dfcSdrh */
244adee20fSdanielk1977 Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
25812d7a21Sdrh   Table *pTab = 0;
26812d7a21Sdrh   int i;
27812d7a21Sdrh   for(i=0; i<pSrc->nSrc; i++){
28812d7a21Sdrh     const char *zTab = pSrc->a[i].zName;
29812d7a21Sdrh     const char *zDb = pSrc->a[i].zDatabase;
304adee20fSdanielk1977     pTab = sqlite3LocateTable(pParse, zTab, zDb);
31812d7a21Sdrh     pSrc->a[i].pTab = pTab;
32a76b5dfcSdrh   }
33a76b5dfcSdrh   return pTab;
34a76b5dfcSdrh }
35a76b5dfcSdrh 
36a76b5dfcSdrh /*
37812d7a21Sdrh ** Check to make sure the given table is writable.  If it is not
38812d7a21Sdrh ** writable, generate an error message and return 1.  If it is
39812d7a21Sdrh ** writable return 0;
40812d7a21Sdrh */
414adee20fSdanielk1977 int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
425cf590c1Sdrh   if( pTab->readOnly ){
434adee20fSdanielk1977     sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
445cf590c1Sdrh     return 1;
455cf590c1Sdrh   }
465cf590c1Sdrh   if( !viewOk && pTab->pSelect ){
474adee20fSdanielk1977     sqlite3ErrorMsg(pParse, "cannot modify %s because it is a view",pTab->zName);
48812d7a21Sdrh     return 1;
49812d7a21Sdrh   }
50812d7a21Sdrh   return 0;
51812d7a21Sdrh }
52812d7a21Sdrh 
53812d7a21Sdrh /*
54cce7d176Sdrh ** Process a DELETE FROM statement.
55cce7d176Sdrh */
564adee20fSdanielk1977 void sqlite3DeleteFrom(
57cce7d176Sdrh   Parse *pParse,         /* The parser context */
58113088ecSdrh   SrcList *pTabList,     /* The table from which we should delete things */
59cce7d176Sdrh   Expr *pWhere           /* The WHERE clause.  May be null */
60cce7d176Sdrh ){
61cce7d176Sdrh   Vdbe *v;               /* The virtual database engine */
62cce7d176Sdrh   Table *pTab;           /* The table from which records will be deleted */
63e22a334bSdrh   const char *zDb;       /* Name of database holding pTab */
64cfe9a69fSdanielk1977   int end, addr = 0;     /* A couple addresses of generated code */
65cce7d176Sdrh   int i;                 /* Loop counter */
66cce7d176Sdrh   WhereInfo *pWInfo;     /* Information about the WHERE clause */
67cce7d176Sdrh   Index *pIdx;           /* For looping over indices of the table */
686a3ea0e6Sdrh   int iCur;              /* VDBE Cursor number for pTab */
69ecdc7530Sdrh   sqlite *db;            /* Main database structure */
705cf590c1Sdrh   int isView;            /* True if attempting to delete from a view */
7185e2096fSdrh   AuthContext sContext;  /* Authorization context */
721bee3d7bSdrh 
7370ce3f0cSdrh   int row_triggers_exist = 0;  /* True if any triggers exist */
7470ce3f0cSdrh   int before_triggers;         /* True if there are BEFORE triggers */
7570ce3f0cSdrh   int after_triggers;          /* True if there are AFTER triggers */
7670ce3f0cSdrh   int oldIdx = -1;             /* Cursor for the OLD table of AFTER triggers */
77cce7d176Sdrh 
7885e2096fSdrh   sContext.pParse = 0;
7924b03fd0Sdanielk1977   if( pParse->nErr || sqlite3_malloc_failed ){
80daffd0e5Sdrh     pTabList = 0;
81daffd0e5Sdrh     goto delete_from_cleanup;
82daffd0e5Sdrh   }
83ecdc7530Sdrh   db = pParse->db;
84113088ecSdrh   assert( pTabList->nSrc==1 );
85daffd0e5Sdrh 
861ccde15dSdrh   /* Locate the table which we want to delete.  This table has to be
87ad3cab52Sdrh   ** put in an SrcList structure because some of the subroutines we
88cce7d176Sdrh   ** will be calling are designed to work with multiple tables and expect
89ad3cab52Sdrh   ** an SrcList* parameter instead of just a Table* parameter.
90cce7d176Sdrh   */
914adee20fSdanielk1977   pTab = sqlite3SrcListLookup(pParse, pTabList);
92a69d9168Sdrh   if( pTab==0 )  goto delete_from_cleanup;
934adee20fSdanielk1977   before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
94a69d9168Sdrh                          TK_DELETE, TK_BEFORE, TK_ROW, 0);
954adee20fSdanielk1977   after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
96a69d9168Sdrh                          TK_DELETE, TK_AFTER, TK_ROW, 0);
97a69d9168Sdrh   row_triggers_exist = before_triggers || after_triggers;
985cf590c1Sdrh   isView = pTab->pSelect!=0;
994adee20fSdanielk1977   if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
1005cf590c1Sdrh     goto delete_from_cleanup;
101113088ecSdrh   }
102e22a334bSdrh   assert( pTab->iDb<db->nDb );
103e22a334bSdrh   zDb = db->aDb[pTab->iDb].zName;
1044adee20fSdanielk1977   if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
105e5f9c644Sdrh     goto delete_from_cleanup;
106e5f9c644Sdrh   }
107cce7d176Sdrh 
1085cf590c1Sdrh   /* If pTab is really a view, make sure it has been initialized.
1095cf590c1Sdrh   */
1104adee20fSdanielk1977   if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
1115cf590c1Sdrh     goto delete_from_cleanup;
1125cf590c1Sdrh   }
1135cf590c1Sdrh 
114c977f7f5Sdrh   /* Allocate a cursor used to store the old.* data for a trigger.
115c977f7f5Sdrh   */
116f29ce559Sdanielk1977   if( row_triggers_exist ){
117c3f9bad2Sdanielk1977     oldIdx = pParse->nTab++;
118f29ce559Sdanielk1977   }
119c3f9bad2Sdanielk1977 
120967e8b73Sdrh   /* Resolve the column names in all the expressions.
121cce7d176Sdrh   */
1226a3ea0e6Sdrh   assert( pTabList->nSrc==1 );
1236a3ea0e6Sdrh   iCur = pTabList->a[0].iCursor = pParse->nTab++;
124cce7d176Sdrh   if( pWhere ){
1254adee20fSdanielk1977     if( sqlite3ExprResolveIds(pParse, pTabList, 0, pWhere) ){
126cce7d176Sdrh       goto delete_from_cleanup;
127cce7d176Sdrh     }
1284adee20fSdanielk1977     if( sqlite3ExprCheck(pParse, pWhere, 0, 0) ){
129cce7d176Sdrh       goto delete_from_cleanup;
130cce7d176Sdrh     }
131cce7d176Sdrh   }
132cce7d176Sdrh 
13385e2096fSdrh   /* Start the view context
13485e2096fSdrh   */
13585e2096fSdrh   if( isView ){
1364adee20fSdanielk1977     sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
13785e2096fSdrh   }
13885e2096fSdrh 
139cce7d176Sdrh   /* Begin generating code.
140cce7d176Sdrh   */
1414adee20fSdanielk1977   v = sqlite3GetVdbe(pParse);
142f29ce559Sdanielk1977   if( v==0 ){
143f29ce559Sdanielk1977     goto delete_from_cleanup;
144f29ce559Sdanielk1977   }
1454adee20fSdanielk1977   sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
1465e00f6c7Sdrh 
1475cf590c1Sdrh   /* If we are trying to delete from a view, construct that view into
1485cf590c1Sdrh   ** a temporary table.
1495cf590c1Sdrh   */
1505cf590c1Sdrh   if( isView ){
1514adee20fSdanielk1977     Select *pView = sqlite3SelectDup(pTab->pSelect);
15284ac9d02Sdanielk1977     sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
1534adee20fSdanielk1977     sqlite3SelectDelete(pView);
1545cf590c1Sdrh   }
1555cf590c1Sdrh 
1561bee3d7bSdrh   /* Initialize the counter of the number of rows deleted, if
1571bee3d7bSdrh   ** we are counting rows.
1581bee3d7bSdrh   */
1591bee3d7bSdrh   if( db->flags & SQLITE_CountRows ){
1604adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
1611bee3d7bSdrh   }
162cce7d176Sdrh 
1630353ceddSdrh   /* Special case: A DELETE without a WHERE clause deletes everything.
164c977f7f5Sdrh   ** It is easier just to erase the whole table.  Note, however, that
165c977f7f5Sdrh   ** this means that the row change count will be incorrect.
1660353ceddSdrh   */
167c3f9bad2Sdanielk1977   if( pWhere==0 && !row_triggers_exist ){
1681bee3d7bSdrh     if( db->flags & SQLITE_CountRows ){
1691bee3d7bSdrh       /* If counting rows deleted, just count the total number of
1701bee3d7bSdrh       ** entries in the table. */
1714adee20fSdanielk1977       int endOfLoop = sqlite3VdbeMakeLabel(v);
1721bee3d7bSdrh       int addr;
1735cf590c1Sdrh       if( !isView ){
1744adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
1754adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
176b4964b72Sdanielk1977         sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
1775cf590c1Sdrh       }
1784adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
1794adee20fSdanielk1977       addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
1804adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
1814adee20fSdanielk1977       sqlite3VdbeResolveLabel(v, endOfLoop);
1824adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
1831bee3d7bSdrh     }
1845cf590c1Sdrh     if( !isView ){
1854adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
1860353ceddSdrh       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
1874adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
1880353ceddSdrh       }
1890353ceddSdrh     }
1905cf590c1Sdrh   }
1910353ceddSdrh 
1920353ceddSdrh   /* The usual case: There is a WHERE clause so we have to scan through
1938bc03a7aSjplyon   ** the table and pick which records to delete.
1940353ceddSdrh   */
1950353ceddSdrh   else{
1967cedc8d4Sdanielk1977     /* Ensure all required collation sequences are available. */
1977cedc8d4Sdanielk1977     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
1987cedc8d4Sdanielk1977       if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
1997cedc8d4Sdanielk1977         goto delete_from_cleanup;
2007cedc8d4Sdanielk1977       }
2017cedc8d4Sdanielk1977     }
2027cedc8d4Sdanielk1977 
203cce7d176Sdrh     /* Begin the database scan
204cce7d176Sdrh     */
2054adee20fSdanielk1977     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
206cce7d176Sdrh     if( pWInfo==0 ) goto delete_from_cleanup;
207cce7d176Sdrh 
2081ccde15dSdrh     /* Remember the key of every item to be deleted.
209cce7d176Sdrh     */
2104adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
2111bee3d7bSdrh     if( db->flags & SQLITE_CountRows ){
2124adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
2131bee3d7bSdrh     }
214cce7d176Sdrh 
215cce7d176Sdrh     /* End the database scan loop.
216cce7d176Sdrh     */
2174adee20fSdanielk1977     sqlite3WhereEnd(pWInfo);
218cce7d176Sdrh 
21970ce3f0cSdrh     /* Open the pseudo-table used to store OLD if there are triggers.
22070ce3f0cSdrh     */
22170ce3f0cSdrh     if( row_triggers_exist ){
2224adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
22384ac9d02Sdanielk1977       sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
22470ce3f0cSdrh     }
22570ce3f0cSdrh 
2261ccde15dSdrh     /* Delete every item whose key was written to the list during the
2271ccde15dSdrh     ** database scan.  We have to delete items after the scan is complete
2281ccde15dSdrh     ** because deleting an item can change the scan order.
229cce7d176Sdrh     */
2304adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
2314adee20fSdanielk1977     end = sqlite3VdbeMakeLabel(v);
232c3f9bad2Sdanielk1977 
233c977f7f5Sdrh     /* This is the beginning of the delete loop when there are
234c977f7f5Sdrh     ** row triggers.
235c977f7f5Sdrh     */
236c3f9bad2Sdanielk1977     if( row_triggers_exist ){
2374adee20fSdanielk1977       addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
2384adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
2395cf590c1Sdrh       if( !isView ){
2404adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
2414adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
242b4964b72Sdanielk1977         sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
2435cf590c1Sdrh       }
2447cf6e4deSdrh       sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
2454adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
2464adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
2474adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
2485cf590c1Sdrh       if( !isView ){
2494adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
2505cf590c1Sdrh       }
251c3f9bad2Sdanielk1977 
2524adee20fSdanielk1977       sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
2536f34903eSdanielk1977           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
2546f34903eSdanielk1977 	  addr);
255c3f9bad2Sdanielk1977     }
256c3f9bad2Sdanielk1977 
2575cf590c1Sdrh     if( !isView ){
258c977f7f5Sdrh       /* Open cursors for the table we are deleting from and all its
259c977f7f5Sdrh       ** indices.  If there are row triggers, this happens inside the
260c977f7f5Sdrh       ** OP_ListRead loop because the cursor have to all be closed
261c977f7f5Sdrh       ** before the trigger fires.  If there are no row triggers, the
262c977f7f5Sdrh       ** cursors are opened only once on the outside the loop.
263c977f7f5Sdrh       */
2646a3ea0e6Sdrh       pParse->nTab = iCur + 1;
2654adee20fSdanielk1977       sqlite3OpenTableAndIndices(pParse, pTab, iCur);
266c3f9bad2Sdanielk1977 
267c977f7f5Sdrh       /* This is the beginning of the delete loop when there are no
268c977f7f5Sdrh       ** row triggers */
269f29ce559Sdanielk1977       if( !row_triggers_exist ){
2704adee20fSdanielk1977         addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
271f29ce559Sdanielk1977       }
272c3f9bad2Sdanielk1977 
273c977f7f5Sdrh       /* Delete the row */
2744adee20fSdanielk1977       sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
2755cf590c1Sdrh     }
276c3f9bad2Sdanielk1977 
277c977f7f5Sdrh     /* If there are row triggers, close all cursors then invoke
278c977f7f5Sdrh     ** the AFTER triggers
279c977f7f5Sdrh     */
280c3f9bad2Sdanielk1977     if( row_triggers_exist ){
2815cf590c1Sdrh       if( !isView ){
282c3f9bad2Sdanielk1977         for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
2834adee20fSdanielk1977           sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
284c3f9bad2Sdanielk1977         }
2854adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
2865cf590c1Sdrh       }
2874adee20fSdanielk1977       sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
2886f34903eSdanielk1977           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
2896f34903eSdanielk1977 	  addr);
290c3f9bad2Sdanielk1977     }
291c3f9bad2Sdanielk1977 
292c977f7f5Sdrh     /* End of the delete loop */
2934adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
2944adee20fSdanielk1977     sqlite3VdbeResolveLabel(v, end);
2954adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
296c3f9bad2Sdanielk1977 
297c977f7f5Sdrh     /* Close the cursors after the loop if there are no row triggers */
298c3f9bad2Sdanielk1977     if( !row_triggers_exist ){
299c3f9bad2Sdanielk1977       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
3004adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
301c3f9bad2Sdanielk1977       }
3024adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
3036a3ea0e6Sdrh       pParse->nTab = iCur;
304c3f9bad2Sdanielk1977     }
3050353ceddSdrh   }
3064adee20fSdanielk1977   sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
3074adee20fSdanielk1977   sqlite3EndWriteOperation(pParse);
3085e00f6c7Sdrh 
3091bee3d7bSdrh   /*
3101bee3d7bSdrh   ** Return the number of rows that were deleted.
3111bee3d7bSdrh   */
3121bee3d7bSdrh   if( db->flags & SQLITE_CountRows ){
3134adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
31422322fd4Sdanielk1977     sqlite3VdbeSetNumCols(v, 1);
3153cf86063Sdanielk1977     sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
3161bee3d7bSdrh   }
317cce7d176Sdrh 
318cce7d176Sdrh delete_from_cleanup:
3194adee20fSdanielk1977   sqlite3AuthContextPop(&sContext);
3204adee20fSdanielk1977   sqlite3SrcListDelete(pTabList);
3214adee20fSdanielk1977   sqlite3ExprDelete(pWhere);
322cce7d176Sdrh   return;
323cce7d176Sdrh }
3249cfcf5d4Sdrh 
3259cfcf5d4Sdrh /*
3269cfcf5d4Sdrh ** This routine generates VDBE code that causes a single row of a
3279cfcf5d4Sdrh ** single table to be deleted.
3289cfcf5d4Sdrh **
3299cfcf5d4Sdrh ** The VDBE must be in a particular state when this routine is called.
3309cfcf5d4Sdrh ** These are the requirements:
3319cfcf5d4Sdrh **
3329cfcf5d4Sdrh **   1.  A read/write cursor pointing to pTab, the table containing the row
3339cfcf5d4Sdrh **       to be deleted, must be opened as cursor number "base".
3349cfcf5d4Sdrh **
3359cfcf5d4Sdrh **   2.  Read/write cursors for all indices of pTab must be open as
3369cfcf5d4Sdrh **       cursor number base+i for the i-th index.
3379cfcf5d4Sdrh **
3389cfcf5d4Sdrh **   3.  The record number of the row to be deleted must be on the top
3399cfcf5d4Sdrh **       of the stack.
3409cfcf5d4Sdrh **
3419cfcf5d4Sdrh ** This routine pops the top of the stack to remove the record number
3429cfcf5d4Sdrh ** and then generates code to remove both the table record and all index
3439cfcf5d4Sdrh ** entries that point to that record.
3449cfcf5d4Sdrh */
3454adee20fSdanielk1977 void sqlite3GenerateRowDelete(
34638640e15Sdrh   sqlite *db,        /* The database containing the index */
3479cfcf5d4Sdrh   Vdbe *v,           /* Generate code into this VDBE */
3489cfcf5d4Sdrh   Table *pTab,       /* Table containing the row to be deleted */
3496a3ea0e6Sdrh   int iCur,          /* Cursor number for the table */
350c8d30ac1Sdrh   int count          /* Increment the row change counter */
3519cfcf5d4Sdrh ){
35207d6e3a7Sdrh   int addr;
3534adee20fSdanielk1977   addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
3544adee20fSdanielk1977   sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
3554adee20fSdanielk1977   sqlite3VdbeAddOp(v, OP_Delete, iCur,
356b0c374ffSrdc     (count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
3574adee20fSdanielk1977   sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
3580ca3e24bSdrh }
3590ca3e24bSdrh 
3600ca3e24bSdrh /*
3610ca3e24bSdrh ** This routine generates VDBE code that causes the deletion of all
3620ca3e24bSdrh ** index entries associated with a single row of a single table.
3630ca3e24bSdrh **
3640ca3e24bSdrh ** The VDBE must be in a particular state when this routine is called.
3650ca3e24bSdrh ** These are the requirements:
3660ca3e24bSdrh **
3670ca3e24bSdrh **   1.  A read/write cursor pointing to pTab, the table containing the row
3686a3ea0e6Sdrh **       to be deleted, must be opened as cursor number "iCur".
3690ca3e24bSdrh **
3700ca3e24bSdrh **   2.  Read/write cursors for all indices of pTab must be open as
3716a3ea0e6Sdrh **       cursor number iCur+i for the i-th index.
3720ca3e24bSdrh **
3736a3ea0e6Sdrh **   3.  The "iCur" cursor must be pointing to the row that is to be
3740ca3e24bSdrh **       deleted.
3750ca3e24bSdrh */
3764adee20fSdanielk1977 void sqlite3GenerateRowIndexDelete(
37738640e15Sdrh   sqlite *db,        /* The database containing the index */
3780ca3e24bSdrh   Vdbe *v,           /* Generate code into this VDBE */
3790ca3e24bSdrh   Table *pTab,       /* Table containing the row to be deleted */
3806a3ea0e6Sdrh   int iCur,          /* Cursor number for the table */
3810ca3e24bSdrh   char *aIdxUsed     /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
3820ca3e24bSdrh ){
3839cfcf5d4Sdrh   int i;
3849cfcf5d4Sdrh   Index *pIdx;
3859cfcf5d4Sdrh 
3869cfcf5d4Sdrh   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
3870ca3e24bSdrh     if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
38851846b56Sdrh     sqlite3GenerateIndexKey(v, pIdx, iCur);
38951846b56Sdrh     sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
39051846b56Sdrh   }
39151846b56Sdrh }
39251846b56Sdrh 
39351846b56Sdrh /*
39451846b56Sdrh ** Generate code that will assemble an index key and put it on the top
39551846b56Sdrh ** of the tack.  The key with be for index pIdx which is an index on pTab.
39651846b56Sdrh ** iCur is the index of a cursor open on the pTab table and pointing to
39751846b56Sdrh ** the entry that needs indexing.
39851846b56Sdrh */
39951846b56Sdrh void sqlite3GenerateIndexKey(
40051846b56Sdrh   Vdbe *v,           /* Generate code into this VDBE */
40151846b56Sdrh   Index *pIdx,       /* The index for which to generate a key */
40251846b56Sdrh   int iCur           /* Cursor number for the pIdx->pTable table */
40351846b56Sdrh ){
40451846b56Sdrh   int j;
40551846b56Sdrh   Table *pTab = pIdx->pTable;
40651846b56Sdrh 
4074adee20fSdanielk1977   sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
4089cfcf5d4Sdrh   for(j=0; j<pIdx->nColumn; j++){
4099cfcf5d4Sdrh     int idx = pIdx->aiColumn[j];
4109cfcf5d4Sdrh     if( idx==pTab->iPKey ){
4114adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Dup, j, 0);
4129cfcf5d4Sdrh     }else{
4134adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
4149cfcf5d4Sdrh     }
4159cfcf5d4Sdrh   }
416*ededfd5eSdanielk1977   sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
417a37cdde0Sdanielk1977   sqlite3IndexAffinityStr(v, pIdx);
4189cfcf5d4Sdrh }
419