| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #include "sqliteInt.h" |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ |
| | SrcItem *pItem = pSrc->a; |
| | Table *pTab; |
| | assert( pItem && pSrc->nSrc>=1 ); |
| | pTab = sqlite3LocateTableItem(pParse, 0, pItem); |
| | if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab); |
| | pItem->pSTab = pTab; |
| | pItem->fg.notCte = 1; |
| | if( pTab ){ |
| | pTab->nTabRef++; |
| | if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ |
| | pTab = 0; |
| | } |
| | } |
| | return pTab; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){ |
| | sqlite3VdbeAddOp0(v, OP_FkCheck); |
| | sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1); |
| | sqlite3VdbeSetNumCols(v, 1); |
| | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static int vtabIsReadOnly(Parse *pParse, Table *pTab){ |
| | assert( IsVirtual(pTab) ); |
| | if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){ |
| | return 1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if( pParse->pToplevel!=0 |
| | && pTab->u.vtab.p->eVtabRisk > |
| | ((pParse->db->flags & SQLITE_TrustedSchema)!=0) |
| | ){ |
| | sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", |
| | pTab->zName); |
| | } |
| | return 0; |
| | } |
| | static int tabIsReadOnly(Parse *pParse, Table *pTab){ |
| | sqlite3 *db; |
| | if( IsVirtual(pTab) ){ |
| | return vtabIsReadOnly(pParse, pTab); |
| | } |
| | if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; |
| | db = pParse->db; |
| | if( (pTab->tabFlags & TF_Readonly)!=0 ){ |
| | return sqlite3WritableSchema(db)==0 && pParse->nested==0; |
| | } |
| | assert( pTab->tabFlags & TF_Shadow ); |
| | return sqlite3ReadOnlyShadowTables(db); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){ |
| | if( tabIsReadOnly(pParse, pTab) ){ |
| | sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); |
| | return 1; |
| | } |
| | #ifndef SQLITE_OMIT_VIEW |
| | if( IsView(pTab) |
| | && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0)) |
| | ){ |
| | sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); |
| | return 1; |
| | } |
| | #endif |
| | return 0; |
| | } |
| |
|
| |
|
| | #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3MaterializeView( |
| | Parse *pParse, |
| | Table *pView, |
| | Expr *pWhere, |
| | ExprList *pOrderBy, |
| | Expr *pLimit, |
| | int iCur |
| | ){ |
| | SelectDest dest; |
| | Select *pSel; |
| | SrcList *pFrom; |
| | sqlite3 *db = pParse->db; |
| | int iDb = sqlite3SchemaToIndex(db, pView->pSchema); |
| | pWhere = sqlite3ExprDup(db, pWhere, 0); |
| | pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); |
| | if( pFrom ){ |
| | assert( pFrom->nSrc==1 ); |
| | pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); |
| | assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 ); |
| | pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); |
| | assert( pFrom->a[0].fg.isUsing==0 ); |
| | assert( pFrom->a[0].u3.pOn==0 ); |
| | } |
| | pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, |
| | SF_IncludeHidden, pLimit); |
| | sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); |
| | sqlite3Select(pParse, pSel, &dest); |
| | sqlite3SelectDelete(db, pSel); |
| | } |
| | #endif |
| |
|
| | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Expr *sqlite3LimitWhere( |
| | Parse *pParse, |
| | SrcList *pSrc, |
| | Expr *pWhere, |
| | ExprList *pOrderBy, |
| | Expr *pLimit, |
| | char *zStmtType |
| | ){ |
| | sqlite3 *db = pParse->db; |
| | Expr *pLhs = NULL; |
| | Expr *pInClause = NULL; |
| | ExprList *pEList = NULL; |
| | SrcList *pSelectSrc = NULL; |
| | Select *pSelect = NULL; |
| | Table *pTab; |
| |
|
| | |
| | |
| | if( pOrderBy && pLimit==0 ) { |
| | sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType); |
| | sqlite3ExprDelete(pParse->db, pWhere); |
| | sqlite3ExprListDelete(pParse->db, pOrderBy); |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | if( pLimit == 0 ) { |
| | return pWhere; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | pTab = pSrc->a[0].pSTab; |
| | if( HasRowid(pTab) ){ |
| | pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); |
| | pEList = sqlite3ExprListAppend( |
| | pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) |
| | ); |
| | }else{ |
| | Index *pPk = sqlite3PrimaryKeyIndex(pTab); |
| | assert( pPk!=0 ); |
| | assert( pPk->nKeyCol>=1 ); |
| | if( pPk->nKeyCol==1 ){ |
| | const char *zName; |
| | assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]<pTab->nCol ); |
| | zName = pTab->aCol[pPk->aiColumn[0]].zCnName; |
| | pLhs = sqlite3Expr(db, TK_ID, zName); |
| | pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); |
| | }else{ |
| | int i; |
| | for(i=0; i<pPk->nKeyCol; i++){ |
| | Expr *p; |
| | assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]<pTab->nCol ); |
| | p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); |
| | pEList = sqlite3ExprListAppend(pParse, pEList, p); |
| | } |
| | pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); |
| | if( pLhs ){ |
| | pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | pSrc->a[0].pSTab = 0; |
| | pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); |
| | pSrc->a[0].pSTab = pTab; |
| | if( pSrc->a[0].fg.isIndexedBy ){ |
| | assert( pSrc->a[0].fg.isCte==0 ); |
| | pSrc->a[0].u2.pIBIndex = 0; |
| | pSrc->a[0].fg.isIndexedBy = 0; |
| | sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); |
| | }else if( pSrc->a[0].fg.isCte ){ |
| | pSrc->a[0].u2.pCteUse->nUse++; |
| | } |
| |
|
| | |
| | pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, |
| | pOrderBy,0,pLimit |
| | ); |
| |
|
| | |
| | pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0); |
| | sqlite3PExprAddSelect(pParse, pInClause, pSelect); |
| | return pInClause; |
| | } |
| | #endif |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3DeleteFrom( |
| | Parse *pParse, |
| | SrcList *pTabList, |
| | Expr *pWhere, |
| | ExprList *pOrderBy, |
| | Expr *pLimit |
| | ){ |
| | Vdbe *v; |
| | Table *pTab; |
| | int i; |
| | WhereInfo *pWInfo; |
| | Index *pIdx; |
| | int iTabCur; |
| | int iDataCur = 0; |
| | int iIdxCur = 0; |
| | int nIdx; |
| | sqlite3 *db; |
| | AuthContext sContext; |
| | NameContext sNC; |
| | int iDb; |
| | int memCnt = 0; |
| | int rcauth; |
| | int eOnePass; |
| | int aiCurOnePass[2]; |
| | u8 *aToOpen = 0; |
| | Index *pPk; |
| | int iPk = 0; |
| | i16 nPk = 1; |
| | int iKey; |
| | i16 nKey; |
| | int iEphCur = 0; |
| | int iRowSet = 0; |
| | int addrBypass = 0; |
| | int addrLoop = 0; |
| | int addrEphOpen = 0; |
| | int bComplex; |
| | |
| |
|
| | #ifndef SQLITE_OMIT_TRIGGER |
| | int isView; |
| | Trigger *pTrigger; |
| | #endif |
| |
|
| | memset(&sContext, 0, sizeof(sContext)); |
| | db = pParse->db; |
| | assert( db->pParse==pParse ); |
| | if( pParse->nErr ){ |
| | goto delete_from_cleanup; |
| | } |
| | assert( db->mallocFailed==0 ); |
| | assert( pTabList->nSrc==1 ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | pTab = sqlite3SrcListLookup(pParse, pTabList); |
| | if( pTab==0 ) goto delete_from_cleanup; |
| |
|
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_TRIGGER |
| | pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); |
| | isView = IsView(pTab); |
| | #else |
| | # define pTrigger 0 |
| | # define isView 0 |
| | #endif |
| | bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); |
| | #ifdef SQLITE_OMIT_VIEW |
| | # undef isView |
| | # define isView 0 |
| | #endif |
| |
|
| | #if TREETRACE_ENABLED |
| | if( sqlite3TreeTrace & 0x10000 ){ |
| | sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__); |
| | sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere, |
| | pOrderBy, pLimit, pTrigger); |
| | } |
| | #endif |
| |
|
| | #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT |
| | if( !isView ){ |
| | pWhere = sqlite3LimitWhere( |
| | pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE" |
| | ); |
| | pOrderBy = 0; |
| | pLimit = 0; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | if( sqlite3ViewGetColumnNames(pParse, pTab) ){ |
| | goto delete_from_cleanup; |
| | } |
| |
|
| | if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ |
| | goto delete_from_cleanup; |
| | } |
| | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| | assert( iDb<db->nDb ); |
| | rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, |
| | db->aDb[iDb].zDbSName); |
| | assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); |
| | if( rcauth==SQLITE_DENY ){ |
| | goto delete_from_cleanup; |
| | } |
| | assert(!isView || pTrigger); |
| |
|
| | |
| | |
| | assert( pTabList->nSrc==1 ); |
| | iTabCur = pTabList->a[0].iCursor = pParse->nTab++; |
| | for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ |
| | pParse->nTab++; |
| | } |
| |
|
| | |
| | |
| | if( isView ){ |
| | sqlite3AuthContextPush(pParse, &sContext, pTab->zName); |
| | } |
| |
|
| | |
| | |
| | v = sqlite3GetVdbe(pParse); |
| | if( v==0 ){ |
| | goto delete_from_cleanup; |
| | } |
| | if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); |
| | sqlite3BeginWriteOperation(pParse, bComplex, iDb); |
| |
|
| | |
| | |
| | |
| | #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) |
| | if( isView ){ |
| | sqlite3MaterializeView(pParse, pTab, |
| | pWhere, pOrderBy, pLimit, iTabCur |
| | ); |
| | iDataCur = iIdxCur = iTabCur; |
| | pOrderBy = 0; |
| | pLimit = 0; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | memset(&sNC, 0, sizeof(sNC)); |
| | sNC.pParse = pParse; |
| | sNC.pSrcList = pTabList; |
| | if( sqlite3ResolveExprNames(&sNC, pWhere) ){ |
| | goto delete_from_cleanup; |
| | } |
| |
|
| | |
| | |
| | |
| | if( (db->flags & SQLITE_CountRows)!=0 |
| | && !pParse->nested |
| | && !pParse->pTriggerTab |
| | && !pParse->bReturning |
| | ){ |
| | memCnt = ++pParse->nMem; |
| | sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( rcauth==SQLITE_OK |
| | && pWhere==0 |
| | && !bComplex |
| | && !IsVirtual(pTab) |
| | #ifdef SQLITE_ENABLE_PREUPDATE_HOOK |
| | && db->xPreUpdateCallback==0 |
| | #endif |
| | ){ |
| | assert( !isView ); |
| | sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); |
| | if( HasRowid(pTab) ){ |
| | sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, |
| | pTab->zName, P4_STATIC); |
| | } |
| | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | assert( pIdx->pSchema==pTab->pSchema ); |
| | if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ |
| | sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1); |
| | }else{ |
| | sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); |
| | } |
| | } |
| | }else |
| | #endif |
| | { |
| | u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; |
| | if( sNC.ncFlags & NC_Subquery ) bComplex = 1; |
| | wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); |
| | if( HasRowid(pTab) ){ |
| | |
| | pPk = 0; |
| | assert( nPk==1 ); |
| | iRowSet = ++pParse->nMem; |
| | sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); |
| | }else{ |
| | |
| | |
| | pPk = sqlite3PrimaryKeyIndex(pTab); |
| | assert( pPk!=0 ); |
| | nPk = pPk->nKeyCol; |
| | iPk = pParse->nMem+1; |
| | pParse->nMem += nPk; |
| | iEphCur = pParse->nTab++; |
| | addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk); |
| | sqlite3VdbeSetP4KeyInfo(pParse, pPk); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1); |
| | if( pWInfo==0 ) goto delete_from_cleanup; |
| | eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); |
| | assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); |
| | assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF |
| | || OptimizationDisabled(db, SQLITE_OnePass) ); |
| | if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); |
| | if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ |
| | sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); |
| | } |
| | |
| | |
| | if( memCnt ){ |
| | sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); |
| | } |
| | |
| | |
| | if( pPk ){ |
| | for(i=0; i<nPk; i++){ |
| | assert( pPk->aiColumn[i]>=0 ); |
| | sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, |
| | pPk->aiColumn[i], iPk+i); |
| | } |
| | iKey = iPk; |
| | }else{ |
| | iKey = ++pParse->nMem; |
| | sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); |
| | } |
| | |
| | if( eOnePass!=ONEPASS_OFF ){ |
| | |
| | |
| | |
| | nKey = nPk; |
| | aToOpen = sqlite3DbMallocRawNN(db, nIdx+2); |
| | if( aToOpen==0 ){ |
| | sqlite3WhereEnd(pWInfo); |
| | goto delete_from_cleanup; |
| | } |
| | memset(aToOpen, 1, nIdx+1); |
| | aToOpen[nIdx+1] = 0; |
| | if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; |
| | if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; |
| | if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); |
| | addrBypass = sqlite3VdbeMakeLabel(pParse); |
| | }else{ |
| | if( pPk ){ |
| | |
| | iKey = ++pParse->nMem; |
| | nKey = 0; |
| | sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, |
| | sqlite3IndexAffinityStr(pParse->db, pPk), nPk); |
| | sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); |
| | }else{ |
| | |
| | nKey = 1; |
| | sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); |
| | } |
| | sqlite3WhereEnd(pWInfo); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !isView ){ |
| | int iAddrOnce = 0; |
| | if( eOnePass==ONEPASS_MULTI ){ |
| | iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); |
| | } |
| | testcase( IsVirtual(pTab) ); |
| | sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE, |
| | iTabCur, aToOpen, &iDataCur, &iIdxCur); |
| | assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); |
| | assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); |
| | if( eOnePass==ONEPASS_MULTI ){ |
| | sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | if( eOnePass!=ONEPASS_OFF ){ |
| | assert( nKey==nPk ); |
| | if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ |
| | assert( pPk!=0 || IsView(pTab) ); |
| | sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); |
| | VdbeCoverage(v); |
| | } |
| | }else if( pPk ){ |
| | addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); |
| | if( IsVirtual(pTab) ){ |
| | sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); |
| | }else{ |
| | sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); |
| | } |
| | assert( nKey==0 ); |
| | }else{ |
| | addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); |
| | VdbeCoverage(v); |
| | assert( nKey==1 ); |
| | } |
| | |
| | |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | if( IsVirtual(pTab) ){ |
| | const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); |
| | sqlite3VtabMakeWritable(pParse, pTab); |
| | assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); |
| | sqlite3MayAbort(pParse); |
| | if( eOnePass==ONEPASS_SINGLE ){ |
| | sqlite3VdbeAddOp1(v, OP_Close, iTabCur); |
| | if( sqlite3IsToplevel(pParse) ){ |
| | pParse->isMultiWrite = 0; |
| | } |
| | } |
| | sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); |
| | sqlite3VdbeChangeP5(v, OE_Abort); |
| | }else |
| | #endif |
| | { |
| | int count = (pParse->nested==0); |
| | sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, |
| | iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); |
| | } |
| | |
| | |
| | if( eOnePass!=ONEPASS_OFF ){ |
| | sqlite3VdbeResolveLabel(v, addrBypass); |
| | sqlite3WhereEnd(pWInfo); |
| | }else if( pPk ){ |
| | sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v); |
| | sqlite3VdbeJumpHere(v, addrLoop); |
| | }else{ |
| | sqlite3VdbeGoto(v, addrLoop); |
| | sqlite3VdbeJumpHere(v, addrLoop); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if( pParse->nested==0 && pParse->pTriggerTab==0 ){ |
| | sqlite3AutoincrementEnd(pParse); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if( memCnt ){ |
| | sqlite3CodeChangeCount(v, memCnt, "rows deleted"); |
| | } |
| |
|
| | delete_from_cleanup: |
| | sqlite3AuthContextPop(&sContext); |
| | sqlite3SrcListDelete(db, pTabList); |
| | sqlite3ExprDelete(db, pWhere); |
| | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) |
| | sqlite3ExprListDelete(db, pOrderBy); |
| | sqlite3ExprDelete(db, pLimit); |
| | #endif |
| | if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen); |
| | return; |
| | } |
| | |
| | |
| | |
| | #ifdef isView |
| | #undef isView |
| | #endif |
| | #ifdef pTrigger |
| | #undef pTrigger |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3GenerateRowDelete( |
| | Parse *pParse, |
| | Table *pTab, |
| | Trigger *pTrigger, |
| | int iDataCur, |
| | int iIdxCur, |
| | int iPk, |
| | i16 nPk, |
| | u8 count, |
| | u8 onconf, |
| | u8 eMode, |
| | int iIdxNoSeek |
| | ){ |
| | Vdbe *v = pParse->pVdbe; |
| | int iOld = 0; |
| | int iLabel; |
| | u8 opSeek; |
| |
|
| | |
| | assert( v ); |
| | VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", |
| | iDataCur, iIdxCur, iPk, (int)nPk)); |
| |
|
| | |
| | |
| | |
| | iLabel = sqlite3VdbeMakeLabel(pParse); |
| | opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; |
| | if( eMode==ONEPASS_OFF ){ |
| | sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); |
| | VdbeCoverageIf(v, opSeek==OP_NotExists); |
| | VdbeCoverageIf(v, opSeek==OP_NotFound); |
| | } |
| |
|
| | |
| | |
| | if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ |
| | u32 mask; |
| | int iCol; |
| | int addrStart; |
| |
|
| | |
| | |
| | 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); |
| |
|
| | |
| | |
| | sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); |
| | for(iCol=0; iCol<pTab->nCol; iCol++){ |
| | testcase( mask!=0xffffffff && iCol==31 ); |
| | testcase( mask!=0xffffffff && iCol==32 ); |
| | if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ |
| | int kk = sqlite3TableColumnToStorage(pTab, iCol); |
| | sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1); |
| | } |
| | } |
| |
|
| | |
| | addrStart = sqlite3VdbeCurrentAddr(v); |
| | sqlite3CodeRowTrigger(pParse, pTrigger, |
| | TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel |
| | ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( addrStart<sqlite3VdbeCurrentAddr(v) ){ |
| | sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); |
| | VdbeCoverageIf(v, opSeek==OP_NotExists); |
| | VdbeCoverageIf(v, opSeek==OP_NotFound); |
| | testcase( iIdxNoSeek>=0 ); |
| | iIdxNoSeek = -1; |
| | } |
| |
|
| | |
| | |
| | |
| | sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !IsView(pTab) ){ |
| | u8 p5 = 0; |
| | sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); |
| | sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); |
| | if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){ |
| | sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); |
| | } |
| | if( eMode!=ONEPASS_OFF ){ |
| | sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); |
| | } |
| | if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){ |
| | sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek); |
| | } |
| | if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION; |
| | sqlite3VdbeChangeP5(v, p5); |
| | } |
| |
|
| | |
| | |
| | |
| | sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0); |
| |
|
| | |
| | if( pTrigger ){ |
| | sqlite3CodeRowTrigger(pParse, pTrigger, |
| | TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | sqlite3VdbeResolveLabel(v, iLabel); |
| | VdbeModuleComment((v, "END: GenRowDel()")); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3GenerateRowIndexDelete( |
| | Parse *pParse, |
| | Table *pTab, |
| | int iDataCur, |
| | int iIdxCur, |
| | int *aRegIdx, |
| | int iIdxNoSeek |
| | ){ |
| | int i; |
| | int r1 = -1; |
| | int iPartIdxLabel; |
| | Index *pIdx; |
| | Index *pPrior = 0; |
| | Vdbe *v; |
| | Index *pPk; |
| |
|
| | v = pParse->pVdbe; |
| | pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); |
| | for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ |
| | assert( iIdxCur+i!=iDataCur || pPk==pIdx ); |
| | if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; |
| | if( pIdx==pPk ) continue; |
| | if( iIdxCur+i==iIdxNoSeek ) continue; |
| | VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); |
| | r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, |
| | &iPartIdxLabel, pPrior, r1); |
| | sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, |
| | pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); |
| | sqlite3VdbeChangeP5(v, 1); |
| | sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); |
| | pPrior = pIdx; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3GenerateIndexKey( |
| | Parse *pParse, |
| | Index *pIdx, |
| | int iDataCur, |
| | int regOut, |
| | int prefixOnly, |
| | int *piPartIdxLabel, |
| | Index *pPrior, |
| | int regPrior |
| | ){ |
| | Vdbe *v = pParse->pVdbe; |
| | int j; |
| | int regBase; |
| | int nCol; |
| |
|
| | if( piPartIdxLabel ){ |
| | if( pIdx->pPartIdxWhere ){ |
| | *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); |
| | pParse->iSelfTab = iDataCur + 1; |
| | sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, |
| | SQLITE_JUMPIFNULL); |
| | pParse->iSelfTab = 0; |
| | pPrior = 0; |
| | |
| | }else{ |
| | *piPartIdxLabel = 0; |
| | } |
| | } |
| | nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; |
| | regBase = sqlite3GetTempRange(pParse, nCol); |
| | if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; |
| | for(j=0; j<nCol; j++){ |
| | if( pPrior |
| | && pPrior->aiColumn[j]==pIdx->aiColumn[j] |
| | && pPrior->aiColumn[j]!=XN_EXPR |
| | ){ |
| | |
| | continue; |
| | } |
| | sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); |
| | if( pIdx->aiColumn[j]>=0 ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); |
| | } |
| | } |
| | if( regOut ){ |
| | sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); |
| | } |
| | sqlite3ReleaseTempRange(pParse, regBase, nCol); |
| | return regBase; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ |
| | if( iLabel ){ |
| | sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); |
| | } |
| | } |
| |
|