drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 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 | */ |
| 21 | void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 22 | if( p ){ |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 23 | sqlite3ExprListDelete(db, p->pUpsertTarget); |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 24 | sqlite3ExprDelete(db, p->pUpsertTargetWhere); |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 25 | sqlite3ExprListDelete(db, p->pUpsertSet); |
| 26 | sqlite3ExprDelete(db, p->pUpsertWhere); |
| 27 | sqlite3DbFree(db, p); |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 28 | } |
| 29 | } |
| 30 | |
| 31 | /* |
| 32 | ** Duplicate an Upsert object. |
| 33 | */ |
| 34 | Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){ |
| 35 | if( p==0 ) return 0; |
| 36 | return sqlite3UpsertNew(db, |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 37 | sqlite3ExprListDup(db, p->pUpsertTarget, 0), |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 38 | sqlite3ExprDup(db, p->pUpsertTargetWhere, 0), |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 39 | sqlite3ExprListDup(db, p->pUpsertSet, 0), |
| 40 | sqlite3ExprDup(db, p->pUpsertWhere, 0) |
| 41 | ); |
| 42 | } |
| 43 | |
| 44 | /* |
| 45 | ** Create a new Upsert object. |
| 46 | */ |
| 47 | Upsert *sqlite3UpsertNew( |
| 48 | sqlite3 *db, /* Determines which memory allocator to use */ |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 49 | ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 50 | Expr *pTargetWhere, /* Optional WHERE clause on the target */ |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 51 | ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */ |
| 52 | Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */ |
| 53 | ){ |
| 54 | Upsert *pNew; |
| 55 | pNew = sqlite3DbMallocRaw(db, sizeof(Upsert)); |
| 56 | if( pNew==0 ){ |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 57 | sqlite3ExprListDelete(db, pTarget); |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 58 | sqlite3ExprDelete(db, pTargetWhere); |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 59 | sqlite3ExprListDelete(db, pSet); |
| 60 | sqlite3ExprDelete(db, pWhere); |
| 61 | return 0; |
| 62 | }else{ |
| 63 | pNew->pUpsertTarget = pTarget; |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 64 | pNew->pUpsertTargetWhere = pTargetWhere; |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 65 | pNew->pUpsertSet = pSet; |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 66 | pNew->pUpsertWhere = pWhere; |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 67 | pNew->pUpsertIdx = 0; |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 68 | } |
| 69 | return pNew; |
| 70 | } |
| 71 | |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 72 | /* |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 73 | ** Analyze the ON CONFLICT clause described by pUpsert. Resolve all |
| 74 | ** symbols in the conflict-target. |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 75 | ** |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 76 | ** Return SQLITE_OK if everything works, or an error code is something |
| 77 | ** is wrong. |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 78 | */ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 79 | int sqlite3UpsertAnalyzeTarget( |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 80 | Parse *pParse, /* The parsing context */ |
| 81 | SrcList *pTabList, /* Table into which we are inserting */ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 82 | Upsert *pUpsert /* The ON CONFLICT clauses */ |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 83 | ){ |
drh | d5af542 | 2018-04-13 14:27:01 +0000 | [diff] [blame] | 84 | Table *pTab; /* That table into which we are inserting */ |
| 85 | int rc; /* Result code */ |
| 86 | int iCursor; /* Cursor used by pTab */ |
| 87 | Index *pIdx; /* One of the indexes of pTab */ |
| 88 | ExprList *pTarget; /* The conflict-target clause */ |
| 89 | Expr *pTerm; /* One term of the conflict-target clause */ |
| 90 | NameContext sNC; /* Context for resolving symbolic names */ |
| 91 | Expr sCol[2]; /* Index column converted into an Expr */ |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 92 | |
| 93 | assert( pTabList->nSrc==1 ); |
| 94 | assert( pTabList->a[0].pTab!=0 ); |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 95 | assert( pUpsert!=0 ); |
| 96 | assert( pUpsert->pUpsertTarget!=0 ); |
| 97 | |
| 98 | /* Resolve all symbolic names in the conflict-target clause, which |
| 99 | ** includes both the list of columns and the optional partial-index |
| 100 | ** WHERE clause. |
| 101 | */ |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 102 | memset(&sNC, 0, sizeof(sNC)); |
| 103 | sNC.pParse = pParse; |
| 104 | sNC.pSrcList = pTabList; |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 105 | rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); |
| 106 | if( rc ) return rc; |
| 107 | rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); |
| 108 | if( rc ) return rc; |
| 109 | |
| 110 | /* Check to see if the conflict target matches the rowid. */ |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 111 | pTab = pTabList->a[0].pTab; |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 112 | pTarget = pUpsert->pUpsertTarget; |
drh | d5af542 | 2018-04-13 14:27:01 +0000 | [diff] [blame] | 113 | iCursor = pTabList->a[0].iCursor; |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 114 | if( HasRowid(pTab) |
| 115 | && pTarget->nExpr==1 |
| 116 | && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN |
| 117 | && (pTerm->iColumn==XN_ROWID || pTerm->iColumn==pTab->iPKey) |
| 118 | ){ |
| 119 | /* The conflict-target is the rowid of the primary table */ |
| 120 | assert( pUpsert->pUpsertIdx==0 ); |
| 121 | return SQLITE_OK; |
| 122 | } |
| 123 | |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 124 | /* Initialize sCol[0..1] to be an expression parse tree for a |
| 125 | ** single column of an index. The sCol[0] node will be the TK_COLLATE |
| 126 | ** operator and sCol[1] will be the TK_COLUMN operator. Code below |
| 127 | ** will populate the specific collation and column number values |
| 128 | ** prior to comparing against the conflict-target expression. |
| 129 | */ |
| 130 | memset(sCol, 0, sizeof(sCol)); |
| 131 | sCol[0].op = TK_COLLATE; |
| 132 | sCol[0].pLeft = &sCol[1]; |
| 133 | sCol[1].op = TK_COLUMN; |
| 134 | sCol[1].iTable = pTabList->a[0].iCursor; |
| 135 | |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 136 | /* Check for matches against other indexes */ |
| 137 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 138 | int ii, jj, nn; |
| 139 | if( !IsUniqueIndex(pIdx) ) continue; |
| 140 | if( pTarget->nExpr!=pIdx->nKeyCol ) continue; |
| 141 | if( pIdx->pPartIdxWhere ){ |
| 142 | if( pUpsert->pUpsertTargetWhere==0 ) continue; |
| 143 | if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere, |
drh | d5af542 | 2018-04-13 14:27:01 +0000 | [diff] [blame] | 144 | pIdx->pPartIdxWhere, iCursor)!=0 ){ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 145 | continue; |
| 146 | } |
| 147 | } |
| 148 | nn = pIdx->nKeyCol; |
| 149 | for(ii=0; ii<nn; ii++){ |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 150 | Expr *pExpr; |
| 151 | if( pIdx->aiColumn[ii]==XN_EXPR ){ |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 152 | assert( pIdx->aColExpr!=0 ); |
| 153 | assert( pIdx->aColExpr->nExpr>ii ); |
| 154 | pExpr = pIdx->aColExpr->a[ii].pExpr; |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 155 | }else{ |
| 156 | sCol[1].iColumn = pIdx->aiColumn[ii]; |
| 157 | sCol[0].u.zToken = (char*)pIdx->azColl[ii]; |
| 158 | pExpr = &sCol[0]; |
| 159 | } |
| 160 | for(jj=0; jj<nn; jj++){ |
drh | d5af542 | 2018-04-13 14:27:01 +0000 | [diff] [blame] | 161 | if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){ |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 162 | break; /* Column ii of the index matches column jj of target */ |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 163 | } |
| 164 | } |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 165 | if( jj>=nn ){ |
| 166 | /* The target contains no match for column jj of the index */ |
| 167 | break; |
| 168 | } |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 169 | } |
drh | 3b45d8b | 2018-04-13 13:44:48 +0000 | [diff] [blame] | 170 | if( ii<nn ){ |
| 171 | /* Column ii of the index did not match any term of the conflict target. |
| 172 | ** Continue the search with the next index. */ |
| 173 | continue; |
| 174 | } |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 175 | pUpsert->pUpsertIdx = pIdx; |
| 176 | return SQLITE_OK; |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 177 | } |
drh | e9c2e77 | 2018-04-13 13:06:45 +0000 | [diff] [blame] | 178 | sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any " |
| 179 | "PRIMARY KEY or UNIQUE constraint"); |
| 180 | return SQLITE_ERROR; |
drh | 788d55a | 2018-04-13 01:15:09 +0000 | [diff] [blame] | 181 | } |
| 182 | |
drh | 9eddaca | 2018-04-13 18:59:17 +0000 | [diff] [blame] | 183 | /* |
| 184 | ** Generate bytecode that does an UPDATE as part of an upsert. |
| 185 | */ |
| 186 | void sqlite3UpsertDoUpdate( |
| 187 | Parse *pParse, /* The parsing and code-generating context */ |
| 188 | Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */ |
| 189 | Table *pTab, /* The table being updated */ |
| 190 | Index *pIdx, /* The UNIQUE constraint that failed */ |
| 191 | int iDataCur, /* Cursor for the pTab, table being updated */ |
drh | 0b30a11 | 2018-04-13 21:55:22 +0000 | [diff] [blame] | 192 | int iIdxCur /* Cursor for pIdx */ |
drh | 9eddaca | 2018-04-13 18:59:17 +0000 | [diff] [blame] | 193 | ){ |
| 194 | Vdbe *v = pParse->pVdbe; |
drh | 0b30a11 | 2018-04-13 21:55:22 +0000 | [diff] [blame] | 195 | sqlite3 *db = pParse->db; |
| 196 | int regKey; /* Register(s) containing the key */ |
| 197 | Expr *pWhere; /* Where clause for the UPDATE */ |
| 198 | Expr *pE1, *pE2; |
| 199 | SrcList *pSrc; /* FROM clause for the UPDATE */ |
| 200 | |
drh | 9eddaca | 2018-04-13 18:59:17 +0000 | [diff] [blame] | 201 | assert( v!=0 ); |
| 202 | VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); |
drh | 0b30a11 | 2018-04-13 21:55:22 +0000 | [diff] [blame] | 203 | pWhere = sqlite3ExprDup(db, pUpsert->pUpsertWhere, 0); |
| 204 | if( pIdx==0 || HasRowid(pTab) ){ |
| 205 | /* We are dealing with an IPK */ |
| 206 | regKey = ++pParse->nMem; |
| 207 | if( pIdx ){ |
| 208 | sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regKey); |
| 209 | }else{ |
| 210 | sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regKey); |
| 211 | } |
| 212 | pE1 = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); |
| 213 | if( pE1 ){ |
| 214 | pE1->pTab = pTab; |
| 215 | pE1->iTable = pParse->nTab; |
| 216 | pE1->iColumn = -1; |
| 217 | } |
| 218 | pE2 = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0); |
| 219 | if( pE2 ){ |
| 220 | pE2->iTable = regKey; |
| 221 | pE2->affinity = SQLITE_AFF_INTEGER; |
| 222 | } |
| 223 | pWhere = sqlite3ExprAnd(db,pWhere,sqlite3PExpr(pParse, TK_EQ, pE1, pE2)); |
drh | 0b30a11 | 2018-04-13 21:55:22 +0000 | [diff] [blame] | 224 | }else{ |
| 225 | /* a WITHOUT ROWID table */ |
drh | e966a36 | 2018-04-14 22:35:34 +0000 | [diff] [blame^] | 226 | int i, j; |
| 227 | int iTab = pParse->nTab+1; |
| 228 | Index *pX; |
| 229 | for(pX=pTab->pIndex; ALWAYS(pX) && !IsPrimaryKeyIndex(pX); pX=pX->pNext){ |
| 230 | iTab++; |
| 231 | } |
| 232 | for(i=0; i<pIdx->nKeyCol; i++){ |
| 233 | regKey = ++pParse->nMem; |
| 234 | sqlite3VdbeAddOp3(v, OP_Column, iDataCur, i, regKey); |
| 235 | j = pIdx->aiColumn[i]; |
| 236 | VdbeComment((v, "%s", pTab->aCol[j].zName)); |
| 237 | pE1 = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); |
| 238 | if( pE1 ){ |
| 239 | pE1->pTab = pTab; |
| 240 | pE1->iTable = iTab; |
| 241 | pE1->iColumn = j; |
| 242 | } |
| 243 | pE2 = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0); |
| 244 | if( pE2 ){ |
| 245 | pE2->iTable = regKey; |
| 246 | pE2->affinity = pTab->zColAff[j]; |
| 247 | } |
| 248 | pWhere = sqlite3ExprAnd(db,pWhere,sqlite3PExpr(pParse, TK_EQ, pE1, pE2)); |
| 249 | } |
drh | 0b30a11 | 2018-04-13 21:55:22 +0000 | [diff] [blame] | 250 | } |
drh | e966a36 | 2018-04-14 22:35:34 +0000 | [diff] [blame^] | 251 | pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0); |
| 252 | sqlite3Update(pParse, pSrc, |
| 253 | sqlite3ExprListDup(db, pUpsert->pUpsertSet, 0), |
| 254 | pWhere, OE_Abort, 0, 0); |
drh | 9eddaca | 2018-04-13 18:59:17 +0000 | [diff] [blame] | 255 | VdbeNoopComment((v, "End DO UPDATE of UPSERT")); |
| 256 | } |
| 257 | |
drh | fcfd756 | 2018-04-12 21:42:51 +0000 | [diff] [blame] | 258 | #endif /* SQLITE_OMIT_UPSERT */ |