xref: /sqlite-3.40.0/src/upsert.c (revision 4bc1cc18)
1 /*
2 ** 2018-04-12
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 ** This file contains code to implement various aspects of UPSERT
13 ** processing and handling of the Upsert object.
14 */
15 #include "sqliteInt.h"
16 
17 #ifndef SQLITE_OMIT_UPSERT
18 /*
19 ** Free a list of Upsert objects
20 */
upsertDelete(sqlite3 * db,Upsert * p)21 static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
22   do{
23     Upsert *pNext = p->pNextUpsert;
24     sqlite3ExprListDelete(db, p->pUpsertTarget);
25     sqlite3ExprDelete(db, p->pUpsertTargetWhere);
26     sqlite3ExprListDelete(db, p->pUpsertSet);
27     sqlite3ExprDelete(db, p->pUpsertWhere);
28     sqlite3DbFree(db, p->pToFree);
29     sqlite3DbFree(db, p);
30     p = pNext;
31   }while( p );
32 }
sqlite3UpsertDelete(sqlite3 * db,Upsert * p)33 void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
34   if( p ) upsertDelete(db, p);
35 }
36 
37 
38 /*
39 ** Duplicate an Upsert object.
40 */
sqlite3UpsertDup(sqlite3 * db,Upsert * p)41 Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
42   if( p==0 ) return 0;
43   return sqlite3UpsertNew(db,
44            sqlite3ExprListDup(db, p->pUpsertTarget, 0),
45            sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
46            sqlite3ExprListDup(db, p->pUpsertSet, 0),
47            sqlite3ExprDup(db, p->pUpsertWhere, 0),
48            sqlite3UpsertDup(db, p->pNextUpsert)
49          );
50 }
51 
52 /*
53 ** Create a new Upsert object.
54 */
sqlite3UpsertNew(sqlite3 * db,ExprList * pTarget,Expr * pTargetWhere,ExprList * pSet,Expr * pWhere,Upsert * pNext)55 Upsert *sqlite3UpsertNew(
56   sqlite3 *db,           /* Determines which memory allocator to use */
57   ExprList *pTarget,     /* Target argument to ON CONFLICT, or NULL */
58   Expr *pTargetWhere,    /* Optional WHERE clause on the target */
59   ExprList *pSet,        /* UPDATE columns, or NULL for a DO NOTHING */
60   Expr *pWhere,          /* WHERE clause for the ON CONFLICT UPDATE */
61   Upsert *pNext          /* Next ON CONFLICT clause in the list */
62 ){
63   Upsert *pNew;
64   pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
65   if( pNew==0 ){
66     sqlite3ExprListDelete(db, pTarget);
67     sqlite3ExprDelete(db, pTargetWhere);
68     sqlite3ExprListDelete(db, pSet);
69     sqlite3ExprDelete(db, pWhere);
70     sqlite3UpsertDelete(db, pNext);
71     return 0;
72   }else{
73     pNew->pUpsertTarget = pTarget;
74     pNew->pUpsertTargetWhere = pTargetWhere;
75     pNew->pUpsertSet = pSet;
76     pNew->pUpsertWhere = pWhere;
77     pNew->isDoUpdate = pSet!=0;
78     pNew->pNextUpsert = pNext;
79   }
80   return pNew;
81 }
82 
83 /*
84 ** Analyze the ON CONFLICT clause described by pUpsert.  Resolve all
85 ** symbols in the conflict-target.
86 **
87 ** Return SQLITE_OK if everything works, or an error code is something
88 ** is wrong.
89 */
sqlite3UpsertAnalyzeTarget(Parse * pParse,SrcList * pTabList,Upsert * pUpsert)90 int sqlite3UpsertAnalyzeTarget(
91   Parse *pParse,     /* The parsing context */
92   SrcList *pTabList, /* Table into which we are inserting */
93   Upsert *pUpsert    /* The ON CONFLICT clauses */
94 ){
95   Table *pTab;            /* That table into which we are inserting */
96   int rc;                 /* Result code */
97   int iCursor;            /* Cursor used by pTab */
98   Index *pIdx;            /* One of the indexes of pTab */
99   ExprList *pTarget;      /* The conflict-target clause */
100   Expr *pTerm;            /* One term of the conflict-target clause */
101   NameContext sNC;        /* Context for resolving symbolic names */
102   Expr sCol[2];           /* Index column converted into an Expr */
103   int nClause = 0;        /* Counter of ON CONFLICT clauses */
104 
105   assert( pTabList->nSrc==1 );
106   assert( pTabList->a[0].pTab!=0 );
107   assert( pUpsert!=0 );
108   assert( pUpsert->pUpsertTarget!=0 );
109 
110   /* Resolve all symbolic names in the conflict-target clause, which
111   ** includes both the list of columns and the optional partial-index
112   ** WHERE clause.
113   */
114   memset(&sNC, 0, sizeof(sNC));
115   sNC.pParse = pParse;
116   sNC.pSrcList = pTabList;
117   for(; pUpsert && pUpsert->pUpsertTarget;
118         pUpsert=pUpsert->pNextUpsert, nClause++){
119     rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
120     if( rc ) return rc;
121     rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
122     if( rc ) return rc;
123 
124     /* Check to see if the conflict target matches the rowid. */
125     pTab = pTabList->a[0].pTab;
126     pTarget = pUpsert->pUpsertTarget;
127     iCursor = pTabList->a[0].iCursor;
128     if( HasRowid(pTab)
129      && pTarget->nExpr==1
130      && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
131      && pTerm->iColumn==XN_ROWID
132     ){
133       /* The conflict-target is the rowid of the primary table */
134       assert( pUpsert->pUpsertIdx==0 );
135       continue;
136     }
137 
138     /* Initialize sCol[0..1] to be an expression parse tree for a
139     ** single column of an index.  The sCol[0] node will be the TK_COLLATE
140     ** operator and sCol[1] will be the TK_COLUMN operator.  Code below
141     ** will populate the specific collation and column number values
142     ** prior to comparing against the conflict-target expression.
143     */
144     memset(sCol, 0, sizeof(sCol));
145     sCol[0].op = TK_COLLATE;
146     sCol[0].pLeft = &sCol[1];
147     sCol[1].op = TK_COLUMN;
148     sCol[1].iTable = pTabList->a[0].iCursor;
149 
150     /* Check for matches against other indexes */
151     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
152       int ii, jj, nn;
153       if( !IsUniqueIndex(pIdx) ) continue;
154       if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
155       if( pIdx->pPartIdxWhere ){
156         if( pUpsert->pUpsertTargetWhere==0 ) continue;
157         if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
158                                pIdx->pPartIdxWhere, iCursor)!=0 ){
159           continue;
160         }
161       }
162       nn = pIdx->nKeyCol;
163       for(ii=0; ii<nn; ii++){
164         Expr *pExpr;
165         sCol[0].u.zToken = (char*)pIdx->azColl[ii];
166         if( pIdx->aiColumn[ii]==XN_EXPR ){
167           assert( pIdx->aColExpr!=0 );
168           assert( pIdx->aColExpr->nExpr>ii );
169           assert( pIdx->bHasExpr );
170           pExpr = pIdx->aColExpr->a[ii].pExpr;
171           if( pExpr->op!=TK_COLLATE ){
172             sCol[0].pLeft = pExpr;
173             pExpr = &sCol[0];
174           }
175         }else{
176           sCol[0].pLeft = &sCol[1];
177           sCol[1].iColumn = pIdx->aiColumn[ii];
178           pExpr = &sCol[0];
179         }
180         for(jj=0; jj<nn; jj++){
181           if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
182             break;  /* Column ii of the index matches column jj of target */
183           }
184         }
185         if( jj>=nn ){
186           /* The target contains no match for column jj of the index */
187           break;
188         }
189       }
190       if( ii<nn ){
191         /* Column ii of the index did not match any term of the conflict target.
192         ** Continue the search with the next index. */
193         continue;
194       }
195       pUpsert->pUpsertIdx = pIdx;
196       break;
197     }
198     if( pUpsert->pUpsertIdx==0 ){
199       char zWhich[16];
200       if( nClause==0 && pUpsert->pNextUpsert==0 ){
201         zWhich[0] = 0;
202       }else{
203         sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
204       }
205       sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
206                               "PRIMARY KEY or UNIQUE constraint", zWhich);
207       return SQLITE_ERROR;
208     }
209   }
210   return SQLITE_OK;
211 }
212 
213 /*
214 ** Return true if pUpsert is the last ON CONFLICT clause with a
215 ** conflict target, or if pUpsert is followed by another ON CONFLICT
216 ** clause that targets the INTEGER PRIMARY KEY.
217 */
sqlite3UpsertNextIsIPK(Upsert * pUpsert)218 int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
219   Upsert *pNext;
220   if( NEVER(pUpsert==0) ) return 0;
221   pNext = pUpsert->pNextUpsert;
222   if( pNext==0 ) return 1;
223   if( pNext->pUpsertTarget==0 ) return 1;
224   if( pNext->pUpsertIdx==0 ) return 1;
225   return 0;
226 }
227 
228 /*
229 ** Given the list of ON CONFLICT clauses described by pUpsert, and
230 ** a particular index pIdx, return a pointer to the particular ON CONFLICT
231 ** clause that applies to the index.  Or, if the index is not subject to
232 ** any ON CONFLICT clause, return NULL.
233 */
sqlite3UpsertOfIndex(Upsert * pUpsert,Index * pIdx)234 Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
235   while(
236       pUpsert
237    && pUpsert->pUpsertTarget!=0
238    && pUpsert->pUpsertIdx!=pIdx
239   ){
240      pUpsert = pUpsert->pNextUpsert;
241   }
242   return pUpsert;
243 }
244 
245 /*
246 ** Generate bytecode that does an UPDATE as part of an upsert.
247 **
248 ** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
249 ** In this case parameter iCur is a cursor open on the table b-tree that
250 ** currently points to the conflicting table row. Otherwise, if pIdx
251 ** is not NULL, then pIdx is the constraint that failed and iCur is a
252 ** cursor points to the conflicting row.
253 */
sqlite3UpsertDoUpdate(Parse * pParse,Upsert * pUpsert,Table * pTab,Index * pIdx,int iCur)254 void sqlite3UpsertDoUpdate(
255   Parse *pParse,        /* The parsing and code-generating context */
256   Upsert *pUpsert,      /* The ON CONFLICT clause for the upsert */
257   Table *pTab,          /* The table being updated */
258   Index *pIdx,          /* The UNIQUE constraint that failed */
259   int iCur              /* Cursor for pIdx (or pTab if pIdx==NULL) */
260 ){
261   Vdbe *v = pParse->pVdbe;
262   sqlite3 *db = pParse->db;
263   SrcList *pSrc;            /* FROM clause for the UPDATE */
264   int iDataCur;
265   int i;
266   Upsert *pTop = pUpsert;
267 
268   assert( v!=0 );
269   assert( pUpsert!=0 );
270   iDataCur = pUpsert->iDataCur;
271   pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
272   VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
273   if( pIdx && iCur!=iDataCur ){
274     if( HasRowid(pTab) ){
275       int regRowid = sqlite3GetTempReg(pParse);
276       sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
277       sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
278       VdbeCoverage(v);
279       sqlite3ReleaseTempReg(pParse, regRowid);
280     }else{
281       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
282       int nPk = pPk->nKeyCol;
283       int iPk = pParse->nMem+1;
284       pParse->nMem += nPk;
285       for(i=0; i<nPk; i++){
286         int k;
287         assert( pPk->aiColumn[i]>=0 );
288         k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
289         sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
290         VdbeComment((v, "%s.%s", pIdx->zName,
291                     pTab->aCol[pPk->aiColumn[i]].zCnName));
292       }
293       sqlite3VdbeVerifyAbortable(v, OE_Abort);
294       i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
295       VdbeCoverage(v);
296       sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
297             "corrupt database", P4_STATIC);
298       sqlite3MayAbort(pParse);
299       sqlite3VdbeJumpHere(v, i);
300     }
301   }
302   /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
303   ** So we have to make a copy before passing it down into sqlite3Update() */
304   pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
305   /* excluded.* columns of type REAL need to be converted to a hard real */
306   for(i=0; i<pTab->nCol; i++){
307     if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
308       sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
309     }
310   }
311   sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
312       sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
313   VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
314 }
315 
316 #endif /* SQLITE_OMIT_UPSERT */
317