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 INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS   (1 << 5)
 
#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 Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, 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 (const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
 
bool reindex_relation (const ReindexStmt *stmt, 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 92 of file index.h.

◆ INDEX_CONSTR_CREATE_INIT_DEFERRED

#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)

Definition at line 93 of file index.h.

◆ INDEX_CONSTR_CREATE_MARK_AS_PRIMARY

#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)

Definition at line 91 of file index.h.

◆ INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS

#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)

Definition at line 95 of file index.h.

◆ INDEX_CONSTR_CREATE_UPDATE_INDEX

#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)

Definition at line 94 of file index.h.

◆ INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS

#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS   (1 << 5)

Definition at line 96 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 161 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_PERMANENT

#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10

Definition at line 163 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_UNLOGGED

#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08

Definition at line 162 of file index.h.

◆ REINDEX_REL_PROCESS_TOAST

#define REINDEX_REL_PROCESS_TOAST   0x01

Definition at line 159 of file index.h.

◆ REINDEX_REL_SUPPRESS_INDEX_USE

#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02

Definition at line 160 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 2466 of file index.c.

2467 {
2468  IndexInfo *ii;
2469  Form_pg_index indexStruct = index->rd_index;
2470  int i;
2471  int numAtts;
2472 
2473  /* check the number of keys, and copy attr numbers into the IndexInfo */
2474  numAtts = indexStruct->indnatts;
2475  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2476  elog(ERROR, "invalid indnatts %d for index %u",
2477  numAtts, RelationGetRelid(index));
2478 
2479  /*
2480  * Create the node, using dummy index expressions, and pretending there is
2481  * no predicate.
2482  */
2483  ii = makeIndexInfo(indexStruct->indnatts,
2484  indexStruct->indnkeyatts,
2485  index->rd_rel->relam,
2487  NIL,
2488  indexStruct->indisunique,
2489  indexStruct->indnullsnotdistinct,
2490  indexStruct->indisready,
2491  false,
2492  index->rd_indam->amsummarizing);
2493 
2494  /* fill in attribute numbers */
2495  for (i = 0; i < numAtts; i++)
2496  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2497 
2498  /* We ignore the exclusion constraint if any */
2499 
2500  return ii;
2501 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
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:745
#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:505
List * RelationGetDummyIndexExpressions(Relation relation)
Definition: relcache.c:5073
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:186
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 2407 of file index.c.

2408 {
2409  IndexInfo *ii;
2410  Form_pg_index indexStruct = index->rd_index;
2411  int i;
2412  int numAtts;
2413 
2414  /* check the number of keys, and copy attr numbers into the IndexInfo */
2415  numAtts = indexStruct->indnatts;
2416  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2417  elog(ERROR, "invalid indnatts %d for index %u",
2418  numAtts, RelationGetRelid(index));
2419 
2420  /*
2421  * Create the node, fetching any expressions needed for expressional
2422  * indexes and index predicate if any.
2423  */
2424  ii = makeIndexInfo(indexStruct->indnatts,
2425  indexStruct->indnkeyatts,
2426  index->rd_rel->relam,
2429  indexStruct->indisunique,
2430  indexStruct->indnullsnotdistinct,
2431  indexStruct->indisready,
2432  false,
2433  index->rd_indam->amsummarizing);
2434 
2435  /* fill in attribute numbers */
2436  for (i = 0; i < numAtts; i++)
2437  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2438 
2439  /* fetch exclusion constraint info if any */
2440  if (indexStruct->indisexclusion)
2441  {
2443  &ii->ii_ExclusionOps,
2444  &ii->ii_ExclusionProcs,
2445  &ii->ii_ExclusionStrats);
2446  }
2447 
2448  return ii;
2449 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5127
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5570
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5014
uint16 * ii_ExclusionStrats
Definition: execnodes.h:193
Oid * ii_ExclusionOps
Definition: execnodes.h:191
Oid * ii_ExclusionProcs
Definition: execnodes.h:192

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

Referenced by _brin_parallel_scan_and_build(), _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 2645 of file index.c.

2646 {
2647  int indnkeyatts;
2648  int i;
2649 
2651 
2652  /*
2653  * fetch info for checking unique indexes
2654  */
2655  Assert(ii->ii_Unique);
2656 
2657  if (index->rd_rel->relam != BTREE_AM_OID)
2658  elog(ERROR, "unexpected non-btree speculative unique index");
2659 
2660  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2661  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2662  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2663 
2664  /*
2665  * We have to look up the operator's strategy number. This provides a
2666  * cross-check that the operator does match the index.
2667  */
2668  /* We need the func OIDs and strategy numbers too */
2669  for (i = 0; i < indnkeyatts; i++)
2670  {
2672  ii->ii_UniqueOps[i] =
2673  get_opfamily_member(index->rd_opfamily[i],
2674  index->rd_opcintype[i],
2675  index->rd_opcintype[i],
2676  ii->ii_UniqueStrats[i]);
2677  if (!OidIsValid(ii->ii_UniqueOps[i]))
2678  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2679  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2680  index->rd_opcintype[i], index->rd_opfamily[i]);
2681  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2682  }
2683 }
unsigned short uint16
Definition: c.h:492
#define OidIsValid(objectId)
Definition: c.h:762
Assert(fmt[strlen(fmt) - 1] !='\n')
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1263
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
void * palloc(Size size)
Definition: mcxt.c:1304
unsigned int Oid
Definition: postgres_ext.h:31
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ii_Unique
Definition: execnodes.h:197
Oid * ii_UniqueOps
Definition: execnodes.h:194
uint16 * ii_UniqueStrats
Definition: execnodes.h:196
Oid * ii_UniqueProcs
Definition: execnodes.h:195

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 2514 of file index.c.

2518 {
2519  int i;
2520 
2521  if (info1->ii_Unique != info2->ii_Unique)
2522  return false;
2523 
2524  if (info1->ii_NullsNotDistinct != info2->ii_NullsNotDistinct)
2525  return false;
2526 
2527  /* indexes are only equivalent if they have the same access method */
2528  if (info1->ii_Am != info2->ii_Am)
2529  return false;
2530 
2531  /* and same number of attributes */
2532  if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs)
2533  return false;
2534 
2535  /* and same number of key attributes */
2536  if (info1->ii_NumIndexKeyAttrs != info2->ii_NumIndexKeyAttrs)
2537  return false;
2538 
2539  /*
2540  * and columns match through the attribute map (actual attribute numbers
2541  * might differ!) Note that this checks that index columns that are
2542  * expressions appear in the same positions. We will next compare the
2543  * expressions themselves.
2544  */
2545  for (i = 0; i < info1->ii_NumIndexAttrs; i++)
2546  {
2547  if (attmap->maplen < info2->ii_IndexAttrNumbers[i])
2548  elog(ERROR, "incorrect attribute map");
2549 
2550  /* ignore expressions for now (but check their collation/opfamily) */
2551  if (!(info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber &&
2553  {
2554  /* fail if just one index has an expression in this column */
2555  if (info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber ||
2557  return false;
2558 
2559  /* both are columns, so check for match after mapping */
2560  if (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
2561  info1->ii_IndexAttrNumbers[i])
2562  return false;
2563  }
2564 
2565  /* collation and opfamily are not valid for included columns */
2566  if (i >= info1->ii_NumIndexKeyAttrs)
2567  continue;
2568 
2569  if (collations1[i] != collations2[i])
2570  return false;
2571  if (opfamilies1[i] != opfamilies2[i])
2572  return false;
2573  }
2574 
2575  /*
2576  * For expression indexes: either both are expression indexes, or neither
2577  * is; if they are, make sure the expressions match.
2578  */
2579  if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
2580  return false;
2581  if (info1->ii_Expressions != NIL)
2582  {
2583  bool found_whole_row;
2584  Node *mapped;
2585 
2586  mapped = map_variable_attnos((Node *) info2->ii_Expressions,
2587  1, 0, attmap,
2588  InvalidOid, &found_whole_row);
2589  if (found_whole_row)
2590  {
2591  /*
2592  * we could throw an error here, but seems out of scope for this
2593  * routine.
2594  */
2595  return false;
2596  }
2597 
2598  if (!equal(info1->ii_Expressions, mapped))
2599  return false;
2600  }
2601 
2602  /* Partial index predicates must be identical, if they exist */
2603  if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL))
2604  return false;
2605  if (info1->ii_Predicate != NULL)
2606  {
2607  bool found_whole_row;
2608  Node *mapped;
2609 
2610  mapped = map_variable_attnos((Node *) info2->ii_Predicate,
2611  1, 0, attmap,
2612  InvalidOid, &found_whole_row);
2613  if (found_whole_row)
2614  {
2615  /*
2616  * we could throw an error here, but seems out of scope for this
2617  * routine.
2618  */
2619  return false;
2620  }
2621  if (!equal(info1->ii_Predicate, mapped))
2622  return false;
2623  }
2624 
2625  /* No support currently for comparing exclusion indexes. */
2626  if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL)
2627  return false;
2628 
2629  return true;
2630 }
#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:184
bool ii_NullsNotDistinct
Definition: execnodes.h:198
int ii_NumIndexKeyAttrs
Definition: execnodes.h:185
List * ii_Expressions
Definition: execnodes.h:187
Oid ii_Am
Definition: execnodes.h:206
List * ii_Predicate
Definition: execnodes.h:189
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 4171 of file index.c.

4172 {
4175 }
static List * pendingReindexedIndexes
Definition: index.c:4040
static int list_length(const List *l)
Definition: pg_list.h:152
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

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 2705 of file index.c.

2710 {
2711  ListCell *indexpr_item;
2712  int i;
2713 
2714  if (indexInfo->ii_Expressions != NIL &&
2715  indexInfo->ii_ExpressionsState == NIL)
2716  {
2717  /* First time through, set up expression evaluation state */
2718  indexInfo->ii_ExpressionsState =
2719  ExecPrepareExprList(indexInfo->ii_Expressions, estate);
2720  /* Check caller has set up context correctly */
2721  Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2722  }
2723  indexpr_item = list_head(indexInfo->ii_ExpressionsState);
2724 
2725  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
2726  {
2727  int keycol = indexInfo->ii_IndexAttrNumbers[i];
2728  Datum iDatum;
2729  bool isNull;
2730 
2731  if (keycol < 0)
2732  iDatum = slot_getsysattr(slot, keycol, &isNull);
2733  else if (keycol != 0)
2734  {
2735  /*
2736  * Plain index column; get the value we need directly from the
2737  * heap tuple.
2738  */
2739  iDatum = slot_getattr(slot, keycol, &isNull);
2740  }
2741  else
2742  {
2743  /*
2744  * Index expression --- need to evaluate it.
2745  */
2746  if (indexpr_item == NULL)
2747  elog(ERROR, "wrong number of index expressions");
2748  iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
2749  GetPerTupleExprContext(estate),
2750  &isNull);
2751  indexpr_item = lnext(indexInfo->ii_ExpressionsState, indexpr_item);
2752  }
2753  values[i] = iDatum;
2754  isnull[i] = isNull;
2755  }
2756 
2757  if (indexpr_item != NULL)
2758  elog(ERROR, "wrong number of index expressions");
2759 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:806
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:348
#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:188
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:410
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:389

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 2941 of file index.c.

2946 {
2947  IndexBuildResult *stats;
2948  Oid save_userid;
2949  int save_sec_context;
2950  int save_nestlevel;
2951 
2952  /*
2953  * sanity checks
2954  */
2955  Assert(RelationIsValid(indexRelation));
2956  Assert(PointerIsValid(indexRelation->rd_indam));
2957  Assert(PointerIsValid(indexRelation->rd_indam->ambuild));
2958  Assert(PointerIsValid(indexRelation->rd_indam->ambuildempty));
2959 
2960  /*
2961  * Determine worker process details for parallel CREATE INDEX. Currently,
2962  * only btree has support for parallel builds.
2963  *
2964  * Note that planner considers parallel safety for us.
2965  */
2966  if (parallel && IsNormalProcessingMode() &&
2967  indexRelation->rd_indam->amcanbuildparallel)
2968  indexInfo->ii_ParallelWorkers =
2970  RelationGetRelid(indexRelation));
2971 
2972  if (indexInfo->ii_ParallelWorkers == 0)
2973  ereport(DEBUG1,
2974  (errmsg_internal("building index \"%s\" on table \"%s\" serially",
2975  RelationGetRelationName(indexRelation),
2976  RelationGetRelationName(heapRelation))));
2977  else
2978  ereport(DEBUG1,
2979  (errmsg_internal("building index \"%s\" on table \"%s\" with request for %d parallel workers",
2980  RelationGetRelationName(indexRelation),
2981  RelationGetRelationName(heapRelation),
2982  indexInfo->ii_ParallelWorkers)));
2983 
2984  /*
2985  * Switch to the table owner's userid, so that any index functions are run
2986  * as that user. Also lock down security-restricted operations and
2987  * arrange to make GUC variable changes local to this command.
2988  */
2989  GetUserIdAndSecContext(&save_userid, &save_sec_context);
2990  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
2991  save_sec_context | SECURITY_RESTRICTED_OPERATION);
2992  save_nestlevel = NewGUCNestLevel();
2994 
2995  /* Set up initial progress report status */
2996  {
2997  const int progress_index[] = {
3004  };
3005  const int64 progress_vals[] = {
3008  0, 0, 0, 0
3009  };
3010 
3011  pgstat_progress_update_multi_param(6, progress_index, progress_vals);
3012  }
3013 
3014  /*
3015  * Call the access method's build procedure
3016  */
3017  stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation,
3018  indexInfo);
3019  Assert(PointerIsValid(stats));
3020 
3021  /*
3022  * If this is an unlogged index, we may need to write out an init fork for
3023  * it -- but we must first check whether one already exists. If, for
3024  * example, an unlogged relation is truncated in the transaction that
3025  * created it, or truncated twice in a subsequent transaction, the
3026  * relfilenumber won't change, and nothing needs to be done here.
3027  */
3028  if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
3029  !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
3030  {
3031  smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3032  log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
3033  indexRelation->rd_indam->ambuildempty(indexRelation);
3034  }
3035 
3036  /*
3037  * If we found any potentially broken HOT chains, mark the index as not
3038  * being usable until the current transaction is below the event horizon.
3039  * See src/backend/access/heap/README.HOT for discussion. While it might
3040  * become safe to use the index earlier based on actual cleanup activity
3041  * and other active transactions, the test for that would be much more
3042  * complex and would require some form of blocking, so keep it simple and
3043  * fast by just using the current transaction.
3044  *
3045  * However, when reindexing an existing index, we should do nothing here.
3046  * Any HOT chains that are broken with respect to the index must predate
3047  * the index's original creation, so there is no need to change the
3048  * index's usability horizon. Moreover, we *must not* try to change the
3049  * index's pg_index entry while reindexing pg_index itself, and this
3050  * optimization nicely prevents that. The more complex rules needed for a
3051  * reindex are handled separately after this function returns.
3052  *
3053  * We also need not set indcheckxmin during a concurrent index build,
3054  * because we won't set indisvalid true until all transactions that care
3055  * about the broken HOT chains are gone.
3056  *
3057  * Therefore, this code path can only be taken during non-concurrent
3058  * CREATE INDEX. Thus the fact that heap_update will set the pg_index
3059  * tuple's xmin doesn't matter, because that tuple was created in the
3060  * current transaction anyway. That also means we don't need to worry
3061  * about any concurrent readers of the tuple; no other transaction can see
3062  * it yet.
3063  */
3064  if (indexInfo->ii_BrokenHotChain &&
3065  !isreindex &&
3066  !indexInfo->ii_Concurrent)
3067  {
3068  Oid indexId = RelationGetRelid(indexRelation);
3069  Relation pg_index;
3070  HeapTuple indexTuple;
3071  Form_pg_index indexForm;
3072 
3073  pg_index = table_open(IndexRelationId, RowExclusiveLock);
3074 
3075  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3076  ObjectIdGetDatum(indexId));
3077  if (!HeapTupleIsValid(indexTuple))
3078  elog(ERROR, "cache lookup failed for index %u", indexId);
3079  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3080 
3081  /* If it's a new index, indcheckxmin shouldn't be set ... */
3082  Assert(!indexForm->indcheckxmin);
3083 
3084  indexForm->indcheckxmin = true;
3085  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3086 
3087  heap_freetuple(indexTuple);
3088  table_close(pg_index, RowExclusiveLock);
3089  }
3090 
3091  /*
3092  * Update heap and index pg_class rows
3093  */
3094  index_update_stats(heapRelation,
3095  true,
3096  stats->heap_tuples);
3097 
3098  index_update_stats(indexRelation,
3099  false,
3100  stats->index_tuples);
3101 
3102  /* Make the updated catalog row versions visible */
3104 
3105  /*
3106  * If it's for an exclusion constraint, make a second pass over the heap
3107  * to verify that the constraint is satisfied. We must not do this until
3108  * the index is fully valid. (Broken HOT chains shouldn't matter, though;
3109  * see comments for IndexCheckExclusion.)
3110  */
3111  if (indexInfo->ii_ExclusionOps != NULL)
3112  IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
3113 
3114  /* Roll back any GUC changes executed by index functions */
3115  AtEOXact_GUC(false, save_nestlevel);
3116 
3117  /* Restore userid and security context */
3118  SetUserIdAndSecContext(save_userid, save_sec_context);
3119 }
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
#define PointerIsValid(pointer)
Definition: c.h:750
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
#define DEBUG1
Definition: elog.h:30
#define ereport(elevel,...)
Definition: elog.h:149
int NewGUCNestLevel(void)
Definition: guc.c:2237
void RestrictSearchPath(void)
Definition: guc.c:2248
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2264
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#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:2784
static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
Definition: index.c:3134
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:315
#define IsNormalProcessingMode()
Definition: miscadmin.h:453
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
int plan_create_index_workers(Oid tableOid, Oid indexOid)
Definition: planner.c:6600
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:567
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationIsValid(relation)
Definition: rel.h:478
@ INIT_FORKNUM
Definition: relpath.h:53
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:411
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:398
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:186
ItemPointerData t_self
Definition: htup.h:65
ambuildempty_function ambuildempty
Definition: amapi.h:267
ambuild_function ambuild
Definition: amapi.h:266
bool amcanbuildparallel
Definition: amapi.h:247
double heap_tuples
Definition: genam.h:32
double index_tuples
Definition: genam.h:33
bool ii_BrokenHotChain
Definition: execnodes.h:203
int ii_ParallelWorkers
Definition: execnodes.h:205
bool ii_Concurrent
Definition: execnodes.h:202
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
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:1079

References IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, IndexAmRoutine::amcanbuildparallel, 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(), 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, RestrictSearchPath(), 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 201 of file index.c.

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

References 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 1481 of file index.c.

1483 {
1484  Relation heapRel;
1485  Oid save_userid;
1486  int save_sec_context;
1487  int save_nestlevel;
1488  Relation indexRelation;
1489  IndexInfo *indexInfo;
1490 
1491  /* This had better make sure that a snapshot is active */
1493 
1494  /* Open and lock the parent heap relation */
1495  heapRel = table_open(heapRelationId, ShareUpdateExclusiveLock);
1496 
1497  /*
1498  * Switch to the table owner's userid, so that any index functions are run
1499  * as that user. Also lock down security-restricted operations and
1500  * arrange to make GUC variable changes local to this command.
1501  */
1502  GetUserIdAndSecContext(&save_userid, &save_sec_context);
1503  SetUserIdAndSecContext(heapRel->rd_rel->relowner,
1504  save_sec_context | SECURITY_RESTRICTED_OPERATION);
1505  save_nestlevel = NewGUCNestLevel();
1507 
1508  indexRelation = index_open(indexRelationId, RowExclusiveLock);
1509 
1510  /*
1511  * We have to re-build the IndexInfo struct, since it was lost in the
1512  * commit of the transaction where this concurrent index was created at
1513  * the catalog level.
1514  */
1515  indexInfo = BuildIndexInfo(indexRelation);
1516  Assert(!indexInfo->ii_ReadyForInserts);
1517  indexInfo->ii_Concurrent = true;
1518  indexInfo->ii_BrokenHotChain = false;
1519 
1520  /* Now build the index */
1521  index_build(heapRel, indexRelation, indexInfo, false, true);
1522 
1523  /* Roll back any GUC changes executed by index functions */
1524  AtEOXact_GUC(false, save_nestlevel);
1525 
1526  /* Restore userid and security context */
1527  SetUserIdAndSecContext(save_userid, save_sec_context);
1528 
1529  /* Close both the relations, but keep the locks */
1530  table_close(heapRel, NoLock);
1531  index_close(indexRelation, NoLock);
1532 
1533  /*
1534  * Update the pg_index row to mark the index as ready for inserts. Once we
1535  * commit this transaction, any new transactions that open the table must
1536  * insert new entries into the index for insertions and non-HOT updates.
1537  */
1539 }
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3440
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:2941
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2407
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:782
bool ii_ReadyForInserts
Definition: execnodes.h:199

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, RestrictSearchPath(), 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 1297 of file index.c.

1299 {
1300  Relation indexRelation;
1301  IndexInfo *oldInfo,
1302  *newInfo;
1303  Oid newIndexId = InvalidOid;
1304  HeapTuple indexTuple,
1305  classTuple;
1306  Datum indclassDatum,
1307  colOptionDatum,
1308  reloptionsDatum;
1309  Datum *opclassOptions;
1310  oidvector *indclass;
1311  int2vector *indcoloptions;
1312  NullableDatum *stattargets;
1313  bool isnull;
1314  List *indexColNames = NIL;
1315  List *indexExprs = NIL;
1316  List *indexPreds = NIL;
1317 
1318  indexRelation = index_open(oldIndexId, RowExclusiveLock);
1319 
1320  /* The new index needs some information from the old index */
1321  oldInfo = BuildIndexInfo(indexRelation);
1322 
1323  /*
1324  * Concurrent build of an index with exclusion constraints is not
1325  * supported.
1326  */
1327  if (oldInfo->ii_ExclusionOps != NULL)
1328  ereport(ERROR,
1329  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1330  errmsg("concurrent index creation for exclusion constraints is not supported")));
1331 
1332  /* Get the array of class and column options IDs from index info */
1333  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId));
1334  if (!HeapTupleIsValid(indexTuple))
1335  elog(ERROR, "cache lookup failed for index %u", oldIndexId);
1336  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1337  Anum_pg_index_indclass);
1338  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1339 
1340  colOptionDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1341  Anum_pg_index_indoption);
1342  indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum);
1343 
1344  /* Fetch reloptions of index if any */
1345  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(oldIndexId));
1346  if (!HeapTupleIsValid(classTuple))
1347  elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
1348  reloptionsDatum = SysCacheGetAttr(RELOID, classTuple,
1349  Anum_pg_class_reloptions, &isnull);
1350 
1351  /*
1352  * Fetch the list of expressions and predicates directly from the
1353  * catalogs. This cannot rely on the information from IndexInfo of the
1354  * old index as these have been flattened for the planner.
1355  */
1356  if (oldInfo->ii_Expressions != NIL)
1357  {
1358  Datum exprDatum;
1359  char *exprString;
1360 
1361  exprDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1362  Anum_pg_index_indexprs);
1363  exprString = TextDatumGetCString(exprDatum);
1364  indexExprs = (List *) stringToNode(exprString);
1365  pfree(exprString);
1366  }
1367  if (oldInfo->ii_Predicate != NIL)
1368  {
1369  Datum predDatum;
1370  char *predString;
1371 
1372  predDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1373  Anum_pg_index_indpred);
1374  predString = TextDatumGetCString(predDatum);
1375  indexPreds = (List *) stringToNode(predString);
1376 
1377  /* Also convert to implicit-AND format */
1378  indexPreds = make_ands_implicit((Expr *) indexPreds);
1379  pfree(predString);
1380  }
1381 
1382  /*
1383  * Build the index information for the new index. Note that rebuild of
1384  * indexes with exclusion constraints is not supported, hence there is no
1385  * need to fill all the ii_Exclusion* fields.
1386  */
1387  newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1388  oldInfo->ii_NumIndexKeyAttrs,
1389  oldInfo->ii_Am,
1390  indexExprs,
1391  indexPreds,
1392  oldInfo->ii_Unique,
1393  oldInfo->ii_NullsNotDistinct,
1394  false, /* not ready for inserts */
1395  true,
1396  indexRelation->rd_indam->amsummarizing);
1397 
1398  /*
1399  * Extract the list of column names and the column numbers for the new
1400  * index information. All this information will be used for the index
1401  * creation.
1402  */
1403  for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++)
1404  {
1405  TupleDesc indexTupDesc = RelationGetDescr(indexRelation);
1406  Form_pg_attribute att = TupleDescAttr(indexTupDesc, i);
1407 
1408  indexColNames = lappend(indexColNames, NameStr(att->attname));
1409  newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i];
1410  }
1411 
1412  /* Extract opclass options for each attribute */
1413  opclassOptions = palloc0(sizeof(Datum) * newInfo->ii_NumIndexAttrs);
1414  for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1415  opclassOptions[i] = get_attoptions(oldIndexId, i + 1);
1416 
1417  /* Extract statistic targets for each attribute */
1418  stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs);
1419  for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1420  {
1421  HeapTuple tp;
1422  Datum dat;
1423 
1424  tp = SearchSysCache2(ATTNUM, ObjectIdGetDatum(oldIndexId), Int16GetDatum(i + 1));
1425  if (!HeapTupleIsValid(tp))
1426  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1427  i + 1, oldIndexId);
1428  dat = SysCacheGetAttr(ATTNUM, tp, Anum_pg_attribute_attstattarget, &isnull);
1429  ReleaseSysCache(tp);
1430  stattargets[i].value = dat;
1431  stattargets[i].isnull = isnull;
1432  }
1433 
1434  /*
1435  * Now create the new index.
1436  *
1437  * For a partition index, we adjust the partition dependency later, to
1438  * ensure a consistent state at all times. That is why parentIndexRelid
1439  * is not set here.
1440  */
1441  newIndexId = index_create(heapRelation,
1442  newName,
1443  InvalidOid, /* indexRelationId */
1444  InvalidOid, /* parentIndexRelid */
1445  InvalidOid, /* parentConstraintId */
1446  InvalidRelFileNumber, /* relFileNumber */
1447  newInfo,
1448  indexColNames,
1449  indexRelation->rd_rel->relam,
1450  tablespaceOid,
1451  indexRelation->rd_indcollation,
1452  indclass->values,
1453  opclassOptions,
1454  indcoloptions->values,
1455  stattargets,
1456  reloptionsDatum,
1458  0,
1459  true, /* allow table to be a system catalog? */
1460  false, /* is_internal? */
1461  NULL);
1462 
1463  /* Close the relations used and clean up */
1464  index_close(indexRelation, NoLock);
1465  ReleaseSysCache(indexTuple);
1466  ReleaseSysCache(classTuple);
1467 
1468  return newIndexId;
1469 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
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 Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition: index.c:724
#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:339
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:721
void pfree(void *pointer)
Definition: mcxt.c:1508
void * palloc0(Size size)
Definition: mcxt.c:1334
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:531
#define InvalidRelFileNumber
Definition: relpath.h:26
bool amsummarizing
Definition: amapi.h:253
Definition: pg_list.h:54
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
Oid * rd_indcollation
Definition: rel.h:217
Definition: c.h:702
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:709
Definition: c.h:713
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:720
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
#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_Predicate, IndexInfo::ii_Unique, index_close(), index_create(), INDEX_CREATE_CONCURRENT, INDEX_CREATE_SKIP_BUILD, index_open(), Int16GetDatum(), InvalidOid, InvalidRelFileNumber, NullableDatum::isnull, lappend(), make_ands_implicit(), makeIndexInfo(), NameStr, NIL, NoLock, ObjectIdGetDatum(), palloc0(), palloc0_array, pfree(), RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_rel, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCache2(), stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), TextDatumGetCString, TupleDescAttr, NullableDatum::value, int2vector::values, and oidvector::values.

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1819 of file index.c.

1820 {
1821  Relation userHeapRelation;
1822  Relation userIndexRelation;
1823 
1824  /*
1825  * No more predicate locks will be acquired on this index, and we're about
1826  * to stop doing inserts into the index which could show conflicts with
1827  * existing predicate locks, so now is the time to move them to the heap
1828  * relation.
1829  */
1830  userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock);
1831  userIndexRelation = index_open(indexId, ShareUpdateExclusiveLock);
1832  TransferPredicateLocksToHeapRelation(userIndexRelation);
1833 
1834  /*
1835  * Now we are sure that nobody uses the index for queries; they just might
1836  * have it open for updating it. So now we can unset indisready and
1837  * indislive, then wait till nobody could be using it at all anymore.
1838  */
1840 
1841  /*
1842  * Invalidate the relcache for the table, so that after this commit all
1843  * sessions will refresh the table's index list. Forgetting just the
1844  * index's relcache entry is not enough.
1845  */
1846  CacheInvalidateRelcache(userHeapRelation);
1847 
1848  /*
1849  * Close the relations again, though still holding session lock.
1850  */
1851  table_close(userHeapRelation, NoLock);
1852  index_close(userIndexRelation, NoLock);
1853 }
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3103

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 1548 of file index.c.

1549 {
1550  Relation pg_class,
1551  pg_index,
1552  pg_constraint,
1553  pg_trigger;
1554  Relation oldClassRel,
1555  newClassRel;
1556  HeapTuple oldClassTuple,
1557  newClassTuple;
1558  Form_pg_class oldClassForm,
1559  newClassForm;
1560  HeapTuple oldIndexTuple,
1561  newIndexTuple;
1562  Form_pg_index oldIndexForm,
1563  newIndexForm;
1564  bool isPartition;
1565  Oid indexConstraintOid;
1566  List *constraintOids = NIL;
1567  ListCell *lc;
1568 
1569  /*
1570  * Take a necessary lock on the old and new index before swapping them.
1571  */
1572  oldClassRel = relation_open(oldIndexId, ShareUpdateExclusiveLock);
1573  newClassRel = relation_open(newIndexId, ShareUpdateExclusiveLock);
1574 
1575  /* Now swap names and dependencies of those indexes */
1576  pg_class = table_open(RelationRelationId, RowExclusiveLock);
1577 
1578  oldClassTuple = SearchSysCacheCopy1(RELOID,
1579  ObjectIdGetDatum(oldIndexId));
1580  if (!HeapTupleIsValid(oldClassTuple))
1581  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1582  newClassTuple = SearchSysCacheCopy1(RELOID,
1583  ObjectIdGetDatum(newIndexId));
1584  if (!HeapTupleIsValid(newClassTuple))
1585  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1586 
1587  oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple);
1588  newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple);
1589 
1590  /* Swap the names */
1591  namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1592  namestrcpy(&oldClassForm->relname, oldName);
1593 
1594  /* Swap the partition flags to track inheritance properly */
1595  isPartition = newClassForm->relispartition;
1596  newClassForm->relispartition = oldClassForm->relispartition;
1597  oldClassForm->relispartition = isPartition;
1598 
1599  CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple);
1600  CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple);
1601 
1602  heap_freetuple(oldClassTuple);
1603  heap_freetuple(newClassTuple);
1604 
1605  /* Now swap index info */
1606  pg_index = table_open(IndexRelationId, RowExclusiveLock);
1607 
1608  oldIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1609  ObjectIdGetDatum(oldIndexId));
1610  if (!HeapTupleIsValid(oldIndexTuple))
1611  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1612  newIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1613  ObjectIdGetDatum(newIndexId));
1614  if (!HeapTupleIsValid(newIndexTuple))
1615  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1616 
1617  oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple);
1618  newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple);
1619 
1620  /*
1621  * Copy constraint flags from the old index. This is safe because the old
1622  * index guaranteed uniqueness.
1623  */
1624  newIndexForm->indisprimary = oldIndexForm->indisprimary;
1625  oldIndexForm->indisprimary = false;
1626  newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1627  oldIndexForm->indisexclusion = false;
1628  newIndexForm->indimmediate = oldIndexForm->indimmediate;
1629  oldIndexForm->indimmediate = true;
1630 
1631  /* Preserve indisreplident in the new index */
1632  newIndexForm->indisreplident = oldIndexForm->indisreplident;
1633 
1634  /* Preserve indisclustered in the new index */
1635  newIndexForm->indisclustered = oldIndexForm->indisclustered;
1636 
1637  /*
1638  * Mark the new index as valid, and the old index as invalid similarly to
1639  * what index_set_state_flags() does.
1640  */
1641  newIndexForm->indisvalid = true;
1642  oldIndexForm->indisvalid = false;
1643  oldIndexForm->indisclustered = false;
1644  oldIndexForm->indisreplident = false;
1645 
1646  CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple);
1647  CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple);
1648 
1649  heap_freetuple(oldIndexTuple);
1650  heap_freetuple(newIndexTuple);
1651 
1652  /*
1653  * Move constraints and triggers over to the new index
1654  */
1655 
1656  constraintOids = get_index_ref_constraints(oldIndexId);
1657 
1658  indexConstraintOid = get_index_constraint(oldIndexId);
1659 
1660  if (OidIsValid(indexConstraintOid))
1661  constraintOids = lappend_oid(constraintOids, indexConstraintOid);
1662 
1663  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
1664  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
1665 
1666  foreach(lc, constraintOids)
1667  {
1668  HeapTuple constraintTuple,
1669  triggerTuple;
1670  Form_pg_constraint conForm;
1671  ScanKeyData key[1];
1672  SysScanDesc scan;
1673  Oid constraintOid = lfirst_oid(lc);
1674 
1675  /* Move the constraint from the old to the new index */
1676  constraintTuple = SearchSysCacheCopy1(CONSTROID,
1677  ObjectIdGetDatum(constraintOid));
1678  if (!HeapTupleIsValid(constraintTuple))
1679  elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1680 
1681  conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple));
1682 
1683  if (conForm->conindid == oldIndexId)
1684  {
1685  conForm->conindid = newIndexId;
1686 
1687  CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple);
1688  }
1689 
1690  heap_freetuple(constraintTuple);
1691 
1692  /* Search for trigger records */
1693  ScanKeyInit(&key[0],
1694  Anum_pg_trigger_tgconstraint,
1695  BTEqualStrategyNumber, F_OIDEQ,
1696  ObjectIdGetDatum(constraintOid));
1697 
1698  scan = systable_beginscan(pg_trigger, TriggerConstraintIndexId, true,
1699  NULL, 1, key);
1700 
1701  while (HeapTupleIsValid((triggerTuple = systable_getnext(scan))))
1702  {
1703  Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1704 
1705  if (tgForm->tgconstrindid != oldIndexId)
1706  continue;
1707 
1708  /* Make a modifiable copy */
1709  triggerTuple = heap_copytuple(triggerTuple);
1710  tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1711 
1712  tgForm->tgconstrindid = newIndexId;
1713 
1714  CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple);
1715 
1716  heap_freetuple(triggerTuple);
1717  }
1718 
1719  systable_endscan(scan);
1720  }
1721 
1722  /*
1723  * Move comment if any
1724  */
1725  {
1727  ScanKeyData skey[3];
1728  SysScanDesc sd;
1729  HeapTuple tuple;
1730  Datum values[Natts_pg_description] = {0};
1731  bool nulls[Natts_pg_description] = {0};
1732  bool replaces[Natts_pg_description] = {0};
1733 
1734  values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId);
1735  replaces[Anum_pg_description_objoid - 1] = true;
1736 
1737  ScanKeyInit(&skey[0],
1738  Anum_pg_description_objoid,
1739  BTEqualStrategyNumber, F_OIDEQ,
1740  ObjectIdGetDatum(oldIndexId));
1741  ScanKeyInit(&skey[1],
1742  Anum_pg_description_classoid,
1743  BTEqualStrategyNumber, F_OIDEQ,
1744  ObjectIdGetDatum(RelationRelationId));
1745  ScanKeyInit(&skey[2],
1746  Anum_pg_description_objsubid,
1747  BTEqualStrategyNumber, F_INT4EQ,
1748  Int32GetDatum(0));
1749 
1750  description = table_open(DescriptionRelationId, RowExclusiveLock);
1751 
1752  sd = systable_beginscan(description, DescriptionObjIndexId, true,
1753  NULL, 3, skey);
1754 
1755  while ((tuple = systable_getnext(sd)) != NULL)
1756  {
1758  values, nulls, replaces);
1759  CatalogTupleUpdate(description, &tuple->t_self, tuple);
1760 
1761  break; /* Assume there can be only one match */
1762  }
1763 
1764  systable_endscan(sd);
1766  }
1767 
1768  /*
1769  * Swap inheritance relationship with parent index
1770  */
1771  if (get_rel_relispartition(oldIndexId))
1772  {
1773  List *ancestors = get_partition_ancestors(oldIndexId);
1774  Oid parentIndexRelid = linitial_oid(ancestors);
1775 
1776  DeleteInheritsTuple(oldIndexId, parentIndexRelid, false, NULL);
1777  StoreSingleInheritance(newIndexId, parentIndexRelid, 1);
1778 
1779  list_free(ancestors);
1780  }
1781 
1782  /*
1783  * Swap all dependencies of and on the old index to the new one, and
1784  * vice-versa. Note that a call to CommandCounterIncrement() would cause
1785  * duplicate entries in pg_depend, so this should not be done.
1786  */
1787  changeDependenciesOf(RelationRelationId, newIndexId, oldIndexId);
1788  changeDependenciesOn(RelationRelationId, newIndexId, oldIndexId);
1789 
1790  changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId);
1791  changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId);
1792 
1793  /* copy over statistics from old to new index */
1794  pgstat_copy_relation_stats(newClassRel, oldClassRel);
1795 
1796  /* Copy data of pg_statistic from the old index to the new one */
1797  CopyStatistics(oldIndexId, newIndexId);
1798 
1799  /* Close relations */
1800  table_close(pg_class, RowExclusiveLock);
1801  table_close(pg_index, RowExclusiveLock);
1802  table_close(pg_constraint, RowExclusiveLock);
1803  table_close(pg_trigger, RowExclusiveLock);
1804 
1805  /* The lock taken previously is not released until the end of transaction */
1806  relation_close(oldClassRel, NoLock);
1807  relation_close(newClassRel, NoLock);
1808 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
void CopyStatistics(Oid fromrelid, Oid torelid)
Definition: heap.c:3201
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void list_free(List *list)
Definition: list.c:1546
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2005
void namestrcpy(Name name, const char *str)
Definition: name.c:233
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
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:552
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
#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:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
const char * description

References BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependenciesOf(), changeDependenciesOn(), CopyStatistics(), DeleteInheritsTuple(), description, elog, ERROR, get_index_constraint(), get_index_ref_constraints(), get_partition_ancestors(), get_rel_relispartition(), GETSTRUCT, heap_copytuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, 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, 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 1881 of file index.c.

1890 {
1891  Oid namespaceId = RelationGetNamespace(heapRelation);
1892  ObjectAddress myself,
1893  idxaddr;
1894  Oid conOid;
1895  bool deferrable;
1896  bool initdeferred;
1897  bool mark_as_primary;
1898  bool islocal;
1899  bool noinherit;
1900  bool is_without_overlaps;
1901  int inhcount;
1902 
1903  deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1904  initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1905  mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
1906  is_without_overlaps = (constr_flags & INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS) != 0;
1907 
1908  /* constraint creation support doesn't work while bootstrapping */
1910 
1911  /* enforce system-table restriction */
1912  if (!allow_system_table_mods &&
1913  IsSystemRelation(heapRelation) &&
1915  ereport(ERROR,
1916  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1917  errmsg("user-defined indexes on system catalog tables are not supported")));
1918 
1919  /* primary/unique constraints shouldn't have any expressions */
1920  if (indexInfo->ii_Expressions &&
1921  constraintType != CONSTRAINT_EXCLUSION)
1922  elog(ERROR, "constraints cannot have index expressions");
1923 
1924  /*
1925  * If we're manufacturing a constraint for a pre-existing index, we need
1926  * to get rid of the existing auto dependencies for the index (the ones
1927  * that index_create() would have made instead of calling this function).
1928  *
1929  * Note: this code would not necessarily do the right thing if the index
1930  * has any expressions or predicate, but we'd never be turning such an
1931  * index into a UNIQUE or PRIMARY KEY constraint.
1932  */
1933  if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
1934  deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
1935  RelationRelationId, DEPENDENCY_AUTO);
1936 
1937  if (OidIsValid(parentConstraintId))
1938  {
1939  islocal = false;
1940  inhcount = 1;
1941  noinherit = false;
1942  }
1943  else
1944  {
1945  islocal = true;
1946  inhcount = 0;
1947  noinherit = true;
1948  }
1949 
1950  /*
1951  * Construct a pg_constraint entry.
1952  */
1953  conOid = CreateConstraintEntry(constraintName,
1954  namespaceId,
1955  constraintType,
1956  deferrable,
1957  initdeferred,
1958  true,
1959  parentConstraintId,
1960  RelationGetRelid(heapRelation),
1961  indexInfo->ii_IndexAttrNumbers,
1962  indexInfo->ii_NumIndexKeyAttrs,
1963  indexInfo->ii_NumIndexAttrs,
1964  InvalidOid, /* no domain */
1965  indexRelationId, /* index OID */
1966  InvalidOid, /* no foreign key */
1967  NULL,
1968  NULL,
1969  NULL,
1970  NULL,
1971  0,
1972  ' ',
1973  ' ',
1974  NULL,
1975  0,
1976  ' ',
1977  indexInfo->ii_ExclusionOps,
1978  NULL, /* no check constraint */
1979  NULL,
1980  islocal,
1981  inhcount,
1982  noinherit,
1983  is_without_overlaps,
1984  is_internal);
1985 
1986  /*
1987  * Register the index as internally dependent on the constraint.
1988  *
1989  * Note that the constraint has a dependency on the table, so we don't
1990  * need (or want) any direct dependency from the index to the table.
1991  */
1992  ObjectAddressSet(myself, ConstraintRelationId, conOid);
1993  ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId);
1994  recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
1995 
1996  /*
1997  * Also, if this is a constraint on a partition, give it partition-type
1998  * dependencies on the parent constraint as well as the table.
1999  */
2000  if (OidIsValid(parentConstraintId))
2001  {
2002  ObjectAddress referenced;
2003 
2004  ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
2005  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
2006  ObjectAddressSet(referenced, RelationRelationId,
2007  RelationGetRelid(heapRelation));
2008  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
2009  }
2010 
2011  /*
2012  * If the constraint is deferrable, create the deferred uniqueness
2013  * checking trigger. (The trigger will be given an internal dependency on
2014  * the constraint by CreateTrigger.)
2015  */
2016  if (deferrable)
2017  {
2019 
2020  trigger->replace = false;
2021  trigger->isconstraint = true;
2022  trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
2023  "PK_ConstraintTrigger" :
2024  "Unique_ConstraintTrigger";
2025  trigger->relation = NULL;
2026  trigger->funcname = SystemFuncName("unique_key_recheck");
2027  trigger->args = NIL;
2028  trigger->row = true;
2029  trigger->timing = TRIGGER_TYPE_AFTER;
2030  trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE;
2031  trigger->columns = NIL;
2032  trigger->whenClause = NULL;
2033  trigger->transitionRels = NIL;
2034  trigger->deferrable = true;
2035  trigger->initdeferred = initdeferred;
2036  trigger->constrrel = NULL;
2037 
2038  (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
2039  InvalidOid, conOid, indexRelationId, InvalidOid,
2040  InvalidOid, NULL, true, false);
2041  }
2042 
2043  /*
2044  * If needed, mark the index as primary and/or deferred in pg_index.
2045  *
2046  * Note: When making an existing index into a constraint, caller must have
2047  * a table lock that prevents concurrent table updates; otherwise, there
2048  * is a risk that concurrent readers of the table will miss seeing this
2049  * index at all.
2050  */
2051  if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
2052  (mark_as_primary || deferrable))
2053  {
2054  Relation pg_index;
2055  HeapTuple indexTuple;
2056  Form_pg_index indexForm;
2057  bool dirty = false;
2058  bool marked_as_primary = false;
2059 
2060  pg_index = table_open(IndexRelationId, RowExclusiveLock);
2061 
2062  indexTuple = SearchSysCacheCopy1(INDEXRELID,
2063  ObjectIdGetDatum(indexRelationId));
2064  if (!HeapTupleIsValid(indexTuple))
2065  elog(ERROR, "cache lookup failed for index %u", indexRelationId);
2066  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
2067 
2068  if (mark_as_primary && !indexForm->indisprimary)
2069  {
2070  indexForm->indisprimary = true;
2071  dirty = true;
2072  marked_as_primary = true;
2073  }
2074 
2075  if (deferrable && indexForm->indimmediate)
2076  {
2077  indexForm->indimmediate = false;
2078  dirty = true;
2079  }
2080 
2081  if (dirty)
2082  {
2083  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
2084 
2085  /*
2086  * When we mark an existing index as primary, force a relcache
2087  * flush on its parent table, so that all sessions will become
2088  * aware that the table now has a primary key. This is important
2089  * because it affects some replication behaviors.
2090  */
2091  if (marked_as_primary)
2092  CacheInvalidateRelcache(heapRelation);
2093 
2094  InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
2095  InvalidOid, is_internal);
2096  }
2097 
2098  heap_freetuple(indexTuple);
2099  table_close(pg_index, RowExclusiveLock);
2100  }
2101 
2102  return myself;
2103 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
@ 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_WITHOUT_OVERLAPS
Definition: index.h:96
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:94
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:95
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:91
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
#define makeNode(_type_)
Definition: nodes.h:155
#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 conPeriod, bool is_internal)
Definition: pg_constraint.c:49
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:546
Node * whenClause
Definition: parsenodes.h:2869
List * transitionRels
Definition: parsenodes.h:2871
RangeVar * constrrel
Definition: parsenodes.h:2875
RangeVar * relation
Definition: parsenodes.h:2860
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:158

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, INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS, 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 Datum opclassOptions,
const int16 coloptions,
const NullableDatum stattargets,
Datum  reloptions,
bits16  flags,
bits16  constr_flags,
bool  allow_system_table_mods,
bool  is_internal,
Oid constraintId 
)

Definition at line 724 of file index.c.

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

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

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(), 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 3440 of file index.c.

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

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, 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 3520 of file index.c.

3521 {
3522  HeapTuple tuple;
3524  Oid result;
3525 
3526  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3527  if (!HeapTupleIsValid(tuple))
3528  {
3529  if (missing_ok)
3530  return InvalidOid;
3531  elog(ERROR, "cache lookup failed for index %u", indexId);
3532  }
3533  index = (Form_pg_index) GETSTRUCT(tuple);
3534  Assert(index->indexrelid == indexId);
3535 
3536  result = index->indrelid;
3537  ReleaseSysCache(tuple);
3538  return result;
3539 }

References Assert(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, 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 4391 of file indexcmds.c.

4392 {
4393  Relation pg_inherits;
4394  ScanKeyData key[2];
4395  SysScanDesc scan;
4396  Oid partRelid = RelationGetRelid(partitionIdx);
4397  HeapTuple tuple;
4398  bool fix_dependencies;
4399 
4400  /* Make sure this is an index */
4401  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4402  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4403 
4404  /*
4405  * Scan pg_inherits for rows linking our index to some parent.
4406  */
4407  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
4408  ScanKeyInit(&key[0],
4409  Anum_pg_inherits_inhrelid,
4410  BTEqualStrategyNumber, F_OIDEQ,
4411  ObjectIdGetDatum(partRelid));
4412  ScanKeyInit(&key[1],
4413  Anum_pg_inherits_inhseqno,
4414  BTEqualStrategyNumber, F_INT4EQ,
4415  Int32GetDatum(1));
4416  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
4417  NULL, 2, key);
4418  tuple = systable_getnext(scan);
4419 
4420  if (!HeapTupleIsValid(tuple))
4421  {
4422  if (parentOid == InvalidOid)
4423  {
4424  /*
4425  * No pg_inherits row, and no parent wanted: nothing to do in this
4426  * case.
4427  */
4428  fix_dependencies = false;
4429  }
4430  else
4431  {
4432  StoreSingleInheritance(partRelid, parentOid, 1);
4433  fix_dependencies = true;
4434  }
4435  }
4436  else
4437  {
4438  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
4439 
4440  if (parentOid == InvalidOid)
4441  {
4442  /*
4443  * There exists a pg_inherits row, which we want to clear; do so.
4444  */
4445  CatalogTupleDelete(pg_inherits, &tuple->t_self);
4446  fix_dependencies = true;
4447  }
4448  else
4449  {
4450  /*
4451  * A pg_inherits row exists. If it's the same we want, then we're
4452  * good; if it differs, that amounts to a corrupt catalog and
4453  * should not happen.
4454  */
4455  if (inhForm->inhparent != parentOid)
4456  {
4457  /* unexpected: we should not get called in this case */
4458  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4459  inhForm->inhrelid, inhForm->inhparent);
4460  }
4461 
4462  /* already in the right state */
4463  fix_dependencies = false;
4464  }
4465  }
4466 
4467  /* done with pg_inherits */
4468  systable_endscan(scan);
4469  relation_close(pg_inherits, RowExclusiveLock);
4470 
4471  /* set relhassubclass if an index partition has been added to the parent */
4472  if (OidIsValid(parentOid))
4473  SetRelationHasSubclass(parentOid, true);
4474 
4475  /* set relispartition correctly on the partition */
4476  update_relispartition(partRelid, OidIsValid(parentOid));
4477 
4478  if (fix_dependencies)
4479  {
4480  /*
4481  * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4482  * dependencies on the parent index and the table; if removing a
4483  * parent, delete PARTITION dependencies.
4484  */
4485  if (OidIsValid(parentOid))
4486  {
4487  ObjectAddress partIdx;
4488  ObjectAddress parentIdx;
4489  ObjectAddress partitionTbl;
4490 
4491  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
4492  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
4493  ObjectAddressSet(partitionTbl, RelationRelationId,
4494  partitionIdx->rd_index->indrelid);
4495  recordDependencyOn(&partIdx, &parentIdx,
4497  recordDependencyOn(&partIdx, &partitionTbl,
4499  }
4500  else
4501  {
4502  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4503  RelationRelationId,
4505  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4506  RelationRelationId,
4508  }
4509 
4510  /* make our updates visible */
4512  }
4513 }
static void update_relispartition(Oid relationId, bool newval)
Definition: indexcmds.c:4520
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 211 of file index.h.

212 {
213  BlockNumber block = (BlockNumber) (encoded >> 16);
214  OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
215 
216  ItemPointerSet(itemptr, block, offset);
217 }
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 190 of file index.h.

191 {
192  BlockNumber block = ItemPointerGetBlockNumber(itemptr);
193  OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr);
194  int64 encoded;
195 
196  /*
197  * Use the 16 least significant bits for the offset. 32 adjacent bits are
198  * used for the block number. Since remaining bits are unused, there
199  * cannot be negative encoded values (We assume a two's complement
200  * representation).
201  */
202  encoded = ((uint64) block << 16) | (uint16) offset;
203 
204  return encoded;
205 }
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 ( const ReindexStmt stmt,
Oid  indexId,
bool  skip_constraint_checks,
char  persistence,
const ReindexParams params 
)

Definition at line 3545 of file index.c.

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

References AccessExclusiveLock, AtEOXact_GUC(), BuildIndexInfo(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CheckRelationTableSpaceMove(), CheckTableNotInUse(), CommandCounterIncrement(), elog, ereport, errcode(), errdetail_internal(), errmsg(), ERROR, EventTriggerCollectSimpleCommand(), 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(), INFO, InvalidObjectAddress, InvalidOid, IsSystemRelation(), IsToastNamespace(), NewGUCNestLevel(), NoLock, ObjectAddressSet, 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(), RestrictSearchPath(), RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetReindexProcessing(), SetRelationTableSpace(), SetUserIdAndSecContext(), ShareLock, stmt, HeapTupleData::t_self, table_close(), table_open(), ReindexParams::tablespaceOid, TransferPredicateLocksToHeapRelation(), try_index_open(), and try_table_open().

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

◆ reindex_relation()

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

Definition at line 3885 of file index.c.

3887 {
3888  Relation rel;
3889  Oid toast_relid;
3890  List *indexIds;
3891  char persistence;
3892  bool result = false;
3893  ListCell *indexId;
3894  int i;
3895 
3896  /*
3897  * Open and lock the relation. ShareLock is sufficient since we only need
3898  * to prevent schema and data changes in it. The lock level used here
3899  * should match ReindexTable().
3900  */
3901  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3902  rel = try_table_open(relid, ShareLock);
3903  else
3904  rel = table_open(relid, ShareLock);
3905 
3906  /* if relation is gone, leave */
3907  if (!rel)
3908  return false;
3909 
3910  /*
3911  * Partitioned tables should never get processed here, as they have no
3912  * physical storage.
3913  */
3914  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3915  elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
3918 
3919  toast_relid = rel->rd_rel->reltoastrelid;
3920 
3921  /*
3922  * Get the list of index OIDs for this relation. (We trust the relcache
3923  * to get this with a sequential scan if ignoring system indexes.)
3924  */
3925  indexIds = RelationGetIndexList(rel);
3926 
3927  if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
3928  {
3929  /* Suppress use of all the indexes until they are rebuilt */
3930  SetReindexPending(indexIds);
3931 
3932  /*
3933  * Make the new heap contents visible --- now things might be
3934  * inconsistent!
3935  */
3937  }
3938 
3939  /*
3940  * Reindex the toast table, if any, before the main table.
3941  *
3942  * This helps in cases where a corruption in the toast table's index would
3943  * otherwise error and stop REINDEX TABLE command when it tries to fetch a
3944  * toasted datum. This way. the toast table's index is rebuilt and fixed
3945  * before it is used for reindexing the main table.
3946  *
3947  * It is critical to call reindex_relation() *after* the call to
3948  * RelationGetIndexList() returning the list of indexes on the relation,
3949  * because reindex_relation() will call CommandCounterIncrement() after
3950  * every reindex_index(). See REINDEX_REL_SUPPRESS_INDEX_USE for more
3951  * details.
3952  */
3953  if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
3954  {
3955  /*
3956  * Note that this should fail if the toast relation is missing, so
3957  * reset REINDEXOPT_MISSING_OK. Even if a new tablespace is set for
3958  * the parent relation, the indexes on its toast table are not moved.
3959  * This rule is enforced by setting tablespaceOid to InvalidOid.
3960  */
3961  ReindexParams newparams = *params;
3962 
3963  newparams.options &= ~(REINDEXOPT_MISSING_OK);
3964  newparams.tablespaceOid = InvalidOid;
3965  result |= reindex_relation(stmt, toast_relid, flags, &newparams);
3966  }
3967 
3968  /*
3969  * Compute persistence of indexes: same as that of owning rel, unless
3970  * caller specified otherwise.
3971  */
3973  persistence = RELPERSISTENCE_UNLOGGED;
3974  else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
3975  persistence = RELPERSISTENCE_PERMANENT;
3976  else
3977  persistence = rel->rd_rel->relpersistence;
3978 
3979  /* Reindex all the indexes. */
3980  i = 1;
3981  foreach(indexId, indexIds)
3982  {
3983  Oid indexOid = lfirst_oid(indexId);
3984  Oid indexNamespaceId = get_rel_namespace(indexOid);
3985 
3986  /*
3987  * Skip any invalid indexes on a TOAST table. These can only be
3988  * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
3989  * rebuilt it would not be possible to drop them anymore.
3990  */
3991  if (IsToastNamespace(indexNamespaceId) &&
3992  !get_index_isvalid(indexOid))
3993  {
3994  ereport(WARNING,
3995  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3996  errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
3997  get_namespace_name(indexNamespaceId),
3998  get_rel_name(indexOid))));
3999  continue;
4000  }
4001 
4002  reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
4003  persistence, params);
4004 
4006 
4007  /* Index should no longer be in the pending list */
4008  Assert(!ReindexIsProcessingIndex(indexOid));
4009 
4010  /* Set index rebuild count */
4012  i);
4013  i++;
4014  }
4015 
4016  /*
4017  * Close rel, but continue to hold the lock.
4018  */
4019  table_close(rel, NoLock);
4020 
4021  result |= (indexIds != NIL);
4022 
4023  return result;
4024 }
#define WARNING
Definition: elog.h:36
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4069
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3885
static void SetReindexPending(List *indexes)
Definition: index.c:4113
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition: index.c:3545
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:162
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition: index.h:160
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:163
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:161
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1930
#define PROGRESS_CLUSTER_INDEX_REBUILD_COUNT
Definition: progress.h:64
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4749

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, stmt, 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 4048 of file index.c.

4049 {
4050  return heapOid == currentlyReindexedHeap;
4051 }
static Oid currentlyReindexedHeap
Definition: index.c:4038

References currentlyReindexedHeap.

Referenced by index_update_stats().

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4069 of file index.c.

4070 {
4071  return indexOid == currentlyReindexedIndex ||
4073 }
static Oid currentlyReindexedIndex
Definition: index.c:4039
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722

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 4142 of file index.c.

4143 {
4144  /*
4145  * Because reindexing is not re-entrant, we don't need to cope with nested
4146  * reindexing states. We just need to avoid messing up the outer-level
4147  * state in case a subtransaction fails within a REINDEX. So checking the
4148  * current nest level against that of the reindex operation is sufficient.
4149  */
4150  if (reindexingNestLevel >= nestLevel)
4151  {
4154 
4155  /*
4156  * We needn't try to release the contents of pendingReindexedIndexes;
4157  * that list should be in a transaction-lifespan context, so it will
4158  * go away automatically.
4159  */
4161 
4162  reindexingNestLevel = 0;
4163  }
4164 }
static int reindexingNestLevel
Definition: index.c:4041

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4200 of file index.c.

4201 {
4202  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4203  int c = 0;
4204  MemoryContext oldcontext;
4205 
4208 
4211  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4214  sistate->pendingReindexedIndexes[c]);
4215  MemoryContextSwitchTo(oldcontext);
4216 
4217  /* Note the worker has its own transaction nesting level */
4219 }
MemoryContext TopMemoryContext
Definition: mcxt.c:137
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
char * c
Oid currentlyReindexedHeap
Definition: index.c:94
Oid currentlyReindexedIndex
Definition: index.c:95
int numPendingReindexedIndexes
Definition: index.c:96
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:97
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:915

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 3290 of file index.c.

3291 {
3292  Relation heapRelation,
3293  indexRelation;
3294  IndexInfo *indexInfo;
3295  IndexVacuumInfo ivinfo;
3297  Oid save_userid;
3298  int save_sec_context;
3299  int save_nestlevel;
3300 
3301  {
3302  const int progress_index[] = {
3308  };
3309  const int64 progress_vals[] = {
3311  0, 0, 0, 0
3312  };
3313 
3314  pgstat_progress_update_multi_param(5, progress_index, progress_vals);
3315  }
3316 
3317  /* Open and lock the parent heap relation */
3318  heapRelation = table_open(heapId, ShareUpdateExclusiveLock);
3319 
3320  /*
3321  * Switch to the table owner's userid, so that any index functions are run
3322  * as that user. Also lock down security-restricted operations and
3323  * arrange to make GUC variable changes local to this command.
3324  */
3325  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3326  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3327  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3328  save_nestlevel = NewGUCNestLevel();
3330 
3331  indexRelation = index_open(indexId, RowExclusiveLock);
3332 
3333  /*
3334  * Fetch info needed for index_insert. (You might think this should be
3335  * passed in from DefineIndex, but its copy is long gone due to having
3336  * been built in a previous transaction.)
3337  */
3338  indexInfo = BuildIndexInfo(indexRelation);
3339 
3340  /* mark build is concurrent just for consistency */
3341  indexInfo->ii_Concurrent = true;
3342 
3343  /*
3344  * Scan the index and gather up all the TIDs into a tuplesort object.
3345  */
3346  ivinfo.index = indexRelation;
3347  ivinfo.heaprel = heapRelation;
3348  ivinfo.analyze_only = false;
3349  ivinfo.report_progress = true;
3350  ivinfo.estimated_count = true;
3351  ivinfo.message_level = DEBUG2;
3352  ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3353  ivinfo.strategy = NULL;
3354 
3355  /*
3356  * Encode TIDs as int8 values for the sort, rather than directly sorting
3357  * item pointers. This can be significantly faster, primarily because TID
3358  * is a pass-by-reference type on all platforms, whereas int8 is
3359  * pass-by-value on most platforms.
3360  */
3361  state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
3362  InvalidOid, false,
3364  NULL, TUPLESORT_NONE);
3365  state.htups = state.itups = state.tups_inserted = 0;
3366 
3367  /* ambulkdelete updates progress metrics */
3368  (void) index_bulk_delete(&ivinfo, NULL,
3369  validate_index_callback, (void *) &state);
3370 
3371  /* Execute the sort */
3372  {
3373  const int progress_index[] = {
3377  };
3378  const int64 progress_vals[] = {
3380  0, 0
3381  };
3382 
3383  pgstat_progress_update_multi_param(3, progress_index, progress_vals);
3384  }
3385  tuplesort_performsort(state.tuplesort);
3386 
3387  /*
3388  * Now scan the heap and "merge" it with the index
3389  */
3392  table_index_validate_scan(heapRelation,
3393  indexRelation,
3394  indexInfo,
3395  snapshot,
3396  &state);
3397 
3398  /* Done with tuplesort object */
3399  tuplesort_end(state.tuplesort);
3400 
3401  elog(DEBUG2,
3402  "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3403  state.htups, state.itups, state.tups_inserted);
3404 
3405  /* Roll back any GUC changes executed by index functions */
3406  AtEOXact_GUC(false, save_nestlevel);
3407 
3408  /* Restore userid and security context */
3409  SetUserIdAndSecContext(save_userid, save_sec_context);
3410 
3411  /* Close rels, but keep locks */
3412  index_close(indexRelation, NoLock);
3413  table_close(heapRelation, NoLock);
3414 }
#define DEBUG2
Definition: elog.h:29
int maintenance_work_mem
Definition: globals.c:130
static bool validate_index_callback(ItemPointer itemptr, void *opaque)
Definition: index.c:3420
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:751
#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:1831
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1379
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:966
#define TUPLESORT_NONE
Definition: tuplesort.h:93
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, RestrictSearchPath(), 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().