Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execIndexing.c
4 : : * routines for inserting index tuples and enforcing unique and
5 : : * exclusion constraints.
6 : : *
7 : : * ExecInsertIndexTuples() is the main entry point. It's called after
8 : : * inserting a tuple to the heap, and it inserts corresponding index tuples
9 : : * into all indexes. At the same time, it enforces any unique and
10 : : * exclusion constraints:
11 : : *
12 : : * Unique Indexes
13 : : * --------------
14 : : *
15 : : * Enforcing a unique constraint is straightforward. When the index AM
16 : : * inserts the tuple to the index, it also checks that there are no
17 : : * conflicting tuples in the index already. It does so atomically, so that
18 : : * even if two backends try to insert the same key concurrently, only one
19 : : * of them will succeed. All the logic to ensure atomicity, and to wait
20 : : * for in-progress transactions to finish, is handled by the index AM.
21 : : *
22 : : * If a unique constraint is deferred, we request the index AM to not
23 : : * throw an error if a conflict is found. Instead, we make note that there
24 : : * was a conflict and return the list of indexes with conflicts to the
25 : : * caller. The caller must re-check them later, by calling index_insert()
26 : : * with the UNIQUE_CHECK_EXISTING option.
27 : : *
28 : : * Exclusion Constraints
29 : : * ---------------------
30 : : *
31 : : * Exclusion constraints are different from unique indexes in that when the
32 : : * tuple is inserted to the index, the index AM does not check for
33 : : * duplicate keys at the same time. After the insertion, we perform a
34 : : * separate scan on the index to check for conflicting tuples, and if one
35 : : * is found, we throw an error and the transaction is aborted. If the
36 : : * conflicting tuple's inserter or deleter is in-progress, we wait for it
37 : : * to finish first.
38 : : *
39 : : * There is a chance of deadlock, if two backends insert a tuple at the
40 : : * same time, and then perform the scan to check for conflicts. They will
41 : : * find each other's tuple, and both try to wait for each other. The
42 : : * deadlock detector will detect that, and abort one of the transactions.
43 : : * That's fairly harmless, as one of them was bound to abort with a
44 : : * "duplicate key error" anyway, although you get a different error
45 : : * message.
46 : : *
47 : : * If an exclusion constraint is deferred, we still perform the conflict
48 : : * checking scan immediately after inserting the index tuple. But instead
49 : : * of throwing an error if a conflict is found, we return that information
50 : : * to the caller. The caller must re-check them later by calling
51 : : * check_exclusion_constraint().
52 : : *
53 : : * Speculative insertion
54 : : * ---------------------
55 : : *
56 : : * Speculative insertion is a two-phase mechanism used to implement
57 : : * INSERT ... ON CONFLICT DO UPDATE/NOTHING. The tuple is first inserted
58 : : * to the heap and update the indexes as usual, but if a constraint is
59 : : * violated, we can still back out the insertion without aborting the whole
60 : : * transaction. In an INSERT ... ON CONFLICT statement, if a conflict is
61 : : * detected, the inserted tuple is backed out and the ON CONFLICT action is
62 : : * executed instead.
63 : : *
64 : : * Insertion to a unique index works as usual: the index AM checks for
65 : : * duplicate keys atomically with the insertion. But instead of throwing
66 : : * an error on a conflict, the speculatively inserted heap tuple is backed
67 : : * out.
68 : : *
69 : : * Exclusion constraints are slightly more complicated. As mentioned
70 : : * earlier, there is a risk of deadlock when two backends insert the same
71 : : * key concurrently. That was not a problem for regular insertions, when
72 : : * one of the transactions has to be aborted anyway, but with a speculative
73 : : * insertion we cannot let a deadlock happen, because we only want to back
74 : : * out the speculatively inserted tuple on conflict, not abort the whole
75 : : * transaction.
76 : : *
77 : : * When a backend detects that the speculative insertion conflicts with
78 : : * another in-progress tuple, it has two options:
79 : : *
80 : : * 1. back out the speculatively inserted tuple, then wait for the other
81 : : * transaction, and retry. Or,
82 : : * 2. wait for the other transaction, with the speculatively inserted tuple
83 : : * still in place.
84 : : *
85 : : * If two backends insert at the same time, and both try to wait for each
86 : : * other, they will deadlock. So option 2 is not acceptable. Option 1
87 : : * avoids the deadlock, but it is prone to a livelock instead. Both
88 : : * transactions will wake up immediately as the other transaction backs
89 : : * out. Then they both retry, and conflict with each other again, lather,
90 : : * rinse, repeat.
91 : : *
92 : : * To avoid the livelock, one of the backends must back out first, and then
93 : : * wait, while the other one waits without backing out. It doesn't matter
94 : : * which one backs out, so we employ an arbitrary rule that the transaction
95 : : * with the higher XID backs out.
96 : : *
97 : : *
98 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
99 : : * Portions Copyright (c) 1994, Regents of the University of California
100 : : *
101 : : *
102 : : * IDENTIFICATION
103 : : * src/backend/executor/execIndexing.c
104 : : *
105 : : *-------------------------------------------------------------------------
106 : : */
107 : : #include "postgres.h"
108 : :
109 : : #include "access/genam.h"
110 : : #include "access/relscan.h"
111 : : #include "access/tableam.h"
112 : : #include "access/xact.h"
113 : : #include "catalog/index.h"
114 : : #include "executor/executor.h"
115 : : #include "nodes/nodeFuncs.h"
116 : : #include "storage/lmgr.h"
117 : : #include "utils/injection_point.h"
118 : : #include "utils/multirangetypes.h"
119 : : #include "utils/rangetypes.h"
120 : : #include "utils/snapmgr.h"
121 : :
122 : : /* waitMode argument to check_exclusion_or_unique_constraint() */
123 : : typedef enum
124 : : {
125 : : CEOUC_WAIT,
126 : : CEOUC_NOWAIT,
127 : : CEOUC_LIVELOCK_PREVENTING_WAIT,
128 : : } CEOUC_WAIT_MODE;
129 : :
130 : : static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
131 : : IndexInfo *indexInfo,
132 : : const ItemPointerData *tupleid,
133 : : const Datum *values, const bool *isnull,
134 : : EState *estate, bool newIndex,
135 : : CEOUC_WAIT_MODE waitMode,
136 : : bool violationOK,
137 : : ItemPointer conflictTid);
138 : :
139 : : static bool index_recheck_constraint(Relation index, const Oid *constr_procs,
140 : : const Datum *existing_values, const bool *existing_isnull,
141 : : const Datum *new_values);
142 : : static bool index_unchanged_by_update(ResultRelInfo *resultRelInfo,
143 : : EState *estate, IndexInfo *indexInfo,
144 : : Relation indexRelation);
145 : : static bool index_expression_changed_walker(Node *node,
146 : : Bitmapset *allUpdatedCols);
147 : : static void ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval,
148 : : char typtype, Oid atttypid);
149 : :
150 : : /* ----------------------------------------------------------------
151 : : * ExecOpenIndices
152 : : *
153 : : * Find the indices associated with a result relation, open them,
154 : : * and save information about them in the result ResultRelInfo.
155 : : *
156 : : * At entry, caller has already opened and locked
157 : : * resultRelInfo->ri_RelationDesc.
158 : : * ----------------------------------------------------------------
159 : : */
160 : : void
161 : 118202 : ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
162 : : {
163 : 118202 : Relation resultRelation = resultRelInfo->ri_RelationDesc;
164 : 118202 : List *indexoidlist;
165 : 118202 : ListCell *l;
166 : 118202 : int len,
167 : : i;
168 : 118202 : RelationPtr relationDescs;
169 : 118202 : IndexInfo **indexInfoArray;
170 : :
171 : 118202 : resultRelInfo->ri_NumIndices = 0;
172 : :
173 : : /* fast path if no indexes */
174 [ + + ]: 118202 : if (!RelationGetForm(resultRelation)->relhasindex)
175 : 940 : return;
176 : :
177 : : /*
178 : : * Get cached list of index OIDs
179 : : */
180 : 117262 : indexoidlist = RelationGetIndexList(resultRelation);
181 : 117262 : len = list_length(indexoidlist);
182 [ + + ]: 117262 : if (len == 0)
183 : 93 : return;
184 : :
185 : : /* This Assert will fail if ExecOpenIndices is called twice */
186 [ + - ]: 117169 : Assert(resultRelInfo->ri_IndexRelationDescs == NULL);
187 : :
188 : : /*
189 : : * allocate space for result arrays
190 : : */
191 : 117169 : relationDescs = palloc_array(Relation, len);
192 : 117169 : indexInfoArray = palloc_array(IndexInfo *, len);
193 : :
194 : 117169 : resultRelInfo->ri_NumIndices = len;
195 : 117169 : resultRelInfo->ri_IndexRelationDescs = relationDescs;
196 : 117169 : resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
197 : :
198 : : /*
199 : : * For each index, open the index relation and save pg_index info. We
200 : : * acquire RowExclusiveLock, signifying we will update the index.
201 : : *
202 : : * Note: we do this even if the index is not indisready; it's not worth
203 : : * the trouble to optimize for the case where it isn't.
204 : : */
205 : 117169 : i = 0;
206 [ + - + + : 383232 : foreach(l, indexoidlist)
+ + ]
207 : : {
208 : 266063 : Oid indexOid = lfirst_oid(l);
209 : 266063 : Relation indexDesc;
210 : 266063 : IndexInfo *ii;
211 : :
212 : 266063 : indexDesc = index_open(indexOid, RowExclusiveLock);
213 : :
214 : : /* extract index key information from the index's pg_index info */
215 : 266063 : ii = BuildIndexInfo(indexDesc);
216 : :
217 : : /*
218 : : * If the indexes are to be used for speculative insertion, add extra
219 : : * information required by unique index entries.
220 : : */
221 [ + + + + : 266063 : if (speculative && ii->ii_Unique && !indexDesc->rd_index->indisexclusion)
+ + ]
222 : 188 : BuildSpeculativeIndexInfo(indexDesc, ii);
223 : :
224 : 266063 : relationDescs[i] = indexDesc;
225 : 266063 : indexInfoArray[i] = ii;
226 : 266063 : i++;
227 : 266063 : }
228 : :
229 : 117169 : list_free(indexoidlist);
230 [ - + ]: 118202 : }
231 : :
232 : : /* ----------------------------------------------------------------
233 : : * ExecCloseIndices
234 : : *
235 : : * Close the index relations stored in resultRelInfo
236 : : * ----------------------------------------------------------------
237 : : */
238 : : void
239 : 125312 : ExecCloseIndices(ResultRelInfo *resultRelInfo)
240 : : {
241 : 125312 : int i;
242 : 125312 : int numIndices;
243 : 125312 : RelationPtr indexDescs;
244 : 125312 : IndexInfo **indexInfos;
245 : :
246 : 125312 : numIndices = resultRelInfo->ri_NumIndices;
247 : 125312 : indexDescs = resultRelInfo->ri_IndexRelationDescs;
248 : 125312 : indexInfos = resultRelInfo->ri_IndexRelationInfo;
249 : :
250 [ + + ]: 391115 : for (i = 0; i < numIndices; i++)
251 : : {
252 : : /* This Assert will fail if ExecCloseIndices is called twice */
253 [ + - ]: 265803 : Assert(indexDescs[i] != NULL);
254 : :
255 : : /* Give the index a chance to do some post-insert cleanup */
256 : 265803 : index_insert_cleanup(indexDescs[i], indexInfos[i]);
257 : :
258 : : /* Drop lock acquired by ExecOpenIndices */
259 : 265803 : index_close(indexDescs[i], RowExclusiveLock);
260 : :
261 : : /* Mark the index as closed */
262 : 265803 : indexDescs[i] = NULL;
263 : 265803 : }
264 : :
265 : : /*
266 : : * We don't attempt to free the IndexInfo data structures or the arrays,
267 : : * instead assuming that such stuff will be cleaned up automatically in
268 : : * FreeExecutorState.
269 : : */
270 : 125312 : }
271 : :
272 : : /* ----------------------------------------------------------------
273 : : * ExecInsertIndexTuples
274 : : *
275 : : * This routine takes care of inserting index tuples
276 : : * into all the relations indexing the result relation
277 : : * when a heap tuple is inserted into the result relation.
278 : : *
279 : : * When 'update' is true and 'onlySummarizing' is false,
280 : : * executor is performing an UPDATE that could not use an
281 : : * optimization like heapam's HOT (in more general terms a
282 : : * call to table_tuple_update() took place and set
283 : : * 'update_indexes' to TU_All). Receiving this hint makes
284 : : * us consider if we should pass down the 'indexUnchanged'
285 : : * hint in turn. That's something that we figure out for
286 : : * each index_insert() call iff 'update' is true.
287 : : * (When 'update' is false we already know not to pass the
288 : : * hint to any index.)
289 : : *
290 : : * If onlySummarizing is set, an equivalent optimization to
291 : : * HOT has been applied and any updated columns are indexed
292 : : * only by summarizing indexes (or in more general terms a
293 : : * call to table_tuple_update() took place and set
294 : : * 'update_indexes' to TU_Summarizing). We can (and must)
295 : : * therefore only update the indexes that have
296 : : * 'amsummarizing' = true.
297 : : *
298 : : * Unique and exclusion constraints are enforced at the same
299 : : * time. This returns a list of index OIDs for any unique or
300 : : * exclusion constraints that are deferred and that had
301 : : * potential (unconfirmed) conflicts. (if noDupErr == true,
302 : : * the same is done for non-deferred constraints, but report
303 : : * if conflict was speculative or deferred conflict to caller)
304 : : *
305 : : * If 'arbiterIndexes' is nonempty, noDupErr applies only to
306 : : * those indexes. NIL means noDupErr applies to all indexes.
307 : : * ----------------------------------------------------------------
308 : : */
309 : : List *
310 : 550202 : ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
311 : : TupleTableSlot *slot,
312 : : EState *estate,
313 : : bool update,
314 : : bool noDupErr,
315 : : bool *specConflict,
316 : : List *arbiterIndexes,
317 : : bool onlySummarizing)
318 : : {
319 : 550202 : ItemPointer tupleid = &slot->tts_tid;
320 : 550202 : List *result = NIL;
321 : 550202 : int i;
322 : 550202 : int numIndices;
323 : 550202 : RelationPtr relationDescs;
324 : 550202 : Relation heapRelation;
325 : 550202 : IndexInfo **indexInfoArray;
326 : 550202 : ExprContext *econtext;
327 : 550202 : Datum values[INDEX_MAX_KEYS];
328 : 550202 : bool isnull[INDEX_MAX_KEYS];
329 : :
330 [ + - ]: 550202 : Assert(ItemPointerIsValid(tupleid));
331 : :
332 : : /*
333 : : * Get information from the result relation info structure.
334 : : */
335 : 550202 : numIndices = resultRelInfo->ri_NumIndices;
336 : 550202 : relationDescs = resultRelInfo->ri_IndexRelationDescs;
337 : 550202 : indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
338 : 550202 : heapRelation = resultRelInfo->ri_RelationDesc;
339 : :
340 : : /* Sanity check: slot must belong to the same rel as the resultRelInfo. */
341 [ + - ]: 550202 : Assert(slot->tts_tableOid == RelationGetRelid(heapRelation));
342 : :
343 : : /*
344 : : * We will use the EState's per-tuple context for evaluating predicates
345 : : * and index expressions (creating it if it's not already there).
346 : : */
347 [ + + ]: 550202 : econtext = GetPerTupleExprContext(estate);
348 : :
349 : : /* Arrange for econtext's scan tuple to be the tuple under test */
350 : 550202 : econtext->ecxt_scantuple = slot;
351 : :
352 : : /*
353 : : * for each index, form and insert the index tuple
354 : : */
355 [ + + ]: 1151230 : for (i = 0; i < numIndices; i++)
356 : : {
357 : 601028 : Relation indexRelation = relationDescs[i];
358 : 601028 : IndexInfo *indexInfo;
359 : 601028 : bool applyNoDupErr;
360 : 601028 : IndexUniqueCheck checkUnique;
361 : 601028 : bool indexUnchanged;
362 : 601028 : bool satisfiesConstraint;
363 : :
364 [ + - ]: 601028 : if (indexRelation == NULL)
365 : 0 : continue;
366 : :
367 : 601028 : indexInfo = indexInfoArray[i];
368 : :
369 : : /* If the index is marked as read-only, ignore it */
370 [ + - ]: 601028 : if (!indexInfo->ii_ReadyForInserts)
371 : 0 : continue;
372 : :
373 : : /*
374 : : * Skip processing of non-summarizing indexes if we only update
375 : : * summarizing indexes
376 : : */
377 [ + + + + ]: 601028 : if (onlySummarizing && !indexInfo->ii_Summarizing)
378 : 1 : continue;
379 : :
380 : : /* Check for partial index */
381 [ + + ]: 601027 : if (indexInfo->ii_Predicate != NIL)
382 : : {
383 : 21 : ExprState *predicate;
384 : :
385 : : /*
386 : : * If predicate state not set up yet, create it (in the estate's
387 : : * per-query context)
388 : : */
389 : 21 : predicate = indexInfo->ii_PredicateState;
390 [ + + ]: 21 : if (predicate == NULL)
391 : : {
392 : 17 : predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
393 : 17 : indexInfo->ii_PredicateState = predicate;
394 : 17 : }
395 : :
396 : : /* Skip this index-update if the predicate isn't satisfied */
397 [ + + ]: 21 : if (!ExecQual(predicate, econtext))
398 : 6 : continue;
399 [ + + ]: 21 : }
400 : :
401 : : /*
402 : : * FormIndexDatum fills in its values and isnull parameters with the
403 : : * appropriate values for the column(s) of the index.
404 : : */
405 : 1202042 : FormIndexDatum(indexInfo,
406 : 601021 : slot,
407 : 601021 : estate,
408 : 601021 : values,
409 : 601021 : isnull);
410 : :
411 : : /* Check whether to apply noDupErr to this index */
412 [ + + ]: 601115 : applyNoDupErr = noDupErr &&
413 [ + + ]: 94 : (arbiterIndexes == NIL ||
414 : 156 : list_member_oid(arbiterIndexes,
415 : 78 : indexRelation->rd_index->indexrelid));
416 : :
417 : : /*
418 : : * The index AM does the actual insertion, plus uniqueness checking.
419 : : *
420 : : * For an immediate-mode unique index, we just tell the index AM to
421 : : * throw error if not unique.
422 : : *
423 : : * For a deferrable unique index, we tell the index AM to just detect
424 : : * possible non-uniqueness, and we add the index OID to the result
425 : : * list if further checking is needed.
426 : : *
427 : : * For a speculative insertion (used by INSERT ... ON CONFLICT), do
428 : : * the same as for a deferrable unique index.
429 : : */
430 [ + + ]: 601021 : if (!indexRelation->rd_index->indisunique)
431 : 240871 : checkUnique = UNIQUE_CHECK_NO;
432 [ + + ]: 360150 : else if (applyNoDupErr)
433 : 88 : checkUnique = UNIQUE_CHECK_PARTIAL;
434 [ + + ]: 360062 : else if (indexRelation->rd_index->indimmediate)
435 : 360038 : checkUnique = UNIQUE_CHECK_YES;
436 : : else
437 : 24 : checkUnique = UNIQUE_CHECK_PARTIAL;
438 : :
439 : : /*
440 : : * There's definitely going to be an index_insert() call for this
441 : : * index. If we're being called as part of an UPDATE statement,
442 : : * consider if the 'indexUnchanged' = true hint should be passed.
443 : : */
444 [ + + ]: 601021 : indexUnchanged = update && index_unchanged_by_update(resultRelInfo,
445 : 20804 : estate,
446 : 20804 : indexInfo,
447 : 20804 : indexRelation);
448 : :
449 : 601021 : satisfiesConstraint =
450 : 1202042 : index_insert(indexRelation, /* index relation */
451 : 601021 : values, /* array of index Datums */
452 : 601021 : isnull, /* null flags */
453 : 601021 : tupleid, /* tid of heap tuple */
454 : 601021 : heapRelation, /* heap relation */
455 : 601021 : checkUnique, /* type of uniqueness check to do */
456 : 601021 : indexUnchanged, /* UPDATE without logical change? */
457 : 601021 : indexInfo); /* index AM may need this */
458 : :
459 : : /*
460 : : * If the index has an associated exclusion constraint, check that.
461 : : * This is simpler than the process for uniqueness checks since we
462 : : * always insert first and then check. If the constraint is deferred,
463 : : * we check now anyway, but don't throw error on violation or wait for
464 : : * a conclusive outcome from a concurrent insertion; instead we'll
465 : : * queue a recheck event. Similarly, noDupErr callers (speculative
466 : : * inserters) will recheck later, and wait for a conclusive outcome
467 : : * then.
468 : : *
469 : : * An index for an exclusion constraint can't also be UNIQUE (not an
470 : : * essential property, we just don't allow it in the grammar), so no
471 : : * need to preserve the prior state of satisfiesConstraint.
472 : : */
473 [ + + ]: 601021 : if (indexInfo->ii_ExclusionOps != NULL)
474 : : {
475 : 293 : bool violationOK;
476 : 293 : CEOUC_WAIT_MODE waitMode;
477 : :
478 [ + + ]: 293 : if (applyNoDupErr)
479 : : {
480 : 16 : violationOK = true;
481 : 16 : waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
482 : 16 : }
483 [ + + ]: 277 : else if (!indexRelation->rd_index->indimmediate)
484 : : {
485 : 7 : violationOK = true;
486 : 7 : waitMode = CEOUC_NOWAIT;
487 : 7 : }
488 : : else
489 : : {
490 : 270 : violationOK = false;
491 : 270 : waitMode = CEOUC_WAIT;
492 : : }
493 : :
494 : 293 : satisfiesConstraint =
495 : 586 : check_exclusion_or_unique_constraint(heapRelation,
496 : 293 : indexRelation, indexInfo,
497 : 293 : tupleid, values, isnull,
498 : 293 : estate, false,
499 : 293 : waitMode, violationOK, NULL);
500 : 293 : }
501 : :
502 [ + + ]: 601021 : if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
503 [ + + ]: 601021 : indexInfo->ii_ExclusionOps != NULL) &&
504 : 601021 : !satisfiesConstraint)
505 : : {
506 : : /*
507 : : * The tuple potentially violates the uniqueness or exclusion
508 : : * constraint, so make a note of the index so that we can re-check
509 : : * it later. Speculative inserters are told if there was a
510 : : * speculative conflict, since that always requires a restart.
511 : : */
512 : 20 : result = lappend_oid(result, RelationGetRelid(indexRelation));
513 [ - + # # ]: 20 : if (indexRelation->rd_index->indimmediate && specConflict)
514 : 0 : *specConflict = true;
515 : 20 : }
516 [ - + + ]: 601028 : }
517 : :
518 : 1100404 : return result;
519 : 550202 : }
520 : :
521 : : /* ----------------------------------------------------------------
522 : : * ExecCheckIndexConstraints
523 : : *
524 : : * This routine checks if a tuple violates any unique or
525 : : * exclusion constraints. Returns true if there is no conflict.
526 : : * Otherwise returns false, and the TID of the conflicting
527 : : * tuple is returned in *conflictTid.
528 : : *
529 : : * If 'arbiterIndexes' is given, only those indexes are checked.
530 : : * NIL means all indexes.
531 : : *
532 : : * Note that this doesn't lock the values in any way, so it's
533 : : * possible that a conflicting tuple is inserted immediately
534 : : * after this returns. This can be used for either a pre-check
535 : : * before insertion or a re-check after finding a conflict.
536 : : *
537 : : * 'tupleid' should be the TID of the tuple that has been recently
538 : : * inserted (or can be invalid if we haven't inserted a new tuple yet).
539 : : * This tuple will be excluded from conflict checking.
540 : : * ----------------------------------------------------------------
541 : : */
542 : : bool
543 : 229 : ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
544 : : EState *estate, ItemPointer conflictTid,
545 : : const ItemPointerData *tupleid, List *arbiterIndexes)
546 : : {
547 : 229 : int i;
548 : 229 : int numIndices;
549 : 229 : RelationPtr relationDescs;
550 : 229 : Relation heapRelation;
551 : 229 : IndexInfo **indexInfoArray;
552 : 229 : ExprContext *econtext;
553 : 229 : Datum values[INDEX_MAX_KEYS];
554 : 229 : bool isnull[INDEX_MAX_KEYS];
555 : 229 : ItemPointerData invalidItemPtr;
556 : 229 : bool checkedIndex = false;
557 : :
558 : 229 : ItemPointerSetInvalid(conflictTid);
559 : 229 : ItemPointerSetInvalid(&invalidItemPtr);
560 : :
561 : : /*
562 : : * Get information from the result relation info structure.
563 : : */
564 : 229 : numIndices = resultRelInfo->ri_NumIndices;
565 : 229 : relationDescs = resultRelInfo->ri_IndexRelationDescs;
566 : 229 : indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
567 : 229 : heapRelation = resultRelInfo->ri_RelationDesc;
568 : :
569 : : /*
570 : : * We will use the EState's per-tuple context for evaluating predicates
571 : : * and index expressions (creating it if it's not already there).
572 : : */
573 [ + + ]: 229 : econtext = GetPerTupleExprContext(estate);
574 : :
575 : : /* Arrange for econtext's scan tuple to be the tuple under test */
576 : 229 : econtext->ecxt_scantuple = slot;
577 : :
578 : : /*
579 : : * For each index, form index tuple and check if it satisfies the
580 : : * constraint.
581 : : */
582 [ + + ]: 330 : for (i = 0; i < numIndices; i++)
583 : : {
584 : 243 : Relation indexRelation = relationDescs[i];
585 : 243 : IndexInfo *indexInfo;
586 : 243 : bool satisfiesConstraint;
587 : :
588 [ + - ]: 243 : if (indexRelation == NULL)
589 : 0 : continue;
590 : :
591 : 243 : indexInfo = indexInfoArray[i];
592 : :
593 [ + + + - ]: 243 : if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
594 : 0 : continue;
595 : :
596 : : /* If the index is marked as read-only, ignore it */
597 [ + - ]: 243 : if (!indexInfo->ii_ReadyForInserts)
598 : 0 : continue;
599 : :
600 : : /* When specific arbiter indexes requested, only examine them */
601 [ + + + + ]: 243 : if (arbiterIndexes != NIL &&
602 : 432 : !list_member_oid(arbiterIndexes,
603 : 216 : indexRelation->rd_index->indexrelid))
604 : 13 : continue;
605 : :
606 [ + + ]: 230 : if (!indexRelation->rd_index->indimmediate)
607 [ + - + - ]: 1 : ereport(ERROR,
608 : : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
609 : : errmsg("ON CONFLICT does not support deferrable unique constraints/exclusion constraints as arbiters"),
610 : : errtableconstraint(heapRelation,
611 : : RelationGetRelationName(indexRelation))));
612 : :
613 : 229 : checkedIndex = true;
614 : :
615 : : /* Check for partial index */
616 [ + + ]: 229 : if (indexInfo->ii_Predicate != NIL)
617 : : {
618 : 6 : ExprState *predicate;
619 : :
620 : : /*
621 : : * If predicate state not set up yet, create it (in the estate's
622 : : * per-query context)
623 : : */
624 : 6 : predicate = indexInfo->ii_PredicateState;
625 [ - + ]: 6 : if (predicate == NULL)
626 : : {
627 : 6 : predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
628 : 6 : indexInfo->ii_PredicateState = predicate;
629 : 6 : }
630 : :
631 : : /* Skip this index-update if the predicate isn't satisfied */
632 [ + - ]: 6 : if (!ExecQual(predicate, econtext))
633 : 0 : continue;
634 [ - + ]: 6 : }
635 : :
636 : : /*
637 : : * FormIndexDatum fills in its values and isnull parameters with the
638 : : * appropriate values for the column(s) of the index.
639 : : */
640 : 458 : FormIndexDatum(indexInfo,
641 : 229 : slot,
642 : 229 : estate,
643 : 229 : values,
644 : 229 : isnull);
645 : :
646 : 229 : satisfiesConstraint =
647 : 458 : check_exclusion_or_unique_constraint(heapRelation, indexRelation,
648 : 229 : indexInfo, tupleid,
649 : 229 : values, isnull, estate, false,
650 : : CEOUC_WAIT, true,
651 : 229 : conflictTid);
652 [ + + ]: 229 : if (!satisfiesConstraint)
653 : 141 : return false;
654 [ + + + ]: 242 : }
655 : :
656 [ + + + - ]: 87 : if (arbiterIndexes != NIL && !checkedIndex)
657 [ # # # # ]: 0 : elog(ERROR, "unexpected failure to find arbiter index");
658 : :
659 : 87 : return true;
660 : 228 : }
661 : :
662 : : /*
663 : : * Check for violation of an exclusion or unique constraint
664 : : *
665 : : * heap: the table containing the new tuple
666 : : * index: the index supporting the constraint
667 : : * indexInfo: info about the index, including the exclusion properties
668 : : * tupleid: heap TID of the new tuple we have just inserted (invalid if we
669 : : * haven't inserted a new tuple yet)
670 : : * values, isnull: the *index* column values computed for the new tuple
671 : : * estate: an EState we can do evaluation in
672 : : * newIndex: if true, we are trying to build a new index (this affects
673 : : * only the wording of error messages)
674 : : * waitMode: whether to wait for concurrent inserters/deleters
675 : : * violationOK: if true, don't throw error for violation
676 : : * conflictTid: if not-NULL, the TID of the conflicting tuple is returned here
677 : : *
678 : : * Returns true if OK, false if actual or potential violation
679 : : *
680 : : * 'waitMode' determines what happens if a conflict is detected with a tuple
681 : : * that was inserted or deleted by a transaction that's still running.
682 : : * CEOUC_WAIT means that we wait for the transaction to commit, before
683 : : * throwing an error or returning. CEOUC_NOWAIT means that we report the
684 : : * violation immediately; so the violation is only potential, and the caller
685 : : * must recheck sometime later. This behavior is convenient for deferred
686 : : * exclusion checks; we need not bother queuing a deferred event if there is
687 : : * definitely no conflict at insertion time.
688 : : *
689 : : * CEOUC_LIVELOCK_PREVENTING_WAIT is like CEOUC_NOWAIT, but we will sometimes
690 : : * wait anyway, to prevent livelocking if two transactions try inserting at
691 : : * the same time. This is used with speculative insertions, for INSERT ON
692 : : * CONFLICT statements. (See notes in file header)
693 : : *
694 : : * If violationOK is true, we just report the potential or actual violation to
695 : : * the caller by returning 'false'. Otherwise we throw a descriptive error
696 : : * message here. When violationOK is false, a false result is impossible.
697 : : *
698 : : * Note: The indexam is normally responsible for checking unique constraints,
699 : : * so this normally only needs to be used for exclusion constraints. But this
700 : : * function is also called when doing a "pre-check" for conflicts on a unique
701 : : * constraint, when doing speculative insertion. Caller may use the returned
702 : : * conflict TID to take further steps.
703 : : */
704 : : static bool
705 : 595 : check_exclusion_or_unique_constraint(Relation heap, Relation index,
706 : : IndexInfo *indexInfo,
707 : : const ItemPointerData *tupleid,
708 : : const Datum *values, const bool *isnull,
709 : : EState *estate, bool newIndex,
710 : : CEOUC_WAIT_MODE waitMode,
711 : : bool violationOK,
712 : : ItemPointer conflictTid)
713 : : {
714 : 595 : Oid *constr_procs;
715 : 595 : uint16 *constr_strats;
716 : 595 : Oid *index_collations = index->rd_indcollation;
717 : 595 : int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
718 : 595 : IndexScanDesc index_scan;
719 : 595 : ScanKeyData scankeys[INDEX_MAX_KEYS];
720 : 595 : SnapshotData DirtySnapshot;
721 : 595 : int i;
722 : 595 : bool conflict;
723 : 595 : bool found_self;
724 : 595 : ExprContext *econtext;
725 : 595 : TupleTableSlot *existing_slot;
726 : 595 : TupleTableSlot *save_scantuple;
727 : :
728 [ + + ]: 595 : if (indexInfo->ii_ExclusionOps)
729 : : {
730 : 392 : constr_procs = indexInfo->ii_ExclusionProcs;
731 : 392 : constr_strats = indexInfo->ii_ExclusionStrats;
732 : 392 : }
733 : : else
734 : : {
735 : 203 : constr_procs = indexInfo->ii_UniqueProcs;
736 : 203 : constr_strats = indexInfo->ii_UniqueStrats;
737 : : }
738 : :
739 : : /*
740 : : * If this is a WITHOUT OVERLAPS constraint, we must also forbid empty
741 : : * ranges/multiranges. This must happen before we look for NULLs below, or
742 : : * a UNIQUE constraint could insert an empty range along with a NULL
743 : : * scalar part.
744 : : */
745 [ + + ]: 595 : if (indexInfo->ii_WithoutOverlaps)
746 : : {
747 : : /*
748 : : * Look up the type from the heap tuple, but check the Datum from the
749 : : * index tuple.
750 : : */
751 : 330 : AttrNumber attno = indexInfo->ii_IndexAttrNumbers[indnkeyatts - 1];
752 : :
753 [ + + ]: 330 : if (!isnull[indnkeyatts - 1])
754 : : {
755 : 326 : TupleDesc tupdesc = RelationGetDescr(heap);
756 : 326 : Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
757 : 326 : TypeCacheEntry *typcache = lookup_type_cache(att->atttypid, 0);
758 : :
759 : 652 : ExecWithoutOverlapsNotEmpty(heap, att->attname,
760 : 326 : values[indnkeyatts - 1],
761 : 326 : typcache->typtype, att->atttypid);
762 : 326 : }
763 : 330 : }
764 : :
765 : : /*
766 : : * If any of the input values are NULL, and the index uses the default
767 : : * nulls-are-distinct mode, the constraint check is assumed to pass (i.e.,
768 : : * we assume the operators are strict). Otherwise, we interpret the
769 : : * constraint as specifying IS NULL for each column whose input value is
770 : : * NULL.
771 : : */
772 [ + + ]: 587 : if (!indexInfo->ii_NullsNotDistinct)
773 : : {
774 [ + + ]: 1492 : for (i = 0; i < indnkeyatts; i++)
775 : : {
776 [ + + ]: 926 : if (isnull[i])
777 : 20 : return true;
778 : 906 : }
779 : 566 : }
780 : :
781 : : /*
782 : : * Search the tuples that are in the index for any violations, including
783 : : * tuples that aren't visible yet.
784 : : */
785 : 567 : InitDirtySnapshot(DirtySnapshot);
786 : :
787 [ + + ]: 1464 : for (i = 0; i < indnkeyatts; i++)
788 : : {
789 : 1794 : ScanKeyEntryInitialize(&scankeys[i],
790 : 897 : isnull[i] ? SK_ISNULL | SK_SEARCHNULL : 0,
791 : 897 : i + 1,
792 : 897 : constr_strats[i],
793 : : InvalidOid,
794 : 897 : index_collations[i],
795 : 897 : constr_procs[i],
796 : 897 : values[i]);
797 : 897 : }
798 : :
799 : : /*
800 : : * Need a TupleTableSlot to put existing tuples in.
801 : : *
802 : : * To use FormIndexDatum, we have to make the econtext's scantuple point
803 : : * to this slot. Be sure to save and restore caller's value for
804 : : * scantuple.
805 : : */
806 : 567 : existing_slot = table_slot_create(heap, NULL);
807 : :
808 [ + - ]: 567 : econtext = GetPerTupleExprContext(estate);
809 : 567 : save_scantuple = econtext->ecxt_scantuple;
810 : 567 : econtext->ecxt_scantuple = existing_slot;
811 : :
812 : : /*
813 : : * May have to restart scan from this point if a potential conflict is
814 : : * found.
815 : : */
816 : : retry:
817 : 567 : conflict = false;
818 : 567 : found_self = false;
819 : 567 : index_scan = index_beginscan(heap, index, &DirtySnapshot, NULL, indnkeyatts, 0);
820 : 567 : index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
821 : :
822 [ + + ]: 1032 : while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
823 : : {
824 : 492 : TransactionId xwait;
825 : 492 : XLTW_Oper reason_wait;
826 : 492 : Datum existing_values[INDEX_MAX_KEYS];
827 : 492 : bool existing_isnull[INDEX_MAX_KEYS];
828 : 492 : char *error_new;
829 : 492 : char *error_existing;
830 : :
831 : : /*
832 : : * Ignore the entry for the tuple we're trying to check.
833 : : */
834 [ + + + + ]: 492 : if (ItemPointerIsValid(tupleid) &&
835 : 351 : ItemPointerEquals(tupleid, &existing_slot->tts_tid))
836 : : {
837 [ - + ]: 311 : if (found_self) /* should not happen */
838 [ # # # # ]: 0 : elog(ERROR, "found self tuple multiple times in index \"%s\"",
839 : : RelationGetRelationName(index));
840 : 311 : found_self = true;
841 : 311 : continue;
842 : : }
843 : :
844 : : /*
845 : : * Extract the index column values and isnull flags from the existing
846 : : * tuple.
847 : : */
848 : 362 : FormIndexDatum(indexInfo, existing_slot, estate,
849 : 181 : existing_values, existing_isnull);
850 : :
851 : : /* If lossy indexscan, must recheck the condition */
852 [ + + ]: 181 : if (index_scan->xs_recheck)
853 : : {
854 [ + + + + ]: 46 : if (!index_recheck_constraint(index,
855 : 23 : constr_procs,
856 : 23 : existing_values,
857 : 23 : existing_isnull,
858 : 23 : values))
859 : 9 : continue; /* tuple doesn't actually match, so no
860 : : * conflict */
861 : 14 : }
862 : :
863 : : /*
864 : : * At this point we have either a conflict or a potential conflict.
865 : : *
866 : : * If an in-progress transaction is affecting the visibility of this
867 : : * tuple, we need to wait for it to complete and then recheck (unless
868 : : * the caller requested not to). For simplicity we do rechecking by
869 : : * just restarting the whole scan --- this case probably doesn't
870 : : * happen often enough to be worth trying harder, and anyway we don't
871 : : * want to hold any index internal locks while waiting.
872 : : */
873 [ - + ]: 172 : xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
874 : 172 : DirtySnapshot.xmin : DirtySnapshot.xmax;
875 : :
876 [ - + # # ]: 172 : if (TransactionIdIsValid(xwait) &&
877 [ # # ]: 0 : (waitMode == CEOUC_WAIT ||
878 [ # # ]: 0 : (waitMode == CEOUC_LIVELOCK_PREVENTING_WAIT &&
879 [ # # ]: 0 : DirtySnapshot.speculativeToken &&
880 : 0 : TransactionIdPrecedes(GetCurrentTransactionId(), xwait))))
881 : : {
882 : 0 : reason_wait = indexInfo->ii_ExclusionOps ?
883 : : XLTW_RecheckExclusionConstr : XLTW_InsertIndex;
884 : 0 : index_endscan(index_scan);
885 [ # # ]: 0 : if (DirtySnapshot.speculativeToken)
886 : 0 : SpeculativeInsertionWait(DirtySnapshot.xmin,
887 : 0 : DirtySnapshot.speculativeToken);
888 : : else
889 : 0 : XactLockTableWait(xwait, heap,
890 : 0 : &existing_slot->tts_tid, reason_wait);
891 : 0 : goto retry;
892 : : }
893 : :
894 : : /*
895 : : * We have a definite conflict (or a potential one, but the caller
896 : : * didn't want to wait). Return it to caller, or report it.
897 : : */
898 [ + + ]: 172 : if (violationOK)
899 : : {
900 : 145 : conflict = true;
901 [ + + ]: 145 : if (conflictTid)
902 : 141 : *conflictTid = existing_slot->tts_tid;
903 : 145 : break;
904 : : }
905 : :
906 : 27 : error_new = BuildIndexValueDescription(index, values, isnull);
907 : 54 : error_existing = BuildIndexValueDescription(index, existing_values,
908 : 27 : existing_isnull);
909 [ + + ]: 27 : if (newIndex)
910 [ + - + - : 6 : ereport(ERROR,
+ - - + ]
911 : : (errcode(ERRCODE_EXCLUSION_VIOLATION),
912 : : errmsg("could not create exclusion constraint \"%s\"",
913 : : RelationGetRelationName(index)),
914 : : error_new && error_existing ?
915 : : errdetail("Key %s conflicts with key %s.",
916 : : error_new, error_existing) :
917 : : errdetail("Key conflicts exist."),
918 : : errtableconstraint(heap,
919 : : RelationGetRelationName(index))));
920 : : else
921 [ + - + - : 21 : ereport(ERROR,
+ - - + ]
922 : : (errcode(ERRCODE_EXCLUSION_VIOLATION),
923 : : errmsg("conflicting key value violates exclusion constraint \"%s\"",
924 : : RelationGetRelationName(index)),
925 : : error_new && error_existing ?
926 : : errdetail("Key %s conflicts with existing key %s.",
927 : : error_new, error_existing) :
928 : : errdetail("Key conflicts with existing key."),
929 : : errtableconstraint(heap,
930 : : RelationGetRelationName(index))));
931 [ - + - - ]: 465 : }
932 : :
933 : 540 : index_endscan(index_scan);
934 : :
935 : : /*
936 : : * Ordinarily, at this point the search should have found the originally
937 : : * inserted tuple (if any), unless we exited the loop early because of
938 : : * conflict. However, it is possible to define exclusion constraints for
939 : : * which that wouldn't be true --- for instance, if the operator is <>. So
940 : : * we no longer complain if found_self is still false.
941 : : */
942 : :
943 : 540 : econtext->ecxt_scantuple = save_scantuple;
944 : :
945 : 540 : ExecDropSingleTupleTableSlot(existing_slot);
946 : :
947 : : #ifdef USE_INJECTION_POINTS
948 : : if (!conflict)
949 : : INJECTION_POINT("check-exclusion-or-unique-constraint-no-conflict", NULL);
950 : : #endif
951 : :
952 : 540 : return !conflict;
953 : 560 : }
954 : :
955 : : /*
956 : : * Check for violation of an exclusion constraint
957 : : *
958 : : * This is a dumbed down version of check_exclusion_or_unique_constraint
959 : : * for external callers. They don't need all the special modes.
960 : : */
961 : : void
962 : 79 : check_exclusion_constraint(Relation heap, Relation index,
963 : : IndexInfo *indexInfo,
964 : : const ItemPointerData *tupleid,
965 : : const Datum *values, const bool *isnull,
966 : : EState *estate, bool newIndex)
967 : : {
968 : 158 : (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
969 : 79 : values, isnull,
970 : 79 : estate, newIndex,
971 : : CEOUC_WAIT, false, NULL);
972 : 79 : }
973 : :
974 : : /*
975 : : * Check existing tuple's index values to see if it really matches the
976 : : * exclusion condition against the new_values. Returns true if conflict.
977 : : */
978 : : static bool
979 : 23 : index_recheck_constraint(Relation index, const Oid *constr_procs,
980 : : const Datum *existing_values, const bool *existing_isnull,
981 : : const Datum *new_values)
982 : : {
983 : 23 : int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
984 : 23 : int i;
985 : :
986 [ + + ]: 57 : for (i = 0; i < indnkeyatts; i++)
987 : : {
988 : : /* Assume the exclusion operators are strict */
989 [ - + ]: 43 : if (existing_isnull[i])
990 : 0 : return false;
991 : :
992 [ + + + + ]: 86 : if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
993 : 43 : index->rd_indcollation[i],
994 : 43 : existing_values[i],
995 : 43 : new_values[i])))
996 : 9 : return false;
997 : 34 : }
998 : :
999 : 14 : return true;
1000 : 23 : }
1001 : :
1002 : : /*
1003 : : * Check if ExecInsertIndexTuples() should pass indexUnchanged hint.
1004 : : *
1005 : : * When the executor performs an UPDATE that requires a new round of index
1006 : : * tuples, determine if we should pass 'indexUnchanged' = true hint for one
1007 : : * single index.
1008 : : */
1009 : : static bool
1010 : 20804 : index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
1011 : : IndexInfo *indexInfo, Relation indexRelation)
1012 : : {
1013 : 20804 : Bitmapset *updatedCols;
1014 : 20804 : Bitmapset *extraUpdatedCols;
1015 : 20804 : Bitmapset *allUpdatedCols;
1016 : 20804 : bool hasexpression = false;
1017 : 20804 : List *idxExprs;
1018 : :
1019 : : /*
1020 : : * Check cache first
1021 : : */
1022 [ + + ]: 20804 : if (indexInfo->ii_CheckedUnchanged)
1023 : 20536 : return indexInfo->ii_IndexUnchanged;
1024 : 268 : indexInfo->ii_CheckedUnchanged = true;
1025 : :
1026 : : /*
1027 : : * Check for indexed attribute overlap with updated columns.
1028 : : *
1029 : : * Only do this for key columns. A change to a non-key column within an
1030 : : * INCLUDE index should not be counted here. Non-key column values are
1031 : : * opaque payload state to the index AM, a little like an extra table TID.
1032 : : *
1033 : : * Note that row-level BEFORE triggers won't affect our behavior, since
1034 : : * they don't affect the updatedCols bitmaps generally. It doesn't seem
1035 : : * worth the trouble of checking which attributes were changed directly.
1036 : : */
1037 : 268 : updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
1038 : 268 : extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
1039 [ + + + + ]: 611 : for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
1040 : : {
1041 : 343 : int keycol = indexInfo->ii_IndexAttrNumbers[attr];
1042 : :
1043 [ + + ]: 343 : if (keycol <= 0)
1044 : : {
1045 : : /*
1046 : : * Skip expressions for now, but remember to deal with them later
1047 : : * on
1048 : : */
1049 : 4 : hasexpression = true;
1050 : 4 : continue;
1051 : : }
1052 : :
1053 : 678 : if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
1054 [ + + + + : 678 : updatedCols) ||
- + ]
1055 : 268 : bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
1056 : 134 : extraUpdatedCols))
1057 : : {
1058 : : /* Changed key column -- don't hint for this index */
1059 : 205 : indexInfo->ii_IndexUnchanged = false;
1060 : 205 : return false;
1061 : : }
1062 [ + + + ]: 343 : }
1063 : :
1064 : : /*
1065 : : * When we get this far and index has no expressions, return true so that
1066 : : * index_insert() call will go on to pass 'indexUnchanged' = true hint.
1067 : : *
1068 : : * The _absence_ of an indexed key attribute that overlaps with updated
1069 : : * attributes (in addition to the total absence of indexed expressions)
1070 : : * shows that the index as a whole is logically unchanged by UPDATE.
1071 : : */
1072 [ + + ]: 63 : if (!hasexpression)
1073 : : {
1074 : 60 : indexInfo->ii_IndexUnchanged = true;
1075 : 60 : return true;
1076 : : }
1077 : :
1078 : : /*
1079 : : * Need to pass only one bms to expression_tree_walker helper function.
1080 : : * Avoid allocating memory in common case where there are no extra cols.
1081 : : */
1082 [ - + ]: 3 : if (!extraUpdatedCols)
1083 : 3 : allUpdatedCols = updatedCols;
1084 : : else
1085 : 0 : allUpdatedCols = bms_union(updatedCols, extraUpdatedCols);
1086 : :
1087 : : /*
1088 : : * We have to work slightly harder in the event of indexed expressions,
1089 : : * but the principle is the same as before: try to find columns (Vars,
1090 : : * actually) that overlap with known-updated columns.
1091 : : *
1092 : : * If we find any matching Vars, don't pass hint for index. Otherwise
1093 : : * pass hint.
1094 : : */
1095 : 3 : idxExprs = RelationGetIndexExpressions(indexRelation);
1096 : 6 : hasexpression = index_expression_changed_walker((Node *) idxExprs,
1097 : 3 : allUpdatedCols);
1098 : 3 : list_free(idxExprs);
1099 [ + - ]: 3 : if (extraUpdatedCols)
1100 : 0 : bms_free(allUpdatedCols);
1101 : :
1102 [ + + ]: 3 : if (hasexpression)
1103 : : {
1104 : 2 : indexInfo->ii_IndexUnchanged = false;
1105 : 2 : return false;
1106 : : }
1107 : :
1108 : : /*
1109 : : * Deliberately don't consider index predicates. We should even give the
1110 : : * hint when result rel's "updated tuple" has no corresponding index
1111 : : * tuple, which is possible with a partial index (provided the usual
1112 : : * conditions are met).
1113 : : */
1114 : 1 : indexInfo->ii_IndexUnchanged = true;
1115 : 1 : return true;
1116 : 20804 : }
1117 : :
1118 : : /*
1119 : : * Indexed expression helper for index_unchanged_by_update().
1120 : : *
1121 : : * Returns true when Var that appears within allUpdatedCols located.
1122 : : */
1123 : : static bool
1124 : 9 : index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols)
1125 : : {
1126 [ + - ]: 9 : if (node == NULL)
1127 : 0 : return false;
1128 : :
1129 [ + + ]: 9 : if (IsA(node, Var))
1130 : : {
1131 : 3 : Var *var = (Var *) node;
1132 : :
1133 [ + + + + ]: 6 : if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
1134 : 3 : allUpdatedCols))
1135 : : {
1136 : : /* Var was updated -- indicates that we should not hint */
1137 : 2 : return true;
1138 : : }
1139 : :
1140 : : /* Still haven't found a reason to not pass the hint */
1141 : 1 : return false;
1142 : 3 : }
1143 : :
1144 : 6 : return expression_tree_walker(node, index_expression_changed_walker,
1145 : : allUpdatedCols);
1146 : 9 : }
1147 : :
1148 : : /*
1149 : : * ExecWithoutOverlapsNotEmpty - raise an error if the tuple has an empty
1150 : : * range or multirange in the given attribute.
1151 : : */
1152 : : static void
1153 : 326 : ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval, char typtype, Oid atttypid)
1154 : : {
1155 : 326 : bool isempty;
1156 : 326 : RangeType *r;
1157 : 326 : MultirangeType *mr;
1158 : :
1159 [ + + - ]: 326 : switch (typtype)
1160 : : {
1161 : : case TYPTYPE_RANGE:
1162 : 172 : r = DatumGetRangeTypeP(attval);
1163 : 172 : isempty = RangeIsEmpty(r);
1164 : 172 : break;
1165 : : case TYPTYPE_MULTIRANGE:
1166 : 154 : mr = DatumGetMultirangeTypeP(attval);
1167 : 154 : isempty = MultirangeIsEmpty(mr);
1168 : 154 : break;
1169 : : default:
1170 [ # # # # ]: 0 : elog(ERROR, "WITHOUT OVERLAPS column \"%s\" is not a range or multirange",
1171 : : NameStr(attname));
1172 : 0 : }
1173 : :
1174 : : /* Report a CHECK_VIOLATION */
1175 [ + + ]: 326 : if (isempty)
1176 [ + - + - ]: 14 : ereport(ERROR,
1177 : : (errcode(ERRCODE_CHECK_VIOLATION),
1178 : : errmsg("empty WITHOUT OVERLAPS value found in column \"%s\" in relation \"%s\"",
1179 : : NameStr(attname), RelationGetRelationName(rel))));
1180 : 312 : }
|