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

Go to the source code of this file.

Data Structures

struct  SerializedReindexState
 

Functions

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

Variables

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

Function Documentation

◆ AppendAttributeTuples()

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

Definition at line 513 of file index.c.

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

References CatalogCloseIndexes(), CatalogOpenIndexes(), fb(), i, InsertPgAttributeTuples(), InvalidOid, TupleDescData::natts, palloc0_array, RelationData::rd_att, RelationGetDescr, RowExclusiveLock, table_close(), and table_open().

Referenced by index_create().

◆ BuildDummyIndexInfo()

IndexInfo * BuildDummyIndexInfo ( Relation  index)

Definition at line 2506 of file index.c.

2507{
2508 IndexInfo *ii;
2509 Form_pg_index indexStruct = index->rd_index;
2510 int i;
2511 int numAtts;
2512
2513 /* check the number of keys, and copy attr numbers into the IndexInfo */
2514 numAtts = indexStruct->indnatts;
2516 elog(ERROR, "invalid indnatts %d for index %u",
2518
2519 /*
2520 * Create the node, using dummy index expressions, and pretending there is
2521 * no predicate.
2522 */
2523 ii = makeIndexInfo(indexStruct->indnatts,
2524 indexStruct->indnkeyatts,
2525 index->rd_rel->relam,
2527 NIL,
2528 indexStruct->indisunique,
2529 indexStruct->indnullsnotdistinct,
2530 indexStruct->indisready,
2531 false,
2532 index->rd_indam->amsummarizing,
2533 indexStruct->indisexclusion && indexStruct->indisunique);
2534
2535 /* fill in attribute numbers */
2536 for (i = 0; i < numAtts; i++)
2537 ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2538
2539 /* We ignore the exclusion constraint if any */
2540
2541 return ii;
2542}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing, bool withoutoverlaps)
Definition makefuncs.c:834
#define INDEX_MAX_KEYS
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
#define NIL
Definition pg_list.h:68
#define RelationGetRelid(relation)
Definition rel.h:516
List * RelationGetDummyIndexExpressions(Relation relation)
Definition relcache.c:5147
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:189
Definition type.h:96

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

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo * BuildIndexInfo ( Relation  index)

Definition at line 2446 of file index.c.

2447{
2448 IndexInfo *ii;
2449 Form_pg_index indexStruct = index->rd_index;
2450 int i;
2451 int numAtts;
2452
2453 /* check the number of keys, and copy attr numbers into the IndexInfo */
2454 numAtts = indexStruct->indnatts;
2456 elog(ERROR, "invalid indnatts %d for index %u",
2458
2459 /*
2460 * Create the node, fetching any expressions needed for expressional
2461 * indexes and index predicate if any.
2462 */
2463 ii = makeIndexInfo(indexStruct->indnatts,
2464 indexStruct->indnkeyatts,
2465 index->rd_rel->relam,
2468 indexStruct->indisunique,
2469 indexStruct->indnullsnotdistinct,
2470 indexStruct->indisready,
2471 false,
2472 index->rd_indam->amsummarizing,
2473 indexStruct->indisexclusion && indexStruct->indisunique);
2474
2475 /* fill in attribute numbers */
2476 for (i = 0; i < numAtts; i++)
2477 ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2478
2479 /* fetch exclusion constraint info if any */
2480 if (indexStruct->indisexclusion)
2481 {
2483 &ii->ii_ExclusionOps,
2484 &ii->ii_ExclusionProcs,
2485 &ii->ii_ExclusionStrats);
2486 }
2487
2488 return ii;
2489}
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5201
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5088
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5644
uint16 * ii_ExclusionStrats
Definition execnodes.h:206
Oid * ii_ExclusionOps
Definition execnodes.h:202
Oid * ii_ExclusionProcs
Definition execnodes.h:204

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

Referenced by _brin_parallel_scan_and_build(), _bt_parallel_scan_and_sort(), _gin_parallel_scan_and_build(), ATExecAddIndexConstraint(), ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), brinsummarize(), bt_check_every_level(), build_index_value_desc(), DefineIndex(), do_analyze_rel(), ExecOpenIndices(), index_concurrently_build(), index_create_copy(), recheck_matched_pk_tuple(), reindex_index(), tuplesort_begin_cluster(), unique_key_recheck(), and validate_index().

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2687 of file index.c.

2688{
2689 int indnkeyatts;
2690 int i;
2691
2693
2694 /*
2695 * fetch info for checking unique indexes
2696 */
2697 Assert(ii->ii_Unique);
2698
2702
2703 /*
2704 * We have to look up the operator's strategy number. This provides a
2705 * cross-check that the operator does match the index.
2706 */
2707 /* We need the func OIDs and strategy numbers too */
2708 for (i = 0; i < indnkeyatts; i++)
2709 {
2710 ii->ii_UniqueStrats[i] =
2712 index->rd_rel->relam,
2713 index->rd_opfamily[i],
2714 false);
2715 ii->ii_UniqueOps[i] =
2716 get_opfamily_member(index->rd_opfamily[i],
2717 index->rd_opcintype[i],
2718 index->rd_opcintype[i],
2719 ii->ii_UniqueStrats[i]);
2720 if (!OidIsValid(ii->ii_UniqueOps[i]))
2721 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2722 ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2723 index->rd_opcintype[i], index->rd_opfamily[i]);
2725 }
2726}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition amapi.c:161
#define Assert(condition)
Definition c.h:943
uint16_t uint16
Definition c.h:623
#define OidIsValid(objectId)
Definition c.h:858
@ COMPARE_EQ
Definition cmptype.h:36
#define palloc_array(type, count)
Definition fe_memutils.h:76
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:170
unsigned int Oid
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:535
bool ii_Unique
Definition execnodes.h:214
Oid * ii_UniqueOps
Definition execnodes.h:209
uint16 * ii_UniqueStrats
Definition execnodes.h:211
Oid * ii_UniqueProcs
Definition execnodes.h:210

References Assert, COMPARE_EQ, elog, ERROR, fb(), get_opcode(), get_opfamily_member(), i, IndexInfo::ii_Unique, IndexInfo::ii_UniqueOps, IndexInfo::ii_UniqueProcs, IndexInfo::ii_UniqueStrats, IndexAmTranslateCompareType(), IndexRelationGetNumberOfKeyAttributes, OidIsValid, and palloc_array.

Referenced by BuildConflictIndexInfo(), and ExecOpenIndices().

◆ CompareIndexInfo()

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

Definition at line 2555 of file index.c.

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

References elog, equal(), ERROR, fb(), i, InvalidAttrNumber, InvalidOid, map_variable_attnos(), and NIL.

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

◆ ConstructTupleDescriptor()

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

Definition at line 282 of file index.c.

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

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

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4263 of file index.c.

4264{
4267}
static List * pendingReindexedIndexes
Definition index.c:4132
static int list_length(const List *l)
Definition pg_list.h:152
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2748 of file index.c.

2753{
2755 int i;
2756
2757 if (indexInfo->ii_Expressions != NIL &&
2758 indexInfo->ii_ExpressionsState == NIL)
2759 {
2760 /* First time through, set up expression evaluation state */
2761 indexInfo->ii_ExpressionsState =
2762 ExecPrepareExprList(indexInfo->ii_Expressions, estate);
2763 /* Check caller has set up context correctly */
2764 Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2765 }
2767
2768 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
2769 {
2770 int keycol = indexInfo->ii_IndexAttrNumbers[i];
2771 Datum iDatum;
2772 bool isNull;
2773
2774 if (keycol < 0)
2775 iDatum = slot_getsysattr(slot, keycol, &isNull);
2776 else if (keycol != 0)
2777 {
2778 /*
2779 * Plain index column; get the value we need directly from the
2780 * heap tuple.
2781 */
2782 iDatum = slot_getattr(slot, keycol, &isNull);
2783 }
2784 else
2785 {
2786 /*
2787 * Index expression --- need to evaluate it.
2788 */
2789 if (indexpr_item == NULL)
2790 elog(ERROR, "wrong number of index expressions");
2792 GetPerTupleExprContext(estate),
2793 &isNull);
2795 }
2796 values[i] = iDatum;
2797 isnull[i] = isNull;
2798 }
2799
2800 if (indexpr_item != NULL)
2801 elog(ERROR, "wrong number of index expressions");
2802}
static Datum values[MAXATTR]
Definition bootstrap.c:190
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition execExpr.c:872
#define GetPerTupleExprContext(estate)
Definition executor.h:660
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:439
uint64_t Datum
Definition postgres.h:70
List * ii_ExpressionsState
Definition execnodes.h:194
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:438
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:417

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

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

◆ index_build()

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

Definition at line 3021 of file index.c.

3027{
3028 IndexBuildResult *stats;
3029 Oid save_userid;
3030 int save_sec_context;
3031 int save_nestlevel;
3032
3033 /*
3034 * sanity checks
3035 */
3036 Assert(RelationIsValid(indexRelation));
3037 Assert(indexRelation->rd_indam);
3038 Assert(indexRelation->rd_indam->ambuild);
3039 Assert(indexRelation->rd_indam->ambuildempty);
3040
3041 /*
3042 * Determine worker process details for parallel CREATE INDEX. Currently,
3043 * only btree, GIN, and BRIN have support for parallel builds.
3044 *
3045 * Note that planner considers parallel safety for us.
3046 */
3048 indexRelation->rd_indam->amcanbuildparallel)
3049 indexInfo->ii_ParallelWorkers =
3051 RelationGetRelid(indexRelation));
3052
3053 if (indexInfo->ii_ParallelWorkers == 0)
3055 (errmsg_internal("building index \"%s\" on table \"%s\" serially",
3056 RelationGetRelationName(indexRelation),
3057 RelationGetRelationName(heapRelation))));
3058 else
3060 (errmsg_internal("building index \"%s\" on table \"%s\" with request for %d parallel workers",
3061 RelationGetRelationName(indexRelation),
3062 RelationGetRelationName(heapRelation),
3063 indexInfo->ii_ParallelWorkers)));
3064
3065 /*
3066 * Switch to the table owner's userid, so that any index functions are run
3067 * as that user. Also lock down security-restricted operations and
3068 * arrange to make GUC variable changes local to this command.
3069 */
3070 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3071 SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3072 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3073 save_nestlevel = NewGUCNestLevel();
3075
3076 /* Set up initial progress report status */
3077 if (progress)
3078 {
3079 const int progress_index[] = {
3086 };
3087 const int64 progress_vals[] = {
3090 0, 0, 0, 0
3091 };
3092
3094 }
3095
3096 /*
3097 * Call the access method's build procedure
3098 */
3099 stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation,
3100 indexInfo);
3101 Assert(stats);
3102
3103 /*
3104 * If this is an unlogged index, we may need to write out an init fork for
3105 * it -- but we must first check whether one already exists. If, for
3106 * example, an unlogged relation is truncated in the transaction that
3107 * created it, or truncated twice in a subsequent transaction, the
3108 * relfilenumber won't change, and nothing needs to be done here.
3109 */
3110 if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
3111 !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
3112 {
3113 smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3114 log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
3115 indexRelation->rd_indam->ambuildempty(indexRelation);
3116 }
3117
3118 /*
3119 * If we found any potentially broken HOT chains, mark the index as not
3120 * being usable until the current transaction is below the event horizon.
3121 * See src/backend/access/heap/README.HOT for discussion. While it might
3122 * become safe to use the index earlier based on actual cleanup activity
3123 * and other active transactions, the test for that would be much more
3124 * complex and would require some form of blocking, so keep it simple and
3125 * fast by just using the current transaction.
3126 *
3127 * However, when reindexing an existing index, we should do nothing here.
3128 * Any HOT chains that are broken with respect to the index must predate
3129 * the index's original creation, so there is no need to change the
3130 * index's usability horizon. Moreover, we *must not* try to change the
3131 * index's pg_index entry while reindexing pg_index itself, and this
3132 * optimization nicely prevents that. The more complex rules needed for a
3133 * reindex are handled separately after this function returns.
3134 *
3135 * We also need not set indcheckxmin during a concurrent index build,
3136 * because we won't set indisvalid true until all transactions that care
3137 * about the broken HOT chains are gone.
3138 *
3139 * Therefore, this code path can only be taken during non-concurrent
3140 * CREATE INDEX. Thus the fact that heap_update will set the pg_index
3141 * tuple's xmin doesn't matter, because that tuple was created in the
3142 * current transaction anyway. That also means we don't need to worry
3143 * about any concurrent readers of the tuple; no other transaction can see
3144 * it yet.
3145 */
3146 if (indexInfo->ii_BrokenHotChain &&
3147 !isreindex &&
3148 !indexInfo->ii_Concurrent)
3149 {
3150 Oid indexId = RelationGetRelid(indexRelation);
3154
3156
3160 elog(ERROR, "cache lookup failed for index %u", indexId);
3162
3163 /* If it's a new index, indcheckxmin shouldn't be set ... */
3164 Assert(!indexForm->indcheckxmin);
3165
3166 indexForm->indcheckxmin = true;
3168
3171 }
3172
3173 /*
3174 * Update heap and index pg_class rows
3175 */
3176 index_update_stats(heapRelation,
3177 true,
3178 stats->heap_tuples);
3179
3180 index_update_stats(indexRelation,
3181 false,
3182 stats->index_tuples);
3183
3184 /* Make the updated catalog row versions visible */
3186
3187 /*
3188 * If it's for an exclusion constraint, make a second pass over the heap
3189 * to verify that the constraint is satisfied. We must not do this until
3190 * the index is fully valid. (Broken HOT chains shouldn't matter, though;
3191 * see comments for IndexCheckExclusion.)
3192 */
3193 if (indexInfo->ii_ExclusionOps != NULL)
3194 IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
3195
3196 /* Roll back any GUC changes executed by index functions */
3197 AtEOXact_GUC(false, save_nestlevel);
3198
3199 /* Restore userid and security context */
3200 SetUserIdAndSecContext(save_userid, save_sec_context);
3201}
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
int64_t int64
Definition c.h:621
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define DEBUG1
Definition elog.h:30
#define ereport(elevel,...)
Definition elog.h:151
int NewGUCNestLevel(void)
Definition guc.c:2142
void RestrictSearchPath(void)
Definition guc.c:2153
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2169
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
static void index_update_stats(Relation rel, bool hasindex, double reltuples)
Definition index.c:2827
static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
Definition index.c:3216
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:320
#define IsNormalProcessingMode()
Definition miscadmin.h:486
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c:613
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:620
static int progress
Definition pgbench.c:262
int plan_create_index_workers(Oid tableOid, Oid indexOid)
Definition planner.c:7041
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition progress.h:123
#define PROGRESS_CREATEIDX_TUPLES_TOTAL
Definition progress.h:115
#define PROGRESS_SCAN_BLOCKS_DONE
Definition progress.h:151
#define PROGRESS_CREATEIDX_TUPLES_DONE
Definition progress.h:116
#define PROGRESS_CREATEIDX_SUBPHASE
Definition progress.h:114
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition progress.h:135
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:113
#define PROGRESS_SCAN_BLOCKS_TOTAL
Definition progress.h:150
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:578
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationIsValid(relation)
Definition rel.h:491
@ INIT_FORKNUM
Definition relpath.h:61
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition smgr.c:481
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:462
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition storage.c:187
ambuildempty_function ambuildempty
Definition amapi.h:296
ambuild_function ambuild
Definition amapi.h:295
bool amcanbuildparallel
Definition amapi.h:276
double heap_tuples
Definition genam.h:40
double index_tuples
Definition genam.h:41
bool ii_BrokenHotChain
Definition execnodes.h:226
int ii_ParallelWorkers
Definition execnodes.h:232
bool ii_Concurrent
Definition execnodes.h:224
const struct IndexAmRoutine * rd_indam
Definition rel.h:206
RelFileLocator rd_locator
Definition rel.h:57
Form_pg_class rd_rel
Definition rel.h:111
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void CommandCounterIncrement(void)
Definition xact.c:1130

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

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

◆ index_check_primary_key()

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

Definition at line 203 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1503 of file index.c.

1505{
1506 Relation heapRel;
1507 Oid save_userid;
1508 int save_sec_context;
1509 int save_nestlevel;
1510 Relation indexRelation;
1511 IndexInfo *indexInfo;
1512
1513 /* This had better make sure that a snapshot is active */
1515
1516 /* Open and lock the parent heap relation */
1518
1519 /*
1520 * Switch to the table owner's userid, so that any index functions are run
1521 * as that user. Also lock down security-restricted operations and
1522 * arrange to make GUC variable changes local to this command.
1523 */
1524 GetUserIdAndSecContext(&save_userid, &save_sec_context);
1525 SetUserIdAndSecContext(heapRel->rd_rel->relowner,
1526 save_sec_context | SECURITY_RESTRICTED_OPERATION);
1527 save_nestlevel = NewGUCNestLevel();
1529
1531
1532 /*
1533 * We have to re-build the IndexInfo struct, since it was lost in the
1534 * commit of the transaction where this concurrent index was created at
1535 * the catalog level.
1536 */
1537 indexInfo = BuildIndexInfo(indexRelation);
1538 Assert(!indexInfo->ii_ReadyForInserts);
1539 indexInfo->ii_Concurrent = true;
1540 indexInfo->ii_BrokenHotChain = false;
1541
1542 /* Now build the index */
1543 index_build(heapRel, indexRelation, indexInfo, false, true, true);
1544
1545 /* Roll back any GUC changes executed by index functions */
1546 AtEOXact_GUC(false, save_nestlevel);
1547
1548 /* Restore userid and security context */
1549 SetUserIdAndSecContext(save_userid, save_sec_context);
1550
1551 /* Close both the relations, but keep the locks */
1552 table_close(heapRel, NoLock);
1553 index_close(indexRelation, NoLock);
1554
1555 /*
1556 * Update the pg_index row to mark the index as ready for inserts. Once we
1557 * commit this transaction, any new transactions that open the table must
1558 * insert new entries into the index for insertions and non-HOT updates.
1559 */
1561}
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel, bool progress)
Definition index.c:3021
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3524
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2446
@ INDEX_CREATE_SET_READY
Definition index.h:32
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
#define NoLock
Definition lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
bool ActiveSnapshotSet(void)
Definition snapmgr.c:812
bool ii_ReadyForInserts
Definition execnodes.h:218

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1841 of file index.c.

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

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

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

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

Definition at line 1570 of file index.c.

1571{
1573 pg_index,
1575 pg_trigger;
1586 bool isPartition;
1589 ListCell *lc;
1590
1591 /*
1592 * Take a necessary lock on the old and new index before swapping them.
1593 */
1596
1597 /* Now swap names and dependencies of those indexes */
1599
1603 elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1607 elog(ERROR, "could not find tuple for relation %u", newIndexId);
1608
1611
1612 /* Swap the names */
1613 namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1614 namestrcpy(&oldClassForm->relname, oldName);
1615
1616 /* Swap the partition flags to track inheritance properly */
1617 isPartition = newClassForm->relispartition;
1618 newClassForm->relispartition = oldClassForm->relispartition;
1619 oldClassForm->relispartition = isPartition;
1620
1623
1626
1627 /* Now swap index info */
1629
1633 elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1637 elog(ERROR, "could not find tuple for relation %u", newIndexId);
1638
1641
1642 /*
1643 * Copy constraint flags from the old index. This is safe because the old
1644 * index guaranteed uniqueness.
1645 */
1646 newIndexForm->indisprimary = oldIndexForm->indisprimary;
1647 oldIndexForm->indisprimary = false;
1648 newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1649 oldIndexForm->indisexclusion = false;
1650 newIndexForm->indimmediate = oldIndexForm->indimmediate;
1651 oldIndexForm->indimmediate = true;
1652
1653 /* Preserve indisreplident in the new index */
1654 newIndexForm->indisreplident = oldIndexForm->indisreplident;
1655
1656 /* Preserve indisclustered in the new index */
1657 newIndexForm->indisclustered = oldIndexForm->indisclustered;
1658
1659 /*
1660 * Mark the new index as valid, and the old index as invalid similarly to
1661 * what index_set_state_flags() does.
1662 */
1663 newIndexForm->indisvalid = true;
1664 oldIndexForm->indisvalid = false;
1665 oldIndexForm->indisclustered = false;
1666 oldIndexForm->indisreplident = false;
1667
1670
1673
1674 /*
1675 * Move constraints and triggers over to the new index
1676 */
1677
1679
1681
1684
1687
1688 foreach(lc, constraintOids)
1689 {
1693 ScanKeyData key[1];
1694 SysScanDesc scan;
1696
1697 /* Move the constraint from the old to the new index */
1701 elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1702
1704
1705 if (conForm->conindid == oldIndexId)
1706 {
1707 conForm->conindid = newIndexId;
1708
1710 }
1711
1713
1714 /* Search for trigger records */
1715 ScanKeyInit(&key[0],
1719
1721 NULL, 1, key);
1722
1724 {
1726
1727 if (tgForm->tgconstrindid != oldIndexId)
1728 continue;
1729
1730 /* Make a modifiable copy */
1733
1734 tgForm->tgconstrindid = newIndexId;
1735
1737
1739 }
1740
1741 systable_endscan(scan);
1742 }
1743
1744 /*
1745 * Move comment if any
1746 */
1747 {
1749 ScanKeyData skey[3];
1751 HeapTuple tuple;
1753 bool nulls[Natts_pg_description] = {0};
1754 bool replaces[Natts_pg_description] = {0};
1755
1758
1759 ScanKeyInit(&skey[0],
1763 ScanKeyInit(&skey[1],
1767 ScanKeyInit(&skey[2],
1770 Int32GetDatum(0));
1771
1773
1775 NULL, 3, skey);
1776
1777 while ((tuple = systable_getnext(sd)) != NULL)
1778 {
1780 values, nulls, replaces);
1781 CatalogTupleUpdate(description, &tuple->t_self, tuple);
1782
1783 break; /* Assume there can be only one match */
1784 }
1785
1788 }
1789
1790 /*
1791 * Swap inheritance relationship with parent index
1792 */
1794 {
1796 Oid parentIndexRelid = linitial_oid(ancestors);
1797
1800
1801 list_free(ancestors);
1802 }
1803
1804 /*
1805 * Swap all dependencies of and on the old index to the new one, and
1806 * vice-versa. Note that a call to CommandCounterIncrement() would cause
1807 * duplicate entries in pg_depend, so this should not be done.
1808 */
1811
1814
1815 /* copy over statistics from old to new index */
1817
1818 /* Copy data of pg_statistic from the old index to the new one */
1820
1821 /* Close relations */
1826
1827 /* The lock taken previously is not released until the end of transaction */
1830}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
void CopyStatistics(Oid fromrelid, Oid torelid)
Definition heap.c:3442
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:686
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
void list_free(List *list)
Definition list.c:1546
bool get_rel_relispartition(Oid relid)
Definition lsyscache.c:2247
List * get_partition_ancestors(Oid relid)
Definition partition.c:134
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition pg_depend.c:567
List * get_index_ref_constraints(Oid indexId)
Definition pg_depend.c:1117
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:623
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1061
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
#define linitial_oid(l)
Definition pg_list.h:180
#define lfirst_oid(lc)
Definition pg_list.h:174
END_CATALOG_STRUCT typedef FormData_pg_trigger * Form_pg_trigger
Definition pg_trigger.h:84
void pgstat_copy_relation_stats(Relation dst, Relation src)
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
#define BTEqualStrategyNumber
Definition stratnum.h:31
ItemPointerData t_self
Definition htup.h:65
Definition pg_list.h:54
const char * description

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1903 of file index.c.

1912{
1913 Oid namespaceId = RelationGetNamespace(heapRelation);
1915 idxaddr;
1916 Oid conOid;
1917 bool deferrable;
1918 bool initdeferred;
1919 bool mark_as_primary;
1920 bool islocal;
1921 bool noinherit;
1923 int16 inhcount;
1924
1925 deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1926 initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1929
1930 /* constraint creation support doesn't work while bootstrapping */
1932
1933 /* enforce system-table restriction */
1935 IsSystemRelation(heapRelation) &&
1937 ereport(ERROR,
1939 errmsg("user-defined indexes on system catalog tables are not supported")));
1940
1941 /* primary/unique constraints shouldn't have any expressions */
1942 if (indexInfo->ii_Expressions &&
1944 elog(ERROR, "constraints cannot have index expressions");
1945
1946 /*
1947 * If we're manufacturing a constraint for a pre-existing index, we need
1948 * to get rid of the existing auto dependencies for the index (the ones
1949 * that index_create() would have made instead of calling this function).
1950 *
1951 * Note: this code would not necessarily do the right thing if the index
1952 * has any expressions or predicate, but we'd never be turning such an
1953 * index into a UNIQUE or PRIMARY KEY constraint.
1954 */
1958
1960 {
1961 islocal = false;
1962 inhcount = 1;
1963 noinherit = false;
1964 }
1965 else
1966 {
1967 islocal = true;
1968 inhcount = 0;
1969 noinherit = true;
1970 }
1971
1972 /*
1973 * Construct a pg_constraint entry.
1974 */
1978 deferrable,
1979 initdeferred,
1980 true, /* Is Enforced */
1981 true,
1983 RelationGetRelid(heapRelation),
1984 indexInfo->ii_IndexAttrNumbers,
1985 indexInfo->ii_NumIndexKeyAttrs,
1986 indexInfo->ii_NumIndexAttrs,
1987 InvalidOid, /* no domain */
1988 indexRelationId, /* index OID */
1989 InvalidOid, /* no foreign key */
1990 NULL,
1991 NULL,
1992 NULL,
1993 NULL,
1994 0,
1995 ' ',
1996 ' ',
1997 NULL,
1998 0,
1999 ' ',
2000 indexInfo->ii_ExclusionOps,
2001 NULL, /* no check constraint */
2002 NULL,
2003 islocal,
2004 inhcount,
2005 noinherit,
2007 is_internal);
2008
2009 /*
2010 * Register the index as internally dependent on the constraint.
2011 *
2012 * Note that the constraint has a dependency on the table, so we don't
2013 * need (or want) any direct dependency from the index to the table.
2014 */
2018
2019 /*
2020 * Also, if this is a constraint on a partition, give it partition-type
2021 * dependencies on the parent constraint as well as the table.
2022 */
2024 {
2026
2030 RelationGetRelid(heapRelation));
2032 }
2033
2034 /*
2035 * If the constraint is deferrable, create the deferred uniqueness
2036 * checking trigger. (The trigger will be given an internal dependency on
2037 * the constraint by CreateTrigger.)
2038 */
2039 if (deferrable)
2040 {
2042
2043 trigger->replace = false;
2044 trigger->isconstraint = true;
2045 trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
2046 "PK_ConstraintTrigger" :
2047 "Unique_ConstraintTrigger";
2048 trigger->relation = NULL;
2049 trigger->funcname = SystemFuncName("unique_key_recheck");
2050 trigger->args = NIL;
2051 trigger->row = true;
2052 trigger->timing = TRIGGER_TYPE_AFTER;
2054 trigger->columns = NIL;
2055 trigger->whenClause = NULL;
2056 trigger->transitionRels = NIL;
2057 trigger->deferrable = true;
2058 trigger->initdeferred = initdeferred;
2059 trigger->constrrel = NULL;
2060
2063 InvalidOid, NULL, true, false);
2064 }
2065
2066 /*
2067 * If needed, mark the index as primary and/or deferred in pg_index.
2068 *
2069 * Note: When making an existing index into a constraint, caller must have
2070 * a table lock that prevents concurrent table updates; otherwise, there
2071 * is a risk that concurrent readers of the table will miss seeing this
2072 * index at all.
2073 */
2075 (mark_as_primary || deferrable))
2076 {
2080 bool dirty = false;
2081 bool marked_as_primary = false;
2082
2084
2088 elog(ERROR, "cache lookup failed for index %u", indexRelationId);
2090
2091 if (mark_as_primary && !indexForm->indisprimary)
2092 {
2093 indexForm->indisprimary = true;
2094 dirty = true;
2095 marked_as_primary = true;
2096 }
2097
2098 if (deferrable && indexForm->indimmediate)
2099 {
2100 indexForm->indimmediate = false;
2101 dirty = true;
2102 }
2103
2104 if (dirty)
2105 {
2107
2108 /*
2109 * When we mark an existing index as primary, force a relcache
2110 * flush on its parent table, so that all sessions will become
2111 * aware that the table now has a primary key. This is important
2112 * because it affects some replication behaviors.
2113 */
2115 CacheInvalidateRelcache(heapRelation);
2116
2118 InvalidOid, is_internal);
2119 }
2120
2123 }
2124
2125 return myself;
2126}
int16_t int16
Definition c.h:619
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition dependency.h:37
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition index.h:103
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition index.h:101
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition index.h:102
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition index.h:99
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition index.h:98
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:100
#define IsBootstrapProcessingMode()
Definition miscadmin.h:484
#define makeNode(_type_)
Definition nodes.h:161
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
#define ObjectAddressSet(addr, class_id, object_id)
List * SystemFuncName(char *name)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:47
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:353
#define RelationGetNamespace(relation)
Definition rel.h:557
ObjectAddress CreateTrigger(const 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:162

References Assert, CacheInvalidateRelcache(), CatalogTupleUpdate(), CreateConstraintEntry(), CreateTrigger(), deleteDependencyRecordsForClass(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_index, GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_MARK_AS_PRIMARY, INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS, INDEX_CONSTR_CREATE_UPDATE_INDEX, INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS, InvalidOid, InvokeObjectPostAlterHookArg, IsBootstrapProcessingMode, IsNormalProcessingMode, IsSystemRelation(), makeNode, NIL, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, recordDependencyOn(), RelationGetNamespace, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy1, SystemFuncName(), table_close(), and table_open().

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 730 of file index.c.

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

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

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

◆ index_create_copy()

Oid index_create_copy ( Relation  heapRelation,
uint16  flags,
Oid  oldIndexId,
Oid  tablespaceOid,
const char newName 
)

Definition at line 1306 of file index.c.

1308{
1309 Relation indexRelation;
1311 *newInfo;
1313 bool concurrently = (flags & INDEX_CREATE_CONCURRENT) != 0;
1315 classTuple;
1323 bool isnull;
1325 List *indexExprs = NIL;
1326 List *indexPreds = NIL;
1327
1328 indexRelation = index_open(oldIndexId, RowExclusiveLock);
1329
1330 /* The new index needs some information from the old index */
1331 oldInfo = BuildIndexInfo(indexRelation);
1332
1333 /*
1334 * Concurrent build of an index with exclusion constraints is not
1335 * supported.
1336 */
1337 if (oldInfo->ii_ExclusionOps != NULL && concurrently)
1338 ereport(ERROR,
1340 errmsg("concurrent index creation for exclusion constraints is not supported")));
1341
1342 /* Get the array of class and column options IDs from index info */
1345 elog(ERROR, "cache lookup failed for index %u", oldIndexId);
1349
1353
1354 /* Fetch reloptions of index if any */
1357 elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
1359 Anum_pg_class_reloptions, &isnull);
1360
1361 /*
1362 * Fetch the list of expressions and predicates directly from the
1363 * catalogs. This cannot rely on the information from IndexInfo of the
1364 * old index as these have been flattened for the planner.
1365 */
1366 if (oldInfo->ii_Expressions != NIL)
1367 {
1369 char *exprString;
1370
1376 }
1377 if (oldInfo->ii_Predicate != NIL)
1378 {
1380 char *predString;
1381
1386
1387 /* Also convert to implicit-AND format */
1390 }
1391
1392 /*
1393 * Build the index information for the new index.
1394 */
1395 newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1396 oldInfo->ii_NumIndexKeyAttrs,
1397 oldInfo->ii_Am,
1398 indexExprs,
1399 indexPreds,
1400 oldInfo->ii_Unique,
1401 oldInfo->ii_NullsNotDistinct,
1402 !concurrently, /* isready */
1403 concurrently, /* concurrent */
1404 indexRelation->rd_indam->amsummarizing,
1405 oldInfo->ii_WithoutOverlaps);
1406
1407 /* fetch exclusion constraint info if any */
1408 if (indexRelation->rd_index->indisexclusion)
1409 {
1410 /*
1411 * XXX Beware: we're making newInfo point to oldInfo-owned memory. It
1412 * would be more orthodox to palloc+memcpy, but we don't need that
1413 * here at present.
1414 */
1415 newInfo->ii_ExclusionOps = oldInfo->ii_ExclusionOps;
1416 newInfo->ii_ExclusionProcs = oldInfo->ii_ExclusionProcs;
1417 newInfo->ii_ExclusionStrats = oldInfo->ii_ExclusionStrats;
1418 }
1419
1420 /*
1421 * Extract the list of column names and the column numbers for the new
1422 * index information. All this information will be used for the index
1423 * creation.
1424 */
1425 for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++)
1426 {
1427 TupleDesc indexTupDesc = RelationGetDescr(indexRelation);
1429
1431 newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i];
1432 }
1433
1434 /* Extract opclass options for each attribute */
1435 opclassOptions = palloc0_array(Datum, newInfo->ii_NumIndexAttrs);
1436 for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1438
1439 /* Extract statistic targets for each attribute */
1440 stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs);
1441 for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1442 {
1443 HeapTuple tp;
1444 Datum dat;
1445
1447 if (!HeapTupleIsValid(tp))
1448 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1449 i + 1, oldIndexId);
1451 ReleaseSysCache(tp);
1452 stattargets[i].value = dat;
1453 stattargets[i].isnull = isnull;
1454 }
1455
1456 /*
1457 * Now create the new index.
1458 *
1459 * For a partition index, we adjust the partition dependency later, to
1460 * ensure a consistent state at all times. That is why parentIndexRelid
1461 * is not set here.
1462 */
1463 newIndexId = index_create(heapRelation,
1464 newName,
1465 InvalidOid, /* indexRelationId */
1466 InvalidOid, /* parentIndexRelid */
1467 InvalidOid, /* parentConstraintId */
1468 InvalidRelFileNumber, /* relFileNumber */
1469 newInfo,
1471 indexRelation->rd_rel->relam,
1472 tablespaceOid,
1473 indexRelation->rd_indcollation,
1474 indclass->values,
1476 indcoloptions->values,
1479 flags,
1480 0,
1481 true, /* allow table to be a system catalog? */
1482 false, /* is_internal? */
1483 NULL);
1484
1485 /* Close the relations used and clean up */
1486 index_close(indexRelation, NoLock);
1489
1490 return newIndexId;
1491}
#define TextDatumGetCString(d)
Definition builtins.h:99
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, uint16 flags, uint16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:730
List * lappend(List *list, void *datum)
Definition list.c:339
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
void pfree(void *pointer)
Definition mcxt.c:1616
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
void * stringToNode(const char *str)
Definition read.c:90
bool amsummarizing
Definition amapi.h:282
Oid * rd_indcollation
Definition rel.h:217
Definition c.h:815
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596

References IndexAmRoutine::amsummarizing, BuildIndexInfo(), DatumGetPointer(), elog, ereport, errcode(), errmsg, ERROR, fb(), get_attoptions(), HeapTupleIsValid, i, index_close(), index_create(), INDEX_CREATE_CONCURRENT, index_open(), Int16GetDatum(), InvalidOid, InvalidRelFileNumber, lappend(), make_ands_implicit(), makeIndexInfo(), NameStr, NIL, NoLock, ObjectIdGetDatum(), palloc0_array, pfree(), RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_rel, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCache2(), stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), TextDatumGetCString, and TupleDescAttr().

Referenced by build_new_indexes(), and ReindexRelationConcurrently().

◆ index_drop()

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

Definition at line 2140 of file index.c.

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

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

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3524 of file index.c.

3525{
3529
3530 /* Open pg_index and fetch a writable copy of the index's tuple */
3532
3536 elog(ERROR, "cache lookup failed for index %u", indexId);
3538
3539 /* Perform the requested state change on the copy */
3540 switch (action)
3541 {
3543 /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3544 Assert(indexForm->indislive);
3545 Assert(!indexForm->indisready);
3546 Assert(!indexForm->indisvalid);
3547 indexForm->indisready = true;
3548 break;
3550 /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3551 Assert(indexForm->indislive);
3552 Assert(indexForm->indisready);
3553 Assert(!indexForm->indisvalid);
3554 indexForm->indisvalid = true;
3555 break;
3557
3558 /*
3559 * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3560 *
3561 * If indisready == true we leave it set so the index still gets
3562 * maintained by active transactions. We only need to ensure that
3563 * indisvalid is false. (We don't assert that either is initially
3564 * true, though, since we want to be able to retry a DROP INDEX
3565 * CONCURRENTLY that failed partway through.)
3566 *
3567 * Note: the CLUSTER logic assumes that indisclustered cannot be
3568 * set on any invalid index, so clear that flag too. For
3569 * cleanliness, also clear indisreplident.
3570 */
3571 indexForm->indisvalid = false;
3572 indexForm->indisclustered = false;
3573 indexForm->indisreplident = false;
3574 break;
3576
3577 /*
3578 * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3579 *
3580 * We clear both indisready and indislive, because we not only
3581 * want to stop updates, we want to prevent sessions from touching
3582 * the index at all.
3583 */
3584 Assert(!indexForm->indisvalid);
3585 Assert(!indexForm->indisclustered);
3586 Assert(!indexForm->indisreplident);
3587 indexForm->indisready = false;
3588 indexForm->indislive = false;
3589 break;
3590 }
3591
3592 /* ... and update it */
3594
3596}
@ INDEX_CREATE_SET_VALID
Definition index.h:33

References Assert, CatalogTupleUpdate(), elog, ERROR, fb(), Form_pg_index, GETSTRUCT(), HeapTupleIsValid, INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_DROP_CLEAR_VALID, INDEX_DROP_SET_DEAD, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

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

◆ index_update_stats()

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

Definition at line 2827 of file index.c.

2830{
2831 bool update_stats;
2832 BlockNumber relpages = 0; /* keep compiler quiet */
2833 BlockNumber relallvisible = 0;
2834 BlockNumber relallfrozen = 0;
2835 Oid relid = RelationGetRelid(rel);
2837 ScanKeyData key[1];
2838 HeapTuple tuple;
2839 void *state;
2840 Form_pg_class rd_rel;
2841 bool dirty;
2842
2843 /*
2844 * As a special hack, if we are dealing with an empty table and the
2845 * existing reltuples is -1, we leave that alone. This ensures that
2846 * creating an index as part of CREATE TABLE doesn't cause the table to
2847 * prematurely look like it's been vacuumed. The rd_rel we modify may
2848 * differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2849 * commands that change reltuples take locks conflicting with ours. (Even
2850 * if a command changed reltuples under a weaker lock, this affects only
2851 * statistics for an empty table.)
2852 */
2853 if (reltuples == 0 && rel->rd_rel->reltuples < 0)
2854 reltuples = -1;
2855
2856 /*
2857 * Don't update statistics during binary upgrade, because the indexes are
2858 * created before the data is moved into place.
2859 */
2860 update_stats = reltuples >= 0 && !IsBinaryUpgrade;
2861
2862 /*
2863 * If autovacuum is off, user may not be expecting table relstats to
2864 * change. This can be important when restoring a dump that includes
2865 * statistics, as the table statistics may be restored before the index is
2866 * created, and we want to preserve the restored table statistics.
2867 */
2868 if (rel->rd_rel->relkind == RELKIND_RELATION ||
2869 rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
2870 rel->rd_rel->relkind == RELKIND_MATVIEW)
2871 {
2872 if (AutoVacuumingActive())
2873 {
2875
2876 if (options != NULL && !options->autovacuum.enabled)
2877 update_stats = false;
2878 }
2879 else
2880 update_stats = false;
2881 }
2882
2883 /*
2884 * Finish I/O and visibility map buffer locks before
2885 * systable_inplace_update_begin() locks the pg_class buffer. The rd_rel
2886 * we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2887 * GRANT, but no command changes a relkind from non-index to index. (Even
2888 * if one did, relallvisible doesn't break functionality.)
2889 */
2890 if (update_stats)
2891 {
2892 relpages = RelationGetNumberOfBlocks(rel);
2893
2894 if (rel->rd_rel->relkind != RELKIND_INDEX)
2895 visibilitymap_count(rel, &relallvisible, &relallfrozen);
2896 }
2897
2898 /*
2899 * We always update the pg_class row using a non-transactional,
2900 * overwrite-in-place update. There are several reasons for this:
2901 *
2902 * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work.
2903 *
2904 * 2. We could be reindexing pg_class itself, in which case we can't move
2905 * its pg_class row because CatalogTupleInsert/CatalogTupleUpdate might
2906 * not know about all the indexes yet (see reindex_relation).
2907 *
2908 * 3. Because we execute CREATE INDEX with just share lock on the parent
2909 * rel (to allow concurrent index creations), an ordinary update could
2910 * suffer a tuple-concurrently-updated failure against another CREATE
2911 * INDEX committing at about the same time. We can avoid that by having
2912 * them both do nontransactional updates (we assume they will both be
2913 * trying to change the pg_class row to the same thing, so it doesn't
2914 * matter which goes first).
2915 *
2916 * It is safe to use a non-transactional update even though our
2917 * transaction could still fail before committing. Setting relhasindex
2918 * true is safe even if there are no indexes (VACUUM will eventually fix
2919 * it). And of course the new relpages and reltuples counts are correct
2920 * regardless. However, we don't want to change relpages (or
2921 * relallvisible) if the caller isn't providing an updated reltuples
2922 * count, because that would bollix the reltuples/relpages ratio which is
2923 * what's really important.
2924 */
2925
2927
2928 ScanKeyInit(&key[0],
2931 ObjectIdGetDatum(relid));
2933 1, key, &tuple, &state);
2934
2935 if (!HeapTupleIsValid(tuple))
2936 elog(ERROR, "could not find tuple for relation %u", relid);
2937 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
2938
2939 /* Should this be a more comprehensive test? */
2940 Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
2941
2942 /* Apply required updates, if any, to copied tuple */
2943
2944 dirty = false;
2945 if (rd_rel->relhasindex != hasindex)
2946 {
2947 rd_rel->relhasindex = hasindex;
2948 dirty = true;
2949 }
2950
2951 if (update_stats)
2952 {
2953 if (rd_rel->relpages != (int32) relpages)
2954 {
2955 rd_rel->relpages = (int32) relpages;
2956 dirty = true;
2957 }
2958 if (rd_rel->reltuples != (float4) reltuples)
2959 {
2960 rd_rel->reltuples = (float4) reltuples;
2961 dirty = true;
2962 }
2963 if (rd_rel->relallvisible != (int32) relallvisible)
2964 {
2965 rd_rel->relallvisible = (int32) relallvisible;
2966 dirty = true;
2967 }
2968 if (rd_rel->relallfrozen != (int32) relallfrozen)
2969 {
2970 rd_rel->relallfrozen = (int32) relallfrozen;
2971 dirty = true;
2972 }
2973 }
2974
2975 /*
2976 * If anything changed, write out the tuple
2977 */
2978 if (dirty)
2979 {
2981 /* the above sends transactional and immediate cache inval messages */
2982 }
2983 else
2984 {
2986
2987 /*
2988 * While we didn't change relhasindex, CREATE INDEX needs a
2989 * transactional inval for when the new index's catalog rows become
2990 * visible. Other CREATE INDEX and REINDEX code happens to also queue
2991 * this inval, but keep this in case rare callers rely on this part of
2992 * our API contract.
2993 */
2995 }
2996
2997 heap_freetuple(tuple);
2998
3000}
bool AutoVacuumingActive(void)
uint32 BlockNumber
Definition block.h:31
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:309
int32_t int32
Definition c.h:620
float float4
Definition c.h:713
void systable_inplace_update_cancel(void *state)
Definition genam.c:905
void systable_inplace_update_begin(Relation relation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, const ScanKeyData *key, HeapTuple *oldtupcopy, void **state)
Definition genam.c:810
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition genam.c:886
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition inval.c:1669
bytea * rd_options
Definition rel.h:175
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)

References Assert, AutoVacuumingActive(), BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), elog, ERROR, fb(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, IsBinaryUpgrade, ObjectIdGetDatum(), RelationData::rd_options, RelationData::rd_rel, RelationGetNumberOfBlocks, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), systable_inplace_update_begin(), systable_inplace_update_cancel(), systable_inplace_update_finish(), table_close(), table_open(), and visibilitymap_count().

Referenced by index_build(), and index_create().

◆ IndexCheckExclusion()

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

Definition at line 3216 of file index.c.

3219{
3220 TableScanDesc scan;
3222 bool isnull[INDEX_MAX_KEYS];
3224 TupleTableSlot *slot;
3225 EState *estate;
3226 ExprContext *econtext;
3227 Snapshot snapshot;
3228
3229 /*
3230 * If we are reindexing the target index, mark it as no longer being
3231 * reindexed, to forestall an Assert in index_beginscan when we try to use
3232 * the index for probes. This is OK because the index is now fully valid.
3233 */
3236
3237 /*
3238 * Need an EState for evaluation of index expressions and partial-index
3239 * predicates. Also a slot to hold the current tuple.
3240 */
3241 estate = CreateExecutorState();
3242 econtext = GetPerTupleExprContext(estate);
3243 slot = table_slot_create(heapRelation, NULL);
3244
3245 /* Arrange for econtext's scan tuple to be the tuple under test */
3246 econtext->ecxt_scantuple = slot;
3247
3248 /* Set up execution state for predicate, if any. */
3249 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3250
3251 /*
3252 * Scan all live tuples in the base relation.
3253 */
3254 snapshot = RegisterSnapshot(GetLatestSnapshot());
3255 scan = table_beginscan_strat(heapRelation, /* relation */
3256 snapshot, /* snapshot */
3257 0, /* number of keys */
3258 NULL, /* scan key */
3259 true, /* buffer access strategy OK */
3260 true); /* syncscan OK */
3261
3262 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3263 {
3265
3266 /*
3267 * In a partial index, ignore tuples that don't satisfy the predicate.
3268 */
3269 if (predicate != NULL)
3270 {
3271 if (!ExecQual(predicate, econtext))
3272 continue;
3273 }
3274
3275 /*
3276 * Extract index column values, including computing expressions.
3277 */
3278 FormIndexDatum(indexInfo,
3279 slot,
3280 estate,
3281 values,
3282 isnull);
3283
3284 /*
3285 * Check that this tuple has no conflicts.
3286 */
3287 check_exclusion_constraint(heapRelation,
3288 indexRelation, indexInfo,
3289 &(slot->tts_tid), values, isnull,
3290 estate, true);
3291
3293 }
3294
3295 table_endscan(scan);
3296 UnregisterSnapshot(snapshot);
3297
3299
3300 FreeExecutorState(estate);
3301
3302 /* These may have been pointing to the now-gone estate */
3303 indexInfo->ii_ExpressionsState = NIL;
3304 indexInfo->ii_PredicateState = NULL;
3305}
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition execExpr.c:826
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, const ItemPointerData *tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
void FreeExecutorState(EState *estate)
Definition execUtils.c:197
EState * CreateExecutorState(void)
Definition execUtils.c:90
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition executor.h:522
static void ResetReindexProcessing(void)
Definition index.c:4191
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition index.c:4150
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition index.c:2748
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
@ ForwardScanDirection
Definition sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition snapmgr.c:354
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
MemoryContext ecxt_per_tuple_memory
Definition execnodes.h:295
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:287
ExprState * ii_PredicateState
Definition execnodes.h:199
ItemPointerData tts_tid
Definition tuptable.h:142
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition tableam.c:92
static void table_endscan(TableScanDesc scan)
Definition tableam.h:1058
static TableScanDesc table_beginscan_strat(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key, bool allow_strat, bool allow_sync)
Definition tableam.h:965
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition tableam.h:1093

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

Referenced by index_build().

◆ IndexGetRelation()

◆ InitializeAttributeOids()

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

Definition at line 495 of file index.c.

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

References fb(), i, RelationGetDescr, and TupleDescAttr().

Referenced by index_create().

◆ reindex_index()

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

Definition at line 3629 of file index.c.

3632{
3633 Relation iRel,
3634 heapRelation;
3635 Oid heapId;
3636 Oid save_userid;
3637 int save_sec_context;
3638 int save_nestlevel;
3639 IndexInfo *indexInfo;
3640 volatile bool skipped_constraint = false;
3641 PGRUsage ru0;
3642 bool progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
3643 bool set_tablespace = false;
3644
3646
3647 /*
3648 * Open and lock the parent heap relation. ShareLock is sufficient since
3649 * we only need to be sure no schema or data changes are going on.
3650 */
3652 (params->options & REINDEXOPT_MISSING_OK) != 0);
3653 /* if relation is missing, leave */
3654 if (!OidIsValid(heapId))
3655 return;
3656
3657 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3658 heapRelation = try_table_open(heapId, ShareLock);
3659 else
3660 heapRelation = table_open(heapId, ShareLock);
3661
3662 /* if relation is gone, leave */
3663 if (!heapRelation)
3664 return;
3665
3666 /*
3667 * Switch to the table owner's userid, so that any index functions are run
3668 * as that user. Also lock down security-restricted operations and
3669 * arrange to make GUC variable changes local to this command.
3670 */
3671 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3672 SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3673 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3674 save_nestlevel = NewGUCNestLevel();
3676
3677 if (progress)
3678 {
3679 const int progress_cols[] = {
3682 };
3683 const int64 progress_vals[] = {
3685 indexId
3686 };
3687
3689 heapId);
3691 }
3692
3693 /*
3694 * Open the target index relation and get an exclusive lock on it, to
3695 * ensure that no one else is touching this particular index.
3696 */
3697 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3699 else
3701
3702 /* if index relation is gone, leave */
3703 if (!iRel)
3704 {
3705 /* Roll back any GUC changes */
3706 AtEOXact_GUC(false, save_nestlevel);
3707
3708 /* Restore userid and security context */
3709 SetUserIdAndSecContext(save_userid, save_sec_context);
3710
3711 /* Close parent heap relation, but keep locks */
3712 table_close(heapRelation, NoLock);
3713 return;
3714 }
3715
3716 if (progress)
3718 iRel->rd_rel->relam);
3719
3720 /*
3721 * If a statement is available, telling that this comes from a REINDEX
3722 * command, collect the index for event triggers.
3723 */
3724 if (stmt)
3725 {
3726 ObjectAddress address;
3727
3731 (const Node *) stmt);
3732 }
3733
3734 /*
3735 * Partitioned indexes should never get processed here, as they have no
3736 * physical storage.
3737 */
3738 if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3739 elog(ERROR, "cannot reindex partitioned index \"%s.%s\"",
3742
3743 /*
3744 * Don't allow reindex on temp tables of other backends ... their local
3745 * buffer manager is not going to cope.
3746 */
3748 ereport(ERROR,
3750 errmsg("cannot reindex temporary tables of other sessions")));
3751
3752 /*
3753 * Don't allow reindex of an invalid index on TOAST table. This is a
3754 * leftover from a failed REINDEX CONCURRENTLY, and if rebuilt it would
3755 * not be possible to drop it anymore.
3756 */
3759 ereport(ERROR,
3761 errmsg("cannot reindex invalid index on TOAST table")));
3762
3763 /*
3764 * System relations cannot be moved even if allow_system_table_mods is
3765 * enabled to keep things consistent with the concurrent case where all
3766 * the indexes of a relation are processed in series, including indexes of
3767 * toast relations.
3768 *
3769 * Note that this check is not part of CheckRelationTableSpaceMove() as it
3770 * gets used for ALTER TABLE SET TABLESPACE that could cascade across
3771 * toast relations.
3772 */
3773 if (OidIsValid(params->tablespaceOid) &&
3775 ereport(ERROR,
3777 errmsg("cannot move system relation \"%s\"",
3779
3780 /* Check if the tablespace of this index needs to be changed */
3781 if (OidIsValid(params->tablespaceOid) &&
3783 set_tablespace = true;
3784
3785 /*
3786 * Also check for active uses of the index in the current transaction; we
3787 * don't want to reindex underneath an open indexscan.
3788 */
3789 CheckTableNotInUse(iRel, "REINDEX INDEX");
3790
3791 /* Set new tablespace, if requested */
3792 if (set_tablespace)
3793 {
3794 /* Update its pg_class row */
3796
3797 /*
3798 * Schedule unlinking of the old index storage at transaction commit.
3799 */
3802
3803 /* Make sure the reltablespace change is visible */
3805 }
3806
3807 /*
3808 * All predicate locks on the index are about to be made invalid. Promote
3809 * them to relation locks on the heap.
3810 */
3812
3813 /* Fetch info needed for index_build */
3814 indexInfo = BuildIndexInfo(iRel);
3815
3816 /* If requested, skip checking uniqueness/exclusion constraints */
3818 {
3819 if (indexInfo->ii_Unique || indexInfo->ii_ExclusionOps != NULL)
3820 skipped_constraint = true;
3821 indexInfo->ii_Unique = false;
3822 indexInfo->ii_ExclusionOps = NULL;
3823 indexInfo->ii_ExclusionProcs = NULL;
3824 indexInfo->ii_ExclusionStrats = NULL;
3825 }
3826
3827 /* Suppress use of the target index while rebuilding it */
3829
3830 /* Create a new physical relation for the index */
3831 RelationSetNewRelfilenumber(iRel, persistence);
3832
3833 /* Initialize the index and rebuild */
3834 /* Note: we do not need to re-establish pkey setting */
3835 index_build(heapRelation, iRel, indexInfo, true, true, progress);
3836
3837 /* Re-allow use of target index */
3839
3840 /*
3841 * If the index is marked invalid/not-ready/dead (ie, it's from a failed
3842 * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway),
3843 * and we didn't skip a uniqueness check, we can now mark it valid. This
3844 * allows REINDEX to be used to clean up in such cases.
3845 *
3846 * We can also reset indcheckxmin, because we have now done a
3847 * non-concurrent index build, *except* in the case where index_build
3848 * found some still-broken HOT chains. If it did, and we don't have to
3849 * change any of the other flags, we just leave indcheckxmin alone (note
3850 * that index_build won't have changed it, because this is a reindex).
3851 * This is okay and desirable because not updating the tuple leaves the
3852 * index's usability horizon (recorded as the tuple's xmin value) the same
3853 * as it was.
3854 *
3855 * But, if the index was invalid/not-ready/dead and there were broken HOT
3856 * chains, we had better force indcheckxmin true, because the normal
3857 * argument that the HOT chains couldn't conflict with the index is
3858 * suspect for an invalid index. (A conflict is definitely possible if
3859 * the index was dead. It probably shouldn't happen otherwise, but let's
3860 * be conservative.) In this case advancing the usability horizon is
3861 * appropriate.
3862 *
3863 * Another reason for avoiding unnecessary updates here is that while
3864 * reindexing pg_index itself, we must not try to update tuples in it.
3865 * pg_index's indexes should always have these flags in their clean state,
3866 * so that won't happen.
3867 */
3868 if (!skipped_constraint)
3869 {
3873 bool index_bad;
3874
3876
3880 elog(ERROR, "cache lookup failed for index %u", indexId);
3882
3883 index_bad = (!indexForm->indisvalid ||
3884 !indexForm->indisready ||
3885 !indexForm->indislive);
3886 if (index_bad ||
3887 (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
3888 {
3889 if (!indexInfo->ii_BrokenHotChain)
3890 indexForm->indcheckxmin = false;
3891 else if (index_bad)
3892 indexForm->indcheckxmin = true;
3893 indexForm->indisvalid = true;
3894 indexForm->indisready = true;
3895 indexForm->indislive = true;
3897
3898 /*
3899 * Invalidate the relcache for the table, so that after we commit
3900 * all sessions will refresh the table's index list. This ensures
3901 * that if anyone misses seeing the pg_index row during this
3902 * update, they'll refresh their list before attempting any update
3903 * on the table.
3904 */
3905 CacheInvalidateRelcache(heapRelation);
3906 }
3907
3909 }
3910
3911 /* Log what we did */
3912 if ((params->options & REINDEXOPT_VERBOSE) != 0)
3913 ereport(INFO,
3914 (errmsg("index \"%s\" was reindexed",
3916 errdetail_internal("%s",
3917 pg_rusage_show(&ru0))));
3918
3919 /* Roll back any GUC changes executed by index functions */
3920 AtEOXact_GUC(false, save_nestlevel);
3921
3922 /* Restore userid and security context */
3923 SetUserIdAndSecContext(save_userid, save_sec_context);
3924
3925 /* Close rels, but keep locks */
3927 table_close(heapRelation, NoLock);
3928
3929 if (progress)
3931}
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_CREATE_INDEX
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:261
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
#define INFO
Definition elog.h:34
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, const Node *parsetree)
#define stmt
static void SetReindexProcessing(Oid heapOid, Oid indexOid)
Definition index.c:4172
#define REINDEXOPT_MISSING_OK
Definition index.h:49
#define REINDEXOPT_REPORT_PROGRESS
Definition index.h:48
#define REINDEXOPT_VERBOSE
Definition index.h:47
Relation try_index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:153
#define ShareLock
Definition lockdefs.h:40
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3825
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
const ObjectAddress InvalidObjectAddress
const char * pg_rusage_show(const PGRUsage *ru0)
Definition pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition pg_rusage.c:27
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:112
#define PROGRESS_CREATEIDX_COMMAND_REINDEX
Definition progress.h:141
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:111
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:110
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:669
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition relcache.c:3765
void RelationAssumeNewRelfilelocator(Relation relation)
Definition relcache.c:3968
Oid tablespaceOid
Definition index.h:42
uint32 options
Definition index.h:41
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:60
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition tablecmds.c:3724
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition tablecmds.c:3781

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

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

◆ reindex_relation()

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

Definition at line 3969 of file index.c.

3971{
3972 Relation rel;
3974 List *indexIds;
3975 char persistence;
3976 bool result = false;
3978 int i;
3979
3980 /*
3981 * Open and lock the relation. ShareLock is sufficient since we only need
3982 * to prevent schema and data changes in it. The lock level used here
3983 * should match ReindexTable().
3984 */
3985 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3986 rel = try_table_open(relid, ShareLock);
3987 else
3988 rel = table_open(relid, ShareLock);
3989
3990 /* if relation is gone, leave */
3991 if (!rel)
3992 return false;
3993
3994 /*
3995 * Partitioned tables should never get processed here, as they have no
3996 * physical storage.
3997 */
3998 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3999 elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
4002
4003 toast_relid = rel->rd_rel->reltoastrelid;
4004
4005 /*
4006 * Get the list of index OIDs for this relation. (We trust the relcache
4007 * to get this with a sequential scan if ignoring system indexes.)
4008 */
4010
4012 {
4013 /* Suppress use of all the indexes until they are rebuilt */
4015
4016 /*
4017 * Make the new heap contents visible --- now things might be
4018 * inconsistent!
4019 */
4021 }
4022
4023 /*
4024 * Reindex the toast table, if any, before the main table.
4025 *
4026 * This helps in cases where a corruption in the toast table's index would
4027 * otherwise error and stop REINDEX TABLE command when it tries to fetch a
4028 * toasted datum. This way. the toast table's index is rebuilt and fixed
4029 * before it is used for reindexing the main table.
4030 *
4031 * It is critical to call reindex_relation() *after* the call to
4032 * RelationGetIndexList() returning the list of indexes on the relation,
4033 * because reindex_relation() will call CommandCounterIncrement() after
4034 * every reindex_index(). See REINDEX_REL_SUPPRESS_INDEX_USE for more
4035 * details.
4036 */
4038 {
4039 /*
4040 * Note that this should fail if the toast relation is missing, so
4041 * reset REINDEXOPT_MISSING_OK. Even if a new tablespace is set for
4042 * the parent relation, the indexes on its toast table are not moved.
4043 * This rule is enforced by setting tablespaceOid to InvalidOid.
4044 */
4045 ReindexParams newparams = *params;
4046
4048 newparams.tablespaceOid = InvalidOid;
4050 }
4051
4052 /*
4053 * Compute persistence of indexes: same as that of owning rel, unless
4054 * caller specified otherwise.
4055 */
4057 persistence = RELPERSISTENCE_UNLOGGED;
4058 else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
4059 persistence = RELPERSISTENCE_PERMANENT;
4060 else
4061 persistence = rel->rd_rel->relpersistence;
4062
4063 /* Reindex all the indexes. */
4064 i = 1;
4065 foreach(indexId, indexIds)
4066 {
4067 Oid indexOid = lfirst_oid(indexId);
4069
4070 /*
4071 * Skip any invalid indexes on a TOAST table. These can only be
4072 * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
4073 * rebuilt it would not be possible to drop them anymore.
4074 */
4076 !get_index_isvalid(indexOid))
4077 {
4080 errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
4082 get_rel_name(indexOid))));
4083
4084 /*
4085 * Remove this invalid toast index from the reindex pending list,
4086 * as it is skipped here due to the hard failure that would happen
4087 * in reindex_index(), should we try to process it.
4088 */
4090 RemoveReindexPending(indexOid);
4091 continue;
4092 }
4093
4094 reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
4095 persistence, params);
4096
4098
4099 /* Index should no longer be in the pending list */
4100 Assert(!ReindexIsProcessingIndex(indexOid));
4101
4102 /* Set index rebuild count */
4104 i);
4105 i++;
4106 }
4107
4108 /*
4109 * Close rel, but continue to hold the lock.
4110 */
4111 table_close(rel, NoLock);
4112
4113 result |= (indexIds != NIL);
4114
4115 return result;
4116}
#define WARNING
Definition elog.h:36
bool ReindexIsProcessingIndex(Oid indexOid)
Definition index.c:4161
static void RemoveReindexPending(Oid indexOid)
Definition index.c:4221
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3969
static void SetReindexPending(List *indexes)
Definition index.c:4205
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition index.c:3629
#define REINDEX_REL_PROCESS_TOAST
Definition index.h:166
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition index.h:169
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition index.h:167
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition index.h:170
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:168
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2172
#define PROGRESS_REPACK_INDEX_REBUILD_COUNT
Definition progress.h:94
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4827

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

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

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4150 of file index.c.

4151{
4152 return indexOid == currentlyReindexedIndex;
4153}
static Oid currentlyReindexedIndex
Definition index.c:4131

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4140 of file index.c.

4141{
4142 return heapOid == currentlyReindexedHeap;
4143}
static Oid currentlyReindexedHeap
Definition index.c:4130

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4161 of file index.c.

4162{
4163 return indexOid == currentlyReindexedIndex ||
4165}
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722

References currentlyReindexedIndex, list_member_oid(), and pendingReindexedIndexes.

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

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 149 of file index.c.

150{
151 bool result = false;
154
155 /*
156 * Get the list of index OIDs for the table from the relcache, and look up
157 * each one in the pg_index syscache until we find one marked primary key
158 * (hopefully there isn't more than one such).
159 */
161
162 foreach(indexoidscan, indexoidlist)
163 {
164 Oid indexoid = lfirst_oid(indexoidscan);
166
168 if (!HeapTupleIsValid(indexTuple)) /* should not happen */
169 elog(ERROR, "cache lookup failed for index %u", indexoid);
172 if (result)
173 break;
174 }
175
177
178 return result;
179}

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

Referenced by index_check_primary_key().

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4221 of file index.c.

4222{
4223 if (IsInParallelMode())
4224 elog(ERROR, "cannot modify reindex state during a parallel operation");
4226 indexOid);
4227}
List * list_delete_oid(List *list, Oid datum)
Definition list.c:910
bool IsInParallelMode(void)
Definition xact.c:1119

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

Referenced by reindex_relation(), and SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4191 of file index.c.

4192{
4195 /* reindexingNestLevel remains set till end of (sub)transaction */
4196}

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4234 of file index.c.

4235{
4236 /*
4237 * Because reindexing is not re-entrant, we don't need to cope with nested
4238 * reindexing states. We just need to avoid messing up the outer-level
4239 * state in case a subtransaction fails within a REINDEX. So checking the
4240 * current nest level against that of the reindex operation is sufficient.
4241 */
4242 if (reindexingNestLevel >= nestLevel)
4243 {
4246
4247 /*
4248 * We needn't try to release the contents of pendingReindexedIndexes;
4249 * that list should be in a transaction-lifespan context, so it will
4250 * go away automatically.
4251 */
4253
4255 }
4256}
static int reindexingNestLevel
Definition index.c:4133

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void reindexstate)

Definition at line 4292 of file index.c.

4293{
4295 int c = 0;
4296 MemoryContext oldcontext;
4297
4298 currentlyReindexedHeap = sistate->currentlyReindexedHeap;
4299 currentlyReindexedIndex = sistate->currentlyReindexedIndex;
4300
4303 for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4306 sistate->pendingReindexedIndexes[c]);
4307 MemoryContextSwitchTo(oldcontext);
4308
4309 /* Note the worker has its own transaction nesting level */
4311}
MemoryContext TopMemoryContext
Definition mcxt.c:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
char * c
int GetCurrentTransactionNestLevel(void)
Definition xact.c:931

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

void SerializeReindexState ( Size  maxsize,
char start_address 
)

Definition at line 4274 of file index.c.

4275{
4277 int c = 0;
4278 ListCell *lc;
4279
4280 sistate->currentlyReindexedHeap = currentlyReindexedHeap;
4281 sistate->currentlyReindexedIndex = currentlyReindexedIndex;
4282 sistate->numPendingReindexedIndexes = list_length(pendingReindexedIndexes);
4283 foreach(lc, pendingReindexedIndexes)
4284 sistate->pendingReindexedIndexes[c++] = lfirst_oid(lc);
4285}

References currentlyReindexedHeap, currentlyReindexedIndex, fb(), lfirst_oid, list_length(), and pendingReindexedIndexes.

Referenced by InitializeParallelDSM().

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4205 of file index.c.

4206{
4207 /* Reindexing is not re-entrant. */
4209 elog(ERROR, "cannot reindex while reindexing");
4210 if (IsInParallelMode())
4211 elog(ERROR, "cannot modify reindex state during a parallel operation");
4214}
List * list_copy(const List *oldlist)
Definition list.c:1573

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

Referenced by reindex_relation().

◆ SetReindexProcessing()

static void SetReindexProcessing ( Oid  heapOid,
Oid  indexOid 
)
static

Definition at line 4172 of file index.c.

4173{
4174 Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4175 /* Reindexing is not re-entrant. */
4177 elog(ERROR, "cannot reindex while reindexing");
4178 currentlyReindexedHeap = heapOid;
4179 currentlyReindexedIndex = indexOid;
4180 /* Index is no longer "pending" reindex. */
4181 RemoveReindexPending(indexOid);
4182 /* This may have been set already, but in case it isn't, do so now. */
4184}

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

Referenced by reindex_index().

◆ UpdateIndexRelation()

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

Definition at line 564 of file index.c.

576{
584 bool nulls[Natts_pg_index] = {0};
586 HeapTuple tuple;
587 int i;
588
589 /*
590 * Copy the index key, opclass, and indoption info into arrays (should we
591 * make the caller pass them like this to start with?)
592 */
594 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
595 indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i];
599
600 /*
601 * Convert the index expressions (if any) to a text datum
602 */
603 if (indexInfo->ii_Expressions != NIL)
604 {
605 char *exprsString;
606
610 }
611 else
612 exprsDatum = (Datum) 0;
613
614 /*
615 * Convert the index predicate (if any) to a text datum. Note we convert
616 * implicit-AND format to normal explicit-AND for storage.
617 */
618 if (indexInfo->ii_Predicate != NIL)
619 {
620 char *predString;
621
625 }
626 else
627 predDatum = (Datum) 0;
628
629
630 /*
631 * open the system catalog index relation
632 */
634
635 /*
636 * Build a pg_index tuple
637 */
658 if (exprsDatum == (Datum) 0)
659 nulls[Anum_pg_index_indexprs - 1] = true;
661 if (predDatum == (Datum) 0)
662 nulls[Anum_pg_index_indpred - 1] = true;
663
665
666 /*
667 * insert the tuple into the pg_index catalog
668 */
670
671 /*
672 * close the relation and free the tuple
673 */
675 heap_freetuple(tuple);
676}
#define CStringGetTextDatum(s)
Definition builtins.h:98
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
int2vector * buildint2vector(const int16 *int2s, int n)
Definition int.c:114
Expr * make_ands_explicit(List *andclauses)
Definition makefuncs.c:799
oidvector * buildoidvector(const Oid *oids, int n)
Definition oid.c:87
char * nodeToString(const void *obj)
Definition outfuncs.c:811
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum BoolGetDatum(bool X)
Definition postgres.h:112

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

Referenced by index_create().

◆ validate_index()

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

Definition at line 3371 of file index.c.

3372{
3373 Relation heapRelation,
3374 indexRelation;
3375 IndexInfo *indexInfo;
3378 Oid save_userid;
3379 int save_sec_context;
3380 int save_nestlevel;
3381
3382 {
3383 const int progress_index[] = {
3389 };
3390 const int64 progress_vals[] = {
3392 0, 0, 0, 0
3393 };
3394
3396 }
3397
3398 /* Open and lock the parent heap relation */
3400
3401 /*
3402 * Switch to the table owner's userid, so that any index functions are run
3403 * as that user. Also lock down security-restricted operations and
3404 * arrange to make GUC variable changes local to this command.
3405 */
3406 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3407 SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3408 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3409 save_nestlevel = NewGUCNestLevel();
3411
3412 indexRelation = index_open(indexId, RowExclusiveLock);
3413
3414 /*
3415 * Fetch info needed for index_insert. (You might think this should be
3416 * passed in from DefineIndex, but its copy is long gone due to having
3417 * been built in a previous transaction.)
3418 */
3419 indexInfo = BuildIndexInfo(indexRelation);
3420
3421 /* mark build is concurrent just for consistency */
3422 indexInfo->ii_Concurrent = true;
3423
3424 /*
3425 * Scan the index and gather up all the TIDs into a tuplesort object.
3426 */
3427 ivinfo.index = indexRelation;
3428 ivinfo.heaprel = heapRelation;
3429 ivinfo.analyze_only = false;
3430 ivinfo.report_progress = true;
3431 ivinfo.estimated_count = true;
3432 ivinfo.message_level = DEBUG2;
3433 ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3434 ivinfo.strategy = NULL;
3435
3436 /*
3437 * Encode TIDs as int8 values for the sort, rather than directly sorting
3438 * item pointers. This can be significantly faster, primarily because TID
3439 * is a pass-by-reference type on all platforms, whereas int8 is
3440 * pass-by-value on most platforms.
3441 */
3443 InvalidOid, false,
3446 state.htups = state.itups = state.tups_inserted = 0;
3447
3448 /* ambulkdelete updates progress metrics */
3451
3452 /* Execute the sort */
3453 {
3454 const int progress_index[] = {
3458 };
3459 const int64 progress_vals[] = {
3461 0, 0
3462 };
3463
3465 }
3466 tuplesort_performsort(state.tuplesort);
3467
3468 /*
3469 * Now scan the heap and "merge" it with the index
3470 */
3473 table_index_validate_scan(heapRelation,
3474 indexRelation,
3475 indexInfo,
3476 snapshot,
3477 &state);
3478
3479 /* Done with tuplesort object */
3480 tuplesort_end(state.tuplesort);
3481
3482 /* Make sure to release resources cached in indexInfo (if needed). */
3483 index_insert_cleanup(indexRelation, indexInfo);
3484
3485 elog(DEBUG2,
3486 "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3487 state.htups, state.itups, state.tups_inserted);
3488
3489 /* Roll back any GUC changes executed by index functions */
3490 AtEOXact_GUC(false, save_nestlevel);
3491
3492 /* Restore userid and security context */
3493 SetUserIdAndSecContext(save_userid, save_sec_context);
3494
3495 /* Close rels, but keep locks */
3496 index_close(indexRelation, NoLock);
3497 table_close(heapRelation, NoLock);
3498}
#define DEBUG2
Definition elog.h:29
int maintenance_work_mem
Definition globals.c:133
static bool validate_index_callback(ItemPointer itemptr, void *opaque)
Definition index.c:3504
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition indexam.c:773
void index_insert_cleanup(Relation indexRelation, IndexInfo *indexInfo)
Definition indexam.c:242
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN
Definition progress.h:127
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT
Definition progress.h:126
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition progress.h:125
static void table_index_validate_scan(Relation table_rel, Relation index_rel, IndexInfo *index_info, Snapshot snapshot, ValidateIndexState *state)
Definition tableam.h:1908
void tuplesort_performsort(Tuplesortstate *state)
Definition tuplesort.c:1260
void tuplesort_end(Tuplesortstate *state)
Definition tuplesort.c:848
#define TUPLESORT_NONE
Definition tuplesort.h:67
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

static bool validate_index_callback ( ItemPointer  itemptr,
void opaque 
)
static

Definition at line 3504 of file index.c.

3505{
3507 int64 encoded = itemptr_encode(itemptr);
3508
3509 tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3510 state->itups += 1;
3511 return false; /* never actually delete anything */
3512}
static int64 itemptr_encode(const ItemPointerData *itemptr)
Definition index.h:197
static Datum Int64GetDatum(int64 X)
Definition postgres.h:413
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)

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

Referenced by validate_index().

Variable Documentation

◆ binary_upgrade_next_index_pg_class_oid

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid

Definition at line 86 of file index.c.

Referenced by binary_upgrade_set_next_index_pg_class_oid(), and index_create().

◆ binary_upgrade_next_index_pg_class_relfilenumber

RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber

◆ currentlyReindexedHeap

◆ currentlyReindexedIndex

◆ pendingReindexedIndexes

◆ reindexingNestLevel

int reindexingNestLevel = 0
static