PostgreSQL Source Code  git master
index.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/amapi.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/reloptions.h"
#include "access/sysattr.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/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
#include "parser/parser.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/syscache.h"
#include "utils/tuplesort.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
Include dependency graph for index.c:

Go to the source code of this file.

Data Structures

struct  v_i_state
 
struct  SerializedReindexState
 

Functions

static bool relationHasPrimaryKey (Relation rel)
 
static TupleDesc ConstructTupleDescriptor (Relation heapRelation, IndexInfo *indexInfo, List *indexColNames, Oid accessMethodObjectId, Oid *collationObjectId, Oid *classObjectId)
 
static void InitializeAttributeOids (Relation indexRelation, int numatts, Oid indexoid)
 
static void AppendAttributeTuples (Relation indexRelation, int numatts)
 
static void UpdateIndexRelation (Oid indexoid, Oid heapoid, Oid parentIndexId, IndexInfo *indexInfo, Oid *collationOids, Oid *classOids, 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 int64 itemptr_encode (ItemPointer itemptr)
 
static void itemptr_decode (ItemPointer itemptr, int64 encoded)
 
static bool validate_index_callback (ItemPointer itemptr, void *opaque)
 
static void validate_index_heapscan (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, Snapshot snapshot, v_i_state *state)
 
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)
 
static void ResetReindexPending (void)
 
void index_check_primary_key (Relation heapRel, IndexInfo *indexInfo, bool is_alter_table)
 
Oid index_create (Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, Oid relFileNode, IndexInfo *indexInfo, List *indexColNames, Oid accessMethodObjectId, Oid tableSpaceId, Oid *collationObjectId, Oid *classObjectId, int16 *coloptions, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
 
ObjectAddress index_constraint_create (Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, 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)
 
IndexInfoBuildIndexInfo (Relation index)
 
bool CompareIndexInfo (IndexInfo *info1, IndexInfo *info2, Oid *collations1, Oid *collations2, Oid *opfamilies1, Oid *opfamilies2, AttrNumber *attmap, int maplen)
 
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 isprimary, bool isreindex, bool parallel)
 
double IndexBuildHeapScan (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, IndexBuildCallback callback, void *callback_state, HeapScanDesc scan)
 
double IndexBuildHeapRangeScan (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, bool anyvisible, BlockNumber start_blockno, BlockNumber numblocks, IndexBuildCallback callback, void *callback_state, HeapScanDesc scan)
 
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 (Oid indexId, bool skip_constraint_checks, char persistence, int options)
 
bool reindex_relation (Oid relid, int flags, int options)
 
bool ReindexIsProcessingHeap (Oid heapOid)
 
bool ReindexIsProcessingIndex (Oid indexOid)
 
Size EstimateReindexStateSpace (void)
 
void SerializeReindexState (Size maxsize, char *start_address)
 
void RestoreReindexState (void *reindexstate)
 

Variables

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid
 
static Oid currentlyReindexedHeap = InvalidOid
 
static Oid currentlyReindexedIndex = InvalidOid
 
static ListpendingReindexedIndexes = NIL
 

Function Documentation

◆ AppendAttributeTuples()

static void AppendAttributeTuples ( Relation  indexRelation,
int  numatts 
)
static

Definition at line 537 of file index.c.

References Assert, CatalogCloseIndexes(), CatalogOpenIndexes(), heap_close, heap_open(), i, InsertPgAttributeTuple(), RelationGetDescr, RowExclusiveLock, and TupleDescAttr.

Referenced by index_create().

538 {
539  Relation pg_attribute;
540  CatalogIndexState indstate;
541  TupleDesc indexTupDesc;
542  int i;
543 
544  /*
545  * open the attribute relation and its indexes
546  */
547  pg_attribute = heap_open(AttributeRelationId, RowExclusiveLock);
548 
549  indstate = CatalogOpenIndexes(pg_attribute);
550 
551  /*
552  * insert data from new index's tupdesc into pg_attribute
553  */
554  indexTupDesc = RelationGetDescr(indexRelation);
555 
556  for (i = 0; i < numatts; i++)
557  {
558  Form_pg_attribute attr = TupleDescAttr(indexTupDesc, i);
559 
560  /*
561  * There used to be very grotty code here to set these fields, but I
562  * think it's unnecessary. They should be set already.
563  */
564  Assert(attr->attnum == i + 1);
565  Assert(attr->attcacheoff == -1);
566 
567  InsertPgAttributeTuple(pg_attribute, attr, indstate);
568  }
569 
570  CatalogCloseIndexes(indstate);
571 
572  heap_close(pg_attribute, RowExclusiveLock);
573 }
#define RelationGetDescr(relation)
Definition: rel.h:433
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define heap_close(r, l)
Definition: heapam.h:97
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define Assert(condition)
Definition: c.h:699
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:40
void InsertPgAttributeTuple(Relation pg_attribute_rel, Form_pg_attribute new_attribute, CatalogIndexState indstate)
Definition: heap.c:604
int i
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:58

◆ BuildIndexInfo()

IndexInfo* BuildIndexInfo ( Relation  index)

Definition at line 1745 of file index.c.

References Assert, CurrentMemoryContext, elog, ERROR, i, IndexInfo::ii_Am, IndexInfo::ii_AmCache, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_Context, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_ParallelWorkers, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, IndexInfo::ii_UniqueOps, IndexInfo::ii_UniqueProcs, IndexInfo::ii_UniqueStrats, INDEX_MAX_KEYS, IndexIsReady, makeNode, NIL, RelationData::rd_index, RelationData::rd_rel, RelationGetExclusionInfo(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), and RelationGetRelid.

Referenced by _bt_parallel_scan_and_sort(), ATExecAddIndexConstraint(), ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), brinsummarize(), bt_check_every_level(), DefineIndex(), do_analyze_rel(), ExecOpenIndices(), get_actual_variable_range(), ProjIndexIsUnchanged(), reindex_index(), RelationGetIndexAttrBitmap(), RelationTruncateIndexes(), tuplesort_begin_cluster(), unique_key_recheck(), and validate_index().

1746 {
1747  IndexInfo *ii = makeNode(IndexInfo);
1748  Form_pg_index indexStruct = index->rd_index;
1749  int i;
1750  int numAtts;
1751 
1752  /* check the number of keys, and copy attr numbers into the IndexInfo */
1753  numAtts = indexStruct->indnatts;
1754  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
1755  elog(ERROR, "invalid indnatts %d for index %u",
1756  numAtts, RelationGetRelid(index));
1757  ii->ii_NumIndexAttrs = numAtts;
1758  ii->ii_NumIndexKeyAttrs = indexStruct->indnkeyatts;
1759  Assert(ii->ii_NumIndexKeyAttrs != 0);
1761 
1762  for (i = 0; i < numAtts; i++)
1763  ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
1764 
1765  /* fetch any expressions needed for expressional indexes */
1767  ii->ii_ExpressionsState = NIL;
1768 
1769  /* fetch index predicate if any */
1771  ii->ii_PredicateState = NULL;
1772 
1773  /* fetch exclusion constraint info if any */
1774  if (indexStruct->indisexclusion)
1775  {
1777  &ii->ii_ExclusionOps,
1778  &ii->ii_ExclusionProcs,
1779  &ii->ii_ExclusionStrats);
1780  }
1781  else
1782  {
1783  ii->ii_ExclusionOps = NULL;
1784  ii->ii_ExclusionProcs = NULL;
1785  ii->ii_ExclusionStrats = NULL;
1786  }
1787 
1788  /* other info */
1789  ii->ii_Unique = indexStruct->indisunique;
1790  ii->ii_ReadyForInserts = IndexIsReady(indexStruct);
1791  /* assume not doing speculative insertion for now */
1792  ii->ii_UniqueOps = NULL;
1793  ii->ii_UniqueProcs = NULL;
1794  ii->ii_UniqueStrats = NULL;
1795 
1796  /* initialize index-build state to default */
1797  ii->ii_Concurrent = false;
1798  ii->ii_BrokenHotChain = false;
1799  ii->ii_ParallelWorkers = 0;
1800 
1801  /* set up for possible use by index AM */
1802  ii->ii_Am = index->rd_rel->relam;
1803  ii->ii_AmCache = NULL;
1805 
1806  return ii;
1807 }
#define NIL
Definition: pg_list.h:69
MemoryContext ii_Context
Definition: execnodes.h:171
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5000
uint16 * ii_UniqueStrats
Definition: execnodes.h:163
List * ii_Predicate
Definition: execnodes.h:156
#define IndexIsReady(indexForm)
Definition: pg_index.h:86
ExprState * ii_PredicateState
Definition: execnodes.h:157
Oid * ii_ExclusionProcs
Definition: execnodes.h:159
Form_pg_class rd_rel
Definition: rel.h:84
Oid * ii_UniqueOps
Definition: execnodes.h:161
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:4608
List * ii_ExpressionsState
Definition: execnodes.h:155
Form_pg_index rd_index
Definition: rel.h:131
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4546
Oid * ii_UniqueProcs
Definition: execnodes.h:162
bool ii_BrokenHotChain
Definition: execnodes.h:167
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
bool ii_ReadyForInserts
Definition: execnodes.h:165
void * ii_AmCache
Definition: execnodes.h:170
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
int ii_NumIndexAttrs
Definition: execnodes.h:151
bool ii_Unique
Definition: execnodes.h:164
#define makeNode(_type_)
Definition: nodes.h:565
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
#define INDEX_MAX_KEYS
int ii_ParallelWorkers
Definition: execnodes.h:168
bool ii_Concurrent
Definition: execnodes.h:166
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int i
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
uint16 * ii_ExclusionStrats
Definition: execnodes.h:160
#define RelationGetRelid(relation)
Definition: rel.h:407
Oid ii_Am
Definition: execnodes.h:169

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 1940 of file index.c.

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, palloc(), RelationData::rd_opcintype, RelationData::rd_opfamily, and RelationData::rd_rel.

Referenced by ExecOpenIndices().

1941 {
1942  int indnkeyatts;
1943  int i;
1944 
1945  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
1946 
1947  /*
1948  * fetch info for checking unique indexes
1949  */
1950  Assert(ii->ii_Unique);
1951 
1952  if (index->rd_rel->relam != BTREE_AM_OID)
1953  elog(ERROR, "unexpected non-btree speculative unique index");
1954 
1955  ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
1956  ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
1957  ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
1958 
1959  /*
1960  * We have to look up the operator's strategy number. This provides a
1961  * cross-check that the operator does match the index.
1962  */
1963  /* We need the func OIDs and strategy numbers too */
1964  for (i = 0; i < indnkeyatts; i++)
1965  {
1967  ii->ii_UniqueOps[i] =
1968  get_opfamily_member(index->rd_opfamily[i],
1969  index->rd_opcintype[i],
1970  index->rd_opcintype[i],
1971  ii->ii_UniqueStrats[i]);
1972  if (!OidIsValid(ii->ii_UniqueOps[i]))
1973  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
1974  ii->ii_UniqueStrats[i], index->rd_opcintype[i],
1975  index->rd_opcintype[i], index->rd_opfamily[i]);
1976  ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
1977  }
1978 }
uint16 * ii_UniqueStrats
Definition: execnodes.h:163
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid * ii_UniqueOps
Definition: execnodes.h:161
unsigned short uint16
Definition: c.h:324
#define ERROR
Definition: elog.h:43
Oid * ii_UniqueProcs
Definition: execnodes.h:162
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
Oid * rd_opfamily
Definition: rel.h:154
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:426
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079
bool ii_Unique
Definition: execnodes.h:164
#define Assert(condition)
Definition: c.h:699
void * palloc(Size size)
Definition: mcxt.c:924
int i
#define elog
Definition: elog.h:219
Oid * rd_opcintype
Definition: rel.h:155
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ CompareIndexInfo()

bool CompareIndexInfo ( IndexInfo info1,
IndexInfo info2,
Oid collations1,
Oid collations2,
Oid opfamilies1,
Oid opfamilies2,
AttrNumber attmap,
int  maplen 
)

Definition at line 1820 of file index.c.

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

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

1824 {
1825  int i;
1826 
1827  if (info1->ii_Unique != info2->ii_Unique)
1828  return false;
1829 
1830  /* indexes are only equivalent if they have the same access method */
1831  if (info1->ii_Am != info2->ii_Am)
1832  return false;
1833 
1834  /* and same number of attributes */
1835  if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs)
1836  return false;
1837 
1838  /* and same number of key attributes */
1839  if (info1->ii_NumIndexKeyAttrs != info2->ii_NumIndexKeyAttrs)
1840  return false;
1841 
1842 
1843  /*
1844  * and columns match through the attribute map (actual attribute numbers
1845  * might differ!) Note that this implies that index columns that are
1846  * expressions appear in the same positions. We will next compare the
1847  * expressions themselves.
1848  */
1849  for (i = 0; i < info1->ii_NumIndexAttrs; i++)
1850  {
1851  if (maplen < info2->ii_IndexAttrNumbers[i])
1852  elog(ERROR, "incorrect attribute map");
1853 
1854  /* ignore expressions at this stage */
1855  if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) &&
1856  (attmap[info2->ii_IndexAttrNumbers[i] - 1] !=
1857  info1->ii_IndexAttrNumbers[i]))
1858  return false;
1859 
1860  /* collation and opfamily is not valid for including columns */
1861  if (i >= info1->ii_NumIndexKeyAttrs)
1862  continue;
1863 
1864  if (collations1[i] != collations2[i])
1865  return false;
1866  if (opfamilies1[i] != opfamilies2[i])
1867  return false;
1868  }
1869 
1870  /*
1871  * For expression indexes: either both are expression indexes, or neither
1872  * is; if they are, make sure the expressions match.
1873  */
1874  if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
1875  return false;
1876  if (info1->ii_Expressions != NIL)
1877  {
1878  bool found_whole_row;
1879  Node *mapped;
1880 
1881  mapped = map_variable_attnos((Node *) info2->ii_Expressions,
1882  1, 0, attmap, maplen,
1883  InvalidOid, &found_whole_row);
1884  if (found_whole_row)
1885  {
1886  /*
1887  * we could throw an error here, but seems out of scope for this
1888  * routine.
1889  */
1890  return false;
1891  }
1892 
1893  if (!equal(info1->ii_Expressions, mapped))
1894  return false;
1895  }
1896 
1897  /* Partial index predicates must be identical, if they exist */
1898  if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL))
1899  return false;
1900  if (info1->ii_Predicate != NULL)
1901  {
1902  bool found_whole_row;
1903  Node *mapped;
1904 
1905  mapped = map_variable_attnos((Node *) info2->ii_Predicate,
1906  1, 0, attmap, maplen,
1907  InvalidOid, &found_whole_row);
1908  if (found_whole_row)
1909  {
1910  /*
1911  * we could throw an error here, but seems out of scope for this
1912  * routine.
1913  */
1914  return false;
1915  }
1916  if (!equal(info1->ii_Predicate, mapped))
1917  return false;
1918  }
1919 
1920  /* No support currently for comparing exclusion indexes. */
1921  if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL)
1922  return false;
1923 
1924  return true;
1925 }
#define NIL
Definition: pg_list.h:69
List * ii_Predicate
Definition: execnodes.h:156
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2986
Definition: nodes.h:517
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
int ii_NumIndexAttrs
Definition: execnodes.h:151
#define InvalidOid
Definition: postgres_ext.h:36
bool ii_Unique
Definition: execnodes.h:164
List * ii_Expressions
Definition: execnodes.h:154
#define InvalidAttrNumber
Definition: attnum.h:23
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int i
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
Oid ii_Am
Definition: execnodes.h:169

◆ ConstructTupleDescriptor()

static TupleDesc ConstructTupleDescriptor ( Relation  heapRelation,
IndexInfo indexInfo,
List indexColNames,
Oid  accessMethodObjectId,
Oid collationObjectId,
Oid classObjectId 
)
static

Definition at line 292 of file index.c.

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

Referenced by index_create().

298 {
299  int numatts = indexInfo->ii_NumIndexAttrs;
300  int numkeyatts = indexInfo->ii_NumIndexKeyAttrs;
301  ListCell *colnames_item = list_head(indexColNames);
302  ListCell *indexpr_item = list_head(indexInfo->ii_Expressions);
303  IndexAmRoutine *amroutine;
304  TupleDesc heapTupDesc;
305  TupleDesc indexTupDesc;
306  int natts; /* #atts in heap rel --- for error checks */
307  int i;
308 
309  /* We need access to the index AM's API struct */
310  amroutine = GetIndexAmRoutineByAmId(accessMethodObjectId, false);
311 
312  /* ... and to the table's tuple descriptor */
313  heapTupDesc = RelationGetDescr(heapRelation);
314  natts = RelationGetForm(heapRelation)->relnatts;
315 
316  /*
317  * allocate the new tuple descriptor
318  */
319  indexTupDesc = CreateTemplateTupleDesc(numatts, false);
320 
321  /*
322  * For simple index columns, we copy the pg_attribute row from the parent
323  * relation and modify it as necessary. For expressions we have to cons
324  * up a pg_attribute row the hard way.
325  */
326  for (i = 0; i < numatts; i++)
327  {
328  AttrNumber atnum = indexInfo->ii_IndexAttrNumbers[i];
329  Form_pg_attribute to = TupleDescAttr(indexTupDesc, i);
330  HeapTuple tuple;
331  Form_pg_type typeTup;
332  Form_pg_opclass opclassTup;
333  Oid keyType;
334 
335  if (atnum != 0)
336  {
337  /* Simple index column */
338  Form_pg_attribute from;
339 
340  if (atnum < 0)
341  {
342  /*
343  * here we are indexing on a system attribute (-1...-n)
344  */
345  from = SystemAttributeDefinition(atnum,
346  heapRelation->rd_rel->relhasoids);
347  }
348  else
349  {
350  /*
351  * here we are indexing on a normal attribute (1...n)
352  */
353  if (atnum > natts) /* safety check */
354  elog(ERROR, "invalid column number %d", atnum);
355  from = TupleDescAttr(heapTupDesc,
356  AttrNumberGetAttrOffset(atnum));
357  }
358 
359  /*
360  * now that we've determined the "from", let's copy the tuple desc
361  * data...
362  */
363  memcpy(to, from, ATTRIBUTE_FIXED_PART_SIZE);
364 
365  /*
366  * Fix the stuff that should not be the same as the underlying
367  * attr
368  */
369  to->attnum = i + 1;
370 
371  to->attstattarget = -1;
372  to->attcacheoff = -1;
373  to->attnotnull = false;
374  to->atthasdef = false;
375  to->atthasmissing = false;
376  to->attidentity = '\0';
377  to->attislocal = true;
378  to->attinhcount = 0;
379  to->attcollation = (i < numkeyatts) ?
380  collationObjectId[i] : InvalidOid;
381  }
382  else
383  {
384  /* Expressional index */
385  Node *indexkey;
386 
388 
389  if (indexpr_item == NULL) /* shouldn't happen */
390  elog(ERROR, "too few entries in indexprs list");
391  indexkey = (Node *) lfirst(indexpr_item);
392  indexpr_item = lnext(indexpr_item);
393 
394  /*
395  * Lookup the expression type in pg_type for the type length etc.
396  */
397  keyType = exprType(indexkey);
398  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
399  if (!HeapTupleIsValid(tuple))
400  elog(ERROR, "cache lookup failed for type %u", keyType);
401  typeTup = (Form_pg_type) GETSTRUCT(tuple);
402 
403  /*
404  * Assign some of the attributes values. Leave the rest as 0.
405  */
406  to->attnum = i + 1;
407  to->atttypid = keyType;
408  to->attlen = typeTup->typlen;
409  to->attbyval = typeTup->typbyval;
410  to->attstorage = typeTup->typstorage;
411  to->attalign = typeTup->typalign;
412  to->attstattarget = -1;
413  to->attcacheoff = -1;
414  to->atttypmod = exprTypmod(indexkey);
415  to->attislocal = true;
416  to->attcollation = (i < numkeyatts) ?
417  collationObjectId[i] : InvalidOid;
418 
419  ReleaseSysCache(tuple);
420 
421  /*
422  * Make sure the expression yields a type that's safe to store in
423  * an index. We need this defense because we have index opclasses
424  * for pseudo-types such as "record", and the actually stored type
425  * had better be safe; eg, a named composite type is okay, an
426  * anonymous record type is not. The test is the same as for
427  * whether a table column is of a safe type (which is why we
428  * needn't check for the non-expression case).
429  */
430  CheckAttributeType(NameStr(to->attname),
431  to->atttypid, to->attcollation,
432  NIL, false);
433  }
434 
435  /*
436  * We do not yet have the correct relation OID for the index, so just
437  * set it invalid for now. InitializeAttributeOids() will fix it
438  * later.
439  */
440  to->attrelid = InvalidOid;
441 
442  /*
443  * Set the attribute name as specified by caller.
444  */
445  if (colnames_item == NULL) /* shouldn't happen */
446  elog(ERROR, "too few entries in colnames list");
447  namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
448  colnames_item = lnext(colnames_item);
449 
450  /*
451  * Check the opclass and index AM to see if either provides a keytype
452  * (overriding the attribute type). Opclass (if exists) takes
453  * precedence.
454  */
455  keyType = amroutine->amkeytype;
456 
457  /*
458  * Code below is concerned to the opclasses which are not used with
459  * the included columns.
460  */
461  if (i < indexInfo->ii_NumIndexKeyAttrs)
462  {
463  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(classObjectId[i]));
464  if (!HeapTupleIsValid(tuple))
465  elog(ERROR, "cache lookup failed for opclass %u",
466  classObjectId[i]);
467  opclassTup = (Form_pg_opclass) GETSTRUCT(tuple);
468  if (OidIsValid(opclassTup->opckeytype))
469  keyType = opclassTup->opckeytype;
470 
471  /*
472  * If keytype is specified as ANYELEMENT, and opcintype is
473  * ANYARRAY, then the attribute type must be an array (else it'd
474  * not have matched this opclass); use its element type.
475  */
476  if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID)
477  {
478  keyType = get_base_element_type(to->atttypid);
479  if (!OidIsValid(keyType))
480  elog(ERROR, "could not get element type of array type %u",
481  to->atttypid);
482  }
483 
484  ReleaseSysCache(tuple);
485  }
486 
487  /*
488  * If a key type different from the heap value is specified, update
489  * the type-related fields in the index tupdesc.
490  */
491  if (OidIsValid(keyType) && keyType != to->atttypid)
492  {
493  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
494  if (!HeapTupleIsValid(tuple))
495  elog(ERROR, "cache lookup failed for type %u", keyType);
496  typeTup = (Form_pg_type) GETSTRUCT(tuple);
497 
498  to->atttypid = keyType;
499  to->atttypmod = -1;
500  to->attlen = typeTup->typlen;
501  to->attbyval = typeTup->typbyval;
502  to->attalign = typeTup->typalign;
503  to->attstorage = typeTup->typstorage;
504 
505  ReleaseSysCache(tuple);
506  }
507  }
508 
509  pfree(amroutine);
510 
511  return indexTupDesc;
512 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define RelationGetDescr(relation)
Definition: rel.h:433
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define RelationGetForm(relation)
Definition: rel.h:401
Definition: nodes.h:517
#define MemSet(start, val, len)
Definition: c.h:908
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
Oid amkeytype
Definition: amapi.h:198
#define OidIsValid(objectId)
Definition: c.h:605
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
#define AttrNumberGetAttrOffset(attNum)
Definition: attnum.h:51
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:189
#define lnext(lc)
Definition: pg_list.h:105
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, bool allow_system_table_mods)
Definition: heap.c:494
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
int ii_NumIndexAttrs
Definition: execnodes.h:151
Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
Definition: heap.c:203
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
#define lfirst(lc)
Definition: pg_list.h:106
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2575
int i
#define NameStr(name)
Definition: c.h:576
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81
int16 AttrNumber
Definition: attnum.h:21

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4106 of file index.c.

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

Referenced by InitializeParallelDSM().

4107 {
4110 }
static List * pendingReindexedIndexes
Definition: index.c:3994
unsigned int Oid
Definition: postgres_ext.h:31
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
static int list_length(const List *l)
Definition: pg_list.h:89
#define offsetof(type, field)
Definition: c.h:622

◆ FormIndexDatum()

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

Definition at line 2000 of file index.c.

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, and slot_getattr().

Referenced by CatalogIndexInsert(), check_exclusion_or_unique_constraint(), comparetup_cluster(), compute_index_stats(), ExecCheckIndexConstraints(), ExecInsertIndexTuples(), get_actual_variable_range(), IndexBuildHeapRangeScan(), IndexCheckExclusion(), ProjIndexIsUnchanged(), unique_key_recheck(), and validate_index_heapscan().

2005 {
2006  ListCell *indexpr_item;
2007  int i;
2008 
2009  if (indexInfo->ii_Expressions != NIL &&
2010  indexInfo->ii_ExpressionsState == NIL)
2011  {
2012  /* First time through, set up expression evaluation state */
2013  indexInfo->ii_ExpressionsState =
2014  ExecPrepareExprList(indexInfo->ii_Expressions, estate);
2015  /* Check caller has set up context correctly */
2016  Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2017  }
2018  indexpr_item = list_head(indexInfo->ii_ExpressionsState);
2019 
2020  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
2021  {
2022  int keycol = indexInfo->ii_IndexAttrNumbers[i];
2023  Datum iDatum;
2024  bool isNull;
2025 
2026  if (keycol != 0)
2027  {
2028  /*
2029  * Plain index column; get the value we need directly from the
2030  * heap tuple.
2031  */
2032  iDatum = slot_getattr(slot, keycol, &isNull);
2033  }
2034  else
2035  {
2036  /*
2037  * Index expression --- need to evaluate it.
2038  */
2039  if (indexpr_item == NULL)
2040  elog(ERROR, "wrong number of index expressions");
2041  iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
2042  GetPerTupleExprContext(estate),
2043  &isNull);
2044  indexpr_item = lnext(indexpr_item);
2045  }
2046  values[i] = iDatum;
2047  isnull[i] = isNull;
2048  }
2049 
2050  if (indexpr_item != NULL)
2051  elog(ERROR, "wrong number of index expressions");
2052 }
#define NIL
Definition: pg_list.h:69
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:296
#define GetPerTupleExprContext(estate)
Definition: executor.h:489
List * ii_ExpressionsState
Definition: execnodes.h:155
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:562
uintptr_t Datum
Definition: postgres.h:365
int ii_NumIndexAttrs
Definition: execnodes.h:151
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1518
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153

◆ index_build()

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

Definition at line 2229 of file index.c.

References IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, Assert, AtEOXact_GUC(), CatalogTupleUpdate(), CommandCounterIncrement(), DEBUG1, EarlyPruningEnabled, elog, ereport, errmsg(), errmsg_plural(), ERROR, GETSTRUCT, GetUserIdAndSecContext(), heap_close, heap_freetuple(), heap_open(), 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, NewGUCNestLevel(), ObjectIdGetDatum, plan_create_index_workers(), PointerIsValid, RelationData::rd_amroutine, RelationData::rd_rel, RelationData::rd_smgr, RelationGetRelationName, RelationGetRelid, RelationIsValid, RelationOpenSmgr, RowExclusiveLock, SearchSysCacheCopy1, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), smgrcreate(), smgrexists(), and HeapTupleData::t_self.

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

2235 {
2236  IndexBuildResult *stats;
2237  Oid save_userid;
2238  int save_sec_context;
2239  int save_nestlevel;
2240 
2241  /*
2242  * sanity checks
2243  */
2244  Assert(RelationIsValid(indexRelation));
2245  Assert(PointerIsValid(indexRelation->rd_amroutine));
2246  Assert(PointerIsValid(indexRelation->rd_amroutine->ambuild));
2247  Assert(PointerIsValid(indexRelation->rd_amroutine->ambuildempty));
2248 
2249  /*
2250  * Determine worker process details for parallel CREATE INDEX. Currently,
2251  * only btree has support for parallel builds.
2252  *
2253  * Note that planner considers parallel safety for us.
2254  */
2255  if (parallel && IsNormalProcessingMode() &&
2256  indexRelation->rd_rel->relam == BTREE_AM_OID)
2257  indexInfo->ii_ParallelWorkers =
2259  RelationGetRelid(indexRelation));
2260 
2261  if (indexInfo->ii_ParallelWorkers == 0)
2262  ereport(DEBUG1,
2263  (errmsg("building index \"%s\" on table \"%s\" serially",
2264  RelationGetRelationName(indexRelation),
2265  RelationGetRelationName(heapRelation))));
2266  else
2267  ereport(DEBUG1,
2268  (errmsg_plural("building index \"%s\" on table \"%s\" with request for %d parallel worker",
2269  "building index \"%s\" on table \"%s\" with request for %d parallel workers",
2270  indexInfo->ii_ParallelWorkers,
2271  RelationGetRelationName(indexRelation),
2272  RelationGetRelationName(heapRelation),
2273  indexInfo->ii_ParallelWorkers)));
2274 
2275  /*
2276  * Switch to the table owner's userid, so that any index functions are run
2277  * as that user. Also lock down security-restricted operations and
2278  * arrange to make GUC variable changes local to this command.
2279  */
2280  GetUserIdAndSecContext(&save_userid, &save_sec_context);
2281  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
2282  save_sec_context | SECURITY_RESTRICTED_OPERATION);
2283  save_nestlevel = NewGUCNestLevel();
2284 
2285  /*
2286  * Call the access method's build procedure
2287  */
2288  stats = indexRelation->rd_amroutine->ambuild(heapRelation, indexRelation,
2289  indexInfo);
2290  Assert(PointerIsValid(stats));
2291 
2292  /*
2293  * If this is an unlogged index, we may need to write out an init fork for
2294  * it -- but we must first check whether one already exists. If, for
2295  * example, an unlogged relation is truncated in the transaction that
2296  * created it, or truncated twice in a subsequent transaction, the
2297  * relfilenode won't change, and nothing needs to be done here.
2298  */
2299  if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
2300  !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM))
2301  {
2302  RelationOpenSmgr(indexRelation);
2303  smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false);
2304  indexRelation->rd_amroutine->ambuildempty(indexRelation);
2305  }
2306 
2307  /*
2308  * If we found any potentially broken HOT chains, mark the index as not
2309  * being usable until the current transaction is below the event horizon.
2310  * See src/backend/access/heap/README.HOT for discussion. Also set this
2311  * if early pruning/vacuuming is enabled for the heap relation. While it
2312  * might become safe to use the index earlier based on actual cleanup
2313  * activity and other active transactions, the test for that would be much
2314  * more complex and would require some form of blocking, so keep it simple
2315  * and fast by just using the current transaction.
2316  *
2317  * However, when reindexing an existing index, we should do nothing here.
2318  * Any HOT chains that are broken with respect to the index must predate
2319  * the index's original creation, so there is no need to change the
2320  * index's usability horizon. Moreover, we *must not* try to change the
2321  * index's pg_index entry while reindexing pg_index itself, and this
2322  * optimization nicely prevents that. The more complex rules needed for a
2323  * reindex are handled separately after this function returns.
2324  *
2325  * We also need not set indcheckxmin during a concurrent index build,
2326  * because we won't set indisvalid true until all transactions that care
2327  * about the broken HOT chains or early pruning/vacuuming are gone.
2328  *
2329  * Therefore, this code path can only be taken during non-concurrent
2330  * CREATE INDEX. Thus the fact that heap_update will set the pg_index
2331  * tuple's xmin doesn't matter, because that tuple was created in the
2332  * current transaction anyway. That also means we don't need to worry
2333  * about any concurrent readers of the tuple; no other transaction can see
2334  * it yet.
2335  */
2336  if ((indexInfo->ii_BrokenHotChain || EarlyPruningEnabled(heapRelation)) &&
2337  !isreindex &&
2338  !indexInfo->ii_Concurrent)
2339  {
2340  Oid indexId = RelationGetRelid(indexRelation);
2341  Relation pg_index;
2342  HeapTuple indexTuple;
2343  Form_pg_index indexForm;
2344 
2345  pg_index = heap_open(IndexRelationId, RowExclusiveLock);
2346 
2347  indexTuple = SearchSysCacheCopy1(INDEXRELID,
2348  ObjectIdGetDatum(indexId));
2349  if (!HeapTupleIsValid(indexTuple))
2350  elog(ERROR, "cache lookup failed for index %u", indexId);
2351  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
2352 
2353  /* If it's a new index, indcheckxmin shouldn't be set ... */
2354  Assert(!indexForm->indcheckxmin);
2355 
2356  indexForm->indcheckxmin = true;
2357  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
2358 
2359  heap_freetuple(indexTuple);
2360  heap_close(pg_index, RowExclusiveLock);
2361  }
2362 
2363  /*
2364  * Update heap and index pg_class rows
2365  */
2366  index_update_stats(heapRelation,
2367  true,
2368  stats->heap_tuples);
2369 
2370  index_update_stats(indexRelation,
2371  false,
2372  stats->index_tuples);
2373 
2374  /* Make the updated catalog row versions visible */
2376 
2377  /*
2378  * If it's for an exclusion constraint, make a second pass over the heap
2379  * to verify that the constraint is satisfied. We must not do this until
2380  * the index is fully valid. (Broken HOT chains shouldn't matter, though;
2381  * see comments for IndexCheckExclusion.)
2382  */
2383  if (indexInfo->ii_ExclusionOps != NULL)
2384  IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
2385 
2386  /* Roll back any GUC changes executed by index functions */
2387  AtEOXact_GUC(false, save_nestlevel);
2388 
2389  /* Restore userid and security context */
2390  SetUserIdAndSecContext(save_userid, save_sec_context);
2391 }
static void index_update_stats(Relation rel, bool hasindex, double reltuples)
Definition: index.c:2077
#define DEBUG1
Definition: elog.h:25
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:376
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:298
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:491
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:850
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
#define heap_close(r, l)
Definition: heapam.h:97
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:287
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:153
#define RelationOpenSmgr(relation)
Definition: rel.h:465
#define EarlyPruningEnabled(rel)
Definition: snapmgr.h:46
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ambuild_function ambuild
Definition: amapi.h:207
#define RelationIsValid(relation)
Definition: rel.h:380
ItemPointerData t_self
Definition: htup.h:65
#define IsNormalProcessingMode()
Definition: miscadmin.h:374
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:484
#define RowExclusiveLock
Definition: lockdefs.h:38
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5299
#define RelationGetRelationName(relation)
Definition: rel.h:441
bool ii_BrokenHotChain
Definition: execnodes.h:167
static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
Definition: index.c:2953
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
int ii_ParallelWorkers
Definition: execnodes.h:168
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
int plan_create_index_workers(Oid tableOid, Oid indexOid)
Definition: planner.c:6029
bool ii_Concurrent
Definition: execnodes.h:166
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int NewGUCNestLevel(void)
Definition: guc.c:5285
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
ambuildempty_function ambuildempty
Definition: amapi.h:208
#define elog
Definition: elog.h:219
#define PointerIsValid(pointer)
Definition: c.h:593
#define RelationGetRelid(relation)
Definition: rel.h:407
double index_tuples
Definition: genam.h:33
double heap_tuples
Definition: genam.h:32

◆ index_check_primary_key()

void index_check_primary_key ( Relation  heapRel,
IndexInfo indexInfo,
bool  is_alter_table 
)

Definition at line 213 of file index.c.

References AlterTableInternal(), AT_SetNotNull, ATTNUM, attnum, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, i, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexKeyAttrs, Int16GetDatum, lappend(), makeNode, AlterTableCmd::name, NameStr, NIL, ObjectIdGetDatum, pstrdup(), RelationGetRelationName, RelationGetRelid, relationHasPrimaryKey(), ReleaseSysCache(), SearchSysCache2(), and AlterTableCmd::subtype.

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

216 {
217  List *cmds;
218  int i;
219 
220  /*
221  * If ALTER TABLE, check that there isn't already a PRIMARY KEY. In CREATE
222  * TABLE, we have faith that the parser rejected multiple pkey clauses;
223  * and CREATE INDEX doesn't have a way to say PRIMARY KEY, so it's no
224  * problem either.
225  */
226  if (is_alter_table &&
227  relationHasPrimaryKey(heapRel))
228  {
229  ereport(ERROR,
230  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
231  errmsg("multiple primary keys for table \"%s\" are not allowed",
232  RelationGetRelationName(heapRel))));
233  }
234 
235  /*
236  * Check that all of the attributes in a primary key are marked as not
237  * null, otherwise attempt to ALTER TABLE .. SET NOT NULL
238  */
239  cmds = NIL;
240  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
241  {
242  AttrNumber attnum = indexInfo->ii_IndexAttrNumbers[i];
243  HeapTuple atttuple;
244  Form_pg_attribute attform;
245 
246  if (attnum == 0)
247  ereport(ERROR,
248  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
249  errmsg("primary keys cannot be expressions")));
250 
251  /* System attributes are never null, so no need to check */
252  if (attnum < 0)
253  continue;
254 
255  atttuple = SearchSysCache2(ATTNUM,
257  Int16GetDatum(attnum));
258  if (!HeapTupleIsValid(atttuple))
259  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
260  attnum, RelationGetRelid(heapRel));
261  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
262 
263  if (!attform->attnotnull)
264  {
265  /* Add a subcommand to make this one NOT NULL */
267 
268  cmd->subtype = AT_SetNotNull;
269  cmd->name = pstrdup(NameStr(attform->attname));
270  cmds = lappend(cmds, cmd);
271  }
272 
273  ReleaseSysCache(atttuple);
274  }
275 
276  /*
277  * XXX: possible future improvement: when being called from ALTER TABLE,
278  * it would be more efficient to merge this with the outer ALTER TABLE, so
279  * as to avoid two scans. But that seems to complicate DefineIndex's API
280  * unduly.
281  */
282  if (cmds)
283  AlterTableInternal(RelationGetRelid(heapRel), cmds, true);
284 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define Int16GetDatum(X)
Definition: postgres.h:434
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1806
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
#define RelationGetRelationName(relation)
Definition: rel.h:441
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
static bool relationHasPrimaryKey(Relation rel)
Definition: index.c:160
int16 attnum
Definition: pg_attribute.h:79
#define makeNode(_type_)
Definition: nodes.h:565
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1123
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3313
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:576
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ index_constraint_create()

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

Definition at line 1225 of file index.c.

References CreateTrigStmt::args, Assert, CatalogTupleUpdate(), ObjectAddress::classId, CreateTrigStmt::columns, CreateTrigStmt::constrrel, CreateConstraintEntry(), CreateTrigger(), CreateTrigStmt::deferrable, deleteDependencyRecordsForClass(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_INTERNAL_AUTO, elog, ereport, errcode(), errmsg(), ERROR, CreateTrigStmt::events, CreateTrigStmt::funcname, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), 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, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelid, CreateTrigStmt::row, RowExclusiveLock, SearchSysCacheCopy1, SystemFuncName(), HeapTupleData::t_self, CreateTrigStmt::timing, CreateTrigStmt::trigname, and CreateTrigStmt::whenClause.

Referenced by ATExecAddIndexConstraint(), and index_create().

1234 {
1235  Oid namespaceId = RelationGetNamespace(heapRelation);
1236  ObjectAddress myself,
1237  referenced;
1238  Oid conOid;
1239  bool deferrable;
1240  bool initdeferred;
1241  bool mark_as_primary;
1242  bool islocal;
1243  bool noinherit;
1244  int inhcount;
1245 
1246  deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1247  initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1248  mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
1249 
1250  /* constraint creation support doesn't work while bootstrapping */
1252 
1253  /* enforce system-table restriction */
1254  if (!allow_system_table_mods &&
1255  IsSystemRelation(heapRelation) &&
1257  ereport(ERROR,
1258  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1259  errmsg("user-defined indexes on system catalog tables are not supported")));
1260 
1261  /* primary/unique constraints shouldn't have any expressions */
1262  if (indexInfo->ii_Expressions &&
1263  constraintType != CONSTRAINT_EXCLUSION)
1264  elog(ERROR, "constraints cannot have index expressions");
1265 
1266  /*
1267  * If we're manufacturing a constraint for a pre-existing index, we need
1268  * to get rid of the existing auto dependencies for the index (the ones
1269  * that index_create() would have made instead of calling this function).
1270  *
1271  * Note: this code would not necessarily do the right thing if the index
1272  * has any expressions or predicate, but we'd never be turning such an
1273  * index into a UNIQUE or PRIMARY KEY constraint.
1274  */
1275  if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
1276  deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
1277  RelationRelationId, DEPENDENCY_AUTO);
1278 
1279  if (OidIsValid(parentConstraintId))
1280  {
1281  islocal = false;
1282  inhcount = 1;
1283  noinherit = false;
1284  }
1285  else
1286  {
1287  islocal = true;
1288  inhcount = 0;
1289  noinherit = true;
1290  }
1291 
1292  /*
1293  * Construct a pg_constraint entry.
1294  */
1295  conOid = CreateConstraintEntry(constraintName,
1296  namespaceId,
1297  constraintType,
1298  deferrable,
1299  initdeferred,
1300  true,
1301  parentConstraintId,
1302  RelationGetRelid(heapRelation),
1303  indexInfo->ii_IndexAttrNumbers,
1304  indexInfo->ii_NumIndexKeyAttrs,
1305  indexInfo->ii_NumIndexAttrs,
1306  InvalidOid, /* no domain */
1307  indexRelationId, /* index OID */
1308  InvalidOid, /* no foreign key */
1309  NULL,
1310  NULL,
1311  NULL,
1312  NULL,
1313  0,
1314  ' ',
1315  ' ',
1316  ' ',
1317  indexInfo->ii_ExclusionOps,
1318  NULL, /* no check constraint */
1319  NULL,
1320  NULL,
1321  islocal,
1322  inhcount,
1323  noinherit,
1324  is_internal);
1325 
1326  /*
1327  * Register the index as internally dependent on the constraint.
1328  *
1329  * Note that the constraint has a dependency on the table, so we don't
1330  * need (or want) any direct dependency from the index to the table.
1331  */
1332  myself.classId = RelationRelationId;
1333  myself.objectId = indexRelationId;
1334  myself.objectSubId = 0;
1335 
1336  referenced.classId = ConstraintRelationId;
1337  referenced.objectId = conOid;
1338  referenced.objectSubId = 0;
1339 
1340  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1341 
1342  /*
1343  * Also, if this is a constraint on a partition, mark it as depending
1344  * on the constraint in the parent.
1345  */
1346  if (OidIsValid(parentConstraintId))
1347  {
1348  ObjectAddress parentConstr;
1349 
1350  ObjectAddressSet(parentConstr, ConstraintRelationId, parentConstraintId);
1351  recordDependencyOn(&referenced, &parentConstr, DEPENDENCY_INTERNAL_AUTO);
1352  }
1353 
1354  /*
1355  * If the constraint is deferrable, create the deferred uniqueness
1356  * checking trigger. (The trigger will be given an internal dependency on
1357  * the constraint by CreateTrigger.)
1358  */
1359  if (deferrable)
1360  {
1361  CreateTrigStmt *trigger;
1362 
1363  trigger = makeNode(CreateTrigStmt);
1364  trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
1365  "PK_ConstraintTrigger" :
1366  "Unique_ConstraintTrigger";
1367  trigger->relation = NULL;
1368  trigger->funcname = SystemFuncName("unique_key_recheck");
1369  trigger->args = NIL;
1370  trigger->row = true;
1371  trigger->timing = TRIGGER_TYPE_AFTER;
1372  trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE;
1373  trigger->columns = NIL;
1374  trigger->whenClause = NULL;
1375  trigger->isconstraint = true;
1376  trigger->deferrable = true;
1377  trigger->initdeferred = initdeferred;
1378  trigger->constrrel = NULL;
1379 
1380  (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
1381  InvalidOid, conOid, indexRelationId, InvalidOid,
1382  InvalidOid, NULL, true, false);
1383  }
1384 
1385  /*
1386  * If needed, mark the index as primary and/or deferred in pg_index.
1387  *
1388  * Note: When making an existing index into a constraint, caller must have
1389  * a table lock that prevents concurrent table updates; otherwise, there
1390  * is a risk that concurrent readers of the table will miss seeing this
1391  * index at all.
1392  */
1393  if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
1394  (mark_as_primary || deferrable))
1395  {
1396  Relation pg_index;
1397  HeapTuple indexTuple;
1398  Form_pg_index indexForm;
1399  bool dirty = false;
1400 
1401  pg_index = heap_open(IndexRelationId, RowExclusiveLock);
1402 
1403  indexTuple = SearchSysCacheCopy1(INDEXRELID,
1404  ObjectIdGetDatum(indexRelationId));
1405  if (!HeapTupleIsValid(indexTuple))
1406  elog(ERROR, "cache lookup failed for index %u", indexRelationId);
1407  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
1408 
1409  if (mark_as_primary && !indexForm->indisprimary)
1410  {
1411  indexForm->indisprimary = true;
1412  dirty = true;
1413  }
1414 
1415  if (deferrable && indexForm->indimmediate)
1416  {
1417  indexForm->indimmediate = false;
1418  dirty = true;
1419  }
1420 
1421  if (dirty)
1422  {
1423  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
1424 
1425  InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
1426  InvalidOid, is_internal);
1427  }
1428 
1429  heap_freetuple(indexTuple);
1430  heap_close(pg_index, RowExclusiveLock);
1431  }
1432 
1433  return referenced;
1434 }
#define NIL
Definition: pg_list.h:69
List * SystemFuncName(char *name)
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
Node * whenClause
Definition: parsenodes.h:2378
int errcode(int sqlerrcode)
Definition: elog.c:575
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define heap_close(r, l)
Definition: heapam.h:97
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:77
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:166
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:75
RangeVar * constrrel
Definition: parsenodes.h:2385
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
ItemPointerData t_self
Definition: htup.h:65
#define IsNormalProcessingMode()
Definition: miscadmin.h:374
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
int ii_NumIndexAttrs
Definition: execnodes.h:151
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:241
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:565
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:76
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:2369
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, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
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:159
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
#define RelationGetRelid(relation)
Definition: rel.h:407
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:74
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:73
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ index_create()

Oid index_create ( Relation  heapRelation,
const char *  indexRelationName,
Oid  indexRelationId,
Oid  parentIndexRelid,
Oid  parentConstraintId,
Oid  relFileNode,
IndexInfo indexInfo,
List indexColNames,
Oid  accessMethodObjectId,
Oid  tableSpaceId,
Oid collationObjectId,
Oid classObjectId,
int16 coloptions,
Datum  reloptions,
bits16  flags,
bits16  constr_flags,
bool  allow_system_table_mods,
bool  is_internal,
Oid constraintId 
)

Definition at line 745 of file index.c.

References AccessExclusiveLock, AppendAttributeTuples(), Assert, binary_upgrade_next_index_pg_class_oid, ObjectAddress::classId, CommandCounterIncrement(), ConstructTupleDescriptor(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, get_relname_relid(), GetNewRelFileNode(), heap_close, heap_create(), heap_open(), 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_register(), index_update_stats(), InitializeAttributeOids(), InsertPgClassTuple(), InvalidOid, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsNormalProcessingMode, IsSystemRelation(), LockRelation(), NoLock, NOTICE, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnSingleRelExpr(), RelationGetNamespace, RelationGetRelid, RelationInitIndexAccessInfo(), RelationIsMapped, relkind, relpersistence, RowExclusiveLock, StoreSingleInheritance(), and UpdateIndexRelation().

Referenced by create_toast_table(), and DefineIndex().

764 {
765  Oid heapRelationId = RelationGetRelid(heapRelation);
766  Relation pg_class;
767  Relation indexRelation;
768  TupleDesc indexTupDesc;
769  bool shared_relation;
770  bool mapped_relation;
771  bool is_exclusion;
772  Oid namespaceId;
773  int i;
774  char relpersistence;
775  bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0;
776  bool invalid = (flags & INDEX_CREATE_INVALID) != 0;
777  bool concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0;
778  bool partitioned = (flags & INDEX_CREATE_PARTITIONED) != 0;
779  char relkind;
780 
781  /* constraint flags can only be set when a constraint is requested */
782  Assert((constr_flags == 0) ||
783  ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0));
784  /* partitioned indexes must never be "built" by themselves */
785  Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD));
786 
787  relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX;
788  is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
789 
790  pg_class = heap_open(RelationRelationId, RowExclusiveLock);
791 
792  /*
793  * The index will be in the same namespace as its parent table, and is
794  * shared across databases if and only if the parent is. Likewise, it
795  * will use the relfilenode map if and only if the parent does; and it
796  * inherits the parent's relpersistence.
797  */
798  namespaceId = RelationGetNamespace(heapRelation);
799  shared_relation = heapRelation->rd_rel->relisshared;
800  mapped_relation = RelationIsMapped(heapRelation);
801  relpersistence = heapRelation->rd_rel->relpersistence;
802 
803  /*
804  * check parameters
805  */
806  if (indexInfo->ii_NumIndexAttrs < 1)
807  elog(ERROR, "must index at least one column");
808 
809  if (!allow_system_table_mods &&
810  IsSystemRelation(heapRelation) &&
812  ereport(ERROR,
813  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
814  errmsg("user-defined indexes on system catalog tables are not supported")));
815 
816  /*
817  * concurrent index build on a system catalog is unsafe because we tend to
818  * release locks before committing in catalogs
819  */
820  if (concurrent &&
821  IsSystemRelation(heapRelation))
822  ereport(ERROR,
823  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
824  errmsg("concurrent index creation on system catalog tables is not supported")));
825 
826  /*
827  * This case is currently not supported, but there's no way to ask for it
828  * in the grammar anyway, so it can't happen.
829  */
830  if (concurrent && is_exclusion)
831  ereport(ERROR,
832  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
833  errmsg_internal("concurrent index creation for exclusion constraints is not supported")));
834 
835  /*
836  * We cannot allow indexing a shared relation after initdb (because
837  * there's no way to make the entry in other databases' pg_class).
838  */
839  if (shared_relation && !IsBootstrapProcessingMode())
840  ereport(ERROR,
841  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
842  errmsg("shared indexes cannot be created after initdb")));
843 
844  /*
845  * Shared relations must be in pg_global, too (last-ditch check)
846  */
847  if (shared_relation && tableSpaceId != GLOBALTABLESPACE_OID)
848  elog(ERROR, "shared relations must be placed in pg_global tablespace");
849 
850  if (get_relname_relid(indexRelationName, namespaceId))
851  {
852  if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0)
853  {
854  ereport(NOTICE,
855  (errcode(ERRCODE_DUPLICATE_TABLE),
856  errmsg("relation \"%s\" already exists, skipping",
857  indexRelationName)));
858  heap_close(pg_class, RowExclusiveLock);
859  return InvalidOid;
860  }
861 
862  ereport(ERROR,
863  (errcode(ERRCODE_DUPLICATE_TABLE),
864  errmsg("relation \"%s\" already exists",
865  indexRelationName)));
866  }
867 
868  /*
869  * construct tuple descriptor for index tuples
870  */
871  indexTupDesc = ConstructTupleDescriptor(heapRelation,
872  indexInfo,
873  indexColNames,
874  accessMethodObjectId,
875  collationObjectId,
876  classObjectId);
877 
878  /*
879  * Allocate an OID for the index, unless we were told what to use.
880  *
881  * The OID will be the relfilenode as well, so make sure it doesn't
882  * collide with either pg_class OIDs or existing physical files.
883  */
884  if (!OidIsValid(indexRelationId))
885  {
886  /* Use binary-upgrade override for pg_class.oid/relfilenode? */
887  if (IsBinaryUpgrade)
888  {
890  ereport(ERROR,
891  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
892  errmsg("pg_class index OID value not set when in binary upgrade mode")));
893 
894  indexRelationId = binary_upgrade_next_index_pg_class_oid;
896  }
897  else
898  {
899  indexRelationId =
900  GetNewRelFileNode(tableSpaceId, pg_class, relpersistence);
901  }
902  }
903 
904  /*
905  * create the index relation's relcache entry and, if necessary, the
906  * physical disk file. (If we fail further down, it's the smgr's
907  * responsibility to remove the disk file again, if any.)
908  */
909  indexRelation = heap_create(indexRelationName,
910  namespaceId,
911  tableSpaceId,
912  indexRelationId,
913  relFileNode,
914  indexTupDesc,
915  relkind,
916  relpersistence,
917  shared_relation,
918  mapped_relation,
919  allow_system_table_mods);
920 
921  Assert(indexRelationId == RelationGetRelid(indexRelation));
922 
923  /*
924  * Obtain exclusive lock on it. Although no other transactions can see it
925  * until we commit, this prevents deadlock-risk complaints from lock
926  * manager in cases such as CLUSTER.
927  */
928  LockRelation(indexRelation, AccessExclusiveLock);
929 
930  /*
931  * Fill in fields of the index's pg_class entry that are not set correctly
932  * by heap_create.
933  *
934  * XXX should have a cleaner way to create cataloged indexes
935  */
936  indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner;
937  indexRelation->rd_rel->relam = accessMethodObjectId;
938  indexRelation->rd_rel->relhasoids = false;
939  indexRelation->rd_rel->relispartition = OidIsValid(parentIndexRelid);
940 
941  /*
942  * store index's pg_class entry
943  */
944  InsertPgClassTuple(pg_class, indexRelation,
945  RelationGetRelid(indexRelation),
946  (Datum) 0,
947  reloptions);
948 
949  /* done with pg_class */
950  heap_close(pg_class, RowExclusiveLock);
951 
952  /*
953  * now update the object id's of all the attribute tuple forms in the
954  * index relation's tuple descriptor
955  */
956  InitializeAttributeOids(indexRelation,
957  indexInfo->ii_NumIndexAttrs,
958  indexRelationId);
959 
960  /*
961  * append ATTRIBUTE tuples for the index
962  */
963  AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
964 
965  /* ----------------
966  * update pg_index
967  * (append INDEX tuple)
968  *
969  * Note that this stows away a representation of "predicate".
970  * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
971  * ----------------
972  */
973  UpdateIndexRelation(indexRelationId, heapRelationId, parentIndexRelid,
974  indexInfo,
975  collationObjectId, classObjectId, coloptions,
976  isprimary, is_exclusion,
977  (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0,
978  !concurrent && !invalid,
979  !concurrent);
980 
981  /* update pg_inherits, if needed */
982  if (OidIsValid(parentIndexRelid))
983  StoreSingleInheritance(indexRelationId, parentIndexRelid, 1);
984 
985  /*
986  * Register constraint and dependencies for the index.
987  *
988  * If the index is from a CONSTRAINT clause, construct a pg_constraint
989  * entry. The index will be linked to the constraint, which in turn is
990  * linked to the table. If it's not a CONSTRAINT, we need to make a
991  * dependency directly on the table.
992  *
993  * We don't need a dependency on the namespace, because there'll be an
994  * indirect dependency via our parent table.
995  *
996  * During bootstrap we can't register any dependencies, and we don't try
997  * to make a constraint either.
998  */
1000  {
1001  ObjectAddress myself,
1002  referenced;
1003 
1004  myself.classId = RelationRelationId;
1005  myself.objectId = indexRelationId;
1006  myself.objectSubId = 0;
1007 
1008  if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)
1009  {
1010  char constraintType;
1011  ObjectAddress localaddr;
1012 
1013  if (isprimary)
1014  constraintType = CONSTRAINT_PRIMARY;
1015  else if (indexInfo->ii_Unique)
1016  constraintType = CONSTRAINT_UNIQUE;
1017  else if (is_exclusion)
1018  constraintType = CONSTRAINT_EXCLUSION;
1019  else
1020  {
1021  elog(ERROR, "constraint must be PRIMARY, UNIQUE or EXCLUDE");
1022  constraintType = 0; /* keep compiler quiet */
1023  }
1024 
1025  localaddr = index_constraint_create(heapRelation,
1026  indexRelationId,
1027  parentConstraintId,
1028  indexInfo,
1029  indexRelationName,
1030  constraintType,
1031  constr_flags,
1032  allow_system_table_mods,
1033  is_internal);
1034  if (constraintId)
1035  *constraintId = localaddr.objectId;
1036  }
1037  else
1038  {
1039  bool have_simple_col = false;
1040  DependencyType deptype;
1041 
1042  deptype = OidIsValid(parentIndexRelid) ? DEPENDENCY_INTERNAL_AUTO : DEPENDENCY_AUTO;
1043 
1044  /* Create auto dependencies on simply-referenced columns */
1045  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1046  {
1047  if (indexInfo->ii_IndexAttrNumbers[i] != 0)
1048  {
1049  referenced.classId = RelationRelationId;
1050  referenced.objectId = heapRelationId;
1051  referenced.objectSubId = indexInfo->ii_IndexAttrNumbers[i];
1052 
1053  recordDependencyOn(&myself, &referenced, deptype);
1054 
1055  have_simple_col = true;
1056  }
1057  }
1058 
1059  /*
1060  * If there are no simply-referenced columns, give the index an
1061  * auto dependency on the whole table. In most cases, this will
1062  * be redundant, but it might not be if the index expressions and
1063  * predicate contain no Vars or only whole-row Vars.
1064  */
1065  if (!have_simple_col)
1066  {
1067  referenced.classId = RelationRelationId;
1068  referenced.objectId = heapRelationId;
1069  referenced.objectSubId = 0;
1070 
1071  recordDependencyOn(&myself, &referenced, deptype);
1072  }
1073  }
1074 
1075  /* Store dependency on parent index, if any */
1076  if (OidIsValid(parentIndexRelid))
1077  {
1078  referenced.classId = RelationRelationId;
1079  referenced.objectId = parentIndexRelid;
1080  referenced.objectSubId = 0;
1081 
1082  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL_AUTO);
1083  }
1084 
1085  /* Store dependency on collations */
1086  /* The default collation is pinned, so don't bother recording it */
1087  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1088  {
1089  if (OidIsValid(collationObjectId[i]) &&
1090  collationObjectId[i] != DEFAULT_COLLATION_OID)
1091  {
1092  referenced.classId = CollationRelationId;
1093  referenced.objectId = collationObjectId[i];
1094  referenced.objectSubId = 0;
1095 
1096  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1097  }
1098  }
1099 
1100  /* Store dependency on operator classes */
1101  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1102  {
1103  referenced.classId = OperatorClassRelationId;
1104  referenced.objectId = classObjectId[i];
1105  referenced.objectSubId = 0;
1106 
1107  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1108  }
1109 
1110  /* Store dependencies on anything mentioned in index expressions */
1111  if (indexInfo->ii_Expressions)
1112  {
1114  (Node *) indexInfo->ii_Expressions,
1115  heapRelationId,
1117  DEPENDENCY_AUTO, false);
1118  }
1119 
1120  /* Store dependencies on anything mentioned in predicate */
1121  if (indexInfo->ii_Predicate)
1122  {
1124  (Node *) indexInfo->ii_Predicate,
1125  heapRelationId,
1127  DEPENDENCY_AUTO, false);
1128  }
1129  }
1130  else
1131  {
1132  /* Bootstrap mode - assert we weren't asked for constraint support */
1133  Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
1134  }
1135 
1136  /* Post creation hook for new index */
1137  InvokeObjectPostCreateHookArg(RelationRelationId,
1138  indexRelationId, 0, is_internal);
1139 
1140  /*
1141  * Advance the command counter so that we can see the newly-entered
1142  * catalog tuples for the index.
1143  */
1145 
1146  /*
1147  * In bootstrap mode, we have to fill in the index strategy structure with
1148  * information from the catalogs. If we aren't bootstrapping, then the
1149  * relcache entry has already been rebuilt thanks to sinval update during
1150  * CommandCounterIncrement.
1151  */
1153  RelationInitIndexAccessInfo(indexRelation);
1154  else
1155  Assert(indexRelation->rd_indexcxt != NULL);
1156 
1157  indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs;
1158 
1159  /*
1160  * If this is bootstrap (initdb) time, then we don't actually fill in the
1161  * index yet. We'll be creating more indexes and classes later, so we
1162  * delay filling them in until just before we're done with bootstrapping.
1163  * Similarly, if the caller specified to skip the build then filling the
1164  * index is delayed till later (ALTER TABLE can save work in some cases
1165  * with this). Otherwise, we call the AM routine that constructs the
1166  * index.
1167  */
1169  {
1170  index_register(heapRelationId, indexRelationId, indexInfo);
1171  }
1172  else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0)
1173  {
1174  /*
1175  * Caller is responsible for filling the index later on. However,
1176  * we'd better make sure that the heap relation is correctly marked as
1177  * having an index.
1178  */
1179  index_update_stats(heapRelation,
1180  true,
1181  -1.0);
1182  /* Make the above update visible */
1184  }
1185  else
1186  {
1187  index_build(heapRelation, indexRelation, indexInfo, isprimary, false,
1188  true);
1189  }
1190 
1191  /*
1192  * Close the index; but we keep the lock that we acquired above until end
1193  * of transaction. Closing the heap is caller's responsibility.
1194  */
1195  index_close(indexRelation, NoLock);
1196 
1197  return indexRelationId;
1198 }
DependencyType
Definition: dependency.h:87
static void index_update_stats(Relation rel, bool hasindex, double reltuples)
Definition: index.c:2077
static void UpdateIndexRelation(Oid indexoid, Oid heapoid, Oid parentIndexId, IndexInfo *indexInfo, Oid *collationOids, Oid *classOids, int16 *coloptions, bool primary, bool isexclusion, bool immediate, bool isvalid, bool isready)
Definition: index.c:582
List * ii_Predicate
Definition: execnodes.h:156
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:49
#define INDEX_CREATE_INVALID
Definition: index.h:51
static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid)
Definition: index.c:519
Oid binary_upgrade_next_index_pg_class_oid
Definition: index.c:81
Definition: nodes.h:517
int errcode(int sqlerrcode)
Definition: elog.c:575
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isprimary, bool isreindex, bool parallel)
Definition: index.c:2229
#define OidIsValid(objectId)
Definition: c.h:605
bool IsBinaryUpgrade
Definition: globals.c:111
char relkind
Definition: pg_class.h:51
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:772
Form_pg_index rd_index
Definition: rel.h:131
#define ERROR
Definition: elog.h:43
Relation heap_create(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods)
Definition: heap.c:253
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
char relpersistence
Definition: pg_class.h:50
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
#define NoLock
Definition: lockdefs.h:34
#define IsNormalProcessingMode()
Definition: miscadmin.h:374
#define RowExclusiveLock
Definition: lockdefs.h:38
static TupleDesc ConstructTupleDescriptor(Relation heapRelation, IndexInfo *indexInfo, List *indexColNames, Oid accessMethodObjectId, Oid *collationObjectId, Oid *classObjectId)
Definition: index.c:292
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:412
void index_register(Oid heap, Oid ind, IndexInfo *indexInfo)
Definition: bootstrap.c:1051
#define ereport(elevel, rest)
Definition: elog.h:122
static void AppendAttributeTuples(Relation indexRelation, int numatts)
Definition: index.c:537
#define RelationIsMapped(relation)
Definition: rel.h:458
uintptr_t Datum
Definition: postgres.h:365
void CommandCounterIncrement(void)
Definition: xact.c:914
int ii_NumIndexAttrs
Definition: execnodes.h:151
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:45
#define InvalidOid
Definition: postgres_ext.h:36
#define INDEX_CREATE_CONCURRENT
Definition: index.h:48
#define NOTICE
Definition: elog.h:37
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
bool ii_Unique
Definition: execnodes.h:164
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:396
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool ignore_self)
Definition: dependency.c:1401
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1343
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:47
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define INDEX_CREATE_PARTITIONED
Definition: index.h:50
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
MemoryContext rd_indexcxt
Definition: rel.h:151
int i
void LockRelation(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:199
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:46
#define RelationGetRelid(relation)
Definition: rel.h:407
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:74
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1225
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ index_drop()

void index_drop ( Oid  indexId,
bool  concurrent 
)

Definition at line 1443 of file index.c.

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

Referenced by doDeletion().

1444 {
1445  Oid heapId;
1446  Relation userHeapRelation;
1447  Relation userIndexRelation;
1448  Relation indexRelation;
1449  HeapTuple tuple;
1450  bool hasexprs;
1451  LockRelId heaprelid,
1452  indexrelid;
1453  LOCKTAG heaplocktag;
1454  LOCKMODE lockmode;
1455 
1456  /*
1457  * To drop an index safely, we must grab exclusive lock on its parent
1458  * table. Exclusive lock on the index alone is insufficient because
1459  * another backend might be about to execute a query on the parent table.
1460  * If it relies on a previously cached list of index OIDs, then it could
1461  * attempt to access the just-dropped index. We must therefore take a
1462  * table lock strong enough to prevent all queries on the table from
1463  * proceeding until we commit and send out a shared-cache-inval notice
1464  * that will make them update their index lists.
1465  *
1466  * In the concurrent case we avoid this requirement by disabling index use
1467  * in multiple steps and waiting out any transactions that might be using
1468  * the index, so we don't need exclusive lock on the parent table. Instead
1469  * we take ShareUpdateExclusiveLock, to ensure that two sessions aren't
1470  * doing CREATE/DROP INDEX CONCURRENTLY on the same index. (We will get
1471  * AccessExclusiveLock on the index below, once we're sure nobody else is
1472  * using it.)
1473  */
1474  heapId = IndexGetRelation(indexId, false);
1475  lockmode = concurrent ? ShareUpdateExclusiveLock : AccessExclusiveLock;
1476  userHeapRelation = heap_open(heapId, lockmode);
1477  userIndexRelation = index_open(indexId, lockmode);
1478 
1479  /*
1480  * We might still have open queries using it in our own session, which the
1481  * above locking won't prevent, so test explicitly.
1482  */
1483  CheckTableNotInUse(userIndexRelation, "DROP INDEX");
1484 
1485  /*
1486  * Drop Index Concurrently is more or less the reverse process of Create
1487  * Index Concurrently.
1488  *
1489  * First we unset indisvalid so queries starting afterwards don't use the
1490  * index to answer queries anymore. We have to keep indisready = true so
1491  * transactions that are still scanning the index can continue to see
1492  * valid index contents. For instance, if they are using READ COMMITTED
1493  * mode, and another transaction makes changes and commits, they need to
1494  * see those new tuples in the index.
1495  *
1496  * After all transactions that could possibly have used the index for
1497  * queries end, we can unset indisready and indislive, then wait till
1498  * nobody could be touching it anymore. (Note: we need indislive because
1499  * this state must be distinct from the initial state during CREATE INDEX
1500  * CONCURRENTLY, which has indislive true while indisready and indisvalid
1501  * are false. That's because in that state, transactions must examine the
1502  * index for HOT-safety decisions, while in this state we don't want them
1503  * to open it at all.)
1504  *
1505  * Since all predicate locks on the index are about to be made invalid, we
1506  * must promote them to predicate locks on the heap. In the
1507  * non-concurrent case we can just do that now. In the concurrent case
1508  * it's a bit trickier. The predicate locks must be moved when there are
1509  * no index scans in progress on the index and no more can subsequently
1510  * start, so that no new predicate locks can be made on the index. Also,
1511  * they must be moved before heap inserts stop maintaining the index, else
1512  * the conflict with the predicate lock on the index gap could be missed
1513  * before the lock on the heap relation is in place to detect a conflict
1514  * based on the heap tuple insert.
1515  */
1516  if (concurrent)
1517  {
1518  /*
1519  * We must commit our transaction in order to make the first pg_index
1520  * state update visible to other sessions. If the DROP machinery has
1521  * already performed any other actions (removal of other objects,
1522  * pg_depend entries, etc), the commit would make those actions
1523  * permanent, which would leave us with inconsistent catalog state if
1524  * we fail partway through the following sequence. Since DROP INDEX
1525  * CONCURRENTLY is restricted to dropping just one index that has no
1526  * dependencies, we should get here before anything's been done ---
1527  * but let's check that to be sure. We can verify that the current
1528  * transaction has not executed any transactional updates by checking
1529  * that no XID has been assigned.
1530  */
1532  ereport(ERROR,
1533  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1534  errmsg("DROP INDEX CONCURRENTLY must be first action in transaction")));
1535 
1536  /*
1537  * Mark index invalid by updating its pg_index entry
1538  */
1540 
1541  /*
1542  * Invalidate the relcache for the table, so that after this commit
1543  * all sessions will refresh any cached plans that might reference the
1544  * index.
1545  */
1546  CacheInvalidateRelcache(userHeapRelation);
1547 
1548  /* save lockrelid and locktag for below, then close but keep locks */
1549  heaprelid = userHeapRelation->rd_lockInfo.lockRelId;
1550  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1551  indexrelid = userIndexRelation->rd_lockInfo.lockRelId;
1552 
1553  heap_close(userHeapRelation, NoLock);
1554  index_close(userIndexRelation, NoLock);
1555 
1556  /*
1557  * We must commit our current transaction so that the indisvalid
1558  * update becomes visible to other transactions; then start another.
1559  * Note that any previously-built data structures are lost in the
1560  * commit. The only data we keep past here are the relation IDs.
1561  *
1562  * Before committing, get a session-level lock on the table, to ensure
1563  * that neither it nor the index can be dropped before we finish. This
1564  * cannot block, even if someone else is waiting for access, because
1565  * we already have the same lock within our transaction.
1566  */
1569 
1573 
1574  /*
1575  * Now we must wait until no running transaction could be using the
1576  * index for a query. Use AccessExclusiveLock here to check for
1577  * running transactions that hold locks of any kind on the table. Note
1578  * we do not need to worry about xacts that open the table for reading
1579  * after this point; they will see the index as invalid when they open
1580  * the relation.
1581  *
1582  * Note: the reason we use actual lock acquisition here, rather than
1583  * just checking the ProcArray and sleeping, is that deadlock is
1584  * possible if one of the transactions in question is blocked trying
1585  * to acquire an exclusive lock on our table. The lock code will
1586  * detect deadlock and error out properly.
1587  */
1588  WaitForLockers(heaplocktag, AccessExclusiveLock);
1589 
1590  /*
1591  * No more predicate locks will be acquired on this index, and we're
1592  * about to stop doing inserts into the index which could show
1593  * conflicts with existing predicate locks, so now is the time to move
1594  * them to the heap relation.
1595  */
1596  userHeapRelation = heap_open(heapId, ShareUpdateExclusiveLock);
1597  userIndexRelation = index_open(indexId, ShareUpdateExclusiveLock);
1598  TransferPredicateLocksToHeapRelation(userIndexRelation);
1599 
1600  /*
1601  * Now we are sure that nobody uses the index for queries; they just
1602  * might have it open for updating it. So now we can unset indisready
1603  * and indislive, then wait till nobody could be using it at all
1604  * anymore.
1605  */
1607 
1608  /*
1609  * Invalidate the relcache for the table, so that after this commit
1610  * all sessions will refresh the table's index list. Forgetting just
1611  * the index's relcache entry is not enough.
1612  */
1613  CacheInvalidateRelcache(userHeapRelation);
1614 
1615  /*
1616  * Close the relations again, though still holding session lock.
1617  */
1618  heap_close(userHeapRelation, NoLock);
1619  index_close(userIndexRelation, NoLock);
1620 
1621  /*
1622  * Again, commit the transaction to make the pg_index update visible
1623  * to other sessions.
1624  */
1627 
1628  /*
1629  * Wait till every transaction that saw the old index state has
1630  * finished.
1631  */
1632  WaitForLockers(heaplocktag, AccessExclusiveLock);
1633 
1634  /*
1635  * Re-open relations to allow us to complete our actions.
1636  *
1637  * At this point, nothing should be accessing the index, but lets
1638  * leave nothing to chance and grab AccessExclusiveLock on the index
1639  * before the physical deletion.
1640  */
1641  userHeapRelation = heap_open(heapId, ShareUpdateExclusiveLock);
1642  userIndexRelation = index_open(indexId, AccessExclusiveLock);
1643  }
1644  else
1645  {
1646  /* Not concurrent, so just transfer predicate locks and we're good */
1647  TransferPredicateLocksToHeapRelation(userIndexRelation);
1648  }
1649 
1650  /*
1651  * Schedule physical removal of the files (if any)
1652  */
1653  if (userIndexRelation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
1654  RelationDropStorage(userIndexRelation);
1655 
1656  /*
1657  * Close and flush the index's relcache entry, to ensure relcache doesn't
1658  * try to rebuild it while we're deleting catalog entries. We keep the
1659  * lock though.
1660  */
1661  index_close(userIndexRelation, NoLock);
1662 
1663  RelationForgetRelation(indexId);
1664 
1665  /*
1666  * fix INDEX relation, and check for expressional index
1667  */
1668  indexRelation = heap_open(IndexRelationId, RowExclusiveLock);
1669 
1670  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
1671  if (!HeapTupleIsValid(tuple))
1672  elog(ERROR, "cache lookup failed for index %u", indexId);
1673 
1674  hasexprs = !heap_attisnull(tuple, Anum_pg_index_indexprs,
1675  RelationGetDescr(indexRelation));
1676 
1677  CatalogTupleDelete(indexRelation, &tuple->t_self);
1678 
1679  ReleaseSysCache(tuple);
1680  heap_close(indexRelation, RowExclusiveLock);
1681 
1682  /*
1683  * if it has any expression columns, we might have stored statistics about
1684  * them.
1685  */
1686  if (hasexprs)
1687  RemoveStatistics(indexId, 0);
1688 
1689  /*
1690  * fix ATTRIBUTE relation
1691  */
1692  DeleteAttributeTuples(indexId);
1693 
1694  /*
1695  * fix RELATION relation
1696  */
1697  DeleteRelationTuple(indexId);
1698 
1699  /*
1700  * fix INHERITS relation
1701  */
1702  DeleteInheritsTuple(indexId, InvalidOid);
1703 
1704  /*
1705  * We are presently too lazy to attempt to compute the new correct value
1706  * of relhasindex (the next VACUUM will fix it if necessary). So there is
1707  * no need to update the pg_class tuple for the owning relation. But we
1708  * must send out a shared-cache-inval notice on the owning relation to
1709  * ensure other backends update their relcache lists of indexes. (In the
1710  * concurrent case, this is redundant but harmless.)
1711  */
1712  CacheInvalidateRelcache(userHeapRelation);
1713 
1714  /*
1715  * Close owning rel, but keep lock
1716  */
1717  heap_close(userHeapRelation, NoLock);
1718 
1719  /*
1720  * Release the session locks before we go.
1721  */
1722  if (concurrent)
1723  {
1726  }
1727 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3591
LockRelId lockRelId
Definition: rel.h:44
#define RelationGetDescr(relation)
Definition: rel.h:433
int LOCKMODE
Definition: lockdefs.h:26
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3512
void CommitTransactionCommand(void)
Definition: xact.c:2744
Oid dbId
Definition: rel.h:39
Definition: lock.h:178
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent)
Definition: pg_inherits.c:449
int errcode(int sqlerrcode)
Definition: elog.c:575
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
void RelationForgetRelation(Oid rid)
Definition: relcache.c:2525
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:256
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:312
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Definition: rel.h:36
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:299
ItemPointerData t_self
Definition: htup.h:65
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:193
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:87
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3208
#define ereport(elevel, rest)
Definition: elog.h:122
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3044
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void RelationDropStorage(Relation rel)
Definition: storage.c:144
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode)
Definition: lmgr.c:837
#define InvalidOid
Definition: postgres_ext.h:36
void DeleteRelationTuple(Oid relid)
Definition: heap.c:1445
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void StartTransactionCommand(void)
Definition: xact.c:2673
void DeleteAttributeTuples(Oid relid)
Definition: heap.c:1474
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:2928
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
Oid relId
Definition: rel.h:38

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3512 of file index.c.

References Assert, elog, ERROR, GETSTRUCT, GetTopTransactionIdIfAny(), heap_close, heap_inplace_update(), heap_open(), HeapTupleIsValid, INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_DROP_CLEAR_VALID, INDEX_DROP_SET_DEAD, INDEXRELID, InvalidTransactionId, ObjectIdGetDatum, RowExclusiveLock, and SearchSysCacheCopy1.

Referenced by DefineIndex(), and index_drop().

3513 {
3514  Relation pg_index;
3515  HeapTuple indexTuple;
3516  Form_pg_index indexForm;
3517 
3518  /* Assert that current xact hasn't done any transactional updates */
3520 
3521  /* Open pg_index and fetch a writable copy of the index's tuple */
3522  pg_index = heap_open(IndexRelationId, RowExclusiveLock);
3523 
3524  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3525  ObjectIdGetDatum(indexId));
3526  if (!HeapTupleIsValid(indexTuple))
3527  elog(ERROR, "cache lookup failed for index %u", indexId);
3528  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3529 
3530  /* Perform the requested state change on the copy */
3531  switch (action)
3532  {
3534  /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3535  Assert(indexForm->indislive);
3536  Assert(!indexForm->indisready);
3537  Assert(!indexForm->indisvalid);
3538  indexForm->indisready = true;
3539  break;
3541  /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3542  Assert(indexForm->indislive);
3543  Assert(indexForm->indisready);
3544  Assert(!indexForm->indisvalid);
3545  indexForm->indisvalid = true;
3546  break;
3548 
3549  /*
3550  * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3551  *
3552  * If indisready == true we leave it set so the index still gets
3553  * maintained by active transactions. We only need to ensure that
3554  * indisvalid is false. (We don't assert that either is initially
3555  * true, though, since we want to be able to retry a DROP INDEX
3556  * CONCURRENTLY that failed partway through.)
3557  *
3558  * Note: the CLUSTER logic assumes that indisclustered cannot be
3559  * set on any invalid index, so clear that flag too.
3560  */
3561  indexForm->indisvalid = false;
3562  indexForm->indisclustered = false;
3563  break;
3564  case INDEX_DROP_SET_DEAD:
3565 
3566  /*
3567  * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3568  *
3569  * We clear both indisready and indislive, because we not only
3570  * want to stop updates, we want to prevent sessions from touching
3571  * the index at all.
3572  */
3573  Assert(!indexForm->indisvalid);
3574  indexForm->indisready = false;
3575  indexForm->indislive = false;
3576  break;
3577  }
3578 
3579  /* ... and write it back in-place */
3580  heap_inplace_update(pg_index, indexTuple);
3581 
3582  heap_close(pg_index, RowExclusiveLock);
3583 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define heap_close(r, l)
Definition: heapam.h:97
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6387
#define elog
Definition: elog.h:219

◆ index_update_stats()

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

Definition at line 2077 of file index.c.

References Assert, BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), elog, ERROR, ForwardScanDirection, GETSTRUCT, heap_beginscan_catalog(), heap_close, heap_copytuple(), heap_endscan(), heap_freetuple(), heap_getnext(), heap_inplace_update(), heap_open(), HeapTupleIsValid, IsBootstrapProcessingMode, ObjectIdAttributeNumber, ObjectIdGetDatum, ReindexIsProcessingHeap(), relallvisible, RelationGetNumberOfBlocks, RelationGetRelid, RELOID, relpages, reltuples, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, and visibilitymap_count().

Referenced by index_build(), and index_create().

2080 {
2081  Oid relid = RelationGetRelid(rel);
2082  Relation pg_class;
2083  HeapTuple tuple;
2084  Form_pg_class rd_rel;
2085  bool dirty;
2086 
2087  /*
2088  * We always update the pg_class row using a non-transactional,
2089  * overwrite-in-place update. There are several reasons for this:
2090  *
2091  * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work.
2092  *
2093  * 2. We could be reindexing pg_class itself, in which case we can't move
2094  * its pg_class row because CatalogTupleInsert/CatalogTupleUpdate might
2095  * not know about all the indexes yet (see reindex_relation).
2096  *
2097  * 3. Because we execute CREATE INDEX with just share lock on the parent
2098  * rel (to allow concurrent index creations), an ordinary update could
2099  * suffer a tuple-concurrently-updated failure against another CREATE
2100  * INDEX committing at about the same time. We can avoid that by having
2101  * them both do nontransactional updates (we assume they will both be
2102  * trying to change the pg_class row to the same thing, so it doesn't
2103  * matter which goes first).
2104  *
2105  * It is safe to use a non-transactional update even though our
2106  * transaction could still fail before committing. Setting relhasindex
2107  * true is safe even if there are no indexes (VACUUM will eventually fix
2108  * it). And of course the new relpages and
2109  * reltuples counts are correct regardless. However, we don't want to
2110  * change relpages (or relallvisible) if the caller isn't providing an
2111  * updated reltuples count, because that would bollix the
2112  * reltuples/relpages ratio which is what's really important.
2113  */
2114 
2115  pg_class = heap_open(RelationRelationId, RowExclusiveLock);
2116 
2117  /*
2118  * Make a copy of the tuple to update. Normally we use the syscache, but
2119  * we can't rely on that during bootstrap or while reindexing pg_class
2120  * itself.
2121  */
2122  if (IsBootstrapProcessingMode() ||
2123  ReindexIsProcessingHeap(RelationRelationId))
2124  {
2125  /* don't assume syscache will work */
2126  HeapScanDesc pg_class_scan;
2127  ScanKeyData key[1];
2128 
2129  ScanKeyInit(&key[0],
2131  BTEqualStrategyNumber, F_OIDEQ,
2132  ObjectIdGetDatum(relid));
2133 
2134  pg_class_scan = heap_beginscan_catalog(pg_class, 1, key);
2135  tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
2136  tuple = heap_copytuple(tuple);
2137  heap_endscan(pg_class_scan);
2138  }
2139  else
2140  {
2141  /* normal case, use syscache */
2142  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
2143  }
2144 
2145  if (!HeapTupleIsValid(tuple))
2146  elog(ERROR, "could not find tuple for relation %u", relid);
2147  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
2148 
2149  /* Should this be a more comprehensive test? */
2150  Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
2151 
2152  /* Apply required updates, if any, to copied tuple */
2153 
2154  dirty = false;
2155  if (rd_rel->relhasindex != hasindex)
2156  {
2157  rd_rel->relhasindex = hasindex;
2158  dirty = true;
2159  }
2160 
2161  if (reltuples >= 0)
2162  {
2165 
2166  if (rd_rel->relkind != RELKIND_INDEX)
2167  visibilitymap_count(rel, &relallvisible, NULL);
2168  else /* don't bother for indexes */
2169  relallvisible = 0;
2170 
2171  if (rd_rel->relpages != (int32) relpages)
2172  {
2173  rd_rel->relpages = (int32) relpages;
2174  dirty = true;
2175  }
2176  if (rd_rel->reltuples != (float4) reltuples)
2177  {
2178  rd_rel->reltuples = (float4) reltuples;
2179  dirty = true;
2180  }
2181  if (rd_rel->relallvisible != (int32) relallvisible)
2182  {
2183  rd_rel->relallvisible = (int32) relallvisible;
2184  dirty = true;
2185  }
2186  }
2187 
2188  /*
2189  * If anything changed, write out the tuple
2190  */
2191  if (dirty)
2192  {
2193  heap_inplace_update(pg_class, tuple);
2194  /* the above sends a cache inval message */
2195  }
2196  else
2197  {
2198  /* no need to change tuple, but force relcache inval anyway */
2200  }
2201 
2202  heap_freetuple(tuple);
2203 
2204  heap_close(pg_class, RowExclusiveLock);
2205 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
int32 relallvisible
Definition: pg_class.h:45
uint32 BlockNumber
Definition: block.h:31
#define heap_close(r, l)
Definition: heapam.h:97
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
int32 relpages
Definition: pg_class.h:43
signed int int32
Definition: c.h:313
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
bool ReindexIsProcessingHeap(Oid heapOid)
Definition: index.c:4001
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1412
float float4
Definition: c.h:457
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6387
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1269
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407
float4 reltuples
Definition: pg_class.h:44
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ IndexBuildHeapRangeScan()

double IndexBuildHeapRangeScan ( Relation  heapRelation,
Relation  indexRelation,
IndexInfo indexInfo,
bool  allow_sync,
bool  anyvisible,
BlockNumber  start_blockno,
BlockNumber  numblocks,
IndexBuildCallback  callback,
void *  callback_state,
HeapScanDesc  scan 
)

Definition at line 2444 of file index.c.

References Assert, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, callback(), CHECK_FOR_INTERRUPTS, CreateExecutorState(), ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, elog, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, ExecDropSingleTupleTableSlot(), ExecPrepareQual(), ExecQual(), ExecStoreTuple(), FormIndexDatum(), ForwardScanDirection, FreeExecutorState(), GetOldestXmin(), GetPerTupleExprContext, GetTransactionSnapshot(), heap_beginscan_strat(), heap_endscan(), heap_get_root_tuples(), heap_getnext(), heap_setscanlimits(), HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleIsHeapOnly, HeapTupleIsHotUpdated, HeapTupleSatisfiesVacuum(), IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExpressionsState, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_Unique, INDEX_MAX_KEYS, InvalidBlockNumber, InvalidBuffer, InvalidTransactionId, IsBootstrapProcessingMode, IsMVCCSnapshot, IsSystemRelation(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerSetOffsetNumber, LockBuffer(), MakeSingleTupleTableSlot(), MaxHeapTuplesPerPage, MemoryContextReset(), NIL, OffsetNumberIsValid, OidIsValid, OldestXmin, PROCARRAY_FLAGS_VACUUM, RelationData::rd_rel, RegisterSnapshot(), RelationGetDescr, RelationGetRelationName, reltuples, HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_snapshot, SnapshotAny, HeapTupleData::t_data, HeapTupleData::t_self, TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, UnregisterSnapshot(), values, WARNING, XactLockTableWait(), and XLTW_InsertIndexUnique.

Referenced by IndexBuildHeapScan(), and summarize_range().

2454 {
2455  bool is_system_catalog;
2456  bool checking_uniqueness;
2457  HeapTuple heapTuple;
2459  bool isnull[INDEX_MAX_KEYS];
2460  double reltuples;
2461  ExprState *predicate;
2462  TupleTableSlot *slot;
2463  EState *estate;
2464  ExprContext *econtext;
2465  Snapshot snapshot;
2466  bool need_unregister_snapshot = false;
2468  BlockNumber root_blkno = InvalidBlockNumber;
2469  OffsetNumber root_offsets[MaxHeapTuplesPerPage];
2470 
2471  /*
2472  * sanity checks
2473  */
2474  Assert(OidIsValid(indexRelation->rd_rel->relam));
2475 
2476  /* Remember if it's a system catalog */
2477  is_system_catalog = IsSystemRelation(heapRelation);
2478 
2479  /* See whether we're verifying uniqueness/exclusion properties */
2480  checking_uniqueness = (indexInfo->ii_Unique ||
2481  indexInfo->ii_ExclusionOps != NULL);
2482 
2483  /*
2484  * "Any visible" mode is not compatible with uniqueness checks; make sure
2485  * only one of those is requested.
2486  */
2487  Assert(!(anyvisible && checking_uniqueness));
2488 
2489  /*
2490  * Need an EState for evaluation of index expressions and partial-index
2491  * predicates. Also a slot to hold the current tuple.
2492  */
2493  estate = CreateExecutorState();
2494  econtext = GetPerTupleExprContext(estate);
2495  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
2496 
2497  /* Arrange for econtext's scan tuple to be the tuple under test */
2498  econtext->ecxt_scantuple = slot;
2499 
2500  /* Set up execution state for predicate, if any. */
2501  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
2502 
2503  /*
2504  * Prepare for scan of the base relation. In a normal index build, we use
2505  * SnapshotAny because we must retrieve all tuples and do our own time
2506  * qual checks (because we have to index RECENTLY_DEAD tuples). In a
2507  * concurrent build, or during bootstrap, we take a regular MVCC snapshot
2508  * and index whatever's live according to that.
2509  */
2510  OldestXmin = InvalidTransactionId;
2511 
2512  /* okay to ignore lazy VACUUMs here */
2513  if (!IsBootstrapProcessingMode() && !indexInfo->ii_Concurrent)
2514  OldestXmin = GetOldestXmin(heapRelation, PROCARRAY_FLAGS_VACUUM);
2515 
2516  if (!scan)
2517  {
2518  /*
2519  * Serial index build.
2520  *
2521  * Must begin our own heap scan in this case. We may also need to
2522  * register a snapshot whose lifetime is under our direct control.
2523  */
2524  if (!TransactionIdIsValid(OldestXmin))
2525  {
2527  need_unregister_snapshot = true;
2528  }
2529  else
2530  snapshot = SnapshotAny;
2531 
2532  scan = heap_beginscan_strat(heapRelation, /* relation */
2533  snapshot, /* snapshot */
2534  0, /* number of keys */
2535  NULL, /* scan key */
2536  true, /* buffer access strategy OK */
2537  allow_sync); /* syncscan OK? */
2538  }
2539  else
2540  {
2541  /*
2542  * Parallel index build.
2543  *
2544  * Parallel case never registers/unregisters own snapshot. Snapshot
2545  * is taken from parallel heap scan, and is SnapshotAny or an MVCC
2546  * snapshot, based on same criteria as serial case.
2547  */
2549  Assert(allow_sync);
2550  snapshot = scan->rs_snapshot;
2551  }
2552 
2553  /*
2554  * Must call GetOldestXmin() with SnapshotAny. Should never call
2555  * GetOldestXmin() with MVCC snapshot. (It's especially worth checking
2556  * this for parallel builds, since ambuild routines that support parallel
2557  * builds must work these details out for themselves.)
2558  */
2559  Assert(snapshot == SnapshotAny || IsMVCCSnapshot(snapshot));
2560  Assert(snapshot == SnapshotAny ? TransactionIdIsValid(OldestXmin) :
2561  !TransactionIdIsValid(OldestXmin));
2562  Assert(snapshot == SnapshotAny || !anyvisible);
2563 
2564  /* set our scan endpoints */
2565  if (!allow_sync)
2566  heap_setscanlimits(scan, start_blockno, numblocks);
2567  else
2568  {
2569  /* syncscan can only be requested on whole relation */
2570  Assert(start_blockno == 0);
2571  Assert(numblocks == InvalidBlockNumber);
2572  }
2573 
2574  reltuples = 0;
2575 
2576  /*
2577  * Scan all tuples in the base relation.
2578  */
2579  while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2580  {
2581  bool tupleIsAlive;
2582 
2584 
2585  /*
2586  * When dealing with a HOT-chain of updated tuples, we want to index
2587  * the values of the live tuple (if any), but index it under the TID
2588  * of the chain's root tuple. This approach is necessary to preserve
2589  * the HOT-chain structure in the heap. So we need to be able to find
2590  * the root item offset for every tuple that's in a HOT-chain. When
2591  * first reaching a new page of the relation, call
2592  * heap_get_root_tuples() to build a map of root item offsets on the
2593  * page.
2594  *
2595  * It might look unsafe to use this information across buffer
2596  * lock/unlock. However, we hold ShareLock on the table so no
2597  * ordinary insert/update/delete should occur; and we hold pin on the
2598  * buffer continuously while visiting the page, so no pruning
2599  * operation can occur either.
2600  *
2601  * Also, although our opinions about tuple liveness could change while
2602  * we scan the page (due to concurrent transaction commits/aborts),
2603  * the chain root locations won't, so this info doesn't need to be
2604  * rebuilt after waiting for another transaction.
2605  *
2606  * Note the implied assumption that there is no more than one live
2607  * tuple per HOT-chain --- else we could create more than one index
2608  * entry pointing to the same root tuple.
2609  */
2610  if (scan->rs_cblock != root_blkno)
2611  {
2612  Page page = BufferGetPage(scan->rs_cbuf);
2613 
2615  heap_get_root_tuples(page, root_offsets);
2617 
2618  root_blkno = scan->rs_cblock;
2619  }
2620 
2621  if (snapshot == SnapshotAny)
2622  {
2623  /* do our own time qual check */
2624  bool indexIt;
2625  TransactionId xwait;
2626 
2627  recheck:
2628 
2629  /*
2630  * We could possibly get away with not locking the buffer here,
2631  * since caller should hold ShareLock on the relation, but let's
2632  * be conservative about it. (This remark is still correct even
2633  * with HOT-pruning: our pin on the buffer prevents pruning.)
2634  */
2636 
2637  /*
2638  * The criteria for counting a tuple as live in this block need to
2639  * match what analyze.c's acquire_sample_rows() does, otherwise
2640  * CREATE INDEX and ANALYZE may produce wildly different reltuples
2641  * values, e.g. when there are many recently-dead tuples.
2642  */
2643  switch (HeapTupleSatisfiesVacuum(heapTuple, OldestXmin,
2644  scan->rs_cbuf))
2645  {
2646  case HEAPTUPLE_DEAD:
2647  /* Definitely dead, we can ignore it */
2648  indexIt = false;
2649  tupleIsAlive = false;
2650  break;
2651  case HEAPTUPLE_LIVE:
2652  /* Normal case, index and unique-check it */
2653  indexIt = true;
2654  tupleIsAlive = true;
2655  /* Count it as live, too */
2656  reltuples += 1;
2657  break;
2659 
2660  /*
2661  * If tuple is recently deleted then we must index it
2662  * anyway to preserve MVCC semantics. (Pre-existing
2663  * transactions could try to use the index after we finish
2664  * building it, and may need to see such tuples.)
2665  *
2666  * However, if it was HOT-updated then we must only index
2667  * the live tuple at the end of the HOT-chain. Since this
2668  * breaks semantics for pre-existing snapshots, mark the
2669  * index as unusable for them.
2670  *
2671  * We don't count recently-dead tuples in reltuples, even
2672  * if we index them; see acquire_sample_rows().
2673  */
2674  if (HeapTupleIsHotUpdated(heapTuple))
2675  {
2676  indexIt = false;
2677  /* mark the index as unsafe for old snapshots */
2678  indexInfo->ii_BrokenHotChain = true;
2679  }
2680  else
2681  indexIt = true;
2682  /* In any case, exclude the tuple from unique-checking */
2683  tupleIsAlive = false;
2684  break;
2686 
2687  /*
2688  * In "anyvisible" mode, this tuple is visible and we
2689  * don't need any further checks.
2690  */
2691  if (anyvisible)
2692  {
2693  indexIt = true;
2694  tupleIsAlive = true;
2695  reltuples += 1;
2696  break;
2697  }
2698 
2699  /*
2700  * Since caller should hold ShareLock or better, normally
2701  * the only way to see this is if it was inserted earlier
2702  * in our own transaction. However, it can happen in
2703  * system catalogs, since we tend to release write lock
2704  * before commit there. Give a warning if neither case
2705  * applies.
2706  */
2707  xwait = HeapTupleHeaderGetXmin(heapTuple->t_data);
2709  {
2710  if (!is_system_catalog)
2711  elog(WARNING, "concurrent insert in progress within table \"%s\"",
2712  RelationGetRelationName(heapRelation));
2713 
2714  /*
2715  * If we are performing uniqueness checks, indexing
2716  * such a tuple could lead to a bogus uniqueness
2717  * failure. In that case we wait for the inserting
2718  * transaction to finish and check again.
2719  */
2720  if (checking_uniqueness)
2721  {
2722  /*
2723  * Must drop the lock on the buffer before we wait
2724  */
2726  XactLockTableWait(xwait, heapRelation,
2727  &heapTuple->t_self,
2730  goto recheck;
2731  }
2732  }
2733  else
2734  {
2735  /*
2736  * For consistency with acquire_sample_rows(), count
2737  * HEAPTUPLE_INSERT_IN_PROGRESS tuples as live only
2738  * when inserted by our own transaction.
2739  */
2740  reltuples += 1;
2741  }
2742 
2743  /*
2744  * We must index such tuples, since if the index build
2745  * commits then they're good.
2746  */
2747  indexIt = true;
2748  tupleIsAlive = true;
2749  break;
2751 
2752  /*
2753  * As with INSERT_IN_PROGRESS case, this is unexpected
2754  * unless it's our own deletion or a system catalog; but
2755  * in anyvisible mode, this tuple is visible.
2756  */
2757  if (anyvisible)
2758  {
2759  indexIt = true;
2760  tupleIsAlive = false;
2761  reltuples += 1;
2762  break;
2763  }
2764 
2765  xwait = HeapTupleHeaderGetUpdateXid(heapTuple->t_data);
2767  {
2768  if (!is_system_catalog)
2769  elog(WARNING, "concurrent delete in progress within table \"%s\"",
2770  RelationGetRelationName(heapRelation));
2771 
2772  /*
2773  * If we are performing uniqueness checks, assuming
2774  * the tuple is dead could lead to missing a
2775  * uniqueness violation. In that case we wait for the
2776  * deleting transaction to finish and check again.
2777  *
2778  * Also, if it's a HOT-updated tuple, we should not
2779  * index it but rather the live tuple at the end of
2780  * the HOT-chain. However, the deleting transaction
2781  * could abort, possibly leaving this tuple as live
2782  * after all, in which case it has to be indexed. The
2783  * only way to know what to do is to wait for the
2784  * deleting transaction to finish and check again.
2785  */
2786  if (checking_uniqueness ||
2787  HeapTupleIsHotUpdated(heapTuple))
2788  {
2789  /*
2790  * Must drop the lock on the buffer before we wait
2791  */
2793  XactLockTableWait(xwait, heapRelation,
2794  &heapTuple->t_self,
2797  goto recheck;
2798  }
2799 
2800  /*
2801  * Otherwise index it but don't check for uniqueness,
2802  * the same as a RECENTLY_DEAD tuple.
2803  */
2804  indexIt = true;
2805 
2806  /*
2807  * Count HEAPTUPLE_DELETE_IN_PROGRESS tuples as live,
2808  * if they were not deleted by the current
2809  * transaction. That's what acquire_sample_rows()
2810  * does, and we want the behavior to be consistent.
2811  */
2812  reltuples += 1;
2813  }
2814  else if (HeapTupleIsHotUpdated(heapTuple))
2815  {
2816  /*
2817  * It's a HOT-updated tuple deleted by our own xact.
2818  * We can assume the deletion will commit (else the
2819  * index contents don't matter), so treat the same as
2820  * RECENTLY_DEAD HOT-updated tuples.
2821  */
2822  indexIt = false;
2823  /* mark the index as unsafe for old snapshots */
2824  indexInfo->ii_BrokenHotChain = true;
2825  }
2826  else
2827  {
2828  /*
2829  * It's a regular tuple deleted by our own xact. Index
2830  * it, but don't check for uniqueness nor count in
2831  * reltuples, the same as a RECENTLY_DEAD tuple.
2832  */
2833  indexIt = true;
2834  }
2835  /* In any case, exclude the tuple from unique-checking */
2836  tupleIsAlive = false;
2837  break;
2838  default:
2839  elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
2840  indexIt = tupleIsAlive = false; /* keep compiler quiet */
2841  break;
2842  }
2843 
2845 
2846  if (!indexIt)
2847  continue;
2848  }
2849  else
2850  {
2851  /* heap_getnext did the time qual check */
2852  tupleIsAlive = true;
2853  }
2854 
2856 
2857  /* Set up for predicate or expression evaluation */
2858  ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
2859 
2860  /*
2861  * In a partial index, discard tuples that don't satisfy the
2862  * predicate.
2863  */
2864  if (predicate != NULL)
2865  {
2866  if (!ExecQual(predicate, econtext))
2867  continue;
2868  }
2869 
2870  /*
2871  * For the current heap tuple, extract all the attributes we use in
2872  * this index, and note which are null. This also performs evaluation
2873  * of any expressions needed.
2874  */
2875  FormIndexDatum(indexInfo,
2876  slot,
2877  estate,
2878  values,
2879  isnull);
2880 
2881  /*
2882  * You'd think we should go ahead and build the index tuple here, but
2883  * some index AMs want to do further processing on the data first. So
2884  * pass the values[] and isnull[] arrays, instead.
2885  */
2886 
2887  if (HeapTupleIsHeapOnly(heapTuple))
2888  {
2889  /*
2890  * For a heap-only tuple, pretend its TID is that of the root. See
2891  * src/backend/access/heap/README.HOT for discussion.
2892  */
2893  HeapTupleData rootTuple;
2894  OffsetNumber offnum;
2895 
2896  rootTuple = *heapTuple;
2897  offnum = ItemPointerGetOffsetNumber(&heapTuple->t_self);
2898 
2899  if (!OffsetNumberIsValid(root_offsets[offnum - 1]))
2900  ereport(ERROR,
2902  errmsg_internal("failed to find parent tuple for heap-only tuple at (%u,%u) in table \"%s\"",
2903  ItemPointerGetBlockNumber(&heapTuple->t_self),
2904  offnum,
2905  RelationGetRelationName(heapRelation))));
2906 
2908  root_offsets[offnum - 1]);
2909 
2910  /* Call the AM's callback routine to process the tuple */
2911  callback(indexRelation, &rootTuple, values, isnull, tupleIsAlive,
2912  callback_state);
2913  }
2914  else
2915  {
2916  /* Call the AM's callback routine to process the tuple */
2917  callback(indexRelation, heapTuple, values, isnull, tupleIsAlive,
2918  callback_state);
2919  }
2920  }
2921 
2922  heap_endscan(scan);
2923 
2924  /* we can now forget our snapshot, if set and registered by us */
2925  if (need_unregister_snapshot)
2926  UnregisterSnapshot(snapshot);
2927 
2929 
2930  FreeExecutorState(estate);
2931 
2932  /* These may have been pointing to the now-gone estate */
2933  indexInfo->ii_ExpressionsState = NIL;
2934  indexInfo->ii_PredicateState = NULL;
2935 
2936  return reltuples;
2937 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:370
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2000
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
BlockNumber rs_cblock
Definition: relscan.h:71
List * ii_Predicate
Definition: execnodes.h:156
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
uint32 TransactionId
Definition: c.h:474
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:433
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:765
ExprState * ii_PredicateState
Definition: execnodes.h:157
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:226
#define MaxHeapTuplesPerPage
Definition: htup_details.h:592
#define InvalidBuffer
Definition: buf.h:25
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
Definition: tqual.c:1164
int errcode(int sqlerrcode)
Definition: elog.c:575
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
#define PROCARRAY_FLAGS_VACUUM
Definition: procarray.h:52
Form_pg_class rd_rel
Definition: rel.h:84
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:361
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
#define OidIsValid(objectId)
Definition: c.h:605
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
void FreeExecutorState(EState *estate)
Definition: execUtils.c:188
#define HeapTupleIsHotUpdated(tuple)
Definition: htup_details.h:694
#define GetPerTupleExprContext(estate)
Definition: executor.h:489
List * ii_ExpressionsState
Definition: execnodes.h:155
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:247
Snapshot rs_snapshot
Definition: relscan.h:50
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:441
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:516
static TransactionId OldestXmin
Definition: vacuumlazy.c:146
bool ii_BrokenHotChain
Definition: execnodes.h:167
void heap_setscanlimits(HeapScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
Definition: heapam.c:331
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:232
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void heap_get_root_tuples(Page page, OffsetNumber *root_offsets)
Definition: pruneheap.c:746
#define ereport(elevel, rest)
Definition: elog.h:122
EState * CreateExecutorState(void)
Definition: execUtils.c:80
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:43
#define WARNING
Definition: elog.h:40
uintptr_t Datum
Definition: postgres.h:365
#define SnapshotAny
Definition: tqual.h:28
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
TransactionId GetOldestXmin(Relation rel, int flags)
Definition: procarray.c:1315
HeapScanDesc heap_beginscan_strat(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync)
Definition: heapam.c:1422
Buffer rs_cbuf
Definition: relscan.h:72
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
bool ii_Unique
Definition: execnodes.h:164
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:703
#define Assert(condition)
Definition: c.h:699
#define IsMVCCSnapshot(snapshot)
Definition: tqual.h:31
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:318
#define INDEX_MAX_KEYS
#define InvalidBlockNumber
Definition: block.h:33
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:218
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:95
bool ii_Concurrent
Definition: execnodes.h:166
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:126
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
Oid * ii_ExclusionOps
Definition: execnodes.h:158
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:40
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76
#define TransactionIdIsValid(xid)
Definition: transam.h:41
float4 reltuples
Definition: pg_class.h:44
Pointer Page
Definition: bufpage.h:74

◆ IndexBuildHeapScan()

double IndexBuildHeapScan ( Relation  heapRelation,
Relation  indexRelation,
IndexInfo indexInfo,
bool  allow_sync,
IndexBuildCallback  callback,
void *  callback_state,
HeapScanDesc  scan 
)

Definition at line 2418 of file index.c.

References IndexBuildHeapRangeScan(), and InvalidBlockNumber.

Referenced by _bt_parallel_scan_and_sort(), _bt_spools_heapscan(), blbuild(), brinbuild(), bt_check_every_level(), ginbuild(), gistbuild(), hashbuild(), and spgbuild().

2425 {
2426  return IndexBuildHeapRangeScan(heapRelation, indexRelation,
2427  indexInfo, allow_sync,
2428  false,
2429  0, InvalidBlockNumber,
2430  callback, callback_state, scan);
2431 }
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
double IndexBuildHeapRangeScan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, bool anyvisible, BlockNumber start_blockno, BlockNumber numblocks, IndexBuildCallback callback, void *callback_state, HeapScanDesc scan)
Definition: index.c:2444
#define InvalidBlockNumber
Definition: block.h:33

◆ IndexCheckExclusion()

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

Definition at line 2953 of file index.c.

References check_exclusion_constraint(), CHECK_FOR_INTERRUPTS, CreateExecutorState(), ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, ExecDropSingleTupleTableSlot(), ExecPrepareQual(), ExecQual(), ExecStoreTuple(), FormIndexDatum(), ForwardScanDirection, FreeExecutorState(), GetLatestSnapshot(), GetPerTupleExprContext, heap_beginscan_strat(), heap_endscan(), heap_getnext(), IndexInfo::ii_ExpressionsState, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, INDEX_MAX_KEYS, InvalidBuffer, MakeSingleTupleTableSlot(), MemoryContextReset(), NIL, RegisterSnapshot(), ReindexIsCurrentlyProcessingIndex(), RelationGetDescr, RelationGetRelid, ResetReindexProcessing(), HeapTupleData::t_self, UnregisterSnapshot(), and values.

Referenced by index_build().

2956 {
2957  HeapScanDesc scan;
2958  HeapTuple heapTuple;
2960  bool isnull[INDEX_MAX_KEYS];
2961  ExprState *predicate;
2962  TupleTableSlot *slot;
2963  EState *estate;
2964  ExprContext *econtext;
2965  Snapshot snapshot;
2966 
2967  /*
2968  * If we are reindexing the target index, mark it as no longer being
2969  * reindexed, to forestall an Assert in index_beginscan when we try to use
2970  * the index for probes. This is OK because the index is now fully valid.
2971  */
2974 
2975  /*
2976  * Need an EState for evaluation of index expressions and partial-index
2977  * predicates. Also a slot to hold the current tuple.
2978  */
2979  estate = CreateExecutorState();
2980  econtext = GetPerTupleExprContext(estate);
2981  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
2982 
2983  /* Arrange for econtext's scan tuple to be the tuple under test */
2984  econtext->ecxt_scantuple = slot;
2985 
2986  /* Set up execution state for predicate, if any. */
2987  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
2988 
2989  /*
2990  * Scan all live tuples in the base relation.
2991  */
2992  snapshot = RegisterSnapshot(GetLatestSnapshot());
2993  scan = heap_beginscan_strat(heapRelation, /* relation */
2994  snapshot, /* snapshot */
2995  0, /* number of keys */
2996  NULL, /* scan key */
2997  true, /* buffer access strategy OK */
2998  true); /* syncscan OK */
2999 
3000  while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
3001  {
3003 
3005 
3006  /* Set up for predicate or expression evaluation */
3007  ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
3008 
3009  /*
3010  * In a partial index, ignore tuples that don't satisfy the predicate.
3011  */
3012  if (predicate != NULL)
3013  {
3014  if (!ExecQual(predicate, econtext))
3015  continue;
3016  }
3017 
3018  /*
3019  * Extract index column values, including computing expressions.
3020  */
3021  FormIndexDatum(indexInfo,
3022  slot,
3023  estate,
3024  values,
3025  isnull);
3026 
3027  /*
3028  * Check that this tuple has no conflicts.
3029  */
3030  check_exclusion_constraint(heapRelation,
3031  indexRelation, indexInfo,
3032  &(heapTuple->t_self), values, isnull,
3033  estate, true);
3034  }
3035 
3036  heap_endscan(scan);
3037  UnregisterSnapshot(snapshot);
3038 
3040 
3041  FreeExecutorState(estate);
3042 
3043  /* These may have been pointing to the now-gone estate */
3044  indexInfo->ii_ExpressionsState = NIL;
3045  indexInfo->ii_PredicateState = NULL;
3046 }
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2000
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
List * ii_Predicate
Definition: execnodes.h:156
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition: index.c:4011
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:433
ExprState * ii_PredicateState
Definition: execnodes.h:157
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:226
#define InvalidBuffer
Definition: buf.h:25
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:361
static void ResetReindexProcessing(void)
Definition: index.c:4052
void FreeExecutorState(EState *estate)
Definition: execUtils.c:188
#define GetPerTupleExprContext(estate)
Definition: executor.h:489
List * ii_ExpressionsState
Definition: execnodes.h:155
ItemPointerData t_self
Definition: htup.h:65
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:247
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:516
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:232
EState * CreateExecutorState(void)
Definition: execUtils.c:80
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
uintptr_t Datum
Definition: postgres.h:365
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
HeapScanDesc heap_beginscan_strat(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync)
Definition: heapam.c:1422
#define INDEX_MAX_KEYS
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:218
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex)
Definition: execIndexing.c:863
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ IndexGetRelation()

Oid IndexGetRelation ( Oid  indexId,
bool  missing_ok 
)

Definition at line 3591 of file index.c.

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

Referenced by ATExecDetachPartition(), ATPostAlterTypeCleanup(), brin_desummarize_range(), brin_summarize_range(), bringetbitmap(), brinvacuumcleanup(), bt_index_check_internal(), CheckIndexCompatible(), CreateTrigger(), index_drop(), RangeVarCallbackForAttachIndex(), RangeVarCallbackForDropRelation(), RangeVarCallbackForReindexIndex(), refuseDupeIndexAttach(), and reindex_index().

3592 {
3593  HeapTuple tuple;
3595  Oid result;
3596 
3597  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3598  if (!HeapTupleIsValid(tuple))
3599  {
3600  if (missing_ok)
3601  return InvalidOid;
3602  elog(ERROR, "cache lookup failed for index %u", indexId);
3603  }
3604  index = (Form_pg_index) GETSTRUCT(tuple);
3605  Assert(index->indexrelid == indexId);
3606 
3607  result = index->indrelid;
3608  ReleaseSysCache(tuple);
3609  return result;
3610 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
unsigned int Oid
Definition: postgres_ext.h:31
Definition: type.h:89
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define elog
Definition: elog.h:219

◆ InitializeAttributeOids()

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

Definition at line 519 of file index.c.

References i, RelationGetDescr, and TupleDescAttr.

Referenced by index_create().

522 {
523  TupleDesc tupleDescriptor;
524  int i;
525 
526  tupleDescriptor = RelationGetDescr(indexRelation);
527 
528  for (i = 0; i < numatts; i += 1)
529  TupleDescAttr(tupleDescriptor, i)->attrelid = indexoid;
530 }
#define RelationGetDescr(relation)
Definition: rel.h:433
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
int i

◆ itemptr_decode()

static void itemptr_decode ( ItemPointer  itemptr,
int64  encoded 
)
inlinestatic

Definition at line 3236 of file index.c.

References ItemPointerSet.

Referenced by validate_index_heapscan().

3237 {
3238  BlockNumber block = (BlockNumber) (encoded >> 16);
3239  OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
3240 
3241  ItemPointerSet(itemptr, block, offset);
3242 }
uint32 BlockNumber
Definition: block.h:31
uint16 OffsetNumber
Definition: off.h:24
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105

◆ itemptr_encode()

static int64 itemptr_encode ( ItemPointer  itemptr)
inlinestatic

Definition at line 3215 of file index.c.

References ItemPointerGetBlockNumber, and ItemPointerGetOffsetNumber.

Referenced by validate_index_callback().

3216 {
3217  BlockNumber block = ItemPointerGetBlockNumber(itemptr);
3218  OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr);
3219  int64 encoded;
3220 
3221  /*
3222  * Use the 16 least significant bits for the offset. 32 adjacent bits are
3223  * used for the block number. Since remaining bits are unused, there
3224  * cannot be negative encoded values (We assume a two's complement
3225  * representation).
3226  */
3227  encoded = ((uint64) block << 16) | (uint16) offset;
3228 
3229  return encoded;
3230 }
uint32 BlockNumber
Definition: block.h:31
uint16 OffsetNumber
Definition: off.h:24
unsigned short uint16
Definition: c.h:324
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:95
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76

◆ reindex_index()

void reindex_index ( Oid  indexId,
bool  skip_constraint_checks,
char  persistence,
int  options 
)

Definition at line 3616 of file index.c.

References AccessExclusiveLock, BuildIndexInfo(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CheckTableNotInUse(), EarlyPruningEnabled, elog, ereport, errcode(), errdetail_internal(), errmsg(), ERROR, get_rel_name(), GETSTRUCT, heap_close, heap_open(), 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, InvalidMultiXactId, InvalidTransactionId, NoLock, ObjectIdGetDatum, PG_CATCH, PG_END_TRY, PG_RE_THROW, pg_rusage_init(), pg_rusage_show(), PG_TRY, RelationData::rd_rel, REINDEXOPT_VERBOSE, RELATION_IS_OTHER_TEMP, RelationGetRelationName, RelationSetNewRelfilenode(), ResetReindexProcessing(), RowExclusiveLock, SearchSysCacheCopy1, SetReindexProcessing(), ShareLock, HeapTupleData::t_self, and TransferPredicateLocksToHeapRelation().

Referenced by reindex_relation(), and ReindexIndex().

3618 {
3619  Relation iRel,
3620  heapRelation;
3621  Oid heapId;
3622  IndexInfo *indexInfo;
3623  volatile bool skipped_constraint = false;
3624  PGRUsage ru0;
3625 
3626  pg_rusage_init(&ru0);
3627 
3628  /*
3629  * Open and lock the parent heap relation. ShareLock is sufficient since
3630  * we only need to be sure no schema or data changes are going on.
3631  */
3632  heapId = IndexGetRelation(indexId, false);
3633  heapRelation = heap_open(heapId, ShareLock);
3634 
3635  /*
3636  * Open the target index relation and get an exclusive lock on it, to
3637  * ensure that no one else is touching this particular index.
3638  */
3639  iRel = index_open(indexId, AccessExclusiveLock);
3640 
3641  /*
3642  * The case of reindexing partitioned tables and indexes is handled
3643  * differently by upper layers, so this case shouldn't arise.
3644  */
3645  if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3646  elog(ERROR, "unsupported relation kind for index \"%s\"",
3647  RelationGetRelationName(iRel));
3648 
3649  /*
3650  * Don't allow reindex on temp tables of other backends ... their local
3651  * buffer manager is not going to cope.
3652  */
3653  if (RELATION_IS_OTHER_TEMP(iRel))
3654  ereport(ERROR,
3655  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3656  errmsg("cannot reindex temporary tables of other sessions")));
3657 
3658  /*
3659  * Also check for active uses of the index in the current transaction; we
3660  * don't want to reindex underneath an open indexscan.
3661  */
3662  CheckTableNotInUse(iRel, "REINDEX INDEX");
3663 
3664  /*
3665  * All predicate locks on the index are about to be made invalid. Promote
3666  * them to relation locks on the heap.
3667  */
3669 
3670  PG_TRY();
3671  {
3672  /* Suppress use of the target index while rebuilding it */
3673  SetReindexProcessing(heapId, indexId);
3674 
3675  /* Fetch info needed for index_build */
3676  indexInfo = BuildIndexInfo(iRel);
3677 
3678  /* If requested, skip checking uniqueness/exclusion constraints */
3679  if (skip_constraint_checks)
3680  {
3681  if (indexInfo->ii_Unique || indexInfo->ii_ExclusionOps != NULL)
3682  skipped_constraint = true;
3683  indexInfo->ii_Unique = false;
3684  indexInfo->ii_ExclusionOps = NULL;
3685  indexInfo->ii_ExclusionProcs = NULL;
3686  indexInfo->ii_ExclusionStrats = NULL;
3687  }
3688 
3689  /* We'll build a new physical relation for the index */
3692 
3693  /* Initialize the index and rebuild */
3694  /* Note: we do not need to re-establish pkey setting */
3695  index_build(heapRelation, iRel, indexInfo, false, true, true);
3696  }
3697  PG_CATCH();
3698  {
3699  /* Make sure flag gets cleared on error exit */
3701  PG_RE_THROW();
3702  }
3703  PG_END_TRY();
3705 
3706  /*
3707  * If the index is marked invalid/not-ready/dead (ie, it's from a failed
3708  * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway),
3709  * and we didn't skip a uniqueness check, we can now mark it valid. This
3710  * allows REINDEX to be used to clean up in such cases.
3711  *
3712  * We can also reset indcheckxmin, because we have now done a
3713  * non-concurrent index build, *except* in the case where index_build
3714  * found some still-broken HOT chains. If it did, and we don't have to
3715  * change any of the other flags, we just leave indcheckxmin alone (note
3716  * that index_build won't have changed it, because this is a reindex).
3717  * This is okay and desirable because not updating the tuple leaves the
3718  * index's usability horizon (recorded as the tuple's xmin value) the same
3719  * as it was.
3720  *
3721  * But, if the index was invalid/not-ready/dead and there were broken HOT
3722  * chains, we had better force indcheckxmin true, because the normal
3723  * argument that the HOT chains couldn't conflict with the index is
3724  * suspect for an invalid index. (A conflict is definitely possible if
3725  * the index was dead. It probably shouldn't happen otherwise, but let's
3726  * be conservative.) In this case advancing the usability horizon is
3727  * appropriate.
3728  *
3729  * Another reason for avoiding unnecessary updates here is that while
3730  * reindexing pg_index itself, we must not try to update tuples in it.
3731  * pg_index's indexes should always have these flags in their clean state,
3732  * so that won't happen.
3733  *
3734  * If early pruning/vacuuming is enabled for the heap relation, the
3735  * usability horizon must be advanced to the current transaction on every
3736  * build or rebuild. pg_index is OK in this regard because catalog tables
3737  * are not subject to early cleanup.
3738  */
3739  if (!skipped_constraint)
3740  {
3741  Relation pg_index;
3742  HeapTuple indexTuple;
3743  Form_pg_index indexForm;
3744  bool index_bad;
3745  bool early_pruning_enabled = EarlyPruningEnabled(heapRelation);
3746 
3747  pg_index = heap_open(IndexRelationId, RowExclusiveLock);
3748 
3749  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3750  ObjectIdGetDatum(indexId));
3751  if (!HeapTupleIsValid(indexTuple))
3752  elog(ERROR, "cache lookup failed for index %u", indexId);
3753  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3754 
3755  index_bad = (!indexForm->indisvalid ||
3756  !indexForm->indisready ||
3757  !indexForm->indislive);
3758  if (index_bad ||
3759  (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain) ||
3760  early_pruning_enabled)
3761  {
3762  if (!indexInfo->ii_BrokenHotChain && !early_pruning_enabled)
3763  indexForm->indcheckxmin = false;
3764  else if (index_bad || early_pruning_enabled)
3765  indexForm->indcheckxmin = true;
3766  indexForm->indisvalid = true;
3767  indexForm->indisready = true;
3768  indexForm->indislive = true;
3769  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3770 
3771  /*
3772  * Invalidate the relcache for the table, so that after we commit
3773  * all sessions will refresh the table's index list. This ensures
3774  * that if anyone misses seeing the pg_index row during this
3775  * update, they'll refresh their list before attempting any update
3776  * on the table.
3777  */
3778  CacheInvalidateRelcache(heapRelation);
3779  }
3780 
3781  heap_close(pg_index, RowExclusiveLock);
3782  }
3783 
3784  /* Log what we did */
3786  ereport(INFO,
3787  (errmsg("index \"%s\" was reindexed",
3788  get_rel_name(indexId)),
3789  errdetail_internal("%s",
3790  pg_rusage_show(&ru0))));
3791 
3792  /* Close rels, but keep locks */
3793  index_close(iRel, NoLock);
3794  heap_close(heapRelation, NoLock);
3795 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3591
void RelationSetNewRelfilenode(Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
Definition: relcache.c:3264
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
static void SetReindexProcessing(Oid heapOid, Oid indexOid)
Definition: index.c:4035
Oid * ii_ExclusionProcs
Definition: execnodes.h:159
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
#define heap_close(r, l)
Definition: heapam.h:97
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1745
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isprimary, bool isreindex, bool parallel)
Definition: index.c:2229
#define REINDEXOPT_VERBOSE
Definition: parsenodes.h:3272
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
static void ResetReindexProcessing(void)
Definition: index.c:4052
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
#define EarlyPruningEnabled(rel)
Definition: snapmgr.h:46
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:441
bool ii_BrokenHotChain
Definition: execnodes.h:167
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3208
#define ereport(elevel, rest)
Definition: elog.h:122
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3044
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidMultiXactId
Definition: multixact.h:23
bool ii_Unique
Definition: execnodes.h:164
#define PG_CATCH()
Definition: elog.h:293
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:538
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
#define PG_RE_THROW()
Definition: elog.h:314
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define AccessExclusiveLock
Definition: lockdefs.h:45
Oid * ii_ExclusionOps
Definition: execnodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
#define elog
Definition: elog.h:219
uint16 * ii_ExclusionStrats
Definition: execnodes.h:160
#define PG_TRY()
Definition: elog.h:284
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
#define PG_END_TRY()
Definition: elog.h:300

◆ reindex_relation()

bool reindex_relation ( Oid  relid,
int  flags,
int  options 
)

Definition at line 3833 of file index.c.

References Assert, ClassOidIndexId, CommandCounterIncrement(), ereport, errcode(), errmsg(), heap_close, heap_open(), INDEX_ATTR_BITMAP_HOT, InvalidOid, lappend_oid(), lfirst_oid, NIL, NoLock, OidIsValid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, 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, reindex_relation(), ReindexIsProcessingIndex(), RelationGetIndexAttrBitmap(), RelationGetIndexList(), RelationGetRelationName, RelationGetRelid, RelationSetIndexList(), ResetReindexPending(), SetReindexPending(), ShareLock, and WARNING.

Referenced by ExecuteTruncateGuts(), finish_heap_swap(), reindex_relation(), ReindexMultipleTables(), and ReindexTable().

3834 {
3835  Relation rel;
3836  Oid toast_relid;
3837  List *indexIds;
3838  bool is_pg_class;
3839  bool result;
3840 
3841  /*
3842  * Open and lock the relation. ShareLock is sufficient since we only need
3843  * to prevent schema and data changes in it. The lock level used here
3844  * should match ReindexTable().
3845  */
3846  rel = heap_open(relid, ShareLock);
3847 
3848  /*
3849  * This may be useful when implemented someday; but that day is not today.
3850  * For now, avoid erroring out when called in a multi-table context
3851  * (REINDEX SCHEMA) and happen to come across a partitioned table. The
3852  * partitions may be reindexed on their own anyway.
3853  */
3854  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3855  {
3856  ereport(WARNING,
3857  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3858  errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
3859  RelationGetRelationName(rel))));
3860  heap_close(rel, ShareLock);
3861  return false;
3862  }
3863 
3864  toast_relid = rel->rd_rel->reltoastrelid;
3865 
3866  /*
3867  * Get the list of index OIDs for this relation. (We trust to the
3868  * relcache to get this with a sequential scan if ignoring system
3869  * indexes.)
3870  */
3871  indexIds = RelationGetIndexList(rel);
3872 
3873  /*
3874  * reindex_index will attempt to update the pg_class rows for the relation
3875  * and index. If we are processing pg_class itself, we want to make sure
3876  * that the updates do not try to insert index entries into indexes we
3877  * have not processed yet. (When we are trying to recover from corrupted
3878  * indexes, that could easily cause a crash.) We can accomplish this
3879  * because CatalogTupleInsert/CatalogTupleUpdate will use the relcache's
3880  * index list to know which indexes to update. We just force the index
3881  * list to be only the stuff we've processed.
3882  *
3883  * It is okay to not insert entries into the indexes we have not processed
3884  * yet because all of this is transaction-safe. If we fail partway
3885  * through, the updated rows are dead and it doesn't matter whether they
3886  * have index entries. Also, a new pg_class index will be created with a
3887  * correct entry for its own pg_class row because we do
3888  * RelationSetNewRelfilenode() before we do index_build().
3889  *
3890  * Note that we also clear pg_class's rd_oidindex until the loop is done,
3891  * so that that index can't be accessed either. This means we cannot
3892  * safely generate new relation OIDs while in the loop; shouldn't be a
3893  * problem.
3894  */
3895  is_pg_class = (RelationGetRelid(rel) == RelationRelationId);
3896 
3897  /* Ensure rd_indexattr is valid; see comments for RelationSetIndexList */
3898  if (is_pg_class)
3900 
3901  PG_TRY();
3902  {
3903  List *doneIndexes;
3904  ListCell *indexId;
3905  char persistence;
3906 
3907  if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
3908  {
3909  /* Suppress use of all the indexes until they are rebuilt */
3910  SetReindexPending(indexIds);
3911 
3912  /*
3913  * Make the new heap contents visible --- now things might be
3914  * inconsistent!
3915  */
3917  }
3918 
3919  /*
3920  * Compute persistence of indexes: same as that of owning rel, unless
3921  * caller specified otherwise.
3922  */
3924  persistence = RELPERSISTENCE_UNLOGGED;
3925  else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
3926  persistence = RELPERSISTENCE_PERMANENT;
3927  else
3928  persistence = rel->rd_rel->relpersistence;
3929 
3930  /* Reindex all the indexes. */
3931  doneIndexes = NIL;
3932  foreach(indexId, indexIds)
3933  {
3934  Oid indexOid = lfirst_oid(indexId);
3935 
3936  if (is_pg_class)
3937  RelationSetIndexList(rel, doneIndexes, InvalidOid);
3938 
3939  reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
3940  persistence, options);
3941 
3943 
3944  /* Index should no longer be in the pending list */
3945  Assert(!ReindexIsProcessingIndex(indexOid));
3946 
3947  if (is_pg_class)
3948  doneIndexes = lappend_oid(doneIndexes, indexOid);
3949  }
3950  }
3951  PG_CATCH();
3952  {
3953  /* Make sure list gets cleared on error exit */
3955  PG_RE_THROW();
3956  }
3957  PG_END_TRY();
3959 
3960  if (is_pg_class)
3961  RelationSetIndexList(rel, indexIds, ClassOidIndexId);
3962 
3963  /*
3964  * Close rel, but continue to hold the lock.
3965  */
3966  heap_close(rel, NoLock);
3967 
3968  result = (indexIds != NIL);
3969 
3970  /*
3971  * If the relation has a secondary toast rel, reindex that too while we
3972  * still hold the lock on the master table.
3973  */
3974  if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
3975  result |= reindex_relation(toast_relid, flags, options);
3976 
3977  return result;
3978 }
#define NIL
Definition: pg_list.h:69
static void SetReindexPending(List *indexes)
Definition: index.c:4067
static void ResetReindexPending(void)
Definition: index.c:4095
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition: index.h:140
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:605
void RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
Definition: relcache.c:4441
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ClassOidIndexId
Definition: indexing.h:112
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define PG_CATCH()
Definition: elog.h:293
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:142
#define Assert(condition)
Definition: c.h:699
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:141
#define PG_RE_THROW()
Definition: elog.h:314
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, int options)
Definition: index.c:3616
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:4758
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:143
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:139
#define PG_TRY()
Definition: elog.h:284
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4022
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3833
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define PG_END_TRY()
Definition: elog.h:300
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4011 of file index.c.

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

4012 {
4013  return indexOid == currentlyReindexedIndex;
4014 }
static Oid currentlyReindexedIndex
Definition: index.c:3993

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4001 of file index.c.

References currentlyReindexedHeap.

Referenced by index_update_stats().

4002 {
4003  return heapOid == currentlyReindexedHeap;
4004 }
static Oid currentlyReindexedHeap
Definition: index.c:3992

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4022 of file index.c.

References currentlyReindexedIndex, and list_member_oid().

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

4023 {
4024  return indexOid == currentlyReindexedIndex ||
4026 }
static List * pendingReindexedIndexes
Definition: index.c:3994
static Oid currentlyReindexedIndex
Definition: index.c:3993
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 160 of file index.c.

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

Referenced by index_check_primary_key().

161 {
162  bool result = false;
163  List *indexoidlist;
164  ListCell *indexoidscan;
165 
166  /*
167  * Get the list of index OIDs for the table from the relcache, and look up
168  * each one in the pg_index syscache until we find one marked primary key
169  * (hopefully there isn't more than one such).
170  */
171  indexoidlist = RelationGetIndexList(rel);
172 
173  foreach(indexoidscan, indexoidlist)
174  {
175  Oid indexoid = lfirst_oid(indexoidscan);
176  HeapTuple indexTuple;
177 
178  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
179  if (!HeapTupleIsValid(indexTuple)) /* should not happen */
180  elog(ERROR, "cache lookup failed for index %u", indexoid);
181  result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary;
182  ReleaseSysCache(indexTuple);
183  if (result)
184  break;
185  }
186 
187  list_free(indexoidlist);
188 
189  return result;
190 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void list_free(List *list)
Definition: list.c:1133
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4082 of file index.c.

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

Referenced by SetReindexProcessing().

4083 {
4084  if (IsInParallelMode())
4085  elog(ERROR, "cannot modify reindex state during a parallel operation");
4087  indexOid);
4088 }
static List * pendingReindexedIndexes
Definition: index.c:3994
bool IsInParallelMode(void)
Definition: xact.c:905
#define ERROR
Definition: elog.h:43
List * list_delete_oid(List *list, Oid datum)
Definition: list.c:636
#define elog
Definition: elog.h:219

◆ ResetReindexPending()

static void ResetReindexPending ( void  )
static

Definition at line 4095 of file index.c.

References NIL.

Referenced by reindex_relation().

4096 {
4097  /* This may be called in leader error path */
4099 }
#define NIL
Definition: pg_list.h:69
static List * pendingReindexedIndexes
Definition: index.c:3994

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4052 of file index.c.

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

4053 {
4054  /* This may be called in leader error path */
4057 }
static Oid currentlyReindexedHeap
Definition: index.c:3992
static Oid currentlyReindexedIndex
Definition: index.c:3993
#define InvalidOid
Definition: postgres_ext.h:36

◆ RestoreReindexState()

void RestoreReindexState ( void *  reindexstate)

Definition at line 4135 of file index.c.

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

Referenced by ParallelWorkerMain().

4136 {
4137  SerializedReindexState *sistate = (SerializedReindexState *) reindexstate;
4138  int c = 0;
4139  MemoryContext oldcontext;
4140 
4143 
4146  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4149  sistate->pendingReindexedIndexes[c]);
4150  MemoryContextSwitchTo(oldcontext);
4151 }
#define NIL
Definition: pg_list.h:69
static Oid currentlyReindexedHeap
Definition: index.c:3992
Oid currentlyReindexedIndex
Definition: index.c:100
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static List * pendingReindexedIndexes
Definition: index.c:3994
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:102
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
char * c
MemoryContext TopMemoryContext
Definition: mcxt.c:44
int numPendingReindexedIndexes
Definition: index.c:101
static Oid currentlyReindexedIndex
Definition: index.c:3993
#define Assert(condition)
Definition: c.h:699
Oid currentlyReindexedHeap
Definition: index.c:99

◆ SerializeReindexState()

void SerializeReindexState ( Size  maxsize,
char *  start_address 
)

Definition at line 4117 of file index.c.

References SerializedReindexState::currentlyReindexedHeap, currentlyReindexedHeap, SerializedReindexState::currentlyReindexedIndex, currentlyReindexedIndex, lfirst_oid, list_length(), SerializedReindexState::numPendingReindexedIndexes, and SerializedReindexState::pendingReindexedIndexes.

Referenced by InitializeParallelDSM().

4118 {
4119  SerializedReindexState *sistate = (SerializedReindexState *) start_address;
4120  int c = 0;
4121  ListCell *lc;
4122 
4126  foreach(lc, pendingReindexedIndexes)
4127  sistate->pendingReindexedIndexes[c++] = lfirst_oid(lc);
4128 }
static Oid currentlyReindexedHeap
Definition: index.c:3992
Oid currentlyReindexedIndex
Definition: index.c:100
static List * pendingReindexedIndexes
Definition: index.c:3994
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:102
char * c
int numPendingReindexedIndexes
Definition: index.c:101
static Oid currentlyReindexedIndex
Definition: index.c:3993
static int list_length(const List *l)
Definition: pg_list.h:89
Oid currentlyReindexedHeap
Definition: index.c:99
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4067 of file index.c.

References elog, ERROR, IsInParallelMode(), and list_copy().

Referenced by reindex_relation().

4068 {
4069  /* Reindexing is not re-entrant. */
4071  elog(ERROR, "cannot reindex while reindexing");
4072  if (IsInParallelMode())
4073  elog(ERROR, "cannot modify reindex state during a parallel operation");
4075 }
static List * pendingReindexedIndexes
Definition: index.c:3994
List * list_copy(const List *oldlist)
Definition: list.c:1160
bool IsInParallelMode(void)
Definition: xact.c:905
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219

◆ SetReindexProcessing()

static void SetReindexProcessing ( Oid  heapOid,
Oid  indexOid 
)
static

Definition at line 4035 of file index.c.

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

Referenced by reindex_index().

4036 {
4037  Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4038  /* Reindexing is not re-entrant. */
4040  elog(ERROR, "cannot reindex while reindexing");
4041  currentlyReindexedHeap = heapOid;
4042  currentlyReindexedIndex = indexOid;
4043  /* Index is no longer "pending" reindex. */
4044  RemoveReindexPending(indexOid);
4045 }
static Oid currentlyReindexedHeap
Definition: index.c:3992
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
static Oid currentlyReindexedIndex
Definition: index.c:3993
static void RemoveReindexPending(Oid indexOid)
Definition: index.c:4082
#define Assert(condition)
Definition: c.h:699
#define elog
Definition: elog.h:219

◆ UpdateIndexRelation()

static void UpdateIndexRelation ( Oid  indexoid,
Oid  heapoid,
Oid  parentIndexId,
IndexInfo indexInfo,
Oid collationOids,
Oid classOids,
int16 coloptions,
bool  primary,
bool  isexclusion,
bool  immediate,
bool  isvalid,
bool  isready 
)
static

Definition at line 582 of file index.c.

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

Referenced by index_create().

594 {
595  int2vector *indkey;
596  oidvector *indcollation;
597  oidvector *indclass;
598  int2vector *indoption;
599  Datum exprsDatum;
600  Datum predDatum;
601  Datum values[Natts_pg_index];
602  bool nulls[Natts_pg_index];
603  Relation pg_index;
604  HeapTuple tuple;
605  int i;
606 
607  /*
608  * Copy the index key, opclass, and indoption info into arrays (should we
609  * make the caller pass them like this to start with?)
610  */
611  indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs);
612  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
613  indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i];
614  indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs);
615  indclass = buildoidvector(classOids, indexInfo->ii_NumIndexKeyAttrs);
616  indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexKeyAttrs);
617 
618  /*
619  * Convert the index expressions (if any) to a text datum
620  */
621  if (indexInfo->ii_Expressions != NIL)
622  {
623  char *exprsString;
624 
625  exprsString = nodeToString(indexInfo->ii_Expressions);
626  exprsDatum = CStringGetTextDatum(exprsString);
627  pfree(exprsString);
628  }
629  else
630  exprsDatum = (Datum) 0;
631 
632  /*
633  * Convert the index predicate (if any) to a text datum. Note we convert
634  * implicit-AND format to normal explicit-AND for storage.
635  */
636  if (indexInfo->ii_Predicate != NIL)
637  {
638  char *predString;
639 
640  predString = nodeToString(make_ands_explicit(indexInfo->ii_Predicate));
641  predDatum = CStringGetTextDatum(predString);
642  pfree(predString);
643  }
644  else
645  predDatum = (Datum) 0;
646 
647  /*
648  * open the system catalog index relation
649  */
650  pg_index = heap_open(IndexRelationId, RowExclusiveLock);
651 
652  /*
653  * Build a pg_index tuple
654  */
655  MemSet(nulls, false, sizeof(nulls));
656 
657  values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid);
658  values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid);
659  values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs);
660  values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs);
661  values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique);
662  values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary);
663  values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion);
664  values[Anum_pg_index_indimmediate - 1] = BoolGetDatum(immediate);
665  values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false);
666  values[Anum_pg_index_indisvalid - 1] = BoolGetDatum(isvalid);
667  values[Anum_pg_index_indcheckxmin - 1] = BoolGetDatum(false);
668  values[Anum_pg_index_indisready - 1] = BoolGetDatum(isready);
669  values[Anum_pg_index_indislive - 1] = BoolGetDatum(true);
670  values[Anum_pg_index_indisreplident - 1] = BoolGetDatum(false);
671  values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey);
672  values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation);
673  values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
674  values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
675  values[Anum_pg_index_indexprs - 1] = exprsDatum;
676  if (exprsDatum == (Datum) 0)
677  nulls[Anum_pg_index_indexprs - 1] = true;
678  values[Anum_pg_index_indpred - 1] = predDatum;
679  if (predDatum == (Datum) 0)
680  nulls[Anum_pg_index_indpred - 1] = true;
681 
682  tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls);
683 
684  /*
685  * insert the tuple into the pg_index catalog
686  */
687  CatalogTupleInsert(pg_index, tuple);
688 
689  /*
690  * close the relation and free the tuple
691  */
692  heap_close(pg_index, RowExclusiveLock);
693  heap_freetuple(tuple);
694 }
#define NIL
Definition: pg_list.h:69
Definition: c.h:555
List * ii_Predicate
Definition: execnodes.h:156
#define RelationGetDescr(relation)
Definition: rel.h:433
#define PointerGetDatum(X)
Definition: postgres.h:539
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:110
#define Int16GetDatum(X)
Definition: postgres.h:434
#define MemSet(start, val, len)
Definition: c.h:908
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:368
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
#define RowExclusiveLock
Definition: lockdefs.h:38
Definition: c.h:544
uintptr_t Datum
Definition: postgres.h:365
int ii_NumIndexAttrs
Definition: execnodes.h:151
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define BoolGetDatum(X)
Definition: postgres.h:385
bool ii_Unique
Definition: execnodes.h:164
List * ii_Expressions
Definition: execnodes.h:154
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:167
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:552
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:95
char * nodeToString(const void *obj)
Definition: outfuncs.c:4331
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153

◆ validate_index()

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

Definition at line 3113 of file index.c.

References IndexVacuumInfo::analyze_only, AtEOXact_GUC(), BuildIndexInfo(), DEBUG2, elog, IndexVacuumInfo::estimated_count, GetUserIdAndSecContext(), heap_close, heap_open(), v_i_state::htups, IndexInfo::ii_Concurrent, IndexVacuumInfo::index, index_bulk_delete(), index_close(), index_open(), InvalidOid, v_i_state::itups, maintenance_work_mem, IndexVacuumInfo::message_level, NewGUCNestLevel(), NoLock, IndexVacuumInfo::num_heap_tuples, RelationData::rd_rel, RowExclusiveLock, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), ShareUpdateExclusiveLock, IndexVacuumInfo::strategy, v_i_state::tuplesort, tuplesort_begin_datum(), tuplesort_end(), tuplesort_performsort(), v_i_state::tups_inserted, validate_index_callback(), and validate_index_heapscan().

Referenced by DefineIndex().

3114 {
3115  Relation heapRelation,
3116  indexRelation;
3117  IndexInfo *indexInfo;
3118  IndexVacuumInfo ivinfo;
3119  v_i_state state;
3120  Oid save_userid;
3121  int save_sec_context;
3122  int save_nestlevel;
3123 
3124  /* Open and lock the parent heap relation */
3125  heapRelation = heap_open(heapId, ShareUpdateExclusiveLock);
3126  /* And the target index relation */
3127  indexRelation = index_open(indexId, RowExclusiveLock);
3128 
3129  /*
3130  * Fetch info needed for index_insert. (You might think this should be
3131  * passed in from DefineIndex, but its copy is long gone due to having
3132  * been built in a previous transaction.)
3133  */
3134  indexInfo = BuildIndexInfo(indexRelation);
3135 
3136  /* mark build is concurrent just for consistency */
3137  indexInfo->ii_Concurrent = true;
3138 
3139  /*
3140  * Switch to the table owner's userid, so that any index functions are run
3141  * as that user. Also lock down security-restricted operations and
3142  * arrange to make GUC variable changes local to this command.
3143  */
3144  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3145  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3146  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3147  save_nestlevel = NewGUCNestLevel();
3148 
3149  /*
3150  * Scan the index and gather up all the TIDs into a tuplesort object.
3151  */
3152  ivinfo.index = indexRelation;
3153  ivinfo.analyze_only = false;
3154  ivinfo.estimated_count = true;
3155  ivinfo.message_level = DEBUG2;
3156  ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3157  ivinfo.strategy = NULL;
3158 
3159  /*
3160  * Encode TIDs as int8 values for the sort, rather than directly sorting
3161  * item pointers. This can be significantly faster, primarily because TID
3162  * is a pass-by-reference type on all platforms, whereas int8 is
3163  * pass-by-value on most platforms.
3164  */
3165  state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
3166  InvalidOid, false,
3168  NULL, false);
3169  state.htups = state.itups = state.tups_inserted = 0;
3170 
3171  (void) index_bulk_delete(&ivinfo, NULL,
3172  validate_index_callback, (void *) &state);
3173 
3174  /* Execute the sort */
3176 
3177  /*
3178  * Now scan the heap and "merge" it with the index
3179  */
3180  validate_index_heapscan(heapRelation,
3181  indexRelation,
3182  indexInfo,
3183  snapshot,
3184  &state);
3185 
3186  /* Done with tuplesort object */
3187  tuplesort_end(state.tuplesort);
3188 
3189  elog(DEBUG2,
3190  "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3191  state.htups, state.itups, state.tups_inserted);
3192 
3193  /* Roll back any GUC changes executed by index functions */
3194  AtEOXact_GUC(false, save_nestlevel);
3195 
3196  /* Restore userid and security context */
3197  SetUserIdAndSecContext(save_userid, save_sec_context);
3198 
3199  /* Close rels, but keep locks */
3200  index_close(indexRelation, NoLock);
3201  heap_close(heapRelation, NoLock);
3202 }
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1790
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:1099
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:298
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:491
bool analyze_only
Definition: genam.h:47
BufferAccessStrategy strategy
Definition: genam.h:51
Relation index
Definition: genam.h:46
double htups
Definition: index.c:88
#define heap_close(r, l)
Definition: heapam.h:97
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1745
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
Tuplesortstate * tuplesort
Definition: index.c:86
#define DEBUG2
Definition: elog.h:24
static void validate_index_heapscan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, Snapshot snapshot, v_i_state *state)
Definition: index.c:3265
#define NoLock
Definition: lockdefs.h:34
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:484
#define RowExclusiveLock
Definition: lockdefs.h:38
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5299
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:743
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
int maintenance_work_mem
Definition: globals.c:123
int message_level
Definition: genam.h:49
double num_heap_tuples
Definition: genam.h:50
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
Definition: regguts.h:298
bool ii_Concurrent
Definition: execnodes.h:166
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
double itups
Definition: index.c:88
int NewGUCNestLevel(void)
Definition: guc.c:5285
#define elog
Definition: elog.h:219
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1235
static bool validate_index_callback(ItemPointer itemptr, void *opaque)
Definition: index.c:3248
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
double tups_inserted
Definition: index.c:88
bool estimated_count
Definition: genam.h:48

◆ validate_index_callback()

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

Definition at line 3248 of file index.c.

References Int64GetDatum(), itemptr_encode(), v_i_state::itups, v_i_state::tuplesort, and tuplesort_putdatum().

Referenced by validate_index().

3249 {
3250  v_i_state *state = (v_i_state *) opaque;
3251  int64 encoded = itemptr_encode(itemptr);
3252 
3253  tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3254  state->itups += 1;
3255  return false; /* never actually delete anything */
3256 }
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1555
Tuplesortstate * tuplesort
Definition: index.c:86
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1876
static int64 itemptr_encode(ItemPointer itemptr)
Definition: index.c:3215
Definition: regguts.h:298
double itups
Definition: index.c:88

◆ validate_index_heapscan()

static void validate_index_heapscan ( Relation  heapRelation,
Relation  indexRelation,
IndexInfo indexInfo,
Snapshot  snapshot,
v_i_state state 
)
static

Definition at line 3265 of file index.c.

References Assert, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, CHECK_FOR_INTERRUPTS, CreateExecutorState(), DatumGetInt64, DatumGetPointer, ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, ExecDropSingleTupleTableSlot(), ExecPrepareQual(), ExecQual(), ExecStoreTuple(), FormIndexDatum(), ForwardScanDirection, FreeExecutorState(), GetPerTupleExprContext, heap_beginscan_strat(), heap_endscan(), heap_get_root_tuples(), heap_getnext(), HeapTupleIsHeapOnly, v_i_state::htups, IndexInfo::ii_ExpressionsState, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_Unique, index_insert(), INDEX_MAX_KEYS, InvalidBlockNumber, InvalidBuffer, ItemPointerCompare(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerSetOffsetNumber, itemptr_decode(), LockBuffer(), MakeSingleTupleTableSlot(), MaxHeapTuplesPerPage, MemoryContextReset(), NIL, OffsetNumberIsValid, OidIsValid, pfree(), RelationData::rd_rel, RelationGetDescr, RelationGetRelationName, HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapTupleData::t_self, v_i_state::tuplesort, tuplesort_getdatum(), v_i_state::tups_inserted, UNIQUE_CHECK_NO, UNIQUE_CHECK_YES, and values.

Referenced by validate_index().

3270 {
3271  HeapScanDesc scan;
3272  HeapTuple heapTuple;
3274  bool isnull[INDEX_MAX_KEYS];
3275  ExprState *predicate;
3276  TupleTableSlot *slot;
3277  EState *estate;
3278  ExprContext *econtext;
3279  BlockNumber root_blkno = InvalidBlockNumber;
3280  OffsetNumber root_offsets[MaxHeapTuplesPerPage];
3281  bool in_index[MaxHeapTuplesPerPage];
3282 
3283  /* state variables for the merge */
3284  ItemPointer indexcursor = NULL;
3285  ItemPointerData decoded;
3286  bool tuplesort_empty = false;
3287 
3288  /*
3289  * sanity checks
3290  */
3291  Assert(OidIsValid(indexRelation->rd_rel->relam));
3292 
3293  /*
3294  * Need an EState for evaluation of index expressions and partial-index
3295  * predicates. Also a slot to hold the current tuple.
3296  */
3297  estate = CreateExecutorState();
3298  econtext = GetPerTupleExprContext(estate);
3299  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
3300 
3301  /* Arrange for econtext's scan tuple to be the tuple under test */
3302  econtext->ecxt_scantuple = slot;
3303 
3304  /* Set up execution state for predicate, if any. */
3305  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3306 
3307  /*
3308  * Prepare for scan of the base relation. We need just those tuples
3309