| Index: third_party/sqlite/src/src/delete.c
|
| diff --git a/third_party/sqlite/src/src/delete.c b/third_party/sqlite/src/src/delete.c
|
| index ed273bde81aab798020206a4b7445ce3fbe7d1f5..0683f9b9dd36ad619aaf7f4c35b6ac6c90a1faa8 100644
|
| --- a/third_party/sqlite/src/src/delete.c
|
| +++ b/third_party/sqlite/src/src/delete.c
|
| @@ -36,7 +36,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
| sqlite3DeleteTable(pParse->db, pItem->pTab);
|
| pItem->pTab = pTab;
|
| if( pTab ){
|
| - pTab->nRef++;
|
| + pTab->nTabRef++;
|
| }
|
| if( sqlite3IndexedByLookup(pParse, pItem) ){
|
| pTab = 0;
|
| @@ -102,7 +102,7 @@ void sqlite3MaterializeView(
|
| if( pFrom ){
|
| assert( pFrom->nSrc==1 );
|
| pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
| - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
|
| + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
| assert( pFrom->a[0].pOn==0 );
|
| assert( pFrom->a[0].pUsing==0 );
|
| }
|
| @@ -143,7 +143,7 @@ Expr *sqlite3LimitWhere(
|
| */
|
| if( pOrderBy && (pLimit == 0) ) {
|
| sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
| - goto limit_where_cleanup_2;
|
| + goto limit_where_cleanup;
|
| }
|
|
|
| /* We only need to generate a select expression if there
|
| @@ -164,17 +164,17 @@ Expr *sqlite3LimitWhere(
|
| ** );
|
| */
|
|
|
| - pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
| - if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
|
| + pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
| + if( pSelectRowid == 0 ) goto limit_where_cleanup;
|
| pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
|
| - if( pEList == 0 ) goto limit_where_cleanup_2;
|
| + if( pEList == 0 ) goto limit_where_cleanup;
|
|
|
| /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
| ** and the SELECT subtree. */
|
| pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
| if( pSelectSrc == 0 ) {
|
| sqlite3ExprListDelete(pParse->db, pEList);
|
| - goto limit_where_cleanup_2;
|
| + goto limit_where_cleanup;
|
| }
|
|
|
| /* generate the SELECT expression tree. */
|
| @@ -183,22 +183,12 @@ Expr *sqlite3LimitWhere(
|
| if( pSelect == 0 ) return 0;
|
|
|
| /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
| - pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
|
| - if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
|
| - pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
|
| - if( pInClause == 0 ) goto limit_where_cleanup_1;
|
| -
|
| - pInClause->x.pSelect = pSelect;
|
| - pInClause->flags |= EP_xIsSelect;
|
| - sqlite3ExprSetHeightAndFlags(pParse, pInClause);
|
| + pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
| + pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0;
|
| + sqlite3PExprAddSelect(pParse, pInClause, pSelect);
|
| return pInClause;
|
|
|
| - /* something went wrong. clean up anything allocated. */
|
| -limit_where_cleanup_1:
|
| - sqlite3SelectDelete(pParse->db, pSelect);
|
| - return 0;
|
| -
|
| -limit_where_cleanup_2:
|
| +limit_where_cleanup:
|
| sqlite3ExprDelete(pParse->db, pWhere);
|
| sqlite3ExprListDelete(pParse->db, pOrderBy);
|
| sqlite3ExprDelete(pParse->db, pLimit);
|
| @@ -222,7 +212,6 @@ void sqlite3DeleteFrom(
|
| ){
|
| Vdbe *v; /* The virtual database engine */
|
| Table *pTab; /* The table from which records will be deleted */
|
| - const char *zDb; /* Name of database holding pTab */
|
| int i; /* Loop counter */
|
| WhereInfo *pWInfo; /* Information about the WHERE clause */
|
| Index *pIdx; /* For looping over indices of the table */
|
| @@ -249,11 +238,12 @@ void sqlite3DeleteFrom(
|
| int addrBypass = 0; /* Address of jump over the delete logic */
|
| int addrLoop = 0; /* Top of the delete loop */
|
| int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
|
| + int bComplex; /* True if there are triggers or FKs or
|
| + ** subqueries in the WHERE clause */
|
|
|
| #ifndef SQLITE_OMIT_TRIGGER
|
| int isView; /* True if attempting to delete from a view */
|
| Trigger *pTrigger; /* List of table triggers, if required */
|
| - int bComplex; /* True if there are either triggers or FKs */
|
| #endif
|
|
|
| memset(&sContext, 0, sizeof(sContext));
|
| @@ -281,7 +271,6 @@ void sqlite3DeleteFrom(
|
| #else
|
| # define pTrigger 0
|
| # define isView 0
|
| -# define bComplex 0
|
| #endif
|
| #ifdef SQLITE_OMIT_VIEW
|
| # undef isView
|
| @@ -299,8 +288,8 @@ void sqlite3DeleteFrom(
|
| }
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| assert( iDb<db->nDb );
|
| - zDb = db->aDb[iDb].zName;
|
| - rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
|
| + 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;
|
| @@ -366,6 +355,9 @@ void sqlite3DeleteFrom(
|
| && pWhere==0
|
| && !bComplex
|
| && !IsVirtual(pTab)
|
| +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
| + && db->xPreUpdateCallback==0
|
| +#endif
|
| ){
|
| assert( !isView );
|
| sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
|
| @@ -380,7 +372,8 @@ void sqlite3DeleteFrom(
|
| }else
|
| #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
|
| {
|
| - u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
|
| + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
|
| + if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
|
| wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
|
| if( HasRowid(pTab) ){
|
| /* For a rowid table, initialize the RowSet to an empty set */
|
| @@ -439,7 +432,7 @@ void sqlite3DeleteFrom(
|
| ** one, so just keep it in its register(s) and fall through to the
|
| ** delete code. */
|
| nKey = nPk; /* OP_Found will use an unpacked key */
|
| - aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
|
| + aToOpen = sqlite3DbMallocRawNN(db, nIdx+2);
|
| if( aToOpen==0 ){
|
| sqlite3WhereEnd(pWInfo);
|
| goto delete_from_cleanup;
|
| @@ -456,7 +449,7 @@ void sqlite3DeleteFrom(
|
| nKey = 0; /* Zero tells OP_Found to use a composite key */
|
| sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
| sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
|
| }else{
|
| /* Add the rowid of the row to be deleted to the RowSet */
|
| nKey = 1; /* OP_Seek always uses a single rowid */
|
| @@ -479,13 +472,12 @@ void sqlite3DeleteFrom(
|
| */
|
| if( !isView ){
|
| int iAddrOnce = 0;
|
| - u8 p5 = (eOnePass==ONEPASS_OFF ? 0 : OPFLAG_FORDELETE);
|
| if( eOnePass==ONEPASS_MULTI ){
|
| - iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
| }
|
| testcase( IsVirtual(pTab) );
|
| - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, p5, iTabCur,
|
| - aToOpen, &iDataCur, &iIdxCur);
|
| + 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 ) sqlite3VdbeJumpHere(v, iAddrOnce);
|
| @@ -503,7 +495,7 @@ void sqlite3DeleteFrom(
|
| }
|
| }else if( pPk ){
|
| addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
|
| - sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
|
| + sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
|
| assert( nKey==0 ); /* OP_Found will use a composite key */
|
| }else{
|
| addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
|
| @@ -527,12 +519,8 @@ void sqlite3DeleteFrom(
|
| #endif
|
| {
|
| int count = (pParse->nested==0); /* True to count changes */
|
| - int iIdxNoSeek = -1;
|
| - if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
|
| - iIdxNoSeek = aiCurOnePass[1];
|
| - }
|
| sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| - iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
|
| + iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
|
| }
|
|
|
| /* End of the loop over all rowids/primary-keys. */
|
| @@ -546,14 +534,6 @@ void sqlite3DeleteFrom(
|
| sqlite3VdbeGoto(v, addrLoop);
|
| sqlite3VdbeJumpHere(v, addrLoop);
|
| }
|
| -
|
| - /* Close the cursors open on the table and its indexes. */
|
| - if( !isView && !IsVirtual(pTab) ){
|
| - if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
| - for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
| - sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
|
| - }
|
| - }
|
| } /* End non-truncate path */
|
|
|
| /* Update the sqlite_sequence table by storing the content of the
|
| @@ -620,15 +600,17 @@ delete_from_cleanup:
|
| **
|
| ** If eMode is ONEPASS_MULTI, then this call is being made as part
|
| ** of a ONEPASS delete that affects multiple rows. In this case, if
|
| -** iIdxNoSeek is a valid cursor number (>=0), then its position should
|
| -** be preserved following the delete operation. Or, if iIdxNoSeek is not
|
| -** a valid cursor number, the position of iDataCur should be preserved
|
| -** instead.
|
| +** iIdxNoSeek is a valid cursor number (>=0) and is not the same as
|
| +** iDataCur, then its position should be preserved following the delete
|
| +** operation. Or, if iIdxNoSeek is not a valid cursor number, the
|
| +** position of iDataCur should be preserved instead.
|
| **
|
| ** iIdxNoSeek:
|
| -** If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
|
| -** index cursor (from within array of cursors starting at iIdxCur) that
|
| -** already points to the index entry to be deleted.
|
| +** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur,
|
| +** then it identifies an index cursor (from within array of cursors
|
| +** starting at iIdxCur) that already points to the index entry to be deleted.
|
| +** Except, this optimization is disabled if there are BEFORE triggers since
|
| +** the trigger body might have moved the cursor.
|
| */
|
| void sqlite3GenerateRowDelete(
|
| Parse *pParse, /* Parsing context */
|
| @@ -699,13 +681,18 @@ void sqlite3GenerateRowDelete(
|
|
|
| /* If any BEFORE triggers were coded, then seek the cursor to the
|
| ** row to be deleted again. It may be that the BEFORE triggers moved
|
| - ** the cursor or of already deleted the row that the cursor was
|
| + ** the cursor or already deleted the row that the cursor was
|
| ** pointing to.
|
| + **
|
| + ** Also disable the iIdxNoSeek optimization since the BEFORE trigger
|
| + ** may have moved that cursor.
|
| */
|
| 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;
|
| }
|
|
|
| /* Do FK processing. This call checks that any FK constraints that
|
| @@ -716,17 +703,29 @@ void sqlite3GenerateRowDelete(
|
|
|
| /* Delete the index and table entries. Skip this step if pTab is really
|
| ** a view (in which case the only effect of the DELETE statement is to
|
| - ** fire the INSTEAD OF triggers). */
|
| + ** fire the INSTEAD OF triggers).
|
| + **
|
| + ** If variable 'count' is non-zero, then this OP_Delete instruction should
|
| + ** invoke the update-hook. The pre-update-hook, on the other hand should
|
| + ** be invoked unless table pTab is a system table. The difference is that
|
| + ** the update-hook is not invoked for rows removed by REPLACE, but the
|
| + ** pre-update-hook is.
|
| + */
|
| if( pTab->pSelect==0 ){
|
| + u8 p5 = 0;
|
| sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
|
| sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
|
| - if( count ){
|
| - sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
| + if( pParse->nested==0 ){
|
| + sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
|
| }
|
| - if( iIdxNoSeek>=0 ){
|
| + if( eMode!=ONEPASS_OFF ){
|
| + sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
|
| + }
|
| + if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
|
| sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
|
| }
|
| - sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
|
| + if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
|
| + sqlite3VdbeChangeP5(v, p5);
|
| }
|
|
|
| /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
| @@ -876,6 +875,10 @@ int sqlite3GenerateIndexKey(
|
| }
|
| if( regOut ){
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
|
| + if( pIdx->pTable->pSelect ){
|
| + const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
|
| + sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
|
| + }
|
| }
|
| sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
| return regBase;
|
|
|