LCOV - differential code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.0 % 256 238 4 13 1 4 142 2 90 13 144
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 9 9 7 2 7
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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/snapmgr.h"
     118                 : 
     119                 : /* waitMode argument to check_exclusion_or_unique_constraint() */
     120                 : typedef enum
     121                 : {
     122                 :     CEOUC_WAIT,
     123                 :     CEOUC_NOWAIT,
     124                 :     CEOUC_LIVELOCK_PREVENTING_WAIT
     125                 : } CEOUC_WAIT_MODE;
     126                 : 
     127                 : static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
     128                 :                                                  IndexInfo *indexInfo,
     129                 :                                                  ItemPointer tupleid,
     130                 :                                                  Datum *values, bool *isnull,
     131                 :                                                  EState *estate, bool newIndex,
     132                 :                                                  CEOUC_WAIT_MODE waitMode,
     133                 :                                                  bool violationOK,
     134                 :                                                  ItemPointer conflictTid);
     135                 : 
     136                 : static bool index_recheck_constraint(Relation index, Oid *constr_procs,
     137                 :                                      Datum *existing_values, bool *existing_isnull,
     138                 :                                      Datum *new_values);
     139                 : static bool index_unchanged_by_update(ResultRelInfo *resultRelInfo,
     140                 :                                       EState *estate, IndexInfo *indexInfo,
     141                 :                                       Relation indexRelation);
     142                 : static bool index_expression_changed_walker(Node *node,
     143                 :                                             Bitmapset *allUpdatedCols);
     144                 : 
     145                 : /* ----------------------------------------------------------------
     146                 :  *      ExecOpenIndices
     147                 :  *
     148                 :  *      Find the indices associated with a result relation, open them,
     149                 :  *      and save information about them in the result ResultRelInfo.
     150                 :  *
     151                 :  *      At entry, caller has already opened and locked
     152                 :  *      resultRelInfo->ri_RelationDesc.
     153                 :  * ----------------------------------------------------------------
     154                 :  */
     155                 : void
     156 CBC     2371282 : ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
     157                 : {
     158         2371282 :     Relation    resultRelation = resultRelInfo->ri_RelationDesc;
     159                 :     List       *indexoidlist;
     160                 :     ListCell   *l;
     161                 :     int         len,
     162                 :                 i;
     163                 :     RelationPtr relationDescs;
     164                 :     IndexInfo **indexInfoArray;
     165                 : 
     166         2371282 :     resultRelInfo->ri_NumIndices = 0;
     167                 : 
     168                 :     /* fast path if no indexes */
     169         2371282 :     if (!RelationGetForm(resultRelation)->relhasindex)
     170          242770 :         return;
     171                 : 
     172                 :     /*
     173                 :      * Get cached list of index OIDs
     174                 :      */
     175         2128512 :     indexoidlist = RelationGetIndexList(resultRelation);
     176         2128512 :     len = list_length(indexoidlist);
     177         2128512 :     if (len == 0)
     178           20325 :         return;
     179                 : 
     180                 :     /*
     181                 :      * allocate space for result arrays
     182                 :      */
     183         2108187 :     relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
     184         2108187 :     indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
     185                 : 
     186         2108187 :     resultRelInfo->ri_NumIndices = len;
     187         2108187 :     resultRelInfo->ri_IndexRelationDescs = relationDescs;
     188         2108187 :     resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
     189                 : 
     190                 :     /*
     191                 :      * For each index, open the index relation and save pg_index info. We
     192                 :      * acquire RowExclusiveLock, signifying we will update the index.
     193                 :      *
     194                 :      * Note: we do this even if the index is not indisready; it's not worth
     195                 :      * the trouble to optimize for the case where it isn't.
     196                 :      */
     197         2108187 :     i = 0;
     198         6210559 :     foreach(l, indexoidlist)
     199                 :     {
     200         4102372 :         Oid         indexOid = lfirst_oid(l);
     201                 :         Relation    indexDesc;
     202                 :         IndexInfo  *ii;
     203                 : 
     204         4102372 :         indexDesc = index_open(indexOid, RowExclusiveLock);
     205                 : 
     206                 :         /* extract index key information from the index's pg_index info */
     207         4102372 :         ii = BuildIndexInfo(indexDesc);
     208                 : 
     209                 :         /*
     210                 :          * If the indexes are to be used for speculative insertion, add extra
     211                 :          * information required by unique index entries.
     212                 :          */
     213         4102372 :         if (speculative && ii->ii_Unique)
     214             603 :             BuildSpeculativeIndexInfo(indexDesc, ii);
     215                 : 
     216         4102372 :         relationDescs[i] = indexDesc;
     217         4102372 :         indexInfoArray[i] = ii;
     218         4102372 :         i++;
     219                 :     }
     220                 : 
     221         2108187 :     list_free(indexoidlist);
     222                 : }
     223                 : 
     224                 : /* ----------------------------------------------------------------
     225                 :  *      ExecCloseIndices
     226                 :  *
     227                 :  *      Close the index relations stored in resultRelInfo
     228                 :  * ----------------------------------------------------------------
     229                 :  */
     230                 : void
     231         2421886 : ExecCloseIndices(ResultRelInfo *resultRelInfo)
     232                 : {
     233                 :     int         i;
     234                 :     int         numIndices;
     235                 :     RelationPtr indexDescs;
     236                 : 
     237         2421886 :     numIndices = resultRelInfo->ri_NumIndices;
     238         2421886 :     indexDescs = resultRelInfo->ri_IndexRelationDescs;
     239                 : 
     240         6523506 :     for (i = 0; i < numIndices; i++)
     241                 :     {
     242         4101620 :         if (indexDescs[i] == NULL)
     243 UBC           0 :             continue;           /* shouldn't happen? */
     244                 : 
     245                 :         /* Drop lock acquired by ExecOpenIndices */
     246 CBC     4101620 :         index_close(indexDescs[i], RowExclusiveLock);
     247                 :     }
     248                 : 
     249                 :     /*
     250                 :      * XXX should free indexInfo array here too?  Currently we assume that
     251                 :      * such stuff will be cleaned up automatically in FreeExecutorState.
     252                 :      */
     253         2421886 : }
     254                 : 
     255                 : /* ----------------------------------------------------------------
     256                 :  *      ExecInsertIndexTuples
     257                 :  *
     258                 :  *      This routine takes care of inserting index tuples
     259                 :  *      into all the relations indexing the result relation
     260                 :  *      when a heap tuple is inserted into the result relation.
     261                 :  *
     262                 :  *      When 'update' is true and 'onlySummarizing' is false,
     263                 :  *      executor is performing an UPDATE that could not use an
     264                 :  *      optimization like heapam's HOT (in more general terms a
     265                 :  *      call to table_tuple_update() took place and set
     266                 :  *      'update_indexes' to TUUI_All).  Receiving this hint makes
     267                 :  *      us consider if we should pass down the 'indexUnchanged'
     268                 :  *      hint in turn.  That's something that we figure out for
     269                 :  *      each index_insert() call iff 'update' is true.
     270                 :  *      (When 'update' is false we already know not to pass the
     271                 :  *      hint to any index.)
     272                 :  *
     273                 :  *      If onlySummarizing is set, an equivalent optimization to
     274                 :  *      HOT has been applied and any updated columns are indexed
     275                 :  *      only by summarizing indexes (or in more general terms a
     276                 :  *      call to table_tuple_update() took place and set
     277                 :  *      'update_indexes' to TUUI_Summarizing). We can (and must)
     278                 :  *      therefore only update the indexes that have
     279                 :  *      'amsummarizing' = true.
     280                 :  *
     281                 :  *      Unique and exclusion constraints are enforced at the same
     282                 :  *      time.  This returns a list of index OIDs for any unique or
     283                 :  *      exclusion constraints that are deferred and that had
     284                 :  *      potential (unconfirmed) conflicts.  (if noDupErr == true,
     285                 :  *      the same is done for non-deferred constraints, but report
     286                 :  *      if conflict was speculative or deferred conflict to caller)
     287                 :  *
     288                 :  *      If 'arbiterIndexes' is nonempty, noDupErr applies only to
     289                 :  *      those indexes.  NIL means noDupErr applies to all indexes.
     290                 :  * ----------------------------------------------------------------
     291                 :  */
     292                 : List *
     293 GIC     2009170 : ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
     294                 :                       TupleTableSlot *slot,
     295                 :                       EState *estate,
     296                 :                       bool update,
     297                 :                       bool noDupErr,
     298                 :                       bool *specConflict,
     299                 :                       List *arbiterIndexes,
     300                 :                       bool onlySummarizing)
     301                 : {
     302         2009170 :     ItemPointer tupleid = &slot->tts_tid;
     303 CBC     2009170 :     List       *result = NIL;
     304                 :     int         i;
     305                 :     int         numIndices;
     306                 :     RelationPtr relationDescs;
     307                 :     Relation    heapRelation;
     308                 :     IndexInfo **indexInfoArray;
     309                 :     ExprContext *econtext;
     310                 :     Datum       values[INDEX_MAX_KEYS];
     311                 :     bool        isnull[INDEX_MAX_KEYS];
     312 ECB             : 
     313 CBC     2009170 :     Assert(ItemPointerIsValid(tupleid));
     314                 : 
     315                 :     /*
     316                 :      * Get information from the result relation info structure.
     317                 :      */
     318 GIC     2009170 :     numIndices = resultRelInfo->ri_NumIndices;
     319         2009170 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     320         2009170 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     321         2009170 :     heapRelation = resultRelInfo->ri_RelationDesc;
     322                 : 
     323 ECB             :     /* Sanity check: slot must belong to the same rel as the resultRelInfo. */
     324 GIC     2009170 :     Assert(slot->tts_tableOid == RelationGetRelid(heapRelation));
     325                 : 
     326                 :     /*
     327                 :      * We will use the EState's per-tuple context for evaluating predicates
     328 ECB             :      * and index expressions (creating it if it's not already there).
     329                 :      */
     330 CBC     2009170 :     econtext = GetPerTupleExprContext(estate);
     331 ECB             : 
     332                 :     /* Arrange for econtext's scan tuple to be the tuple under test */
     333 GIC     2009170 :     econtext->ecxt_scantuple = slot;
     334 ECB             : 
     335                 :     /*
     336                 :      * for each index, form and insert the index tuple
     337                 :      */
     338 GIC     4251376 :     for (i = 0; i < numIndices; i++)
     339                 :     {
     340 CBC     2242491 :         Relation    indexRelation = relationDescs[i];
     341                 :         IndexInfo  *indexInfo;
     342                 :         bool        applyNoDupErr;
     343 ECB             :         IndexUniqueCheck checkUnique;
     344                 :         bool        indexUnchanged;
     345                 :         bool        satisfiesConstraint;
     346                 : 
     347 GIC     2242491 :         if (indexRelation == NULL)
     348 LBC           0 :             continue;
     349                 : 
     350 CBC     2242491 :         indexInfo = indexInfoArray[i];
     351                 : 
     352                 :         /* If the index is marked as read-only, ignore it */
     353 GIC     2242491 :         if (!indexInfo->ii_ReadyForInserts)
     354             106 :             continue;
     355                 : 
     356                 :         /*
     357                 :          * Skip processing of non-summarizing indexes if we only
     358                 :          * update summarizing indexes
     359                 :          */
     360 GNC     2242385 :         if (onlySummarizing && !indexInfo->ii_Summarizing)
     361               3 :             continue;
     362                 : 
     363                 :         /* Check for partial index */
     364 CBC     2242382 :         if (indexInfo->ii_Predicate != NIL)
     365 EUB             :         {
     366                 :             ExprState  *predicate;
     367 ECB             : 
     368                 :             /*
     369                 :              * If predicate state not set up yet, create it (in the estate's
     370                 :              * per-query context)
     371                 :              */
     372 GIC      200545 :             predicate = indexInfo->ii_PredicateState;
     373          200545 :             if (predicate == NULL)
     374                 :             {
     375             130 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     376             130 :                 indexInfo->ii_PredicateState = predicate;
     377 ECB             :             }
     378                 : 
     379                 :             /* Skip this index-update if the predicate isn't satisfied */
     380 GIC      200545 :             if (!ExecQual(predicate, econtext))
     381 CBC      200274 :                 continue;
     382                 :         }
     383                 : 
     384                 :         /*
     385                 :          * FormIndexDatum fills in its values and isnull parameters with the
     386                 :          * appropriate values for the column(s) of the index.
     387                 :          */
     388 GIC     2042108 :         FormIndexDatum(indexInfo,
     389 ECB             :                        slot,
     390                 :                        estate,
     391                 :                        values,
     392                 :                        isnull);
     393                 : 
     394                 :         /* Check whether to apply noDupErr to this index */
     395 GIC     2044103 :         applyNoDupErr = noDupErr &&
     396            1995 :             (arbiterIndexes == NIL ||
     397 CBC        1995 :              list_member_oid(arbiterIndexes,
     398            1995 :                              indexRelation->rd_index->indexrelid));
     399                 : 
     400                 :         /*
     401                 :          * The index AM does the actual insertion, plus uniqueness checking.
     402                 :          *
     403                 :          * For an immediate-mode unique index, we just tell the index AM to
     404                 :          * throw error if not unique.
     405 ECB             :          *
     406                 :          * For a deferrable unique index, we tell the index AM to just detect
     407                 :          * possible non-uniqueness, and we add the index OID to the result
     408                 :          * list if further checking is needed.
     409                 :          *
     410                 :          * For a speculative insertion (used by INSERT ... ON CONFLICT), do
     411                 :          * the same as for a deferrable unique index.
     412                 :          */
     413 CBC     2042108 :         if (!indexRelation->rd_index->indisunique)
     414          930743 :             checkUnique = UNIQUE_CHECK_NO;
     415         1111365 :         else if (applyNoDupErr)
     416 GIC        2016 :             checkUnique = UNIQUE_CHECK_PARTIAL;
     417         1109349 :         else if (indexRelation->rd_index->indimmediate)
     418         1109274 :             checkUnique = UNIQUE_CHECK_YES;
     419                 :         else
     420              75 :             checkUnique = UNIQUE_CHECK_PARTIAL;
     421                 : 
     422                 :         /*
     423                 :          * There's definitely going to be an index_insert() call for this
     424                 :          * index.  If we're being called as part of an UPDATE statement,
     425                 :          * consider if the 'indexUnchanged' = true hint should be passed.
     426                 :          */
     427         2042108 :         indexUnchanged = update && index_unchanged_by_update(resultRelInfo,
     428                 :                                                              estate,
     429                 :                                                              indexInfo,
     430 ECB             :                                                              indexRelation);
     431                 : 
     432                 :         satisfiesConstraint =
     433 CBC     2042108 :             index_insert(indexRelation, /* index relation */
     434 ECB             :                          values,    /* array of index Datums */
     435                 :                          isnull,    /* null flags */
     436                 :                          tupleid,   /* tid of heap tuple */
     437                 :                          heapRelation,  /* heap relation */
     438                 :                          checkUnique,   /* type of uniqueness check to do */
     439                 :                          indexUnchanged,    /* UPDATE without logical change? */
     440                 :                          indexInfo);    /* index AM may need this */
     441                 : 
     442                 :         /*
     443                 :          * If the index has an associated exclusion constraint, check that.
     444                 :          * This is simpler than the process for uniqueness checks since we
     445                 :          * always insert first and then check.  If the constraint is deferred,
     446                 :          * we check now anyway, but don't throw error on violation or wait for
     447                 :          * a conclusive outcome from a concurrent insertion; instead we'll
     448                 :          * queue a recheck event.  Similarly, noDupErr callers (speculative
     449                 :          * inserters) will recheck later, and wait for a conclusive outcome
     450                 :          * then.
     451                 :          *
     452                 :          * An index for an exclusion constraint can't also be UNIQUE (not an
     453                 :          * essential property, we just don't allow it in the grammar), so no
     454                 :          * need to preserve the prior state of satisfiesConstraint.
     455                 :          */
     456 GIC     2041848 :         if (indexInfo->ii_ExclusionOps != NULL)
     457                 :         {
     458                 :             bool        violationOK;
     459                 :             CEOUC_WAIT_MODE waitMode;
     460                 : 
     461             153 :             if (applyNoDupErr)
     462                 :             {
     463 UIC           0 :                 violationOK = true;
     464               0 :                 waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
     465                 :             }
     466 GIC         153 :             else if (!indexRelation->rd_index->indimmediate)
     467                 :             {
     468              21 :                 violationOK = true;
     469              21 :                 waitMode = CEOUC_NOWAIT;
     470                 :             }
     471                 :             else
     472                 :             {
     473 CBC         132 :                 violationOK = false;
     474 GIC         132 :                 waitMode = CEOUC_WAIT;
     475                 :             }
     476                 : 
     477                 :             satisfiesConstraint =
     478 CBC         153 :                 check_exclusion_or_unique_constraint(heapRelation,
     479                 :                                                      indexRelation, indexInfo,
     480 EUB             :                                                      tupleid, values, isnull,
     481                 :                                                      estate, false,
     482                 :                                                      waitMode, violationOK, NULL);
     483 ECB             :         }
     484                 : 
     485 CBC     2041823 :         if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
     486         2039732 :              indexInfo->ii_ExclusionOps != NULL) &&
     487 GIC        2219 :             !satisfiesConstraint)
     488                 :         {
     489                 :             /*
     490 ECB             :              * The tuple potentially violates the uniqueness or exclusion
     491                 :              * constraint, so make a note of the index so that we can re-check
     492                 :              * it later.  Speculative inserters are told if there was a
     493                 :              * speculative conflict, since that always requires a restart.
     494                 :              */
     495 CBC          66 :             result = lappend_oid(result, RelationGetRelid(indexRelation));
     496 GIC          66 :             if (indexRelation->rd_index->indimmediate && specConflict)
     497               5 :                 *specConflict = true;
     498                 :         }
     499                 :     }
     500                 : 
     501         2008885 :     return result;
     502 ECB             : }
     503                 : 
     504                 : /* ----------------------------------------------------------------
     505                 :  *      ExecCheckIndexConstraints
     506                 :  *
     507                 :  *      This routine checks if a tuple violates any unique or
     508                 :  *      exclusion constraints.  Returns true if there is no conflict.
     509                 :  *      Otherwise returns false, and the TID of the conflicting
     510                 :  *      tuple is returned in *conflictTid.
     511                 :  *
     512                 :  *      If 'arbiterIndexes' is given, only those indexes are checked.
     513                 :  *      NIL means all indexes.
     514                 :  *
     515                 :  *      Note that this doesn't lock the values in any way, so it's
     516                 :  *      possible that a conflicting tuple is inserted immediately
     517                 :  *      after this returns.  But this can be used for a pre-check
     518                 :  *      before insertion.
     519                 :  * ----------------------------------------------------------------
     520                 :  */
     521                 : bool
     522 GIC        4695 : ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
     523                 :                           EState *estate, ItemPointer conflictTid,
     524                 :                           List *arbiterIndexes)
     525                 : {
     526                 :     int         i;
     527                 :     int         numIndices;
     528                 :     RelationPtr relationDescs;
     529                 :     Relation    heapRelation;
     530                 :     IndexInfo **indexInfoArray;
     531                 :     ExprContext *econtext;
     532                 :     Datum       values[INDEX_MAX_KEYS];
     533                 :     bool        isnull[INDEX_MAX_KEYS];
     534                 :     ItemPointerData invalidItemPtr;
     535            4695 :     bool        checkedIndex = false;
     536                 : 
     537            4695 :     ItemPointerSetInvalid(conflictTid);
     538            4695 :     ItemPointerSetInvalid(&invalidItemPtr);
     539 ECB             : 
     540                 :     /*
     541                 :      * Get information from the result relation info structure.
     542                 :      */
     543 GIC        4695 :     numIndices = resultRelInfo->ri_NumIndices;
     544            4695 :     relationDescs = resultRelInfo->ri_IndexRelationDescs;
     545            4695 :     indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
     546            4695 :     heapRelation = resultRelInfo->ri_RelationDesc;
     547                 : 
     548                 :     /*
     549                 :      * We will use the EState's per-tuple context for evaluating predicates
     550                 :      * and index expressions (creating it if it's not already there).
     551                 :      */
     552 CBC        4695 :     econtext = GetPerTupleExprContext(estate);
     553                 : 
     554 ECB             :     /* Arrange for econtext's scan tuple to be the tuple under test */
     555 CBC        4695 :     econtext->ecxt_scantuple = slot;
     556                 : 
     557                 :     /*
     558                 :      * For each index, form index tuple and check if it satisfies the
     559                 :      * constraint.
     560 ECB             :      */
     561 CBC        6752 :     for (i = 0; i < numIndices; i++)
     562 ECB             :     {
     563 CBC        4739 :         Relation    indexRelation = relationDescs[i];
     564                 :         IndexInfo  *indexInfo;
     565                 :         bool        satisfiesConstraint;
     566                 : 
     567 GIC        4739 :         if (indexRelation == NULL)
     568 UIC           0 :             continue;
     569 ECB             : 
     570 GIC        4739 :         indexInfo = indexInfoArray[i];
     571                 : 
     572 CBC        4739 :         if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
     573 GIC           2 :             continue;
     574                 : 
     575                 :         /* If the index is marked as read-only, ignore it */
     576            4737 :         if (!indexInfo->ii_ReadyForInserts)
     577 UIC           0 :             continue;
     578 ECB             : 
     579                 :         /* When specific arbiter indexes requested, only examine them */
     580 CBC        4737 :         if (arbiterIndexes != NIL &&
     581 GIC        4647 :             !list_member_oid(arbiterIndexes,
     582            4647 :                              indexRelation->rd_index->indexrelid))
     583              39 :             continue;
     584 ECB             : 
     585 GBC        4698 :         if (!indexRelation->rd_index->indimmediate)
     586 GIC           3 :             ereport(ERROR,
     587 ECB             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     588                 :                      errmsg("ON CONFLICT does not support deferrable unique constraints/exclusion constraints as arbiters"),
     589                 :                      errtableconstraint(heapRelation,
     590                 :                                         RelationGetRelationName(indexRelation))));
     591                 : 
     592 GIC        4695 :         checkedIndex = true;
     593 ECB             : 
     594 EUB             :         /* Check for partial index */
     595 GIC        4695 :         if (indexInfo->ii_Predicate != NIL)
     596                 :         {
     597 ECB             :             ExprState  *predicate;
     598                 : 
     599                 :             /*
     600                 :              * If predicate state not set up yet, create it (in the estate's
     601                 :              * per-query context)
     602                 :              */
     603 CBC          15 :             predicate = indexInfo->ii_PredicateState;
     604 GIC          15 :             if (predicate == NULL)
     605                 :             {
     606              15 :                 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
     607              15 :                 indexInfo->ii_PredicateState = predicate;
     608                 :             }
     609 ECB             : 
     610                 :             /* Skip this index-update if the predicate isn't satisfied */
     611 GIC          15 :             if (!ExecQual(predicate, econtext))
     612 LBC           0 :                 continue;
     613                 :         }
     614                 : 
     615                 :         /*
     616                 :          * FormIndexDatum fills in its values and isnull parameters with the
     617                 :          * appropriate values for the column(s) of the index.
     618                 :          */
     619 GIC        4695 :         FormIndexDatum(indexInfo,
     620 ECB             :                        slot,
     621                 :                        estate,
     622                 :                        values,
     623                 :                        isnull);
     624                 : 
     625                 :         satisfiesConstraint =
     626 GIC        4695 :             check_exclusion_or_unique_constraint(heapRelation, indexRelation,
     627                 :                                                  indexInfo, &invalidItemPtr,
     628 ECB             :                                                  values, isnull, estate, false,
     629 EUB             :                                                  CEOUC_WAIT, true,
     630                 :                                                  conflictTid);
     631 GIC        4695 :         if (!satisfiesConstraint)
     632            2679 :             return false;
     633                 :     }
     634                 : 
     635            2013 :     if (arbiterIndexes != NIL && !checkedIndex)
     636 LBC           0 :         elog(ERROR, "unexpected failure to find arbiter index");
     637                 : 
     638 GIC        2013 :     return true;
     639                 : }
     640                 : 
     641                 : /*
     642                 :  * Check for violation of an exclusion or unique constraint
     643 ECB             :  *
     644                 :  * heap: the table containing the new tuple
     645                 :  * index: the index supporting the constraint
     646                 :  * indexInfo: info about the index, including the exclusion properties
     647                 :  * tupleid: heap TID of the new tuple we have just inserted (invalid if we
     648                 :  *      haven't inserted a new tuple yet)
     649                 :  * values, isnull: the *index* column values computed for the new tuple
     650                 :  * estate: an EState we can do evaluation in
     651                 :  * newIndex: if true, we are trying to build a new index (this affects
     652                 :  *      only the wording of error messages)
     653 EUB             :  * waitMode: whether to wait for concurrent inserters/deleters
     654                 :  * violationOK: if true, don't throw error for violation
     655 ECB             :  * conflictTid: if not-NULL, the TID of the conflicting tuple is returned here
     656                 :  *
     657                 :  * Returns true if OK, false if actual or potential violation
     658                 :  *
     659                 :  * 'waitMode' determines what happens if a conflict is detected with a tuple
     660                 :  * that was inserted or deleted by a transaction that's still running.
     661                 :  * CEOUC_WAIT means that we wait for the transaction to commit, before
     662                 :  * throwing an error or returning.  CEOUC_NOWAIT means that we report the
     663                 :  * violation immediately; so the violation is only potential, and the caller
     664                 :  * must recheck sometime later.  This behavior is convenient for deferred
     665                 :  * exclusion checks; we need not bother queuing a deferred event if there is
     666                 :  * definitely no conflict at insertion time.
     667                 :  *
     668                 :  * CEOUC_LIVELOCK_PREVENTING_WAIT is like CEOUC_NOWAIT, but we will sometimes
     669                 :  * wait anyway, to prevent livelocking if two transactions try inserting at
     670                 :  * the same time.  This is used with speculative insertions, for INSERT ON
     671                 :  * CONFLICT statements. (See notes in file header)
     672                 :  *
     673                 :  * If violationOK is true, we just report the potential or actual violation to
     674                 :  * the caller by returning 'false'.  Otherwise we throw a descriptive error
     675                 :  * message here.  When violationOK is false, a false result is impossible.
     676                 :  *
     677                 :  * Note: The indexam is normally responsible for checking unique constraints,
     678                 :  * so this normally only needs to be used for exclusion constraints.  But this
     679                 :  * function is also called when doing a "pre-check" for conflicts on a unique
     680                 :  * constraint, when doing speculative insertion.  Caller may use the returned
     681                 :  * conflict TID to take further steps.
     682                 :  */
     683                 : static bool
     684 GIC        4883 : check_exclusion_or_unique_constraint(Relation heap, Relation index,
     685                 :                                      IndexInfo *indexInfo,
     686                 :                                      ItemPointer tupleid,
     687                 :                                      Datum *values, bool *isnull,
     688                 :                                      EState *estate, bool newIndex,
     689                 :                                      CEOUC_WAIT_MODE waitMode,
     690                 :                                      bool violationOK,
     691                 :                                      ItemPointer conflictTid)
     692                 : {
     693                 :     Oid        *constr_procs;
     694                 :     uint16     *constr_strats;
     695            4883 :     Oid        *index_collations = index->rd_indcollation;
     696            4883 :     int         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
     697                 :     IndexScanDesc index_scan;
     698                 :     ScanKeyData scankeys[INDEX_MAX_KEYS];
     699                 :     SnapshotData DirtySnapshot;
     700                 :     int         i;
     701 ECB             :     bool        conflict;
     702                 :     bool        found_self;
     703                 :     ExprContext *econtext;
     704                 :     TupleTableSlot *existing_slot;
     705                 :     TupleTableSlot *save_scantuple;
     706                 : 
     707 GIC        4883 :     if (indexInfo->ii_ExclusionOps)
     708                 :     {
     709             194 :         constr_procs = indexInfo->ii_ExclusionProcs;
     710             194 :         constr_strats = indexInfo->ii_ExclusionStrats;
     711                 :     }
     712 ECB             :     else
     713                 :     {
     714 GIC        4689 :         constr_procs = indexInfo->ii_UniqueProcs;
     715            4689 :         constr_strats = indexInfo->ii_UniqueStrats;
     716                 :     }
     717                 : 
     718                 :     /*
     719                 :      * If any of the input values are NULL, and the index uses the default
     720                 :      * nulls-are-distinct mode, the constraint check is assumed to pass (i.e.,
     721                 :      * we assume the operators are strict).  Otherwise, we interpret the
     722                 :      * constraint as specifying IS NULL for each column whose input value is
     723                 :      * NULL.
     724 ECB             :      */
     725 GIC        4883 :     if (!indexInfo->ii_NullsNotDistinct)
     726 ECB             :     {
     727 CBC        9848 :         for (i = 0; i < indnkeyatts; i++)
     728                 :         {
     729 GIC        4968 :             if (isnull[i])
     730 UIC           0 :                 return true;
     731 ECB             :         }
     732                 :     }
     733                 : 
     734                 :     /*
     735                 :      * Search the tuples that are in the index for any violations, including
     736                 :      * tuples that aren't visible yet.
     737                 :      */
     738 GIC        4883 :     InitDirtySnapshot(DirtySnapshot);
     739                 : 
     740            9854 :     for (i = 0; i < indnkeyatts; i++)
     741                 :     {
     742 CBC        4971 :         ScanKeyEntryInitialize(&scankeys[i],
     743 GIC        4971 :                                isnull[i] ? SK_ISNULL | SK_SEARCHNULL : 0,
     744 CBC        4971 :                                i + 1,
     745 GIC        4971 :                                constr_strats[i],
     746 ECB             :                                InvalidOid,
     747 GBC        4971 :                                index_collations[i],
     748 GIC        4971 :                                constr_procs[i],
     749            4971 :                                values[i]);
     750                 :     }
     751                 : 
     752                 :     /*
     753                 :      * Need a TupleTableSlot to put existing tuples in.
     754                 :      *
     755 ECB             :      * To use FormIndexDatum, we have to make the econtext's scantuple point
     756                 :      * to this slot.  Be sure to save and restore caller's value for
     757                 :      * scantuple.
     758                 :      */
     759 CBC        4883 :     existing_slot = table_slot_create(heap, NULL);
     760 ECB             : 
     761 CBC        4883 :     econtext = GetPerTupleExprContext(estate);
     762            4883 :     save_scantuple = econtext->ecxt_scantuple;
     763 GIC        4883 :     econtext->ecxt_scantuple = existing_slot;
     764 ECB             : 
     765                 :     /*
     766                 :      * May have to restart scan from this point if a potential conflict is
     767                 :      * found.
     768                 :      */
     769 GIC        4918 : retry:
     770            4918 :     conflict = false;
     771            4918 :     found_self = false;
     772            4918 :     index_scan = index_beginscan(heap, index, &DirtySnapshot, indnkeyatts, 0);
     773            4918 :     index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
     774                 : 
     775            5084 :     while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
     776 ECB             :     {
     777                 :         TransactionId xwait;
     778                 :         XLTW_Oper   reason_wait;
     779                 :         Datum       existing_values[INDEX_MAX_KEYS];
     780                 :         bool        existing_isnull[INDEX_MAX_KEYS];
     781                 :         char       *error_new;
     782                 :         char       *error_existing;
     783                 : 
     784                 :         /*
     785                 :          * Ignore the entry for the tuple we're trying to check.
     786                 :          */
     787 CBC        3150 :         if (ItemPointerIsValid(tupleid) &&
     788             218 :             ItemPointerEquals(tupleid, &existing_slot->tts_tid))
     789 ECB             :         {
     790 CBC         139 :             if (found_self)     /* should not happen */
     791 UIC           0 :                 elog(ERROR, "found self tuple multiple times in index \"%s\"",
     792 ECB             :                      RelationGetRelationName(index));
     793 GIC         139 :             found_self = true;
     794             166 :             continue;
     795                 :         }
     796                 : 
     797                 :         /*
     798                 :          * Extract the index column values and isnull flags from the existing
     799                 :          * tuple.
     800                 :          */
     801            2793 :         FormIndexDatum(indexInfo, existing_slot, estate,
     802                 :                        existing_values, existing_isnull);
     803                 : 
     804 ECB             :         /* If lossy indexscan, must recheck the condition */
     805 CBC        2793 :         if (index_scan->xs_recheck)
     806                 :         {
     807              36 :             if (!index_recheck_constraint(index,
     808 EUB             :                                           constr_procs,
     809                 :                                           existing_values,
     810 ECB             :                                           existing_isnull,
     811                 :                                           values))
     812 GIC          27 :                 continue;       /* tuple doesn't actually match, so no
     813                 :                                  * conflict */
     814                 :         }
     815                 : 
     816                 :         /*
     817                 :          * At this point we have either a conflict or a potential conflict.
     818 ECB             :          *
     819                 :          * If an in-progress transaction is affecting the visibility of this
     820                 :          * tuple, we need to wait for it to complete and then recheck (unless
     821                 :          * the caller requested not to).  For simplicity we do rechecking by
     822                 :          * just restarting the whole scan --- this case probably doesn't
     823                 :          * happen often enough to be worth trying harder, and anyway we don't
     824                 :          * want to hold any index internal locks while waiting.
     825                 :          */
     826 GIC        5532 :         xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
     827            2766 :             DirtySnapshot.xmin : DirtySnapshot.xmax;
     828                 : 
     829 CBC        2766 :         if (TransactionIdIsValid(xwait) &&
     830 UIC           0 :             (waitMode == CEOUC_WAIT ||
     831               0 :              (waitMode == CEOUC_LIVELOCK_PREVENTING_WAIT &&
     832               0 :               DirtySnapshot.speculativeToken &&
     833               0 :               TransactionIdPrecedes(GetCurrentTransactionId(), xwait))))
     834                 :         {
     835 GIC          70 :             reason_wait = indexInfo->ii_ExclusionOps ?
     836              35 :                 XLTW_RecheckExclusionConstr : XLTW_InsertIndex;
     837              35 :             index_endscan(index_scan);
     838              35 :             if (DirtySnapshot.speculativeToken)
     839               1 :                 SpeculativeInsertionWait(DirtySnapshot.xmin,
     840                 :                                          DirtySnapshot.speculativeToken);
     841                 :             else
     842              34 :                 XactLockTableWait(xwait, heap,
     843 ECB             :                                   &existing_slot->tts_tid, reason_wait);
     844 CBC          35 :             goto retry;
     845                 :         }
     846 ECB             : 
     847 EUB             :         /*
     848                 :          * We have a definite conflict (or a potential one, but the caller
     849                 :          * didn't want to wait).  Return it to caller, or report it.
     850                 :          */
     851 GIC        2731 :         if (violationOK)
     852 ECB             :         {
     853 CBC        2691 :             conflict = true;
     854            2691 :             if (conflictTid)
     855            2679 :                 *conflictTid = existing_slot->tts_tid;
     856            2691 :             break;
     857                 :         }
     858                 : 
     859              40 :         error_new = BuildIndexValueDescription(index, values, isnull);
     860 GIC          40 :         error_existing = BuildIndexValueDescription(index, existing_values,
     861 ECB             :                                                     existing_isnull);
     862 GIC          40 :         if (newIndex)
     863               6 :             ereport(ERROR,
     864                 :                     (errcode(ERRCODE_EXCLUSION_VIOLATION),
     865                 :                      errmsg("could not create exclusion constraint \"%s\"",
     866                 :                             RelationGetRelationName(index)),
     867                 :                      error_new && error_existing ?
     868 ECB             :                      errdetail("Key %s conflicts with key %s.",
     869                 :                                error_new, error_existing) :
     870                 :                      errdetail("Key conflicts exist."),
     871                 :                      errtableconstraint(heap,
     872                 :                                         RelationGetRelationName(index))));
     873                 :         else
     874 GIC          34 :             ereport(ERROR,
     875                 :                     (errcode(ERRCODE_EXCLUSION_VIOLATION),
     876 ECB             :                      errmsg("conflicting key value violates exclusion constraint \"%s\"",
     877                 :                             RelationGetRelationName(index)),
     878                 :                      error_new && error_existing ?
     879                 :                      errdetail("Key %s conflicts with existing key %s.",
     880                 :                                error_new, error_existing) :
     881                 :                      errdetail("Key conflicts with existing key."),
     882                 :                      errtableconstraint(heap,
     883                 :                                         RelationGetRelationName(index))));
     884                 :     }
     885                 : 
     886 GIC        4843 :     index_endscan(index_scan);
     887                 : 
     888                 :     /*
     889                 :      * Ordinarily, at this point the search should have found the originally
     890                 :      * inserted tuple (if any), unless we exited the loop early because of
     891 ECB             :      * conflict.  However, it is possible to define exclusion constraints for
     892                 :      * which that wouldn't be true --- for instance, if the operator is <>. So
     893                 :      * we no longer complain if found_self is still false.
     894                 :      */
     895                 : 
     896 GIC        4843 :     econtext->ecxt_scantuple = save_scantuple;
     897                 : 
     898            4843 :     ExecDropSingleTupleTableSlot(existing_slot);
     899                 : 
     900            4843 :     return !conflict;
     901                 : }
     902                 : 
     903 ECB             : /*
     904                 :  * Check for violation of an exclusion constraint
     905                 :  *
     906                 :  * This is a dumbed down version of check_exclusion_or_unique_constraint
     907                 :  * for external callers. They don't need all the special modes.
     908                 :  */
     909                 : void
     910 GIC          35 : check_exclusion_constraint(Relation heap, Relation index,
     911                 :                            IndexInfo *indexInfo,
     912                 :                            ItemPointer tupleid,
     913 ECB             :                            Datum *values, bool *isnull,
     914                 :                            EState *estate, bool newIndex)
     915                 : {
     916 GIC          35 :     (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
     917 ECB             :                                                 values, isnull,
     918                 :                                                 estate, newIndex,
     919                 :                                                 CEOUC_WAIT, false, NULL);
     920 GIC          20 : }
     921                 : 
     922                 : /*
     923                 :  * Check existing tuple's index values to see if it really matches the
     924                 :  * exclusion condition against the new_values.  Returns true if conflict.
     925                 :  */
     926                 : static bool
     927 CBC          36 : index_recheck_constraint(Relation index, Oid *constr_procs,
     928                 :                          Datum *existing_values, bool *existing_isnull,
     929                 :                          Datum *new_values)
     930                 : {
     931 GIC          36 :     int         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
     932                 :     int         i;
     933 ECB             : 
     934 GIC          72 :     for (i = 0; i < indnkeyatts; i++)
     935                 :     {
     936                 :         /* Assume the exclusion operators are strict */
     937 CBC          63 :         if (existing_isnull[i])
     938 UIC           0 :             return false;
     939                 : 
     940 GIC          63 :         if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
     941              63 :                                                index->rd_indcollation[i],
     942              63 :                                                existing_values[i],
     943              63 :                                                new_values[i])))
     944 CBC          27 :             return false;
     945                 :     }
     946                 : 
     947 GIC           9 :     return true;
     948 ECB             : }
     949                 : 
     950                 : /*
     951                 :  * Check if ExecInsertIndexTuples() should pass indexUnchanged hint.
     952                 :  *
     953                 :  * When the executor performs an UPDATE that requires a new round of index
     954                 :  * tuples, determine if we should pass 'indexUnchanged' = true hint for one
     955 EUB             :  * single index.
     956                 :  */
     957 ECB             : static bool
     958 CBC      252521 : index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
     959 ECB             :                           IndexInfo *indexInfo, Relation indexRelation)
     960                 : {
     961                 :     Bitmapset  *updatedCols;
     962                 :     Bitmapset  *extraUpdatedCols;
     963                 :     Bitmapset  *allUpdatedCols;
     964 CBC      252521 :     bool        hasexpression = false;
     965                 :     List       *idxExprs;
     966                 : 
     967                 :     /*
     968                 :      * Check cache first
     969                 :      */
     970 GIC      252521 :     if (indexInfo->ii_CheckedUnchanged)
     971          230258 :         return indexInfo->ii_IndexUnchanged;
     972           22263 :     indexInfo->ii_CheckedUnchanged = true;
     973                 : 
     974                 :     /*
     975 ECB             :      * Check for indexed attribute overlap with updated columns.
     976                 :      *
     977                 :      * Only do this for key columns.  A change to a non-key column within an
     978                 :      * INCLUDE index should not be counted here.  Non-key column values are
     979                 :      * opaque payload state to the index AM, a little like an extra table TID.
     980                 :      *
     981                 :      * Note that row-level BEFORE triggers won't affect our behavior, since
     982                 :      * they don't affect the updatedCols bitmaps generally.  It doesn't seem
     983                 :      * worth the trouble of checking which attributes were changed directly.
     984                 :      */
     985 GIC       22263 :     updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
     986           22263 :     extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
     987 CBC       24836 :     for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
     988 ECB             :     {
     989 CBC       23276 :         int         keycol = indexInfo->ii_IndexAttrNumbers[attr];
     990                 : 
     991 GIC       23276 :         if (keycol <= 0)
     992                 :         {
     993                 :             /*
     994                 :              * Skip expressions for now, but remember to deal with them later
     995                 :              * on
     996                 :              */
     997              15 :             hasexpression = true;
     998              15 :             continue;
     999                 :         }
    1000                 : 
    1001           23261 :         if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1002 CBC        2558 :                           updatedCols) ||
    1003            2558 :             bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
    1004 ECB             :                           extraUpdatedCols))
    1005                 :         {
    1006                 :             /* Changed key column -- don't hint for this index */
    1007 GIC       20703 :             indexInfo->ii_IndexUnchanged = false;
    1008 CBC       20703 :             return false;
    1009                 :         }
    1010                 :     }
    1011                 : 
    1012                 :     /*
    1013                 :      * When we get this far and index has no expressions, return true so that
    1014 ECB             :      * index_insert() call will go on to pass 'indexUnchanged' = true hint.
    1015                 :      *
    1016                 :      * The _absence_ of an indexed key attribute that overlaps with updated
    1017                 :      * attributes (in addition to the total absence of indexed expressions)
    1018                 :      * shows that the index as a whole is logically unchanged by UPDATE.
    1019                 :      */
    1020 CBC        1560 :     if (!hasexpression)
    1021                 :     {
    1022 GIC        1548 :         indexInfo->ii_IndexUnchanged = true;
    1023            1548 :         return true;
    1024 ECB             :     }
    1025                 : 
    1026                 :     /*
    1027                 :      * Need to pass only one bms to expression_tree_walker helper function.
    1028                 :      * Avoid allocating memory in common case where there are no extra cols.
    1029                 :      */
    1030 GIC          12 :     if (!extraUpdatedCols)
    1031              12 :         allUpdatedCols = updatedCols;
    1032                 :     else
    1033 UIC           0 :         allUpdatedCols = bms_union(updatedCols, extraUpdatedCols);
    1034                 : 
    1035                 :     /*
    1036                 :      * We have to work slightly harder in the event of indexed expressions,
    1037 ECB             :      * but the principle is the same as before: try to find columns (Vars,
    1038                 :      * actually) that overlap with known-updated columns.
    1039                 :      *
    1040                 :      * If we find any matching Vars, don't pass hint for index.  Otherwise
    1041                 :      * pass hint.
    1042                 :      */
    1043 GIC          12 :     idxExprs = RelationGetIndexExpressions(indexRelation);
    1044              12 :     hasexpression = index_expression_changed_walker((Node *) idxExprs,
    1045                 :                                                     allUpdatedCols);
    1046              12 :     list_free(idxExprs);
    1047 CBC          12 :     if (extraUpdatedCols)
    1048 LBC           0 :         bms_free(allUpdatedCols);
    1049                 : 
    1050 GBC          12 :     if (hasexpression)
    1051                 :     {
    1052 GIC           9 :         indexInfo->ii_IndexUnchanged = false;
    1053               9 :         return false;
    1054                 :     }
    1055                 : 
    1056                 :     /*
    1057                 :      * Deliberately don't consider index predicates.  We should even give the
    1058                 :      * hint when result rel's "updated tuple" has no corresponding index
    1059                 :      * tuple, which is possible with a partial index (provided the usual
    1060 ECB             :      * conditions are met).
    1061                 :      */
    1062 GIC           3 :     indexInfo->ii_IndexUnchanged = true;
    1063 CBC           3 :     return true;
    1064 ECB             : }
    1065 EUB             : 
    1066                 : /*
    1067 ECB             :  * Indexed expression helper for index_unchanged_by_update().
    1068                 :  *
    1069                 :  * Returns true when Var that appears within allUpdatedCols located.
    1070                 :  */
    1071                 : static bool
    1072 GIC          38 : index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols)
    1073                 : {
    1074              38 :     if (node == NULL)
    1075 UIC           0 :         return false;
    1076                 : 
    1077 GIC          38 :     if (IsA(node, Var))
    1078                 :     {
    1079 CBC          12 :         Var        *var = (Var *) node;
    1080 ECB             : 
    1081 GIC          12 :         if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
    1082                 :                           allUpdatedCols))
    1083                 :         {
    1084                 :             /* Var was updated -- indicates that we should not hint */
    1085               9 :             return true;
    1086                 :         }
    1087                 : 
    1088                 :         /* Still haven't found a reason to not pass the hint */
    1089 CBC           3 :         return false;
    1090                 :     }
    1091 ECB             : 
    1092 GBC          26 :     return expression_tree_walker(node, index_expression_changed_walker,
    1093                 :                                   (void *) allUpdatedCols);
    1094 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a