LCOV - differential code coverage report
Current view: top level - src/backend/executor - execIndexing.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 93.0 % 258 240 18 3 237 1
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 9 9 2 7 1
Baseline: 16@8cea358b128 Branches: 80.3 % 198 159 39 159
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (120,180] days: 100.0 % 2 2 2
(180,240] days: 100.0 % 1 1 1
(240..) days: 92.9 % 255 237 18 237
Function coverage date bins:
(180,240] days: 100.0 % 1 1 1
(240..) days: 100.0 % 8 8 1 7
Branch coverage date bins:
(240..) days: 80.3 % 198 159 39 159

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

Generated by: LCOV version 2.1-beta2-3-g6141622