LCOV - differential code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit UBC GIC GNC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 94.4 % 284 268 16 1 267
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 10 10 1 9
Baseline: lcov-20250906-005545-baseline Branches: 80.5 % 215 173 42 173
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 93.1 % 29 27 2 27
(360..) days: 94.5 % 255 241 14 1 240
Function coverage date bins:
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 9 9 1 8
Branch coverage date bins:
(30,360] days: 73.9 % 23 17 6 17
(360..) days: 81.2 % 192 156 36 156

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

Generated by: LCOV version 2.4-beta