PostgreSQL Source Code git master
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 2487 of file index.c.

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

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

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo * BuildIndexInfo ( Relation  index)

Definition at line 2427 of file index.c.

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

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

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

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2668 of file index.c.

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

References Assert, BTEqualStrategyNumber, elog, ERROR, get_opcode(), get_opfamily_member(), i, IndexInfo::ii_Unique, IndexInfo::ii_UniqueOps, IndexInfo::ii_UniqueProcs, IndexInfo::ii_UniqueStrats, IndexRelationGetNumberOfKeyAttributes, OidIsValid, and palloc().

Referenced by ExecOpenIndices().

◆ CompareIndexInfo()

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

Definition at line 2536 of file index.c.

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

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

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

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4213 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2728 of file index.c.

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

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

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

◆ index_build()

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

Definition at line 2973 of file index.c.

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

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

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

◆ index_check_primary_key()

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

Definition at line 201 of file index.c.

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

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1299 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1822 of file index.c.

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

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

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

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

Definition at line 1551 of file index.c.

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

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1884 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 725 of file index.c.

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

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

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

◆ index_drop()

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

Definition at line 2121 of file index.c.

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

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

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3474 of file index.c.

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

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

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

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

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

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 4418 of file indexcmds.c.

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

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

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

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

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

4091{
4092 return heapOid == currentlyReindexedHeap;
4093}
static Oid currentlyReindexedHeap
Definition: index.c:4080

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4111 of file index.c.

4112{
4113 return indexOid == currentlyReindexedIndex ||
4115}
static Oid currentlyReindexedIndex
Definition: index.c:4081
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 4184 of file index.c.

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

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void *  reindexstate)

Definition at line 4242 of file index.c.

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

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

◆ validate_index()

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

Definition at line 3321 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().