xref: /sqlite-3.40.0/src/upsert.c (revision 4bc1cc18)
1fcfd756fSdrh /*
2fcfd756fSdrh ** 2018-04-12
3fcfd756fSdrh **
4fcfd756fSdrh ** The author disclaims copyright to this source code.  In place of
5fcfd756fSdrh ** a legal notice, here is a blessing:
6fcfd756fSdrh **
7fcfd756fSdrh **    May you do good and not evil.
8fcfd756fSdrh **    May you find forgiveness for yourself and forgive others.
9fcfd756fSdrh **    May you share freely, never taking more than you give.
10fcfd756fSdrh **
11fcfd756fSdrh *************************************************************************
12fcfd756fSdrh ** This file contains code to implement various aspects of UPSERT
13fcfd756fSdrh ** processing and handling of the Upsert object.
14fcfd756fSdrh */
15fcfd756fSdrh #include "sqliteInt.h"
16fcfd756fSdrh 
17fcfd756fSdrh #ifndef SQLITE_OMIT_UPSERT
18fcfd756fSdrh /*
19fcfd756fSdrh ** Free a list of Upsert objects
20fcfd756fSdrh */
upsertDelete(sqlite3 * db,Upsert * p)212549e4ccSdrh static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
222549e4ccSdrh   do{
232549e4ccSdrh     Upsert *pNext = p->pNextUpsert;
24fcfd756fSdrh     sqlite3ExprListDelete(db, p->pUpsertTarget);
25e9c2e772Sdrh     sqlite3ExprDelete(db, p->pUpsertTargetWhere);
26fcfd756fSdrh     sqlite3ExprListDelete(db, p->pUpsertSet);
27fcfd756fSdrh     sqlite3ExprDelete(db, p->pUpsertWhere);
28daf2761cSdrh     sqlite3DbFree(db, p->pToFree);
29fcfd756fSdrh     sqlite3DbFree(db, p);
302549e4ccSdrh     p = pNext;
312549e4ccSdrh   }while( p );
32fcfd756fSdrh }
sqlite3UpsertDelete(sqlite3 * db,Upsert * p)332549e4ccSdrh void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
342549e4ccSdrh   if( p ) upsertDelete(db, p);
35fcfd756fSdrh }
36fcfd756fSdrh 
372549e4ccSdrh 
38fcfd756fSdrh /*
39fcfd756fSdrh ** Duplicate an Upsert object.
40fcfd756fSdrh */
sqlite3UpsertDup(sqlite3 * db,Upsert * p)41fcfd756fSdrh Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
42fcfd756fSdrh   if( p==0 ) return 0;
43fcfd756fSdrh   return sqlite3UpsertNew(db,
44fcfd756fSdrh            sqlite3ExprListDup(db, p->pUpsertTarget, 0),
45e9c2e772Sdrh            sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
46fcfd756fSdrh            sqlite3ExprListDup(db, p->pUpsertSet, 0),
472549e4ccSdrh            sqlite3ExprDup(db, p->pUpsertWhere, 0),
482549e4ccSdrh            sqlite3UpsertDup(db, p->pNextUpsert)
49fcfd756fSdrh          );
50fcfd756fSdrh }
51fcfd756fSdrh 
52fcfd756fSdrh /*
53fcfd756fSdrh ** Create a new Upsert object.
54fcfd756fSdrh */
sqlite3UpsertNew(sqlite3 * db,ExprList * pTarget,Expr * pTargetWhere,ExprList * pSet,Expr * pWhere,Upsert * pNext)55fcfd756fSdrh Upsert *sqlite3UpsertNew(
56fcfd756fSdrh   sqlite3 *db,           /* Determines which memory allocator to use */
57fcfd756fSdrh   ExprList *pTarget,     /* Target argument to ON CONFLICT, or NULL */
58e9c2e772Sdrh   Expr *pTargetWhere,    /* Optional WHERE clause on the target */
59fcfd756fSdrh   ExprList *pSet,        /* UPDATE columns, or NULL for a DO NOTHING */
602549e4ccSdrh   Expr *pWhere,          /* WHERE clause for the ON CONFLICT UPDATE */
612549e4ccSdrh   Upsert *pNext          /* Next ON CONFLICT clause in the list */
62fcfd756fSdrh ){
63fcfd756fSdrh   Upsert *pNew;
64e84ad92fSdrh   pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
65fcfd756fSdrh   if( pNew==0 ){
66fcfd756fSdrh     sqlite3ExprListDelete(db, pTarget);
67e9c2e772Sdrh     sqlite3ExprDelete(db, pTargetWhere);
68fcfd756fSdrh     sqlite3ExprListDelete(db, pSet);
69fcfd756fSdrh     sqlite3ExprDelete(db, pWhere);
702549e4ccSdrh     sqlite3UpsertDelete(db, pNext);
71fcfd756fSdrh     return 0;
72fcfd756fSdrh   }else{
73fcfd756fSdrh     pNew->pUpsertTarget = pTarget;
74e9c2e772Sdrh     pNew->pUpsertTargetWhere = pTargetWhere;
75fcfd756fSdrh     pNew->pUpsertSet = pSet;
76fcfd756fSdrh     pNew->pUpsertWhere = pWhere;
77255c1c15Sdrh     pNew->isDoUpdate = pSet!=0;
782549e4ccSdrh     pNew->pNextUpsert = pNext;
79fcfd756fSdrh   }
80fcfd756fSdrh   return pNew;
81fcfd756fSdrh }
82fcfd756fSdrh 
83788d55aaSdrh /*
84e9c2e772Sdrh ** Analyze the ON CONFLICT clause described by pUpsert.  Resolve all
85e9c2e772Sdrh ** symbols in the conflict-target.
86788d55aaSdrh **
87e9c2e772Sdrh ** Return SQLITE_OK if everything works, or an error code is something
88e9c2e772Sdrh ** is wrong.
89788d55aaSdrh */
sqlite3UpsertAnalyzeTarget(Parse * pParse,SrcList * pTabList,Upsert * pUpsert)90e9c2e772Sdrh int sqlite3UpsertAnalyzeTarget(
91788d55aaSdrh   Parse *pParse,     /* The parsing context */
92788d55aaSdrh   SrcList *pTabList, /* Table into which we are inserting */
93e9c2e772Sdrh   Upsert *pUpsert    /* The ON CONFLICT clauses */
94788d55aaSdrh ){
95d5af5420Sdrh   Table *pTab;            /* That table into which we are inserting */
96d5af5420Sdrh   int rc;                 /* Result code */
97d5af5420Sdrh   int iCursor;            /* Cursor used by pTab */
98d5af5420Sdrh   Index *pIdx;            /* One of the indexes of pTab */
99d5af5420Sdrh   ExprList *pTarget;      /* The conflict-target clause */
100d5af5420Sdrh   Expr *pTerm;            /* One term of the conflict-target clause */
101d5af5420Sdrh   NameContext sNC;        /* Context for resolving symbolic names */
102d5af5420Sdrh   Expr sCol[2];           /* Index column converted into an Expr */
1032549e4ccSdrh   int nClause = 0;        /* Counter of ON CONFLICT clauses */
104788d55aaSdrh 
105788d55aaSdrh   assert( pTabList->nSrc==1 );
106788d55aaSdrh   assert( pTabList->a[0].pTab!=0 );
107e9c2e772Sdrh   assert( pUpsert!=0 );
108e9c2e772Sdrh   assert( pUpsert->pUpsertTarget!=0 );
109e9c2e772Sdrh 
110e9c2e772Sdrh   /* Resolve all symbolic names in the conflict-target clause, which
111e9c2e772Sdrh   ** includes both the list of columns and the optional partial-index
112e9c2e772Sdrh   ** WHERE clause.
113e9c2e772Sdrh   */
114788d55aaSdrh   memset(&sNC, 0, sizeof(sNC));
115788d55aaSdrh   sNC.pParse = pParse;
116788d55aaSdrh   sNC.pSrcList = pTabList;
1172549e4ccSdrh   for(; pUpsert && pUpsert->pUpsertTarget;
1182549e4ccSdrh         pUpsert=pUpsert->pNextUpsert, nClause++){
119e9c2e772Sdrh     rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
120e9c2e772Sdrh     if( rc ) return rc;
121e9c2e772Sdrh     rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
122e9c2e772Sdrh     if( rc ) return rc;
123e9c2e772Sdrh 
124e9c2e772Sdrh     /* Check to see if the conflict target matches the rowid. */
125788d55aaSdrh     pTab = pTabList->a[0].pTab;
126e9c2e772Sdrh     pTarget = pUpsert->pUpsertTarget;
127d5af5420Sdrh     iCursor = pTabList->a[0].iCursor;
128e9c2e772Sdrh     if( HasRowid(pTab)
129e9c2e772Sdrh      && pTarget->nExpr==1
130e9c2e772Sdrh      && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
13154514c98Sdrh      && pTerm->iColumn==XN_ROWID
132e9c2e772Sdrh     ){
133e9c2e772Sdrh       /* The conflict-target is the rowid of the primary table */
134e9c2e772Sdrh       assert( pUpsert->pUpsertIdx==0 );
1352549e4ccSdrh       continue;
136e9c2e772Sdrh     }
137e9c2e772Sdrh 
1383b45d8bfSdrh     /* Initialize sCol[0..1] to be an expression parse tree for a
1393b45d8bfSdrh     ** single column of an index.  The sCol[0] node will be the TK_COLLATE
1403b45d8bfSdrh     ** operator and sCol[1] will be the TK_COLUMN operator.  Code below
1413b45d8bfSdrh     ** will populate the specific collation and column number values
1423b45d8bfSdrh     ** prior to comparing against the conflict-target expression.
1433b45d8bfSdrh     */
1443b45d8bfSdrh     memset(sCol, 0, sizeof(sCol));
1453b45d8bfSdrh     sCol[0].op = TK_COLLATE;
1463b45d8bfSdrh     sCol[0].pLeft = &sCol[1];
1473b45d8bfSdrh     sCol[1].op = TK_COLUMN;
1483b45d8bfSdrh     sCol[1].iTable = pTabList->a[0].iCursor;
1493b45d8bfSdrh 
150e9c2e772Sdrh     /* Check for matches against other indexes */
151788d55aaSdrh     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
152e9c2e772Sdrh       int ii, jj, nn;
153e9c2e772Sdrh       if( !IsUniqueIndex(pIdx) ) continue;
154e9c2e772Sdrh       if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
155e9c2e772Sdrh       if( pIdx->pPartIdxWhere ){
156e9c2e772Sdrh         if( pUpsert->pUpsertTargetWhere==0 ) continue;
157e9c2e772Sdrh         if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
158d5af5420Sdrh                                pIdx->pPartIdxWhere, iCursor)!=0 ){
159788d55aaSdrh           continue;
160788d55aaSdrh         }
161788d55aaSdrh       }
162e9c2e772Sdrh       nn = pIdx->nKeyCol;
163e9c2e772Sdrh       for(ii=0; ii<nn; ii++){
164e9c2e772Sdrh         Expr *pExpr;
165277434e9Sdrh         sCol[0].u.zToken = (char*)pIdx->azColl[ii];
1663b45d8bfSdrh         if( pIdx->aiColumn[ii]==XN_EXPR ){
167e9c2e772Sdrh           assert( pIdx->aColExpr!=0 );
168e9c2e772Sdrh           assert( pIdx->aColExpr->nExpr>ii );
169*4bc1cc18Sdrh           assert( pIdx->bHasExpr );
170e9c2e772Sdrh           pExpr = pIdx->aColExpr->a[ii].pExpr;
171277434e9Sdrh           if( pExpr->op!=TK_COLLATE ){
172277434e9Sdrh             sCol[0].pLeft = pExpr;
173277434e9Sdrh             pExpr = &sCol[0];
174277434e9Sdrh           }
1753b45d8bfSdrh         }else{
176277434e9Sdrh           sCol[0].pLeft = &sCol[1];
1773b45d8bfSdrh           sCol[1].iColumn = pIdx->aiColumn[ii];
1783b45d8bfSdrh           pExpr = &sCol[0];
1793b45d8bfSdrh         }
180e9c2e772Sdrh         for(jj=0; jj<nn; jj++){
181d5af5420Sdrh           if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
1823b45d8bfSdrh             break;  /* Column ii of the index matches column jj of target */
1833b45d8bfSdrh           }
1843b45d8bfSdrh         }
1853b45d8bfSdrh         if( jj>=nn ){
1863b45d8bfSdrh           /* The target contains no match for column jj of the index */
187e9c2e772Sdrh           break;
188e9c2e772Sdrh         }
189e9c2e772Sdrh       }
1903b45d8bfSdrh       if( ii<nn ){
1913b45d8bfSdrh         /* Column ii of the index did not match any term of the conflict target.
1923b45d8bfSdrh         ** Continue the search with the next index. */
1933b45d8bfSdrh         continue;
194e9c2e772Sdrh       }
195e9c2e772Sdrh       pUpsert->pUpsertIdx = pIdx;
1962549e4ccSdrh       break;
197e9c2e772Sdrh     }
1982549e4ccSdrh     if( pUpsert->pUpsertIdx==0 ){
1992549e4ccSdrh       char zWhich[16];
2002549e4ccSdrh       if( nClause==0 && pUpsert->pNextUpsert==0 ){
2012549e4ccSdrh         zWhich[0] = 0;
2022549e4ccSdrh       }else{
2032549e4ccSdrh         sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
2042549e4ccSdrh       }
2052549e4ccSdrh       sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
2062549e4ccSdrh                               "PRIMARY KEY or UNIQUE constraint", zWhich);
207e9c2e772Sdrh       return SQLITE_ERROR;
208788d55aaSdrh     }
2092549e4ccSdrh   }
2102549e4ccSdrh   return SQLITE_OK;
2112549e4ccSdrh }
212788d55aaSdrh 
2139eddacadSdrh /*
21461e280adSdrh ** Return true if pUpsert is the last ON CONFLICT clause with a
21561e280adSdrh ** conflict target, or if pUpsert is followed by another ON CONFLICT
21661e280adSdrh ** clause that targets the INTEGER PRIMARY KEY.
21761e280adSdrh */
sqlite3UpsertNextIsIPK(Upsert * pUpsert)21861e280adSdrh int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
21961e280adSdrh   Upsert *pNext;
2201c198483Sdrh   if( NEVER(pUpsert==0) ) return 0;
22161e280adSdrh   pNext = pUpsert->pNextUpsert;
22261e280adSdrh   if( pNext==0 ) return 1;
22361e280adSdrh   if( pNext->pUpsertTarget==0 ) return 1;
22461e280adSdrh   if( pNext->pUpsertIdx==0 ) return 1;
22561e280adSdrh   return 0;
22661e280adSdrh }
22761e280adSdrh 
22861e280adSdrh /*
22961e280adSdrh ** Given the list of ON CONFLICT clauses described by pUpsert, and
23061e280adSdrh ** a particular index pIdx, return a pointer to the particular ON CONFLICT
23161e280adSdrh ** clause that applies to the index.  Or, if the index is not subject to
23261e280adSdrh ** any ON CONFLICT clause, return NULL.
23361e280adSdrh */
sqlite3UpsertOfIndex(Upsert * pUpsert,Index * pIdx)23461e280adSdrh Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
23561e280adSdrh   while(
23661e280adSdrh       pUpsert
23761e280adSdrh    && pUpsert->pUpsertTarget!=0
23861e280adSdrh    && pUpsert->pUpsertIdx!=pIdx
23961e280adSdrh   ){
24061e280adSdrh      pUpsert = pUpsert->pNextUpsert;
24161e280adSdrh   }
24261e280adSdrh   return pUpsert;
24361e280adSdrh }
24461e280adSdrh 
24561e280adSdrh /*
2469eddacadSdrh ** Generate bytecode that does an UPDATE as part of an upsert.
2472cc00423Sdan **
2482cc00423Sdan ** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
2492cc00423Sdan ** In this case parameter iCur is a cursor open on the table b-tree that
2502cc00423Sdan ** currently points to the conflicting table row. Otherwise, if pIdx
2512cc00423Sdan ** is not NULL, then pIdx is the constraint that failed and iCur is a
2522cc00423Sdan ** cursor points to the conflicting row.
2539eddacadSdrh */
sqlite3UpsertDoUpdate(Parse * pParse,Upsert * pUpsert,Table * pTab,Index * pIdx,int iCur)2549eddacadSdrh void sqlite3UpsertDoUpdate(
2559eddacadSdrh   Parse *pParse,        /* The parsing and code-generating context */
2569eddacadSdrh   Upsert *pUpsert,      /* The ON CONFLICT clause for the upsert */
2579eddacadSdrh   Table *pTab,          /* The table being updated */
2589eddacadSdrh   Index *pIdx,          /* The UNIQUE constraint that failed */
2592cc00423Sdan   int iCur              /* Cursor for pIdx (or pTab if pIdx==NULL) */
2609eddacadSdrh ){
2619eddacadSdrh   Vdbe *v = pParse->pVdbe;
2620b30a116Sdrh   sqlite3 *db = pParse->db;
2630b30a116Sdrh   SrcList *pSrc;            /* FROM clause for the UPDATE */
264c4ceea72Sdrh   int iDataCur;
265a7ce167eSdrh   int i;
26691f2717fSdrh   Upsert *pTop = pUpsert;
2670b30a116Sdrh 
2689eddacadSdrh   assert( v!=0 );
269c4ceea72Sdrh   assert( pUpsert!=0 );
270c4ceea72Sdrh   iDataCur = pUpsert->iDataCur;
27161e280adSdrh   pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
27291f2717fSdrh   VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
273fb2213e1Sdrh   if( pIdx && iCur!=iDataCur ){
274fb2213e1Sdrh     if( HasRowid(pTab) ){
275fb2213e1Sdrh       int regRowid = sqlite3GetTempReg(pParse);
276fb2213e1Sdrh       sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
277fb2213e1Sdrh       sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
278fb2213e1Sdrh       VdbeCoverage(v);
279fb2213e1Sdrh       sqlite3ReleaseTempReg(pParse, regRowid);
2800b30a116Sdrh     }else{
281fb2213e1Sdrh       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
282fb2213e1Sdrh       int nPk = pPk->nKeyCol;
283fb2213e1Sdrh       int iPk = pParse->nMem+1;
284fb2213e1Sdrh       pParse->nMem += nPk;
285fb2213e1Sdrh       for(i=0; i<nPk; i++){
286fb2213e1Sdrh         int k;
287fb2213e1Sdrh         assert( pPk->aiColumn[i]>=0 );
288b9bcf7caSdrh         k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
289fb2213e1Sdrh         sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
2909cadb230Sdrh         VdbeComment((v, "%s.%s", pIdx->zName,
291cf9d36d1Sdrh                     pTab->aCol[pPk->aiColumn[i]].zCnName));
2920b30a116Sdrh       }
2934031bafaSdrh       sqlite3VdbeVerifyAbortable(v, OE_Abort);
294fb2213e1Sdrh       i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
295fb2213e1Sdrh       VdbeCoverage(v);
2969cadb230Sdrh       sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
2979cadb230Sdrh             "corrupt database", P4_STATIC);
298fe2a3f1dSdrh       sqlite3MayAbort(pParse);
299fb2213e1Sdrh       sqlite3VdbeJumpHere(v, i);
300e966a36cSdrh     }
301e966a36cSdrh   }
30291f2717fSdrh   /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
30391f2717fSdrh   ** So we have to make a copy before passing it down into sqlite3Update() */
30491f2717fSdrh   pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
305a7ce167eSdrh   /* excluded.* columns of type REAL need to be converted to a hard real */
306a7ce167eSdrh   for(i=0; i<pTab->nCol; i++){
307a7ce167eSdrh     if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
30891f2717fSdrh       sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
309a7ce167eSdrh     }
310a7ce167eSdrh   }
311255c1c15Sdrh   sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
312255c1c15Sdrh       sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
3139eddacadSdrh   VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
3149eddacadSdrh }
3159eddacadSdrh 
316fcfd756fSdrh #endif /* SQLITE_OMIT_UPSERT */
317