xref: /sqlite-3.40.0/src/delete.c (revision 290c1948)
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*290c1948Sdrh ** $Id: delete.c,v 1.78 2004/08/21 17:54:45 drh 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++;
124*290c1948Sdrh   if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
125cce7d176Sdrh     goto delete_from_cleanup;
126cce7d176Sdrh   }
127cce7d176Sdrh 
12885e2096fSdrh   /* Start the view context
12985e2096fSdrh   */
13085e2096fSdrh   if( isView ){
1314adee20fSdanielk1977     sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
13285e2096fSdrh   }
13385e2096fSdrh 
134cce7d176Sdrh   /* Begin generating code.
135cce7d176Sdrh   */
1364adee20fSdanielk1977   v = sqlite3GetVdbe(pParse);
137f29ce559Sdanielk1977   if( v==0 ){
138f29ce559Sdanielk1977     goto delete_from_cleanup;
139f29ce559Sdanielk1977   }
140b28af71aSdanielk1977   sqlite3VdbeCountChanges(v);
1414adee20fSdanielk1977   sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
1425e00f6c7Sdrh 
1435cf590c1Sdrh   /* If we are trying to delete from a view, construct that view into
1445cf590c1Sdrh   ** a temporary table.
1455cf590c1Sdrh   */
1465cf590c1Sdrh   if( isView ){
1474adee20fSdanielk1977     Select *pView = sqlite3SelectDup(pTab->pSelect);
14884ac9d02Sdanielk1977     sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
1494adee20fSdanielk1977     sqlite3SelectDelete(pView);
1505cf590c1Sdrh   }
1515cf590c1Sdrh 
1521bee3d7bSdrh   /* Initialize the counter of the number of rows deleted, if
1531bee3d7bSdrh   ** we are counting rows.
1541bee3d7bSdrh   */
1551bee3d7bSdrh   if( db->flags & SQLITE_CountRows ){
1564adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
1571bee3d7bSdrh   }
158cce7d176Sdrh 
1590353ceddSdrh   /* Special case: A DELETE without a WHERE clause deletes everything.
160c977f7f5Sdrh   ** It is easier just to erase the whole table.  Note, however, that
161c977f7f5Sdrh   ** this means that the row change count will be incorrect.
1620353ceddSdrh   */
163c3f9bad2Sdanielk1977   if( pWhere==0 && !row_triggers_exist ){
1641bee3d7bSdrh     if( db->flags & SQLITE_CountRows ){
1651bee3d7bSdrh       /* If counting rows deleted, just count the total number of
1661bee3d7bSdrh       ** entries in the table. */
1674adee20fSdanielk1977       int endOfLoop = sqlite3VdbeMakeLabel(v);
1681bee3d7bSdrh       int addr;
1695cf590c1Sdrh       if( !isView ){
1704adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
1714adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
172b4964b72Sdanielk1977         sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
1735cf590c1Sdrh       }
1744adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
1754adee20fSdanielk1977       addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
1764adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
1774adee20fSdanielk1977       sqlite3VdbeResolveLabel(v, endOfLoop);
1784adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
1791bee3d7bSdrh     }
1805cf590c1Sdrh     if( !isView ){
1814adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
1820353ceddSdrh       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
1834adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
1840353ceddSdrh       }
1850353ceddSdrh     }
1865cf590c1Sdrh   }
1870353ceddSdrh 
1880353ceddSdrh   /* The usual case: There is a WHERE clause so we have to scan through
1898bc03a7aSjplyon   ** the table and pick which records to delete.
1900353ceddSdrh   */
1910353ceddSdrh   else{
1927cedc8d4Sdanielk1977     /* Ensure all required collation sequences are available. */
1937cedc8d4Sdanielk1977     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
1947cedc8d4Sdanielk1977       if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
1957cedc8d4Sdanielk1977         goto delete_from_cleanup;
1967cedc8d4Sdanielk1977       }
1977cedc8d4Sdanielk1977     }
1987cedc8d4Sdanielk1977 
199cce7d176Sdrh     /* Begin the database scan
200cce7d176Sdrh     */
2014adee20fSdanielk1977     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
202cce7d176Sdrh     if( pWInfo==0 ) goto delete_from_cleanup;
203cce7d176Sdrh 
2041ccde15dSdrh     /* Remember the key of every item to be deleted.
205cce7d176Sdrh     */
2064adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
2071bee3d7bSdrh     if( db->flags & SQLITE_CountRows ){
2084adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
2091bee3d7bSdrh     }
210cce7d176Sdrh 
211cce7d176Sdrh     /* End the database scan loop.
212cce7d176Sdrh     */
2134adee20fSdanielk1977     sqlite3WhereEnd(pWInfo);
214cce7d176Sdrh 
21570ce3f0cSdrh     /* Open the pseudo-table used to store OLD if there are triggers.
21670ce3f0cSdrh     */
21770ce3f0cSdrh     if( row_triggers_exist ){
2184adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
21984ac9d02Sdanielk1977       sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
22070ce3f0cSdrh     }
22170ce3f0cSdrh 
2221ccde15dSdrh     /* Delete every item whose key was written to the list during the
2231ccde15dSdrh     ** database scan.  We have to delete items after the scan is complete
2241ccde15dSdrh     ** because deleting an item can change the scan order.
225cce7d176Sdrh     */
2264adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
2274adee20fSdanielk1977     end = sqlite3VdbeMakeLabel(v);
228c3f9bad2Sdanielk1977 
229c977f7f5Sdrh     /* This is the beginning of the delete loop when there are
230c977f7f5Sdrh     ** row triggers.
231c977f7f5Sdrh     */
232c3f9bad2Sdanielk1977     if( row_triggers_exist ){
2334adee20fSdanielk1977       addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
2344adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
2355cf590c1Sdrh       if( !isView ){
2364adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
2374adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
238b4964b72Sdanielk1977         sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
2395cf590c1Sdrh       }
2407cf6e4deSdrh       sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
2414adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
2424adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
2434adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
2445cf590c1Sdrh       if( !isView ){
2454adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
2465cf590c1Sdrh       }
247c3f9bad2Sdanielk1977 
2484adee20fSdanielk1977       sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
2496f34903eSdanielk1977           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
2506f34903eSdanielk1977 	  addr);
251c3f9bad2Sdanielk1977     }
252c3f9bad2Sdanielk1977 
2535cf590c1Sdrh     if( !isView ){
254c977f7f5Sdrh       /* Open cursors for the table we are deleting from and all its
255c977f7f5Sdrh       ** indices.  If there are row triggers, this happens inside the
256c977f7f5Sdrh       ** OP_ListRead loop because the cursor have to all be closed
257c977f7f5Sdrh       ** before the trigger fires.  If there are no row triggers, the
258c977f7f5Sdrh       ** cursors are opened only once on the outside the loop.
259c977f7f5Sdrh       */
260*290c1948Sdrh       sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
261c3f9bad2Sdanielk1977 
262c977f7f5Sdrh       /* This is the beginning of the delete loop when there are no
263c977f7f5Sdrh       ** row triggers */
264f29ce559Sdanielk1977       if( !row_triggers_exist ){
2654adee20fSdanielk1977         addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
266f29ce559Sdanielk1977       }
267c3f9bad2Sdanielk1977 
268c977f7f5Sdrh       /* Delete the row */
269b28af71aSdanielk1977       sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
2705cf590c1Sdrh     }
271c3f9bad2Sdanielk1977 
272c977f7f5Sdrh     /* If there are row triggers, close all cursors then invoke
273c977f7f5Sdrh     ** the AFTER triggers
274c977f7f5Sdrh     */
275c3f9bad2Sdanielk1977     if( row_triggers_exist ){
2765cf590c1Sdrh       if( !isView ){
277c3f9bad2Sdanielk1977         for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
2784adee20fSdanielk1977           sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
279c3f9bad2Sdanielk1977         }
2804adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
2815cf590c1Sdrh       }
2824adee20fSdanielk1977       sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
2836f34903eSdanielk1977           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
2846f34903eSdanielk1977 	  addr);
285c3f9bad2Sdanielk1977     }
286c3f9bad2Sdanielk1977 
287c977f7f5Sdrh     /* End of the delete loop */
2884adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
2894adee20fSdanielk1977     sqlite3VdbeResolveLabel(v, end);
2904adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
291c3f9bad2Sdanielk1977 
292c977f7f5Sdrh     /* Close the cursors after the loop if there are no row triggers */
293c3f9bad2Sdanielk1977     if( !row_triggers_exist ){
294c3f9bad2Sdanielk1977       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
2954adee20fSdanielk1977         sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
296c3f9bad2Sdanielk1977       }
2974adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
298c3f9bad2Sdanielk1977     }
2990353ceddSdrh   }
3004adee20fSdanielk1977   sqlite3EndWriteOperation(pParse);
3015e00f6c7Sdrh 
3021bee3d7bSdrh   /*
3031bee3d7bSdrh   ** Return the number of rows that were deleted.
3041bee3d7bSdrh   */
3051bee3d7bSdrh   if( db->flags & SQLITE_CountRows ){
3064adee20fSdanielk1977     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
30722322fd4Sdanielk1977     sqlite3VdbeSetNumCols(v, 1);
3083cf86063Sdanielk1977     sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
3091bee3d7bSdrh   }
310cce7d176Sdrh 
311cce7d176Sdrh delete_from_cleanup:
3124adee20fSdanielk1977   sqlite3AuthContextPop(&sContext);
3134adee20fSdanielk1977   sqlite3SrcListDelete(pTabList);
3144adee20fSdanielk1977   sqlite3ExprDelete(pWhere);
315cce7d176Sdrh   return;
316cce7d176Sdrh }
3179cfcf5d4Sdrh 
3189cfcf5d4Sdrh /*
3199cfcf5d4Sdrh ** This routine generates VDBE code that causes a single row of a
3209cfcf5d4Sdrh ** single table to be deleted.
3219cfcf5d4Sdrh **
3229cfcf5d4Sdrh ** The VDBE must be in a particular state when this routine is called.
3239cfcf5d4Sdrh ** These are the requirements:
3249cfcf5d4Sdrh **
3259cfcf5d4Sdrh **   1.  A read/write cursor pointing to pTab, the table containing the row
3269cfcf5d4Sdrh **       to be deleted, must be opened as cursor number "base".
3279cfcf5d4Sdrh **
3289cfcf5d4Sdrh **   2.  Read/write cursors for all indices of pTab must be open as
3299cfcf5d4Sdrh **       cursor number base+i for the i-th index.
3309cfcf5d4Sdrh **
3319cfcf5d4Sdrh **   3.  The record number of the row to be deleted must be on the top
3329cfcf5d4Sdrh **       of the stack.
3339cfcf5d4Sdrh **
3349cfcf5d4Sdrh ** This routine pops the top of the stack to remove the record number
3359cfcf5d4Sdrh ** and then generates code to remove both the table record and all index
3369cfcf5d4Sdrh ** entries that point to that record.
3379cfcf5d4Sdrh */
3384adee20fSdanielk1977 void sqlite3GenerateRowDelete(
33938640e15Sdrh   sqlite *db,        /* The database containing the index */
3409cfcf5d4Sdrh   Vdbe *v,           /* Generate code into this VDBE */
3419cfcf5d4Sdrh   Table *pTab,       /* Table containing the row to be deleted */
3426a3ea0e6Sdrh   int iCur,          /* Cursor number for the table */
343c8d30ac1Sdrh   int count          /* Increment the row change counter */
3449cfcf5d4Sdrh ){
34507d6e3a7Sdrh   int addr;
3464adee20fSdanielk1977   addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
3474adee20fSdanielk1977   sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
348b28af71aSdanielk1977   sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
3494adee20fSdanielk1977   sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
3500ca3e24bSdrh }
3510ca3e24bSdrh 
3520ca3e24bSdrh /*
3530ca3e24bSdrh ** This routine generates VDBE code that causes the deletion of all
3540ca3e24bSdrh ** index entries associated with a single row of a single table.
3550ca3e24bSdrh **
3560ca3e24bSdrh ** The VDBE must be in a particular state when this routine is called.
3570ca3e24bSdrh ** These are the requirements:
3580ca3e24bSdrh **
3590ca3e24bSdrh **   1.  A read/write cursor pointing to pTab, the table containing the row
3606a3ea0e6Sdrh **       to be deleted, must be opened as cursor number "iCur".
3610ca3e24bSdrh **
3620ca3e24bSdrh **   2.  Read/write cursors for all indices of pTab must be open as
3636a3ea0e6Sdrh **       cursor number iCur+i for the i-th index.
3640ca3e24bSdrh **
3656a3ea0e6Sdrh **   3.  The "iCur" cursor must be pointing to the row that is to be
3660ca3e24bSdrh **       deleted.
3670ca3e24bSdrh */
3684adee20fSdanielk1977 void sqlite3GenerateRowIndexDelete(
36938640e15Sdrh   sqlite *db,        /* The database containing the index */
3700ca3e24bSdrh   Vdbe *v,           /* Generate code into this VDBE */
3710ca3e24bSdrh   Table *pTab,       /* Table containing the row to be deleted */
3726a3ea0e6Sdrh   int iCur,          /* Cursor number for the table */
3730ca3e24bSdrh   char *aIdxUsed     /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
3740ca3e24bSdrh ){
3759cfcf5d4Sdrh   int i;
3769cfcf5d4Sdrh   Index *pIdx;
3779cfcf5d4Sdrh 
3789cfcf5d4Sdrh   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
3790ca3e24bSdrh     if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
38051846b56Sdrh     sqlite3GenerateIndexKey(v, pIdx, iCur);
38151846b56Sdrh     sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
38251846b56Sdrh   }
38351846b56Sdrh }
38451846b56Sdrh 
38551846b56Sdrh /*
38651846b56Sdrh ** Generate code that will assemble an index key and put it on the top
38751846b56Sdrh ** of the tack.  The key with be for index pIdx which is an index on pTab.
38851846b56Sdrh ** iCur is the index of a cursor open on the pTab table and pointing to
38951846b56Sdrh ** the entry that needs indexing.
39051846b56Sdrh */
39151846b56Sdrh void sqlite3GenerateIndexKey(
39251846b56Sdrh   Vdbe *v,           /* Generate code into this VDBE */
39351846b56Sdrh   Index *pIdx,       /* The index for which to generate a key */
39451846b56Sdrh   int iCur           /* Cursor number for the pIdx->pTable table */
39551846b56Sdrh ){
39651846b56Sdrh   int j;
39751846b56Sdrh   Table *pTab = pIdx->pTable;
39851846b56Sdrh 
3994adee20fSdanielk1977   sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
4009cfcf5d4Sdrh   for(j=0; j<pIdx->nColumn; j++){
4019cfcf5d4Sdrh     int idx = pIdx->aiColumn[j];
4029cfcf5d4Sdrh     if( idx==pTab->iPKey ){
4034adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Dup, j, 0);
4049cfcf5d4Sdrh     }else{
4054adee20fSdanielk1977       sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
4069cfcf5d4Sdrh     }
4079cfcf5d4Sdrh   }
408ededfd5eSdanielk1977   sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
409a37cdde0Sdanielk1977   sqlite3IndexAffinityStr(v, pIdx);
4109cfcf5d4Sdrh }
411