ds@1952: /* ds@1952: ** 2001 September 15 ds@1952: ** ds@1952: ** The author disclaims copyright to this source code. In place of ds@1952: ** a legal notice, here is a blessing: ds@1952: ** ds@1952: ** May you do good and not evil. ds@1952: ** May you find forgiveness for yourself and forgive others. ds@1952: ** May you share freely, never taking more than you give. ds@1952: ** ds@1952: ************************************************************************* ds@1952: ** This file contains C code routines that are called by the parser ds@1952: ** in order to generate code for DELETE FROM statements. ds@1952: ** ds@1952: ** $Id$ ds@1952: */ ds@1952: #include "sqliteInt.h" ds@1952: ds@1952: /* ds@1952: ** Look up every table that is named in pSrc. If any table is not found, ds@1952: ** add an error message to pParse->zErrMsg and return NULL. If all tables ds@1952: ** are found, return a pointer to the last table. ds@1952: */ ds@1952: Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ ds@1952: Table *pTab = 0; ds@1952: int i; ds@1952: struct SrcList_item *pItem; ds@1952: for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ ds@1952: pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); ds@1952: sqlite3DeleteTable(pItem->pTab); ds@1952: pItem->pTab = pTab; ds@1952: if( pTab ){ ds@1952: pTab->nRef++; ds@1952: } ds@1952: } ds@1952: return pTab; ds@1952: } ds@1952: ds@1952: /* ds@1952: ** Check to make sure the given table is writable. If it is not ds@1952: ** writable, generate an error message and return 1. If it is ds@1952: ** writable return 0; ds@1952: */ ds@1952: int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ ds@1952: if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 ds@1952: && pParse->nested==0) ds@1952: #ifndef SQLITE_OMIT_VIRTUALTABLE ds@1952: || (pTab->pMod && pTab->pMod->pModule->xUpdate==0) ds@1952: #endif ds@1952: ){ ds@1952: sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); ds@1952: return 1; ds@1952: } ds@1952: #ifndef SQLITE_OMIT_VIEW ds@1952: if( !viewOk && pTab->pSelect ){ ds@1952: sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); ds@1952: return 1; ds@1952: } ds@1952: #endif ds@1952: return 0; ds@1952: } ds@1952: ds@1952: /* ds@1952: ** Generate code that will open a table for reading. ds@1952: */ ds@1952: void sqlite3OpenTable( ds@1952: Parse *p, /* Generate code into this VDBE */ ds@1952: int iCur, /* The cursor number of the table */ ds@1952: int iDb, /* The database index in sqlite3.aDb[] */ ds@1952: Table *pTab, /* The table to be opened */ ds@1952: int opcode /* OP_OpenRead or OP_OpenWrite */ ds@1952: ){ ds@1952: Vdbe *v; ds@1952: if( IsVirtual(pTab) ) return; ds@1952: v = sqlite3GetVdbe(p); ds@1952: assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); ds@1952: sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); ds@1952: sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); ds@1952: VdbeComment((v, "# %s", pTab->zName)); ds@1952: sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); ds@1952: sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); ds@1952: } ds@1952: ds@1952: ds@1952: /* ds@1952: ** Generate code for a DELETE FROM statement. ds@1952: ** ds@1952: ** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL; ds@1952: ** \________/ \________________/ ds@1952: ** pTabList pWhere ds@1952: */ ds@1952: void sqlite3DeleteFrom( ds@1952: Parse *pParse, /* The parser context */ ds@1952: SrcList *pTabList, /* The table from which we should delete things */ ds@1952: Expr *pWhere /* The WHERE clause. May be null */ ds@1952: ){ ds@1952: Vdbe *v; /* The virtual database engine */ ds@1952: Table *pTab; /* The table from which records will be deleted */ ds@1952: const char *zDb; /* Name of database holding pTab */ ds@1952: int end, addr = 0; /* A couple addresses of generated code */ ds@1952: int i; /* Loop counter */ ds@1952: WhereInfo *pWInfo; /* Information about the WHERE clause */ ds@1952: Index *pIdx; /* For looping over indices of the table */ ds@1952: int iCur; /* VDBE Cursor number for pTab */ ds@1952: sqlite3 *db; /* Main database structure */ ds@1952: AuthContext sContext; /* Authorization context */ ds@1952: int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ ds@1952: NameContext sNC; /* Name context to resolve expressions in */ ds@1952: int iDb; /* Database number */ ds@1952: int memCnt = 0; /* Memory cell used for change counting */ ds@1952: ds@1952: #ifndef SQLITE_OMIT_TRIGGER ds@1952: int isView; /* True if attempting to delete from a view */ ds@1952: int triggers_exist = 0; /* True if any triggers exist */ ds@1952: #endif ds@1952: ds@1952: sContext.pParse = 0; ds@1952: db = pParse->db; ds@1952: if( pParse->nErr || db->mallocFailed ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: assert( pTabList->nSrc==1 ); ds@1952: ds@1952: /* Locate the table which we want to delete. This table has to be ds@1952: ** put in an SrcList structure because some of the subroutines we ds@1952: ** will be calling are designed to work with multiple tables and expect ds@1952: ** an SrcList* parameter instead of just a Table* parameter. ds@1952: */ ds@1952: pTab = sqlite3SrcListLookup(pParse, pTabList); ds@1952: if( pTab==0 ) goto delete_from_cleanup; ds@1952: ds@1952: /* Figure out if we have any triggers and if the table being ds@1952: ** deleted from is a view ds@1952: */ ds@1952: #ifndef SQLITE_OMIT_TRIGGER ds@1952: triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0); ds@1952: isView = pTab->pSelect!=0; ds@1952: #else ds@1952: # define triggers_exist 0 ds@1952: # define isView 0 ds@1952: #endif ds@1952: #ifdef SQLITE_OMIT_VIEW ds@1952: # undef isView ds@1952: # define isView 0 ds@1952: #endif ds@1952: ds@1952: if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: iDb = sqlite3SchemaToIndex(db, pTab->pSchema); ds@1952: assert( iDbnDb ); ds@1952: zDb = db->aDb[iDb].zName; ds@1952: if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: ds@1952: /* If pTab is really a view, make sure it has been initialized. ds@1952: */ ds@1952: if( sqlite3ViewGetColumnNames(pParse, pTab) ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: ds@1952: /* Allocate a cursor used to store the old.* data for a trigger. ds@1952: */ ds@1952: if( triggers_exist ){ ds@1952: oldIdx = pParse->nTab++; ds@1952: } ds@1952: ds@1952: /* Resolve the column names in the WHERE clause. ds@1952: */ ds@1952: assert( pTabList->nSrc==1 ); ds@1952: iCur = pTabList->a[0].iCursor = pParse->nTab++; ds@1952: memset(&sNC, 0, sizeof(sNC)); ds@1952: sNC.pParse = pParse; ds@1952: sNC.pSrcList = pTabList; ds@1952: if( sqlite3ExprResolveNames(&sNC, pWhere) ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: ds@1952: /* Start the view context ds@1952: */ ds@1952: if( isView ){ ds@1952: sqlite3AuthContextPush(pParse, &sContext, pTab->zName); ds@1952: } ds@1952: ds@1952: /* Begin generating code. ds@1952: */ ds@1952: v = sqlite3GetVdbe(pParse); ds@1952: if( v==0 ){ ds@1952: goto delete_from_cleanup; ds@1952: } ds@1952: if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); ds@1952: sqlite3BeginWriteOperation(pParse, triggers_exist, iDb); ds@1952: ds@1952: /* If we are trying to delete from a view, realize that view into ds@1952: ** a ephemeral table. ds@1952: */ ds@1952: if( isView ){ ds@1952: Select *pView = sqlite3SelectDup(db, pTab->pSelect); ds@1952: sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); ds@1952: sqlite3SelectDelete(pView); ds@1952: } ds@1952: ds@1952: /* Initialize the counter of the number of rows deleted, if ds@1952: ** we are counting rows. ds@1952: */ ds@1952: if( db->flags & SQLITE_CountRows ){ ds@1952: memCnt = pParse->nMem++; ds@1952: sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt); ds@1952: } ds@1952: ds@1952: /* Special case: A DELETE without a WHERE clause deletes everything. ds@1952: ** It is easier just to erase the whole table. Note, however, that ds@1952: ** this means that the row change count will be incorrect. ds@1952: */ ds@1952: if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ ds@1952: if( db->flags & SQLITE_CountRows ){ ds@1952: /* If counting rows deleted, just count the total number of ds@1952: ** entries in the table. */ ds@1952: int endOfLoop = sqlite3VdbeMakeLabel(v); ds@1952: int addr2; ds@1952: if( !isView ){ ds@1952: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); ds@1952: } ds@1952: sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); ds@1952: addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); ds@1952: sqlite3VdbeAddOp(v, OP_Next, iCur, addr2); ds@1952: sqlite3VdbeResolveLabel(v, endOfLoop); ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); ds@1952: } ds@1952: if( !isView ){ ds@1952: sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb); ds@1952: if( !pParse->nested ){ ds@1952: sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); ds@1952: } ds@1952: for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ ds@1952: assert( pIdx->pSchema==pTab->pSchema ); ds@1952: sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb); ds@1952: } ds@1952: } ds@1952: } ds@1952: /* The usual case: There is a WHERE clause so we have to scan through ds@1952: ** the table and pick which records to delete. ds@1952: */ ds@1952: else{ ds@1952: /* Begin the database scan ds@1952: */ ds@1952: pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); ds@1952: if( pWInfo==0 ) goto delete_from_cleanup; ds@1952: ds@1952: /* Remember the rowid of every item to be deleted. ds@1952: */ ds@1952: sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); ds@1952: sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); ds@1952: if( db->flags & SQLITE_CountRows ){ ds@1952: sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); ds@1952: } ds@1952: ds@1952: /* End the database scan loop. ds@1952: */ ds@1952: sqlite3WhereEnd(pWInfo); ds@1952: ds@1952: /* Open the pseudo-table used to store OLD if there are triggers. ds@1952: */ ds@1952: if( triggers_exist ){ ds@1952: sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); ds@1952: sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); ds@1952: } ds@1952: ds@1952: /* Delete every item whose key was written to the list during the ds@1952: ** database scan. We have to delete items after the scan is complete ds@1952: ** because deleting an item can change the scan order. ds@1952: */ ds@1952: end = sqlite3VdbeMakeLabel(v); ds@1952: ds@1952: /* This is the beginning of the delete loop when there are ds@1952: ** row triggers. ds@1952: */ ds@1952: if( triggers_exist ){ ds@1952: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); ds@1952: if( !isView ){ ds@1952: sqlite3VdbeAddOp(v, OP_Dup, 0, 0); ds@1952: sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); ds@1952: } ds@1952: sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); ds@1952: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); ds@1952: sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); ds@1952: sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0); ds@1952: if( !isView ){ ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); ds@1952: } ds@1952: ds@1952: (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab, ds@1952: -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, ds@1952: addr); ds@1952: } ds@1952: ds@1952: if( !isView ){ ds@1952: /* Open cursors for the table we are deleting from and all its ds@1952: ** indices. If there are row triggers, this happens inside the ds@1952: ** OP_FifoRead loop because the cursor have to all be closed ds@1952: ** before the trigger fires. If there are no row triggers, the ds@1952: ** cursors are opened only once on the outside the loop. ds@1952: */ ds@1952: sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); ds@1952: ds@1952: /* This is the beginning of the delete loop when there are no ds@1952: ** row triggers */ ds@1952: if( !triggers_exist ){ ds@1952: addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); ds@1952: } ds@1952: ds@1952: /* Delete the row */ ds@1952: #ifndef SQLITE_OMIT_VIRTUALTABLE ds@1952: if( IsVirtual(pTab) ){ ds@1952: pParse->pVirtualLock = pTab; ds@1952: sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB); ds@1952: }else ds@1952: #endif ds@1952: { ds@1952: sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); ds@1952: } ds@1952: } ds@1952: ds@1952: /* If there are row triggers, close all cursors then invoke ds@1952: ** the AFTER triggers ds@1952: */ ds@1952: if( triggers_exist ){ ds@1952: if( !isView ){ ds@1952: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); ds@1952: } ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); ds@1952: } ds@1952: (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, ds@1952: oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, ds@1952: addr); ds@1952: } ds@1952: ds@1952: /* End of the delete loop */ ds@1952: sqlite3VdbeAddOp(v, OP_Goto, 0, addr); ds@1952: sqlite3VdbeResolveLabel(v, end); ds@1952: ds@1952: /* Close the cursors after the loop if there are no row triggers */ ds@1952: if( !triggers_exist && !IsVirtual(pTab) ){ ds@1952: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); ds@1952: } ds@1952: sqlite3VdbeAddOp(v, OP_Close, iCur, 0); ds@1952: } ds@1952: } ds@1952: ds@1952: /* ds@1952: ** Return the number of rows that were deleted. If this routine is ds@1952: ** generating code because of a call to sqlite3NestedParse(), do not ds@1952: ** invoke the callback function. ds@1952: */ ds@1952: if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ ds@1952: sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0); ds@1952: sqlite3VdbeAddOp(v, OP_Callback, 1, 0); ds@1952: sqlite3VdbeSetNumCols(v, 1); ds@1952: sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC); ds@1952: } ds@1952: ds@1952: delete_from_cleanup: ds@1952: sqlite3AuthContextPop(&sContext); ds@1952: sqlite3SrcListDelete(pTabList); ds@1952: sqlite3ExprDelete(pWhere); ds@1952: return; ds@1952: } ds@1952: ds@1952: /* ds@1952: ** This routine generates VDBE code that causes a single row of a ds@1952: ** single table to be deleted. ds@1952: ** ds@1952: ** The VDBE must be in a particular state when this routine is called. ds@1952: ** These are the requirements: ds@1952: ** ds@1952: ** 1. A read/write cursor pointing to pTab, the table containing the row ds@1952: ** to be deleted, must be opened as cursor number "base". ds@1952: ** ds@1952: ** 2. Read/write cursors for all indices of pTab must be open as ds@1952: ** cursor number base+i for the i-th index. ds@1952: ** ds@1952: ** 3. The record number of the row to be deleted must be on the top ds@1952: ** of the stack. ds@1952: ** ds@1952: ** This routine pops the top of the stack to remove the record number ds@1952: ** and then generates code to remove both the table record and all index ds@1952: ** entries that point to that record. ds@1952: */ ds@1952: void sqlite3GenerateRowDelete( ds@1952: sqlite3 *db, /* The database containing the index */ ds@1952: Vdbe *v, /* Generate code into this VDBE */ ds@1952: Table *pTab, /* Table containing the row to be deleted */ ds@1952: int iCur, /* Cursor number for the table */ ds@1952: int count /* Increment the row change counter */ ds@1952: ){ ds@1952: int addr; ds@1952: addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); ds@1952: sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0); ds@1952: sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); ds@1952: if( count ){ ds@1952: sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); ds@1952: } ds@1952: sqlite3VdbeJumpHere(v, addr); ds@1952: } ds@1952: ds@1952: /* ds@1952: ** This routine generates VDBE code that causes the deletion of all ds@1952: ** index entries associated with a single row of a single table. ds@1952: ** ds@1952: ** The VDBE must be in a particular state when this routine is called. ds@1952: ** These are the requirements: ds@1952: ** ds@1952: ** 1. A read/write cursor pointing to pTab, the table containing the row ds@1952: ** to be deleted, must be opened as cursor number "iCur". ds@1952: ** ds@1952: ** 2. Read/write cursors for all indices of pTab must be open as ds@1952: ** cursor number iCur+i for the i-th index. ds@1952: ** ds@1952: ** 3. The "iCur" cursor must be pointing to the row that is to be ds@1952: ** deleted. ds@1952: */ ds@1952: void sqlite3GenerateRowIndexDelete( ds@1952: Vdbe *v, /* Generate code into this VDBE */ ds@1952: Table *pTab, /* Table containing the row to be deleted */ ds@1952: int iCur, /* Cursor number for the table */ ds@1952: char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ ds@1952: ){ ds@1952: int i; ds@1952: Index *pIdx; ds@1952: ds@1952: for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ ds@1952: if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; ds@1952: sqlite3GenerateIndexKey(v, pIdx, iCur); ds@1952: sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0); ds@1952: } ds@1952: } ds@1952: ds@1952: /* ds@1952: ** Generate code that will assemble an index key and put it on the top ds@1952: ** of the tack. The key with be for index pIdx which is an index on pTab. ds@1952: ** iCur is the index of a cursor open on the pTab table and pointing to ds@1952: ** the entry that needs indexing. ds@1952: */ ds@1952: void sqlite3GenerateIndexKey( ds@1952: Vdbe *v, /* Generate code into this VDBE */ ds@1952: Index *pIdx, /* The index for which to generate a key */ ds@1952: int iCur /* Cursor number for the pIdx->pTable table */ ds@1952: ){ ds@1952: int j; ds@1952: Table *pTab = pIdx->pTable; ds@1952: ds@1952: sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); ds@1952: for(j=0; jnColumn; j++){ ds@1952: int idx = pIdx->aiColumn[j]; ds@1952: if( idx==pTab->iPKey ){ ds@1952: sqlite3VdbeAddOp(v, OP_Dup, j, 0); ds@1952: }else{ ds@1952: sqlite3VdbeAddOp(v, OP_Column, iCur, idx); ds@1952: sqlite3ColumnDefault(v, pTab, idx); ds@1952: } ds@1952: } ds@1952: sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); ds@1952: sqlite3IndexAffinityStr(v, pIdx); ds@1952: }