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/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.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_depend.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/tablespace.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/procarray.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)
 
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, 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 
)
static

Definition at line 516 of file index.c.

517 {
518  Relation pg_attribute;
519  CatalogIndexState indstate;
520  TupleDesc indexTupDesc;
521 
522  /*
523  * open the attribute relation and its indexes
524  */
525  pg_attribute = table_open(AttributeRelationId, RowExclusiveLock);
526 
527  indstate = CatalogOpenIndexes(pg_attribute);
528 
529  /*
530  * insert data from new index's tupdesc into pg_attribute
531  */
532  indexTupDesc = RelationGetDescr(indexRelation);
533 
534  InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid, attopts, indstate);
535 
536  CatalogCloseIndexes(indstate);
537 
538  table_close(pg_attribute, RowExclusiveLock);
539 }
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:697
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationGetDescr(relation)
Definition: rel.h:530
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References CatalogCloseIndexes(), CatalogOpenIndexes(), InsertPgAttributeTuples(), InvalidOid, RelationGetDescr, RowExclusiveLock, table_close(), and table_open().

Referenced by index_create().

◆ BuildDummyIndexInfo()

IndexInfo* BuildDummyIndexInfo ( Relation  index)

Definition at line 2484 of file index.c.

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

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

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo* BuildIndexInfo ( Relation  index)

Definition at line 2425 of file index.c.

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

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

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

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2663 of file index.c.

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

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

Referenced by ExecOpenIndices().

◆ CompareIndexInfo()

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

Definition at line 2532 of file index.c.

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

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

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

◆ ConstructTupleDescriptor()

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

Definition at line 285 of file index.c.

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

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4160 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2723 of file index.c.

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

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

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

◆ index_build()

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

Definition at line 2959 of file index.c.

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

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

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

◆ index_check_primary_key()

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

Definition at line 206 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1448 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1283 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1841 of file index.c.

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

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

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

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1902 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 711 of file index.c.

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

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

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

◆ index_drop()

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

Definition at line 2135 of file index.c.

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

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

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3456 of file index.c.

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

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

◆ index_update_stats()

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

Definition at line 2802 of file index.c.

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

References Assert(), BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), elog(), ERROR, ForwardScanDirection, GETSTRUCT, heap_copytuple(), heap_freetuple(), heap_getnext(), heap_inplace_update(), HeapTupleIsValid, IsBootstrapProcessingMode, sort-test::key, ObjectIdGetDatum(), ReindexIsProcessingHeap(), RelationGetNumberOfBlocks, RelationGetRelid, RELOID, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, table_beginscan_catalog(), table_close(), table_endscan(), 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 3151 of file index.c.

3154 {
3155  TableScanDesc scan;
3157  bool isnull[INDEX_MAX_KEYS];
3158  ExprState *predicate;
3159  TupleTableSlot *slot;
3160  EState *estate;
3161  ExprContext *econtext;
3162  Snapshot snapshot;
3163 
3164  /*
3165  * If we are reindexing the target index, mark it as no longer being
3166  * reindexed, to forestall an Assert in index_beginscan when we try to use
3167  * the index for probes. This is OK because the index is now fully valid.
3168  */
3171 
3172  /*
3173  * Need an EState for evaluation of index expressions and partial-index
3174  * predicates. Also a slot to hold the current tuple.
3175  */
3176  estate = CreateExecutorState();
3177  econtext = GetPerTupleExprContext(estate);
3178  slot = table_slot_create(heapRelation, NULL);
3179 
3180  /* Arrange for econtext's scan tuple to be the tuple under test */
3181  econtext->ecxt_scantuple = slot;
3182 
3183  /* Set up execution state for predicate, if any. */
3184  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3185 
3186  /*
3187  * Scan all live tuples in the base relation.
3188  */
3189  snapshot = RegisterSnapshot(GetLatestSnapshot());
3190  scan = table_beginscan_strat(heapRelation, /* relation */
3191  snapshot, /* snapshot */
3192  0, /* number of keys */
3193  NULL, /* scan key */
3194  true, /* buffer access strategy OK */
3195  true); /* syncscan OK */
3196 
3197  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3198  {
3200 
3201  /*
3202  * In a partial index, ignore tuples that don't satisfy the predicate.
3203  */
3204  if (predicate != NULL)
3205  {
3206  if (!ExecQual(predicate, econtext))
3207  continue;
3208  }
3209 
3210  /*
3211  * Extract index column values, including computing expressions.
3212  */
3213  FormIndexDatum(indexInfo,
3214  slot,
3215  estate,
3216  values,
3217  isnull);
3218 
3219  /*
3220  * Check that this tuple has no conflicts.
3221  */
3222  check_exclusion_constraint(heapRelation,
3223  indexRelation, indexInfo,
3224  &(slot->tts_tid), values, isnull,
3225  estate, true);
3226 
3228  }
3229 
3230  table_endscan(scan);
3231  UnregisterSnapshot(snapshot);
3232 
3234 
3235  FreeExecutorState(estate);
3236 
3237  /* These may have been pointing to the now-gone estate */
3238  indexInfo->ii_ExpressionsState = NIL;
3239  indexInfo->ii_PredicateState = NULL;
3240 }
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:764
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:915
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1253
EState * CreateExecutorState(void)
Definition: execUtils.c:93
void FreeExecutorState(EState *estate)
Definition: execUtils.c:194
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:412
static void ResetReindexProcessing(void)
Definition: index.c:4088
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition: index.c:4047
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2723
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:330
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:298
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:843
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:801
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:256
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:248
ExprState * ii_PredicateState
Definition: execnodes.h:183
ItemPointerData tts_tid
Definition: tuptable.h:129
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static TableScanDesc table_beginscan_strat(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key, bool allow_strat, bool allow_sync)
Definition: tableam.h:925
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1050

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

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

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

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

◆ InitializeAttributeOids()

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

Definition at line 498 of file index.c.

501 {
502  TupleDesc tupleDescriptor;
503  int i;
504 
505  tupleDescriptor = RelationGetDescr(indexRelation);
506 
507  for (i = 0; i < numatts; i += 1)
508  TupleDescAttr(tupleDescriptor, i)->attrelid = indexoid;
509 }

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

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

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(), INDEXRELID, INFO, InvalidObjectAddress, InvalidOid, IsSystemRelation(), IsToastNamespace(), NewGUCNestLevel(), NoLock, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, ReindexParams::options, pg_rusage_init(), pg_rusage_show(), pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), progress, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_REINDEX, PROGRESS_CREATEIDX_INDEX_OID, RelationData::rd_rel, REINDEXOPT_MISSING_OK, REINDEXOPT_REPORT_PROGRESS, REINDEXOPT_VERBOSE, RELATION_IS_OTHER_TEMP, RelationAssumeNewRelfilelocator(), RelationDropStorage(), RelationGetNamespace, RelationGetRelationName, RelationSetNewRelfilenumber(), ResetReindexProcessing(), RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetReindexProcessing(), SetRelationTableSpace(), SetUserIdAndSecContext(), ShareLock, stmt, HeapTupleData::t_self, table_close(), table_open(), ReindexParams::tablespaceOid, TransferPredicateLocksToHeapRelation(), 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 3883 of file index.c.

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

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

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

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4047 of file index.c.

4048 {
4049  return indexOid == currentlyReindexedIndex;
4050 }
static Oid currentlyReindexedIndex
Definition: index.c:4028

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4037 of file index.c.

4038 {
4039  return heapOid == currentlyReindexedHeap;
4040 }
static Oid currentlyReindexedHeap
Definition: index.c:4027

References currentlyReindexedHeap.

Referenced by index_update_stats().

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4058 of file index.c.

4059 {
4060  return indexOid == currentlyReindexedIndex ||
4062 }
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721

References currentlyReindexedIndex, list_member_oid(), and pendingReindexedIndexes.

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

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 152 of file index.c.

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

References elog(), ERROR, GETSTRUCT, HeapTupleIsValid, INDEXRELID, 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 4118 of file index.c.

4119 {
4120  if (IsInParallelMode())
4121  elog(ERROR, "cannot modify reindex state during a parallel operation");
4123  indexOid);
4124 }
List * list_delete_oid(List *list, Oid datum)
Definition: list.c:909
bool IsInParallelMode(void)
Definition: xact.c:1069

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

Referenced by SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4088 of file index.c.

4089 {
4092  /* reindexingNestLevel remains set till end of (sub)transaction */
4093 }

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4131 of file index.c.

4132 {
4133  /*
4134  * Because reindexing is not re-entrant, we don't need to cope with nested
4135  * reindexing states. We just need to avoid messing up the outer-level
4136  * state in case a subtransaction fails within a REINDEX. So checking the
4137  * current nest level against that of the reindex operation is sufficient.
4138  */
4139  if (reindexingNestLevel >= nestLevel)
4140  {
4143 
4144  /*
4145  * We needn't try to release the contents of pendingReindexedIndexes;
4146  * that list should be in a transaction-lifespan context, so it will
4147  * go away automatically.
4148  */
4150 
4151  reindexingNestLevel = 0;
4152  }
4153 }
static int reindexingNestLevel
Definition: index.c:4030

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4189 of file index.c.

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

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4102 of file index.c.

4103 {
4104  /* Reindexing is not re-entrant. */
4106  elog(ERROR, "cannot reindex while reindexing");
4107  if (IsInParallelMode())
4108  elog(ERROR, "cannot modify reindex state during a parallel operation");
4111 }
List * list_copy(const List *oldlist)
Definition: list.c:1572

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

4070 {
4071  Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4072  /* Reindexing is not re-entrant. */
4074  elog(ERROR, "cannot reindex while reindexing");
4075  currentlyReindexedHeap = heapOid;
4076  currentlyReindexedIndex = indexOid;
4077  /* Index is no longer "pending" reindex. */
4078  RemoveReindexPending(indexOid);
4079  /* This may have been set already, but in case it isn't, do so now. */
4081 }
static void RemoveReindexPending(Oid indexOid)
Definition: index.c:4118

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

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

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

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

Definition at line 3436 of file index.c.

3437 {
3439  int64 encoded = itemptr_encode(itemptr);
3440 
3441  tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3442  state->itups += 1;
3443  return false; /* never actually delete anything */
3444 }
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
static int64 itemptr_encode(ItemPointer itemptr)
Definition: index.h:188
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 89 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