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; |