LCOV - code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.4 % 285 269
Test Date: 2026-04-16 02:16:28 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            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.  The tuple is first inserted into the heap
      58              :  * and the indexes are updated as usual, but if a constraint is violated,
      59              :  * we can still back out of 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/lsyscache.h"
     119              : #include "utils/multirangetypes.h"
     120              : #include "utils/rangetypes.h"
     121              : #include "utils/snapmgr.h"
     122              : 
     123              : /* waitMode argument to check_exclusion_or_unique_constraint() */
     124              : typedef enum
     125              : {
     126              :     CEOUC_WAIT,
     127              :     CEOUC_NOWAIT,
     128              :     CEOUC_LIVELOCK_PREVENTING_WAIT,
     129              : } CEOUC_WAIT_MODE;
     130              : 
     131              : static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
     132              :                                                  IndexInfo *indexInfo,
     133              :                                                  const ItemPointerData *tupleid,
     134              :                                                  const Datum *values, const bool *isnull,
     135              :                                                  EState *estate, bool newIndex,
     136              :                                                  CEOUC_WAIT_MODE waitMode,
     137              :                                                  bool violationOK,
     138              :                                                  ItemPointer conflictTid);
     139              : 
     140              : static bool index_recheck_constraint(Relation index, const Oid *constr_procs,
     141              :                                      const Datum *existing_values, const bool *existing_isnull,
     142              :                                      const Datum *new_values);
     143              : static bool index_unchanged_by_update(ResultRelInfo *resultRelInfo,
     144              :                                       EState *estate, IndexInfo *indexInfo,
     145              :                                       Relation indexRelation);
     146              : static bool index_expression_changed_walker(Node *node,
     147              :                                             Bitmapset *allUpdatedCols);
     148              : static void ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval,
     149              :                                         char typtype, Oid atttypid);
     150              : 
     151              : /* ----------------------------------------------------------------
     152              :  *      ExecOpenIndices
     153              :  *
     154              :  *      Find the indices associated with a result relation, open them,
     155              :  *      and save information about them in the result ResultRelInfo.
     156              :  *
     157              :  *      At entry, caller has already opened and locked
     158              :  *      resultRelInfo->ri_RelationDesc.
     159              :  * ----------------------------------------------------------------
     160              :  */
     161              : void
     162      1191514 : ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
     163              : {
     164      1191514 :     Relation    resultRelation = resultRelInfo->ri_RelationDesc;
     165              :     List       *indexoidlist;
     166              :     ListCell   *l;
     167              :     int         len,
     168              :                 i;
     169              :     RelationPtr relationDescs;
     170              :     IndexInfo **indexInfoArray;
     171              : 
     172      1191514 :     resultRelInfo->ri_NumIndices = 0;
     173              : 
     174              :     /* fast path if no indexes */
     175      1191514 :     if (!RelationGetForm(resultRelation)->relhasindex)
     176        49912 :         return;
     177              : 
     178              :     /*
     179              :      * Get cached list of index OIDs
     180              :      */
     181      1141602 :     indexoidlist = RelationGetIndexList(resultRelation);
     182      1141602 :     len = list_length(indexoidlist);
     183      1141602 :     if (len == 0)
     184        20389 :         return;
     185              : 
     186              :     /* This Assert will fail if ExecOpenIndices is called twice */
     187              :     Assert(resultRelInfo->ri_IndexRelationDescs == NULL);
     188              : 
     189              :     /*
     190              :      * allocate space for result arrays
     191              :      */
     192      1121213 :     relationDescs = palloc_array(Relation, len);
     193      1121213 :     indexInfoArray = palloc_array(IndexInfo *, len);
     194              : 
     195      1121213 :     resultRelInfo->ri_NumIndices = len;
     196      1121213 :     resultRelInfo->ri_IndexRelationDescs = relationDescs;
     197      1121213 :     resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
     198              : 
     199              :     /*
     200              :      * For each index, open the index relation and save pg_index info. We
     201              :      * acquire RowExclusiveLock, signifying we will update the index.
     202              :      *
     203              :      * Note: we do this even if the index is not indisready; it's not worth
     204              :      * the trouble to optimize for the case where it isn't.
     205              :      */
     206      1121213 :     i = 0;
     207      3401221 :     foreach(l, indexoidlist)
     208              :     {
     209      2280008 :         Oid         indexOid = lfirst_oid(l);
     210              :         Relation    indexDesc;
     211              :         IndexInfo  *ii;
     212              : 
     213      2280008 :         indexDesc = index_open(indexOid, RowExclusiveLock);
     214              : 
     215              :         /* extract index key information from the index's pg_index info */
     216      2280008 :         ii = BuildIndexInfo(indexDesc);
     217              : 
     218              :         /*
     219              :          * If the indexes are to be used for speculative insertion, add extra
     220              :          * information required by unique index entries.
     221              :          */
     222      2280008 :         if (speculative && ii->ii_Unique && !indexDesc->rd_index->indisexclusion)
     223         1107 :             BuildSpeculativeIndexInfo(indexDesc, ii);
     224              : 
     225      2280008 :         relationDescs[i] = indexDesc;
     226      2280008 :         indexInfoArray[i] = ii;
     227      2280008 :         i++;
     228              :     }
     229              : 
     230      1121213 :     list_free(indexoidlist);
     231              : }
     232              : 
     233              : /* ----------------------------------------------------------------
     234              :  *      ExecCloseIndices
     235              :  *
     236              :  *      Close the index relations stored in resultRelInfo
     237              :  * ----------------------------------------------------------------
     238              :  */
     239              : void
     240      1244040 : ExecCloseIndices(ResultRelInfo *resultRelInfo)
     241              : {
     242              :     int         i;
     243              :     int         numIndices;
     244              :     RelationPtr indexDescs;
     245              :     IndexInfo **indexInfos;
     246              : 
     247      1244040 :     numIndices = resultRelInfo->ri_NumIndices;
     248      1244040 :     indexDescs = resultRelInfo->ri_IndexRelationDescs;
     249      1244040 :     indexInfos = resultRelInfo->ri_IndexRelationInfo;
     250              : 
     251      3522623 :     for (i = 0; i < numIndices; i++)
     252              :     {
     253              :         /* This Assert will fail if ExecCloseIndices is called twice */
     254              :         Assert(indexDescs[i] != NULL);
     255              : 
     256              :         /* Give the index a chance to do some post-insert cleanup */
     257      2278583 :         index_insert_cleanup(indexDescs[i], indexInfos[i]);
     258              : 
     259              :         /* Drop lock acquired by ExecOpenIndices */
     260      2278583 :         index_close(indexDescs[i], RowExclusiveLock);
     261              : 
     262              :         /* Mark the index as closed */
     263      2278583 :         indexDescs[i] = NULL;
     264              :     }
     265              : 
     266              :     /*
     267              :      * We don't attempt to free the IndexInfo data structures or the arrays,
     268              :      * instead assuming that such stuff will be cleaned up automatically in
     269              :      * FreeExecutorState.
     270              :      */
     271      1244040 : }
     272              : 
     273              : /* ----------------------------------------------------------------
     274              :  *      ExecInsertIndexTuples
     275              :  *
     276              :  *      This routine takes care of inserting index tuples
     277              :  *      into all the relations indexing the result relation
     278              :  *      when a heap tuple is inserted into the result relation.
     279              :  *
     280              :  *      When EIIT_IS_UPDATE is set and EIIT_ONLY_SUMMARIZING isn't,
     281              :  *      executor is performing an UPDATE that could not use an
     282              :  *      optimization like heapam's HOT (in more general terms a
     283              :  *      call to table_tuple_update() took place and set
     284              :  *      'update_indexes' to TU_All).  Receiving this hint makes
     285              :  *      us consider if we should pass down the 'indexUnchanged'
     286              :  *      hint in turn.  That's something that we figure out for
     287              :  *      each index_insert() call iff EIIT_IS_UPDATE is set.
     288              :  *      (When that flag is not set we already know not to pass the
     289              :  *      hint to any index.)
     290              :  *
     291              :  *      If EIIT_ONLY_SUMMARIZING is set, an equivalent optimization to
     292              :  *      HOT has been applied and any updated columns are indexed
     293              :  *      only by summarizing indexes (or in more general terms a
     294              :  *      call to table_tuple_update() took place and set
     295              :  *      'update_indexes' to TU_Summarizing). We can (and must)
     296              :  *      therefore only update the indexes that have
     297              :  *      'amsummarizing' = true.
     298              :  *
     299              :  *      Unique and exclusion constraints are enforced at the same
     300              :  *      time.  This returns a list of index OIDs for any unique or
     301              :  *      exclusion constraints that are deferred and that had
     302              :  *      potential (unconfirmed) conflicts.  (if EIIT_NO_DUPE_ERROR,
     303              :  *      the same is done for non-deferred constraints, but report
     304              :  *      if conflict was speculative or deferred conflict to caller)
     305              :  *
     306              :  *      If 'arbiterIndexes' is nonempty, EIIT_NO_DUPE_ERROR applies only to
     307              :  *      those indexes.  NIL means EIIT_NO_DUPE_ERROR applies to all indexes.
     308              :  * ----------------------------------------------------------------
     309              :  */
     310              : List *
     311      2674461 : ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
     312              :                       EState *estate,
     313              :                       uint32 flags,
     314              :                       TupleTableSlot *slot,
     315              :                       List *arbiterIndexes,
     316              :                       bool *specConflict)
     317              : {
     318      2674461 :     ItemPointer tupleid = &slot->tts_tid;
     319      2674461 :     List       *result = NIL;
     320              :     int         i;
     321              :     int         numIndices;
     322              :     RelationPtr relationDescs;
     323              :     Relation    heapRelation;
     324              :     IndexInfo **indexInfoArray;
     325              :     ExprContext *econtext;
     326              :     Datum       values[INDEX_MAX_KEYS];
     327              :     bool        isnull[INDEX_MAX_KEYS];
     328              : 
     329              :     Assert(ItemPointerIsValid(tupleid));
     330              : 
     331              :     /*
     332              :      * Get information from the result relation info structure.
     333              :      */
     334      2674461 :     numIndices = resultRelInfo->ri_NumIndices;
     335      2674461 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     336      2674461 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     337      2674461 :     heapRelation = resultRelInfo->ri_RelationDesc;
     338              : 
     339              :     /* Sanity check: slot must belong to the same rel as the resultRelInfo. */
     340              :     Assert(slot->tts_tableOid == RelationGetRelid(heapRelation));
     341              : 
     342              :     /*
     343              :      * We will use the EState's per-tuple context for evaluating predicates
     344              :      * and index expressions (creating it if it's not already there).
     345              :      */
     346      2674461 :     econtext = GetPerTupleExprContext(estate);
     347              : 
     348              :     /* Arrange for econtext's scan tuple to be the tuple under test */
     349      2674461 :     econtext->ecxt_scantuple = slot;
     350              : 
     351              :     /*
     352              :      * for each index, form and insert the index tuple
     353              :      */
     354      5648654 :     for (i = 0; i < numIndices; i++)
     355              :     {
     356      2974647 :         Relation    indexRelation = relationDescs[i];
     357              :         IndexInfo  *indexInfo;
     358              :         bool        applyNoDupErr;
     359              :         IndexUniqueCheck checkUnique;
     360              :         bool        indexUnchanged;
     361              :         bool        satisfiesConstraint;
     362              : 
     363      2974647 :         if (indexRelation == NULL)
     364            0 :             continue;
     365              : 
     366      2974647 :         indexInfo = indexInfoArray[i];
     367              : 
     368              :         /* If the index is marked as read-only, ignore it */
     369      2974647 :         if (!indexInfo->ii_ReadyForInserts)
     370           55 :             continue;
     371              : 
     372              :         /*
     373              :          * Skip processing of non-summarizing indexes if we only update
     374              :          * summarizing indexes
     375              :          */
     376      2974592 :         if ((flags & EIIT_ONLY_SUMMARIZING) && !indexInfo->ii_Summarizing)
     377            4 :             continue;
     378              : 
     379              :         /* Check for partial index */
     380      2974588 :         if (indexInfo->ii_Predicate != NIL)
     381              :         {
     382              :             ExprState  *predicate;
     383              : 
     384              :             /*
     385              :              * If predicate state not set up yet, create it (in the estate's
     386              :              * per-query context)
     387              :              */
     388       200570 :             predicate = indexInfo->ii_PredicateState;
     389       200570 :             if (predicate == NULL)
     390              :             {
     391          149 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     392          149 :                 indexInfo->ii_PredicateState = predicate;
     393              :             }
     394              : 
     395              :             /* Skip this index-update if the predicate isn't satisfied */
     396       200570 :             if (!ExecQual(predicate, econtext))
     397       200286 :                 continue;
     398              :         }
     399              : 
     400              :         /*
     401              :          * FormIndexDatum fills in its values and isnull parameters with the
     402              :          * appropriate values for the column(s) of the index.
     403              :          */
     404      2774302 :         FormIndexDatum(indexInfo,
     405              :                        slot,
     406              :                        estate,
     407              :                        values,
     408              :                        isnull);
     409              : 
     410              :         /* Check whether to apply noDupErr to this index */
     411      2872966 :         applyNoDupErr = (flags & EIIT_NO_DUPE_ERROR) &&
     412        98664 :             (arbiterIndexes == NIL ||
     413        98664 :              list_member_oid(arbiterIndexes,
     414        98664 :                              indexRelation->rd_index->indexrelid));
     415              : 
     416              :         /*
     417              :          * The index AM does the actual insertion, plus uniqueness checking.
     418              :          *
     419              :          * For an immediate-mode unique index, we just tell the index AM to
     420              :          * throw error if not unique.
     421              :          *
     422              :          * For a deferrable unique index, we tell the index AM to just detect
     423              :          * possible non-uniqueness, and we add the index OID to the result
     424              :          * list if further checking is needed.
     425              :          *
     426              :          * For a speculative insertion (used by INSERT ... ON CONFLICT), do
     427              :          * the same as for a deferrable unique index.
     428              :          */
     429      2774302 :         if (!indexRelation->rd_index->indisunique)
     430      1379669 :             checkUnique = UNIQUE_CHECK_NO;
     431      1394633 :         else if (applyNoDupErr)
     432        98712 :             checkUnique = UNIQUE_CHECK_PARTIAL;
     433      1295921 :         else if (indexRelation->rd_index->indimmediate)
     434      1295822 :             checkUnique = UNIQUE_CHECK_YES;
     435              :         else
     436           99 :             checkUnique = UNIQUE_CHECK_PARTIAL;
     437              : 
     438              :         /*
     439              :          * There's definitely going to be an index_insert() call for this
     440              :          * index.  If we're being called as part of an UPDATE statement,
     441              :          * consider if the 'indexUnchanged' = true hint should be passed.
     442              :          */
     443      3058306 :         indexUnchanged = ((flags & EIIT_IS_UPDATE) &&
     444       284004 :                           index_unchanged_by_update(resultRelInfo,
     445              :                                                     estate,
     446              :                                                     indexInfo,
     447              :                                                     indexRelation));
     448              : 
     449              :         satisfiesConstraint =
     450      2774302 :             index_insert(indexRelation, /* index relation */
     451              :                          values,    /* array of index Datums */
     452              :                          isnull,    /* null flags */
     453              :                          tupleid,   /* tid of heap tuple */
     454              :                          heapRelation,  /* heap relation */
     455              :                          checkUnique,   /* type of uniqueness check to do */
     456              :                          indexUnchanged,    /* UPDATE without logical change? */
     457              :                          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      2773979 :         if (indexInfo->ii_ExclusionOps != NULL)
     474              :         {
     475              :             bool        violationOK;
     476              :             CEOUC_WAIT_MODE waitMode;
     477              : 
     478         2892 :             if (applyNoDupErr)
     479              :             {
     480          108 :                 violationOK = true;
     481          108 :                 waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
     482              :             }
     483         2784 :             else if (!indexRelation->rd_index->indimmediate)
     484              :             {
     485           28 :                 violationOK = true;
     486           28 :                 waitMode = CEOUC_NOWAIT;
     487              :             }
     488              :             else
     489              :             {
     490         2756 :                 violationOK = false;
     491         2756 :                 waitMode = CEOUC_WAIT;
     492              :             }
     493              : 
     494              :             satisfiesConstraint =
     495         2892 :                 check_exclusion_or_unique_constraint(heapRelation,
     496              :                                                      indexRelation, indexInfo,
     497              :                                                      tupleid, values, isnull,
     498              :                                                      estate, false,
     499              :                                                      waitMode, violationOK, NULL);
     500              :         }
     501              : 
     502      2773848 :         if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
     503      2675037 :              indexInfo->ii_ExclusionOps != NULL) &&
     504       101464 :             !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          191 :             result = lappend_oid(result, RelationGetRelid(indexRelation));
     513          191 :             if (indexRelation->rd_index->indimmediate && specConflict)
     514          110 :                 *specConflict = true;
     515              :         }
     516              :     }
     517              : 
     518      2674007 :     return result;
     519              : }
     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         5398 : ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
     544              :                           EState *estate, ItemPointer conflictTid,
     545              :                           const ItemPointerData *tupleid, List *arbiterIndexes)
     546              : {
     547              :     int         i;
     548              :     int         numIndices;
     549              :     RelationPtr relationDescs;
     550              :     Relation    heapRelation;
     551              :     IndexInfo **indexInfoArray;
     552              :     ExprContext *econtext;
     553              :     Datum       values[INDEX_MAX_KEYS];
     554              :     bool        isnull[INDEX_MAX_KEYS];
     555              :     ItemPointerData invalidItemPtr;
     556         5398 :     bool        checkedIndex = false;
     557              : 
     558         5398 :     ItemPointerSetInvalid(conflictTid);
     559         5398 :     ItemPointerSetInvalid(&invalidItemPtr);
     560              : 
     561              :     /*
     562              :      * Get information from the result relation info structure.
     563              :      */
     564         5398 :     numIndices = resultRelInfo->ri_NumIndices;
     565         5398 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     566         5398 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     567         5398 :     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         5398 :     econtext = GetPerTupleExprContext(estate);
     574              : 
     575              :     /* Arrange for econtext's scan tuple to be the tuple under test */
     576         5398 :     econtext->ecxt_scantuple = slot;
     577              : 
     578              :     /*
     579              :      * For each index, form index tuple and check if it satisfies the
     580              :      * constraint.
     581              :      */
     582         7757 :     for (i = 0; i < numIndices; i++)
     583              :     {
     584         5525 :         Relation    indexRelation = relationDescs[i];
     585              :         IndexInfo  *indexInfo;
     586              :         bool        satisfiesConstraint;
     587              : 
     588         5525 :         if (indexRelation == NULL)
     589            0 :             continue;
     590              : 
     591         5525 :         indexInfo = indexInfoArray[i];
     592              : 
     593         5525 :         if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
     594            2 :             continue;
     595              : 
     596              :         /* If the index is marked as read-only, ignore it */
     597         5523 :         if (!indexInfo->ii_ReadyForInserts)
     598            0 :             continue;
     599              : 
     600              :         /* When specific arbiter indexes requested, only examine them */
     601         5523 :         if (arbiterIndexes != NIL &&
     602         5361 :             !list_member_oid(arbiterIndexes,
     603         5361 :                              indexRelation->rd_index->indexrelid))
     604           98 :             continue;
     605              : 
     606         5425 :         if (!indexRelation->rd_index->indimmediate)
     607            4 :             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         5421 :         checkedIndex = true;
     614              : 
     615              :         /* Check for partial index */
     616         5421 :         if (indexInfo->ii_Predicate != NIL)
     617              :         {
     618              :             ExprState  *predicate;
     619              : 
     620              :             /*
     621              :              * If predicate state not set up yet, create it (in the estate's
     622              :              * per-query context)
     623              :              */
     624           28 :             predicate = indexInfo->ii_PredicateState;
     625           28 :             if (predicate == NULL)
     626              :             {
     627           28 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     628           28 :                 indexInfo->ii_PredicateState = predicate;
     629              :             }
     630              : 
     631              :             /* Skip this index-update if the predicate isn't satisfied */
     632           28 :             if (!ExecQual(predicate, econtext))
     633            0 :                 continue;
     634              :         }
     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         5421 :         FormIndexDatum(indexInfo,
     641              :                        slot,
     642              :                        estate,
     643              :                        values,
     644              :                        isnull);
     645              : 
     646              :         satisfiesConstraint =
     647         5421 :             check_exclusion_or_unique_constraint(heapRelation, indexRelation,
     648              :                                                  indexInfo, tupleid,
     649              :                                                  values, isnull, estate, false,
     650              :                                                  CEOUC_WAIT, true,
     651              :                                                  conflictTid);
     652         5420 :         if (!satisfiesConstraint)
     653         3161 :             return false;
     654              :     }
     655              : 
     656         2232 :     if (arbiterIndexes != NIL && !checkedIndex)
     657            0 :         elog(ERROR, "unexpected failure to find arbiter index");
     658              : 
     659         2232 :     return true;
     660              : }
     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         8631 : 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              :     Oid        *constr_procs;
     715              :     uint16     *constr_strats;
     716         8631 :     Oid        *index_collations = index->rd_indcollation;
     717         8631 :     int         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
     718              :     IndexScanDesc index_scan;
     719              :     ScanKeyData scankeys[INDEX_MAX_KEYS];
     720              :     SnapshotData DirtySnapshot;
     721              :     int         i;
     722              :     bool        conflict;
     723              :     bool        found_self;
     724              :     ExprContext *econtext;
     725              :     TupleTableSlot *existing_slot;
     726              :     TupleTableSlot *save_scantuple;
     727              : 
     728         8631 :     if (indexInfo->ii_ExclusionOps)
     729              :     {
     730         3314 :         constr_procs = indexInfo->ii_ExclusionProcs;
     731         3314 :         constr_strats = indexInfo->ii_ExclusionStrats;
     732              :     }
     733              :     else
     734              :     {
     735         5317 :         constr_procs = indexInfo->ii_UniqueProcs;
     736         5317 :         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         8631 :     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         3049 :         AttrNumber  attno = indexInfo->ii_IndexAttrNumbers[indnkeyatts - 1];
     752              : 
     753         3049 :         if (!isnull[indnkeyatts - 1])
     754              :         {
     755         3009 :             TupleDesc   tupdesc = RelationGetDescr(heap);
     756         3009 :             Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
     757         3009 :             TypeCacheEntry *typcache = lookup_type_cache(att->atttypid,
     758              :                                                          TYPECACHE_DOMAIN_BASE_INFO);
     759              :             char        typtype;
     760              : 
     761         3009 :             if (OidIsValid(typcache->domainBaseType))
     762           16 :                 typtype = get_typtype(typcache->domainBaseType);
     763              :             else
     764         2993 :                 typtype = typcache->typtype;
     765              : 
     766         3009 :             ExecWithoutOverlapsNotEmpty(heap, att->attname,
     767         3009 :                                         values[indnkeyatts - 1],
     768              :                                         typtype, att->atttypid);
     769              :         }
     770              :     }
     771              : 
     772              :     /*
     773              :      * If any of the input values are NULL, and the index uses the default
     774              :      * nulls-are-distinct mode, the constraint check is assumed to pass (i.e.,
     775              :      * we assume the operators are strict).  Otherwise, we interpret the
     776              :      * constraint as specifying IS NULL for each column whose input value is
     777              :      * NULL.
     778              :      */
     779         8575 :     if (!indexInfo->ii_NullsNotDistinct)
     780              :     {
     781        20177 :         for (i = 0; i < indnkeyatts; i++)
     782              :         {
     783        11686 :             if (isnull[i])
     784           80 :                 return true;
     785              :         }
     786              :     }
     787              : 
     788              :     /*
     789              :      * Search the tuples that are in the index for any violations, including
     790              :      * tuples that aren't visible yet.
     791              :      */
     792         8495 :     InitDirtySnapshot(DirtySnapshot);
     793              : 
     794        20065 :     for (i = 0; i < indnkeyatts; i++)
     795              :     {
     796        11570 :         ScanKeyEntryInitialize(&scankeys[i],
     797        11570 :                                isnull[i] ? SK_ISNULL | SK_SEARCHNULL : 0,
     798        11570 :                                i + 1,
     799        11570 :                                constr_strats[i],
     800              :                                InvalidOid,
     801        11570 :                                index_collations[i],
     802        11570 :                                constr_procs[i],
     803        11570 :                                values[i]);
     804              :     }
     805              : 
     806              :     /*
     807              :      * Need a TupleTableSlot to put existing tuples in.
     808              :      *
     809              :      * To use FormIndexDatum, we have to make the econtext's scantuple point
     810              :      * to this slot.  Be sure to save and restore caller's value for
     811              :      * scantuple.
     812              :      */
     813         8495 :     existing_slot = table_slot_create(heap, NULL);
     814              : 
     815         8495 :     econtext = GetPerTupleExprContext(estate);
     816         8495 :     save_scantuple = econtext->ecxt_scantuple;
     817         8495 :     econtext->ecxt_scantuple = existing_slot;
     818              : 
     819              :     /*
     820              :      * May have to restart scan from this point if a potential conflict is
     821              :      * found.
     822              :      */
     823         8532 : retry:
     824         8532 :     conflict = false;
     825         8532 :     found_self = false;
     826         8532 :     index_scan = index_beginscan(heap, index,
     827              :                                  &DirtySnapshot, NULL, indnkeyatts, 0,
     828              :                                  SO_NONE);
     829         8532 :     index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
     830              : 
     831        11514 :     while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
     832              :     {
     833              :         TransactionId xwait;
     834              :         XLTW_Oper   reason_wait;
     835              :         Datum       existing_values[INDEX_MAX_KEYS];
     836              :         bool        existing_isnull[INDEX_MAX_KEYS];
     837              :         char       *error_new;
     838              :         char       *error_existing;
     839              : 
     840              :         /*
     841              :          * Ignore the entry for the tuple we're trying to check.
     842              :          */
     843         9542 :         if (ItemPointerIsValid(tupleid) &&
     844         3218 :             ItemPointerEquals(tupleid, &existing_slot->tts_tid))
     845              :         {
     846         2946 :             if (found_self)     /* should not happen */
     847            0 :                 elog(ERROR, "found self tuple multiple times in index \"%s\"",
     848              :                      RelationGetRelationName(index));
     849         2946 :             found_self = true;
     850         2982 :             continue;
     851              :         }
     852              : 
     853              :         /*
     854              :          * Extract the index column values and isnull flags from the existing
     855              :          * tuple.
     856              :          */
     857         3378 :         FormIndexDatum(indexInfo, existing_slot, estate,
     858              :                        existing_values, existing_isnull);
     859              : 
     860              :         /* If lossy indexscan, must recheck the condition */
     861         3378 :         if (index_scan->xs_recheck)
     862              :         {
     863           92 :             if (!index_recheck_constraint(index,
     864              :                                           constr_procs,
     865              :                                           existing_values,
     866              :                                           existing_isnull,
     867              :                                           values))
     868           36 :                 continue;       /* tuple doesn't actually match, so no
     869              :                                  * conflict */
     870              :         }
     871              : 
     872              :         /*
     873              :          * At this point we have either a conflict or a potential conflict.
     874              :          *
     875              :          * If an in-progress transaction is affecting the visibility of this
     876              :          * tuple, we need to wait for it to complete and then recheck (unless
     877              :          * the caller requested not to).  For simplicity we do rechecking by
     878              :          * just restarting the whole scan --- this case probably doesn't
     879              :          * happen often enough to be worth trying harder, and anyway we don't
     880              :          * want to hold any index internal locks while waiting.
     881              :          */
     882         6684 :         xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
     883         3342 :             DirtySnapshot.xmin : DirtySnapshot.xmax;
     884              : 
     885         3342 :         if (TransactionIdIsValid(xwait) &&
     886            0 :             (waitMode == CEOUC_WAIT ||
     887            0 :              (waitMode == CEOUC_LIVELOCK_PREVENTING_WAIT &&
     888            0 :               DirtySnapshot.speculativeToken &&
     889            0 :               TransactionIdPrecedes(GetCurrentTransactionId(), xwait))))
     890              :         {
     891           76 :             reason_wait = indexInfo->ii_ExclusionOps ?
     892           38 :                 XLTW_RecheckExclusionConstr : XLTW_InsertIndex;
     893           38 :             index_endscan(index_scan);
     894           38 :             if (DirtySnapshot.speculativeToken)
     895            1 :                 SpeculativeInsertionWait(DirtySnapshot.xmin,
     896              :                                          DirtySnapshot.speculativeToken);
     897              :             else
     898           37 :                 XactLockTableWait(xwait, heap,
     899           37 :                                   &existing_slot->tts_tid, reason_wait);
     900           37 :             goto retry;
     901              :         }
     902              : 
     903              :         /*
     904              :          * We have a definite conflict (or a potential one, but the caller
     905              :          * didn't want to wait).  Return it to caller, or report it.
     906              :          */
     907         3304 :         if (violationOK)
     908              :         {
     909         3177 :             conflict = true;
     910         3177 :             if (conflictTid)
     911         3161 :                 *conflictTid = existing_slot->tts_tid;
     912         3177 :             break;
     913              :         }
     914              : 
     915          127 :         error_new = BuildIndexValueDescription(index, values, isnull);
     916          127 :         error_existing = BuildIndexValueDescription(index, existing_values,
     917              :                                                     existing_isnull);
     918          127 :         if (newIndex)
     919           24 :             ereport(ERROR,
     920              :                     (errcode(ERRCODE_EXCLUSION_VIOLATION),
     921              :                      errmsg("could not create exclusion constraint \"%s\"",
     922              :                             RelationGetRelationName(index)),
     923              :                      error_new && error_existing ?
     924              :                      errdetail("Key %s conflicts with key %s.",
     925              :                                error_new, error_existing) :
     926              :                      errdetail("Key conflicts exist."),
     927              :                      errtableconstraint(heap,
     928              :                                         RelationGetRelationName(index))));
     929              :         else
     930          103 :             ereport(ERROR,
     931              :                     (errcode(ERRCODE_EXCLUSION_VIOLATION),
     932              :                      errmsg("conflicting key value violates exclusion constraint \"%s\"",
     933              :                             RelationGetRelationName(index)),
     934              :                      error_new && error_existing ?
     935              :                      errdetail("Key %s conflicts with existing key %s.",
     936              :                                error_new, error_existing) :
     937              :                      errdetail("Key conflicts with existing key."),
     938              :                      errtableconstraint(heap,
     939              :                                         RelationGetRelationName(index))));
     940              :     }
     941              : 
     942         8367 :     index_endscan(index_scan);
     943              : 
     944              :     /*
     945              :      * Ordinarily, at this point the search should have found the originally
     946              :      * inserted tuple (if any), unless we exited the loop early because of
     947              :      * conflict.  However, it is possible to define exclusion constraints for
     948              :      * which that wouldn't be true --- for instance, if the operator is <>. So
     949              :      * we no longer complain if found_self is still false.
     950              :      */
     951              : 
     952         8367 :     econtext->ecxt_scantuple = save_scantuple;
     953              : 
     954         8367 :     ExecDropSingleTupleTableSlot(existing_slot);
     955              : 
     956              : #ifdef USE_INJECTION_POINTS
     957         8367 :     if (!conflict)
     958         5190 :         INJECTION_POINT("check-exclusion-or-unique-constraint-no-conflict", NULL);
     959              : #endif
     960              : 
     961         8367 :     return !conflict;
     962              : }
     963              : 
     964              : /*
     965              :  * Check for violation of an exclusion constraint
     966              :  *
     967              :  * This is a dumbed down version of check_exclusion_or_unique_constraint
     968              :  * for external callers. They don't need all the special modes.
     969              :  */
     970              : void
     971          318 : check_exclusion_constraint(Relation heap, Relation index,
     972              :                            IndexInfo *indexInfo,
     973              :                            const ItemPointerData *tupleid,
     974              :                            const Datum *values, const bool *isnull,
     975              :                            EState *estate, bool newIndex)
     976              : {
     977          318 :     (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
     978              :                                                 values, isnull,
     979              :                                                 estate, newIndex,
     980              :                                                 CEOUC_WAIT, false, NULL);
     981          266 : }
     982              : 
     983              : /*
     984              :  * Check existing tuple's index values to see if it really matches the
     985              :  * exclusion condition against the new_values.  Returns true if conflict.
     986              :  */
     987              : static bool
     988           92 : index_recheck_constraint(Relation index, const Oid *constr_procs,
     989              :                          const Datum *existing_values, const bool *existing_isnull,
     990              :                          const Datum *new_values)
     991              : {
     992           92 :     int         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
     993              :     int         i;
     994              : 
     995          228 :     for (i = 0; i < indnkeyatts; i++)
     996              :     {
     997              :         /* Assume the exclusion operators are strict */
     998          172 :         if (existing_isnull[i])
     999            0 :             return false;
    1000              : 
    1001          172 :         if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
    1002          172 :                                                index->rd_indcollation[i],
    1003          172 :                                                existing_values[i],
    1004          172 :                                                new_values[i])))
    1005           36 :             return false;
    1006              :     }
    1007              : 
    1008           56 :     return true;
    1009              : }
    1010              : 
    1011              : /*
    1012              :  * Check if ExecInsertIndexTuples() should pass indexUnchanged hint.
    1013              :  *
    1014              :  * When the executor performs an UPDATE that requires a new round of index
    1015              :  * tuples, determine if we should pass 'indexUnchanged' = true hint for one
    1016              :  * single index.
    1017              :  */
    1018              : static bool
    1019       284004 : index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
    1020              :                           IndexInfo *indexInfo, Relation indexRelation)
    1021              : {
    1022              :     Bitmapset  *updatedCols;
    1023              :     Bitmapset  *extraUpdatedCols;
    1024              :     Bitmapset  *allUpdatedCols;
    1025       284004 :     bool        hasexpression = false;
    1026              :     List       *idxExprs;
    1027              : 
    1028              :     /*
    1029              :      * Check cache first
    1030              :      */
    1031       284004 :     if (indexInfo->ii_CheckedUnchanged)
    1032       261520 :         return indexInfo->ii_IndexUnchanged;
    1033        22484 :     indexInfo->ii_CheckedUnchanged = true;
    1034              : 
    1035              :     /*
    1036              :      * Check for indexed attribute overlap with updated columns.
    1037              :      *
    1038              :      * Only do this for key columns.  A change to a non-key column within an
    1039              :      * INCLUDE index should not be counted here.  Non-key column values are
    1040              :      * opaque payload state to the index AM, a little like an extra table TID.
    1041              :      *
    1042              :      * Note that row-level BEFORE triggers won't affect our behavior, since
    1043              :      * they don't affect the updatedCols bitmaps generally.  It doesn't seem
    1044              :      * worth the trouble of checking which attributes were changed directly.
    1045              :      */
    1046        22484 :     updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
    1047        22484 :     extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
    1048        24853 :     for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
    1049              :     {
    1050        23560 :         int         keycol = indexInfo->ii_IndexAttrNumbers[attr];
    1051              : 
    1052        23560 :         if (keycol <= 0)
    1053              :         {
    1054              :             /*
    1055              :              * Skip expressions for now, but remember to deal with them later
    1056              :              * on
    1057              :              */
    1058           19 :             hasexpression = true;
    1059           19 :             continue;
    1060              :         }
    1061              : 
    1062        23541 :         if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1063         2350 :                           updatedCols) ||
    1064         2350 :             bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1065              :                           extraUpdatedCols))
    1066              :         {
    1067              :             /* Changed key column -- don't hint for this index */
    1068        21191 :             indexInfo->ii_IndexUnchanged = false;
    1069        21191 :             return false;
    1070              :         }
    1071              :     }
    1072              : 
    1073              :     /*
    1074              :      * When we get this far and index has no expressions, return true so that
    1075              :      * index_insert() call will go on to pass 'indexUnchanged' = true hint.
    1076              :      *
    1077              :      * The _absence_ of an indexed key attribute that overlaps with updated
    1078              :      * attributes (in addition to the total absence of indexed expressions)
    1079              :      * shows that the index as a whole is logically unchanged by UPDATE.
    1080              :      */
    1081         1293 :     if (!hasexpression)
    1082              :     {
    1083         1278 :         indexInfo->ii_IndexUnchanged = true;
    1084         1278 :         return true;
    1085              :     }
    1086              : 
    1087              :     /*
    1088              :      * Need to pass only one bms to expression_tree_walker helper function.
    1089              :      * Avoid allocating memory in common case where there are no extra cols.
    1090              :      */
    1091           15 :     if (!extraUpdatedCols)
    1092           15 :         allUpdatedCols = updatedCols;
    1093              :     else
    1094            0 :         allUpdatedCols = bms_union(updatedCols, extraUpdatedCols);
    1095              : 
    1096              :     /*
    1097              :      * We have to work slightly harder in the event of indexed expressions,
    1098              :      * but the principle is the same as before: try to find columns (Vars,
    1099              :      * actually) that overlap with known-updated columns.
    1100              :      *
    1101              :      * If we find any matching Vars, don't pass hint for index.  Otherwise
    1102              :      * pass hint.
    1103              :      */
    1104           15 :     idxExprs = RelationGetIndexExpressions(indexRelation);
    1105           15 :     hasexpression = index_expression_changed_walker((Node *) idxExprs,
    1106              :                                                     allUpdatedCols);
    1107           15 :     list_free(idxExprs);
    1108           15 :     if (extraUpdatedCols)
    1109            0 :         bms_free(allUpdatedCols);
    1110              : 
    1111           15 :     if (hasexpression)
    1112              :     {
    1113           11 :         indexInfo->ii_IndexUnchanged = false;
    1114           11 :         return false;
    1115              :     }
    1116              : 
    1117              :     /*
    1118              :      * Deliberately don't consider index predicates.  We should even give the
    1119              :      * hint when result rel's "updated tuple" has no corresponding index
    1120              :      * tuple, which is possible with a partial index (provided the usual
    1121              :      * conditions are met).
    1122              :      */
    1123            4 :     indexInfo->ii_IndexUnchanged = true;
    1124            4 :     return true;
    1125              : }
    1126              : 
    1127              : /*
    1128              :  * Indexed expression helper for index_unchanged_by_update().
    1129              :  *
    1130              :  * Returns true when Var that appears within allUpdatedCols located.
    1131              :  */
    1132              : static bool
    1133           47 : index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols)
    1134              : {
    1135           47 :     if (node == NULL)
    1136            0 :         return false;
    1137              : 
    1138           47 :     if (IsA(node, Var))
    1139              :     {
    1140           15 :         Var        *var = (Var *) node;
    1141              : 
    1142           15 :         if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
    1143              :                           allUpdatedCols))
    1144              :         {
    1145              :             /* Var was updated -- indicates that we should not hint */
    1146           11 :             return true;
    1147              :         }
    1148              : 
    1149              :         /* Still haven't found a reason to not pass the hint */
    1150            4 :         return false;
    1151              :     }
    1152              : 
    1153           32 :     return expression_tree_walker(node, index_expression_changed_walker,
    1154              :                                   allUpdatedCols);
    1155              : }
    1156              : 
    1157              : /*
    1158              :  * ExecWithoutOverlapsNotEmpty - raise an error if the tuple has an empty
    1159              :  * range or multirange in the given attribute.
    1160              :  */
    1161              : static void
    1162         3009 : ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval, char typtype, Oid atttypid)
    1163              : {
    1164              :     bool        isempty;
    1165              :     RangeType  *r;
    1166              :     MultirangeType *mr;
    1167              : 
    1168         3009 :     switch (typtype)
    1169              :     {
    1170         2321 :         case TYPTYPE_RANGE:
    1171         2321 :             r = DatumGetRangeTypeP(attval);
    1172         2321 :             isempty = RangeIsEmpty(r);
    1173         2321 :             break;
    1174          688 :         case TYPTYPE_MULTIRANGE:
    1175          688 :             mr = DatumGetMultirangeTypeP(attval);
    1176          688 :             isempty = MultirangeIsEmpty(mr);
    1177          688 :             break;
    1178            0 :         default:
    1179            0 :             elog(ERROR, "WITHOUT OVERLAPS column \"%s\" is not a range or multirange",
    1180              :                  NameStr(attname));
    1181              :     }
    1182              : 
    1183              :     /* Report a CHECK_VIOLATION */
    1184         3009 :     if (isempty)
    1185           56 :         ereport(ERROR,
    1186              :                 (errcode(ERRCODE_CHECK_VIOLATION),
    1187              :                  errmsg("empty WITHOUT OVERLAPS value found in column \"%s\" in relation \"%s\"",
    1188              :                         NameStr(attname), RelationGetRelationName(rel))));
    1189         2953 : }
        

Generated by: LCOV version 2.0-1