PostgreSQL Source Code  git master
index.h File Reference
Include dependency graph for index.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ReindexParams
 
struct  ValidateIndexState
 

Macros

#define DEFAULT_INDEX_TYPE   "btree"
 
#define REINDEXOPT_VERBOSE   0x01 /* print progress info */
 
#define REINDEXOPT_REPORT_PROGRESS   0x02 /* report pgstat progress */
 
#define REINDEXOPT_MISSING_OK   0x04 /* skip missing relations */
 
#define REINDEXOPT_CONCURRENTLY   0x08 /* concurrent mode */
 
#define INDEX_CREATE_IS_PRIMARY   (1 << 0)
 
#define INDEX_CREATE_ADD_CONSTRAINT   (1 << 1)
 
#define INDEX_CREATE_SKIP_BUILD   (1 << 2)
 
#define INDEX_CREATE_CONCURRENT   (1 << 3)
 
#define INDEX_CREATE_IF_NOT_EXISTS   (1 << 4)
 
#define INDEX_CREATE_PARTITIONED   (1 << 5)
 
#define INDEX_CREATE_INVALID   (1 << 6)
 
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)
 
#define INDEX_CONSTR_CREATE_DEFERRABLE   (1 << 1)
 
#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)
 
#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)
 
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)
 
#define REINDEX_REL_PROCESS_TOAST   0x01
 
#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02
 
#define REINDEX_REL_CHECK_CONSTRAINTS   0x04
 
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08
 
#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10
 

Typedefs

typedef struct ReindexParams ReindexParams
 
typedef struct ValidateIndexState ValidateIndexState
 

Enumerations

enum  IndexStateFlagsAction { INDEX_CREATE_SET_READY , INDEX_CREATE_SET_VALID , INDEX_DROP_CLEAR_VALID , INDEX_DROP_SET_DEAD }
 

Functions

void index_check_primary_key (Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
 
Oid index_create (Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const int16 *coloptions, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
 
Oid index_concurrently_create_copy (Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
 
void index_concurrently_build (Oid heapRelationId, Oid indexRelationId)
 
void index_concurrently_swap (Oid newIndexId, Oid oldIndexId, const char *oldName)
 
void index_concurrently_set_dead (Oid heapId, Oid indexId)
 
ObjectAddress index_constraint_create (Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
 
void index_drop (Oid indexId, bool concurrent, bool concurrent_lock_mode)
 
IndexInfoBuildIndexInfo (Relation index)
 
IndexInfoBuildDummyIndexInfo (Relation index)
 
bool CompareIndexInfo (const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
 
void BuildSpeculativeIndexInfo (Relation index, IndexInfo *ii)
 
void FormIndexDatum (IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
void index_build (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
 
void validate_index (Oid heapId, Oid indexId, Snapshot snapshot)
 
void index_set_state_flags (Oid indexId, IndexStateFlagsAction action)
 
Oid IndexGetRelation (Oid indexId, bool missing_ok)
 
void reindex_index (Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
 
bool reindex_relation (Oid relid, int flags, const ReindexParams *params)
 
bool ReindexIsProcessingHeap (Oid heapOid)
 
bool ReindexIsProcessingIndex (Oid indexOid)
 
void ResetReindexState (int nestLevel)
 
Size EstimateReindexStateSpace (void)
 
void SerializeReindexState (Size maxsize, char *start_address)
 
void RestoreReindexState (const void *reindexstate)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 
static int64 itemptr_encode (ItemPointer itemptr)
 
static void itemptr_decode (ItemPointer itemptr, int64 encoded)
 

Macro Definition Documentation

◆ DEFAULT_INDEX_TYPE

#define DEFAULT_INDEX_TYPE   "btree"

Definition at line 21 of file index.h.

◆ INDEX_CONSTR_CREATE_DEFERRABLE

#define INDEX_CONSTR_CREATE_DEFERRABLE   (1 << 1)

Definition at line 90 of file index.h.

◆ INDEX_CONSTR_CREATE_INIT_DEFERRED

#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)

Definition at line 91 of file index.h.

◆ INDEX_CONSTR_CREATE_MARK_AS_PRIMARY

#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)

Definition at line 89 of file index.h.

◆ INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS

#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)

Definition at line 93 of file index.h.

◆ INDEX_CONSTR_CREATE_UPDATE_INDEX

#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)

Definition at line 92 of file index.h.

◆ INDEX_CREATE_ADD_CONSTRAINT

#define INDEX_CREATE_ADD_CONSTRAINT   (1 << 1)

Definition at line 62 of file index.h.

◆ INDEX_CREATE_CONCURRENT

#define INDEX_CREATE_CONCURRENT   (1 << 3)

Definition at line 64 of file index.h.

◆ INDEX_CREATE_IF_NOT_EXISTS

#define INDEX_CREATE_IF_NOT_EXISTS   (1 << 4)

Definition at line 65 of file index.h.

◆ INDEX_CREATE_INVALID

#define INDEX_CREATE_INVALID   (1 << 6)

Definition at line 67 of file index.h.

◆ INDEX_CREATE_IS_PRIMARY

#define INDEX_CREATE_IS_PRIMARY   (1 << 0)

Definition at line 61 of file index.h.

◆ INDEX_CREATE_PARTITIONED

#define INDEX_CREATE_PARTITIONED   (1 << 5)

Definition at line 66 of file index.h.

◆ INDEX_CREATE_SKIP_BUILD

#define INDEX_CREATE_SKIP_BUILD   (1 << 2)

Definition at line 63 of file index.h.

◆ REINDEX_REL_CHECK_CONSTRAINTS

#define REINDEX_REL_CHECK_CONSTRAINTS   0x04

Definition at line 157 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_PERMANENT

#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10

Definition at line 159 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_UNLOGGED

#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08

Definition at line 158 of file index.h.

◆ REINDEX_REL_PROCESS_TOAST

#define REINDEX_REL_PROCESS_TOAST   0x01

Definition at line 155 of file index.h.

◆ REINDEX_REL_SUPPRESS_INDEX_USE

#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02

Definition at line 156 of file index.h.

◆ REINDEXOPT_CONCURRENTLY

#define REINDEXOPT_CONCURRENTLY   0x08 /* concurrent mode */

Definition at line 44 of file index.h.

◆ REINDEXOPT_MISSING_OK

#define REINDEXOPT_MISSING_OK   0x04 /* skip missing relations */

Definition at line 43 of file index.h.

◆ REINDEXOPT_REPORT_PROGRESS

#define REINDEXOPT_REPORT_PROGRESS   0x02 /* report pgstat progress */

Definition at line 42 of file index.h.

◆ REINDEXOPT_VERBOSE

#define REINDEXOPT_VERBOSE   0x01 /* print progress info */

Definition at line 41 of file index.h.

Typedef Documentation

◆ ReindexParams

typedef struct ReindexParams ReindexParams

◆ ValidateIndexState

Enumeration Type Documentation

◆ IndexStateFlagsAction

Enumerator
INDEX_CREATE_SET_READY 
INDEX_CREATE_SET_VALID 
INDEX_DROP_CLEAR_VALID 
INDEX_DROP_SET_DEAD 

Definition at line 24 of file index.h.

25 {
IndexStateFlagsAction
Definition: index.h:25
@ INDEX_CREATE_SET_VALID
Definition: index.h:27
@ INDEX_DROP_CLEAR_VALID
Definition: index.h:28
@ INDEX_DROP_SET_DEAD
Definition: index.h:29
@ INDEX_CREATE_SET_READY
Definition: index.h:26

Function Documentation

◆ BuildDummyIndexInfo()

IndexInfo* BuildDummyIndexInfo ( Relation  index)

Definition at line 2487 of file index.c.

2488 {
2489  IndexInfo *ii;
2490  Form_pg_index indexStruct = index->rd_index;
2491  int i;
2492  int numAtts;
2493 
2494  /* check the number of keys, and copy attr numbers into the IndexInfo */
2495  numAtts = indexStruct->indnatts;
2496  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2497  elog(ERROR, "invalid indnatts %d for index %u",
2498  numAtts, RelationGetRelid(index));
2499 
2500  /*
2501  * Create the node, using dummy index expressions, and pretending there is
2502  * no predicate.
2503  */
2504  ii = makeIndexInfo(indexStruct->indnatts,
2505  indexStruct->indnkeyatts,
2506  index->rd_rel->relam,
2508  NIL,
2509  indexStruct->indisunique,
2510  indexStruct->indnullsnotdistinct,
2511  indexStruct->indisready,
2512  false,
2513  index->rd_indam->amsummarizing);
2514 
2515  /* fill in attribute numbers */
2516  for (i = 0; i < numAtts; i++)
2517  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2518 
2519  /* We ignore the exclusion constraint if any */
2520 
2521  return ii;
2522 }
#define ERROR
Definition: elog.h:39
int i
Definition: isn.c:73
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing)
Definition: makefuncs.c:746
#define INDEX_MAX_KEYS
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define NIL
Definition: pg_list.h:68
#define RelationGetRelid(relation)
Definition: rel.h:504
List * RelationGetDummyIndexExpressions(Relation relation)
Definition: relcache.c:5055
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:179
Definition: type.h:95

References elog(), ERROR, i, IndexInfo::ii_IndexAttrNumbers, INDEX_MAX_KEYS, makeIndexInfo(), NIL, RelationGetDummyIndexExpressions(), and RelationGetRelid.

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo* BuildIndexInfo ( Relation  index)

Definition at line 2426 of file index.c.

2427 {
2428  IndexInfo *ii;
2429  Form_pg_index indexStruct = index->rd_index;
2430  int i;
2431  int numAtts;
2432 
2433  /* check the number of keys, and copy attr numbers into the IndexInfo */
2434  numAtts = indexStruct->indnatts;
2435  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2436  elog(ERROR, "invalid indnatts %d for index %u",
2437  numAtts, RelationGetRelid(index));
2438 
2439  /*
2440  * Create the node, fetching any expressions needed for expressional
2441  * indexes and index predicate if any.
2442  */
2443  ii = makeIndexInfo(indexStruct->indnatts,
2444  indexStruct->indnkeyatts,
2445  index->rd_rel->relam,
2448  indexStruct->indisunique,
2449  indexStruct->indnullsnotdistinct,
2450  indexStruct->indisready,
2451  false,
2452  index->rd_indam->amsummarizing);
2453 
2454  /* fill in attribute numbers */
2455  for (i = 0; i < numAtts; i++)
2456  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2457 
2458  /* fetch exclusion constraint info if any */
2459  if (indexStruct->indisexclusion)
2460  {
2462  &ii->ii_ExclusionOps,
2463  &ii->ii_ExclusionProcs,
2464  &ii->ii_ExclusionStrats);
2465  }
2466 
2468 
2469  return ii;
2470 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5109
Datum * RelationGetIndexRawAttOptions(Relation indexrel)
Definition: relcache.c:5828
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5545
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4996
uint16 * ii_ExclusionStrats
Definition: execnodes.h:186
Datum * ii_OpclassOptions
Definition: execnodes.h:190
Oid * ii_ExclusionOps
Definition: execnodes.h:184
Oid * ii_ExclusionProcs
Definition: execnodes.h:185

References elog(), ERROR, i, if(), IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_OpclassOptions, INDEX_MAX_KEYS, makeIndexInfo(), RelationGetExclusionInfo(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), RelationGetIndexRawAttOptions(), and RelationGetRelid.

Referenced by _bt_parallel_scan_and_sort(), ATExecAddIndexConstraint(), ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), brinsummarize(), bt_check_every_level(), DefineIndex(), do_analyze_rel(), ExecOpenIndices(), FindReplTupleInLocalRel(), FindUsableIndexForReplicaIdentityFull(), index_concurrently_build(), index_concurrently_create_copy(), reindex_index(), tuplesort_begin_cluster(), and validate_index().

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2666 of file index.c.

2667 {
2668  int indnkeyatts;
2669  int i;
2670 
2672 
2673  /*
2674  * fetch info for checking unique indexes
2675  */
2676  Assert(ii->ii_Unique);
2677 
2678  if (index->rd_rel->relam != BTREE_AM_OID)
2679  elog(ERROR, "unexpected non-btree speculative unique index");
2680 
2681  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2682  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2683  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2684 
2685  /*
2686  * We have to look up the operator's strategy number. This provides a
2687  * cross-check that the operator does match the index.
2688  */
2689  /* We need the func OIDs and strategy numbers too */
2690  for (i = 0; i < indnkeyatts; i++)
2691  {
2693  ii->ii_UniqueOps[i] =
2694  get_opfamily_member(index->rd_opfamily[i],
2695  index->rd_opcintype[i],
2696  index->rd_opcintype[i],
2697  ii->ii_UniqueStrats[i]);
2698  if (!OidIsValid(ii->ii_UniqueOps[i]))
2699  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2700  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2701  index->rd_opcintype[i], index->rd_opfamily[i]);
2702  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2703  }
2704 }
unsigned short uint16
Definition: c.h:494
#define OidIsValid(objectId)
Definition: c.h:764
Assert(fmt[strlen(fmt) - 1] !='\n')
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1289
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
void * palloc(Size size)
Definition: mcxt.c:1226
unsigned int Oid
Definition: postgres_ext.h:31
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:523
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ii_Unique
Definition: execnodes.h:191
Oid * ii_UniqueOps
Definition: execnodes.h:187
uint16 * ii_UniqueStrats
Definition: execnodes.h:189
Oid * ii_UniqueProcs
Definition: execnodes.h:188

References Assert(), BTEqualStrategyNumber, elog(), ERROR, get_opcode(), get_opfamily_member(), i, IndexInfo::ii_Unique, IndexInfo::ii_UniqueOps, IndexInfo::ii_UniqueProcs, IndexInfo::ii_UniqueStrats, IndexRelationGetNumberOfKeyAttributes, OidIsValid, and palloc().

Referenced by ExecOpenIndices().

◆ CompareIndexInfo()

bool CompareIndexInfo ( const IndexInfo info1,
const IndexInfo info2,
const Oid collations1,
const Oid collations2,
const Oid opfamilies1,
const Oid opfamilies2,
const AttrMap attmap 
)

Definition at line 2535 of file index.c.

2539 {
2540  int i;
2541 
2542  if (info1->ii_Unique != info2->ii_Unique)
2543  return false;
2544 
2545  if (info1->ii_NullsNotDistinct != info2->ii_NullsNotDistinct)
2546  return false;
2547 
2548  /* indexes are only equivalent if they have the same access method */
2549  if (info1->ii_Am != info2->ii_Am)
2550  return false;
2551 
2552  /* and same number of attributes */
2553  if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs)
2554  return false;
2555 
2556  /* and same number of key attributes */
2557  if (info1->ii_NumIndexKeyAttrs != info2->ii_NumIndexKeyAttrs)
2558  return false;
2559 
2560  /*
2561  * and columns match through the attribute map (actual attribute numbers
2562  * might differ!) Note that this checks that index columns that are
2563  * expressions appear in the same positions. We will next compare the
2564  * expressions themselves.
2565  */
2566  for (i = 0; i < info1->ii_NumIndexAttrs; i++)
2567  {
2568  if (attmap->maplen < info2->ii_IndexAttrNumbers[i])
2569  elog(ERROR, "incorrect attribute map");
2570 
2571  /* ignore expressions for now (but check their collation/opfamily) */
2572  if (!(info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber &&
2574  {
2575  /* fail if just one index has an expression in this column */
2576  if (info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber ||
2578  return false;
2579 
2580  /* both are columns, so check for match after mapping */
2581  if (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
2582  info1->ii_IndexAttrNumbers[i])
2583  return false;
2584  }
2585 
2586  /* collation and opfamily are not valid for included columns */
2587  if (i >= info1->ii_NumIndexKeyAttrs)
2588  continue;
2589 
2590  if (collations1[i] != collations2[i])
2591  return false;
2592  if (opfamilies1[i] != opfamilies2[i])
2593  return false;
2594  }
2595 
2596  /*
2597  * For expression indexes: either both are expression indexes, or neither
2598  * is; if they are, make sure the expressions match.
2599  */
2600  if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
2601  return false;
2602  if (info1->ii_Expressions != NIL)
2603  {
2604  bool found_whole_row;
2605  Node *mapped;
2606 
2607  mapped = map_variable_attnos((Node *) info2->ii_Expressions,
2608  1, 0, attmap,
2609  InvalidOid, &found_whole_row);
2610  if (found_whole_row)
2611  {
2612  /*
2613  * we could throw an error here, but seems out of scope for this
2614  * routine.
2615  */
2616  return false;
2617  }
2618 
2619  if (!equal(info1->ii_Expressions, mapped))
2620  return false;
2621  }
2622 
2623  /* Partial index predicates must be identical, if they exist */
2624  if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL))
2625  return false;
2626  if (info1->ii_Predicate != NULL)
2627  {
2628  bool found_whole_row;
2629  Node *mapped;
2630 
2631  mapped = map_variable_attnos((Node *) info2->ii_Predicate,
2632  1, 0, attmap,
2633  InvalidOid, &found_whole_row);
2634  if (found_whole_row)
2635  {
2636  /*
2637  * we could throw an error here, but seems out of scope for this
2638  * routine.
2639  */
2640  return false;
2641  }
2642  if (!equal(info1->ii_Predicate, mapped))
2643  return false;
2644  }
2645 
2646  /* No support currently for comparing exclusion indexes. */
2647  if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL)
2648  return false;
2649 
2650  return true;
2651 }
#define InvalidAttrNumber
Definition: attnum.h:23
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
#define InvalidOid
Definition: postgres_ext.h:36
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
int maplen
Definition: attmap.h:37
AttrNumber * attnums
Definition: attmap.h:36
int ii_NumIndexAttrs
Definition: execnodes.h:177
bool ii_NullsNotDistinct
Definition: execnodes.h:192
int ii_NumIndexKeyAttrs
Definition: execnodes.h:178
List * ii_Expressions
Definition: execnodes.h:180
Oid ii_Am
Definition: execnodes.h:200
List * ii_Predicate
Definition: execnodes.h:182
Definition: nodes.h:129

References AttrMap::attnums, elog(), equal(), ERROR, i, IndexInfo::ii_Am, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NullsNotDistinct, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, InvalidAttrNumber, InvalidOid, map_variable_attnos(), AttrMap::maplen, and NIL.

Referenced by ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), and DefineIndex().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4147 of file index.c.

4148 {
4151 }
static List * pendingReindexedIndexes
Definition: index.c:4016
static int list_length(const List *l)
Definition: pg_list.h:152
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519

References list_length(), mul_size(), and pendingReindexedIndexes.

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

void FormIndexDatum ( IndexInfo indexInfo,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)

Definition at line 2726 of file index.c.

2731 {
2732  ListCell *indexpr_item;
2733  int i;
2734 
2735  if (indexInfo->ii_Expressions != NIL &&
2736  indexInfo->ii_ExpressionsState == NIL)
2737  {
2738  /* First time through, set up expression evaluation state */
2739  indexInfo->ii_ExpressionsState =
2740  ExecPrepareExprList(indexInfo->ii_Expressions, estate);
2741  /* Check caller has set up context correctly */
2742  Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2743  }
2744  indexpr_item = list_head(indexInfo->ii_ExpressionsState);
2745 
2746  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
2747  {
2748  int keycol = indexInfo->ii_IndexAttrNumbers[i];
2749  Datum iDatum;
2750  bool isNull;
2751 
2752  if (keycol < 0)
2753  iDatum = slot_getsysattr(slot, keycol, &isNull);
2754  else if (keycol != 0)
2755  {
2756  /*
2757  * Plain index column; get the value we need directly from the
2758  * heap tuple.
2759  */
2760  iDatum = slot_getattr(slot, keycol, &isNull);
2761  }
2762  else
2763  {
2764  /*
2765  * Index expression --- need to evaluate it.
2766  */
2767  if (indexpr_item == NULL)
2768  elog(ERROR, "wrong number of index expressions");
2769  iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
2770  GetPerTupleExprContext(estate),
2771  &isNull);
2772  indexpr_item = lnext(indexInfo->ii_ExpressionsState, indexpr_item);
2773  }
2774  values[i] = iDatum;
2775  isnull[i] = isNull;
2776  }
2777 
2778  if (indexpr_item != NULL)
2779  elog(ERROR, "wrong number of index expressions");
2780 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:810
#define GetPerTupleExprContext(estate)
Definition: executor.h:549
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:347
#define lfirst(lc)
Definition: pg_list.h:172
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
uintptr_t Datum
Definition: postgres.h:64
List * ii_ExpressionsState
Definition: execnodes.h:181
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:409
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:388

References Assert(), elog(), ERROR, ExecEvalExprSwitchContext(), ExecPrepareExprList(), GetPerTupleExprContext, i, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, lfirst, list_head(), lnext(), NIL, slot_getattr(), slot_getsysattr(), and values.

Referenced by CatalogIndexInsert(), check_exclusion_or_unique_constraint(), comparetup_cluster_tiebreak(), compute_index_stats(), ExecCheckIndexConstraints(), ExecInsertIndexTuples(), heapam_index_build_range_scan(), heapam_index_validate_scan(), and IndexCheckExclusion().

◆ index_build()

void index_build ( Relation  heapRelation,
Relation  indexRelation,
IndexInfo indexInfo,
bool  isreindex,
bool  parallel 
)

Definition at line 2962 of file index.c.

2967 {
2968  IndexBuildResult *stats;
2969  Oid save_userid;
2970  int save_sec_context;
2971  int save_nestlevel;
2972 
2973  /*
2974  * sanity checks
2975  */
2976  Assert(RelationIsValid(indexRelation));
2977  Assert(PointerIsValid(indexRelation->rd_indam));
2978  Assert(PointerIsValid(indexRelation->rd_indam->ambuild));
2979  Assert(PointerIsValid(indexRelation->rd_indam->ambuildempty));
2980 
2981  /*
2982  * Determine worker process details for parallel CREATE INDEX. Currently,
2983  * only btree has support for parallel builds.
2984  *
2985  * Note that planner considers parallel safety for us.
2986  */
2987  if (parallel && IsNormalProcessingMode() &&
2988  indexRelation->rd_rel->relam == BTREE_AM_OID)
2989  indexInfo->ii_ParallelWorkers =
2991  RelationGetRelid(indexRelation));
2992 
2993  if (indexInfo->ii_ParallelWorkers == 0)
2994  ereport(DEBUG1,
2995  (errmsg_internal("building index \"%s\" on table \"%s\" serially",
2996  RelationGetRelationName(indexRelation),
2997  RelationGetRelationName(heapRelation))));
2998  else
2999  ereport(DEBUG1,
3000  (errmsg_internal("building index \"%s\" on table \"%s\" with request for %d parallel workers",
3001  RelationGetRelationName(indexRelation),
3002  RelationGetRelationName(heapRelation),
3003  indexInfo->ii_ParallelWorkers)));
3004 
3005  /*
3006  * Switch to the table owner's userid, so that any index functions are run
3007  * as that user. Also lock down security-restricted operations and
3008  * arrange to make GUC variable changes local to this command.
3009  */
3010  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3011  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3012  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3013  save_nestlevel = NewGUCNestLevel();
3014 
3015  /* Set up initial progress report status */
3016  {
3017  const int progress_index[] = {
3024  };
3025  const int64 progress_vals[] = {
3028  0, 0, 0, 0
3029  };
3030 
3031  pgstat_progress_update_multi_param(6, progress_index, progress_vals);
3032  }
3033 
3034  /*
3035  * Call the access method's build procedure
3036  */
3037  stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation,
3038  indexInfo);
3039  Assert(PointerIsValid(stats));
3040 
3041  /*
3042  * If this is an unlogged index, we may need to write out an init fork for
3043  * it -- but we must first check whether one already exists. If, for
3044  * example, an unlogged relation is truncated in the transaction that
3045  * created it, or truncated twice in a subsequent transaction, the
3046  * relfilenumber won't change, and nothing needs to be done here.
3047  */
3048  if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
3049  !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
3050  {
3051  smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3052  log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
3053  indexRelation->rd_indam->ambuildempty(indexRelation);
3054  }
3055 
3056  /*
3057  * If we found any potentially broken HOT chains, mark the index as not
3058  * being usable until the current transaction is below the event horizon.
3059  * See src/backend/access/heap/README.HOT for discussion. While it might
3060  * become safe to use the index earlier based on actual cleanup activity
3061  * and other active transactions, the test for that would be much more
3062  * complex and would require some form of blocking, so keep it simple and
3063  * fast by just using the current transaction.
3064  *
3065  * However, when reindexing an existing index, we should do nothing here.
3066  * Any HOT chains that are broken with respect to the index must predate
3067  * the index's original creation, so there is no need to change the
3068  * index's usability horizon. Moreover, we *must not* try to change the
3069  * index's pg_index entry while reindexing pg_index itself, and this
3070  * optimization nicely prevents that. The more complex rules needed for a
3071  * reindex are handled separately after this function returns.
3072  *
3073  * We also need not set indcheckxmin during a concurrent index build,
3074  * because we won't set indisvalid true until all transactions that care
3075  * about the broken HOT chains are gone.
3076  *
3077  * Therefore, this code path can only be taken during non-concurrent
3078  * CREATE INDEX. Thus the fact that heap_update will set the pg_index
3079  * tuple's xmin doesn't matter, because that tuple was created in the
3080  * current transaction anyway. That also means we don't need to worry
3081  * about any concurrent readers of the tuple; no other transaction can see
3082  * it yet.
3083  */
3084  if (indexInfo->ii_BrokenHotChain &&
3085  !isreindex &&
3086  !indexInfo->ii_Concurrent)
3087  {
3088  Oid indexId = RelationGetRelid(indexRelation);
3089  Relation pg_index;
3090  HeapTuple indexTuple;
3091  Form_pg_index indexForm;
3092 
3093  pg_index = table_open(IndexRelationId, RowExclusiveLock);
3094 
3095  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3096  ObjectIdGetDatum(indexId));
3097  if (!HeapTupleIsValid(indexTuple))
3098  elog(ERROR, "cache lookup failed for index %u", indexId);
3099  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3100 
3101  /* If it's a new index, indcheckxmin shouldn't be set ... */
3102  Assert(!indexForm->indcheckxmin);
3103 
3104  indexForm->indcheckxmin = true;
3105  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3106 
3107  heap_freetuple(indexTuple);
3108  table_close(pg_index, RowExclusiveLock);
3109  }
3110 
3111  /*
3112  * Update heap and index pg_class rows
3113  */
3114  index_update_stats(heapRelation,
3115  true,
3116  stats->heap_tuples);
3117 
3118  index_update_stats(indexRelation,
3119  false,
3120  stats->index_tuples);
3121 
3122  /* Make the updated catalog row versions visible */
3124 
3125  /*
3126  * If it's for an exclusion constraint, make a second pass over the heap
3127  * to verify that the constraint is satisfied. We must not do this until
3128  * the index is fully valid. (Broken HOT chains shouldn't matter, though;
3129  * see comments for IndexCheckExclusion.)
3130  */
3131  if (indexInfo->ii_ExclusionOps != NULL)
3132  IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
3133 
3134  /* Roll back any GUC changes executed by index functions */
3135  AtEOXact_GUC(false, save_nestlevel);
3136 
3137  /* Restore userid and security context */
3138  SetUserIdAndSecContext(save_userid, save_sec_context);
3139 }
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
#define PointerIsValid(pointer)
Definition: c.h:752
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1156
#define DEBUG1
Definition: elog.h:30
#define ereport(elevel,...)
Definition: elog.h:149
int NewGUCNestLevel(void)
Definition: guc.c:2201
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2215
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static void index_update_stats(Relation rel, bool hasindex, double reltuples)
Definition: index.c:2805
static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
Definition: index.c:3154
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:314
#define IsNormalProcessingMode()
Definition: miscadmin.h:416
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:630
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:637
int plan_create_index_workers(Oid tableOid, Oid indexOid)
Definition: planner.c:6689
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition: progress.h:94
#define PROGRESS_CREATEIDX_TUPLES_TOTAL
Definition: progress.h:86
#define PROGRESS_SCAN_BLOCKS_DONE
Definition: progress.h:122
#define PROGRESS_CREATEIDX_TUPLES_DONE
Definition: progress.h:87
#define PROGRESS_CREATEIDX_SUBPHASE
Definition: progress.h:85
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition: progress.h:106
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:84
#define PROGRESS_SCAN_BLOCKS_TOTAL
Definition: progress.h:121
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:572
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationIsValid(relation)
Definition: rel.h:477
@ INIT_FORKNUM
Definition: relpath.h:53
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:374
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:251
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:185
ItemPointerData t_self
Definition: htup.h:65
ambuildempty_function ambuildempty
Definition: amapi.h:262
ambuild_function ambuild
Definition: amapi.h:261
double heap_tuples
Definition: genam.h:32
double index_tuples
Definition: genam.h:33
bool ii_BrokenHotChain
Definition: execnodes.h:197
int ii_ParallelWorkers
Definition: execnodes.h:199
bool ii_Concurrent
Definition: execnodes.h:196
struct IndexAmRoutine * rd_indam
Definition: rel.h:205
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:182
@ INDEXRELID
Definition: syscache.h:66
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void CommandCounterIncrement(void)
Definition: xact.c:1078

References IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, Assert(), AtEOXact_GUC(), CatalogTupleUpdate(), CommandCounterIncrement(), DEBUG1, elog(), ereport, errmsg_internal(), ERROR, GETSTRUCT, GetUserIdAndSecContext(), heap_freetuple(), IndexBuildResult::heap_tuples, HeapTupleIsValid, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ParallelWorkers, IndexBuildResult::index_tuples, index_update_stats(), IndexCheckExclusion(), INDEXRELID, INIT_FORKNUM, IsNormalProcessingMode, log_smgrcreate(), NewGUCNestLevel(), ObjectIdGetDatum(), pgstat_progress_update_multi_param(), plan_create_index_workers(), PointerIsValid, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_BUILD, PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE, PROGRESS_CREATEIDX_TUPLES_DONE, PROGRESS_CREATEIDX_TUPLES_TOTAL, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL, RelationData::rd_indam, RelationData::rd_locator, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationGetSmgr(), RelationIsValid, RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), smgrcreate(), smgrexists(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by build_indices(), index_concurrently_build(), index_create(), reindex_index(), and RelationTruncateIndexes().

◆ index_check_primary_key()

void index_check_primary_key ( Relation  heapRel,
const IndexInfo indexInfo,
bool  is_alter_table,
const IndexStmt stmt 
)

Definition at line 206 of file index.c.

210 {
211  int i;
212 
213  /*
214  * If ALTER TABLE or CREATE TABLE .. PARTITION OF, check that there isn't
215  * already a PRIMARY KEY. In CREATE TABLE for an ordinary relation, we
216  * have faith that the parser rejected multiple pkey clauses; and CREATE
217  * INDEX doesn't have a way to say PRIMARY KEY, so it's no problem either.
218  */
219  if ((is_alter_table || heapRel->rd_rel->relispartition) &&
220  relationHasPrimaryKey(heapRel))
221  {
222  ereport(ERROR,
223  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
224  errmsg("multiple primary keys for table \"%s\" are not allowed",
225  RelationGetRelationName(heapRel))));
226  }
227 
228  /*
229  * Indexes created with NULLS NOT DISTINCT cannot be used for primary key
230  * constraints. While there is no direct syntax to reach here, it can be
231  * done by creating a separate index and attaching it via ALTER TABLE ..
232  * USING INDEX.
233  */
234  if (indexInfo->ii_NullsNotDistinct)
235  {
236  ereport(ERROR,
237  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
238  errmsg("primary keys cannot use NULLS NOT DISTINCT indexes")));
239  }
240 
241  /*
242  * Check that all of the attributes in a primary key are marked as not
243  * null. (We don't really expect to see that; it'd mean the parser messed
244  * up. But it seems wise to check anyway.)
245  */
246  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
247  {
248  AttrNumber attnum = indexInfo->ii_IndexAttrNumbers[i];
249  HeapTuple atttuple;
250  Form_pg_attribute attform;
251 
252  if (attnum == 0)
253  ereport(ERROR,
254  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
255  errmsg("primary keys cannot be expressions")));
256 
257  /* System attributes are never null, so no need to check */
258  if (attnum < 0)
259  continue;
260 
261  atttuple = SearchSysCache2(ATTNUM,
264  if (!HeapTupleIsValid(atttuple))
265  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
266  attnum, RelationGetRelid(heapRel));
267  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
268 
269  if (!attform->attnotnull)
270  ereport(ERROR,
271  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
272  errmsg("primary key column \"%s\" is not marked NOT NULL",
273  NameStr(attform->attname))));
274 
275  ReleaseSysCache(atttuple);
276  }
277 }
int16 AttrNumber
Definition: attnum.h:21
#define NameStr(name)
Definition: c.h:735
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
static bool relationHasPrimaryKey(Relation rel)
Definition: index.c:152
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:831
@ ATTNUM
Definition: syscache.h:41

References attnum, ATTNUM, elog(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, i, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NullsNotDistinct, IndexInfo::ii_NumIndexKeyAttrs, Int16GetDatum(), NameStr, ObjectIdGetDatum(), RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, relationHasPrimaryKey(), ReleaseSysCache(), and SearchSysCache2().

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1449 of file index.c.

1451 {
1452  Relation heapRel;
1453  Oid save_userid;
1454  int save_sec_context;
1455  int save_nestlevel;
1456  Relation indexRelation;
1457  IndexInfo *indexInfo;
1458 
1459  /* This had better make sure that a snapshot is active */
1461 
1462  /* Open and lock the parent heap relation */
1463  heapRel = table_open(heapRelationId, ShareUpdateExclusiveLock);
1464 
1465  /*
1466  * Switch to the table owner's userid, so that any index functions are run
1467  * as that user. Also lock down security-restricted operations and
1468  * arrange to make GUC variable changes local to this command.
1469  */
1470  GetUserIdAndSecContext(&save_userid, &save_sec_context);
1471  SetUserIdAndSecContext(heapRel->rd_rel->relowner,
1472  save_sec_context | SECURITY_RESTRICTED_OPERATION);
1473  save_nestlevel = NewGUCNestLevel();
1474 
1475  indexRelation = index_open(indexRelationId, RowExclusiveLock);
1476 
1477  /*
1478  * We have to re-build the IndexInfo struct, since it was lost in the
1479  * commit of the transaction where this concurrent index was created at
1480  * the catalog level.
1481  */
1482  indexInfo = BuildIndexInfo(indexRelation);
1483  Assert(!indexInfo->ii_ReadyForInserts);
1484  indexInfo->ii_Concurrent = true;
1485  indexInfo->ii_BrokenHotChain = false;
1486 
1487  /* Now build the index */
1488  index_build(heapRel, indexRelation, indexInfo, false, true);
1489 
1490  /* Roll back any GUC changes executed by index functions */
1491  AtEOXact_GUC(false, save_nestlevel);
1492 
1493  /* Restore userid and security context */
1494  SetUserIdAndSecContext(save_userid, save_sec_context);
1495 
1496  /* Close both the relations, but keep the locks */
1497  table_close(heapRel, NoLock);
1498  index_close(indexRelation, NoLock);
1499 
1500  /*
1501  * Update the pg_index row to mark the index as ready for inserts. Once we
1502  * commit this transaction, any new transactions that open the table must
1503  * insert new entries into the index for insertions and non-HOT updates.
1504  */
1506 }
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3459
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:2962
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2426
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:763
bool ii_ReadyForInserts
Definition: execnodes.h:193

References ActiveSnapshotSet(), Assert(), AtEOXact_GUC(), BuildIndexInfo(), GetUserIdAndSecContext(), IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ReadyForInserts, index_build(), index_close(), INDEX_CREATE_SET_READY, index_open(), index_set_state_flags(), NewGUCNestLevel(), NoLock, RelationData::rd_rel, RowExclusiveLock, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), ShareUpdateExclusiveLock, table_close(), and table_open().

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

Oid index_concurrently_create_copy ( Relation  heapRelation,
Oid  oldIndexId,
Oid  tablespaceOid,
const char *  newName 
)

Definition at line 1282 of file index.c.

1284 {
1285  Relation indexRelation;
1286  IndexInfo *oldInfo,
1287  *newInfo;
1288  Oid newIndexId = InvalidOid;
1289  HeapTuple indexTuple,
1290  classTuple;
1291  Datum indclassDatum,
1292  colOptionDatum,
1293  optionDatum;
1294  oidvector *indclass;
1295  int2vector *indcoloptions;
1296  bool isnull;
1297  List *indexColNames = NIL;
1298  List *indexExprs = NIL;
1299  List *indexPreds = NIL;
1300 
1301  indexRelation = index_open(oldIndexId, RowExclusiveLock);
1302 
1303  /* The new index needs some information from the old index */
1304  oldInfo = BuildIndexInfo(indexRelation);
1305 
1306  /*
1307  * Concurrent build of an index with exclusion constraints is not
1308  * supported.
1309  */
1310  if (oldInfo->ii_ExclusionOps != NULL)
1311  ereport(ERROR,
1312  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1313  errmsg("concurrent index creation for exclusion constraints is not supported")));
1314 
1315  /* Get the array of class and column options IDs from index info */
1316  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId));
1317  if (!HeapTupleIsValid(indexTuple))
1318  elog(ERROR, "cache lookup failed for index %u", oldIndexId);
1319  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1320  Anum_pg_index_indclass);
1321  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1322 
1323  colOptionDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1324  Anum_pg_index_indoption);
1325  indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum);
1326 
1327  /* Fetch options of index if any */
1328  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(oldIndexId));
1329  if (!HeapTupleIsValid(classTuple))
1330  elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
1331  optionDatum = SysCacheGetAttr(RELOID, classTuple,
1332  Anum_pg_class_reloptions, &isnull);
1333 
1334  /*
1335  * Fetch the list of expressions and predicates directly from the
1336  * catalogs. This cannot rely on the information from IndexInfo of the
1337  * old index as these have been flattened for the planner.
1338  */
1339  if (oldInfo->ii_Expressions != NIL)
1340  {
1341  Datum exprDatum;
1342  char *exprString;
1343 
1344  exprDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1345  Anum_pg_index_indexprs);
1346  exprString = TextDatumGetCString(exprDatum);
1347  indexExprs = (List *) stringToNode(exprString);
1348  pfree(exprString);
1349  }
1350  if (oldInfo->ii_Predicate != NIL)
1351  {
1352  Datum predDatum;
1353  char *predString;
1354 
1355  predDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1356  Anum_pg_index_indpred);
1357  predString = TextDatumGetCString(predDatum);
1358  indexPreds = (List *) stringToNode(predString);
1359 
1360  /* Also convert to implicit-AND format */
1361  indexPreds = make_ands_implicit((Expr *) indexPreds);
1362  pfree(predString);
1363  }
1364 
1365  /*
1366  * Build the index information for the new index. Note that rebuild of
1367  * indexes with exclusion constraints is not supported, hence there is no
1368  * need to fill all the ii_Exclusion* fields.
1369  */
1370  newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1371  oldInfo->ii_NumIndexKeyAttrs,
1372  oldInfo->ii_Am,
1373  indexExprs,
1374  indexPreds,
1375  oldInfo->ii_Unique,
1376  oldInfo->ii_NullsNotDistinct,
1377  false, /* not ready for inserts */
1378  true,
1379  indexRelation->rd_indam->amsummarizing);
1380 
1381  /*
1382  * Extract the list of column names and the column numbers for the new
1383  * index information. All this information will be used for the index
1384  * creation.
1385  */
1386  for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++)
1387  {
1388  TupleDesc indexTupDesc = RelationGetDescr(indexRelation);
1389  Form_pg_attribute att = TupleDescAttr(indexTupDesc, i);
1390 
1391  indexColNames = lappend(indexColNames, NameStr(att->attname));
1392  newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i];
1393  }
1394 
1395  /* Extract opclass parameters for each attribute, if any */
1396  if (oldInfo->ii_OpclassOptions != NULL)
1397  {
1398  newInfo->ii_OpclassOptions = palloc0(sizeof(Datum) *
1399  newInfo->ii_NumIndexAttrs);
1400  for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1401  newInfo->ii_OpclassOptions[i] = get_attoptions(oldIndexId, i + 1);
1402  }
1403 
1404  /*
1405  * Now create the new index.
1406  *
1407  * For a partition index, we adjust the partition dependency later, to
1408  * ensure a consistent state at all times. That is why parentIndexRelid
1409  * is not set here.
1410  */
1411  newIndexId = index_create(heapRelation,
1412  newName,
1413  InvalidOid, /* indexRelationId */
1414  InvalidOid, /* parentIndexRelid */
1415  InvalidOid, /* parentConstraintId */
1416  InvalidRelFileNumber, /* relFileNumber */
1417  newInfo,
1418  indexColNames,
1419  indexRelation->rd_rel->relam,
1420  tablespaceOid,
1421  indexRelation->rd_indcollation,
1422  indclass->values,
1423  indcoloptions->values,
1424  optionDatum,
1426  0,
1427  true, /* allow table to be a system catalog? */
1428  false, /* is_internal? */
1429  NULL);
1430 
1431  /* Close the relations used and clean up */
1432  index_close(indexRelation, NoLock);
1433  ReleaseSysCache(indexTuple);
1434  ReleaseSysCache(classTuple);
1435 
1436  return newIndexId;
1437 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const int16 *coloptions, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition: index.c:711
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:63
#define INDEX_CREATE_CONCURRENT
Definition: index.h:64
List * lappend(List *list, void *datum)
Definition: list.c:338
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:996
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:722
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc0(Size size)
Definition: mcxt.c:1257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:530
#define InvalidRelFileNumber
Definition: relpath.h:26
bool amsummarizing
Definition: amapi.h:248
Definition: pg_list.h:54
Oid * rd_indcollation
Definition: rel.h:216
Definition: c.h:704
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:711
Definition: c.h:715
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1081
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:1112
@ RELOID
Definition: syscache.h:89
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References IndexAmRoutine::amsummarizing, BuildIndexInfo(), DatumGetPointer(), elog(), ereport, errcode(), errmsg(), ERROR, get_attoptions(), HeapTupleIsValid, i, IndexInfo::ii_Am, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NullsNotDistinct, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_OpclassOptions, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, index_close(), index_create(), INDEX_CREATE_CONCURRENT, INDEX_CREATE_SKIP_BUILD, index_open(), INDEXRELID, InvalidOid, InvalidRelFileNumber, lappend(), make_ands_implicit(), makeIndexInfo(), NameStr, NIL, NoLock, ObjectIdGetDatum(), palloc0(), pfree(), RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_rel, RelationGetDescr, ReleaseSysCache(), RELOID, RowExclusiveLock, SearchSysCache1(), stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), TextDatumGetCString, TupleDescAttr, int2vector::values, and oidvector::values.

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1842 of file index.c.

1843 {
1844  Relation userHeapRelation;
1845  Relation userIndexRelation;
1846 
1847  /*
1848  * No more predicate locks will be acquired on this index, and we're about
1849  * to stop doing inserts into the index which could show conflicts with
1850  * existing predicate locks, so now is the time to move them to the heap
1851  * relation.
1852  */
1853  userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock);
1854  userIndexRelation = index_open(indexId, ShareUpdateExclusiveLock);
1855  TransferPredicateLocksToHeapRelation(userIndexRelation);
1856 
1857  /*
1858  * Now we are sure that nobody uses the index for queries; they just might
1859  * have it open for updating it. So now we can unset indisready and
1860  * indislive, then wait till nobody could be using it at all anymore.
1861  */
1863 
1864  /*
1865  * Invalidate the relcache for the table, so that after this commit all
1866  * sessions will refresh the table's index list. Forgetting just the
1867  * index's relcache entry is not enough.
1868  */
1869  CacheInvalidateRelcache(userHeapRelation);
1870 
1871  /*
1872  * Close the relations again, though still holding session lock.
1873  */
1874  table_close(userHeapRelation, NoLock);
1875  index_close(userIndexRelation, NoLock);
1876 }
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1363
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3057

References CacheInvalidateRelcache(), index_close(), INDEX_DROP_SET_DEAD, index_open(), index_set_state_flags(), NoLock, ShareUpdateExclusiveLock, table_close(), table_open(), and TransferPredicateLocksToHeapRelation().

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

void index_concurrently_swap ( Oid  newIndexId,
Oid  oldIndexId,
const char *  oldName 
)

Definition at line 1515 of file index.c.

1516 {
1517  Relation pg_class,
1518  pg_index,
1519  pg_constraint,
1520  pg_trigger;
1521  Relation oldClassRel,
1522  newClassRel;
1523  HeapTuple oldClassTuple,
1524  newClassTuple;
1525  Form_pg_class oldClassForm,
1526  newClassForm;
1527  HeapTuple oldIndexTuple,
1528  newIndexTuple;
1529  Form_pg_index oldIndexForm,
1530  newIndexForm;
1531  bool isPartition;
1532  Oid indexConstraintOid;
1533  List *constraintOids = NIL;
1534  ListCell *lc;
1535 
1536  /*
1537  * Take a necessary lock on the old and new index before swapping them.
1538  */
1539  oldClassRel = relation_open(oldIndexId, ShareUpdateExclusiveLock);
1540  newClassRel = relation_open(newIndexId, ShareUpdateExclusiveLock);
1541 
1542  /* Now swap names and dependencies of those indexes */
1543  pg_class = table_open(RelationRelationId, RowExclusiveLock);
1544 
1545  oldClassTuple = SearchSysCacheCopy1(RELOID,
1546  ObjectIdGetDatum(oldIndexId));
1547  if (!HeapTupleIsValid(oldClassTuple))
1548  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1549  newClassTuple = SearchSysCacheCopy1(RELOID,
1550  ObjectIdGetDatum(newIndexId));
1551  if (!HeapTupleIsValid(newClassTuple))
1552  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1553 
1554  oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple);
1555  newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple);
1556 
1557  /* Swap the names */
1558  namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1559  namestrcpy(&oldClassForm->relname, oldName);
1560 
1561  /* Swap the partition flags to track inheritance properly */
1562  isPartition = newClassForm->relispartition;
1563  newClassForm->relispartition = oldClassForm->relispartition;
1564  oldClassForm->relispartition = isPartition;
1565 
1566  CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple);
1567  CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple);
1568 
1569  heap_freetuple(oldClassTuple);
1570  heap_freetuple(newClassTuple);
1571 
1572  /* Now swap index info */
1573  pg_index = table_open(IndexRelationId, RowExclusiveLock);
1574 
1575  oldIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1576  ObjectIdGetDatum(oldIndexId));
1577  if (!HeapTupleIsValid(oldIndexTuple))
1578  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1579  newIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1580  ObjectIdGetDatum(newIndexId));
1581  if (!HeapTupleIsValid(newIndexTuple))
1582  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1583 
1584  oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple);
1585  newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple);
1586 
1587  /*
1588  * Copy constraint flags from the old index. This is safe because the old
1589  * index guaranteed uniqueness.
1590  */
1591  newIndexForm->indisprimary = oldIndexForm->indisprimary;
1592  oldIndexForm->indisprimary = false;
1593  newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1594  oldIndexForm->indisexclusion = false;
1595  newIndexForm->indimmediate = oldIndexForm->indimmediate;
1596  oldIndexForm->indimmediate = true;
1597 
1598  /* Preserve indisreplident in the new index */
1599  newIndexForm->indisreplident = oldIndexForm->indisreplident;
1600 
1601  /* Preserve indisclustered in the new index */
1602  newIndexForm->indisclustered = oldIndexForm->indisclustered;
1603 
1604  /*
1605  * Mark the new index as valid, and the old index as invalid similarly to
1606  * what index_set_state_flags() does.
1607  */
1608  newIndexForm->indisvalid = true;
1609  oldIndexForm->indisvalid = false;
1610  oldIndexForm->indisclustered = false;
1611  oldIndexForm->indisreplident = false;
1612 
1613  CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple);
1614  CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple);
1615 
1616  heap_freetuple(oldIndexTuple);
1617  heap_freetuple(newIndexTuple);
1618 
1619  /*
1620  * Move constraints and triggers over to the new index
1621  */
1622 
1623  constraintOids = get_index_ref_constraints(oldIndexId);
1624 
1625  indexConstraintOid = get_index_constraint(oldIndexId);
1626 
1627  if (OidIsValid(indexConstraintOid))
1628  constraintOids = lappend_oid(constraintOids, indexConstraintOid);
1629 
1630  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
1631  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
1632 
1633  foreach(lc, constraintOids)
1634  {
1635  HeapTuple constraintTuple,
1636  triggerTuple;
1637  Form_pg_constraint conForm;
1638  ScanKeyData key[1];
1639  SysScanDesc scan;
1640  Oid constraintOid = lfirst_oid(lc);
1641 
1642  /* Move the constraint from the old to the new index */
1643  constraintTuple = SearchSysCacheCopy1(CONSTROID,
1644  ObjectIdGetDatum(constraintOid));
1645  if (!HeapTupleIsValid(constraintTuple))
1646  elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1647 
1648  conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple));
1649 
1650  if (conForm->conindid == oldIndexId)
1651  {
1652  conForm->conindid = newIndexId;
1653 
1654  CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple);
1655  }
1656 
1657  heap_freetuple(constraintTuple);
1658 
1659  /* Search for trigger records */
1660  ScanKeyInit(&key[0],
1661  Anum_pg_trigger_tgconstraint,
1662  BTEqualStrategyNumber, F_OIDEQ,
1663  ObjectIdGetDatum(constraintOid));
1664 
1665  scan = systable_beginscan(pg_trigger, TriggerConstraintIndexId, true,
1666  NULL, 1, key);
1667 
1668  while (HeapTupleIsValid((triggerTuple = systable_getnext(scan))))
1669  {
1670  Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1671 
1672  if (tgForm->tgconstrindid != oldIndexId)
1673  continue;
1674 
1675  /* Make a modifiable copy */
1676  triggerTuple = heap_copytuple(triggerTuple);
1677  tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1678 
1679  tgForm->tgconstrindid = newIndexId;
1680 
1681  CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple);
1682 
1683  heap_freetuple(triggerTuple);
1684  }
1685 
1686  systable_endscan(scan);
1687  }
1688 
1689  /*
1690  * Move comment if any
1691  */
1692  {
1694  ScanKeyData skey[3];
1695  SysScanDesc sd;
1696  HeapTuple tuple;
1697  Datum values[Natts_pg_description] = {0};
1698  bool nulls[Natts_pg_description] = {0};
1699  bool replaces[Natts_pg_description] = {0};
1700 
1701  values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId);
1702  replaces[Anum_pg_description_objoid - 1] = true;
1703 
1704  ScanKeyInit(&skey[0],
1705  Anum_pg_description_objoid,
1706  BTEqualStrategyNumber, F_OIDEQ,
1707  ObjectIdGetDatum(oldIndexId));
1708  ScanKeyInit(&skey[1],
1709  Anum_pg_description_classoid,
1710  BTEqualStrategyNumber, F_OIDEQ,
1711  ObjectIdGetDatum(RelationRelationId));
1712  ScanKeyInit(&skey[2],
1713  Anum_pg_description_objsubid,
1714  BTEqualStrategyNumber, F_INT4EQ,
1715  Int32GetDatum(0));
1716 
1717  description = table_open(DescriptionRelationId, RowExclusiveLock);
1718 
1719  sd = systable_beginscan(description, DescriptionObjIndexId, true,
1720  NULL, 3, skey);
1721 
1722  while ((tuple = systable_getnext(sd)) != NULL)
1723  {
1725  values, nulls, replaces);
1726  CatalogTupleUpdate(description, &tuple->t_self, tuple);
1727 
1728  break; /* Assume there can be only one match */
1729  }
1730 
1731  systable_endscan(sd);
1733  }
1734 
1735  /*
1736  * Swap inheritance relationship with parent index
1737  */
1738  if (get_rel_relispartition(oldIndexId))
1739  {
1740  List *ancestors = get_partition_ancestors(oldIndexId);
1741  Oid parentIndexRelid = linitial_oid(ancestors);
1742 
1743  DeleteInheritsTuple(oldIndexId, parentIndexRelid, false, NULL);
1744  StoreSingleInheritance(newIndexId, parentIndexRelid, 1);
1745 
1746  list_free(ancestors);
1747  }
1748 
1749  /*
1750  * Swap all dependencies of and on the old index to the new one, and
1751  * vice-versa. Note that a call to CommandCounterIncrement() would cause
1752  * duplicate entries in pg_depend, so this should not be done.
1753  */
1754  changeDependenciesOf(RelationRelationId, newIndexId, oldIndexId);
1755  changeDependenciesOn(RelationRelationId, newIndexId, oldIndexId);
1756 
1757  changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId);
1758  changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId);
1759 
1760  /* copy over statistics from old to new index */
1761  pgstat_copy_relation_stats(newClassRel, oldClassRel);
1762 
1763  /* Copy data of pg_statistic from the old index to the new one */
1764  CopyStatistics(oldIndexId, newIndexId);
1765 
1766  /* Copy pg_attribute.attstattarget for each index attribute */
1767  {
1768  HeapTuple attrTuple;
1769  Relation pg_attribute;
1770  SysScanDesc scan;
1771  ScanKeyData key[1];
1772 
1773  pg_attribute = table_open(AttributeRelationId, RowExclusiveLock);
1774  ScanKeyInit(&key[0],
1775  Anum_pg_attribute_attrelid,
1776  BTEqualStrategyNumber, F_OIDEQ,
1777  ObjectIdGetDatum(newIndexId));
1778  scan = systable_beginscan(pg_attribute, AttributeRelidNumIndexId,
1779  true, NULL, 1, key);
1780 
1781  while (HeapTupleIsValid((attrTuple = systable_getnext(scan))))
1782  {
1783  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attrTuple);
1784  Datum repl_val[Natts_pg_attribute];
1785  bool repl_null[Natts_pg_attribute];
1786  bool repl_repl[Natts_pg_attribute];
1787  int attstattarget;
1788  HeapTuple newTuple;
1789 
1790  /* Ignore dropped columns */
1791  if (att->attisdropped)
1792  continue;
1793 
1794  /*
1795  * Get attstattarget from the old index and refresh the new value.
1796  */
1797  attstattarget = get_attstattarget(oldIndexId, att->attnum);
1798 
1799  /* no need for a refresh if both match */
1800  if (attstattarget == att->attstattarget)
1801  continue;
1802 
1803  memset(repl_val, 0, sizeof(repl_val));
1804  memset(repl_null, false, sizeof(repl_null));
1805  memset(repl_repl, false, sizeof(repl_repl));
1806 
1807  repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
1808  repl_val[Anum_pg_attribute_attstattarget - 1] = Int16GetDatum(attstattarget);
1809 
1810  newTuple = heap_modify_tuple(attrTuple,
1811  RelationGetDescr(pg_attribute),
1812  repl_val, repl_null, repl_repl);
1813  CatalogTupleUpdate(pg_attribute, &newTuple->t_self, newTuple);
1814 
1815  heap_freetuple(newTuple);
1816  }
1817 
1818  systable_endscan(scan);
1819  table_close(pg_attribute, RowExclusiveLock);
1820  }
1821 
1822  /* Close relations */
1823  table_close(pg_class, RowExclusiveLock);
1824  table_close(pg_index, RowExclusiveLock);
1825  table_close(pg_constraint, RowExclusiveLock);
1826  table_close(pg_trigger, RowExclusiveLock);
1827 
1828  /* The lock taken previously is not released until the end of transaction */
1829  relation_close(oldClassRel, NoLock);
1830  relation_close(newClassRel, NoLock);
1831 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
void CopyStatistics(Oid fromrelid, Oid torelid)
Definition: heap.c:3185
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:768
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1201
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
void list_free(List *list)
Definition: list.c:1545
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2031
int get_attstattarget(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:884
void namestrcpy(Name name, const char *str)
Definition: name.c:233
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
FormData_pg_constraint * Form_pg_constraint
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition: pg_depend.c:564
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:620
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:968
List * get_index_ref_constraints(Oid indexId)
Definition: pg_depend.c:1024
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
Definition: pg_inherits.c:553
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:509
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
void pgstat_copy_relation_stats(Relation dst, Relation src)
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
@ CONSTROID
Definition: syscache.h:53
const char * description

References BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependenciesOf(), changeDependenciesOn(), CONSTROID, CopyStatistics(), DeleteInheritsTuple(), description, elog(), ERROR, get_attstattarget(), get_index_constraint(), get_index_ref_constraints(), get_partition_ancestors(), get_rel_relispartition(), GETSTRUCT, heap_copytuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, INDEXRELID, Int16GetDatum(), Int32GetDatum(), sort-test::key, lappend_oid(), lfirst_oid, linitial_oid, list_free(), NameStr, namestrcpy(), NIL, NoLock, ObjectIdGetDatum(), OidIsValid, pgstat_copy_relation_stats(), relation_close(), relation_open(), RelationGetDescr, RELOID, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, ShareUpdateExclusiveLock, StoreSingleInheritance(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

ObjectAddress index_constraint_create ( Relation  heapRelation,
Oid  indexRelationId,
Oid  parentConstraintId,
const IndexInfo indexInfo,
const char *  constraintName,
char  constraintType,
bits16  constr_flags,
bool  allow_system_table_mods,
bool  is_internal 
)

Definition at line 1903 of file index.c.

1912 {
1913  Oid namespaceId = RelationGetNamespace(heapRelation);
1914  ObjectAddress myself,
1915  idxaddr;
1916  Oid conOid;
1917  bool deferrable;
1918  bool initdeferred;
1919  bool mark_as_primary;
1920  bool islocal;
1921  bool noinherit;
1922  int inhcount;
1923 
1924  deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1925  initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1926  mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
1927 
1928  /* constraint creation support doesn't work while bootstrapping */
1930 
1931  /* enforce system-table restriction */
1932  if (!allow_system_table_mods &&
1933  IsSystemRelation(heapRelation) &&
1935  ereport(ERROR,
1936  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1937  errmsg("user-defined indexes on system catalog tables are not supported")));
1938 
1939  /* primary/unique constraints shouldn't have any expressions */
1940  if (indexInfo->ii_Expressions &&
1941  constraintType != CONSTRAINT_EXCLUSION)
1942  elog(ERROR, "constraints cannot have index expressions");
1943 
1944  /*
1945  * If we're manufacturing a constraint for a pre-existing index, we need
1946  * to get rid of the existing auto dependencies for the index (the ones
1947  * that index_create() would have made instead of calling this function).
1948  *
1949  * Note: this code would not necessarily do the right thing if the index
1950  * has any expressions or predicate, but we'd never be turning such an
1951  * index into a UNIQUE or PRIMARY KEY constraint.
1952  */
1953  if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
1954  deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
1955  RelationRelationId, DEPENDENCY_AUTO);
1956 
1957  if (OidIsValid(parentConstraintId))
1958  {
1959  islocal = false;
1960  inhcount = 1;
1961  noinherit = false;
1962  }
1963  else
1964  {
1965  islocal = true;
1966  inhcount = 0;
1967  noinherit = true;
1968  }
1969 
1970  /*
1971  * Construct a pg_constraint entry.
1972  */
1973  conOid = CreateConstraintEntry(constraintName,
1974  namespaceId,
1975  constraintType,
1976  deferrable,
1977  initdeferred,
1978  true,
1979  parentConstraintId,
1980  RelationGetRelid(heapRelation),
1981  indexInfo->ii_IndexAttrNumbers,
1982  indexInfo->ii_NumIndexKeyAttrs,
1983  indexInfo->ii_NumIndexAttrs,
1984  InvalidOid, /* no domain */
1985  indexRelationId, /* index OID */
1986  InvalidOid, /* no foreign key */
1987  NULL,
1988  NULL,
1989  NULL,
1990  NULL,
1991  0,
1992  ' ',
1993  ' ',
1994  NULL,
1995  0,
1996  ' ',
1997  indexInfo->ii_ExclusionOps,
1998  NULL, /* no check constraint */
1999  NULL,
2000  islocal,
2001  inhcount,
2002  noinherit,
2003  is_internal);
2004 
2005  /*
2006  * Register the index as internally dependent on the constraint.
2007  *
2008  * Note that the constraint has a dependency on the table, so we don't
2009  * need (or want) any direct dependency from the index to the table.
2010  */
2011  ObjectAddressSet(myself, ConstraintRelationId, conOid);
2012  ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId);
2013  recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
2014 
2015  /*
2016  * Also, if this is a constraint on a partition, give it partition-type
2017  * dependencies on the parent constraint as well as the table.
2018  */
2019  if (OidIsValid(parentConstraintId))
2020  {
2021  ObjectAddress referenced;
2022 
2023  ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
2024  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
2025  ObjectAddressSet(referenced, RelationRelationId,
2026  RelationGetRelid(heapRelation));
2027  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
2028  }
2029 
2030  /*
2031  * If the constraint is deferrable, create the deferred uniqueness
2032  * checking trigger. (The trigger will be given an internal dependency on
2033  * the constraint by CreateTrigger.)
2034  */
2035  if (deferrable)
2036  {
2038 
2039  trigger->replace = false;
2040  trigger->isconstraint = true;
2041  trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
2042  "PK_ConstraintTrigger" :
2043  "Unique_ConstraintTrigger";
2044  trigger->relation = NULL;
2045  trigger->funcname = SystemFuncName("unique_key_recheck");
2046  trigger->args = NIL;
2047  trigger->row = true;
2048  trigger->timing = TRIGGER_TYPE_AFTER;
2049  trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE;
2050  trigger->columns = NIL;
2051  trigger->whenClause = NULL;
2052  trigger->transitionRels = NIL;
2053  trigger->deferrable = true;
2054  trigger->initdeferred = initdeferred;
2055  trigger->constrrel = NULL;
2056 
2057  (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
2058  InvalidOid, conOid, indexRelationId, InvalidOid,
2059  InvalidOid, NULL, true, false);
2060  }
2061 
2062  /*
2063  * If needed, mark the index as primary and/or deferred in pg_index.
2064  *
2065  * Note: When making an existing index into a constraint, caller must have
2066  * a table lock that prevents concurrent table updates; otherwise, there
2067  * is a risk that concurrent readers of the table will miss seeing this
2068  * index at all.
2069  */
2070  if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
2071  (mark_as_primary || deferrable))
2072  {
2073  Relation pg_index;
2074  HeapTuple indexTuple;
2075  Form_pg_index indexForm;
2076  bool dirty = false;
2077  bool marked_as_primary = false;
2078 
2079  pg_index = table_open(IndexRelationId, RowExclusiveLock);
2080 
2081  indexTuple = SearchSysCacheCopy1(INDEXRELID,
2082  ObjectIdGetDatum(indexRelationId));
2083  if (!HeapTupleIsValid(indexTuple))
2084  elog(ERROR, "cache lookup failed for index %u", indexRelationId);
2085  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
2086 
2087  if (mark_as_primary && !indexForm->indisprimary)
2088  {
2089  indexForm->indisprimary = true;
2090  dirty = true;
2091  marked_as_primary = true;
2092  }
2093 
2094  if (deferrable && indexForm->indimmediate)
2095  {
2096  indexForm->indimmediate = false;
2097  dirty = true;
2098  }
2099 
2100  if (dirty)
2101  {
2102  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
2103 
2104  /*
2105  * When we mark an existing index as primary, force a relcache
2106  * flush on its parent table, so that all sessions will become
2107  * aware that the table now has a primary key. This is important
2108  * because it affects some replication behaviors.
2109  */
2110  if (marked_as_primary)
2111  CacheInvalidateRelcache(heapRelation);
2112 
2113  InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
2114  InvalidOid, is_internal);
2115  }
2116 
2117  heap_freetuple(indexTuple);
2118  table_close(pg_index, RowExclusiveLock);
2119  }
2120 
2121  return myself;
2122 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:75
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:92
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:93
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:90
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:89
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:91
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:414
#define makeNode(_type_)
Definition: nodes.h:176
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:200
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * SystemFuncName(char *name)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
#define RelationGetNamespace(relation)
Definition: rel.h:545
Node * whenClause
Definition: parsenodes.h:2890
List * transitionRels
Definition: parsenodes.h:2892
RangeVar * constrrel
Definition: parsenodes.h:2896
RangeVar * relation
Definition: parsenodes.h:2881
ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
Definition: trigger.c:165

References CreateTrigStmt::args, Assert(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CreateTrigStmt::columns, CreateTrigStmt::constrrel, CreateConstraintEntry(), CreateTrigger(), CreateTrigStmt::deferrable, deleteDependencyRecordsForClass(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog(), ereport, errcode(), errmsg(), ERROR, CreateTrigStmt::events, CreateTrigStmt::funcname, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_MARK_AS_PRIMARY, INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS, INDEX_CONSTR_CREATE_UPDATE_INDEX, INDEXRELID, CreateTrigStmt::initdeferred, InvalidOid, InvokeObjectPostAlterHookArg, IsBootstrapProcessingMode, CreateTrigStmt::isconstraint, IsNormalProcessingMode, IsSystemRelation(), makeNode, NIL, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, recordDependencyOn(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelid, CreateTrigStmt::replace, CreateTrigStmt::row, RowExclusiveLock, SearchSysCacheCopy1, SystemFuncName(), HeapTupleData::t_self, table_close(), table_open(), CreateTrigStmt::timing, CreateTrigStmt::transitionRels, CreateTrigStmt::trigname, and CreateTrigStmt::whenClause.

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

Oid index_create ( Relation  heapRelation,
const char *  indexRelationName,
Oid  indexRelationId,
Oid  parentIndexRelid,
Oid  parentConstraintId,
RelFileNumber  relFileNumber,
IndexInfo indexInfo,
const List indexColNames,
Oid  accessMethodId,
Oid  tableSpaceId,
const Oid collationIds,
const Oid opclassIds,
const int16 coloptions,
Datum  reloptions,
bits16  flags,
bits16  constr_flags,
bool  allow_system_table_mods,
bool  is_internal,
Oid constraintId 
)

Definition at line 711 of file index.c.

730 {
731  Oid heapRelationId = RelationGetRelid(heapRelation);
732  Relation pg_class;
733  Relation indexRelation;
734  TupleDesc indexTupDesc;
735  bool shared_relation;
736  bool mapped_relation;
737  bool is_exclusion;
738  Oid namespaceId;
739  int i;
740  char relpersistence;
741  bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0;
742  bool invalid = (flags & INDEX_CREATE_INVALID) != 0;
743  bool concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0;
744  bool partitioned = (flags & INDEX_CREATE_PARTITIONED) != 0;
745  char relkind;
746  TransactionId relfrozenxid;
747  MultiXactId relminmxid;
748  bool create_storage = !RelFileNumberIsValid(relFileNumber);
749 
750  /* constraint flags can only be set when a constraint is requested */
751  Assert((constr_flags == 0) ||
752  ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0));
753  /* partitioned indexes must never be "built" by themselves */
754  Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD));
755 
756  relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX;
757  is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
758 
759  pg_class = table_open(RelationRelationId, RowExclusiveLock);
760 
761  /*
762  * The index will be in the same namespace as its parent table, and is
763  * shared across databases if and only if the parent is. Likewise, it
764  * will use the relfilenumber map if and only if the parent does; and it
765  * inherits the parent's relpersistence.
766  */
767  namespaceId = RelationGetNamespace(heapRelation);
768  shared_relation = heapRelation->rd_rel->relisshared;
769  mapped_relation = RelationIsMapped(heapRelation);
770  relpersistence = heapRelation->rd_rel->relpersistence;
771 
772  /*
773  * check parameters
774  */
775  if (indexInfo->ii_NumIndexAttrs < 1)
776  elog(ERROR, "must index at least one column");
777 
778  if (!allow_system_table_mods &&
779  IsSystemRelation(heapRelation) &&
781  ereport(ERROR,
782  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
783  errmsg("user-defined indexes on system catalog tables are not supported")));
784 
785  /*
786  * Btree text_pattern_ops uses text_eq as the equality operator, which is
787  * fine as long as the collation is deterministic; text_eq then reduces to
788  * bitwise equality and so it is semantically compatible with the other
789  * operators and functions in that opclass. But with a nondeterministic
790  * collation, text_eq could yield results that are incompatible with the
791  * actual behavior of the index (which is determined by the opclass's
792  * comparison function). We prevent such problems by refusing creation of
793  * an index with that opclass and a nondeterministic collation.
794  *
795  * The same applies to varchar_pattern_ops and bpchar_pattern_ops. If we
796  * find more cases, we might decide to create a real mechanism for marking
797  * opclasses as incompatible with nondeterminism; but for now, this small
798  * hack suffices.
799  *
800  * Another solution is to use a special operator, not text_eq, as the
801  * equality opclass member; but that is undesirable because it would
802  * prevent index usage in many queries that work fine today.
803  */
804  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
805  {
806  Oid collation = collationIds[i];
807  Oid opclass = opclassIds[i];
808 
809  if (collation)
810  {
811  if ((opclass == TEXT_BTREE_PATTERN_OPS_OID ||
812  opclass == VARCHAR_BTREE_PATTERN_OPS_OID ||
813  opclass == BPCHAR_BTREE_PATTERN_OPS_OID) &&
814  !get_collation_isdeterministic(collation))
815  {
816  HeapTuple classtup;
817 
818  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
819  if (!HeapTupleIsValid(classtup))
820  elog(ERROR, "cache lookup failed for operator class %u", opclass);
821  ereport(ERROR,
822  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
823  errmsg("nondeterministic collations are not supported for operator class \"%s\"",
824  NameStr(((Form_pg_opclass) GETSTRUCT(classtup))->opcname))));
825  ReleaseSysCache(classtup);
826  }
827  }
828  }
829 
830  /*
831  * Concurrent index build on a system catalog is unsafe because we tend to
832  * release locks before committing in catalogs.
833  */
834  if (concurrent &&
835  IsCatalogRelation(heapRelation))
836  ereport(ERROR,
837  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
838  errmsg("concurrent index creation on system catalog tables is not supported")));
839 
840  /*
841  * This case is currently not supported. There's no way to ask for it in
842  * the grammar with CREATE INDEX, but it can happen with REINDEX.
843  */
844  if (concurrent && is_exclusion)
845  ereport(ERROR,
846  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
847  errmsg("concurrent index creation for exclusion constraints is not supported")));
848 
849  /*
850  * We cannot allow indexing a shared relation after initdb (because
851  * there's no way to make the entry in other databases' pg_class).
852  */
853  if (shared_relation && !IsBootstrapProcessingMode())
854  ereport(ERROR,
855  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
856  errmsg("shared indexes cannot be created after initdb")));
857 
858  /*
859  * Shared relations must be in pg_global, too (last-ditch check)
860  */
861  if (shared_relation && tableSpaceId != GLOBALTABLESPACE_OID)
862  elog(ERROR, "shared relations must be placed in pg_global tablespace");
863 
864  /*
865  * Check for duplicate name (both as to the index, and as to the
866  * associated constraint if any). Such cases would fail on the relevant
867  * catalogs' unique indexes anyway, but we prefer to give a friendlier
868  * error message.
869  */
870  if (get_relname_relid(indexRelationName, namespaceId))
871  {
872  if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0)
873  {
874  ereport(NOTICE,
875  (errcode(ERRCODE_DUPLICATE_TABLE),
876  errmsg("relation \"%s\" already exists, skipping",
877  indexRelationName)));
878  table_close(pg_class, RowExclusiveLock);
879  return InvalidOid;
880  }
881 
882  ereport(ERROR,
883  (errcode(ERRCODE_DUPLICATE_TABLE),
884  errmsg("relation \"%s\" already exists",
885  indexRelationName)));
886  }
887 
888  if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0 &&
890  indexRelationName))
891  {
892  /*
893  * INDEX_CREATE_IF_NOT_EXISTS does not apply here, since the
894  * conflicting constraint is not an index.
895  */
896  ereport(ERROR,
898  errmsg("constraint \"%s\" for relation \"%s\" already exists",
899  indexRelationName, RelationGetRelationName(heapRelation))));
900  }
901 
902  /*
903  * construct tuple descriptor for index tuples
904  */
905  indexTupDesc = ConstructTupleDescriptor(heapRelation,
906  indexInfo,
907  indexColNames,
908  accessMethodId,
909  collationIds,
910  opclassIds);
911 
912  /*
913  * Allocate an OID for the index, unless we were told what to use.
914  *
915  * The OID will be the relfilenumber as well, so make sure it doesn't
916  * collide with either pg_class OIDs or existing physical files.
917  */
918  if (!OidIsValid(indexRelationId))
919  {
920  /* Use binary-upgrade override for pg_class.oid and relfilenumber */
921  if (IsBinaryUpgrade)
922  {
924  ereport(ERROR,
925  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
926  errmsg("pg_class index OID value not set when in binary upgrade mode")));
927 
928  indexRelationId = binary_upgrade_next_index_pg_class_oid;
930 
931  /* Override the index relfilenumber */
932  if ((relkind == RELKIND_INDEX) &&
934  ereport(ERROR,
935  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
936  errmsg("index relfilenumber value not set when in binary upgrade mode")));
939 
940  /*
941  * Note that we want create_storage = true for binary upgrade. The
942  * storage we create here will be replaced later, but we need to
943  * have something on disk in the meanwhile.
944  */
945  Assert(create_storage);
946  }
947  else
948  {
949  indexRelationId =
950  GetNewRelFileNumber(tableSpaceId, pg_class, relpersistence);
951  }
952  }
953 
954  /*
955  * create the index relation's relcache entry and, if necessary, the
956  * physical disk file. (If we fail further down, it's the smgr's
957  * responsibility to remove the disk file again, if any.)
958  */
959  indexRelation = heap_create(indexRelationName,
960  namespaceId,
961  tableSpaceId,
962  indexRelationId,
963  relFileNumber,
964  accessMethodId,
965  indexTupDesc,
966  relkind,
967  relpersistence,
968  shared_relation,
969  mapped_relation,
970  allow_system_table_mods,
971  &relfrozenxid,
972  &relminmxid,
973  create_storage);
974 
975  Assert(relfrozenxid == InvalidTransactionId);
976  Assert(relminmxid == InvalidMultiXactId);
977  Assert(indexRelationId == RelationGetRelid(indexRelation));
978 
979  /*
980  * Obtain exclusive lock on it. Although no other transactions can see it
981  * until we commit, this prevents deadlock-risk complaints from lock
982  * manager in cases such as CLUSTER.
983  */
984  LockRelation(indexRelation, AccessExclusiveLock);
985 
986  /*
987  * Fill in fields of the index's pg_class entry that are not set correctly
988  * by heap_create.
989  *
990  * XXX should have a cleaner way to create cataloged indexes
991  */
992  indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner;
993  indexRelation->rd_rel->relam = accessMethodId;
994  indexRelation->rd_rel->relispartition = OidIsValid(parentIndexRelid);
995 
996  /*
997  * store index's pg_class entry
998  */
999  InsertPgClassTuple(pg_class, indexRelation,
1000  RelationGetRelid(indexRelation),
1001  (Datum) 0,
1002  reloptions);
1003 
1004  /* done with pg_class */
1005  table_close(pg_class, RowExclusiveLock);
1006 
1007  /*
1008  * now update the object id's of all the attribute tuple forms in the
1009  * index relation's tuple descriptor
1010  */
1011  InitializeAttributeOids(indexRelation,
1012  indexInfo->ii_NumIndexAttrs,
1013  indexRelationId);
1014 
1015  /*
1016  * append ATTRIBUTE tuples for the index
1017  */
1018  AppendAttributeTuples(indexRelation, indexInfo->ii_OpclassOptions);
1019 
1020  /* ----------------
1021  * update pg_index
1022  * (append INDEX tuple)
1023  *
1024  * Note that this stows away a representation of "predicate".
1025  * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1026  * ----------------
1027  */
1028  UpdateIndexRelation(indexRelationId, heapRelationId, parentIndexRelid,
1029  indexInfo,
1030  collationIds, opclassIds, coloptions,
1031  isprimary, is_exclusion,
1032  (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0,
1033  !concurrent && !invalid,
1034  !concurrent);
1035 
1036  /*
1037  * Register relcache invalidation on the indexes' heap relation, to
1038  * maintain consistency of its index list
1039  */
1040  CacheInvalidateRelcache(heapRelation);
1041 
1042  /* update pg_inherits and the parent's relhassubclass, if needed */
1043  if (OidIsValid(parentIndexRelid))
1044  {
1045  StoreSingleInheritance(indexRelationId, parentIndexRelid, 1);
1046  SetRelationHasSubclass(parentIndexRelid, true);
1047  }
1048 
1049  /*
1050  * Register constraint and dependencies for the index.
1051  *
1052  * If the index is from a CONSTRAINT clause, construct a pg_constraint
1053  * entry. The index will be linked to the constraint, which in turn is
1054  * linked to the table. If it's not a CONSTRAINT, we need to make a
1055  * dependency directly on the table.
1056  *
1057  * We don't need a dependency on the namespace, because there'll be an
1058  * indirect dependency via our parent table.
1059  *
1060  * During bootstrap we can't register any dependencies, and we don't try
1061  * to make a constraint either.
1062  */
1064  {
1065  ObjectAddress myself,
1066  referenced;
1067  ObjectAddresses *addrs;
1068 
1069  ObjectAddressSet(myself, RelationRelationId, indexRelationId);
1070 
1071  if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)
1072  {
1073  char constraintType;
1074  ObjectAddress localaddr;
1075 
1076  if (isprimary)
1077  constraintType = CONSTRAINT_PRIMARY;
1078  else if (indexInfo->ii_Unique)
1079  constraintType = CONSTRAINT_UNIQUE;
1080  else if (is_exclusion)
1081  constraintType = CONSTRAINT_EXCLUSION;
1082  else
1083  {
1084  elog(ERROR, "constraint must be PRIMARY, UNIQUE or EXCLUDE");
1085  constraintType = 0; /* keep compiler quiet */
1086  }
1087 
1088  localaddr = index_constraint_create(heapRelation,
1089  indexRelationId,
1090  parentConstraintId,
1091  indexInfo,
1092  indexRelationName,
1093  constraintType,
1094  constr_flags,
1095  allow_system_table_mods,
1096  is_internal);
1097  if (constraintId)
1098  *constraintId = localaddr.objectId;
1099  }
1100  else
1101  {
1102  bool have_simple_col = false;
1103 
1104  addrs = new_object_addresses();
1105 
1106  /* Create auto dependencies on simply-referenced columns */
1107  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1108  {
1109  if (indexInfo->ii_IndexAttrNumbers[i] != 0)
1110  {
1111  ObjectAddressSubSet(referenced, RelationRelationId,
1112  heapRelationId,
1113  indexInfo->ii_IndexAttrNumbers[i]);
1114  add_exact_object_address(&referenced, addrs);
1115  have_simple_col = true;
1116  }
1117  }
1118 
1119  /*
1120  * If there are no simply-referenced columns, give the index an
1121  * auto dependency on the whole table. In most cases, this will
1122  * be redundant, but it might not be if the index expressions and
1123  * predicate contain no Vars or only whole-row Vars.
1124  */
1125  if (!have_simple_col)
1126  {
1127  ObjectAddressSet(referenced, RelationRelationId,
1128  heapRelationId);
1129  add_exact_object_address(&referenced, addrs);
1130  }
1131 
1133  free_object_addresses(addrs);
1134  }
1135 
1136  /*
1137  * If this is an index partition, create partition dependencies on
1138  * both the parent index and the table. (Note: these must be *in
1139  * addition to*, not instead of, all other dependencies. Otherwise
1140  * we'll be short some dependencies after DETACH PARTITION.)
1141  */
1142  if (OidIsValid(parentIndexRelid))
1143  {
1144  ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid);
1145  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
1146 
1147  ObjectAddressSet(referenced, RelationRelationId, heapRelationId);
1148  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
1149  }
1150 
1151  /* placeholder for normal dependencies */
1152  addrs = new_object_addresses();
1153 
1154  /* Store dependency on collations */
1155 
1156  /* The default collation is pinned, so don't bother recording it */
1157  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1158  {
1159  if (OidIsValid(collationIds[i]) && collationIds[i] != DEFAULT_COLLATION_OID)
1160  {
1161  ObjectAddressSet(referenced, CollationRelationId, collationIds[i]);
1162  add_exact_object_address(&referenced, addrs);
1163  }
1164  }
1165 
1166  /* Store dependency on operator classes */
1167  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1168  {
1169  ObjectAddressSet(referenced, OperatorClassRelationId, opclassIds[i]);
1170  add_exact_object_address(&referenced, addrs);
1171  }
1172 
1174  free_object_addresses(addrs);
1175 
1176  /* Store dependencies on anything mentioned in index expressions */
1177  if (indexInfo->ii_Expressions)
1178  {
1180  (Node *) indexInfo->ii_Expressions,
1181  heapRelationId,
1183  DEPENDENCY_AUTO, false);
1184  }
1185 
1186  /* Store dependencies on anything mentioned in predicate */
1187  if (indexInfo->ii_Predicate)
1188  {
1190  (Node *) indexInfo->ii_Predicate,
1191  heapRelationId,
1193  DEPENDENCY_AUTO, false);
1194  }
1195  }
1196  else
1197  {
1198  /* Bootstrap mode - assert we weren't asked for constraint support */
1199  Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
1200  }
1201 
1202  /* Post creation hook for new index */
1203  InvokeObjectPostCreateHookArg(RelationRelationId,
1204  indexRelationId, 0, is_internal);
1205 
1206  /*
1207  * Advance the command counter so that we can see the newly-entered
1208  * catalog tuples for the index.
1209  */
1211 
1212  /*
1213  * In bootstrap mode, we have to fill in the index strategy structure with
1214  * information from the catalogs. If we aren't bootstrapping, then the
1215  * relcache entry has already been rebuilt thanks to sinval update during
1216  * CommandCounterIncrement.
1217  */
1219  RelationInitIndexAccessInfo(indexRelation);
1220  else
1221  Assert(indexRelation->rd_indexcxt != NULL);
1222 
1223  indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs;
1224 
1225  /* Validate opclass-specific options */
1226  if (indexInfo->ii_OpclassOptions)
1227  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1228  (void) index_opclass_options(indexRelation, i + 1,
1229  indexInfo->ii_OpclassOptions[i],
1230  true);
1231 
1232  /*
1233  * If this is bootstrap (initdb) time, then we don't actually fill in the
1234  * index yet. We'll be creating more indexes and classes later, so we
1235  * delay filling them in until just before we're done with bootstrapping.
1236  * Similarly, if the caller specified to skip the build then filling the
1237  * index is delayed till later (ALTER TABLE can save work in some cases
1238  * with this). Otherwise, we call the AM routine that constructs the
1239  * index.
1240  */
1242  {
1243  index_register(heapRelationId, indexRelationId, indexInfo);
1244  }
1245  else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0)
1246  {
1247  /*
1248  * Caller is responsible for filling the index later on. However,
1249  * we'd better make sure that the heap relation is correctly marked as
1250  * having an index.
1251  */
1252  index_update_stats(heapRelation,
1253  true,
1254  -1.0);
1255  /* Make the above update visible */
1257  }
1258  else
1259  {
1260  index_build(heapRelation, indexRelation, indexInfo, false, true);
1261  }
1262 
1263  /*
1264  * Close the index; but we keep the lock that we acquired above until end
1265  * of transaction. Closing the heap is caller's responsibility.
1266  */
1267  index_close(indexRelation, NoLock);
1268 
1269  return indexRelationId;
1270 }
void index_register(Oid heap, Oid ind, const IndexInfo *indexInfo)
Definition: bootstrap.c:906
TransactionId MultiXactId
Definition: c.h:651
uint32 TransactionId
Definition: c.h:641
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:502
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:105
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2790
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1645
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define NOTICE
Definition: elog.h:35
bool IsBinaryUpgrade
Definition: globals.c:114
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:882
Relation heap_create(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, RelFileNumber relfilenumber, Oid accessmtd, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, bool create_storage)
Definition: heap.c:288
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:90
static void AppendAttributeTuples(Relation indexRelation, const Datum *attopts)
Definition: index.c:516
static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid)
Definition: index.c:498
Oid binary_upgrade_next_index_pg_class_oid
Definition: index.c:89
static TupleDesc ConstructTupleDescriptor(Relation heapRelation, const IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, const Oid *collationIds, const Oid *opclassIds)
Definition: index.c:285
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1903
static void UpdateIndexRelation(Oid indexoid, Oid heapoid, Oid parentIndexId, const IndexInfo *indexInfo, const Oid *collationOids, const Oid *opclassOids, const int16 *coloptions, bool primary, bool isexclusion, bool immediate, bool isvalid, bool isready)
Definition: index.c:548
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:61
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:65
#define INDEX_CREATE_PARTITIONED
Definition: index.h:66
#define INDEX_CREATE_INVALID
Definition: index.h:67
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:62
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:947
invalidindex index d is invalid
Definition: isn.c:134
void LockRelation(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:245
#define AccessExclusiveLock
Definition: lockdefs.h:43
bool get_collation_isdeterministic(Oid colloid)
Definition: lsyscache.c:1080
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1889
#define InvalidMultiXactId
Definition: multixact.h:24
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
@ CONSTRAINT_RELATION
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define RelationIsMapped(relation)
Definition: rel.h:553
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1417
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Form_pg_index rd_index
Definition: rel.h:191
MemoryContext rd_indexcxt
Definition: rel.h:203
@ CLAOID
Definition: syscache.h:48
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3425
#define InvalidTransactionId
Definition: transam.h:31

References AccessExclusiveLock, add_exact_object_address(), AppendAttributeTuples(), Assert(), binary_upgrade_next_index_pg_class_oid, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CLAOID, CommandCounterIncrement(), CONSTRAINT_RELATION, ConstraintNameIsUsed(), ConstructTupleDescriptor(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, free_object_addresses(), get_collation_isdeterministic(), get_relname_relid(), GetNewRelFileNumber(), GETSTRUCT, heap_create(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_OpclassOptions, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, index_build(), index_close(), INDEX_CONSTR_CREATE_DEFERRABLE, index_constraint_create(), INDEX_CREATE_ADD_CONSTRAINT, INDEX_CREATE_CONCURRENT, INDEX_CREATE_IF_NOT_EXISTS, INDEX_CREATE_INVALID, INDEX_CREATE_IS_PRIMARY, INDEX_CREATE_PARTITIONED, INDEX_CREATE_SKIP_BUILD, index_opclass_options(), index_register(), index_update_stats(), InitializeAttributeOids(), InsertPgClassTuple(), invalid, InvalidMultiXactId, InvalidOid, InvalidRelFileNumber, InvalidTransactionId, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsCatalogRelation(), IsNormalProcessingMode, IsSystemRelation(), LockRelation(), NameStr, new_object_addresses(), NoLock, NOTICE, ObjectAddressSet, ObjectAddressSubSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_rel, record_object_address_dependencies(), recordDependencyOn(), recordDependencyOnSingleRelExpr(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationInitIndexAccessInfo(), RelationIsMapped, ReleaseSysCache(), RelFileNumberIsValid, RowExclusiveLock, SearchSysCache1(), SetRelationHasSubclass(), StoreSingleInheritance(), table_close(), table_open(), and UpdateIndexRelation().

Referenced by create_toast_table(), DefineIndex(), and index_concurrently_create_copy().

◆ index_drop()

void index_drop ( Oid  indexId,
bool  concurrent,
bool  concurrent_lock_mode 
)

Definition at line 2136 of file index.c.

2137 {
2138  Oid heapId;
2139  Relation userHeapRelation;
2140  Relation userIndexRelation;
2141  Relation indexRelation;
2142  HeapTuple tuple;
2143  bool hasexprs;
2144  LockRelId heaprelid,
2145  indexrelid;
2146  LOCKTAG heaplocktag;
2147  LOCKMODE lockmode;
2148 
2149  /*
2150  * A temporary relation uses a non-concurrent DROP. Other backends can't
2151  * access a temporary relation, so there's no harm in grabbing a stronger
2152  * lock (see comments in RemoveRelations), and a non-concurrent DROP is
2153  * more efficient.
2154  */
2155  Assert(get_rel_persistence(indexId) != RELPERSISTENCE_TEMP ||
2156  (!concurrent && !concurrent_lock_mode));
2157 
2158  /*
2159  * To drop an index safely, we must grab exclusive lock on its parent
2160  * table. Exclusive lock on the index alone is insufficient because
2161  * another backend might be about to execute a query on the parent table.
2162  * If it relies on a previously cached list of index OIDs, then it could
2163  * attempt to access the just-dropped index. We must therefore take a
2164  * table lock strong enough to prevent all queries on the table from
2165  * proceeding until we commit and send out a shared-cache-inval notice
2166  * that will make them update their index lists.
2167  *
2168  * In the concurrent case we avoid this requirement by disabling index use
2169  * in multiple steps and waiting out any transactions that might be using
2170  * the index, so we don't need exclusive lock on the parent table. Instead
2171  * we take ShareUpdateExclusiveLock, to ensure that two sessions aren't
2172  * doing CREATE/DROP INDEX CONCURRENTLY on the same index. (We will get
2173  * AccessExclusiveLock on the index below, once we're sure nobody else is
2174  * using it.)
2175  */
2176  heapId = IndexGetRelation(indexId, false);
2177  lockmode = (concurrent || concurrent_lock_mode) ? ShareUpdateExclusiveLock : AccessExclusiveLock;
2178  userHeapRelation = table_open(heapId, lockmode);
2179  userIndexRelation = index_open(indexId, lockmode);
2180 
2181  /*
2182  * We might still have open queries using it in our own session, which the
2183  * above locking won't prevent, so test explicitly.
2184  */
2185  CheckTableNotInUse(userIndexRelation, "DROP INDEX");
2186 
2187  /*
2188  * Drop Index Concurrently is more or less the reverse process of Create
2189  * Index Concurrently.
2190  *
2191  * First we unset indisvalid so queries starting afterwards don't use the
2192  * index to answer queries anymore. We have to keep indisready = true so
2193  * transactions that are still scanning the index can continue to see
2194  * valid index contents. For instance, if they are using READ COMMITTED
2195  * mode, and another transaction makes changes and commits, they need to
2196  * see those new tuples in the index.
2197  *
2198  * After all transactions that could possibly have used the index for
2199  * queries end, we can unset indisready and indislive, then wait till
2200  * nobody could be touching it anymore. (Note: we need indislive because
2201  * this state must be distinct from the initial state during CREATE INDEX
2202  * CONCURRENTLY, which has indislive true while indisready and indisvalid
2203  * are false. That's because in that state, transactions must examine the
2204  * index for HOT-safety decisions, while in this state we don't want them
2205  * to open it at all.)
2206  *
2207  * Since all predicate locks on the index are about to be made invalid, we
2208  * must promote them to predicate locks on the heap. In the
2209  * non-concurrent case we can just do that now. In the concurrent case
2210  * it's a bit trickier. The predicate locks must be moved when there are
2211  * no index scans in progress on the index and no more can subsequently
2212  * start, so that no new predicate locks can be made on the index. Also,
2213  * they must be moved before heap inserts stop maintaining the index, else
2214  * the conflict with the predicate lock on the index gap could be missed
2215  * before the lock on the heap relation is in place to detect a conflict
2216  * based on the heap tuple insert.
2217  */
2218  if (concurrent)
2219  {
2220  /*
2221  * We must commit our transaction in order to make the first pg_index
2222  * state update visible to other sessions. If the DROP machinery has
2223  * already performed any other actions (removal of other objects,
2224  * pg_depend entries, etc), the commit would make those actions
2225  * permanent, which would leave us with inconsistent catalog state if
2226  * we fail partway through the following sequence. Since DROP INDEX
2227  * CONCURRENTLY is restricted to dropping just one index that has no
2228  * dependencies, we should get here before anything's been done ---
2229  * but let's check that to be sure. We can verify that the current
2230  * transaction has not executed any transactional updates by checking
2231  * that no XID has been assigned.
2232  */
2234  ereport(ERROR,
2235  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2236  errmsg("DROP INDEX CONCURRENTLY must be first action in transaction")));
2237 
2238  /*
2239  * Mark index invalid by updating its pg_index entry
2240  */
2242 
2243  /*
2244  * Invalidate the relcache for the table, so that after this commit
2245  * all sessions will refresh any cached plans that might reference the
2246  * index.
2247  */
2248  CacheInvalidateRelcache(userHeapRelation);
2249 
2250  /* save lockrelid and locktag for below, then close but keep locks */
2251  heaprelid = userHeapRelation->rd_lockInfo.lockRelId;
2252  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
2253  indexrelid = userIndexRelation->rd_lockInfo.lockRelId;
2254 
2255  table_close(userHeapRelation, NoLock);
2256  index_close(userIndexRelation, NoLock);
2257 
2258  /*
2259  * We must commit our current transaction so that the indisvalid
2260  * update becomes visible to other transactions; then start another.
2261  * Note that any previously-built data structures are lost in the
2262  * commit. The only data we keep past here are the relation IDs.
2263  *
2264  * Before committing, get a session-level lock on the table, to ensure
2265  * that neither it nor the index can be dropped before we finish. This
2266  * cannot block, even if someone else is waiting for access, because
2267  * we already have the same lock within our transaction.
2268  */
2271 
2275 
2276  /*
2277  * Now we must wait until no running transaction could be using the
2278  * index for a query. Use AccessExclusiveLock here to check for
2279  * running transactions that hold locks of any kind on the table. Note
2280  * we do not need to worry about xacts that open the table for reading
2281  * after this point; they will see the index as invalid when they open
2282  * the relation.
2283  *
2284  * Note: the reason we use actual lock acquisition here, rather than
2285  * just checking the ProcArray and sleeping, is that deadlock is
2286  * possible if one of the transactions in question is blocked trying
2287  * to acquire an exclusive lock on our table. The lock code will
2288  * detect deadlock and error out properly.
2289  *
2290  * Note: we report progress through WaitForLockers() unconditionally
2291  * here, even though it will only be used when we're called by REINDEX
2292  * CONCURRENTLY and not when called by DROP INDEX CONCURRENTLY.
2293  */
2294  WaitForLockers(heaplocktag, AccessExclusiveLock, true);
2295 
2296  /* Finish invalidation of index and mark it as dead */
2297  index_concurrently_set_dead(heapId, indexId);
2298 
2299  /*
2300  * Again, commit the transaction to make the pg_index update visible
2301  * to other sessions.
2302  */
2305 
2306  /*
2307  * Wait till every transaction that saw the old index state has
2308  * finished. See above about progress reporting.
2309  */
2310  WaitForLockers(heaplocktag, AccessExclusiveLock, true);
2311 
2312  /*
2313  * Re-open relations to allow us to complete our actions.
2314  *
2315  * At this point, nothing should be accessing the index, but lets
2316  * leave nothing to chance and grab AccessExclusiveLock on the index
2317  * before the physical deletion.
2318  */
2319  userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock);
2320  userIndexRelation = index_open(indexId, AccessExclusiveLock);
2321  }
2322  else
2323  {
2324  /* Not concurrent, so just transfer predicate locks and we're good */
2325  TransferPredicateLocksToHeapRelation(userIndexRelation);
2326  }
2327 
2328  /*
2329  * Schedule physical removal of the files (if any)
2330  */
2331  if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
2332  RelationDropStorage(userIndexRelation);
2333 
2334  /* ensure that stats are dropped if transaction commits */
2335  pgstat_drop_relation(userIndexRelation);
2336 
2337  /*
2338  * Close and flush the index's relcache entry, to ensure relcache doesn't
2339  * try to rebuild it while we're deleting catalog entries. We keep the
2340  * lock though.
2341  */
2342  index_close(userIndexRelation, NoLock);
2343 
2344  RelationForgetRelation(indexId);
2345 
2346  /*
2347  * fix INDEX relation, and check for expressional index
2348  */
2349  indexRelation = table_open(IndexRelationId, RowExclusiveLock);
2350 
2351  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2352  if (!HeapTupleIsValid(tuple))
2353  elog(ERROR, "cache lookup failed for index %u", indexId);
2354 
2355  hasexprs = !heap_attisnull(tuple, Anum_pg_index_indexprs,
2356  RelationGetDescr(indexRelation));
2357 
2358  CatalogTupleDelete(indexRelation, &tuple->t_self);
2359 
2360  ReleaseSysCache(tuple);
2361  table_close(indexRelation, RowExclusiveLock);
2362 
2363  /*
2364  * if it has any expression columns, we might have stored statistics about
2365  * them.
2366  */
2367  if (hasexprs)
2368  RemoveStatistics(indexId, 0);
2369 
2370  /*
2371  * fix ATTRIBUTE relation
2372  */
2373  DeleteAttributeTuples(indexId);
2374 
2375  /*
2376  * fix RELATION relation
2377  */
2378  DeleteRelationTuple(indexId);
2379 
2380  /*
2381  * fix INHERITS relation
2382  */
2383  DeleteInheritsTuple(indexId, InvalidOid, false, NULL);
2384 
2385  /*
2386  * We are presently too lazy to attempt to compute the new correct value
2387  * of relhasindex (the next VACUUM will fix it if necessary). So there is
2388  * no need to update the pg_class tuple for the owning relation. But we
2389  * must send out a shared-cache-inval notice on the owning relation to
2390  * ensure other backends update their relcache lists of indexes. (In the
2391  * concurrent case, this is redundant but harmless.)
2392  */
2393  CacheInvalidateRelcache(userHeapRelation);
2394 
2395  /*
2396  * Close owning rel, but keep lock
2397  */
2398  table_close(userHeapRelation, NoLock);
2399 
2400  /*
2401  * Release the session locks before we go.
2402  */
2403  if (concurrent)
2404  {
2407  }
2408 }
void DeleteRelationTuple(Oid relid)
Definition: heap.c:1536
void DeleteAttributeTuples(Oid relid)
Definition: heap.c:1565
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:3238
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:447
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3539
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition: index.c:1842
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:398
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:986
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:411
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
int LOCKMODE
Definition: lockdefs.h:26
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:2082
void pgstat_drop_relation(Relation rel)
void RelationForgetRelation(Oid rid)
Definition: relcache.c:2834
void PopActiveSnapshot(void)
Definition: snapmgr.c:724
void RelationDropStorage(Relation rel)
Definition: storage.c:205
Definition: lock.h:165
LockRelId lockRelId
Definition: rel.h:46
Definition: rel.h:39
Oid relId
Definition: rel.h:40
Oid dbId
Definition: rel.h:41
LockInfoData rd_lockInfo
Definition: rel.h:114
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4183
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:432
void StartTransactionCommand(void)
Definition: xact.c:2937
void CommitTransactionCommand(void)
Definition: xact.c:3034

References AccessExclusiveLock, Assert(), CacheInvalidateRelcache(), CatalogTupleDelete(), CheckTableNotInUse(), CommitTransactionCommand(), LockRelId::dbId, DeleteAttributeTuples(), DeleteInheritsTuple(), DeleteRelationTuple(), elog(), ereport, errcode(), errmsg(), ERROR, get_rel_persistence(), GetTopTransactionIdIfAny(), heap_attisnull(), HeapTupleIsValid, index_close(), index_concurrently_set_dead(), INDEX_DROP_CLEAR_VALID, index_open(), index_set_state_flags(), IndexGetRelation(), INDEXRELID, InvalidOid, InvalidTransactionId, LockRelationIdForSession(), LockInfoData::lockRelId, NoLock, ObjectIdGetDatum(), pgstat_drop_relation(), PopActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, RelationDropStorage(), RelationForgetRelation(), RelationGetDescr, ReleaseSysCache(), LockRelId::relId, RemoveStatistics(), RowExclusiveLock, SearchSysCache1(), SET_LOCKTAG_RELATION, ShareUpdateExclusiveLock, StartTransactionCommand(), HeapTupleData::t_self, table_close(), table_open(), TransferPredicateLocksToHeapRelation(), UnlockRelationIdForSession(), and WaitForLockers().

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3459 of file index.c.

3460 {
3461  Relation pg_index;
3462  HeapTuple indexTuple;
3463  Form_pg_index indexForm;
3464 
3465  /* Open pg_index and fetch a writable copy of the index's tuple */
3466  pg_index = table_open(IndexRelationId, RowExclusiveLock);
3467 
3468  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3469  ObjectIdGetDatum(indexId));
3470  if (!HeapTupleIsValid(indexTuple))
3471  elog(ERROR, "cache lookup failed for index %u", indexId);
3472  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3473 
3474  /* Perform the requested state change on the copy */
3475  switch (action)
3476  {
3478  /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3479  Assert(indexForm->indislive);
3480  Assert(!indexForm->indisready);
3481  Assert(!indexForm->indisvalid);
3482  indexForm->indisready = true;
3483  break;
3485  /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3486  Assert(indexForm->indislive);
3487  Assert(indexForm->indisready);
3488  Assert(!indexForm->indisvalid);
3489  indexForm->indisvalid = true;
3490  break;
3492 
3493  /*
3494  * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3495  *
3496  * If indisready == true we leave it set so the index still gets
3497  * maintained by active transactions. We only need to ensure that
3498  * indisvalid is false. (We don't assert that either is initially
3499  * true, though, since we want to be able to retry a DROP INDEX
3500  * CONCURRENTLY that failed partway through.)
3501  *
3502  * Note: the CLUSTER logic assumes that indisclustered cannot be
3503  * set on any invalid index, so clear that flag too. For
3504  * cleanliness, also clear indisreplident.
3505  */
3506  indexForm->indisvalid = false;
3507  indexForm->indisclustered = false;
3508  indexForm->indisreplident = false;
3509  break;
3510  case INDEX_DROP_SET_DEAD:
3511 
3512  /*
3513  * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3514  *
3515  * We clear both indisready and indislive, because we not only
3516  * want to stop updates, we want to prevent sessions from touching
3517  * the index at all.
3518  */
3519  Assert(!indexForm->indisvalid);
3520  Assert(!indexForm->indisclustered);
3521  Assert(!indexForm->indisreplident);
3522  indexForm->indisready = false;
3523  indexForm->indislive = false;
3524  break;
3525  }
3526 
3527  /* ... and update it */
3528  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3529 
3530  table_close(pg_index, RowExclusiveLock);
3531 }

References generate_unaccent_rules::action, Assert(), CatalogTupleUpdate(), elog(), ERROR, GETSTRUCT, HeapTupleIsValid, INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_DROP_CLEAR_VALID, INDEX_DROP_SET_DEAD, INDEXRELID, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by DefineIndex(), index_concurrently_build(), index_concurrently_set_dead(), and index_drop().

◆ IndexGetRelation()

Oid IndexGetRelation ( Oid  indexId,
bool  missing_ok 
)

Definition at line 3539 of file index.c.

3540 {
3541  HeapTuple tuple;
3543  Oid result;
3544 
3545  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3546  if (!HeapTupleIsValid(tuple))
3547  {
3548  if (missing_ok)
3549  return InvalidOid;
3550  elog(ERROR, "cache lookup failed for index %u", indexId);
3551  }
3552  index = (Form_pg_index) GETSTRUCT(tuple);
3553  Assert(index->indexrelid == indexId);
3554 
3555  result = index->indrelid;
3556  ReleaseSysCache(tuple);
3557  return result;
3558 }

References Assert(), elog(), ERROR, GETSTRUCT, HeapTupleIsValid, INDEXRELID, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache1().

Referenced by brin_desummarize_range(), brin_summarize_range(), bringetbitmap(), brinvacuumcleanup(), bt_index_check_internal(), CheckIndexCompatible(), DetachPartitionFinalize(), get_tables_to_cluster_partitioned(), index_drop(), RangeVarCallbackForAttachIndex(), RangeVarCallbackForDropRelation(), RangeVarCallbackForReindexIndex(), reindex_index(), and ReindexRelationConcurrently().

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 4261 of file indexcmds.c.

4262 {
4263  Relation pg_inherits;
4264  ScanKeyData key[2];
4265  SysScanDesc scan;
4266  Oid partRelid = RelationGetRelid(partitionIdx);
4267  HeapTuple tuple;
4268  bool fix_dependencies;
4269 
4270  /* Make sure this is an index */
4271  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4272  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4273 
4274  /*
4275  * Scan pg_inherits for rows linking our index to some parent.
4276  */
4277  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
4278  ScanKeyInit(&key[0],
4279  Anum_pg_inherits_inhrelid,
4280  BTEqualStrategyNumber, F_OIDEQ,
4281  ObjectIdGetDatum(partRelid));
4282  ScanKeyInit(&key[1],
4283  Anum_pg_inherits_inhseqno,
4284  BTEqualStrategyNumber, F_INT4EQ,
4285  Int32GetDatum(1));
4286  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
4287  NULL, 2, key);
4288  tuple = systable_getnext(scan);
4289 
4290  if (!HeapTupleIsValid(tuple))
4291  {
4292  if (parentOid == InvalidOid)
4293  {
4294  /*
4295  * No pg_inherits row, and no parent wanted: nothing to do in this
4296  * case.
4297  */
4298  fix_dependencies = false;
4299  }
4300  else
4301  {
4302  StoreSingleInheritance(partRelid, parentOid, 1);
4303  fix_dependencies = true;
4304  }
4305  }
4306  else
4307  {
4308  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
4309 
4310  if (parentOid == InvalidOid)
4311  {
4312  /*
4313  * There exists a pg_inherits row, which we want to clear; do so.
4314  */
4315  CatalogTupleDelete(pg_inherits, &tuple->t_self);
4316  fix_dependencies = true;
4317  }
4318  else
4319  {
4320  /*
4321  * A pg_inherits row exists. If it's the same we want, then we're
4322  * good; if it differs, that amounts to a corrupt catalog and
4323  * should not happen.
4324  */
4325  if (inhForm->inhparent != parentOid)
4326  {
4327  /* unexpected: we should not get called in this case */
4328  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4329  inhForm->inhrelid, inhForm->inhparent);
4330  }
4331 
4332  /* already in the right state */
4333  fix_dependencies = false;
4334  }
4335  }
4336 
4337  /* done with pg_inherits */
4338  systable_endscan(scan);
4339  relation_close(pg_inherits, RowExclusiveLock);
4340 
4341  /* set relhassubclass if an index partition has been added to the parent */
4342  if (OidIsValid(parentOid))
4343  SetRelationHasSubclass(parentOid, true);
4344 
4345  /* set relispartition correctly on the partition */
4346  update_relispartition(partRelid, OidIsValid(parentOid));
4347 
4348  if (fix_dependencies)
4349  {
4350  /*
4351  * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4352  * dependencies on the parent index and the table; if removing a
4353  * parent, delete PARTITION dependencies.
4354  */
4355  if (OidIsValid(parentOid))
4356  {
4357  ObjectAddress partIdx;
4358  ObjectAddress parentIdx;
4359  ObjectAddress partitionTbl;
4360 
4361  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
4362  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
4363  ObjectAddressSet(partitionTbl, RelationRelationId,
4364  partitionIdx->rd_index->indrelid);
4365  recordDependencyOn(&partIdx, &parentIdx,
4367  recordDependencyOn(&partIdx, &partitionTbl,
4369  }
4370  else
4371  {
4372  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4373  RelationRelationId,
4375  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4376  RelationRelationId,
4378  }
4379 
4380  /* make our updates visible */
4382  }
4383 }
static void update_relispartition(Oid relationId, bool newval)
Definition: indexcmds.c:4390
static void fix_dependencies(ArchiveHandle *AH)
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45

References Assert(), BTEqualStrategyNumber, CatalogTupleDelete(), CommandCounterIncrement(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog(), ERROR, fix_dependencies(), GETSTRUCT, HeapTupleIsValid, Int32GetDatum(), InvalidOid, sort-test::key, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, RelationData::rd_index, RelationData::rd_rel, recordDependencyOn(), relation_close(), relation_open(), RelationGetRelid, RowExclusiveLock, ScanKeyInit(), SetRelationHasSubclass(), StoreSingleInheritance(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and update_relispartition().

Referenced by ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), DefineIndex(), and DetachPartitionFinalize().

◆ itemptr_decode()

static void itemptr_decode ( ItemPointer  itemptr,
int64  encoded 
)
inlinestatic

Definition at line 206 of file index.h.

207 {
208  BlockNumber block = (BlockNumber) (encoded >> 16);
209  OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
210 
211  ItemPointerSet(itemptr, block, offset);
212 }
uint32 BlockNumber
Definition: block.h:31
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
uint16 OffsetNumber
Definition: off.h:24

References ItemPointerSet().

Referenced by heapam_index_validate_scan().

◆ itemptr_encode()

static int64 itemptr_encode ( ItemPointer  itemptr)
inlinestatic

Definition at line 185 of file index.h.

186 {
187  BlockNumber block = ItemPointerGetBlockNumber(itemptr);
188  OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr);
189  int64 encoded;
190 
191  /*
192  * Use the 16 least significant bits for the offset. 32 adjacent bits are
193  * used for the block number. Since remaining bits are unused, there
194  * cannot be negative encoded values (We assume a two's complement
195  * representation).
196  */
197  encoded = ((uint64) block << 16) | (uint16) offset;
198 
199  return encoded;
200 }
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103

References ItemPointerGetBlockNumber(), and ItemPointerGetOffsetNumber().

Referenced by vac_tid_reaped(), and validate_index_callback().

◆ reindex_index()

void reindex_index ( Oid  indexId,
bool  skip_constraint_checks,
char  persistence,
const ReindexParams params 
)

Definition at line 3564 of file index.c.

3566 {
3567  Relation iRel,
3568  heapRelation;
3569  Oid heapId;
3570  Oid save_userid;
3571  int save_sec_context;
3572  int save_nestlevel;
3573  IndexInfo *indexInfo;
3574  volatile bool skipped_constraint = false;
3575  PGRUsage ru0;
3576  bool progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
3577  bool set_tablespace = false;
3578 
3579  pg_rusage_init(&ru0);
3580 
3581  /*
3582  * Open and lock the parent heap relation. ShareLock is sufficient since
3583  * we only need to be sure no schema or data changes are going on.
3584  */
3585  heapId = IndexGetRelation(indexId,
3586  (params->options & REINDEXOPT_MISSING_OK) != 0);
3587  /* if relation is missing, leave */
3588  if (!OidIsValid(heapId))
3589  return;
3590 
3591  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3592  heapRelation = try_table_open(heapId, ShareLock);
3593  else
3594  heapRelation = table_open(heapId, ShareLock);
3595 
3596  /* if relation is gone, leave */
3597  if (!heapRelation)
3598  return;
3599 
3600  /*
3601  * Switch to the table owner's userid, so that any index functions are run
3602  * as that user. Also lock down security-restricted operations and
3603  * arrange to make GUC variable changes local to this command.
3604  */
3605  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3606  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3607  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3608  save_nestlevel = NewGUCNestLevel();
3609 
3610  if (progress)
3611  {
3612  const int progress_cols[] = {
3615  };
3616  const int64 progress_vals[] = {
3618  indexId
3619  };
3620 
3622  heapId);
3623  pgstat_progress_update_multi_param(2, progress_cols, progress_vals);
3624  }
3625 
3626  /*
3627  * Open the target index relation and get an exclusive lock on it, to
3628  * ensure that no one else is touching this particular index.
3629  */
3630  iRel = index_open(indexId, AccessExclusiveLock);
3631 
3632  if (progress)
3634  iRel->rd_rel->relam);
3635 
3636  /*
3637  * Partitioned indexes should never get processed here, as they have no
3638  * physical storage.
3639  */
3640  if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3641  elog(ERROR, "cannot reindex partitioned index \"%s.%s\"",
3643  RelationGetRelationName(iRel));
3644 
3645  /*
3646  * Don't allow reindex on temp tables of other backends ... their local
3647  * buffer manager is not going to cope.
3648  */
3649  if (RELATION_IS_OTHER_TEMP(iRel))
3650  ereport(ERROR,
3651  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3652  errmsg("cannot reindex temporary tables of other sessions")));
3653 
3654  /*
3655  * Don't allow reindex of an invalid index on TOAST table. This is a
3656  * leftover from a failed REINDEX CONCURRENTLY, and if rebuilt it would
3657  * not be possible to drop it anymore.
3658  */
3660  !get_index_isvalid(indexId))
3661  ereport(ERROR,
3662  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3663  errmsg("cannot reindex invalid index on TOAST table")));
3664 
3665  /*
3666  * System relations cannot be moved even if allow_system_table_mods is
3667  * enabled to keep things consistent with the concurrent case where all
3668  * the indexes of a relation are processed in series, including indexes of
3669  * toast relations.
3670  *
3671  * Note that this check is not part of CheckRelationTableSpaceMove() as it
3672  * gets used for ALTER TABLE SET TABLESPACE that could cascade across
3673  * toast relations.
3674  */
3675  if (OidIsValid(params->tablespaceOid) &&
3676  IsSystemRelation(iRel))
3677  ereport(ERROR,
3678  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3679  errmsg("cannot move system relation \"%s\"",
3680  RelationGetRelationName(iRel))));
3681 
3682  /* Check if the tablespace of this index needs to be changed */
3683  if (OidIsValid(params->tablespaceOid) &&
3685  set_tablespace = true;
3686 
3687  /*
3688  * Also check for active uses of the index in the current transaction; we
3689  * don't want to reindex underneath an open indexscan.
3690  */
3691  CheckTableNotInUse(iRel, "REINDEX INDEX");
3692 
3693  /* Set new tablespace, if requested */
3694  if (set_tablespace)
3695  {
3696  /* Update its pg_class row */
3698 
3699  /*
3700  * Schedule unlinking of the old index storage at transaction commit.
3701  */
3702  RelationDropStorage(iRel);
3704 
3705  /* Make sure the reltablespace change is visible */
3707  }
3708 
3709  /*
3710  * All predicate locks on the index are about to be made invalid. Promote
3711  * them to relation locks on the heap.
3712  */
3714 
3715  /* Fetch info needed for index_build */
3716  indexInfo = BuildIndexInfo(iRel);
3717 
3718  /* If requested, skip checking uniqueness/exclusion constraints */
3719  if (skip_constraint_checks)
3720  {
3721  if (indexInfo->ii_Unique || indexInfo->ii_ExclusionOps != NULL)
3722  skipped_constraint = true;
3723  indexInfo->ii_Unique = false;
3724  indexInfo->ii_ExclusionOps = NULL;
3725  indexInfo->ii_ExclusionProcs = NULL;
3726  indexInfo->ii_ExclusionStrats = NULL;
3727  }
3728 
3729  /* Suppress use of the target index while rebuilding it */
3730  SetReindexProcessing(heapId, indexId);
3731 
3732  /* Create a new physical relation for the index */
3733  RelationSetNewRelfilenumber(iRel, persistence);
3734 
3735  /* Initialize the index and rebuild */
3736  /* Note: we do not need to re-establish pkey setting */
3737  index_build(heapRelation, iRel, indexInfo, true, true);
3738 
3739  /* Re-allow use of target index */
3741 
3742  /*
3743  * If the index is marked invalid/not-ready/dead (ie, it's from a failed
3744  * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway),
3745  * and we didn't skip a uniqueness check, we can now mark it valid. This
3746  * allows REINDEX to be used to clean up in such cases.
3747  *
3748  * We can also reset indcheckxmin, because we have now done a
3749  * non-concurrent index build, *except* in the case where index_build
3750  * found some still-broken HOT chains. If it did, and we don't have to
3751  * change any of the other flags, we just leave indcheckxmin alone (note
3752  * that index_build won't have changed it, because this is a reindex).
3753  * This is okay and desirable because not updating the tuple leaves the
3754  * index's usability horizon (recorded as the tuple's xmin value) the same
3755  * as it was.
3756  *
3757  * But, if the index was invalid/not-ready/dead and there were broken HOT
3758  * chains, we had better force indcheckxmin true, because the normal
3759  * argument that the HOT chains couldn't conflict with the index is
3760  * suspect for an invalid index. (A conflict is definitely possible if
3761  * the index was dead. It probably shouldn't happen otherwise, but let's
3762  * be conservative.) In this case advancing the usability horizon is
3763  * appropriate.
3764  *
3765  * Another reason for avoiding unnecessary updates here is that while
3766  * reindexing pg_index itself, we must not try to update tuples in it.
3767  * pg_index's indexes should always have these flags in their clean state,
3768  * so that won't happen.
3769  */
3770  if (!skipped_constraint)
3771  {
3772  Relation pg_index;
3773  HeapTuple indexTuple;
3774  Form_pg_index indexForm;
3775  bool index_bad;
3776 
3777  pg_index = table_open(IndexRelationId, RowExclusiveLock);
3778 
3779  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3780  ObjectIdGetDatum(indexId));
3781  if (!HeapTupleIsValid(indexTuple))
3782  elog(ERROR, "cache lookup failed for index %u", indexId);
3783  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3784 
3785  index_bad = (!indexForm->indisvalid ||
3786  !indexForm->indisready ||
3787  !indexForm->indislive);
3788  if (index_bad ||
3789  (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
3790  {
3791  if (!indexInfo->ii_BrokenHotChain)
3792  indexForm->indcheckxmin = false;
3793  else if (index_bad)
3794  indexForm->indcheckxmin = true;
3795  indexForm->indisvalid = true;
3796  indexForm->indisready = true;
3797  indexForm->indislive = true;
3798  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3799 
3800  /*
3801  * Invalidate the relcache for the table, so that after we commit
3802  * all sessions will refresh the table's index list. This ensures
3803  * that if anyone misses seeing the pg_index row during this
3804  * update, they'll refresh their list before attempting any update
3805  * on the table.
3806  */
3807  CacheInvalidateRelcache(heapRelation);
3808  }
3809 
3810  table_close(pg_index, RowExclusiveLock);
3811  }
3812 
3813  /* Log what we did */
3814  if ((params->options & REINDEXOPT_VERBOSE) != 0)
3815  ereport(INFO,
3816  (errmsg("index \"%s\" was reindexed",
3817  get_rel_name(indexId)),
3818  errdetail_internal("%s",
3819  pg_rusage_show(&ru0))));
3820 
3821  /* Roll back any GUC changes executed by index functions */
3822  AtEOXact_GUC(false, save_nestlevel);
3823 
3824  /* Restore userid and security context */
3825  SetUserIdAndSecContext(save_userid, save_sec_context);
3826 
3827  /* Close rels, but keep locks */
3828  index_close(iRel, NoLock);
3829  table_close(heapRelation, NoLock);
3830 
3831  if (progress)
3833 }
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_CREATE_INDEX
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1229
#define INFO
Definition: elog.h:34
static void ResetReindexProcessing(void)
Definition: index.c:4075
static void SetReindexProcessing(Oid heapOid, Oid indexOid)
Definition: index.c:4056
#define REINDEXOPT_MISSING_OK
Definition: index.h:43
#define REINDEXOPT_REPORT_PROGRESS
Definition: index.h:42
#define REINDEXOPT_VERBOSE
Definition: index.h:41
#define ShareLock
Definition: lockdefs.h:40
bool get_index_isvalid(Oid index_oid)
Definition: lsyscache.c:3560
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1932
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
int progress
Definition: pgbench.c:261
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition: progress.h:83
#define PROGRESS_CREATEIDX_COMMAND_REINDEX
Definition: progress.h:112
#define PROGRESS_CREATEIDX_INDEX_OID
Definition: progress.h:82
#define PROGRESS_CREATEIDX_COMMAND
Definition: progress.h:81
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:659
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3710
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3909
Oid tablespaceOid
Definition: index.h:36
bits32 options
Definition: index.h:35
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:60
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3466
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition: tablecmds.c:3523

References AccessExclusiveLock, AtEOXact_GUC(), BuildIndexInfo(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CheckRelationTableSpaceMove(), CheckTableNotInUse(), CommandCounterIncrement(), elog(), ereport, errcode(), errdetail_internal(), errmsg(), ERROR, get_index_isvalid(), get_namespace_name(), get_rel_name(), GETSTRUCT, GetUserIdAndSecContext(), HeapTupleIsValid, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Unique, index_build(), index_close(), index_open(), IndexGetRelation(), INDEXRELID, INFO, InvalidOid, IsSystemRelation(), IsToastNamespace(), NewGUCNestLevel(), NoLock, ObjectIdGetDatum(), OidIsValid, ReindexParams::options, pg_rusage_init(), pg_rusage_show(), pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), progress, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_REINDEX, PROGRESS_CREATEIDX_INDEX_OID, RelationData::rd_rel, REINDEXOPT_MISSING_OK, REINDEXOPT_REPORT_PROGRESS, REINDEXOPT_VERBOSE, RELATION_IS_OTHER_TEMP, RelationAssumeNewRelfilelocator(), RelationDropStorage(), RelationGetNamespace, RelationGetRelationName, RelationSetNewRelfilenumber(), ResetReindexProcessing(), RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetReindexProcessing(), SetRelationTableSpace(), SetUserIdAndSecContext(), ShareLock, HeapTupleData::t_self, table_close(), table_open(), ReindexParams::tablespaceOid, TransferPredicateLocksToHeapRelation(), and try_table_open().

Referenced by reindex_relation(), ReindexIndex(), and ReindexMultipleInternal().

◆ reindex_relation()

bool reindex_relation ( Oid  relid,
int  flags,
const ReindexParams params 
)

Definition at line 3871 of file index.c.

3872 {
3873  Relation rel;
3874  Oid toast_relid;
3875  List *indexIds;
3876  char persistence;
3877  bool result;
3878  ListCell *indexId;
3879  int i;
3880 
3881  /*
3882  * Open and lock the relation. ShareLock is sufficient since we only need
3883  * to prevent schema and data changes in it. The lock level used here
3884  * should match ReindexTable().
3885  */
3886  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3887  rel = try_table_open(relid, ShareLock);
3888  else
3889  rel = table_open(relid, ShareLock);
3890 
3891  /* if relation is gone, leave */
3892  if (!rel)
3893  return false;
3894 
3895  /*
3896  * Partitioned tables should never get processed here, as they have no
3897  * physical storage.
3898  */
3899  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3900  elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
3903 
3904  toast_relid = rel->rd_rel->reltoastrelid;
3905 
3906  /*
3907  * Get the list of index OIDs for this relation. (We trust to the
3908  * relcache to get this with a sequential scan if ignoring system
3909  * indexes.)
3910  */
3911  indexIds = RelationGetIndexList(rel);
3912 
3913  if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
3914  {
3915  /* Suppress use of all the indexes until they are rebuilt */
3916  SetReindexPending(indexIds);
3917 
3918  /*
3919  * Make the new heap contents visible --- now things might be
3920  * inconsistent!
3921  */
3923  }
3924 
3925  /*
3926  * Compute persistence of indexes: same as that of owning rel, unless
3927  * caller specified otherwise.
3928  */
3930  persistence = RELPERSISTENCE_UNLOGGED;
3931  else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
3932  persistence = RELPERSISTENCE_PERMANENT;
3933  else
3934  persistence = rel->rd_rel->relpersistence;
3935 
3936  /* Reindex all the indexes. */
3937  i = 1;
3938  foreach(indexId, indexIds)
3939  {
3940  Oid indexOid = lfirst_oid(indexId);
3941  Oid indexNamespaceId = get_rel_namespace(indexOid);
3942 
3943  /*
3944  * Skip any invalid indexes on a TOAST table. These can only be
3945  * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
3946  * rebuilt it would not be possible to drop them anymore.
3947  */
3948  if (IsToastNamespace(indexNamespaceId) &&
3949  !get_index_isvalid(indexOid))
3950  {
3951  ereport(WARNING,
3952  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3953  errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
3954  get_namespace_name(indexNamespaceId),
3955  get_rel_name(indexOid))));
3956  continue;
3957  }
3958 
3959  reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
3960  persistence, params);
3961 
3963 
3964  /* Index should no longer be in the pending list */
3965  Assert(!ReindexIsProcessingIndex(indexOid));
3966 
3967  /* Set index rebuild count */
3969  i);
3970  i++;
3971  }
3972 
3973  /*
3974  * Close rel, but continue to hold the lock.
3975  */
3976  table_close(rel, NoLock);
3977 
3978  result = (indexIds != NIL);
3979 
3980  /*
3981  * If the relation has a secondary toast rel, reindex that too while we
3982  * still hold the lock on the main table.
3983  */
3984  if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
3985  {
3986  /*
3987  * Note that this should fail if the toast relation is missing, so
3988  * reset REINDEXOPT_MISSING_OK. Even if a new tablespace is set for
3989  * the parent relation, the indexes on its toast table are not moved.
3990  * This rule is enforced by setting tablespaceOid to InvalidOid.
3991  */
3992  ReindexParams newparams = *params;
3993 
3994  newparams.options &= ~(REINDEXOPT_MISSING_OK);
3995  newparams.tablespaceOid = InvalidOid;
3996  result |= reindex_relation(toast_relid, flags, &newparams);
3997  }
3998 
3999  return result;
4000 }
#define WARNING
Definition: elog.h:36
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4045
bool reindex_relation(Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3871
static void SetReindexPending(List *indexes)
Definition: index.c:4089
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition: index.c:3564
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:155
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:158
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition: index.h:156
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:159
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:157
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1956
#define PROGRESS_CLUSTER_INDEX_REBUILD_COUNT
Definition: progress.h:64
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4740

References Assert(), CommandCounterIncrement(), elog(), ereport, errcode(), errmsg(), ERROR, get_index_isvalid(), get_namespace_name(), get_rel_name(), get_rel_namespace(), i, InvalidOid, IsToastNamespace(), lfirst_oid, NIL, NoLock, OidIsValid, ReindexParams::options, pgstat_progress_update_param(), PROGRESS_CLUSTER_INDEX_REBUILD_COUNT, RelationData::rd_rel, reindex_index(), REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_FORCE_INDEXES_PERMANENT, REINDEX_REL_FORCE_INDEXES_UNLOGGED, REINDEX_REL_PROCESS_TOAST, REINDEX_REL_SUPPRESS_INDEX_USE, ReindexIsProcessingIndex(), REINDEXOPT_MISSING_OK, RelationGetIndexList(), RelationGetNamespace, RelationGetRelationName, SetReindexPending(), ShareLock, table_close(), table_open(), ReindexParams::tablespaceOid, try_table_open(), and WARNING.

Referenced by ExecuteTruncateGuts(), finish_heap_swap(), ReindexMultipleInternal(), and ReindexTable().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4024 of file index.c.

4025 {
4026  return heapOid == currentlyReindexedHeap;
4027 }
static Oid currentlyReindexedHeap
Definition: index.c:4014

References currentlyReindexedHeap.

Referenced by index_update_stats().

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4045 of file index.c.

4046 {
4047  return indexOid == currentlyReindexedIndex ||
4049 }
static Oid currentlyReindexedIndex
Definition: index.c:4015
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721

References currentlyReindexedIndex, list_member_oid(), and pendingReindexedIndexes.

Referenced by CatalogIndexInsert(), reindex_relation(), systable_beginscan(), and systable_beginscan_ordered().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4118 of file index.c.

4119 {
4120  /*
4121  * Because reindexing is not re-entrant, we don't need to cope with nested
4122  * reindexing states. We just need to avoid messing up the outer-level
4123  * state in case a subtransaction fails within a REINDEX. So checking the
4124  * current nest level against that of the reindex operation is sufficient.
4125  */
4126  if (reindexingNestLevel >= nestLevel)
4127  {
4130 
4131  /*
4132  * We needn't try to release the contents of pendingReindexedIndexes;
4133  * that list should be in a transaction-lifespan context, so it will
4134  * go away automatically.
4135  */
4137 
4138  reindexingNestLevel = 0;
4139  }
4140 }
static int reindexingNestLevel
Definition: index.c:4017

References currentlyReindexedHeap, currentlyReindexedIndex, InvalidOid, NIL, pendingReindexedIndexes, and reindexingNestLevel.

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4176 of file index.c.

4177 {
4178  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4179  int c = 0;
4180  MemoryContext oldcontext;
4181 
4184 
4187  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4190  sistate->pendingReindexedIndexes[c]);
4191  MemoryContextSwitchTo(oldcontext);
4192 
4193  /* Note the worker has its own transaction nesting level */
4195 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
char * c
Oid currentlyReindexedHeap
Definition: index.c:99
Oid currentlyReindexedIndex
Definition: index.c:100
int numPendingReindexedIndexes
Definition: index.c:101
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:102
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:914

References Assert(), SerializedReindexState::currentlyReindexedHeap, currentlyReindexedHeap, SerializedReindexState::currentlyReindexedIndex, currentlyReindexedIndex, GetCurrentTransactionNestLevel(), lappend_oid(), MemoryContextSwitchTo(), NIL, SerializedReindexState::numPendingReindexedIndexes, SerializedReindexState::pendingReindexedIndexes, pendingReindexedIndexes, reindexingNestLevel, and TopMemoryContext.

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ validate_index()

void validate_index ( Oid  heapId,
Oid  indexId,
Snapshot  snapshot 
)

Definition at line 3310 of file index.c.

3311 {
3312  Relation heapRelation,
3313  indexRelation;
3314  IndexInfo *indexInfo;
3315  IndexVacuumInfo ivinfo;
3317  Oid save_userid;
3318  int save_sec_context;
3319  int save_nestlevel;
3320 
3321  {
3322  const int progress_index[] = {
3328  };
3329  const int64 progress_vals[] = {
3331  0, 0, 0, 0
3332  };
3333 
3334  pgstat_progress_update_multi_param(5, progress_index, progress_vals);
3335  }
3336 
3337  /* Open and lock the parent heap relation */
3338  heapRelation = table_open(heapId, ShareUpdateExclusiveLock);
3339 
3340  /*
3341  * Switch to the table owner's userid, so that any index functions are run
3342  * as that user. Also lock down security-restricted operations and
3343  * arrange to make GUC variable changes local to this command.
3344  */
3345  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3346  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3347  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3348  save_nestlevel = NewGUCNestLevel();
3349 
3350  indexRelation = index_open(indexId, RowExclusiveLock);
3351 
3352  /*
3353  * Fetch info needed for index_insert. (You might think this should be
3354  * passed in from DefineIndex, but its copy is long gone due to having
3355  * been built in a previous transaction.)
3356  */
3357  indexInfo = BuildIndexInfo(indexRelation);
3358 
3359  /* mark build is concurrent just for consistency */
3360  indexInfo->ii_Concurrent = true;
3361 
3362  /*
3363  * Scan the index and gather up all the TIDs into a tuplesort object.
3364  */
3365  ivinfo.index = indexRelation;
3366  ivinfo.heaprel = heapRelation;
3367  ivinfo.analyze_only = false;
3368  ivinfo.report_progress = true;
3369  ivinfo.estimated_count = true;
3370  ivinfo.message_level = DEBUG2;
3371  ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3372  ivinfo.strategy = NULL;
3373 
3374  /*
3375  * Encode TIDs as int8 values for the sort, rather than directly sorting
3376  * item pointers. This can be significantly faster, primarily because TID
3377  * is a pass-by-reference type on all platforms, whereas int8 is
3378  * pass-by-value on most platforms.
3379  */
3380  state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
3381  InvalidOid, false,
3383  NULL, TUPLESORT_NONE);
3384  state.htups = state.itups = state.tups_inserted = 0;
3385 
3386  /* ambulkdelete updates progress metrics */
3387  (void) index_bulk_delete(&ivinfo, NULL,
3388  validate_index_callback, (void *) &state);
3389 
3390  /* Execute the sort */
3391  {
3392  const int progress_index[] = {
3396  };
3397  const int64 progress_vals[] = {
3399  0, 0
3400  };
3401 
3402  pgstat_progress_update_multi_param(3, progress_index, progress_vals);
3403  }
3404  tuplesort_performsort(state.tuplesort);
3405 
3406  /*
3407  * Now scan the heap and "merge" it with the index
3408  */
3411  table_index_validate_scan(heapRelation,
3412  indexRelation,
3413  indexInfo,
3414  snapshot,
3415  &state);
3416 
3417  /* Done with tuplesort object */
3418  tuplesort_end(state.tuplesort);
3419 
3420  elog(DEBUG2,
3421  "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3422  state.htups, state.itups, state.tups_inserted);
3423 
3424  /* Roll back any GUC changes executed by index functions */
3425  AtEOXact_GUC(false, save_nestlevel);
3426 
3427  /* Restore userid and security context */
3428  SetUserIdAndSecContext(save_userid, save_sec_context);
3429 
3430  /* Close rels, but keep locks */
3431  index_close(indexRelation, NoLock);
3432  table_close(heapRelation, NoLock);
3433 }
#define DEBUG2
Definition: elog.h:29
int maintenance_work_mem
Definition: globals.c:127
static bool validate_index_callback(ItemPointer itemptr, void *opaque)
Definition: index.c:3439
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:699
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN
Definition: progress.h:98
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT
Definition: progress.h:97
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition: progress.h:96
Relation index
Definition: genam.h:46
double num_heap_tuples
Definition: genam.h:52
bool analyze_only
Definition: genam.h:48
BufferAccessStrategy strategy
Definition: genam.h:53
Relation heaprel
Definition: genam.h:47
bool report_progress
Definition: genam.h:49
int message_level
Definition: genam.h:51
bool estimated_count
Definition: genam.h:50
Definition: regguts.h:323
static void table_index_validate_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, Snapshot snapshot, struct ValidateIndexState *state)
Definition: tableam.h:1836
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1382
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:969
#define TUPLESORT_NONE
Definition: tuplesort.h:92
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)

References IndexVacuumInfo::analyze_only, AtEOXact_GUC(), BuildIndexInfo(), DEBUG2, elog(), IndexVacuumInfo::estimated_count, GetUserIdAndSecContext(), IndexVacuumInfo::heaprel, IndexInfo::ii_Concurrent, IndexVacuumInfo::index, index_bulk_delete(), index_close(), index_open(), InvalidOid, maintenance_work_mem, IndexVacuumInfo::message_level, NewGUCNestLevel(), NoLock, IndexVacuumInfo::num_heap_tuples, pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN, PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT, PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN, PROGRESS_CREATEIDX_TUPLES_DONE, PROGRESS_CREATEIDX_TUPLES_TOTAL, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL, RelationData::rd_rel, IndexVacuumInfo::report_progress, RowExclusiveLock, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), ShareUpdateExclusiveLock, IndexVacuumInfo::strategy, table_close(), table_index_validate_scan(), table_open(), tuplesort_begin_datum(), tuplesort_end(), TUPLESORT_NONE, tuplesort_performsort(), and validate_index_callback().

Referenced by DefineIndex(), and ReindexRelationConcurrently().