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

Go to the source code of this file.

Data Structures

struct  ReindexParams
 
struct  ValidateIndexState
 

Macros

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

Typedefs

typedef struct ReindexParams ReindexParams
 
typedef struct ValidateIndexState ValidateIndexState
 

Enumerations

enum  IndexStateFlagsAction { INDEX_CREATE_SET_READY , INDEX_CREATE_SET_VALID , INDEX_DROP_CLEAR_VALID , INDEX_DROP_SET_DEAD }
 

Functions

void index_check_primary_key (Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
 
Oid index_create (Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const 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_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 160 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_PERMANENT

#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10

Definition at line 162 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_UNLOGGED

#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08

Definition at line 161 of file index.h.

◆ REINDEX_REL_PROCESS_TOAST

#define REINDEX_REL_PROCESS_TOAST   0x01

Definition at line 158 of file index.h.

◆ REINDEX_REL_SUPPRESS_INDEX_USE

#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02

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

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

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

2643 {
2644  int indnkeyatts;
2645  int i;
2646 
2648 
2649  /*
2650  * fetch info for checking unique indexes
2651  */
2652  Assert(ii->ii_Unique);
2653 
2654  if (index->rd_rel->relam != BTREE_AM_OID)
2655  elog(ERROR, "unexpected non-btree speculative unique index");
2656 
2657  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2658  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2659  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2660 
2661  /*
2662  * We have to look up the operator's strategy number. This provides a
2663  * cross-check that the operator does match the index.
2664  */
2665  /* We need the func OIDs and strategy numbers too */
2666  for (i = 0; i < indnkeyatts; i++)
2667  {
2669  ii->ii_UniqueOps[i] =
2670  get_opfamily_member(index->rd_opfamily[i],
2671  index->rd_opcintype[i],
2672  index->rd_opcintype[i],
2673  ii->ii_UniqueStrats[i]);
2674  if (!OidIsValid(ii->ii_UniqueOps[i]))
2675  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2676  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2677  index->rd_opcintype[i], index->rd_opfamily[i]);
2678  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2679  }
2680 }
unsigned short uint16
Definition: c.h:505
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
void * palloc(Size size)
Definition: mcxt.c:1317
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 2511 of file index.c.

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

4176 {
4179 }
static List * pendingReindexedIndexes
Definition: index.c:4044
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 2702 of file index.c.

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

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

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

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:746
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
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 1482 of file index.c.

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

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

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

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

1550 {
1551  Relation pg_class,
1552  pg_index,
1553  pg_constraint,
1554  pg_trigger;
1555  Relation oldClassRel,
1556  newClassRel;
1557  HeapTuple oldClassTuple,
1558  newClassTuple;
1559  Form_pg_class oldClassForm,
1560  newClassForm;
1561  HeapTuple oldIndexTuple,
1562  newIndexTuple;
1563  Form_pg_index oldIndexForm,
1564  newIndexForm;
1565  bool isPartition;
1566  Oid indexConstraintOid;
1567  List *constraintOids = NIL;
1568  ListCell *lc;
1569 
1570  /*
1571  * Take a necessary lock on the old and new index before swapping them.
1572  */
1573  oldClassRel = relation_open(oldIndexId, ShareUpdateExclusiveLock);
1574  newClassRel = relation_open(newIndexId, ShareUpdateExclusiveLock);
1575 
1576  /* Now swap names and dependencies of those indexes */
1577  pg_class = table_open(RelationRelationId, RowExclusiveLock);
1578 
1579  oldClassTuple = SearchSysCacheCopy1(RELOID,
1580  ObjectIdGetDatum(oldIndexId));
1581  if (!HeapTupleIsValid(oldClassTuple))
1582  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1583  newClassTuple = SearchSysCacheCopy1(RELOID,
1584  ObjectIdGetDatum(newIndexId));
1585  if (!HeapTupleIsValid(newClassTuple))
1586  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1587 
1588  oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple);
1589  newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple);
1590 
1591  /* Swap the names */
1592  namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1593  namestrcpy(&oldClassForm->relname, oldName);
1594 
1595  /* Swap the partition flags to track inheritance properly */
1596  isPartition = newClassForm->relispartition;
1597  newClassForm->relispartition = oldClassForm->relispartition;
1598  oldClassForm->relispartition = isPartition;
1599 
1600  CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple);
1601  CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple);
1602 
1603  heap_freetuple(oldClassTuple);
1604  heap_freetuple(newClassTuple);
1605 
1606  /* Now swap index info */
1607  pg_index = table_open(IndexRelationId, RowExclusiveLock);
1608 
1609  oldIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1610  ObjectIdGetDatum(oldIndexId));
1611  if (!HeapTupleIsValid(oldIndexTuple))
1612  elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1613  newIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1614  ObjectIdGetDatum(newIndexId));
1615  if (!HeapTupleIsValid(newIndexTuple))
1616  elog(ERROR, "could not find tuple for relation %u", newIndexId);
1617 
1618  oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple);
1619  newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple);
1620 
1621  /*
1622  * Copy constraint flags from the old index. This is safe because the old
1623  * index guaranteed uniqueness.
1624  */
1625  newIndexForm->indisprimary = oldIndexForm->indisprimary;
1626  oldIndexForm->indisprimary = false;
1627  newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1628  oldIndexForm->indisexclusion = false;
1629  newIndexForm->indimmediate = oldIndexForm->indimmediate;
1630  oldIndexForm->indimmediate = true;
1631 
1632  /* Preserve indisreplident in the new index */
1633  newIndexForm->indisreplident = oldIndexForm->indisreplident;
1634 
1635  /* Preserve indisclustered in the new index */
1636  newIndexForm->indisclustered = oldIndexForm->indisclustered;
1637 
1638  /*
1639  * Mark the new index as valid, and the old index as invalid similarly to
1640  * what index_set_state_flags() does.
1641  */
1642  newIndexForm->indisvalid = true;
1643  oldIndexForm->indisvalid = false;
1644  oldIndexForm->indisclustered = false;
1645  oldIndexForm->indisreplident = false;
1646 
1647  CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple);
1648  CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple);
1649 
1650  heap_freetuple(oldIndexTuple);
1651  heap_freetuple(newIndexTuple);
1652 
1653  /*
1654  * Move constraints and triggers over to the new index
1655  */
1656 
1657  constraintOids = get_index_ref_constraints(oldIndexId);
1658 
1659  indexConstraintOid = get_index_constraint(oldIndexId);
1660 
1661  if (OidIsValid(indexConstraintOid))
1662  constraintOids = lappend_oid(constraintOids, indexConstraintOid);
1663 
1664  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
1665  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
1666 
1667  foreach(lc, constraintOids)
1668  {
1669  HeapTuple constraintTuple,
1670  triggerTuple;
1671  Form_pg_constraint conForm;
1672  ScanKeyData key[1];
1673  SysScanDesc scan;
1674  Oid constraintOid = lfirst_oid(lc);
1675 
1676  /* Move the constraint from the old to the new index */
1677  constraintTuple = SearchSysCacheCopy1(CONSTROID,
1678  ObjectIdGetDatum(constraintOid));
1679  if (!HeapTupleIsValid(constraintTuple))
1680  elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1681 
1682  conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple));
1683 
1684  if (conForm->conindid == oldIndexId)
1685  {
1686  conForm->conindid = newIndexId;
1687 
1688  CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple);
1689  }
1690 
1691  heap_freetuple(constraintTuple);
1692 
1693  /* Search for trigger records */
1694  ScanKeyInit(&key[0],
1695  Anum_pg_trigger_tgconstraint,
1696  BTEqualStrategyNumber, F_OIDEQ,
1697  ObjectIdGetDatum(constraintOid));
1698 
1699  scan = systable_beginscan(pg_trigger, TriggerConstraintIndexId, true,
1700  NULL, 1, key);
1701 
1702  while (HeapTupleIsValid((triggerTuple = systable_getnext(scan))))
1703  {
1704  Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1705 
1706  if (tgForm->tgconstrindid != oldIndexId)
1707  continue;
1708 
1709  /* Make a modifiable copy */
1710  triggerTuple = heap_copytuple(triggerTuple);
1711  tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1712 
1713  tgForm->tgconstrindid = newIndexId;
1714 
1715  CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple);
1716 
1717  heap_freetuple(triggerTuple);
1718  }
1719 
1720  systable_endscan(scan);
1721  }
1722 
1723  /*
1724  * Move comment if any
1725  */
1726  {
1728  ScanKeyData skey[3];
1729  SysScanDesc sd;
1730  HeapTuple tuple;
1731  Datum values[Natts_pg_description] = {0};
1732  bool nulls[Natts_pg_description] = {0};
1733  bool replaces[Natts_pg_description] = {0};
1734 
1735  values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId);
1736  replaces[Anum_pg_description_objoid - 1] = true;
1737 
1738  ScanKeyInit(&skey[0],
1739  Anum_pg_description_objoid,
1740  BTEqualStrategyNumber, F_OIDEQ,
1741  ObjectIdGetDatum(oldIndexId));
1742  ScanKeyInit(&skey[1],
1743  Anum_pg_description_classoid,
1744  BTEqualStrategyNumber, F_OIDEQ,
1745  ObjectIdGetDatum(RelationRelationId));
1746  ScanKeyInit(&skey[2],
1747  Anum_pg_description_objsubid,
1748  BTEqualStrategyNumber, F_INT4EQ,
1749  Int32GetDatum(0));
1750 
1751  description = table_open(DescriptionRelationId, RowExclusiveLock);
1752 
1753  sd = systable_beginscan(description, DescriptionObjIndexId, true,
1754  NULL, 3, skey);
1755 
1756  while ((tuple = systable_getnext(sd)) != NULL)
1757  {
1759  values, nulls, replaces);
1760  CatalogTupleUpdate(description, &tuple->t_self, tuple);
1761 
1762  break; /* Assume there can be only one match */
1763  }
1764 
1765  systable_endscan(sd);
1767  }
1768 
1769  /*
1770  * Swap inheritance relationship with parent index
1771  */
1772  if (get_rel_relispartition(oldIndexId))
1773  {
1774  List *ancestors = get_partition_ancestors(oldIndexId);
1775  Oid parentIndexRelid = linitial_oid(ancestors);
1776 
1777  DeleteInheritsTuple(oldIndexId, parentIndexRelid, false, NULL);
1778  StoreSingleInheritance(newIndexId, parentIndexRelid, 1);
1779 
1780  list_free(ancestors);
1781  }
1782 
1783  /*
1784  * Swap all dependencies of and on the old index to the new one, and
1785  * vice-versa. Note that a call to CommandCounterIncrement() would cause
1786  * duplicate entries in pg_depend, so this should not be done.
1787  */
1788  changeDependenciesOf(RelationRelationId, newIndexId, oldIndexId);
1789  changeDependenciesOn(RelationRelationId, newIndexId, oldIndexId);
1790 
1791  changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId);
1792  changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId);
1793 
1794  /* copy over statistics from old to new index */
1795  pgstat_copy_relation_stats(newClassRel, oldClassRel);
1796 
1797  /* Copy data of pg_statistic from the old index to the new one */
1798  CopyStatistics(oldIndexId, newIndexId);
1799 
1800  /* Close relations */
1801  table_close(pg_class, RowExclusiveLock);
1802  table_close(pg_index, RowExclusiveLock);
1803  table_close(pg_constraint, RowExclusiveLock);
1804  table_close(pg_trigger, RowExclusiveLock);
1805 
1806  /* The lock taken previously is not released until the end of transaction */
1807  relation_close(oldClassRel, NoLock);
1808  relation_close(newClassRel, NoLock);
1809 }
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:2870
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:2027
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:566
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:622
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:989
List * get_index_ref_constraints(Oid indexId)
Definition: pg_depend.c:1045
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  int inhcount;
1901 
1902  deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1903  initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1904  mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
1905 
1906  /* constraint creation support doesn't work while bootstrapping */
1908 
1909  /* enforce system-table restriction */
1910  if (!allow_system_table_mods &&
1911  IsSystemRelation(heapRelation) &&
1913  ereport(ERROR,
1914  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1915  errmsg("user-defined indexes on system catalog tables are not supported")));
1916 
1917  /* primary/unique constraints shouldn't have any expressions */
1918  if (indexInfo->ii_Expressions &&
1919  constraintType != CONSTRAINT_EXCLUSION)
1920  elog(ERROR, "constraints cannot have index expressions");
1921 
1922  /*
1923  * If we're manufacturing a constraint for a pre-existing index, we need
1924  * to get rid of the existing auto dependencies for the index (the ones
1925  * that index_create() would have made instead of calling this function).
1926  *
1927  * Note: this code would not necessarily do the right thing if the index
1928  * has any expressions or predicate, but we'd never be turning such an
1929  * index into a UNIQUE or PRIMARY KEY constraint.
1930  */
1931  if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
1932  deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
1933  RelationRelationId, DEPENDENCY_AUTO);
1934 
1935  if (OidIsValid(parentConstraintId))
1936  {
1937  islocal = false;
1938  inhcount = 1;
1939  noinherit = false;
1940  }
1941  else
1942  {
1943  islocal = true;
1944  inhcount = 0;
1945  noinherit = true;
1946  }
1947 
1948  /*
1949  * Construct a pg_constraint entry.
1950  */
1951  conOid = CreateConstraintEntry(constraintName,
1952  namespaceId,
1953  constraintType,
1954  deferrable,
1955  initdeferred,
1956  true,
1957  parentConstraintId,
1958  RelationGetRelid(heapRelation),
1959  indexInfo->ii_IndexAttrNumbers,
1960  indexInfo->ii_NumIndexKeyAttrs,
1961  indexInfo->ii_NumIndexAttrs,
1962  InvalidOid, /* no domain */
1963  indexRelationId, /* index OID */
1964  InvalidOid, /* no foreign key */
1965  NULL,
1966  NULL,
1967  NULL,
1968  NULL,
1969  0,
1970  ' ',
1971  ' ',
1972  NULL,
1973  0,
1974  ' ',
1975  indexInfo->ii_ExclusionOps,
1976  NULL, /* no check constraint */
1977  NULL,
1978  islocal,
1979  inhcount,
1980  noinherit,
1981  is_internal);
1982 
1983  /*
1984  * Register the index as internally dependent on the constraint.
1985  *
1986  * Note that the constraint has a dependency on the table, so we don't
1987  * need (or want) any direct dependency from the index to the table.
1988  */
1989  ObjectAddressSet(myself, ConstraintRelationId, conOid);
1990  ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId);
1991  recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
1992 
1993  /*
1994  * Also, if this is a constraint on a partition, give it partition-type
1995  * dependencies on the parent constraint as well as the table.
1996  */
1997  if (OidIsValid(parentConstraintId))
1998  {
1999  ObjectAddress referenced;
2000 
2001  ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
2002  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
2003  ObjectAddressSet(referenced, RelationRelationId,
2004  RelationGetRelid(heapRelation));
2005  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
2006  }
2007 
2008  /*
2009  * If the constraint is deferrable, create the deferred uniqueness
2010  * checking trigger. (The trigger will be given an internal dependency on
2011  * the constraint by CreateTrigger.)
2012  */
2013  if (deferrable)
2014  {
2016 
2017  trigger->replace = false;
2018  trigger->isconstraint = true;
2019  trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
2020  "PK_ConstraintTrigger" :
2021  "Unique_ConstraintTrigger";
2022  trigger->relation = NULL;
2023  trigger->funcname = SystemFuncName("unique_key_recheck");
2024  trigger->args = NIL;
2025  trigger->row = true;
2026  trigger->timing = TRIGGER_TYPE_AFTER;
2027  trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE;
2028  trigger->columns = NIL;
2029  trigger->whenClause = NULL;
2030  trigger->transitionRels = NIL;
2031  trigger->deferrable = true;
2032  trigger->initdeferred = initdeferred;
2033  trigger->constrrel = NULL;
2034 
2035  (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
2036  InvalidOid, conOid, indexRelationId, InvalidOid,
2037  InvalidOid, NULL, true, false);
2038  }
2039 
2040  /*
2041  * If needed, mark the index as primary and/or deferred in pg_index.
2042  *
2043  * Note: When making an existing index into a constraint, caller must have
2044  * a table lock that prevents concurrent table updates; otherwise, there
2045  * is a risk that concurrent readers of the table will miss seeing this
2046  * index at all.
2047  */
2048  if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
2049  (mark_as_primary || deferrable))
2050  {
2051  Relation pg_index;
2052  HeapTuple indexTuple;
2053  Form_pg_index indexForm;
2054  bool dirty = false;
2055  bool marked_as_primary = false;
2056 
2057  pg_index = table_open(IndexRelationId, RowExclusiveLock);
2058 
2059  indexTuple = SearchSysCacheCopy1(INDEXRELID,
2060  ObjectIdGetDatum(indexRelationId));
2061  if (!HeapTupleIsValid(indexTuple))
2062  elog(ERROR, "cache lookup failed for index %u", indexRelationId);
2063  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
2064 
2065  if (mark_as_primary && !indexForm->indisprimary)
2066  {
2067  indexForm->indisprimary = true;
2068  dirty = true;
2069  marked_as_primary = true;
2070  }
2071 
2072  if (deferrable && indexForm->indimmediate)
2073  {
2074  indexForm->indimmediate = false;
2075  dirty = true;
2076  }
2077 
2078  if (dirty)
2079  {
2080  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
2081 
2082  /*
2083  * When we mark an existing index as primary, force a relcache
2084  * flush on its parent table, so that all sessions will become
2085  * aware that the table now has a primary key. This is important
2086  * because it affects some replication behaviors.
2087  */
2088  if (marked_as_primary)
2089  CacheInvalidateRelcache(heapRelation);
2090 
2091  InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
2092  InvalidOid, is_internal);
2093  }
2094 
2095  heap_freetuple(indexTuple);
2096  table_close(pg_index, RowExclusiveLock);
2097  }
2098 
2099  return myself;
2100 }
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_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:454
#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 is_internal)
Definition: pg_constraint.c:48
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
#define RelationGetNamespace(relation)
Definition: rel.h:546
Node * whenClause
Definition: parsenodes.h:3021
List * transitionRels
Definition: parsenodes.h:3023
RangeVar * constrrel
Definition: parsenodes.h:3027
RangeVar * relation
Definition: parsenodes.h:3012
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, 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  LockRelationOid(parentIndexRelid, ShareUpdateExclusiveLock);
1062  SetRelationHasSubclass(parentIndexRelid, true);
1063  }
1064 
1065  /*
1066  * Register constraint and dependencies for the index.
1067  *
1068  * If the index is from a CONSTRAINT clause, construct a pg_constraint
1069  * entry. The index will be linked to the constraint, which in turn is
1070  * linked to the table. If it's not a CONSTRAINT, we need to make a
1071  * dependency directly on the table.
1072  *
1073  * We don't need a dependency on the namespace, because there'll be an
1074  * indirect dependency via our parent table.
1075  *
1076  * During bootstrap we can't register any dependencies, and we don't try
1077  * to make a constraint either.
1078  */
1080  {
1081  ObjectAddress myself,
1082  referenced;
1083  ObjectAddresses *addrs;
1084 
1085  ObjectAddressSet(myself, RelationRelationId, indexRelationId);
1086 
1087  if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)
1088  {
1089  char constraintType;
1090  ObjectAddress localaddr;
1091 
1092  if (isprimary)
1093  constraintType = CONSTRAINT_PRIMARY;
1094  else if (indexInfo->ii_Unique)
1095  constraintType = CONSTRAINT_UNIQUE;
1096  else if (is_exclusion)
1097  constraintType = CONSTRAINT_EXCLUSION;
1098  else
1099  {
1100  elog(ERROR, "constraint must be PRIMARY, UNIQUE or EXCLUDE");
1101  constraintType = 0; /* keep compiler quiet */
1102  }
1103 
1104  localaddr = index_constraint_create(heapRelation,
1105  indexRelationId,
1106  parentConstraintId,
1107  indexInfo,
1108  indexRelationName,
1109  constraintType,
1110  constr_flags,
1111  allow_system_table_mods,
1112  is_internal);
1113  if (constraintId)
1114  *constraintId = localaddr.objectId;
1115  }
1116  else
1117  {
1118  bool have_simple_col = false;
1119 
1120  addrs = new_object_addresses();
1121 
1122  /* Create auto dependencies on simply-referenced columns */
1123  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1124  {
1125  if (indexInfo->ii_IndexAttrNumbers[i] != 0)
1126  {
1127  ObjectAddressSubSet(referenced, RelationRelationId,
1128  heapRelationId,
1129  indexInfo->ii_IndexAttrNumbers[i]);
1130  add_exact_object_address(&referenced, addrs);
1131  have_simple_col = true;
1132  }
1133  }
1134 
1135  /*
1136  * If there are no simply-referenced columns, give the index an
1137  * auto dependency on the whole table. In most cases, this will
1138  * be redundant, but it might not be if the index expressions and
1139  * predicate contain no Vars or only whole-row Vars.
1140  */
1141  if (!have_simple_col)
1142  {
1143  ObjectAddressSet(referenced, RelationRelationId,
1144  heapRelationId);
1145  add_exact_object_address(&referenced, addrs);
1146  }
1147 
1149  free_object_addresses(addrs);
1150  }
1151 
1152  /*
1153  * If this is an index partition, create partition dependencies on
1154  * both the parent index and the table. (Note: these must be *in
1155  * addition to*, not instead of, all other dependencies. Otherwise
1156  * we'll be short some dependencies after DETACH PARTITION.)
1157  */
1158  if (OidIsValid(parentIndexRelid))
1159  {
1160  ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid);
1161  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
1162 
1163  ObjectAddressSet(referenced, RelationRelationId, heapRelationId);
1164  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
1165  }
1166 
1167  /* placeholder for normal dependencies */
1168  addrs = new_object_addresses();
1169 
1170  /* Store dependency on collations */
1171 
1172  /* The default collation is pinned, so don't bother recording it */
1173  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1174  {
1175  if (OidIsValid(collationIds[i]) && collationIds[i] != DEFAULT_COLLATION_OID)
1176  {
1177  ObjectAddressSet(referenced, CollationRelationId, collationIds[i]);
1178  add_exact_object_address(&referenced, addrs);
1179  }
1180  }
1181 
1182  /* Store dependency on operator classes */
1183  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1184  {
1185  ObjectAddressSet(referenced, OperatorClassRelationId, opclassIds[i]);
1186  add_exact_object_address(&referenced, addrs);
1187  }
1188 
1190  free_object_addresses(addrs);
1191 
1192  /* Store dependencies on anything mentioned in index expressions */
1193  if (indexInfo->ii_Expressions)
1194  {
1196  (Node *) indexInfo->ii_Expressions,
1197  heapRelationId,
1199  DEPENDENCY_AUTO, false);
1200  }
1201 
1202  /* Store dependencies on anything mentioned in predicate */
1203  if (indexInfo->ii_Predicate)
1204  {
1206  (Node *) indexInfo->ii_Predicate,
1207  heapRelationId,
1209  DEPENDENCY_AUTO, false);
1210  }
1211  }
1212  else
1213  {
1214  /* Bootstrap mode - assert we weren't asked for constraint support */
1215  Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
1216  }
1217 
1218  /* Post creation hook for new index */
1219  InvokeObjectPostCreateHookArg(RelationRelationId,
1220  indexRelationId, 0, is_internal);
1221 
1222  /*
1223  * Advance the command counter so that we can see the newly-entered
1224  * catalog tuples for the index.
1225  */
1227 
1228  /*
1229  * In bootstrap mode, we have to fill in the index strategy structure with
1230  * information from the catalogs. If we aren't bootstrapping, then the
1231  * relcache entry has already been rebuilt thanks to sinval update during
1232  * CommandCounterIncrement.
1233  */
1235  RelationInitIndexAccessInfo(indexRelation);
1236  else
1237  Assert(indexRelation->rd_indexcxt != NULL);
1238 
1239  indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs;
1240 
1241  /* Validate opclass-specific options */
1242  if (opclassOptions)
1243  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1244  (void) index_opclass_options(indexRelation, i + 1,
1245  opclassOptions[i],
1246  true);
1247 
1248  /*
1249  * If this is bootstrap (initdb) time, then we don't actually fill in the
1250  * index yet. We'll be creating more indexes and classes later, so we
1251  * delay filling them in until just before we're done with bootstrapping.
1252  * Similarly, if the caller specified to skip the build then filling the
1253  * index is delayed till later (ALTER TABLE can save work in some cases
1254  * with this). Otherwise, we call the AM routine that constructs the
1255  * index.
1256  */
1258  {
1259  index_register(heapRelationId, indexRelationId, indexInfo);
1260  }
1261  else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0)
1262  {
1263  /*
1264  * Caller is responsible for filling the index later on. However,
1265  * we'd better make sure that the heap relation is correctly marked as
1266  * having an index.
1267  */
1268  index_update_stats(heapRelation,
1269  true,
1270  -1.0);
1271  /* Make the above update visible */
1273  }
1274  else
1275  {
1276  index_build(heapRelation, indexRelation, indexInfo, false, true);
1277  }
1278 
1279  /*
1280  * Close the index; but we keep the lock that we acquired above until end
1281  * of transaction. Closing the heap is caller's responsibility.
1282  */
1283  index_close(indexRelation, NoLock);
1284 
1285  return indexRelationId;
1286 }
void index_register(Oid heap, Oid ind, const IndexInfo *indexInfo)
Definition: bootstrap.c:900
TransactionId MultiXactId
Definition: c.h:662
uint32 TransactionId
Definition: c.h:652
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:521
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2742
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:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define NOTICE
Definition: elog.h:35
bool IsBinaryUpgrade
Definition: globals.c:119
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:896
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:996
invalidindex index d is invalid
Definition: isn.c:134
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
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:1885
#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:1424
#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:3484
#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(), LockRelationOid(), 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(), ShareUpdateExclusiveLock, 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 2114 of file index.c.

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

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

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

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

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

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 4280 of file indexcmds.c.

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

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

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

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

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

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

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

4053 {
4054  return heapOid == currentlyReindexedHeap;
4055 }
static Oid currentlyReindexedHeap
Definition: index.c:4042

References currentlyReindexedHeap.

Referenced by index_update_stats().

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4073 of file index.c.

4074 {
4075  return indexOid == currentlyReindexedIndex ||
4077 }
static Oid currentlyReindexedIndex
Definition: index.c:4043
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 4146 of file index.c.

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

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4204 of file index.c.

4205 {
4206  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4207  int c = 0;
4208  MemoryContext oldcontext;
4209 
4212 
4215  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4218  sistate->pendingReindexedIndexes[c]);
4219  MemoryContextSwitchTo(oldcontext);
4220 
4221  /* Note the worker has its own transaction nesting level */
4223 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * c
MemoryContextSwitchTo(old_ctx)
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:927

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

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