aboutsummaryrefslogtreecommitdiff
path: root/src/upsert.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2018-04-20 15:56:24 +0000
committerdrh <drh@noemail.net>2018-04-20 15:56:24 +0000
commitfb2213e1ff30891cc109015442f9dee2e3e2fbd5 (patch)
treea07b09e6f6ca31444ec4f83dfb1b5c153fd97579 /src/upsert.c
parenta46838cb1362893b7436ffce0e27a98899b1639f (diff)
downloadsqlite-fb2213e1ff30891cc109015442f9dee2e3e2fbd5.tar.gz
sqlite-fb2213e1ff30891cc109015442f9dee2e3e2fbd5.zip
Avoid unnecessary cursor seeks during upsert processing.
FossilOrigin-Name: 7c4b6d5475092a3e205f01a6972366e27a404568e8e7ba327f2feefac2ce2c7c
Diffstat (limited to 'src/upsert.c')
-rw-r--r--src/upsert.c69
1 files changed, 25 insertions, 44 deletions
diff --git a/src/upsert.c b/src/upsert.c
index 80c0056c0..568dffb53 100644
--- a/src/upsert.c
+++ b/src/upsert.c
@@ -203,62 +203,43 @@ void sqlite3UpsertDoUpdate(
){
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
- int regKey; /* Register(s) containing the key */
- Expr *pWhere; /* Where clause for the UPDATE */
- Expr *pE1, *pE2;
SrcList *pSrc; /* FROM clause for the UPDATE */
+ int iDataCur = pUpsert->iDataCur;
assert( v!=0 );
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
- pWhere = sqlite3ExprDup(db, pUpsert->pUpsertWhere, 0);
- if( pIdx==0 || HasRowid(pTab) ){
- /* We are dealing with an IPK */
- regKey = ++pParse->nMem;
- if( pIdx ){
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regKey);
+ if( pIdx && iCur!=iDataCur ){
+ if( HasRowid(pTab) ){
+ int regRowid = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, regRowid);
}else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regKey);
- }
- pE1 = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
- if( pE1 ){
- pE1->pTab = pTab;
- pE1->iTable = pUpsert->iDataCur;
- pE1->iColumn = -1;
- }
- pE2 = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0);
- if( pE2 ){
- pE2->iTable = regKey;
- pE2->affinity = SQLITE_AFF_INTEGER;
- }
- pWhere = sqlite3ExprAnd(db,pWhere,sqlite3PExpr(pParse, TK_EQ, pE1, pE2));
- }else{
- /* a WITHOUT ROWID table */
- int i, j;
- for(i=0; i<pIdx->nKeyCol; i++){
- regKey = ++pParse->nMem;
- sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regKey);
- j = pIdx->aiColumn[i];
- VdbeComment((v, "%s", pTab->aCol[j].zName));
- pE1 = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
- if( pE1 ){
- pE1->pTab = pTab;
- pE1->iTable = pUpsert->iDataCur;
- pE1->iColumn = j;
- }
- pE2 = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0);
- if( pE2 ){
- pE2->iTable = regKey;
- pE2->affinity = pTab->zColAff[j];
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ int nPk = pPk->nKeyCol;
+ int iPk = pParse->nMem+1;
+ int i;
+ pParse->nMem += nPk;
+ for(i=0; i<nPk; i++){
+ int k;
+ assert( pPk->aiColumn[i]>=0 );
+ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
}
- pWhere = sqlite3ExprAnd(db,pWhere,sqlite3PExpr(pParse, TK_EQ, pE1, pE2));
+ i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CORRUPT, OE_Abort);
+ sqlite3VdbeJumpHere(v, i);
}
}
/* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
** we have to make a copy before passing it down into sqlite3Update() */
pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
- pWhere, OE_Abort, 0, 0, pUpsert);
- pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
+ pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
+ pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
+ pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
}