LCOV - differential code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit UBC GIC GNC CBC DCB
Current: 7a15cff1f11193467898da1c1fabf06fd2caee04 vs 84a3778c79c2d28b4dc281d03ef2ab019b16483b Lines: 94.4 % 284 268 16 1 2 265 2
Current Date: 2025-12-15 18:36:29 -0500 Functions: 100.0 % 10 10 2 8
Baseline: lcov-20251216-010103-baseline Branches: 80.5 % 215 173 42 173
Baseline Date: 2025-12-15 13:30:48 -0800 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 2 2 2
(30,360] days: 100.0 % 4 4 4
(360..) days: 94.2 % 278 262 16 1 261
Function coverage date bins:
(360..) days: 100.0 % 10 10 2 8
Branch coverage date bins:
(30,360] days: 50.0 % 4 2 2 2
(360..) days: 81.0 % 211 171 40 171

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

Generated by: LCOV version 2.4-beta