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