LCOV - code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 266 282 94.3 %
Date: 2025-12-13 03:17:34 Functions: 10 10 100.0 %
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 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-2025, 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     1866890 : ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
     162             : {
     163     1866890 :     Relation    resultRelation = resultRelInfo->ri_RelationDesc;
     164             :     List       *indexoidlist;
     165             :     ListCell   *l;
     166             :     int         len,
     167             :                 i;
     168             :     RelationPtr relationDescs;
     169             :     IndexInfo **indexInfoArray;
     170             : 
     171     1866890 :     resultRelInfo->ri_NumIndices = 0;
     172             : 
     173             :     /* fast path if no indexes */
     174     1866890 :     if (!RelationGetForm(resultRelation)->relhasindex)
     175       82562 :         return;
     176             : 
     177             :     /*
     178             :      * Get cached list of index OIDs
     179             :      */
     180     1784328 :     indexoidlist = RelationGetIndexList(resultRelation);
     181     1784328 :     len = list_length(indexoidlist);
     182     1784328 :     if (len == 0)
     183       40592 :         return;
     184             : 
     185             :     /* This Assert will fail if ExecOpenIndices is called twice */
     186             :     Assert(resultRelInfo->ri_IndexRelationDescs == NULL);
     187             : 
     188             :     /*
     189             :      * allocate space for result arrays
     190             :      */
     191     1743736 :     relationDescs = palloc_array(Relation, len);
     192     1743736 :     indexInfoArray = palloc_array(IndexInfo *, len);
     193             : 
     194     1743736 :     resultRelInfo->ri_NumIndices = len;
     195     1743736 :     resultRelInfo->ri_IndexRelationDescs = relationDescs;
     196     1743736 :     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     1743736 :     i = 0;
     206     5242716 :     foreach(l, indexoidlist)
     207             :     {
     208     3498980 :         Oid         indexOid = lfirst_oid(l);
     209             :         Relation    indexDesc;
     210             :         IndexInfo  *ii;
     211             : 
     212     3498980 :         indexDesc = index_open(indexOid, RowExclusiveLock);
     213             : 
     214             :         /* extract index key information from the index's pg_index info */
     215     3498980 :         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     3498980 :         if (speculative && ii->ii_Unique && !indexDesc->rd_index->indisexclusion)
     222        1364 :             BuildSpeculativeIndexInfo(indexDesc, ii);
     223             : 
     224     3498980 :         relationDescs[i] = indexDesc;
     225     3498980 :         indexInfoArray[i] = ii;
     226     3498980 :         i++;
     227             :     }
     228             : 
     229     1743736 :     list_free(indexoidlist);
     230             : }
     231             : 
     232             : /* ----------------------------------------------------------------
     233             :  *      ExecCloseIndices
     234             :  *
     235             :  *      Close the index relations stored in resultRelInfo
     236             :  * ----------------------------------------------------------------
     237             :  */
     238             : void
     239     1946580 : ExecCloseIndices(ResultRelInfo *resultRelInfo)
     240             : {
     241             :     int         i;
     242             :     int         numIndices;
     243             :     RelationPtr indexDescs;
     244             :     IndexInfo **indexInfos;
     245             : 
     246     1946580 :     numIndices = resultRelInfo->ri_NumIndices;
     247     1946580 :     indexDescs = resultRelInfo->ri_IndexRelationDescs;
     248     1946580 :     indexInfos = resultRelInfo->ri_IndexRelationInfo;
     249             : 
     250     5443492 :     for (i = 0; i < numIndices; i++)
     251             :     {
     252             :         /* This Assert will fail if ExecCloseIndices is called twice */
     253             :         Assert(indexDescs[i] != NULL);
     254             : 
     255             :         /* Give the index a chance to do some post-insert cleanup */
     256     3496912 :         index_insert_cleanup(indexDescs[i], indexInfos[i]);
     257             : 
     258             :         /* Drop lock acquired by ExecOpenIndices */
     259     3496912 :         index_close(indexDescs[i], RowExclusiveLock);
     260             : 
     261             :         /* Mark the index as closed */
     262     3496912 :         indexDescs[i] = NULL;
     263             :     }
     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     1946580 : }
     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     3631300 : 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     3631300 :     ItemPointer tupleid = &slot->tts_tid;
     320     3631300 :     List       *result = NIL;
     321             :     int         i;
     322             :     int         numIndices;
     323             :     RelationPtr relationDescs;
     324             :     Relation    heapRelation;
     325             :     IndexInfo **indexInfoArray;
     326             :     ExprContext *econtext;
     327             :     Datum       values[INDEX_MAX_KEYS];
     328             :     bool        isnull[INDEX_MAX_KEYS];
     329             : 
     330             :     Assert(ItemPointerIsValid(tupleid));
     331             : 
     332             :     /*
     333             :      * Get information from the result relation info structure.
     334             :      */
     335     3631300 :     numIndices = resultRelInfo->ri_NumIndices;
     336     3631300 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     337     3631300 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     338     3631300 :     heapRelation = resultRelInfo->ri_RelationDesc;
     339             : 
     340             :     /* Sanity check: slot must belong to the same rel as the resultRelInfo. */
     341             :     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     3631300 :     econtext = GetPerTupleExprContext(estate);
     348             : 
     349             :     /* Arrange for econtext's scan tuple to be the tuple under test */
     350     3631300 :     econtext->ecxt_scantuple = slot;
     351             : 
     352             :     /*
     353             :      * for each index, form and insert the index tuple
     354             :      */
     355     7631696 :     for (i = 0; i < numIndices; i++)
     356             :     {
     357     4001116 :         Relation    indexRelation = relationDescs[i];
     358             :         IndexInfo  *indexInfo;
     359             :         bool        applyNoDupErr;
     360             :         IndexUniqueCheck checkUnique;
     361             :         bool        indexUnchanged;
     362             :         bool        satisfiesConstraint;
     363             : 
     364     4001116 :         if (indexRelation == NULL)
     365           0 :             continue;
     366             : 
     367     4001116 :         indexInfo = indexInfoArray[i];
     368             : 
     369             :         /* If the index is marked as read-only, ignore it */
     370     4001116 :         if (!indexInfo->ii_ReadyForInserts)
     371         162 :             continue;
     372             : 
     373             :         /*
     374             :          * Skip processing of non-summarizing indexes if we only update
     375             :          * summarizing indexes
     376             :          */
     377     4000954 :         if (onlySummarizing && !indexInfo->ii_Summarizing)
     378           6 :             continue;
     379             : 
     380             :         /* Check for partial index */
     381     4000948 :         if (indexInfo->ii_Predicate != NIL)
     382             :         {
     383             :             ExprState  *predicate;
     384             : 
     385             :             /*
     386             :              * If predicate state not set up yet, create it (in the estate's
     387             :              * per-query context)
     388             :              */
     389      401106 :             predicate = indexInfo->ii_PredicateState;
     390      401106 :             if (predicate == NULL)
     391             :             {
     392         272 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     393         272 :                 indexInfo->ii_PredicateState = predicate;
     394             :             }
     395             : 
     396             :             /* Skip this index-update if the predicate isn't satisfied */
     397      401106 :             if (!ExecQual(predicate, econtext))
     398      400560 :                 continue;
     399             :         }
     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     3600388 :         FormIndexDatum(indexInfo,
     406             :                        slot,
     407             :                        estate,
     408             :                        values,
     409             :                        isnull);
     410             : 
     411             :         /* Check whether to apply noDupErr to this index */
     412     3756814 :         applyNoDupErr = noDupErr &&
     413      156426 :             (arbiterIndexes == NIL ||
     414      156426 :              list_member_oid(arbiterIndexes,
     415      156426 :                              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     3600388 :         if (!indexRelation->rd_index->indisunique)
     431     1915436 :             checkUnique = UNIQUE_CHECK_NO;
     432     1684952 :         else if (applyNoDupErr)
     433      156502 :             checkUnique = UNIQUE_CHECK_PARTIAL;
     434     1528450 :         else if (indexRelation->rd_index->indimmediate)
     435     1528300 :             checkUnique = UNIQUE_CHECK_YES;
     436             :         else
     437         150 :             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     3600388 :         indexUnchanged = update && index_unchanged_by_update(resultRelInfo,
     445             :                                                              estate,
     446             :                                                              indexInfo,
     447             :                                                              indexRelation);
     448             : 
     449             :         satisfiesConstraint =
     450     3600388 :             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     3599842 :         if (indexInfo->ii_ExclusionOps != NULL)
     474             :         {
     475             :             bool        violationOK;
     476             :             CEOUC_WAIT_MODE waitMode;
     477             : 
     478        1994 :             if (applyNoDupErr)
     479             :             {
     480         144 :                 violationOK = true;
     481         144 :                 waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
     482             :             }
     483        1850 :             else if (!indexRelation->rd_index->indimmediate)
     484             :             {
     485          42 :                 violationOK = true;
     486          42 :                 waitMode = CEOUC_NOWAIT;
     487             :             }
     488             :             else
     489             :             {
     490        1808 :                 violationOK = false;
     491        1808 :                 waitMode = CEOUC_WAIT;
     492             :             }
     493             : 
     494             :             satisfiesConstraint =
     495        1994 :                 check_exclusion_or_unique_constraint(heapRelation,
     496             :                                                      indexRelation, indexInfo,
     497             :                                                      tupleid, values, isnull,
     498             :                                                      estate, false,
     499             :                                                      waitMode, violationOK, NULL);
     500             :         }
     501             : 
     502     3599668 :         if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
     503     3443016 :              indexInfo->ii_ExclusionOps != NULL) &&
     504      158328 :             !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         288 :             result = lappend_oid(result, RelationGetRelid(indexRelation));
     513         288 :             if (indexRelation->rd_index->indimmediate && specConflict)
     514         166 :                 *specConflict = true;
     515             :         }
     516             :     }
     517             : 
     518     3630580 :     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        9798 : 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        9798 :     bool        checkedIndex = false;
     557             : 
     558        9798 :     ItemPointerSetInvalid(conflictTid);
     559        9798 :     ItemPointerSetInvalid(&invalidItemPtr);
     560             : 
     561             :     /*
     562             :      * Get information from the result relation info structure.
     563             :      */
     564        9798 :     numIndices = resultRelInfo->ri_NumIndices;
     565        9798 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     566        9798 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     567        9798 :     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        9798 :     econtext = GetPerTupleExprContext(estate);
     574             : 
     575             :     /* Arrange for econtext's scan tuple to be the tuple under test */
     576        9798 :     econtext->ecxt_scantuple = slot;
     577             : 
     578             :     /*
     579             :      * For each index, form index tuple and check if it satisfies the
     580             :      * constraint.
     581             :      */
     582       14196 :     for (i = 0; i < numIndices; i++)
     583             :     {
     584        9996 :         Relation    indexRelation = relationDescs[i];
     585             :         IndexInfo  *indexInfo;
     586             :         bool        satisfiesConstraint;
     587             : 
     588        9996 :         if (indexRelation == NULL)
     589           0 :             continue;
     590             : 
     591        9996 :         indexInfo = indexInfoArray[i];
     592             : 
     593        9996 :         if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
     594           4 :             continue;
     595             : 
     596             :         /* If the index is marked as read-only, ignore it */
     597        9992 :         if (!indexInfo->ii_ReadyForInserts)
     598           0 :             continue;
     599             : 
     600             :         /* When specific arbiter indexes requested, only examine them */
     601        9992 :         if (arbiterIndexes != NIL &&
     602        9722 :             !list_member_oid(arbiterIndexes,
     603        9722 :                              indexRelation->rd_index->indexrelid))
     604         144 :             continue;
     605             : 
     606        9848 :         if (!indexRelation->rd_index->indimmediate)
     607           6 :             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        9842 :         checkedIndex = true;
     614             : 
     615             :         /* Check for partial index */
     616        9842 :         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          44 :             predicate = indexInfo->ii_PredicateState;
     625          44 :             if (predicate == NULL)
     626             :             {
     627          44 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     628          44 :                 indexInfo->ii_PredicateState = predicate;
     629             :             }
     630             : 
     631             :             /* Skip this index-update if the predicate isn't satisfied */
     632          44 :             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        9842 :         FormIndexDatum(indexInfo,
     641             :                        slot,
     642             :                        estate,
     643             :                        values,
     644             :                        isnull);
     645             : 
     646             :         satisfiesConstraint =
     647        9842 :             check_exclusion_or_unique_constraint(heapRelation, indexRelation,
     648             :                                                  indexInfo, tupleid,
     649             :                                                  values, isnull, estate, false,
     650             :                                                  CEOUC_WAIT, true,
     651             :                                                  conflictTid);
     652        9840 :         if (!satisfiesConstraint)
     653        5590 :             return false;
     654             :     }
     655             : 
     656        4200 :     if (arbiterIndexes != NIL && !checkedIndex)
     657           0 :         elog(ERROR, "unexpected failure to find arbiter index");
     658             : 
     659        4200 :     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       12314 : 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       12314 :     Oid        *index_collations = index->rd_indcollation;
     717       12314 :     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       12314 :     if (indexInfo->ii_ExclusionOps)
     729             :     {
     730        2628 :         constr_procs = indexInfo->ii_ExclusionProcs;
     731        2628 :         constr_strats = indexInfo->ii_ExclusionStrats;
     732             :     }
     733             :     else
     734             :     {
     735        9686 :         constr_procs = indexInfo->ii_UniqueProcs;
     736        9686 :         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       12314 :     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        2222 :         AttrNumber  attno = indexInfo->ii_IndexAttrNumbers[indnkeyatts - 1];
     752             : 
     753        2222 :         if (!isnull[indnkeyatts - 1])
     754             :         {
     755        2162 :             TupleDesc   tupdesc = RelationGetDescr(heap);
     756        2162 :             Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
     757        2162 :             TypeCacheEntry *typcache = lookup_type_cache(att->atttypid, 0);
     758             : 
     759        2162 :             ExecWithoutOverlapsNotEmpty(heap, att->attname,
     760        2162 :                                         values[indnkeyatts - 1],
     761        2162 :                                         typcache->typtype, att->atttypid);
     762             :         }
     763             :     }
     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       12230 :     if (!indexInfo->ii_NullsNotDistinct)
     773             :     {
     774       26648 :         for (i = 0; i < indnkeyatts; i++)
     775             :         {
     776       14544 :             if (isnull[i])
     777         120 :                 return true;
     778             :         }
     779             :     }
     780             : 
     781             :     /*
     782             :      * Search the tuples that are in the index for any violations, including
     783             :      * tuples that aren't visible yet.
     784             :      */
     785       12110 :     InitDirtySnapshot(DirtySnapshot);
     786             : 
     787       26480 :     for (i = 0; i < indnkeyatts; i++)
     788             :     {
     789       14370 :         ScanKeyEntryInitialize(&scankeys[i],
     790       14370 :                                isnull[i] ? SK_ISNULL | SK_SEARCHNULL : 0,
     791       14370 :                                i + 1,
     792       14370 :                                constr_strats[i],
     793             :                                InvalidOid,
     794       14370 :                                index_collations[i],
     795       14370 :                                constr_procs[i],
     796       14370 :                                values[i]);
     797             :     }
     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       12110 :     existing_slot = table_slot_create(heap, NULL);
     807             : 
     808       12110 :     econtext = GetPerTupleExprContext(estate);
     809       12110 :     save_scantuple = econtext->ecxt_scantuple;
     810       12110 :     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       12182 : retry:
     817       12182 :     conflict = false;
     818       12182 :     found_self = false;
     819       12182 :     index_scan = index_beginscan(heap, index, &DirtySnapshot, NULL, indnkeyatts, 0);
     820       12182 :     index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
     821             : 
     822       14332 :     while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
     823             :     {
     824             :         TransactionId xwait;
     825             :         XLTW_Oper   reason_wait;
     826             :         Datum       existing_values[INDEX_MAX_KEYS];
     827             :         bool        existing_isnull[INDEX_MAX_KEYS];
     828             :         char       *error_new;
     829             :         char       *error_existing;
     830             : 
     831             :         /*
     832             :          * Ignore the entry for the tuple we're trying to check.
     833             :          */
     834       10480 :         if (ItemPointerIsValid(tupleid) &&
     835        2474 :             ItemPointerEquals(tupleid, &existing_slot->tts_tid))
     836             :         {
     837        2096 :             if (found_self)     /* should not happen */
     838           0 :                 elog(ERROR, "found self tuple multiple times in index \"%s\"",
     839             :                      RelationGetRelationName(index));
     840        2096 :             found_self = true;
     841        2150 :             continue;
     842             :         }
     843             : 
     844             :         /*
     845             :          * Extract the index column values and isnull flags from the existing
     846             :          * tuple.
     847             :          */
     848        5910 :         FormIndexDatum(indexInfo, existing_slot, estate,
     849             :                        existing_values, existing_isnull);
     850             : 
     851             :         /* If lossy indexscan, must recheck the condition */
     852        5910 :         if (index_scan->xs_recheck)
     853             :         {
     854         138 :             if (!index_recheck_constraint(index,
     855             :                                           constr_procs,
     856             :                                           existing_values,
     857             :                                           existing_isnull,
     858             :                                           values))
     859          54 :                 continue;       /* tuple doesn't actually match, so no
     860             :                                  * conflict */
     861             :         }
     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       11712 :         xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
     874        5856 :             DirtySnapshot.xmin : DirtySnapshot.xmax;
     875             : 
     876        5856 :         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         148 :             reason_wait = indexInfo->ii_ExclusionOps ?
     883          74 :                 XLTW_RecheckExclusionConstr : XLTW_InsertIndex;
     884          74 :             index_endscan(index_scan);
     885          74 :             if (DirtySnapshot.speculativeToken)
     886           2 :                 SpeculativeInsertionWait(DirtySnapshot.xmin,
     887             :                                          DirtySnapshot.speculativeToken);
     888             :             else
     889          72 :                 XactLockTableWait(xwait, heap,
     890          72 :                                   &existing_slot->tts_tid, reason_wait);
     891          72 :             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        5782 :         if (violationOK)
     899             :         {
     900        5614 :             conflict = true;
     901        5614 :             if (conflictTid)
     902        5590 :                 *conflictTid = existing_slot->tts_tid;
     903        5614 :             break;
     904             :         }
     905             : 
     906         168 :         error_new = BuildIndexValueDescription(index, values, isnull);
     907         168 :         error_existing = BuildIndexValueDescription(index, existing_values,
     908             :                                                     existing_isnull);
     909         168 :         if (newIndex)
     910          36 :             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         132 :             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             :     }
     932             : 
     933       11940 :     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       11940 :     econtext->ecxt_scantuple = save_scantuple;
     944             : 
     945       11940 :     ExecDropSingleTupleTableSlot(existing_slot);
     946             : 
     947             : #ifdef USE_INJECTION_POINTS
     948       11940 :     if (!conflict)
     949        6326 :         INJECTION_POINT("check-exclusion-or-unique-constraint-no-conflict", NULL);
     950             : #endif
     951             : 
     952       11940 :     return !conflict;
     953             : }
     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         478 : 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         478 :     (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
     969             :                                                 values, isnull,
     970             :                                                 estate, newIndex,
     971             :                                                 CEOUC_WAIT, false, NULL);
     972         400 : }
     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         138 : 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         138 :     int         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
     984             :     int         i;
     985             : 
     986         342 :     for (i = 0; i < indnkeyatts; i++)
     987             :     {
     988             :         /* Assume the exclusion operators are strict */
     989         258 :         if (existing_isnull[i])
     990           0 :             return false;
     991             : 
     992         258 :         if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
     993         258 :                                                index->rd_indcollation[i],
     994         258 :                                                existing_values[i],
     995         258 :                                                new_values[i])))
     996          54 :             return false;
     997             :     }
     998             : 
     999          84 :     return true;
    1000             : }
    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      356220 : index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
    1011             :                           IndexInfo *indexInfo, Relation indexRelation)
    1012             : {
    1013             :     Bitmapset  *updatedCols;
    1014             :     Bitmapset  *extraUpdatedCols;
    1015             :     Bitmapset  *allUpdatedCols;
    1016      356220 :     bool        hasexpression = false;
    1017             :     List       *idxExprs;
    1018             : 
    1019             :     /*
    1020             :      * Check cache first
    1021             :      */
    1022      356220 :     if (indexInfo->ii_CheckedUnchanged)
    1023      312106 :         return indexInfo->ii_IndexUnchanged;
    1024       44114 :     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       44114 :     updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
    1038       44114 :     extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
    1039       47954 :     for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
    1040             :     {
    1041       45754 :         int         keycol = indexInfo->ii_IndexAttrNumbers[attr];
    1042             : 
    1043       45754 :         if (keycol <= 0)
    1044             :         {
    1045             :             /*
    1046             :              * Skip expressions for now, but remember to deal with them later
    1047             :              * on
    1048             :              */
    1049          30 :             hasexpression = true;
    1050          30 :             continue;
    1051             :         }
    1052             : 
    1053       45724 :         if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1054        3810 :                           updatedCols) ||
    1055        3810 :             bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1056             :                           extraUpdatedCols))
    1057             :         {
    1058             :             /* Changed key column -- don't hint for this index */
    1059       41914 :             indexInfo->ii_IndexUnchanged = false;
    1060       41914 :             return false;
    1061             :         }
    1062             :     }
    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        2200 :     if (!hasexpression)
    1073             :     {
    1074        2176 :         indexInfo->ii_IndexUnchanged = true;
    1075        2176 :         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          24 :     if (!extraUpdatedCols)
    1083          24 :         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          24 :     idxExprs = RelationGetIndexExpressions(indexRelation);
    1096          24 :     hasexpression = index_expression_changed_walker((Node *) idxExprs,
    1097             :                                                     allUpdatedCols);
    1098          24 :     list_free(idxExprs);
    1099          24 :     if (extraUpdatedCols)
    1100           0 :         bms_free(allUpdatedCols);
    1101             : 
    1102          24 :     if (hasexpression)
    1103             :     {
    1104          18 :         indexInfo->ii_IndexUnchanged = false;
    1105          18 :         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           6 :     indexInfo->ii_IndexUnchanged = true;
    1115           6 :     return true;
    1116             : }
    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          76 : index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols)
    1125             : {
    1126          76 :     if (node == NULL)
    1127           0 :         return false;
    1128             : 
    1129          76 :     if (IsA(node, Var))
    1130             :     {
    1131          24 :         Var        *var = (Var *) node;
    1132             : 
    1133          24 :         if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
    1134             :                           allUpdatedCols))
    1135             :         {
    1136             :             /* Var was updated -- indicates that we should not hint */
    1137          18 :             return true;
    1138             :         }
    1139             : 
    1140             :         /* Still haven't found a reason to not pass the hint */
    1141           6 :         return false;
    1142             :     }
    1143             : 
    1144          52 :     return expression_tree_walker(node, index_expression_changed_walker,
    1145             :                                   allUpdatedCols);
    1146             : }
    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        2162 : ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval, char typtype, Oid atttypid)
    1154             : {
    1155             :     bool        isempty;
    1156             :     RangeType  *r;
    1157             :     MultirangeType *mr;
    1158             : 
    1159        2162 :     switch (typtype)
    1160             :     {
    1161        1238 :         case TYPTYPE_RANGE:
    1162        1238 :             r = DatumGetRangeTypeP(attval);
    1163        1238 :             isempty = RangeIsEmpty(r);
    1164        1238 :             break;
    1165         924 :         case TYPTYPE_MULTIRANGE:
    1166         924 :             mr = DatumGetMultirangeTypeP(attval);
    1167         924 :             isempty = MultirangeIsEmpty(mr);
    1168         924 :             break;
    1169           0 :         default:
    1170           0 :             elog(ERROR, "WITHOUT OVERLAPS column \"%s\" is not a range or multirange",
    1171             :                  NameStr(attname));
    1172             :     }
    1173             : 
    1174             :     /* Report a CHECK_VIOLATION */
    1175        2162 :     if (isempty)
    1176          84 :         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        2078 : }

Generated by: LCOV version 1.16