PostgreSQL Source Code git master
index.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/amapi.h"
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
#include "access/visibilitymap.h"
#include "access/xact.h"
#include "bootstrap/bootstrap.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_description.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "commands/event_trigger.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parser.h"
#include "pgstat.h"
#include "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, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
 
Oid index_concurrently_create_copy (Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
 
void index_concurrently_build (Oid heapRelationId, Oid indexRelationId)
 
void index_concurrently_swap (Oid newIndexId, Oid oldIndexId, const char *oldName)
 
void index_concurrently_set_dead (Oid heapId, Oid indexId)
 
ObjectAddress index_constraint_create (Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
 
void index_drop (Oid indexId, bool concurrent, bool concurrent_lock_mode)
 
IndexInfoBuildIndexInfo (Relation index)
 
IndexInfoBuildDummyIndexInfo (Relation index)
 
bool CompareIndexInfo (const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
 
void BuildSpeculativeIndexInfo (Relation index, IndexInfo *ii)
 
void FormIndexDatum (IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
void index_build (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
 
void validate_index (Oid heapId, Oid indexId, Snapshot snapshot)
 
void index_set_state_flags (Oid indexId, IndexStateFlagsAction action)
 
Oid IndexGetRelation (Oid indexId, bool missing_ok)
 
void reindex_index (const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
 
bool reindex_relation (const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
 
bool ReindexIsProcessingHeap (Oid heapOid)
 
bool ReindexIsProcessingIndex (Oid indexOid)
 
void ResetReindexState (int nestLevel)
 
Size EstimateReindexStateSpace (void)
 
void SerializeReindexState (Size maxsize, char *start_address)
 
void RestoreReindexState (const void *reindexstate)
 

Variables

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

Function Documentation

◆ AppendAttributeTuples()

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

Definition at line 510 of file index.c.

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

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

Referenced by index_create().

◆ BuildDummyIndexInfo()

IndexInfo * BuildDummyIndexInfo ( Relation  index)

Definition at line 2486 of file index.c.

2487{
2488 IndexInfo *ii;
2489 Form_pg_index indexStruct = index->rd_index;
2490 int i;
2491 int numAtts;
2492
2493 /* check the number of keys, and copy attr numbers into the IndexInfo */
2494 numAtts = indexStruct->indnatts;
2495 if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2496 elog(ERROR, "invalid indnatts %d for index %u",
2497 numAtts, RelationGetRelid(index));
2498
2499 /*
2500 * Create the node, using dummy index expressions, and pretending there is
2501 * no predicate.
2502 */
2503 ii = makeIndexInfo(indexStruct->indnatts,
2504 indexStruct->indnkeyatts,
2505 index->rd_rel->relam,
2507 NIL,
2508 indexStruct->indisunique,
2509 indexStruct->indnullsnotdistinct,
2510 indexStruct->indisready,
2511 false,
2512 index->rd_indam->amsummarizing,
2513 indexStruct->indisexclusion && indexStruct->indisunique);
2514
2515 /* fill in attribute numbers */
2516 for (i = 0; i < numAtts; i++)
2517 ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2518
2519 /* We ignore the exclusion constraint if any */
2520
2521 return ii;
2522}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
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
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define NIL
Definition: pg_list.h:68
#define RelationGetRelid(relation)
Definition: rel.h:515
List * RelationGetDummyIndexExpressions(Relation relation)
Definition: relcache.c:5151
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:175
Definition: type.h:96

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

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo * BuildIndexInfo ( Relation  index)

Definition at line 2426 of file index.c.

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

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

Referenced by _brin_parallel_scan_and_build(), _bt_parallel_scan_and_sort(), _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_concurrently_create_copy(), reindex_index(), tuplesort_begin_cluster(), and validate_index().

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2667 of file index.c.

2668{
2669 int indnkeyatts;
2670 int i;
2671
2673
2674 /*
2675 * fetch info for checking unique indexes
2676 */
2677 Assert(ii->ii_Unique);
2678
2679 ii->ii_UniqueOps = palloc_array(Oid, indnkeyatts);
2680 ii->ii_UniqueProcs = palloc_array(Oid, indnkeyatts);
2681 ii->ii_UniqueStrats = palloc_array(uint16, indnkeyatts);
2682
2683 /*
2684 * We have to look up the operator's strategy number. This provides a
2685 * cross-check that the operator does match the index.
2686 */
2687 /* We need the func OIDs and strategy numbers too */
2688 for (i = 0; i < indnkeyatts; i++)
2689 {
2690 ii->ii_UniqueStrats[i] =
2692 index->rd_rel->relam,
2693 index->rd_opfamily[i],
2694 false);
2695 ii->ii_UniqueOps[i] =
2696 get_opfamily_member(index->rd_opfamily[i],
2697 index->rd_opcintype[i],
2698 index->rd_opcintype[i],
2699 ii->ii_UniqueStrats[i]);
2700 if (!OidIsValid(ii->ii_UniqueOps[i]))
2701 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2702 ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2703 index->rd_opcintype[i], index->rd_opfamily[i]);
2705 }
2706}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition: amapi.c:161
uint16_t uint16
Definition: c.h:551
#define OidIsValid(objectId)
Definition: c.h:788
@ COMPARE_EQ
Definition: cmptype.h:36
#define palloc_array(type, count)
Definition: fe_memutils.h:76
Assert(PointerIsAligned(start, uint64))
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1435
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:168
unsigned int Oid
Definition: postgres_ext.h:32
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:534
bool ii_Unique
Definition: execnodes.h:200
Oid * ii_UniqueOps
Definition: execnodes.h:195
uint16 * ii_UniqueStrats
Definition: execnodes.h:197
Oid * ii_UniqueProcs
Definition: execnodes.h:196

References Assert(), COMPARE_EQ, elog, ERROR, 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 2535 of file index.c.

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

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

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

◆ ConstructTupleDescriptor()

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

Definition at line 281 of file index.c.

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

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

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4240 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2728 of file index.c.

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

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

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

◆ index_build()

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

Definition at line 3000 of file index.c.

3005{
3006 IndexBuildResult *stats;
3007 Oid save_userid;
3008 int save_sec_context;
3009 int save_nestlevel;
3010
3011 /*
3012 * sanity checks
3013 */
3014 Assert(RelationIsValid(indexRelation));
3015 Assert(indexRelation->rd_indam);
3016 Assert(indexRelation->rd_indam->ambuild);
3017 Assert(indexRelation->rd_indam->ambuildempty);
3018
3019 /*
3020 * Determine worker process details for parallel CREATE INDEX. Currently,
3021 * only btree, GIN, and BRIN have support for parallel builds.
3022 *
3023 * Note that planner considers parallel safety for us.
3024 */
3025 if (parallel && IsNormalProcessingMode() &&
3026 indexRelation->rd_indam->amcanbuildparallel)
3027 indexInfo->ii_ParallelWorkers =
3029 RelationGetRelid(indexRelation));
3030
3031 if (indexInfo->ii_ParallelWorkers == 0)
3033 (errmsg_internal("building index \"%s\" on table \"%s\" serially",
3034 RelationGetRelationName(indexRelation),
3035 RelationGetRelationName(heapRelation))));
3036 else
3038 (errmsg_internal("building index \"%s\" on table \"%s\" with request for %d parallel workers",
3039 RelationGetRelationName(indexRelation),
3040 RelationGetRelationName(heapRelation),
3041 indexInfo->ii_ParallelWorkers)));
3042
3043 /*
3044 * Switch to the table owner's userid, so that any index functions are run
3045 * as that user. Also lock down security-restricted operations and
3046 * arrange to make GUC variable changes local to this command.
3047 */
3048 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3049 SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3050 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3051 save_nestlevel = NewGUCNestLevel();
3053
3054 /* Set up initial progress report status */
3055 {
3056 const int progress_index[] = {
3063 };
3064 const int64 progress_vals[] = {
3067 0, 0, 0, 0
3068 };
3069
3070 pgstat_progress_update_multi_param(6, progress_index, progress_vals);
3071 }
3072
3073 /*
3074 * Call the access method's build procedure
3075 */
3076 stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation,
3077 indexInfo);
3078 Assert(stats);
3079
3080 /*
3081 * If this is an unlogged index, we may need to write out an init fork for
3082 * it -- but we must first check whether one already exists. If, for
3083 * example, an unlogged relation is truncated in the transaction that
3084 * created it, or truncated twice in a subsequent transaction, the
3085 * relfilenumber won't change, and nothing needs to be done here.
3086 */
3087 if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
3088 !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
3089 {
3090 smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3091 log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
3092 indexRelation->rd_indam->ambuildempty(indexRelation);
3093 }
3094
3095 /*
3096 * If we found any potentially broken HOT chains, mark the index as not
3097 * being usable until the current transaction is below the event horizon.
3098 * See src/backend/access/heap/README.HOT for discussion. While it might
3099 * become safe to use the index earlier based on actual cleanup activity
3100 * and other active transactions, the test for that would be much more
3101 * complex and would require some form of blocking, so keep it simple and
3102 * fast by just using the current transaction.
3103 *
3104 * However, when reindexing an existing index, we should do nothing here.
3105 * Any HOT chains that are broken with respect to the index must predate
3106 * the index's original creation, so there is no need to change the
3107 * index's usability horizon. Moreover, we *must not* try to change the
3108 * index's pg_index entry while reindexing pg_index itself, and this
3109 * optimization nicely prevents that. The more complex rules needed for a
3110 * reindex are handled separately after this function returns.
3111 *
3112 * We also need not set indcheckxmin during a concurrent index build,
3113 * because we won't set indisvalid true until all transactions that care
3114 * about the broken HOT chains are gone.
3115 *
3116 * Therefore, this code path can only be taken during non-concurrent
3117 * CREATE INDEX. Thus the fact that heap_update will set the pg_index
3118 * tuple's xmin doesn't matter, because that tuple was created in the
3119 * current transaction anyway. That also means we don't need to worry
3120 * about any concurrent readers of the tuple; no other transaction can see
3121 * it yet.
3122 */
3123 if (indexInfo->ii_BrokenHotChain &&
3124 !isreindex &&
3125 !indexInfo->ii_Concurrent)
3126 {
3127 Oid indexId = RelationGetRelid(indexRelation);
3128 Relation pg_index;
3129 HeapTuple indexTuple;
3130 Form_pg_index indexForm;
3131
3132 pg_index = table_open(IndexRelationId, RowExclusiveLock);
3133
3134 indexTuple = SearchSysCacheCopy1(INDEXRELID,
3135 ObjectIdGetDatum(indexId));
3136 if (!HeapTupleIsValid(indexTuple))
3137 elog(ERROR, "cache lookup failed for index %u", indexId);
3138 indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3139
3140 /* If it's a new index, indcheckxmin shouldn't be set ... */
3141 Assert(!indexForm->indcheckxmin);
3142
3143 indexForm->indcheckxmin = true;
3144 CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3145
3146 heap_freetuple(indexTuple);
3147 table_close(pg_index, RowExclusiveLock);
3148 }
3149
3150 /*
3151 * Update heap and index pg_class rows
3152 */
3153 index_update_stats(heapRelation,
3154 true,
3155 stats->heap_tuples);
3156
3157 index_update_stats(indexRelation,
3158 false,
3159 stats->index_tuples);
3160
3161 /* Make the updated catalog row versions visible */
3163
3164 /*
3165 * If it's for an exclusion constraint, make a second pass over the heap
3166 * to verify that the constraint is satisfied. We must not do this until
3167 * the index is fully valid. (Broken HOT chains shouldn't matter, though;
3168 * see comments for IndexCheckExclusion.)
3169 */
3170 if (indexInfo->ii_ExclusionOps != NULL)
3171 IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
3172
3173 /* Roll back any GUC changes executed by index functions */
3174 AtEOXact_GUC(false, save_nestlevel);
3175
3176 /* Restore userid and security context */
3177 SetUserIdAndSecContext(save_userid, save_sec_context);
3178}
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
int64_t int64
Definition: c.h:549
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
#define DEBUG1
Definition: elog.h:30
#define ereport(elevel,...)
Definition: elog.h:150
int NewGUCNestLevel(void)
Definition: guc.c:2110
void RestrictSearchPath(void)
Definition: guc.c:2121
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2137
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
static void index_update_stats(Relation rel, bool hasindex, double reltuples)
Definition: index.c:2807
static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo)
Definition: index.c:3193
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition: indexing.c:313
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:319
#define IsNormalProcessingMode()
Definition: miscadmin.h:479
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:612
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:619
int plan_create_index_workers(Oid tableOid, Oid indexOid)
Definition: planner.c:6966
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition: progress.h:114
#define PROGRESS_CREATEIDX_TUPLES_TOTAL
Definition: progress.h:106
#define PROGRESS_SCAN_BLOCKS_DONE
Definition: progress.h:142
#define PROGRESS_CREATEIDX_TUPLES_DONE
Definition: progress.h:107
#define PROGRESS_CREATEIDX_SUBPHASE
Definition: progress.h:105
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition: progress.h:126
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:104
#define PROGRESS_SCAN_BLOCKS_TOTAL
Definition: progress.h:141
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:577
#define RelationGetRelationName(relation)
Definition: rel.h:549
#define RelationIsValid(relation)
Definition: rel.h:490
@ 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
ItemPointerData t_self
Definition: htup.h:65
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:59
double index_tuples
Definition: genam.h:60
bool ii_BrokenHotChain
Definition: execnodes.h:212
int ii_ParallelWorkers
Definition: execnodes.h:218
bool ii_Concurrent
Definition: execnodes.h:210
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:1101

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

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

◆ index_check_primary_key()

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

Definition at line 202 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1483 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1298 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1821 of file index.c.

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

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

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

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

Definition at line 1550 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1883 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 724 of file index.c.

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

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

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

◆ index_drop()

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

Definition at line 2120 of file index.c.

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

References AccessExclusiveLock, Assert(), CacheInvalidateRelcache(), CatalogTupleDelete(), CheckTableNotInUse(), CommitTransactionCommand(), LockRelId::dbId, DeleteAttributeTuples(), DeleteInheritsTuple(), DeleteRelationTuple(), elog, ereport, errcode(), errmsg(), ERROR, 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(), LockInfoData::lockRelId, NoLock, ObjectIdGetDatum(), pgstat_drop_relation(), PopActiveSnapshot(), PushActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, RelationDropStorage(), RelationForgetRelation(), RelationGetDescr, ReleaseSysCache(), LockRelId::relId, RemoveStatistics(), RowExclusiveLock, SearchSysCache1(), SET_LOCKTAG_RELATION, ShareUpdateExclusiveLock, StartTransactionCommand(), HeapTupleData::t_self, table_close(), table_open(), TransferPredicateLocksToHeapRelation(), UnlockRelationIdForSession(), and WaitForLockers().

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3501 of file index.c.

3502{
3503 Relation pg_index;
3504 HeapTuple indexTuple;
3505 Form_pg_index indexForm;
3506
3507 /* Open pg_index and fetch a writable copy of the index's tuple */
3508 pg_index = table_open(IndexRelationId, RowExclusiveLock);
3509
3510 indexTuple = SearchSysCacheCopy1(INDEXRELID,
3511 ObjectIdGetDatum(indexId));
3512 if (!HeapTupleIsValid(indexTuple))
3513 elog(ERROR, "cache lookup failed for index %u", indexId);
3514 indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3515
3516 /* Perform the requested state change on the copy */
3517 switch (action)
3518 {
3520 /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3521 Assert(indexForm->indislive);
3522 Assert(!indexForm->indisready);
3523 Assert(!indexForm->indisvalid);
3524 indexForm->indisready = true;
3525 break;
3527 /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3528 Assert(indexForm->indislive);
3529 Assert(indexForm->indisready);
3530 Assert(!indexForm->indisvalid);
3531 indexForm->indisvalid = true;
3532 break;
3534
3535 /*
3536 * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3537 *
3538 * If indisready == true we leave it set so the index still gets
3539 * maintained by active transactions. We only need to ensure that
3540 * indisvalid is false. (We don't assert that either is initially
3541 * true, though, since we want to be able to retry a DROP INDEX
3542 * CONCURRENTLY that failed partway through.)
3543 *
3544 * Note: the CLUSTER logic assumes that indisclustered cannot be
3545 * set on any invalid index, so clear that flag too. For
3546 * cleanliness, also clear indisreplident.
3547 */
3548 indexForm->indisvalid = false;
3549 indexForm->indisclustered = false;
3550 indexForm->indisreplident = false;
3551 break;
3553
3554 /*
3555 * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3556 *
3557 * We clear both indisready and indislive, because we not only
3558 * want to stop updates, we want to prevent sessions from touching
3559 * the index at all.
3560 */
3561 Assert(!indexForm->indisvalid);
3562 Assert(!indexForm->indisclustered);
3563 Assert(!indexForm->indisreplident);
3564 indexForm->indisready = false;
3565 indexForm->indislive = false;
3566 break;
3567 }
3568
3569 /* ... and update it */
3570 CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3571
3572 table_close(pg_index, RowExclusiveLock);
3573}
@ INDEX_CREATE_SET_VALID
Definition: index.h:27

References generate_unaccent_rules::action, Assert(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_DROP_CLEAR_VALID, INDEX_DROP_SET_DEAD, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

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

◆ index_update_stats()

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

Definition at line 2807 of file index.c.

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

References Assert(), AutoVacuumingActive(), BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), elog, ERROR, GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, if(), IsBinaryUpgrade, sort-test::key, 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 3193 of file index.c.

3196{
3197 TableScanDesc scan;
3199 bool isnull[INDEX_MAX_KEYS];
3200 ExprState *predicate;
3201 TupleTableSlot *slot;
3202 EState *estate;
3203 ExprContext *econtext;
3204 Snapshot snapshot;
3205
3206 /*
3207 * If we are reindexing the target index, mark it as no longer being
3208 * reindexed, to forestall an Assert in index_beginscan when we try to use
3209 * the index for probes. This is OK because the index is now fully valid.
3210 */
3213
3214 /*
3215 * Need an EState for evaluation of index expressions and partial-index
3216 * predicates. Also a slot to hold the current tuple.
3217 */
3218 estate = CreateExecutorState();
3219 econtext = GetPerTupleExprContext(estate);
3220 slot = table_slot_create(heapRelation, NULL);
3221
3222 /* Arrange for econtext's scan tuple to be the tuple under test */
3223 econtext->ecxt_scantuple = slot;
3224
3225 /* Set up execution state for predicate, if any. */
3226 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3227
3228 /*
3229 * Scan all live tuples in the base relation.
3230 */
3231 snapshot = RegisterSnapshot(GetLatestSnapshot());
3232 scan = table_beginscan_strat(heapRelation, /* relation */
3233 snapshot, /* snapshot */
3234 0, /* number of keys */
3235 NULL, /* scan key */
3236 true, /* buffer access strategy OK */
3237 true); /* syncscan OK */
3238
3239 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3240 {
3242
3243 /*
3244 * In a partial index, ignore tuples that don't satisfy the predicate.
3245 */
3246 if (predicate != NULL)
3247 {
3248 if (!ExecQual(predicate, econtext))
3249 continue;
3250 }
3251
3252 /*
3253 * Extract index column values, including computing expressions.
3254 */
3255 FormIndexDatum(indexInfo,
3256 slot,
3257 estate,
3258 values,
3259 isnull);
3260
3261 /*
3262 * Check that this tuple has no conflicts.
3263 */
3264 check_exclusion_constraint(heapRelation,
3265 indexRelation, indexInfo,
3266 &(slot->tts_tid), values, isnull,
3267 estate, true);
3268
3270 }
3271
3272 table_endscan(scan);
3273 UnregisterSnapshot(snapshot);
3274
3276
3277 FreeExecutorState(estate);
3278
3279 /* These may have been pointing to the now-gone estate */
3280 indexInfo->ii_ExpressionsState = NIL;
3281 indexInfo->ii_PredicateState = NULL;
3282}
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:793
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, const ItemPointerData *tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex)
Definition: execIndexing.c:962
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1443
void FreeExecutorState(EState *estate)
Definition: execUtils.c:192
EState * CreateExecutorState(void)
Definition: execUtils.c:88
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:519
static void ResetReindexProcessing(void)
Definition: index.c:4168
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition: index.c:4127
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2728
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:281
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:273
ExprState * ii_PredicateState
Definition: execnodes.h:185
ItemPointerData tts_tid
Definition: tuptable.h:128
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:985
static TableScanDesc table_beginscan_strat(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key, bool allow_strat, bool allow_sync)
Definition: tableam.h:900
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1020

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

Referenced by index_build().

◆ IndexGetRelation()

Oid IndexGetRelation ( Oid  indexId,
bool  missing_ok 
)

Definition at line 3581 of file index.c.

3582{
3583 HeapTuple tuple;
3585 Oid result;
3586
3587 tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3588 if (!HeapTupleIsValid(tuple))
3589 {
3590 if (missing_ok)
3591 return InvalidOid;
3592 elog(ERROR, "cache lookup failed for index %u", indexId);
3593 }
3594 index = (Form_pg_index) GETSTRUCT(tuple);
3595 Assert(index->indexrelid == indexId);
3596
3597 result = index->indrelid;
3598 ReleaseSysCache(tuple);
3599 return result;
3600}

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

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

◆ InitializeAttributeOids()

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

Definition at line 492 of file index.c.

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

References i, RelationGetDescr, and TupleDescAttr().

Referenced by index_create().

◆ reindex_index()

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

Definition at line 3606 of file index.c.

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

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

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

◆ reindex_relation()

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

Definition at line 3946 of file index.c.

3948{
3949 Relation rel;
3950 Oid toast_relid;
3951 List *indexIds;
3952 char persistence;
3953 bool result = false;
3954 ListCell *indexId;
3955 int i;
3956
3957 /*
3958 * Open and lock the relation. ShareLock is sufficient since we only need
3959 * to prevent schema and data changes in it. The lock level used here
3960 * should match ReindexTable().
3961 */
3962 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3963 rel = try_table_open(relid, ShareLock);
3964 else
3965 rel = table_open(relid, ShareLock);
3966
3967 /* if relation is gone, leave */
3968 if (!rel)
3969 return false;
3970
3971 /*
3972 * Partitioned tables should never get processed here, as they have no
3973 * physical storage.
3974 */
3975 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3976 elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
3979
3980 toast_relid = rel->rd_rel->reltoastrelid;
3981
3982 /*
3983 * Get the list of index OIDs for this relation. (We trust the relcache
3984 * to get this with a sequential scan if ignoring system indexes.)
3985 */
3986 indexIds = RelationGetIndexList(rel);
3987
3989 {
3990 /* Suppress use of all the indexes until they are rebuilt */
3991 SetReindexPending(indexIds);
3992
3993 /*
3994 * Make the new heap contents visible --- now things might be
3995 * inconsistent!
3996 */
3998 }
3999
4000 /*
4001 * Reindex the toast table, if any, before the main table.
4002 *
4003 * This helps in cases where a corruption in the toast table's index would
4004 * otherwise error and stop REINDEX TABLE command when it tries to fetch a
4005 * toasted datum. This way. the toast table's index is rebuilt and fixed
4006 * before it is used for reindexing the main table.
4007 *
4008 * It is critical to call reindex_relation() *after* the call to
4009 * RelationGetIndexList() returning the list of indexes on the relation,
4010 * because reindex_relation() will call CommandCounterIncrement() after
4011 * every reindex_index(). See REINDEX_REL_SUPPRESS_INDEX_USE for more
4012 * details.
4013 */
4014 if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
4015 {
4016 /*
4017 * Note that this should fail if the toast relation is missing, so
4018 * reset REINDEXOPT_MISSING_OK. Even if a new tablespace is set for
4019 * the parent relation, the indexes on its toast table are not moved.
4020 * This rule is enforced by setting tablespaceOid to InvalidOid.
4021 */
4022 ReindexParams newparams = *params;
4023
4024 newparams.options &= ~(REINDEXOPT_MISSING_OK);
4025 newparams.tablespaceOid = InvalidOid;
4026 result |= reindex_relation(stmt, toast_relid, flags, &newparams);
4027 }
4028
4029 /*
4030 * Compute persistence of indexes: same as that of owning rel, unless
4031 * caller specified otherwise.
4032 */
4034 persistence = RELPERSISTENCE_UNLOGGED;
4035 else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
4036 persistence = RELPERSISTENCE_PERMANENT;
4037 else
4038 persistence = rel->rd_rel->relpersistence;
4039
4040 /* Reindex all the indexes. */
4041 i = 1;
4042 foreach(indexId, indexIds)
4043 {
4044 Oid indexOid = lfirst_oid(indexId);
4045 Oid indexNamespaceId = get_rel_namespace(indexOid);
4046
4047 /*
4048 * Skip any invalid indexes on a TOAST table. These can only be
4049 * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
4050 * rebuilt it would not be possible to drop them anymore.
4051 */
4052 if (IsToastNamespace(indexNamespaceId) &&
4053 !get_index_isvalid(indexOid))
4054 {
4056 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4057 errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
4058 get_namespace_name(indexNamespaceId),
4059 get_rel_name(indexOid))));
4060
4061 /*
4062 * Remove this invalid toast index from the reindex pending list,
4063 * as it is skipped here due to the hard failure that would happen
4064 * in reindex_index(), should we try to process it.
4065 */
4067 RemoveReindexPending(indexOid);
4068 continue;
4069 }
4070
4071 reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
4072 persistence, params);
4073
4075
4076 /* Index should no longer be in the pending list */
4077 Assert(!ReindexIsProcessingIndex(indexOid));
4078
4079 /* Set index rebuild count */
4081 i);
4082 i++;
4083 }
4084
4085 /*
4086 * Close rel, but continue to hold the lock.
4087 */
4088 table_close(rel, NoLock);
4089
4090 result |= (indexIds != NIL);
4091
4092 return result;
4093}
#define WARNING
Definition: elog.h:36
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4138
static void RemoveReindexPending(Oid indexOid)
Definition: index.c:4198
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3946
static void SetReindexPending(List *indexes)
Definition: index.c:4182
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition: index.c:3606
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:162
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition: index.h:160
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:163
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:161
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2102
#define PROGRESS_CLUSTER_INDEX_REBUILD_COUNT
Definition: progress.h:84
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4831

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

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

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4127 of file index.c.

4128{
4129 return indexOid == currentlyReindexedIndex;
4130}
static Oid currentlyReindexedIndex
Definition: index.c:4108

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4117 of file index.c.

4118{
4119 return heapOid == currentlyReindexedHeap;
4120}
static Oid currentlyReindexedHeap
Definition: index.c:4107

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4138 of file index.c.

4139{
4140 return indexOid == currentlyReindexedIndex ||
4142}
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 148 of file index.c.

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

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

Referenced by index_check_primary_key().

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4198 of file index.c.

4199{
4200 if (IsInParallelMode())
4201 elog(ERROR, "cannot modify reindex state during a parallel operation");
4203 indexOid);
4204}
List * list_delete_oid(List *list, Oid datum)
Definition: list.c:910
bool IsInParallelMode(void)
Definition: xact.c:1090

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

Referenced by reindex_relation(), and SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4168 of file index.c.

4169{
4172 /* reindexingNestLevel remains set till end of (sub)transaction */
4173}

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4211 of file index.c.

4212{
4213 /*
4214 * Because reindexing is not re-entrant, we don't need to cope with nested
4215 * reindexing states. We just need to avoid messing up the outer-level
4216 * state in case a subtransaction fails within a REINDEX. So checking the
4217 * current nest level against that of the reindex operation is sufficient.
4218 */
4219 if (reindexingNestLevel >= nestLevel)
4220 {
4223
4224 /*
4225 * We needn't try to release the contents of pendingReindexedIndexes;
4226 * that list should be in a transaction-lifespan context, so it will
4227 * go away automatically.
4228 */
4230
4232 }
4233}
static int reindexingNestLevel
Definition: index.c:4110

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4269 of file index.c.

4270{
4271 const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4272 int c = 0;
4273 MemoryContext oldcontext;
4274
4277
4280 for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4283 sistate->pendingReindexedIndexes[c]);
4284 MemoryContextSwitchTo(oldcontext);
4285
4286 /* Note the worker has its own transaction nesting level */
4288}
MemoryContext TopMemoryContext
Definition: mcxt.c:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
char * c
Oid currentlyReindexedHeap
Definition: index.c:95
Oid currentlyReindexedIndex
Definition: index.c:96
int numPendingReindexedIndexes
Definition: index.c:97
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:98
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:930

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4182 of file index.c.

4183{
4184 /* Reindexing is not re-entrant. */
4186 elog(ERROR, "cannot reindex while reindexing");
4187 if (IsInParallelMode())
4188 elog(ERROR, "cannot modify reindex state during a parallel operation");
4191}
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 4149 of file index.c.

4150{
4151 Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4152 /* Reindexing is not re-entrant. */
4154 elog(ERROR, "cannot reindex while reindexing");
4155 currentlyReindexedHeap = heapOid;
4156 currentlyReindexedIndex = indexOid;
4157 /* Index is no longer "pending" reindex. */
4158 RemoveReindexPending(indexOid);
4159 /* This may have been set already, but in case it isn't, do so now. */
4161}

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

Referenced by reindex_index().

◆ UpdateIndexRelation()

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

Definition at line 561 of file index.c.

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

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

Referenced by index_create().

◆ validate_index()

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

Definition at line 3348 of file index.c.

3349{
3350 Relation heapRelation,
3351 indexRelation;
3352 IndexInfo *indexInfo;
3353 IndexVacuumInfo ivinfo;
3355 Oid save_userid;
3356 int save_sec_context;
3357 int save_nestlevel;
3358
3359 {
3360 const int progress_index[] = {
3366 };
3367 const int64 progress_vals[] = {
3369 0, 0, 0, 0
3370 };
3371
3372 pgstat_progress_update_multi_param(5, progress_index, progress_vals);
3373 }
3374
3375 /* Open and lock the parent heap relation */
3376 heapRelation = table_open(heapId, ShareUpdateExclusiveLock);
3377
3378 /*
3379 * Switch to the table owner's userid, so that any index functions are run
3380 * as that user. Also lock down security-restricted operations and
3381 * arrange to make GUC variable changes local to this command.
3382 */
3383 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3384 SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3385 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3386 save_nestlevel = NewGUCNestLevel();
3388
3389 indexRelation = index_open(indexId, RowExclusiveLock);
3390
3391 /*
3392 * Fetch info needed for index_insert. (You might think this should be
3393 * passed in from DefineIndex, but its copy is long gone due to having
3394 * been built in a previous transaction.)
3395 */
3396 indexInfo = BuildIndexInfo(indexRelation);
3397
3398 /* mark build is concurrent just for consistency */
3399 indexInfo->ii_Concurrent = true;
3400
3401 /*
3402 * Scan the index and gather up all the TIDs into a tuplesort object.
3403 */
3404 ivinfo.index = indexRelation;
3405 ivinfo.heaprel = heapRelation;
3406 ivinfo.analyze_only = false;
3407 ivinfo.report_progress = true;
3408 ivinfo.estimated_count = true;
3409 ivinfo.message_level = DEBUG2;
3410 ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3411 ivinfo.strategy = NULL;
3412
3413 /*
3414 * Encode TIDs as int8 values for the sort, rather than directly sorting
3415 * item pointers. This can be significantly faster, primarily because TID
3416 * is a pass-by-reference type on all platforms, whereas int8 is
3417 * pass-by-value on most platforms.
3418 */
3419 state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
3420 InvalidOid, false,
3422 NULL, TUPLESORT_NONE);
3423 state.htups = state.itups = state.tups_inserted = 0;
3424
3425 /* ambulkdelete updates progress metrics */
3426 (void) index_bulk_delete(&ivinfo, NULL,
3428
3429 /* Execute the sort */
3430 {
3431 const int progress_index[] = {
3435 };
3436 const int64 progress_vals[] = {
3438 0, 0
3439 };
3440
3441 pgstat_progress_update_multi_param(3, progress_index, progress_vals);
3442 }
3443 tuplesort_performsort(state.tuplesort);
3444
3445 /*
3446 * Now scan the heap and "merge" it with the index
3447 */
3450 table_index_validate_scan(heapRelation,
3451 indexRelation,
3452 indexInfo,
3453 snapshot,
3454 &state);
3455
3456 /* Done with tuplesort object */
3457 tuplesort_end(state.tuplesort);
3458
3459 /* Make sure to release resources cached in indexInfo (if needed). */
3460 index_insert_cleanup(indexRelation, indexInfo);
3461
3462 elog(DEBUG2,
3463 "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3464 state.htups, state.itups, state.tups_inserted);
3465
3466 /* Roll back any GUC changes executed by index functions */
3467 AtEOXact_GUC(false, save_nestlevel);
3468
3469 /* Restore userid and security context */
3470 SetUserIdAndSecContext(save_userid, save_sec_context);
3471
3472 /* Close rels, but keep locks */
3473 index_close(indexRelation, NoLock);
3474 table_close(heapRelation, NoLock);
3475}
#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:3481
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:805
void index_insert_cleanup(Relation indexRelation, IndexInfo *indexInfo)
Definition: indexam.c:241
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN
Definition: progress.h:118
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT
Definition: progress.h:117
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition: progress.h:116
Relation index
Definition: genam.h:73
double num_heap_tuples
Definition: genam.h:79
bool analyze_only
Definition: genam.h:75
BufferAccessStrategy strategy
Definition: genam.h:80
Relation heaprel
Definition: genam.h:74
bool report_progress
Definition: genam.h:76
int message_level
Definition: genam.h:78
bool estimated_count
Definition: genam.h:77
static void table_index_validate_scan(Relation table_rel, Relation index_rel, IndexInfo *index_info, Snapshot snapshot, ValidateIndexState *state)
Definition: tableam.h:1818
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1349
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:937
#define TUPLESORT_NONE
Definition: tuplesort.h:94
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

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

Definition at line 3481 of file index.c.

3482{
3484 int64 encoded = itemptr_encode(itemptr);
3485
3486 tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3487 state->itups += 1;
3488 return false; /* never actually delete anything */
3489}
static int64 itemptr_encode(const ItemPointerData *itemptr)
Definition: index.h:190
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)

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

Referenced by validate_index().

Variable Documentation

◆ binary_upgrade_next_index_pg_class_oid

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid

Definition at line 85 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