PostgreSQL Source Code  git master
index.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/amapi.h"
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
#include "access/visibilitymap.h"
#include "access/xact.h"
#include "bootstrap/bootstrap.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_description.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "commands/event_trigger.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parser.h"
#include "pgstat.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_rusage.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tuplesort.h"
Include dependency graph for index.c:

Go to the source code of this file.

Data Structures

struct  SerializedReindexState
 

Functions

static bool relationHasPrimaryKey (Relation rel)
 
static TupleDesc ConstructTupleDescriptor (Relation heapRelation, const IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, const Oid *collationIds, const Oid *opclassIds)
 
static void InitializeAttributeOids (Relation indexRelation, int numatts, Oid indexoid)
 
static void AppendAttributeTuples (Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets)
 
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)
 
static void index_update_stats (Relation rel, bool hasindex, double reltuples)
 
static void IndexCheckExclusion (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
 
static bool validate_index_callback (ItemPointer itemptr, void *opaque)
 
static bool ReindexIsCurrentlyProcessingIndex (Oid indexOid)
 
static void SetReindexProcessing (Oid heapOid, Oid indexOid)
 
static void ResetReindexProcessing (void)
 
static void SetReindexPending (List *indexes)
 
static void RemoveReindexPending (Oid indexOid)
 
void index_check_primary_key (Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
 
Oid index_create (Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
 
Oid index_concurrently_create_copy (Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
 
void index_concurrently_build (Oid heapRelationId, Oid indexRelationId)
 
void index_concurrently_swap (Oid newIndexId, Oid oldIndexId, const char *oldName)
 
void index_concurrently_set_dead (Oid heapId, Oid indexId)
 
ObjectAddress index_constraint_create (Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
 
void index_drop (Oid indexId, bool concurrent, bool concurrent_lock_mode)
 
IndexInfoBuildIndexInfo (Relation index)
 
IndexInfoBuildDummyIndexInfo (Relation index)
 
bool CompareIndexInfo (const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
 
void BuildSpeculativeIndexInfo (Relation index, IndexInfo *ii)
 
void FormIndexDatum (IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
void index_build (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
 
void validate_index (Oid heapId, Oid indexId, Snapshot snapshot)
 
void index_set_state_flags (Oid indexId, IndexStateFlagsAction action)
 
Oid IndexGetRelation (Oid indexId, bool missing_ok)
 
void reindex_index (const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
 
bool reindex_relation (const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
 
bool ReindexIsProcessingHeap (Oid heapOid)
 
bool ReindexIsProcessingIndex (Oid indexOid)
 
void ResetReindexState (int nestLevel)
 
Size EstimateReindexStateSpace (void)
 
void SerializeReindexState (Size maxsize, char *start_address)
 
void RestoreReindexState (const void *reindexstate)
 

Variables

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid
 
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
 
static Oid currentlyReindexedHeap = InvalidOid
 
static Oid currentlyReindexedIndex = InvalidOid
 
static ListpendingReindexedIndexes = NIL
 
static int reindexingNestLevel = 0
 

Function Documentation

◆ AppendAttributeTuples()

static void AppendAttributeTuples ( Relation  indexRelation,
const Datum attopts,
const NullableDatum stattargets 
)
static

Definition at line 510 of file index.c.

511 {
512  Relation pg_attribute;
513  CatalogIndexState indstate;
514  TupleDesc indexTupDesc;
515  FormExtraData_pg_attribute *attrs_extra = NULL;
516 
517  if (attopts)
518  {
519  attrs_extra = palloc0_array(FormExtraData_pg_attribute, indexRelation->rd_att->natts);
520 
521  for (int i = 0; i < indexRelation->rd_att->natts; i++)
522  {
523  if (attopts[i])
524  attrs_extra[i].attoptions.value = attopts[i];
525  else
526  attrs_extra[i].attoptions.isnull = true;
527 
528  if (stattargets)
529  attrs_extra[i].attstattarget = stattargets[i];
530  else
531  attrs_extra[i].attstattarget.isnull = true;
532  }
533  }
534 
535  /*
536  * open the attribute relation and its indexes
537  */
538  pg_attribute = table_open(AttributeRelationId, RowExclusiveLock);
539 
540  indstate = CatalogOpenIndexes(pg_attribute);
541 
542  /*
543  * insert data from new index's tupdesc into pg_attribute
544  */
545  indexTupDesc = RelationGetDescr(indexRelation);
546 
547  InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid, attrs_extra, indstate);
548 
549  CatalogCloseIndexes(indstate);
550 
551  table_close(pg_attribute, RowExclusiveLock);
552 }
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
Definition: heap.c:702
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
int i
Definition: isn.c:73
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationGetDescr(relation)
Definition: rel.h:531
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
TupleDesc rd_att
Definition: rel.h:112
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References FormExtraData_pg_attribute::attoptions, FormExtraData_pg_attribute::attstattarget, CatalogCloseIndexes(), CatalogOpenIndexes(), i, InsertPgAttributeTuples(), InvalidOid, NullableDatum::isnull, TupleDescData::natts, palloc0_array, RelationData::rd_att, RelationGetDescr, RowExclusiveLock, table_close(), table_open(), and NullableDatum::value.

Referenced by index_create().

◆ BuildDummyIndexInfo()

IndexInfo* BuildDummyIndexInfo ( Relation  index)

Definition at line 2490 of file index.c.

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

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

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

2672 {
2673  int indnkeyatts;
2674  int i;
2675 
2677 
2678  /*
2679  * fetch info for checking unique indexes
2680  */
2681  Assert(ii->ii_Unique);
2682 
2683  if (index->rd_rel->relam != BTREE_AM_OID)
2684  elog(ERROR, "unexpected non-btree speculative unique index");
2685 
2686  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2687  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2688  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2689 
2690  /*
2691  * We have to look up the operator's strategy number. This provides a
2692  * cross-check that the operator does match the index.
2693  */
2694  /* We need the func OIDs and strategy numbers too */
2695  for (i = 0; i < indnkeyatts; i++)
2696  {
2698  ii->ii_UniqueOps[i] =
2699  get_opfamily_member(index->rd_opfamily[i],
2700  index->rd_opcintype[i],
2701  index->rd_opcintype[i],
2702  ii->ii_UniqueStrats[i]);
2703  if (!OidIsValid(ii->ii_UniqueOps[i]))
2704  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2705  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2706  index->rd_opcintype[i], index->rd_opfamily[i]);
2707  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2708  }
2709 }
unsigned short uint16
Definition: c.h:508
#define Assert(condition)
Definition: c.h:861
#define OidIsValid(objectId)
Definition: c.h:778
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
void * palloc(Size size)
Definition: mcxt.c:1317
unsigned int Oid
Definition: postgres_ext.h:31
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ii_Unique
Definition: execnodes.h:199
Oid * ii_UniqueOps
Definition: execnodes.h:196
uint16 * ii_UniqueStrats
Definition: execnodes.h:198
Oid * ii_UniqueProcs
Definition: execnodes.h:197

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

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

◆ ConstructTupleDescriptor()

static TupleDesc ConstructTupleDescriptor ( Relation  heapRelation,
const IndexInfo indexInfo,
const List indexColNames,
Oid  accessMethodId,
const Oid collationIds,
const Oid opclassIds 
)
static

Definition at line 280 of file index.c.

286 {
287  int numatts = indexInfo->ii_NumIndexAttrs;
288  int numkeyatts = indexInfo->ii_NumIndexKeyAttrs;
289  ListCell *colnames_item = list_head(indexColNames);
290  ListCell *indexpr_item = list_head(indexInfo->ii_Expressions);
291  IndexAmRoutine *amroutine;
292  TupleDesc heapTupDesc;
293  TupleDesc indexTupDesc;
294  int natts; /* #atts in heap rel --- for error checks */
295  int i;
296 
297  /* We need access to the index AM's API struct */
298  amroutine = GetIndexAmRoutineByAmId(accessMethodId, false);
299 
300  /* ... and to the table's tuple descriptor */
301  heapTupDesc = RelationGetDescr(heapRelation);
302  natts = RelationGetForm(heapRelation)->relnatts;
303 
304  /*
305  * allocate the new tuple descriptor
306  */
307  indexTupDesc = CreateTemplateTupleDesc(numatts);
308 
309  /*
310  * Fill in the pg_attribute row.
311  */
312  for (i = 0; i < numatts; i++)
313  {
314  AttrNumber atnum = indexInfo->ii_IndexAttrNumbers[i];
315  Form_pg_attribute to = TupleDescAttr(indexTupDesc, i);
316  HeapTuple tuple;
317  Form_pg_type typeTup;
318  Form_pg_opclass opclassTup;
319  Oid keyType;
320 
322  to->attnum = i + 1;
323  to->attcacheoff = -1;
324  to->attislocal = true;
325  to->attcollation = (i < numkeyatts) ? collationIds[i] : InvalidOid;
326 
327  /*
328  * Set the attribute name as specified by caller.
329  */
330  if (colnames_item == NULL) /* shouldn't happen */
331  elog(ERROR, "too few entries in colnames list");
332  namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
333  colnames_item = lnext(indexColNames, colnames_item);
334 
335  /*
336  * For simple index columns, we copy some pg_attribute fields from the
337  * parent relation. For expressions we have to look at the expression
338  * result.
339  */
340  if (atnum != 0)
341  {
342  /* Simple index column */
343  const FormData_pg_attribute *from;
344 
345  Assert(atnum > 0); /* should've been caught above */
346 
347  if (atnum > natts) /* safety check */
348  elog(ERROR, "invalid column number %d", atnum);
349  from = TupleDescAttr(heapTupDesc,
350  AttrNumberGetAttrOffset(atnum));
351 
352  to->atttypid = from->atttypid;
353  to->attlen = from->attlen;
354  to->attndims = from->attndims;
355  to->atttypmod = from->atttypmod;
356  to->attbyval = from->attbyval;
357  to->attalign = from->attalign;
358  to->attstorage = from->attstorage;
359  to->attcompression = from->attcompression;
360  }
361  else
362  {
363  /* Expressional index */
364  Node *indexkey;
365 
366  if (indexpr_item == NULL) /* shouldn't happen */
367  elog(ERROR, "too few entries in indexprs list");
368  indexkey = (Node *) lfirst(indexpr_item);
369  indexpr_item = lnext(indexInfo->ii_Expressions, indexpr_item);
370 
371  /*
372  * Lookup the expression type in pg_type for the type length etc.
373  */
374  keyType = exprType(indexkey);
375  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
376  if (!HeapTupleIsValid(tuple))
377  elog(ERROR, "cache lookup failed for type %u", keyType);
378  typeTup = (Form_pg_type) GETSTRUCT(tuple);
379 
380  /*
381  * Assign some of the attributes values. Leave the rest.
382  */
383  to->atttypid = keyType;
384  to->attlen = typeTup->typlen;
385  to->atttypmod = exprTypmod(indexkey);
386  to->attbyval = typeTup->typbyval;
387  to->attalign = typeTup->typalign;
388  to->attstorage = typeTup->typstorage;
389 
390  /*
391  * For expression columns, set attcompression invalid, since
392  * there's no table column from which to copy the value. Whenever
393  * we actually need to compress a value, we'll use whatever the
394  * current value of default_toast_compression is at that point in
395  * time.
396  */
397  to->attcompression = InvalidCompressionMethod;
398 
399  ReleaseSysCache(tuple);
400 
401  /*
402  * Make sure the expression yields a type that's safe to store in
403  * an index. We need this defense because we have index opclasses
404  * for pseudo-types such as "record", and the actually stored type
405  * had better be safe; eg, a named composite type is okay, an
406  * anonymous record type is not. The test is the same as for
407  * whether a table column is of a safe type (which is why we
408  * needn't check for the non-expression case).
409  */
410  CheckAttributeType(NameStr(to->attname),
411  to->atttypid, to->attcollation,
412  NIL, 0);
413  }
414 
415  /*
416  * We do not yet have the correct relation OID for the index, so just
417  * set it invalid for now. InitializeAttributeOids() will fix it
418  * later.
419  */
420  to->attrelid = InvalidOid;
421 
422  /*
423  * Check the opclass and index AM to see if either provides a keytype
424  * (overriding the attribute type). Opclass (if exists) takes
425  * precedence.
426  */
427  keyType = amroutine->amkeytype;
428 
429  if (i < indexInfo->ii_NumIndexKeyAttrs)
430  {
431  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassIds[i]));
432  if (!HeapTupleIsValid(tuple))
433  elog(ERROR, "cache lookup failed for opclass %u", opclassIds[i]);
434  opclassTup = (Form_pg_opclass) GETSTRUCT(tuple);
435  if (OidIsValid(opclassTup->opckeytype))
436  keyType = opclassTup->opckeytype;
437 
438  /*
439  * If keytype is specified as ANYELEMENT, and opcintype is
440  * ANYARRAY, then the attribute type must be an array (else it'd
441  * not have matched this opclass); use its element type.
442  *
443  * We could also allow ANYCOMPATIBLE/ANYCOMPATIBLEARRAY here, but
444  * there seems no need to do so; there's no reason to declare an
445  * opclass as taking ANYCOMPATIBLEARRAY rather than ANYARRAY.
446  */
447  if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID)
448  {
449  keyType = get_base_element_type(to->atttypid);
450  if (!OidIsValid(keyType))
451  elog(ERROR, "could not get element type of array type %u",
452  to->atttypid);
453  }
454 
455  ReleaseSysCache(tuple);
456  }
457 
458  /*
459  * If a key type different from the heap value is specified, update
460  * the type-related fields in the index tupdesc.
461  */
462  if (OidIsValid(keyType) && keyType != to->atttypid)
463  {
464  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
465  if (!HeapTupleIsValid(tuple))
466  elog(ERROR, "cache lookup failed for type %u", keyType);
467  typeTup = (Form_pg_type) GETSTRUCT(tuple);
468 
469  to->atttypid = keyType;
470  to->atttypmod = -1;
471  to->attlen = typeTup->typlen;
472  to->attbyval = typeTup->typbyval;
473  to->attalign = typeTup->typalign;
474  to->attstorage = typeTup->typstorage;
475  /* As above, use the default compression method in this case */
476  to->attcompression = InvalidCompressionMethod;
477 
478  ReleaseSysCache(tuple);
479  }
480  }
481 
482  pfree(amroutine);
483 
484  return indexTupDesc;
485 }
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
int16 AttrNumber
Definition: attnum.h:21
#define AttrNumberGetAttrOffset(attNum)
Definition: attnum.h:51
#define NameStr(name)
Definition: c.h:749
#define MemSet(start, val, len)
Definition: c.h:1023
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:548
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2832
void pfree(void *pointer)
Definition: mcxt.c:1521
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
FormData_pg_attribute
Definition: pg_attribute.h:193
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:201
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#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
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetForm(relation)
Definition: rel.h:499
Oid amkeytype
Definition: amapi.h:265
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define InvalidCompressionMethod
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References IndexAmRoutine::amkeytype, Assert, ATTRIBUTE_FIXED_PART_SIZE, AttrNumberGetAttrOffset, CheckAttributeType(), CreateTemplateTupleDesc(), elog, ERROR, exprType(), exprTypmod(), FormData_pg_attribute, get_base_element_type(), GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, i, if(), IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, InvalidCompressionMethod, InvalidOid, lfirst, list_head(), lnext(), MemSet, NameStr, namestrcpy(), NIL, ObjectIdGetDatum(), OidIsValid, pfree(), RelationGetDescr, RelationGetForm, ReleaseSysCache(), SearchSysCache1(), and TupleDescAttr.

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4193 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2731 of file index.c.

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

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

Referenced by build_index_value_desc(), 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 2953 of file index.c.

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

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

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

◆ index_check_primary_key()

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

Definition at line 201 of file index.c.

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

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

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1298 of file index.c.

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

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, IndexInfo::ii_WithoutOverlaps, index_close(), index_create(), INDEX_CREATE_CONCURRENT, INDEX_CREATE_SKIP_BUILD, index_open(), Int16GetDatum(), InvalidOid, InvalidRelFileNumber, NullableDatum::isnull, lappend(), make_ands_implicit(), makeIndexInfo(), NameStr, NIL, NoLock, ObjectIdGetDatum(), palloc0(), palloc0_array, pfree(), RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_rel, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCache2(), stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), TextDatumGetCString, TupleDescAttr, NullableDatum::value, int2vector::values, and oidvector::values.

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1821 of file index.c.

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

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

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

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

Definition at line 1550 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1883 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 724 of file index.c.

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

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

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

◆ index_drop()

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

Definition at line 2119 of file index.c.

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

References AccessExclusiveLock, Assert, CacheInvalidateRelcache(), CatalogTupleDelete(), CheckTableNotInUse(), CommitTransactionCommand(), LockRelId::dbId, DeleteAttributeTuples(), DeleteInheritsTuple(), DeleteRelationTuple(), elog, ereport, errcode(), errmsg(), ERROR, get_rel_persistence(), GetTopTransactionIdIfAny(), GetTransactionSnapshot(), HaveRegisteredOrActiveSnapshot(), 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(), PushActiveSnapshot(), 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 3454 of file index.c.

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

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().

◆ index_update_stats()

static void index_update_stats ( Relation  rel,
bool  hasindex,
double  reltuples 
)
static

Definition at line 2810 of file index.c.

2813 {
2814  Oid relid = RelationGetRelid(rel);
2815  Relation pg_class;
2816  ScanKeyData key[1];
2817  HeapTuple tuple;
2818  void *state;
2819  Form_pg_class rd_rel;
2820  bool dirty;
2821 
2822  /*
2823  * We always update the pg_class row using a non-transactional,
2824  * overwrite-in-place update. There are several reasons for this:
2825  *
2826  * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work.
2827  *
2828  * 2. We could be reindexing pg_class itself, in which case we can't move
2829  * its pg_class row because CatalogTupleInsert/CatalogTupleUpdate might
2830  * not know about all the indexes yet (see reindex_relation).
2831  *
2832  * 3. Because we execute CREATE INDEX with just share lock on the parent
2833  * rel (to allow concurrent index creations), an ordinary update could
2834  * suffer a tuple-concurrently-updated failure against another CREATE
2835  * INDEX committing at about the same time. We can avoid that by having
2836  * them both do nontransactional updates (we assume they will both be
2837  * trying to change the pg_class row to the same thing, so it doesn't
2838  * matter which goes first).
2839  *
2840  * It is safe to use a non-transactional update even though our
2841  * transaction could still fail before committing. Setting relhasindex
2842  * true is safe even if there are no indexes (VACUUM will eventually fix
2843  * it). And of course the new relpages and reltuples counts are correct
2844  * regardless. However, we don't want to change relpages (or
2845  * relallvisible) if the caller isn't providing an updated reltuples
2846  * count, because that would bollix the reltuples/relpages ratio which is
2847  * what's really important.
2848  */
2849 
2850  pg_class = table_open(RelationRelationId, RowExclusiveLock);
2851 
2852  ScanKeyInit(&key[0],
2853  Anum_pg_class_oid,
2854  BTEqualStrategyNumber, F_OIDEQ,
2855  ObjectIdGetDatum(relid));
2856  systable_inplace_update_begin(pg_class, ClassOidIndexId, true, NULL,
2857  1, key, &tuple, &state);
2858 
2859  if (!HeapTupleIsValid(tuple))
2860  elog(ERROR, "could not find tuple for relation %u", relid);
2861  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
2862 
2863  /* Should this be a more comprehensive test? */
2864  Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
2865 
2866  /*
2867  * As a special hack, if we are dealing with an empty table and the
2868  * existing reltuples is -1, we leave that alone. This ensures that
2869  * creating an index as part of CREATE TABLE doesn't cause the table to
2870  * prematurely look like it's been vacuumed.
2871  */
2872  if (reltuples == 0 && rd_rel->reltuples < 0)
2873  reltuples = -1;
2874 
2875  /* Apply required updates, if any, to copied tuple */
2876 
2877  dirty = false;
2878  if (rd_rel->relhasindex != hasindex)
2879  {
2880  rd_rel->relhasindex = hasindex;
2881  dirty = true;
2882  }
2883 
2884  /*
2885  * Avoid updating statistics during binary upgrade, because the indexes
2886  * are created before the data is moved into place.
2887  */
2888  if (reltuples >= 0 && !IsBinaryUpgrade)
2889  {
2890  BlockNumber relpages = RelationGetNumberOfBlocks(rel);
2891  BlockNumber relallvisible;
2892 
2893  if (rd_rel->relkind != RELKIND_INDEX)
2894  visibilitymap_count(rel, &relallvisible, NULL);
2895  else /* don't bother for indexes */
2896  relallvisible = 0;
2897 
2898  if (rd_rel->relpages != (int32) relpages)
2899  {
2900  rd_rel->relpages = (int32) relpages;
2901  dirty = true;
2902  }
2903  if (rd_rel->reltuples != (float4) reltuples)
2904  {
2905  rd_rel->reltuples = (float4) reltuples;
2906  dirty = true;
2907  }
2908  if (rd_rel->relallvisible != (int32) relallvisible)
2909  {
2910  rd_rel->relallvisible = (int32) relallvisible;
2911  dirty = true;
2912  }
2913  }
2914 
2915  /*
2916  * If anything changed, write out the tuple
2917  */
2918  if (dirty)
2919  {
2921  /* the above sends a cache inval message */
2922  }
2923  else
2924  {
2926  /* no need to change tuple, but force relcache inval anyway */
2928  }
2929 
2930  heap_freetuple(tuple);
2931 
2932  table_close(pg_class, RowExclusiveLock);
2933 }
uint32 BlockNumber
Definition: block.h:31
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:273
signed int int32
Definition: c.h:497
float float4
Definition: c.h:632
void systable_inplace_update_cancel(void *state)
Definition: genam.c:903
void systable_inplace_update_begin(Relation relation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, const ScanKeyData *key, HeapTuple *oldtupcopy, void **state)
Definition: genam.c:806
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition: genam.c:884
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1396
Definition: regguts.h:323
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)

References Assert, BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, IsBinaryUpgrade, sort-test::key, ObjectIdGetDatum(), RelationGetNumberOfBlocks, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), systable_inplace_update_begin(), systable_inplace_update_cancel(), systable_inplace_update_finish(), table_close(), table_open(), and visibilitymap_count().

Referenced by index_build(), and index_create().

◆ IndexCheckExclusion()

static void IndexCheckExclusion ( Relation  heapRelation,
Relation  indexRelation,
IndexInfo indexInfo 
)
static

Definition at line 3146 of file index.c.

3149 {
3150  TableScanDesc scan;
3152  bool isnull[INDEX_MAX_KEYS];
3153  ExprState *predicate;
3154  TupleTableSlot *slot;
3155  EState *estate;
3156  ExprContext *econtext;
3157  Snapshot snapshot;
3158 
3159  /*
3160  * If we are reindexing the target index, mark it as no longer being
3161  * reindexed, to forestall an Assert in index_beginscan when we try to use
3162  * the index for probes. This is OK because the index is now fully valid.
3163  */
3166 
3167  /*
3168  * Need an EState for evaluation of index expressions and partial-index
3169  * predicates. Also a slot to hold the current tuple.
3170  */
3171  estate = CreateExecutorState();
3172  econtext = GetPerTupleExprContext(estate);
3173  slot = table_slot_create(heapRelation, NULL);
3174 
3175  /* Arrange for econtext's scan tuple to be the tuple under test */
3176  econtext->ecxt_scantuple = slot;
3177 
3178  /* Set up execution state for predicate, if any. */
3179  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3180 
3181  /*
3182  * Scan all live tuples in the base relation.
3183  */
3184  snapshot = RegisterSnapshot(GetLatestSnapshot());
3185  scan = table_beginscan_strat(heapRelation, /* relation */
3186  snapshot, /* snapshot */
3187  0, /* number of keys */
3188  NULL, /* scan key */
3189  true, /* buffer access strategy OK */
3190  true); /* syncscan OK */
3191 
3192  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3193  {
3195 
3196  /*
3197  * In a partial index, ignore tuples that don't satisfy the predicate.
3198  */
3199  if (predicate != NULL)
3200  {
3201  if (!ExecQual(predicate, econtext))
3202  continue;
3203  }
3204 
3205  /*
3206  * Extract index column values, including computing expressions.
3207  */
3208  FormIndexDatum(indexInfo,
3209  slot,
3210  estate,
3211  values,
3212  isnull);
3213 
3214  /*
3215  * Check that this tuple has no conflicts.
3216  */
3217  check_exclusion_constraint(heapRelation,
3218  indexRelation, indexInfo,
3219  &(slot->tts_tid), values, isnull,
3220  estate, true);
3221 
3223  }
3224 
3225  table_endscan(scan);
3226  UnregisterSnapshot(snapshot);
3227 
3229 
3230  FreeExecutorState(estate);
3231 
3232  /* These may have been pointing to the now-gone estate */
3233  indexInfo->ii_ExpressionsState = NIL;
3234  indexInfo->ii_PredicateState = NULL;
3235 }
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:771
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex)
Definition: execIndexing.c:950
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void FreeExecutorState(EState *estate)
Definition: execUtils.c:191
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:424
static void ResetReindexProcessing(void)
Definition: index.c:4121
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition: index.c:4080
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2731
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:291
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:266
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:258
ExprState * ii_PredicateState
Definition: execnodes.h:192
ItemPointerData tts_tid
Definition: tuptable.h:129
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1019
static TableScanDesc table_beginscan_strat(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key, bool allow_strat, bool allow_sync)
Definition: tableam.h:932
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1055

References check_exclusion_constraint(), CHECK_FOR_INTERRUPTS, CreateExecutorState(), ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, ExecDropSingleTupleTableSlot(), ExecPrepareQual(), ExecQual(), FormIndexDatum(), ForwardScanDirection, FreeExecutorState(), GetLatestSnapshot(), GetPerTupleExprContext, IndexInfo::ii_ExpressionsState, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, INDEX_MAX_KEYS, MemoryContextReset(), NIL, RegisterSnapshot(), ReindexIsCurrentlyProcessingIndex(), RelationGetRelid, ResetReindexProcessing(), table_beginscan_strat(), table_endscan(), table_scan_getnextslot(), table_slot_create(), TupleTableSlot::tts_tid, UnregisterSnapshot(), and values.

Referenced by index_build().

◆ IndexGetRelation()

Oid IndexGetRelation ( Oid  indexId,
bool  missing_ok 
)

Definition at line 3534 of file index.c.

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

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().

◆ InitializeAttributeOids()

static void InitializeAttributeOids ( Relation  indexRelation,
int  numatts,
Oid  indexoid 
)
static

Definition at line 492 of file index.c.

495 {
496  TupleDesc tupleDescriptor;
497  int i;
498 
499  tupleDescriptor = RelationGetDescr(indexRelation);
500 
501  for (i = 0; i < numatts; i += 1)
502  TupleDescAttr(tupleDescriptor, i)->attrelid = indexoid;
503 }

References i, RelationGetDescr, and TupleDescAttr.

Referenced by index_create().

◆ reindex_index()

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

Definition at line 3559 of file index.c.

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

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

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

◆ reindex_relation()

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

Definition at line 3899 of file index.c.

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

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, RemoveReindexPending(), SetReindexPending(), ShareLock, stmt, table_close(), table_open(), ReindexParams::tablespaceOid, try_table_open(), and WARNING.

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

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4080 of file index.c.

4081 {
4082  return indexOid == currentlyReindexedIndex;
4083 }
static Oid currentlyReindexedIndex
Definition: index.c:4061

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4070 of file index.c.

4071 {
4072  return heapOid == currentlyReindexedHeap;
4073 }
static Oid currentlyReindexedHeap
Definition: index.c:4060

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4091 of file index.c.

4092 {
4093  return indexOid == currentlyReindexedIndex ||
4095 }
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().

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 147 of file index.c.

148 {
149  bool result = false;
150  List *indexoidlist;
151  ListCell *indexoidscan;
152 
153  /*
154  * Get the list of index OIDs for the table from the relcache, and look up
155  * each one in the pg_index syscache until we find one marked primary key
156  * (hopefully there isn't more than one such).
157  */
158  indexoidlist = RelationGetIndexList(rel);
159 
160  foreach(indexoidscan, indexoidlist)
161  {
162  Oid indexoid = lfirst_oid(indexoidscan);
163  HeapTuple indexTuple;
164 
165  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
166  if (!HeapTupleIsValid(indexTuple)) /* should not happen */
167  elog(ERROR, "cache lookup failed for index %u", indexoid);
168  result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary;
169  ReleaseSysCache(indexTuple);
170  if (result)
171  break;
172  }
173 
174  list_free(indexoidlist);
175 
176  return result;
177 }

References elog, ERROR, GETSTRUCT, HeapTupleIsValid, lfirst_oid, list_free(), ObjectIdGetDatum(), RelationGetIndexList(), ReleaseSysCache(), and SearchSysCache1().

Referenced by index_check_primary_key().

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4151 of file index.c.

4152 {
4153  if (IsInParallelMode())
4154  elog(ERROR, "cannot modify reindex state during a parallel operation");
4156  indexOid);
4157 }
List * list_delete_oid(List *list, Oid datum)
Definition: list.c:910
bool IsInParallelMode(void)
Definition: xact.c:1088

References elog, ERROR, IsInParallelMode(), list_delete_oid(), and pendingReindexedIndexes.

Referenced by reindex_relation(), and SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4121 of file index.c.

4122 {
4125  /* reindexingNestLevel remains set till end of (sub)transaction */
4126 }

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4164 of file index.c.

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

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4222 of file index.c.

4223 {
4224  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4225  int c = 0;
4226  MemoryContext oldcontext;
4227 
4230 
4233  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4236  sistate->pendingReindexedIndexes[c]);
4237  MemoryContextSwitchTo(oldcontext);
4238 
4239  /* Note the worker has its own transaction nesting level */
4241 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * c
MemoryContextSwitchTo(old_ctx)
Oid currentlyReindexedHeap
Definition: index.c:94
Oid currentlyReindexedIndex
Definition: index.c:95
int numPendingReindexedIndexes
Definition: index.c:96
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:97
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:928

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()

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4135 of file index.c.

4136 {
4137  /* Reindexing is not re-entrant. */
4139  elog(ERROR, "cannot reindex while reindexing");
4140  if (IsInParallelMode())
4141  elog(ERROR, "cannot modify reindex state during a parallel operation");
4144 }
List * list_copy(const List *oldlist)
Definition: list.c:1573

References elog, ERROR, GetCurrentTransactionNestLevel(), IsInParallelMode(), list_copy(), pendingReindexedIndexes, and reindexingNestLevel.

Referenced by reindex_relation().

◆ SetReindexProcessing()

static void SetReindexProcessing ( Oid  heapOid,
Oid  indexOid 
)
static

Definition at line 4102 of file index.c.

4103 {
4104  Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4105  /* Reindexing is not re-entrant. */
4107  elog(ERROR, "cannot reindex while reindexing");
4108  currentlyReindexedHeap = heapOid;
4109  currentlyReindexedIndex = indexOid;
4110  /* Index is no longer "pending" reindex. */
4111  RemoveReindexPending(indexOid);
4112  /* This may have been set already, but in case it isn't, do so now. */
4114 }

References Assert, currentlyReindexedHeap, currentlyReindexedIndex, elog, ERROR, GetCurrentTransactionNestLevel(), OidIsValid, reindexingNestLevel, and RemoveReindexPending().

Referenced by reindex_index().

◆ UpdateIndexRelation()

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 
)
static

Definition at line 561 of file index.c.

573 {
574  int2vector *indkey;
575  oidvector *indcollation;
576  oidvector *indclass;
577  int2vector *indoption;
578  Datum exprsDatum;
579  Datum predDatum;
580  Datum values[Natts_pg_index];
581  bool nulls[Natts_pg_index] = {0};
582  Relation pg_index;
583  HeapTuple tuple;
584  int i;
585 
586  /*
587  * Copy the index key, opclass, and indoption info into arrays (should we
588  * make the caller pass them like this to start with?)
589  */
590  indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs);
591  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
592  indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i];
593  indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs);
594  indclass = buildoidvector(opclassOids, indexInfo->ii_NumIndexKeyAttrs);
595  indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexKeyAttrs);
596 
597  /*
598  * Convert the index expressions (if any) to a text datum
599  */
600  if (indexInfo->ii_Expressions != NIL)
601  {
602  char *exprsString;
603 
604  exprsString = nodeToString(indexInfo->ii_Expressions);
605  exprsDatum = CStringGetTextDatum(exprsString);
606  pfree(exprsString);
607  }
608  else
609  exprsDatum = (Datum) 0;
610 
611  /*
612  * Convert the index predicate (if any) to a text datum. Note we convert
613  * implicit-AND format to normal explicit-AND for storage.
614  */
615  if (indexInfo->ii_Predicate != NIL)
616  {
617  char *predString;
618 
619  predString = nodeToString(make_ands_explicit(indexInfo->ii_Predicate));
620  predDatum = CStringGetTextDatum(predString);
621  pfree(predString);
622  }
623  else
624  predDatum = (Datum) 0;
625 
626 
627  /*
628  * open the system catalog index relation
629  */
630  pg_index = table_open(IndexRelationId, RowExclusiveLock);
631 
632  /*
633  * Build a pg_index tuple
634  */
635  values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid);
636  values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid);
637  values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs);
638  values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs);
639  values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique);
640  values[Anum_pg_index_indnullsnotdistinct - 1] = BoolGetDatum(indexInfo->ii_NullsNotDistinct);
641  values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary);
642  values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion);
643  values[Anum_pg_index_indimmediate - 1] = BoolGetDatum(immediate);
644  values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false);
645  values[Anum_pg_index_indisvalid - 1] = BoolGetDatum(isvalid);
646  values[Anum_pg_index_indcheckxmin - 1] = BoolGetDatum(false);
647  values[Anum_pg_index_indisready - 1] = BoolGetDatum(isready);
648  values[Anum_pg_index_indislive - 1] = BoolGetDatum(true);
649  values[Anum_pg_index_indisreplident - 1] = BoolGetDatum(false);
650  values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey);
651  values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation);
652  values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
653  values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
654  values[Anum_pg_index_indexprs - 1] = exprsDatum;
655  if (exprsDatum == (Datum) 0)
656  nulls[Anum_pg_index_indexprs - 1] = true;
657  values[Anum_pg_index_indpred - 1] = predDatum;
658  if (predDatum == (Datum) 0)
659  nulls[Anum_pg_index_indpred - 1] = true;
660 
661  tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls);
662 
663  /*
664  * insert the tuple into the pg_index catalog
665  */
666  CatalogTupleInsert(pg_index, tuple);
667 
668  /*
669  * close the relation and free the tuple
670  */
671  table_close(pg_index, RowExclusiveLock);
672  heap_freetuple(tuple);
673 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:726
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102

References BoolGetDatum(), buildint2vector(), buildoidvector(), CatalogTupleInsert(), CStringGetTextDatum, heap_form_tuple(), heap_freetuple(), i, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NullsNotDistinct, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, Int16GetDatum(), make_ands_explicit(), NIL, nodeToString(), ObjectIdGetDatum(), pfree(), PointerGetDatum(), RelationGetDescr, RowExclusiveLock, table_close(), table_open(), int2vector::values, and values.

Referenced by index_create().

◆ validate_index()

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

Definition at line 3301 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

static bool validate_index_callback ( ItemPointer  itemptr,
void *  opaque 
)
static

Definition at line 3434 of file index.c.

3435 {
3437  int64 encoded = itemptr_encode(itemptr);
3438 
3439  tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3440  state->itups += 1;
3441  return false; /* never actually delete anything */
3442 }
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
static int64 itemptr_encode(ItemPointer itemptr)
Definition: index.h:190
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)

References Int64GetDatum(), itemptr_encode(), and tuplesort_putdatum().

Referenced by validate_index().

Variable Documentation

◆ binary_upgrade_next_index_pg_class_oid

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid

Definition at line 84 of file index.c.

Referenced by binary_upgrade_set_next_index_pg_class_oid(), and index_create().

◆ binary_upgrade_next_index_pg_class_relfilenumber

RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber

◆ currentlyReindexedHeap

◆ currentlyReindexedIndex

◆ pendingReindexedIndexes

◆ reindexingNestLevel

int reindexingNestLevel = 0
static