PostgreSQL Source Code  git master
execIndexing.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/relscan.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/index.h"
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "storage/lmgr.h"
#include "utils/snapmgr.h"
Include dependency graph for execIndexing.c:

Go to the source code of this file.

Enumerations

enum  CEOUC_WAIT_MODE { CEOUC_WAIT, CEOUC_NOWAIT, CEOUC_LIVELOCK_PREVENTING_WAIT }
 

Functions

static bool check_exclusion_or_unique_constraint (Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool errorOK, ItemPointer conflictTid)
 
static bool index_recheck_constraint (Relation index, Oid *constr_procs, Datum *existing_values, bool *existing_isnull, Datum *new_values)
 
void ExecOpenIndices (ResultRelInfo *resultRelInfo, bool speculative)
 
void ExecCloseIndices (ResultRelInfo *resultRelInfo)
 
ListExecInsertIndexTuples (TupleTableSlot *slot, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
 
bool ExecCheckIndexConstraints (TupleTableSlot *slot, EState *estate, ItemPointer conflictTid, List *arbiterIndexes)
 
void check_exclusion_constraint (Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex)
 

Enumeration Type Documentation

◆ CEOUC_WAIT_MODE

Enumerator
CEOUC_WAIT 
CEOUC_NOWAIT 
CEOUC_LIVELOCK_PREVENTING_WAIT 

Definition at line 120 of file execIndexing.c.

Function Documentation

◆ check_exclusion_constraint()

void check_exclusion_constraint ( Relation  heap,
Relation  index,
IndexInfo indexInfo,
ItemPointer  tupleid,
Datum values,
bool isnull,
EState estate,
bool  newIndex 
)

Definition at line 866 of file execIndexing.c.

References CEOUC_WAIT, and check_exclusion_or_unique_constraint().

Referenced by exec_rt_fetch(), IndexCheckExclusion(), and unique_key_recheck().

871 {
872  (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
873  values, isnull,
874  estate, newIndex,
875  CEOUC_WAIT, false, NULL);
876 }
static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool errorOK, ItemPointer conflictTid)
Definition: execIndexing.c:646
static Datum values[MAXATTR]
Definition: bootstrap.c:167

◆ check_exclusion_or_unique_constraint()

static bool check_exclusion_or_unique_constraint ( Relation  heap,
Relation  index,
IndexInfo indexInfo,
ItemPointer  tupleid,
Datum values,
bool isnull,
EState estate,
bool  newIndex,
CEOUC_WAIT_MODE  waitMode,
bool  errorOK,
ItemPointer  conflictTid 
)
static

Definition at line 646 of file execIndexing.c.

References BuildIndexValueDescription(), CEOUC_LIVELOCK_PREVENTING_WAIT, CEOUC_WAIT, ExprContext::ecxt_scantuple, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, errtableconstraint(), ExecDropSingleTupleTableSlot(), FormIndexDatum(), ForwardScanDirection, GetCurrentTransactionId(), GetPerTupleExprContext, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_UniqueProcs, IndexInfo::ii_UniqueStrats, index_beginscan(), index_endscan(), index_getnext_slot(), INDEX_MAX_KEYS, index_recheck_constraint(), index_rescan(), IndexRelationGetNumberOfKeyAttributes, InitDirtySnapshot, InvalidOid, ItemPointerEquals(), ItemPointerIsValid, RelationData::rd_indcollation, RelationGetRelationName, ScanKeyEntryInitialize(), SpeculativeInsertionWait(), SnapshotData::speculativeToken, table_slot_create(), TransactionIdIsValid, TransactionIdPrecedes(), TupleTableSlot::tts_tid, XactLockTableWait(), XLTW_InsertIndex, XLTW_RecheckExclusionConstr, SnapshotData::xmax, SnapshotData::xmin, and IndexScanDescData::xs_recheck.

Referenced by check_exclusion_constraint(), ExecCheckIndexConstraints(), and ExecInsertIndexTuples().

654 {
655  Oid *constr_procs;
656  uint16 *constr_strats;
657  Oid *index_collations = index->rd_indcollation;
658  int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
659  IndexScanDesc index_scan;
660  ScanKeyData scankeys[INDEX_MAX_KEYS];
661  SnapshotData DirtySnapshot;
662  int i;
663  bool conflict;
664  bool found_self;
665  ExprContext *econtext;
666  TupleTableSlot *existing_slot;
667  TupleTableSlot *save_scantuple;
668 
669  if (indexInfo->ii_ExclusionOps)
670  {
671  constr_procs = indexInfo->ii_ExclusionProcs;
672  constr_strats = indexInfo->ii_ExclusionStrats;
673  }
674  else
675  {
676  constr_procs = indexInfo->ii_UniqueProcs;
677  constr_strats = indexInfo->ii_UniqueStrats;
678  }
679 
680  /*
681  * If any of the input values are NULL, the constraint check is assumed to
682  * pass (i.e., we assume the operators are strict).
683  */
684  for (i = 0; i < indnkeyatts; i++)
685  {
686  if (isnull[i])
687  return true;
688  }
689 
690  /*
691  * Search the tuples that are in the index for any violations, including
692  * tuples that aren't visible yet.
693  */
694  InitDirtySnapshot(DirtySnapshot);
695 
696  for (i = 0; i < indnkeyatts; i++)
697  {
698  ScanKeyEntryInitialize(&scankeys[i],
699  0,
700  i + 1,
701  constr_strats[i],
702  InvalidOid,
703  index_collations[i],
704  constr_procs[i],
705  values[i]);
706  }
707 
708  /*
709  * Need a TupleTableSlot to put existing tuples in.
710  *
711  * To use FormIndexDatum, we have to make the econtext's scantuple point
712  * to this slot. Be sure to save and restore caller's value for
713  * scantuple.
714  */
715  existing_slot = table_slot_create(heap, NULL);
716 
717  econtext = GetPerTupleExprContext(estate);
718  save_scantuple = econtext->ecxt_scantuple;
719  econtext->ecxt_scantuple = existing_slot;
720 
721  /*
722  * May have to restart scan from this point if a potential conflict is
723  * found.
724  */
725 retry:
726  conflict = false;
727  found_self = false;
728  index_scan = index_beginscan(heap, index, &DirtySnapshot, indnkeyatts, 0);
729  index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
730 
731  while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
732  {
733  TransactionId xwait;
734  XLTW_Oper reason_wait;
735  Datum existing_values[INDEX_MAX_KEYS];
736  bool existing_isnull[INDEX_MAX_KEYS];
737  char *error_new;
738  char *error_existing;
739 
740  /*
741  * Ignore the entry for the tuple we're trying to check.
742  */
743  if (ItemPointerIsValid(tupleid) &&
744  ItemPointerEquals(tupleid, &existing_slot->tts_tid))
745  {
746  if (found_self) /* should not happen */
747  elog(ERROR, "found self tuple multiple times in index \"%s\"",
748  RelationGetRelationName(index));
749  found_self = true;
750  continue;
751  }
752 
753  /*
754  * Extract the index column values and isnull flags from the existing
755  * tuple.
756  */
757  FormIndexDatum(indexInfo, existing_slot, estate,
758  existing_values, existing_isnull);
759 
760  /* If lossy indexscan, must recheck the condition */
761  if (index_scan->xs_recheck)
762  {
763  if (!index_recheck_constraint(index,
764  constr_procs,
765  existing_values,
766  existing_isnull,
767  values))
768  continue; /* tuple doesn't actually match, so no
769  * conflict */
770  }
771 
772  /*
773  * At this point we have either a conflict or a potential conflict.
774  *
775  * If an in-progress transaction is affecting the visibility of this
776  * tuple, we need to wait for it to complete and then recheck (unless
777  * the caller requested not to). For simplicity we do rechecking by
778  * just restarting the whole scan --- this case probably doesn't
779  * happen often enough to be worth trying harder, and anyway we don't
780  * want to hold any index internal locks while waiting.
781  */
782  xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
783  DirtySnapshot.xmin : DirtySnapshot.xmax;
784 
785  if (TransactionIdIsValid(xwait) &&
786  (waitMode == CEOUC_WAIT ||
787  (waitMode == CEOUC_LIVELOCK_PREVENTING_WAIT &&
788  DirtySnapshot.speculativeToken &&
790  {
791  reason_wait = indexInfo->ii_ExclusionOps ?
793  index_endscan(index_scan);
794  if (DirtySnapshot.speculativeToken)
795  SpeculativeInsertionWait(DirtySnapshot.xmin,
796  DirtySnapshot.speculativeToken);
797  else
798  XactLockTableWait(xwait, heap,
799  &existing_slot->tts_tid, reason_wait);
800  goto retry;
801  }
802 
803  /*
804  * We have a definite conflict (or a potential one, but the caller
805  * didn't want to wait). Return it to caller, or report it.
806  */
807  if (violationOK)
808  {
809  conflict = true;
810  if (conflictTid)
811  *conflictTid = existing_slot->tts_tid;
812  break;
813  }
814 
815  error_new = BuildIndexValueDescription(index, values, isnull);
816  error_existing = BuildIndexValueDescription(index, existing_values,
817  existing_isnull);
818  if (newIndex)
819  ereport(ERROR,
820  (errcode(ERRCODE_EXCLUSION_VIOLATION),
821  errmsg("could not create exclusion constraint \"%s\"",
822  RelationGetRelationName(index)),
823  error_new && error_existing ?
824  errdetail("Key %s conflicts with key %s.",
825  error_new, error_existing) :
826  errdetail("Key conflicts exist."),
827  errtableconstraint(heap,
828  RelationGetRelationName(index))));
829  else
830  ereport(ERROR,
831  (errcode(ERRCODE_EXCLUSION_VIOLATION),
832  errmsg("conflicting key value violates exclusion constraint \"%s\"",
833  RelationGetRelationName(index)),
834  error_new && error_existing ?
835  errdetail("Key %s conflicts with existing key %s.",
836  error_new, error_existing) :
837  errdetail("Key conflicts with existing key."),
838  errtableconstraint(heap,
839  RelationGetRelationName(index))));
840  }
841 
842  index_endscan(index_scan);
843 
844  /*
845  * Ordinarily, at this point the search should have found the originally
846  * inserted tuple (if any), unless we exited the loop early because of
847  * conflict. However, it is possible to define exclusion constraints for
848  * which that wouldn't be true --- for instance, if the operator is <>. So
849  * we no longer complain if found_self is still false.
850  */
851 
852  econtext->ecxt_scantuple = save_scantuple;
853 
854  ExecDropSingleTupleTableSlot(existing_slot);
855 
856  return !conflict;
857 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2567
uint16 * ii_UniqueStrats
Definition: execnodes.h:168
#define InitDirtySnapshot(snapshotdata)
Definition: snapmgr.h:76
uint32 TransactionId
Definition: c.h:514
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
Oid * ii_ExclusionProcs
Definition: execnodes.h:164
int errcode(int sqlerrcode)
Definition: elog.c:608
unsigned int Oid
Definition: postgres_ext.h:31
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5272
unsigned short uint16
Definition: c.h:358
Oid * rd_indcollation
Definition: rel.h:168
static bool index_recheck_constraint(Relation index, Oid *constr_procs, Datum *existing_values, bool *existing_isnull, Datum *new_values)
Definition: execIndexing.c:883
#define ERROR
Definition: elog.h:43
void SpeculativeInsertionWait(TransactionId xid, uint32 token)
Definition: lmgr.c:781
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:422
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition: scankey.c:32
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
Oid * ii_UniqueProcs
Definition: execnodes.h:167
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define RelationGetRelationName(relation)
Definition: rel.h:456
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:315
#define ereport(elevel, rest)
Definition: elog.h:141
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
uint32 speculativeToken
Definition: snapshot.h:193
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:624
#define INDEX_MAX_KEYS
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition: indexam.c:607
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
static Datum values[MAXATTR]
Definition: bootstrap.c:167
XLTW_Oper
Definition: lmgr.h:24
Oid * ii_ExclusionOps
Definition: execnodes.h:163
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
int i
char * BuildIndexValueDescription(Relation indexRelation, Datum *values, bool *isnull)
Definition: genam.c:176
#define TransactionIdIsValid(xid)
Definition: transam.h:41
uint16 * ii_ExclusionStrats
Definition: execnodes.h:165
ItemPointerData tts_tid
Definition: tuptable.h:130
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:197

◆ ExecCheckIndexConstraints()

bool ExecCheckIndexConstraints ( TupleTableSlot slot,
EState estate,
ItemPointer  conflictTid,
List arbiterIndexes 
)

Definition at line 482 of file execIndexing.c.

References CEOUC_WAIT, check_exclusion_or_unique_constraint(), ExprContext::ecxt_scantuple, elog, ereport, errcode(), errmsg(), ERROR, errtableconstraint(), EState::es_result_relation_info, ExecPrepareQual(), ExecQual(), FormIndexDatum(), GetPerTupleExprContext, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, INDEX_MAX_KEYS, ItemPointerSetInvalid, list_member_oid(), NIL, RelationData::rd_index, RelationGetRelationName, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, and values.

Referenced by exec_rt_fetch(), and ExecInsert().

485 {
486  ResultRelInfo *resultRelInfo;
487  int i;
488  int numIndices;
489  RelationPtr relationDescs;
490  Relation heapRelation;
491  IndexInfo **indexInfoArray;
492  ExprContext *econtext;
494  bool isnull[INDEX_MAX_KEYS];
495  ItemPointerData invalidItemPtr;
496  bool checkedIndex = false;
497 
498  ItemPointerSetInvalid(conflictTid);
499  ItemPointerSetInvalid(&invalidItemPtr);
500 
501  /*
502  * Get information from the result relation info structure.
503  */
504  resultRelInfo = estate->es_result_relation_info;
505  numIndices = resultRelInfo->ri_NumIndices;
506  relationDescs = resultRelInfo->ri_IndexRelationDescs;
507  indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
508  heapRelation = resultRelInfo->ri_RelationDesc;
509 
510  /*
511  * We will use the EState's per-tuple context for evaluating predicates
512  * and index expressions (creating it if it's not already there).
513  */
514  econtext = GetPerTupleExprContext(estate);
515 
516  /* Arrange for econtext's scan tuple to be the tuple under test */
517  econtext->ecxt_scantuple = slot;
518 
519  /*
520  * For each index, form index tuple and check if it satisfies the
521  * constraint.
522  */
523  for (i = 0; i < numIndices; i++)
524  {
525  Relation indexRelation = relationDescs[i];
526  IndexInfo *indexInfo;
527  bool satisfiesConstraint;
528 
529  if (indexRelation == NULL)
530  continue;
531 
532  indexInfo = indexInfoArray[i];
533 
534  if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
535  continue;
536 
537  /* If the index is marked as read-only, ignore it */
538  if (!indexInfo->ii_ReadyForInserts)
539  continue;
540 
541  /* When specific arbiter indexes requested, only examine them */
542  if (arbiterIndexes != NIL &&
543  !list_member_oid(arbiterIndexes,
544  indexRelation->rd_index->indexrelid))
545  continue;
546 
547  if (!indexRelation->rd_index->indimmediate)
548  ereport(ERROR,
549  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
550  errmsg("ON CONFLICT does not support deferrable unique constraints/exclusion constraints as arbiters"),
551  errtableconstraint(heapRelation,
552  RelationGetRelationName(indexRelation))));
553 
554  checkedIndex = true;
555 
556  /* Check for partial index */
557  if (indexInfo->ii_Predicate != NIL)
558  {
559  ExprState *predicate;
560 
561  /*
562  * If predicate state not set up yet, create it (in the estate's
563  * per-query context)
564  */
565  predicate = indexInfo->ii_PredicateState;
566  if (predicate == NULL)
567  {
568  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
569  indexInfo->ii_PredicateState = predicate;
570  }
571 
572  /* Skip this index-update if the predicate isn't satisfied */
573  if (!ExecQual(predicate, econtext))
574  continue;
575  }
576 
577  /*
578  * FormIndexDatum fills in its values and isnull parameters with the
579  * appropriate values for the column(s) of the index.
580  */
581  FormIndexDatum(indexInfo,
582  slot,
583  estate,
584  values,
585  isnull);
586 
587  satisfiesConstraint =
588  check_exclusion_or_unique_constraint(heapRelation, indexRelation,
589  indexInfo, &invalidItemPtr,
590  values, isnull, estate, false,
591  CEOUC_WAIT, true,
592  conflictTid);
593  if (!satisfiesConstraint)
594  return false;
595  }
596 
597  if (arbiterIndexes != NIL && !checkedIndex)
598  elog(ERROR, "unexpected failure to find arbiter index");
599 
600  return true;
601 }
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2567
int ri_NumIndices
Definition: execnodes.h:413
#define NIL
Definition: pg_list.h:65
Relation ri_RelationDesc
Definition: execnodes.h:410
List * ii_Predicate
Definition: execnodes.h:161
ExprState * ii_PredicateState
Definition: execnodes.h:162
int errcode(int sqlerrcode)
Definition: elog.c:608
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool errorOK, ItemPointer conflictTid)
Definition: execIndexing.c:646
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5272
Form_pg_index rd_index
Definition: rel.h:143
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:456
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:518
bool ii_ReadyForInserts
Definition: execnodes.h:170
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
bool ii_Unique
Definition: execnodes.h:169
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define INDEX_MAX_KEYS
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
Oid * ii_ExclusionOps
Definition: execnodes.h:163
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:419
int i
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:416
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:521

◆ ExecCloseIndices()

void ExecCloseIndices ( ResultRelInfo resultRelInfo)

Definition at line 226 of file execIndexing.c.

References i, index_close(), ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_NumIndices, and RowExclusiveLock.

Referenced by apply_handle_delete(), apply_handle_insert(), apply_handle_update(), CatalogCloseIndexes(), CopyFrom(), exec_rt_fetch(), ExecCleanupTupleRouting(), and ExecEndPlan().

227 {
228  int i;
229  int numIndices;
230  RelationPtr indexDescs;
231 
232  numIndices = resultRelInfo->ri_NumIndices;
233  indexDescs = resultRelInfo->ri_IndexRelationDescs;
234 
235  for (i = 0; i < numIndices; i++)
236  {
237  if (indexDescs[i] == NULL)
238  continue; /* shouldn't happen? */
239 
240  /* Drop lock acquired by ExecOpenIndices */
241  index_close(indexDescs[i], RowExclusiveLock);
242  }
243 
244  /*
245  * XXX should free indexInfo array here too? Currently we assume that
246  * such stuff will be cleaned up automatically in FreeExecutorState.
247  */
248 }
int ri_NumIndices
Definition: execnodes.h:413
#define RowExclusiveLock
Definition: lockdefs.h:38
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
int i
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:416

◆ ExecInsertIndexTuples()

List* ExecInsertIndexTuples ( TupleTableSlot slot,
EState estate,
bool  noDupErr,
bool specConflict,
List arbiterIndexes 
)

Definition at line 273 of file execIndexing.c.

References Assert, CEOUC_LIVELOCK_PREVENTING_WAIT, CEOUC_NOWAIT, CEOUC_WAIT, check_exclusion_or_unique_constraint(), ExprContext::ecxt_scantuple, EState::es_result_relation_info, ExecPrepareQual(), ExecQual(), FormIndexDatum(), GetPerTupleExprContext, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, index_insert(), INDEX_MAX_KEYS, ItemPointerIsValid, lappend_oid(), list_member_oid(), NIL, RelationData::rd_index, RelationGetRelid, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, TupleTableSlot::tts_tableOid, TupleTableSlot::tts_tid, UNIQUE_CHECK_NO, UNIQUE_CHECK_PARTIAL, UNIQUE_CHECK_YES, and values.

Referenced by CopyFrom(), CopyMultiInsertBufferFlush(), exec_rt_fetch(), ExecInsert(), ExecSimpleRelationInsert(), ExecSimpleRelationUpdate(), and ExecUpdate().

278 {
279  ItemPointer tupleid = &slot->tts_tid;
280  List *result = NIL;
281  ResultRelInfo *resultRelInfo;
282  int i;
283  int numIndices;
284  RelationPtr relationDescs;
285  Relation heapRelation;
286  IndexInfo **indexInfoArray;
287  ExprContext *econtext;
289  bool isnull[INDEX_MAX_KEYS];
290 
291  Assert(ItemPointerIsValid(tupleid));
292 
293  /*
294  * Get information from the result relation info structure.
295  */
296  resultRelInfo = estate->es_result_relation_info;
297  numIndices = resultRelInfo->ri_NumIndices;
298  relationDescs = resultRelInfo->ri_IndexRelationDescs;
299  indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
300  heapRelation = resultRelInfo->ri_RelationDesc;
301 
302  /* Sanity check: slot must belong to the same rel as the resultRelInfo. */
303  Assert(slot->tts_tableOid == RelationGetRelid(heapRelation));
304 
305  /*
306  * We will use the EState's per-tuple context for evaluating predicates
307  * and index expressions (creating it if it's not already there).
308  */
309  econtext = GetPerTupleExprContext(estate);
310 
311  /* Arrange for econtext's scan tuple to be the tuple under test */
312  econtext->ecxt_scantuple = slot;
313 
314  /*
315  * for each index, form and insert the index tuple
316  */
317  for (i = 0; i < numIndices; i++)
318  {
319  Relation indexRelation = relationDescs[i];
320  IndexInfo *indexInfo;
321  bool applyNoDupErr;
322  IndexUniqueCheck checkUnique;
323  bool satisfiesConstraint;
324 
325  if (indexRelation == NULL)
326  continue;
327 
328  indexInfo = indexInfoArray[i];
329 
330  /* If the index is marked as read-only, ignore it */
331  if (!indexInfo->ii_ReadyForInserts)
332  continue;
333 
334  /* Check for partial index */
335  if (indexInfo->ii_Predicate != NIL)
336  {
337  ExprState *predicate;
338 
339  /*
340  * If predicate state not set up yet, create it (in the estate's
341  * per-query context)
342  */
343  predicate = indexInfo->ii_PredicateState;
344  if (predicate == NULL)
345  {
346  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
347  indexInfo->ii_PredicateState = predicate;
348  }
349 
350  /* Skip this index-update if the predicate isn't satisfied */
351  if (!ExecQual(predicate, econtext))
352  continue;
353  }
354 
355  /*
356  * FormIndexDatum fills in its values and isnull parameters with the
357  * appropriate values for the column(s) of the index.
358  */
359  FormIndexDatum(indexInfo,
360  slot,
361  estate,
362  values,
363  isnull);
364 
365  /* Check whether to apply noDupErr to this index */
366  applyNoDupErr = noDupErr &&
367  (arbiterIndexes == NIL ||
368  list_member_oid(arbiterIndexes,
369  indexRelation->rd_index->indexrelid));
370 
371  /*
372  * The index AM does the actual insertion, plus uniqueness checking.
373  *
374  * For an immediate-mode unique index, we just tell the index AM to
375  * throw error if not unique.
376  *
377  * For a deferrable unique index, we tell the index AM to just detect
378  * possible non-uniqueness, and we add the index OID to the result
379  * list if further checking is needed.
380  *
381  * For a speculative insertion (used by INSERT ... ON CONFLICT), do
382  * the same as for a deferrable unique index.
383  */
384  if (!indexRelation->rd_index->indisunique)
385  checkUnique = UNIQUE_CHECK_NO;
386  else if (applyNoDupErr)
387  checkUnique = UNIQUE_CHECK_PARTIAL;
388  else if (indexRelation->rd_index->indimmediate)
389  checkUnique = UNIQUE_CHECK_YES;
390  else
391  checkUnique = UNIQUE_CHECK_PARTIAL;
392 
393  satisfiesConstraint =
394  index_insert(indexRelation, /* index relation */
395  values, /* array of index Datums */
396  isnull, /* null flags */
397  tupleid, /* tid of heap tuple */
398  heapRelation, /* heap relation */
399  checkUnique, /* type of uniqueness check to do */
400  indexInfo); /* index AM may need this */
401 
402  /*
403  * If the index has an associated exclusion constraint, check that.
404  * This is simpler than the process for uniqueness checks since we
405  * always insert first and then check. If the constraint is deferred,
406  * we check now anyway, but don't throw error on violation or wait for
407  * a conclusive outcome from a concurrent insertion; instead we'll
408  * queue a recheck event. Similarly, noDupErr callers (speculative
409  * inserters) will recheck later, and wait for a conclusive outcome
410  * then.
411  *
412  * An index for an exclusion constraint can't also be UNIQUE (not an
413  * essential property, we just don't allow it in the grammar), so no
414  * need to preserve the prior state of satisfiesConstraint.
415  */
416  if (indexInfo->ii_ExclusionOps != NULL)
417  {
418  bool violationOK;
419  CEOUC_WAIT_MODE waitMode;
420 
421  if (applyNoDupErr)
422  {
423  violationOK = true;
425  }
426  else if (!indexRelation->rd_index->indimmediate)
427  {
428  violationOK = true;
429  waitMode = CEOUC_NOWAIT;
430  }
431  else
432  {
433  violationOK = false;
434  waitMode = CEOUC_WAIT;
435  }
436 
437  satisfiesConstraint =
439  indexRelation, indexInfo,
440  tupleid, values, isnull,
441  estate, false,
442  waitMode, violationOK, NULL);
443  }
444 
445  if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
446  indexInfo->ii_ExclusionOps != NULL) &&
447  !satisfiesConstraint)
448  {
449  /*
450  * The tuple potentially violates the uniqueness or exclusion
451  * constraint, so make a note of the index so that we can re-check
452  * it later. Speculative inserters are told if there was a
453  * speculative conflict, since that always requires a restart.
454  */
455  result = lappend_oid(result, RelationGetRelid(indexRelation));
456  if (indexRelation->rd_index->indimmediate && specConflict)
457  *specConflict = true;
458  }
459  }
460 
461  return result;
462 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2567
int ri_NumIndices
Definition: execnodes.h:413
#define NIL
Definition: pg_list.h:65
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:410
List * ii_Predicate
Definition: execnodes.h:161
ExprState * ii_PredicateState
Definition: execnodes.h:162
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool errorOK, ItemPointer conflictTid)
Definition: execIndexing.c:646
IndexUniqueCheck
Definition: genam.h:112
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
Form_pg_index rd_index
Definition: rel.h:143
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:518
bool ii_ReadyForInserts
Definition: execnodes.h:170
uintptr_t Datum
Definition: postgres.h:367
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define Assert(condition)
Definition: c.h:739
#define INDEX_MAX_KEYS
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
static Datum values[MAXATTR]
Definition: bootstrap.c:167
Oid * ii_ExclusionOps
Definition: execnodes.h:163
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:419
int i
CEOUC_WAIT_MODE
Definition: execIndexing.c:120
Definition: pg_list.h:50
ItemPointerData tts_tid
Definition: tuptable.h:130
#define RelationGetRelid(relation)
Definition: rel.h:422
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:416
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: indexam.c:170
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:521

◆ ExecOpenIndices()

void ExecOpenIndices ( ResultRelInfo resultRelInfo,
bool  speculative 
)

Definition at line 151 of file execIndexing.c.

References BuildIndexInfo(), BuildSpeculativeIndexInfo(), i, IndexInfo::ii_Unique, index_open(), lfirst_oid, list_free(), list_length(), palloc(), RelationGetForm, RelationGetIndexList(), relhasindex, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, and RowExclusiveLock.

Referenced by apply_handle_delete(), apply_handle_insert(), apply_handle_update(), CatalogOpenIndexes(), CopyFrom(), exec_rt_fetch(), ExecInitModifyTable(), and ExecInitPartitionInfo().

152 {
153  Relation resultRelation = resultRelInfo->ri_RelationDesc;
154  List *indexoidlist;
155  ListCell *l;
156  int len,
157  i;
158  RelationPtr relationDescs;
159  IndexInfo **indexInfoArray;
160 
161  resultRelInfo->ri_NumIndices = 0;
162 
163  /* fast path if no indexes */
164  if (!RelationGetForm(resultRelation)->relhasindex)
165  return;
166 
167  /*
168  * Get cached list of index OIDs
169  */
170  indexoidlist = RelationGetIndexList(resultRelation);
171  len = list_length(indexoidlist);
172  if (len == 0)
173  return;
174 
175  /*
176  * allocate space for result arrays
177  */
178  relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
179  indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
180 
181  resultRelInfo->ri_NumIndices = len;
182  resultRelInfo->ri_IndexRelationDescs = relationDescs;
183  resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
184 
185  /*
186  * For each index, open the index relation and save pg_index info. We
187  * acquire RowExclusiveLock, signifying we will update the index.
188  *
189  * Note: we do this even if the index is not indisready; it's not worth
190  * the trouble to optimize for the case where it isn't.
191  */
192  i = 0;
193  foreach(l, indexoidlist)
194  {
195  Oid indexOid = lfirst_oid(l);
196  Relation indexDesc;
197  IndexInfo *ii;
198 
199  indexDesc = index_open(indexOid, RowExclusiveLock);
200 
201  /* extract index key information from the index's pg_index info */
202  ii = BuildIndexInfo(indexDesc);
203 
204  /*
205  * If the indexes are to be used for speculative insertion, add extra
206  * information required by unique index entries.
207  */
208  if (speculative && ii->ii_Unique)
209  BuildSpeculativeIndexInfo(indexDesc, ii);
210 
211  relationDescs[i] = indexDesc;
212  indexInfoArray[i] = ii;
213  i++;
214  }
215 
216  list_free(indexoidlist);
217 }
int ri_NumIndices
Definition: execnodes.h:413
Relation ri_RelationDesc
Definition: execnodes.h:410
#define RelationGetForm(relation)
Definition: rel.h:416
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2285
unsigned int Oid
Definition: postgres_ext.h:31
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation * RelationPtr
Definition: relcache.h:34
bool ii_Unique
Definition: execnodes.h:169
bool relhasindex
Definition: pg_class.h:72
static int list_length(const List *l)
Definition: pg_list.h:169
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4347
void * palloc(Size size)
Definition: mcxt.c:949
void list_free(List *list)
Definition: list.c:1377
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:419
int i
void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
Definition: index.c:2507
Definition: pg_list.h:50
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:416
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ index_recheck_constraint()

static bool index_recheck_constraint ( Relation  index,
Oid constr_procs,
Datum existing_values,
bool existing_isnull,
Datum new_values 
)
static

Definition at line 883 of file execIndexing.c.

References DatumGetBool, i, IndexRelationGetNumberOfKeyAttributes, OidFunctionCall2Coll(), and RelationData::rd_indcollation.

Referenced by check_exclusion_or_unique_constraint().

886 {
887  int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
888  int i;
889 
890  for (i = 0; i < indnkeyatts; i++)
891  {
892  /* Assume the exclusion operators are strict */
893  if (existing_isnull[i])
894  return false;
895 
896  if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
897  index->rd_indcollation[i],
898  existing_values[i],
899  new_values[i])))
900  return false;
901  }
902 
903  return true;
904 }
Oid * rd_indcollation
Definition: rel.h:168
#define DatumGetBool(X)
Definition: postgres.h:393
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1422
int i