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

Go to the source code of this file.

Data Structures

struct  SerializedReindexState
 

Functions

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

Variables

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

Function Documentation

◆ AppendAttributeTuples()

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

Definition at line 511 of file index.c.

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

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

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

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

Referenced by _brin_parallel_scan_and_build(), _bt_parallel_scan_and_sort(), ATExecAddIndexConstraint(), ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), brinsummarize(), bt_check_every_level(), build_index_value_desc(), DefineIndex(), do_analyze_rel(), ExecOpenIndices(), 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 2668 of file index.c.

2669{
2670 int indnkeyatts;
2671 int i;
2672
2674
2675 /*
2676 * fetch info for checking unique indexes
2677 */
2678 Assert(ii->ii_Unique);
2679
2680 ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2681 ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2682 ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2683
2684 /*
2685 * We have to look up the operator's strategy number. This provides a
2686 * cross-check that the operator does match the index.
2687 */
2688 /* We need the func OIDs and strategy numbers too */
2689 for (i = 0; i < indnkeyatts; i++)
2690 {
2691 ii->ii_UniqueStrats[i] =
2693 index->rd_rel->relam,
2694 index->rd_opfamily[i],
2695 index->rd_opcintype[i],
2696 false);
2697 ii->ii_UniqueOps[i] =
2698 get_opfamily_member(index->rd_opfamily[i],
2699 index->rd_opcintype[i],
2700 index->rd_opcintype[i],
2701 ii->ii_UniqueStrats[i]);
2702 if (!OidIsValid(ii->ii_UniqueOps[i]))
2703 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2704 ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2705 index->rd_opcintype[i], index->rd_opfamily[i]);
2707 }
2708}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, Oid opcintype, bool missing_ok)
Definition: amapi.c:143
#define Assert(condition)
Definition: c.h:815
uint16_t uint16
Definition: c.h:487
#define OidIsValid(objectId)
Definition: c.h:732
@ COMPARE_EQ
Definition: cmptype.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1312
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:167
void * palloc(Size size)
Definition: mcxt.c:1317
unsigned int Oid
Definition: postgres_ext.h:32
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:531
bool ii_Unique
Definition: execnodes.h:208
Oid * ii_UniqueOps
Definition: execnodes.h:205
uint16 * ii_UniqueStrats
Definition: execnodes.h:207
Oid * ii_UniqueProcs
Definition: execnodes.h:206

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

Referenced by ExecOpenIndices().

◆ CompareIndexInfo()

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

Definition at line 2536 of file index.c.

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

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

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

◆ ConstructTupleDescriptor()

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

Definition at line 280 of file index.c.

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

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

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4215 of file index.c.

4216{
4219}
static List * pendingReindexedIndexes
Definition: index.c:4084
static int list_length(const List *l)
Definition: pg_list.h:152
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505

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

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

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

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

◆ index_build()

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

Definition at line 2975 of file index.c.

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

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

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

◆ index_check_primary_key()

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

Definition at line 201 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1484 of file index.c.

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

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

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

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1822 of file index.c.

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

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

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

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

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

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

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

3477{
3478 Relation pg_index;
3479 HeapTuple indexTuple;
3480 Form_pg_index indexForm;
3481
3482 /* Open pg_index and fetch a writable copy of the index's tuple */
3483 pg_index = table_open(IndexRelationId, RowExclusiveLock);
3484
3485 indexTuple = SearchSysCacheCopy1(INDEXRELID,
3486 ObjectIdGetDatum(indexId));
3487 if (!HeapTupleIsValid(indexTuple))
3488 elog(ERROR, "cache lookup failed for index %u", indexId);
3489 indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3490
3491 /* Perform the requested state change on the copy */
3492 switch (action)
3493 {
3495 /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3496 Assert(indexForm->indislive);
3497 Assert(!indexForm->indisready);
3498 Assert(!indexForm->indisvalid);
3499 indexForm->indisready = true;
3500 break;
3502 /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3503 Assert(indexForm->indislive);
3504 Assert(indexForm->indisready);
3505 Assert(!indexForm->indisvalid);
3506 indexForm->indisvalid = true;
3507 break;
3509
3510 /*
3511 * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3512 *
3513 * If indisready == true we leave it set so the index still gets
3514 * maintained by active transactions. We only need to ensure that
3515 * indisvalid is false. (We don't assert that either is initially
3516 * true, though, since we want to be able to retry a DROP INDEX
3517 * CONCURRENTLY that failed partway through.)
3518 *
3519 * Note: the CLUSTER logic assumes that indisclustered cannot be
3520 * set on any invalid index, so clear that flag too. For
3521 * cleanliness, also clear indisreplident.
3522 */
3523 indexForm->indisvalid = false;
3524 indexForm->indisclustered = false;
3525 indexForm->indisreplident = false;
3526 break;
3528
3529 /*
3530 * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3531 *
3532 * We clear both indisready and indislive, because we not only
3533 * want to stop updates, we want to prevent sessions from touching
3534 * the index at all.
3535 */
3536 Assert(!indexForm->indisvalid);
3537 Assert(!indexForm->indisclustered);
3538 Assert(!indexForm->indisreplident);
3539 indexForm->indisready = false;
3540 indexForm->indislive = false;
3541 break;
3542 }
3543
3544 /* ... and update it */
3545 CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3546
3547 table_close(pg_index, RowExclusiveLock);
3548}
@ 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 2809 of file index.c.

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

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

3171{
3172 TableScanDesc scan;
3174 bool isnull[INDEX_MAX_KEYS];
3175 ExprState *predicate;
3176 TupleTableSlot *slot;
3177 EState *estate;
3178 ExprContext *econtext;
3179 Snapshot snapshot;
3180
3181 /*
3182 * If we are reindexing the target index, mark it as no longer being
3183 * reindexed, to forestall an Assert in index_beginscan when we try to use
3184 * the index for probes. This is OK because the index is now fully valid.
3185 */
3188
3189 /*
3190 * Need an EState for evaluation of index expressions and partial-index
3191 * predicates. Also a slot to hold the current tuple.
3192 */
3193 estate = CreateExecutorState();
3194 econtext = GetPerTupleExprContext(estate);
3195 slot = table_slot_create(heapRelation, NULL);
3196
3197 /* Arrange for econtext's scan tuple to be the tuple under test */
3198 econtext->ecxt_scantuple = slot;
3199
3200 /* Set up execution state for predicate, if any. */
3201 predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3202
3203 /*
3204 * Scan all live tuples in the base relation.
3205 */
3206 snapshot = RegisterSnapshot(GetLatestSnapshot());
3207 scan = table_beginscan_strat(heapRelation, /* relation */
3208 snapshot, /* snapshot */
3209 0, /* number of keys */
3210 NULL, /* scan key */
3211 true, /* buffer access strategy OK */
3212 true); /* syncscan OK */
3213
3214 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3215 {
3217
3218 /*
3219 * In a partial index, ignore tuples that don't satisfy the predicate.
3220 */
3221 if (predicate != NULL)
3222 {
3223 if (!ExecQual(predicate, econtext))
3224 continue;
3225 }
3226
3227 /*
3228 * Extract index column values, including computing expressions.
3229 */
3230 FormIndexDatum(indexInfo,
3231 slot,
3232 estate,
3233 values,
3234 isnull);
3235
3236 /*
3237 * Check that this tuple has no conflicts.
3238 */
3239 check_exclusion_constraint(heapRelation,
3240 indexRelation, indexInfo,
3241 &(slot->tts_tid), values, isnull,
3242 estate, true);
3243
3245 }
3246
3247 table_endscan(scan);
3248 UnregisterSnapshot(snapshot);
3249
3251
3252 FreeExecutorState(estate);
3253
3254 /* These may have been pointing to the now-gone estate */
3255 indexInfo->ii_ExpressionsState = NIL;
3256 indexInfo->ii_PredicateState = NULL;
3257}
ExprState * ExecPrepareQual(List *qual, EState *estate)
Definition: execExpr.c:793
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex)
Definition: execIndexing.c:950
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1441
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:426
static void ResetReindexProcessing(void)
Definition: index.c:4143
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid)
Definition: index.c:4102
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2730
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:283
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:752
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:275
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:267
ExprState * ii_PredicateState
Definition: execnodes.h:201
ItemPointerData tts_tid
Definition: tuptable.h:129
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1025
static TableScanDesc table_beginscan_strat(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key, bool allow_strat, bool allow_sync)
Definition: tableam.h:937
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1061

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

3557{
3558 HeapTuple tuple;
3560 Oid result;
3561
3562 tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3563 if (!HeapTupleIsValid(tuple))
3564 {
3565 if (missing_ok)
3566 return InvalidOid;
3567 elog(ERROR, "cache lookup failed for index %u", indexId);
3568 }
3569 index = (Form_pg_index) GETSTRUCT(tuple);
3570 Assert(index->indexrelid == indexId);
3571
3572 result = index->indrelid;
3573 ReleaseSysCache(tuple);
3574 return result;
3575}

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

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

◆ InitializeAttributeOids()

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

Definition at line 493 of file index.c.

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

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

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

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

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

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

4103{
4104 return indexOid == currentlyReindexedIndex;
4105}
static Oid currentlyReindexedIndex
Definition: index.c:4083

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4092 of file index.c.

4093{
4094 return heapOid == currentlyReindexedHeap;
4095}
static Oid currentlyReindexedHeap
Definition: index.c:4082

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4113 of file index.c.

4114{
4115 return indexOid == currentlyReindexedIndex ||
4117}
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722

References currentlyReindexedIndex, list_member_oid(), and pendingReindexedIndexes.

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

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 147 of file index.c.

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

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

Referenced by index_check_primary_key().

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4173 of file index.c.

4174{
4175 if (IsInParallelMode())
4176 elog(ERROR, "cannot modify reindex state during a parallel operation");
4178 indexOid);
4179}
List * list_delete_oid(List *list, Oid datum)
Definition: list.c:910
bool IsInParallelMode(void)
Definition: xact.c:1088

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

Referenced by reindex_relation(), and SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4143 of file index.c.

4144{
4147 /* reindexingNestLevel remains set till end of (sub)transaction */
4148}

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4186 of file index.c.

4187{
4188 /*
4189 * Because reindexing is not re-entrant, we don't need to cope with nested
4190 * reindexing states. We just need to avoid messing up the outer-level
4191 * state in case a subtransaction fails within a REINDEX. So checking the
4192 * current nest level against that of the reindex operation is sufficient.
4193 */
4194 if (reindexingNestLevel >= nestLevel)
4195 {
4198
4199 /*
4200 * We needn't try to release the contents of pendingReindexedIndexes;
4201 * that list should be in a transaction-lifespan context, so it will
4202 * go away automatically.
4203 */
4205
4207 }
4208}
static int reindexingNestLevel
Definition: index.c:4085

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4244 of file index.c.

4245{
4246 const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4247 int c = 0;
4248 MemoryContext oldcontext;
4249
4252
4255 for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4258 sistate->pendingReindexedIndexes[c]);
4259 MemoryContextSwitchTo(oldcontext);
4260
4261 /* Note the worker has its own transaction nesting level */
4263}
MemoryContext TopMemoryContext
Definition: mcxt.c:149
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
char * c
Oid currentlyReindexedHeap
Definition: index.c:94
Oid currentlyReindexedIndex
Definition: index.c:95
int numPendingReindexedIndexes
Definition: index.c:96
Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]
Definition: index.c:97
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:928

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4157 of file index.c.

4158{
4159 /* Reindexing is not re-entrant. */
4161 elog(ERROR, "cannot reindex while reindexing");
4162 if (IsInParallelMode())
4163 elog(ERROR, "cannot modify reindex state during a parallel operation");
4166}
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 4124 of file index.c.

4125{
4126 Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4127 /* Reindexing is not re-entrant. */
4129 elog(ERROR, "cannot reindex while reindexing");
4130 currentlyReindexedHeap = heapOid;
4131 currentlyReindexedIndex = indexOid;
4132 /* Index is no longer "pending" reindex. */
4133 RemoveReindexPending(indexOid);
4134 /* This may have been set already, but in case it isn't, do so now. */
4136}

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

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

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

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

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

Definition at line 3456 of file index.c.

3457{
3459 int64 encoded = itemptr_encode(itemptr);
3460
3461 tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3462 state->itups += 1;
3463 return false; /* never actually delete anything */
3464}
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
static int64 itemptr_encode(ItemPointer itemptr)
Definition: index.h:190
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)

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

Referenced by validate_index().

Variable Documentation

◆ binary_upgrade_next_index_pg_class_oid

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid

Definition at line 84 of file index.c.

Referenced by binary_upgrade_set_next_index_pg_class_oid(), and index_create().

◆ binary_upgrade_next_index_pg_class_relfilenumber

RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber

◆ currentlyReindexedHeap

◆ currentlyReindexedIndex

◆ pendingReindexedIndexes

◆ reindexingNestLevel

int reindexingNestLevel = 0
static