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*/
21static 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}
33void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
34 if( p ) upsertDelete(db, p);
35}
36
37
38/*
39** Duplicate an Upsert object.
40*/
41Upsert *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*/
55Upsert *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*/
90int 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*/
218int 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*/
234Upsert *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*/
254void 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