LCOV - code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 93.5 % 414 387
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 73.4 % 248 182

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

Generated by: LCOV version 2.3.2-1