PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
index.h File Reference
Include dependency graph for index.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ReindexParams
 
struct  ValidateIndexState
 

Macros

#define DEFAULT_INDEX_TYPE   "btree"
 
#define REINDEXOPT_VERBOSE   0x01 /* print progress info */
 
#define REINDEXOPT_REPORT_PROGRESS   0x02 /* report pgstat progress */
 
#define REINDEXOPT_MISSING_OK   0x04 /* skip missing relations */
 
#define REINDEXOPT_CONCURRENTLY   0x08 /* concurrent mode */
 
#define INDEX_CREATE_IS_PRIMARY   (1 << 0)
 
#define INDEX_CREATE_ADD_CONSTRAINT   (1 << 1)
 
#define INDEX_CREATE_SKIP_BUILD   (1 << 2)
 
#define INDEX_CREATE_CONCURRENT   (1 << 3)
 
#define INDEX_CREATE_IF_NOT_EXISTS   (1 << 4)
 
#define INDEX_CREATE_PARTITIONED   (1 << 5)
 
#define INDEX_CREATE_INVALID   (1 << 6)
 
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)
 
#define INDEX_CONSTR_CREATE_DEFERRABLE   (1 << 1)
 
#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)
 
#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)
 
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)
 
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS   (1 << 5)
 
#define REINDEX_REL_PROCESS_TOAST   0x01
 
#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02
 
#define REINDEX_REL_CHECK_CONSTRAINTS   0x04
 
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08
 
#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10
 

Typedefs

typedef struct ReindexParams ReindexParams
 
typedef struct ValidateIndexState ValidateIndexState
 

Enumerations

enum  IndexStateFlagsAction { INDEX_CREATE_SET_READY , INDEX_CREATE_SET_VALID , INDEX_DROP_CLEAR_VALID , INDEX_DROP_SET_DEAD }
 

Functions

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)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 
static int64 itemptr_encode (ItemPointer itemptr)
 
static void itemptr_decode (ItemPointer itemptr, int64 encoded)
 

Macro Definition Documentation

◆ DEFAULT_INDEX_TYPE

#define DEFAULT_INDEX_TYPE   "btree"

Definition at line 21 of file index.h.

◆ INDEX_CONSTR_CREATE_DEFERRABLE

#define INDEX_CONSTR_CREATE_DEFERRABLE   (1 << 1)

Definition at line 92 of file index.h.

◆ INDEX_CONSTR_CREATE_INIT_DEFERRED

#define INDEX_CONSTR_CREATE_INIT_DEFERRED   (1 << 2)

Definition at line 93 of file index.h.

◆ INDEX_CONSTR_CREATE_MARK_AS_PRIMARY

#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY   (1 << 0)

Definition at line 91 of file index.h.

◆ INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS

#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS   (1 << 4)

Definition at line 95 of file index.h.

◆ INDEX_CONSTR_CREATE_UPDATE_INDEX

#define INDEX_CONSTR_CREATE_UPDATE_INDEX   (1 << 3)

Definition at line 94 of file index.h.

◆ INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS

#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS   (1 << 5)

Definition at line 96 of file index.h.

◆ INDEX_CREATE_ADD_CONSTRAINT

#define INDEX_CREATE_ADD_CONSTRAINT   (1 << 1)

Definition at line 62 of file index.h.

◆ INDEX_CREATE_CONCURRENT

#define INDEX_CREATE_CONCURRENT   (1 << 3)

Definition at line 64 of file index.h.

◆ INDEX_CREATE_IF_NOT_EXISTS

#define INDEX_CREATE_IF_NOT_EXISTS   (1 << 4)

Definition at line 65 of file index.h.

◆ INDEX_CREATE_INVALID

#define INDEX_CREATE_INVALID   (1 << 6)

Definition at line 67 of file index.h.

◆ INDEX_CREATE_IS_PRIMARY

#define INDEX_CREATE_IS_PRIMARY   (1 << 0)

Definition at line 61 of file index.h.

◆ INDEX_CREATE_PARTITIONED

#define INDEX_CREATE_PARTITIONED   (1 << 5)

Definition at line 66 of file index.h.

◆ INDEX_CREATE_SKIP_BUILD

#define INDEX_CREATE_SKIP_BUILD   (1 << 2)

Definition at line 63 of file index.h.

◆ REINDEX_REL_CHECK_CONSTRAINTS

#define REINDEX_REL_CHECK_CONSTRAINTS   0x04

Definition at line 161 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_PERMANENT

#define REINDEX_REL_FORCE_INDEXES_PERMANENT   0x10

Definition at line 163 of file index.h.

◆ REINDEX_REL_FORCE_INDEXES_UNLOGGED

#define REINDEX_REL_FORCE_INDEXES_UNLOGGED   0x08

Definition at line 162 of file index.h.

◆ REINDEX_REL_PROCESS_TOAST

#define REINDEX_REL_PROCESS_TOAST   0x01

Definition at line 159 of file index.h.

◆ REINDEX_REL_SUPPRESS_INDEX_USE

#define REINDEX_REL_SUPPRESS_INDEX_USE   0x02

Definition at line 160 of file index.h.

◆ REINDEXOPT_CONCURRENTLY

#define REINDEXOPT_CONCURRENTLY   0x08 /* concurrent mode */

Definition at line 44 of file index.h.

◆ REINDEXOPT_MISSING_OK

#define REINDEXOPT_MISSING_OK   0x04 /* skip missing relations */

Definition at line 43 of file index.h.

◆ REINDEXOPT_REPORT_PROGRESS

#define REINDEXOPT_REPORT_PROGRESS   0x02 /* report pgstat progress */

Definition at line 42 of file index.h.

◆ REINDEXOPT_VERBOSE

#define REINDEXOPT_VERBOSE   0x01 /* print progress info */

Definition at line 41 of file index.h.

Typedef Documentation

◆ ReindexParams

typedef struct ReindexParams ReindexParams

◆ ValidateIndexState

Enumeration Type Documentation

◆ IndexStateFlagsAction

Enumerator
INDEX_CREATE_SET_READY 
INDEX_CREATE_SET_VALID 
INDEX_DROP_CLEAR_VALID 
INDEX_DROP_SET_DEAD 

Definition at line 24 of file index.h.

25{
IndexStateFlagsAction
Definition: index.h:25
@ INDEX_CREATE_SET_VALID
Definition: index.h:27
@ INDEX_DROP_CLEAR_VALID
Definition: index.h:28
@ INDEX_DROP_SET_DEAD
Definition: index.h:29
@ INDEX_CREATE_SET_READY
Definition: index.h:26

Function Documentation

◆ BuildDummyIndexInfo()

IndexInfo * BuildDummyIndexInfo ( Relation  index)

Definition at line 2488 of file index.c.

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

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

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

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

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2669 of file index.c.

2670{
2671 int indnkeyatts;
2672 int i;
2673
2675
2676 /*
2677 * fetch info for checking unique indexes
2678 */
2679 Assert(ii->ii_Unique);
2680
2681 ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2682 ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
2683 ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
2684
2685 /*
2686 * We have to look up the operator's strategy number. This provides a
2687 * cross-check that the operator does match the index.
2688 */
2689 /* We need the func OIDs and strategy numbers too */
2690 for (i = 0; i < indnkeyatts; i++)
2691 {
2692 ii->ii_UniqueStrats[i] =
2694 index->rd_rel->relam,
2695 index->rd_opfamily[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, bool missing_ok)
Definition: amapi.c:148
uint16_t uint16
Definition: c.h:501
#define OidIsValid(objectId)
Definition: c.h:746
@ COMPARE_EQ
Definition: cmptype.h:36
Assert(PointerIsAligned(start, uint64))
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1425
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:167
void * palloc(Size size)
Definition: mcxt.c:1940
unsigned int Oid
Definition: postgres_ext.h:30
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:535
bool ii_Unique
Definition: execnodes.h:209
Oid * ii_UniqueOps
Definition: execnodes.h:206
uint16 * ii_UniqueStrats
Definition: execnodes.h:208
Oid * ii_UniqueProcs
Definition: execnodes.h:207

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

◆ CompareIndexInfo()

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

Definition at line 2537 of file index.c.

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

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

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

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4242 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 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:678
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:458
#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
uintptr_t Datum
Definition: postgres.h:69
List * ii_ExpressionsState
Definition: execnodes.h:200
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:420
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:399

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

◆ IndexGetRelation()

Oid IndexGetRelation ( Oid  indexId,
bool  missing_ok 
)

Definition at line 3583 of file index.c.

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

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

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

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 4409 of file indexcmds.c.

4410{
4411 Relation pg_inherits;
4412 ScanKeyData key[2];
4413 SysScanDesc scan;
4414 Oid partRelid = RelationGetRelid(partitionIdx);
4415 HeapTuple tuple;
4416 bool fix_dependencies;
4417
4418 /* Make sure this is an index */
4419 Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4420 partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4421
4422 /*
4423 * Scan pg_inherits for rows linking our index to some parent.
4424 */
4425 pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
4426 ScanKeyInit(&key[0],
4427 Anum_pg_inherits_inhrelid,
4428 BTEqualStrategyNumber, F_OIDEQ,
4429 ObjectIdGetDatum(partRelid));
4430 ScanKeyInit(&key[1],
4431 Anum_pg_inherits_inhseqno,
4432 BTEqualStrategyNumber, F_INT4EQ,
4433 Int32GetDatum(1));
4434 scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
4435 NULL, 2, key);
4436 tuple = systable_getnext(scan);
4437
4438 if (!HeapTupleIsValid(tuple))
4439 {
4440 if (parentOid == InvalidOid)
4441 {
4442 /*
4443 * No pg_inherits row, and no parent wanted: nothing to do in this
4444 * case.
4445 */
4446 fix_dependencies = false;
4447 }
4448 else
4449 {
4450 StoreSingleInheritance(partRelid, parentOid, 1);
4451 fix_dependencies = true;
4452 }
4453 }
4454 else
4455 {
4456 Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
4457
4458 if (parentOid == InvalidOid)
4459 {
4460 /*
4461 * There exists a pg_inherits row, which we want to clear; do so.
4462 */
4463 CatalogTupleDelete(pg_inherits, &tuple->t_self);
4464 fix_dependencies = true;
4465 }
4466 else
4467 {
4468 /*
4469 * A pg_inherits row exists. If it's the same we want, then we're
4470 * good; if it differs, that amounts to a corrupt catalog and
4471 * should not happen.
4472 */
4473 if (inhForm->inhparent != parentOid)
4474 {
4475 /* unexpected: we should not get called in this case */
4476 elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4477 inhForm->inhrelid, inhForm->inhparent);
4478 }
4479
4480 /* already in the right state */
4481 fix_dependencies = false;
4482 }
4483 }
4484
4485 /* done with pg_inherits */
4486 systable_endscan(scan);
4487 relation_close(pg_inherits, RowExclusiveLock);
4488
4489 /* set relhassubclass if an index partition has been added to the parent */
4490 if (OidIsValid(parentOid))
4491 {
4493 SetRelationHasSubclass(parentOid, true);
4494 }
4495
4496 /* set relispartition correctly on the partition */
4497 update_relispartition(partRelid, OidIsValid(parentOid));
4498
4499 if (fix_dependencies)
4500 {
4501 /*
4502 * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4503 * dependencies on the parent index and the table; if removing a
4504 * parent, delete PARTITION dependencies.
4505 */
4506 if (OidIsValid(parentOid))
4507 {
4508 ObjectAddress partIdx;
4509 ObjectAddress parentIdx;
4510 ObjectAddress partitionTbl;
4511
4512 ObjectAddressSet(partIdx, RelationRelationId, partRelid);
4513 ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
4514 ObjectAddressSet(partitionTbl, RelationRelationId,
4515 partitionIdx->rd_index->indrelid);
4516 recordDependencyOn(&partIdx, &parentIdx,
4518 recordDependencyOn(&partIdx, &partitionTbl,
4520 }
4521 else
4522 {
4523 deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4524 RelationRelationId,
4526 deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4527 RelationRelationId,
4529 }
4530
4531 /* make our updates visible */
4533 }
4534}
static void update_relispartition(Oid relationId, bool newval)
Definition: indexcmds.c:4541
static void fix_dependencies(ArchiveHandle *AH)
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45

References Assert(), BTEqualStrategyNumber, CatalogTupleDelete(), CommandCounterIncrement(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ERROR, fix_dependencies(), GETSTRUCT(), HeapTupleIsValid, Int32GetDatum(), InvalidOid, sort-test::key, LockRelationOid(), ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, RelationData::rd_index, RelationData::rd_rel, recordDependencyOn(), relation_close(), relation_open(), RelationGetRelid, RowExclusiveLock, ScanKeyInit(), SetRelationHasSubclass(), ShareUpdateExclusiveLock, StoreSingleInheritance(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and update_relispartition().

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

◆ itemptr_decode()

static void itemptr_decode ( ItemPointer  itemptr,
int64  encoded 
)
inlinestatic

Definition at line 211 of file index.h.

212{
213 BlockNumber block = (BlockNumber) (encoded >> 16);
214 OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
215
216 ItemPointerSet(itemptr, block, offset);
217}
uint32 BlockNumber
Definition: block.h:31
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
uint16 OffsetNumber
Definition: off.h:24

References ItemPointerSet().

Referenced by heapam_index_validate_scan().

◆ itemptr_encode()

static int64 itemptr_encode ( ItemPointer  itemptr)
inlinestatic

Definition at line 190 of file index.h.

191{
192 BlockNumber block = ItemPointerGetBlockNumber(itemptr);
194 int64 encoded;
195
196 /*
197 * Use the 16 least significant bits for the offset. 32 adjacent bits are
198 * used for the block number. Since remaining bits are unused, there
199 * cannot be negative encoded values (We assume a two's complement
200 * representation).
201 */
202 encoded = ((uint64) block << 16) | (uint16) offset;
203
204 return encoded;
205}
uint64_t uint64
Definition: c.h:503
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103

References ItemPointerGetBlockNumber(), and ItemPointerGetOffsetNumber().

Referenced by validate_index_callback().

◆ reindex_index()

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

Definition at line 3608 of file index.c.

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

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

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

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

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4119 of file index.c.

4120{
4121 return heapOid == currentlyReindexedHeap;
4122}
static Oid currentlyReindexedHeap
Definition: index.c:4109

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4140 of file index.c.

4141{
4142 return indexOid == currentlyReindexedIndex ||
4144}
static Oid currentlyReindexedIndex
Definition: index.c:4110
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().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4213 of file index.c.

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

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4271 of file index.c.

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

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

◆ validate_index()

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

Definition at line 3350 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().