* ExecOnConflictUpdate --- execute UPDATE of INSERT ON CONFLICT DO UPDATE * * Try to lock tuple for update as part of speculative insertion. If * a qual originating from ON CONFLICT DO UPDATE is satisfied, update * (but still lock row, even though it may not satisfy estate's * snapshot). * * Returns true if we're done (with or without an update), or false if * the caller must retry the IN
| 2262 | * the caller must retry the INSERT from scratch. |
| 2263 | */ |
| 2264 | static bool |
| 2265 | ExecOnConflictUpdate(ModifyTableState *mtstate, |
| 2266 | ResultRelInfo *resultRelInfo, |
| 2267 | ItemPointer conflictTid, |
| 2268 | TupleTableSlot *planSlot, |
| 2269 | TupleTableSlot *excludedSlot, |
| 2270 | EState *estate, |
| 2271 | bool canSetTag, |
| 2272 | TupleTableSlot **returning) |
| 2273 | { |
| 2274 | ExprContext *econtext = mtstate->ps.ps_ExprContext; |
| 2275 | Relation relation = resultRelInfo->ri_RelationDesc; |
| 2276 | ExprState *onConflictSetWhere = resultRelInfo->ri_onConflict->oc_WhereClause; |
| 2277 | TupleTableSlot *existing = resultRelInfo->ri_onConflict->oc_Existing; |
| 2278 | TM_FailureData tmfd; |
| 2279 | LockTupleMode lockmode; |
| 2280 | TM_Result test; |
| 2281 | Datum xminDatum; |
| 2282 | TransactionId xmin; |
| 2283 | bool isnull; |
| 2284 | |
| 2285 | /* Determine lock mode to use */ |
| 2286 | lockmode = ExecUpdateLockMode(estate, resultRelInfo); |
| 2287 | |
| 2288 | /* |
| 2289 | * Lock tuple for update. Don't follow updates when tuple cannot be |
| 2290 | * locked without doing so. A row locking conflict here means our |
| 2291 | * previous conclusion that the tuple is conclusively committed is not |
| 2292 | * true anymore. |
| 2293 | */ |
| 2294 | test = table_tuple_lock(relation, conflictTid, |
| 2295 | estate->es_snapshot, |
| 2296 | existing, estate->es_output_cid, |
| 2297 | lockmode, LockWaitBlock, 0, |
| 2298 | &tmfd); |
| 2299 | switch (test) |
| 2300 | { |
| 2301 | case TM_Ok: |
| 2302 | /* success! */ |
| 2303 | break; |
| 2304 | |
| 2305 | case TM_Invisible: |
| 2306 | |
| 2307 | /* |
| 2308 | * This can occur when a just inserted tuple is updated again in |
| 2309 | * the same command. E.g. because multiple rows with the same |
| 2310 | * conflicting key values are inserted. |
| 2311 | * |
| 2312 | * This is somewhat similar to the ExecUpdate() TM_SelfModified |
| 2313 | * case. We do not want to proceed because it would lead to the |
| 2314 | * same row being updated a second time in some unspecified order, |
| 2315 | * and in contrast to plain UPDATEs there's no historical behavior |
| 2316 | * to break. |
| 2317 | * |
| 2318 | * It is the user's responsibility to prevent this situation from |
| 2319 | * occurring. These problems are why SQL-2003 similarly specifies |
| 2320 | * that for SQL MERGE, an exception must be raised in the event of |
| 2321 | * an attempt to update the same row twice. |
no test coverage detected