Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 82295d52ae9608958b6efdaca0a2b455b84b3366 [file] [log] [blame]
drhfcfd7562018-04-12 21:42:511/*
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*/
drh2549e4c2020-12-08 14:29:0321static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
22 do{
23 Upsert *pNext = p->pNextUpsert;
drhfcfd7562018-04-12 21:42:5124 sqlite3ExprListDelete(db, p->pUpsertTarget);
drhe9c2e772018-04-13 13:06:4525 sqlite3ExprDelete(db, p->pUpsertTargetWhere);
drhfcfd7562018-04-12 21:42:5126 sqlite3ExprListDelete(db, p->pUpsertSet);
27 sqlite3ExprDelete(db, p->pUpsertWhere);
drhdaf27612020-12-10 20:31:2528 sqlite3DbFree(db, p->pToFree);
drhfcfd7562018-04-12 21:42:5129 sqlite3DbFree(db, p);
drh2549e4c2020-12-08 14:29:0330 p = pNext;
31 }while( p );
drhfcfd7562018-04-12 21:42:5132}
drh2549e4c2020-12-08 14:29:0333void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
34 if( p ) upsertDelete(db, p);
35}
36
drhfcfd7562018-04-12 21:42:5137
38/*
39** Duplicate an Upsert object.
40*/
41Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
42 if( p==0 ) return 0;
43 return sqlite3UpsertNew(db,
drhfcfd7562018-04-12 21:42:5144 sqlite3ExprListDup(db, p->pUpsertTarget, 0),
drhe9c2e772018-04-13 13:06:4545 sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
drhfcfd7562018-04-12 21:42:5146 sqlite3ExprListDup(db, p->pUpsertSet, 0),
drh2549e4c2020-12-08 14:29:0347 sqlite3ExprDup(db, p->pUpsertWhere, 0),
48 sqlite3UpsertDup(db, p->pNextUpsert)
drhfcfd7562018-04-12 21:42:5149 );
50}
51
52/*
53** Create a new Upsert object.
54*/
55Upsert *sqlite3UpsertNew(
56 sqlite3 *db, /* Determines which memory allocator to use */
drhfcfd7562018-04-12 21:42:5157 ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
drhe9c2e772018-04-13 13:06:4558 Expr *pTargetWhere, /* Optional WHERE clause on the target */
drhfcfd7562018-04-12 21:42:5159 ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
drh2549e4c2020-12-08 14:29:0360 Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */
61 Upsert *pNext /* Next ON CONFLICT clause in the list */
drhfcfd7562018-04-12 21:42:5162){
63 Upsert *pNew;
drhe84ad922020-12-09 20:30:4764 pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
drhfcfd7562018-04-12 21:42:5165 if( pNew==0 ){
drhfcfd7562018-04-12 21:42:5166 sqlite3ExprListDelete(db, pTarget);
drhe9c2e772018-04-13 13:06:4567 sqlite3ExprDelete(db, pTargetWhere);
drhfcfd7562018-04-12 21:42:5168 sqlite3ExprListDelete(db, pSet);
69 sqlite3ExprDelete(db, pWhere);
drh2549e4c2020-12-08 14:29:0370 sqlite3UpsertDelete(db, pNext);
drhfcfd7562018-04-12 21:42:5171 return 0;
72 }else{
73 pNew->pUpsertTarget = pTarget;
drhe9c2e772018-04-13 13:06:4574 pNew->pUpsertTargetWhere = pTargetWhere;
drhfcfd7562018-04-12 21:42:5175 pNew->pUpsertSet = pSet;
drhfcfd7562018-04-12 21:42:5176 pNew->pUpsertWhere = pWhere;
drh255c1c12020-12-12 00:28:1577 pNew->isDoUpdate = pSet!=0;
drh2549e4c2020-12-08 14:29:0378 pNew->pNextUpsert = pNext;
drhfcfd7562018-04-12 21:42:5179 }
80 return pNew;
81}
82
drh788d55a2018-04-13 01:15:0983/*
drhe9c2e772018-04-13 13:06:4584** Analyze the ON CONFLICT clause described by pUpsert. Resolve all
85** symbols in the conflict-target.
drh788d55a2018-04-13 01:15:0986**
drhe9c2e772018-04-13 13:06:4587** Return SQLITE_OK if everything works, or an error code is something
88** is wrong.
drh788d55a2018-04-13 01:15:0989*/
drhe9c2e772018-04-13 13:06:4590int sqlite3UpsertAnalyzeTarget(
drh788d55a2018-04-13 01:15:0991 Parse *pParse, /* The parsing context */
92 SrcList *pTabList, /* Table into which we are inserting */
drh926fb602024-03-08 14:01:4893 Upsert *pUpsert, /* The ON CONFLICT clauses */
94 Upsert *pAll /* Complete list of all ON CONFLICT clauses */
drh788d55a2018-04-13 01:15:0995){
drhd5af5422018-04-13 14:27:0196 Table *pTab; /* That table into which we are inserting */
97 int rc; /* Result code */
98 int iCursor; /* Cursor used by pTab */
99 Index *pIdx; /* One of the indexes of pTab */
100 ExprList *pTarget; /* The conflict-target clause */
101 Expr *pTerm; /* One term of the conflict-target clause */
102 NameContext sNC; /* Context for resolving symbolic names */
103 Expr sCol[2]; /* Index column converted into an Expr */
drh2549e4c2020-12-08 14:29:03104 int nClause = 0; /* Counter of ON CONFLICT clauses */
drh788d55a2018-04-13 01:15:09105
106 assert( pTabList->nSrc==1 );
drhb204b6a2024-08-17 23:23:23107 assert( pTabList->a[0].pSTab!=0 );
drhe9c2e772018-04-13 13:06:45108 assert( pUpsert!=0 );
109 assert( pUpsert->pUpsertTarget!=0 );
110
111 /* Resolve all symbolic names in the conflict-target clause, which
112 ** includes both the list of columns and the optional partial-index
113 ** WHERE clause.
114 */
drh788d55a2018-04-13 01:15:09115 memset(&sNC, 0, sizeof(sNC));
116 sNC.pParse = pParse;
117 sNC.pSrcList = pTabList;
drh2549e4c2020-12-08 14:29:03118 for(; pUpsert && pUpsert->pUpsertTarget;
119 pUpsert=pUpsert->pNextUpsert, nClause++){
120 rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
121 if( rc ) return rc;
122 rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
123 if( rc ) return rc;
124
125 /* Check to see if the conflict target matches the rowid. */
drhb204b6a2024-08-17 23:23:23126 pTab = pTabList->a[0].pSTab;
drh2549e4c2020-12-08 14:29:03127 pTarget = pUpsert->pUpsertTarget;
128 iCursor = pTabList->a[0].iCursor;
129 if( HasRowid(pTab)
130 && pTarget->nExpr==1
131 && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
132 && pTerm->iColumn==XN_ROWID
133 ){
134 /* The conflict-target is the rowid of the primary table */
135 assert( pUpsert->pUpsertIdx==0 );
drh3b45d8b2018-04-13 13:44:48136 continue;
137 }
drh2549e4c2020-12-08 14:29:03138
139 /* Initialize sCol[0..1] to be an expression parse tree for a
140 ** single column of an index. The sCol[0] node will be the TK_COLLATE
141 ** operator and sCol[1] will be the TK_COLUMN operator. Code below
142 ** will populate the specific collation and column number values
143 ** prior to comparing against the conflict-target expression.
144 */
145 memset(sCol, 0, sizeof(sCol));
146 sCol[0].op = TK_COLLATE;
147 sCol[0].pLeft = &sCol[1];
148 sCol[1].op = TK_COLUMN;
149 sCol[1].iTable = pTabList->a[0].iCursor;
150
151 /* Check for matches against other indexes */
152 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
153 int ii, jj, nn;
154 if( !IsUniqueIndex(pIdx) ) continue;
155 if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
156 if( pIdx->pPartIdxWhere ){
157 if( pUpsert->pUpsertTargetWhere==0 ) continue;
158 if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
159 pIdx->pPartIdxWhere, iCursor)!=0 ){
160 continue;
161 }
162 }
163 nn = pIdx->nKeyCol;
164 for(ii=0; ii<nn; ii++){
165 Expr *pExpr;
166 sCol[0].u.zToken = (char*)pIdx->azColl[ii];
167 if( pIdx->aiColumn[ii]==XN_EXPR ){
168 assert( pIdx->aColExpr!=0 );
169 assert( pIdx->aColExpr->nExpr>ii );
drh4bc1cc12022-10-13 21:08:34170 assert( pIdx->bHasExpr );
drh2549e4c2020-12-08 14:29:03171 pExpr = pIdx->aColExpr->a[ii].pExpr;
172 if( pExpr->op!=TK_COLLATE ){
173 sCol[0].pLeft = pExpr;
174 pExpr = &sCol[0];
175 }
176 }else{
177 sCol[0].pLeft = &sCol[1];
178 sCol[1].iColumn = pIdx->aiColumn[ii];
179 pExpr = &sCol[0];
180 }
181 for(jj=0; jj<nn; jj++){
drh2e0ce582023-08-17 17:48:20182 if( sqlite3ExprCompare(0,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
drh2549e4c2020-12-08 14:29:03183 break; /* Column ii of the index matches column jj of target */
184 }
185 }
186 if( jj>=nn ){
187 /* The target contains no match for column jj of the index */
188 break;
189 }
190 }
191 if( ii<nn ){
192 /* Column ii of the index did not match any term of the conflict target.
193 ** Continue the search with the next index. */
194 continue;
195 }
196 pUpsert->pUpsertIdx = pIdx;
drh926fb602024-03-08 14:01:48197 if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
198 /* Really this should be an error. The isDup ON CONFLICT clause will
199 ** never fire. But this problem was not discovered until three years
200 ** after multi-CONFLICT upsert was added, and so we silently ignore
201 ** the problem to prevent breaking applications that might actually
202 ** have redundant ON CONFLICT clauses. */
203 pUpsert->isDup = 1;
204 }
drh2549e4c2020-12-08 14:29:03205 break;
206 }
207 if( pUpsert->pUpsertIdx==0 ){
208 char zWhich[16];
209 if( nClause==0 && pUpsert->pNextUpsert==0 ){
210 zWhich[0] = 0;
211 }else{
212 sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
213 }
214 sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
215 "PRIMARY KEY or UNIQUE constraint", zWhich);
216 return SQLITE_ERROR;
217 }
drh788d55a2018-04-13 01:15:09218 }
drh2549e4c2020-12-08 14:29:03219 return SQLITE_OK;
drh788d55a2018-04-13 01:15:09220}
221
drh9eddaca2018-04-13 18:59:17222/*
drh61e280a2020-12-11 01:17:06223** Return true if pUpsert is the last ON CONFLICT clause with a
224** conflict target, or if pUpsert is followed by another ON CONFLICT
225** clause that targets the INTEGER PRIMARY KEY.
226*/
227int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
228 Upsert *pNext;
drh1c198482020-12-14 13:52:03229 if( NEVER(pUpsert==0) ) return 0;
drh61e280a2020-12-11 01:17:06230 pNext = pUpsert->pNextUpsert;
drh926fb602024-03-08 14:01:48231 while( 1 /*exit-by-return*/ ){
232 if( pNext==0 ) return 1;
233 if( pNext->pUpsertTarget==0 ) return 1;
234 if( pNext->pUpsertIdx==0 ) return 1;
235 if( !pNext->isDup ) return 0;
236 pNext = pNext->pNextUpsert;
237 }
drh61e280a2020-12-11 01:17:06238 return 0;
239}
240
241/*
242** Given the list of ON CONFLICT clauses described by pUpsert, and
243** a particular index pIdx, return a pointer to the particular ON CONFLICT
244** clause that applies to the index. Or, if the index is not subject to
245** any ON CONFLICT clause, return NULL.
246*/
247Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
248 while(
249 pUpsert
250 && pUpsert->pUpsertTarget!=0
251 && pUpsert->pUpsertIdx!=pIdx
252 ){
253 pUpsert = pUpsert->pNextUpsert;
254 }
255 return pUpsert;
256}
257
258/*
drh9eddaca2018-04-13 18:59:17259** Generate bytecode that does an UPDATE as part of an upsert.
dan2cc00422018-04-17 18:16:10260**
261** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
262** In this case parameter iCur is a cursor open on the table b-tree that
263** currently points to the conflicting table row. Otherwise, if pIdx
264** is not NULL, then pIdx is the constraint that failed and iCur is a
265** cursor points to the conflicting row.
drh9eddaca2018-04-13 18:59:17266*/
267void sqlite3UpsertDoUpdate(
268 Parse *pParse, /* The parsing and code-generating context */
269 Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */
270 Table *pTab, /* The table being updated */
271 Index *pIdx, /* The UNIQUE constraint that failed */
dan2cc00422018-04-17 18:16:10272 int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */
drh9eddaca2018-04-13 18:59:17273){
274 Vdbe *v = pParse->pVdbe;
drh0b30a112018-04-13 21:55:22275 sqlite3 *db = pParse->db;
drh0b30a112018-04-13 21:55:22276 SrcList *pSrc; /* FROM clause for the UPDATE */
drhc4ceea72018-08-21 12:16:33277 int iDataCur;
drha7ce1672019-08-30 23:15:00278 int i;
drh91f27172020-12-10 12:49:26279 Upsert *pTop = pUpsert;
drh0b30a112018-04-13 21:55:22280
drh9eddaca2018-04-13 18:59:17281 assert( v!=0 );
drhc4ceea72018-08-21 12:16:33282 assert( pUpsert!=0 );
drhc4ceea72018-08-21 12:16:33283 iDataCur = pUpsert->iDataCur;
drh61e280a2020-12-11 01:17:06284 pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
drh91f27172020-12-10 12:49:26285 VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
drhfb2213e2018-04-20 15:56:24286 if( pIdx && iCur!=iDataCur ){
287 if( HasRowid(pTab) ){
288 int regRowid = sqlite3GetTempReg(pParse);
289 sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
290 sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
291 VdbeCoverage(v);
292 sqlite3ReleaseTempReg(pParse, regRowid);
drh0b30a112018-04-13 21:55:22293 }else{
drhfb2213e2018-04-20 15:56:24294 Index *pPk = sqlite3PrimaryKeyIndex(pTab);
295 int nPk = pPk->nKeyCol;
296 int iPk = pParse->nMem+1;
drhfb2213e2018-04-20 15:56:24297 pParse->nMem += nPk;
298 for(i=0; i<nPk; i++){
299 int k;
300 assert( pPk->aiColumn[i]>=0 );
drhb9bcf7c2019-10-19 13:29:10301 k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
drhfb2213e2018-04-20 15:56:24302 sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
drh9cadb232018-04-20 18:01:31303 VdbeComment((v, "%s.%s", pIdx->zName,
drhcf9d36d2021-08-02 18:03:43304 pTab->aCol[pPk->aiColumn[i]].zCnName));
drhe966a362018-04-14 22:35:34305 }
drh4031baf2018-05-28 17:31:20306 sqlite3VdbeVerifyAbortable(v, OE_Abort);
drhfb2213e2018-04-20 15:56:24307 i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
308 VdbeCoverage(v);
drh9cadb232018-04-20 18:01:31309 sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
310 "corrupt database", P4_STATIC);
drhfe2a3f12019-12-26 23:40:33311 sqlite3MayAbort(pParse);
drhfb2213e2018-04-20 15:56:24312 sqlite3VdbeJumpHere(v, i);
drhe966a362018-04-14 22:35:34313 }
drh0b30a112018-04-13 21:55:22314 }
drh91f27172020-12-10 12:49:26315 /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
316 ** So we have to make a copy before passing it down into sqlite3Update() */
317 pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
drha7ce1672019-08-30 23:15:00318 /* excluded.* columns of type REAL need to be converted to a hard real */
319 for(i=0; i<pTab->nCol; i++){
320 if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
drh91f27172020-12-10 12:49:26321 sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
drha7ce1672019-08-30 23:15:00322 }
323 }
drh255c1c12020-12-12 00:28:15324 sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
325 sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
drh9eddaca2018-04-13 18:59:17326 VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
327}
328
drhfcfd7562018-04-12 21:42:51329#endif /* SQLITE_OMIT_UPSERT */