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

Go to the source code of this file.

Data Structures

struct  ReindexParams
 
struct  ValidateIndexState
 

Macros

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

Typedefs

typedef struct ReindexParams ReindexParams
 
typedef struct ValidateIndexState ValidateIndexState
 

Enumerations

enum  IndexStateFlagsAction { INDEX_CREATE_SET_READY , INDEX_CREATE_SET_VALID , INDEX_DROP_CLEAR_VALID , INDEX_DROP_SET_DEAD }
 

Functions

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

◆ INDEX_CONSTR_CREATE_INIT_DEFERRED

#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)

Definition at line 92 of file index.h.

◆ INDEX_CONSTR_CREATE_MARK_AS_PRIMARY

#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)

Definition at line 90 of file index.h.

◆ INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS

#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)

Definition at line 94 of file index.h.

◆ INDEX_CONSTR_CREATE_UPDATE_INDEX

#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)

Definition at line 93 of file index.h.

◆ INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS

#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS   (1 << 5)

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

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

2439 {
2440  IndexInfo *ii;
2441  Form_pg_index indexStruct = index->rd_index;
2442  int i;
2443  int numAtts;
2444 
2445  /* check the number of keys, and copy attr numbers into the IndexInfo */
2446  numAtts = indexStruct->indnatts;
2447  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2448  elog(ERROR, "invalid indnatts %d for index %u",
2449  numAtts, RelationGetRelid(index));
2450 
2451  /*
2452  * Create the node, fetching any expressions needed for expressional
2453  * indexes and index predicate if any.
2454  */
2455  ii = makeIndexInfo(indexStruct->indnatts,
2456  indexStruct->indnkeyatts,
2457  index->rd_rel->relam,
2460  indexStruct->indisunique,
2461  indexStruct->indnullsnotdistinct,
2462  indexStruct->indisready,
2463  false,
2464  index->rd_indam->amsummarizing);
2465 
2466  /* fill in attribute numbers */
2467  for (i = 0; i < numAtts; i++)
2468  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2469 
2470  /* fetch exclusion constraint info if any */
2471  if (indexStruct->indisexclusion)
2472  {
2474  &ii->ii_ExclusionOps,
2475  &ii->ii_ExclusionProcs,
2476  &ii->ii_ExclusionStrats);
2477  }
2478 
2479  return ii;
2480 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5124
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5563
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5011
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 2676 of file index.c.

2677 {
2678  int indnkeyatts;
2679  int i;
2680 
2682 
2683  /*
2684  * fetch info for checking unique indexes
2685  */
2686  Assert(ii->ii_Unique);
2687 
2688  if (index->rd_rel->relam != BTREE_AM_OID)
2689  elog(ERROR, "unexpected non-btree speculative unique index");
2690 
2691  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2692  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2693  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2694 
2695  /*
2696  * We have to look up the operator's strategy number. This provides a
2697  * cross-check that the operator does match the index.
2698  */
2699  /* We need the func OIDs and strategy numbers too */
2700  for (i = 0; i < indnkeyatts; i++)
2701  {
2703  ii->ii_UniqueOps[i] =
2704  get_opfamily_member(index->rd_opfamily[i],
2705  index->rd_opcintype[i],
2706  index->rd_opcintype[i],
2707  ii->ii_UniqueStrats[i]);
2708  if (!OidIsValid(ii->ii_UniqueOps[i]))
2709  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2710  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2711  index->rd_opcintype[i], index->rd_opfamily[i]);
2712  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2713  }
2714 }
unsigned short uint16
Definition: c.h:494
#define OidIsValid(objectId)
Definition: c.h:764
Assert(fmt[strlen(fmt) - 1] !='\n')
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1262
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
void * palloc(Size size)
Definition: mcxt.c:1201
unsigned int Oid
Definition: postgres_ext.h:31
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:523
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ii_Unique
Definition: execnodes.h: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 2545 of file index.c.

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

4200 {
4203 }
static List * pendingReindexedIndexes
Definition: index.c:4068
static int list_length(const List *l)
Definition: pg_list.h:152
Size mul_size(Size s1, Size s2)
Definition: shmem.c:511

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

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

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

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

◆ index_build()

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

Definition at line 2972 of file index.c.

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

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, RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), smgrcreate(), smgrexists(), HeapTupleData::t_self, table_close(), and table_open().

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

◆ index_check_primary_key()

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

Definition at line 206 of file index.c.

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

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1282 of file index.c.

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1850 of file index.c.

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

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

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

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 710 of file index.c.

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

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

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

◆ index_drop()

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

Definition at line 2148 of file index.c.

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

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

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

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

3550 {
3551  HeapTuple tuple;
3553  Oid result;
3554 
3555  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3556  if (!HeapTupleIsValid(tuple))
3557  {
3558  if (missing_ok)
3559  return InvalidOid;
3560  elog(ERROR, "cache lookup failed for index %u", indexId);
3561  }
3562  index = (Form_pg_index) GETSTRUCT(tuple);
3563  Assert(index->indexrelid == indexId);
3564 
3565  result = index->indrelid;
3566  ReleaseSysCache(tuple);
3567  return result;
3568 }

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

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

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

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

◆ itemptr_decode()

static void itemptr_decode ( ItemPointer  itemptr,
int64  encoded 
)
inlinestatic

Definition at line 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 vac_tid_reaped(), and validate_index_callback().

◆ reindex_index()

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

Definition at line 3574 of file index.c.

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

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

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

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

4077 {
4078  return heapOid == currentlyReindexedHeap;
4079 }
static Oid currentlyReindexedHeap
Definition: index.c:4066

References currentlyReindexedHeap.

Referenced by index_update_stats().

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4097 of file index.c.

4098 {
4099  return indexOid == currentlyReindexedIndex ||
4101 }
static Oid currentlyReindexedIndex
Definition: index.c:4067
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 4170 of file index.c.

4171 {
4172  /*
4173  * Because reindexing is not re-entrant, we don't need to cope with nested
4174  * reindexing states. We just need to avoid messing up the outer-level
4175  * state in case a subtransaction fails within a REINDEX. So checking the
4176  * current nest level against that of the reindex operation is sufficient.
4177  */
4178  if (reindexingNestLevel >= nestLevel)
4179  {
4182 
4183  /*
4184  * We needn't try to release the contents of pendingReindexedIndexes;
4185  * that list should be in a transaction-lifespan context, so it will
4186  * go away automatically.
4187  */
4189 
4190  reindexingNestLevel = 0;
4191  }
4192 }
static int reindexingNestLevel
Definition: index.c:4069

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4228 of file index.c.

4229 {
4230  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4231  int c = 0;
4232  MemoryContext oldcontext;
4233 
4236 
4239  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4242  sistate->pendingReindexedIndexes[c]);
4243  MemoryContextSwitchTo(oldcontext);
4244 
4245  /* Note the worker has its own transaction nesting level */
4247 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
char * c
Oid currentlyReindexedHeap
Definition: index.c:99
Oid currentlyReindexedIndex
Definition: index.c:100
int numPendingReindexedIndexes
Definition: index.c:101
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:102
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:914

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ validate_index()

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

Definition at line 3320 of file index.c.

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

References IndexVacuumInfo::analyze_only, AtEOXact_GUC(), BuildIndexInfo(), DEBUG2, elog(), IndexVacuumInfo::estimated_count, GetUserIdAndSecContext(), IndexVacuumInfo::heaprel, IndexInfo::ii_Concurrent, IndexVacuumInfo::index, index_bulk_delete(), index_close(), index_open(), InvalidOid, maintenance_work_mem, IndexVacuumInfo::message_level, NewGUCNestLevel(), NoLock, IndexVacuumInfo::num_heap_tuples, pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN, PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT, PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN, PROGRESS_CREATEIDX_TUPLES_DONE, PROGRESS_CREATEIDX_TUPLES_TOTAL, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL, RelationData::rd_rel, IndexVacuumInfo::report_progress, 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().