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

Go to the source code of this file.

Data Structures

struct  SerializedReindexState
 

Functions

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

Variables

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

Function Documentation

◆ AppendAttributeTuples()

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

Definition at line 513 of file index.c.

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

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

Referenced by index_create().

◆ BuildDummyIndexInfo()

IndexInfo * BuildDummyIndexInfo ( Relation  index)

Definition at line 2489 of file index.c.

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

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

Referenced by RelationTruncateIndexes().

◆ BuildIndexInfo()

IndexInfo * BuildIndexInfo ( Relation  index)

Definition at line 2429 of file index.c.

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

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

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

◆ BuildSpeculativeIndexInfo()

void BuildSpeculativeIndexInfo ( Relation  index,
IndexInfo ii 
)

Definition at line 2670 of file index.c.

2671{
2672 int indnkeyatts;
2673 int i;
2674
2676
2677 /*
2678 * fetch info for checking unique indexes
2679 */
2680 Assert(ii->ii_Unique);
2681
2685
2686 /*
2687 * We have to look up the operator's strategy number. This provides a
2688 * cross-check that the operator does match the index.
2689 */
2690 /* We need the func OIDs and strategy numbers too */
2691 for (i = 0; i < indnkeyatts; i++)
2692 {
2693 ii->ii_UniqueStrats[i] =
2695 index->rd_rel->relam,
2696 index->rd_opfamily[i],
2697 false);
2698 ii->ii_UniqueOps[i] =
2699 get_opfamily_member(index->rd_opfamily[i],
2700 index->rd_opcintype[i],
2701 index->rd_opcintype[i],
2702 ii->ii_UniqueStrats[i]);
2703 if (!OidIsValid(ii->ii_UniqueOps[i]))
2704 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2705 ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2706 index->rd_opcintype[i], index->rd_opfamily[i]);
2708 }
2709}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition amapi.c:161
#define Assert(condition)
Definition c.h:942
uint16_t uint16
Definition c.h:614
#define OidIsValid(objectId)
Definition c.h:857
@ COMPARE_EQ
Definition cmptype.h:36
#define palloc_array(type, count)
Definition fe_memutils.h:76
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:170
unsigned int Oid
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:533
bool ii_Unique
Definition execnodes.h:211
Oid * ii_UniqueOps
Definition execnodes.h:206
uint16 * ii_UniqueStrats
Definition execnodes.h:208
Oid * ii_UniqueProcs
Definition execnodes.h:207

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

Referenced by BuildConflictIndexInfo(), and ExecOpenIndices().

◆ CompareIndexInfo()

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

Definition at line 2538 of file index.c.

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

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

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

◆ ConstructTupleDescriptor()

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

Definition at line 282 of file index.c.

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

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

Referenced by index_create().

◆ EstimateReindexStateSpace()

Size EstimateReindexStateSpace ( void  )

Definition at line 4243 of file index.c.

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

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

Referenced by InitializeParallelDSM().

◆ FormIndexDatum()

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

Definition at line 2731 of file index.c.

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

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

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

◆ index_build()

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

Definition at line 3003 of file index.c.

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

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

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

◆ index_check_primary_key()

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

Definition at line 203 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and DefineIndex().

◆ index_concurrently_build()

void index_concurrently_build ( Oid  heapRelationId,
Oid  indexRelationId 
)

Definition at line 1486 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ index_concurrently_create_copy()

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

Definition at line 1301 of file index.c.

1303{
1304 Relation indexRelation;
1306 *newInfo;
1309 classTuple;
1317 bool isnull;
1319 List *indexExprs = NIL;
1320 List *indexPreds = NIL;
1321
1322 indexRelation = index_open(oldIndexId, RowExclusiveLock);
1323
1324 /* The new index needs some information from the old index */
1325 oldInfo = BuildIndexInfo(indexRelation);
1326
1327 /*
1328 * Concurrent build of an index with exclusion constraints is not
1329 * supported.
1330 */
1331 if (oldInfo->ii_ExclusionOps != NULL)
1332 ereport(ERROR,
1334 errmsg("concurrent index creation for exclusion constraints is not supported")));
1335
1336 /* Get the array of class and column options IDs from index info */
1339 elog(ERROR, "cache lookup failed for index %u", oldIndexId);
1343
1347
1348 /* Fetch reloptions of index if any */
1351 elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
1353 Anum_pg_class_reloptions, &isnull);
1354
1355 /*
1356 * Fetch the list of expressions and predicates directly from the
1357 * catalogs. This cannot rely on the information from IndexInfo of the
1358 * old index as these have been flattened for the planner.
1359 */
1360 if (oldInfo->ii_Expressions != NIL)
1361 {
1363 char *exprString;
1364
1370 }
1371 if (oldInfo->ii_Predicate != NIL)
1372 {
1374 char *predString;
1375
1380
1381 /* Also convert to implicit-AND format */
1384 }
1385
1386 /*
1387 * Build the index information for the new index. Note that rebuild of
1388 * indexes with exclusion constraints is not supported, hence there is no
1389 * need to fill all the ii_Exclusion* fields.
1390 */
1391 newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1392 oldInfo->ii_NumIndexKeyAttrs,
1393 oldInfo->ii_Am,
1394 indexExprs,
1395 indexPreds,
1396 oldInfo->ii_Unique,
1397 oldInfo->ii_NullsNotDistinct,
1398 false, /* not ready for inserts */
1399 true,
1400 indexRelation->rd_indam->amsummarizing,
1401 oldInfo->ii_WithoutOverlaps);
1402
1403 /*
1404 * Extract the list of column names and the column numbers for the new
1405 * index information. All this information will be used for the index
1406 * creation.
1407 */
1408 for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++)
1409 {
1410 TupleDesc indexTupDesc = RelationGetDescr(indexRelation);
1412
1414 newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i];
1415 }
1416
1417 /* Extract opclass options for each attribute */
1418 opclassOptions = palloc0_array(Datum, newInfo->ii_NumIndexAttrs);
1419 for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1421
1422 /* Extract statistic targets for each attribute */
1423 stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs);
1424 for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1425 {
1426 HeapTuple tp;
1427 Datum dat;
1428
1430 if (!HeapTupleIsValid(tp))
1431 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1432 i + 1, oldIndexId);
1434 ReleaseSysCache(tp);
1435 stattargets[i].value = dat;
1436 stattargets[i].isnull = isnull;
1437 }
1438
1439 /*
1440 * Now create the new index.
1441 *
1442 * For a partition index, we adjust the partition dependency later, to
1443 * ensure a consistent state at all times. That is why parentIndexRelid
1444 * is not set here.
1445 */
1446 newIndexId = index_create(heapRelation,
1447 newName,
1448 InvalidOid, /* indexRelationId */
1449 InvalidOid, /* parentIndexRelid */
1450 InvalidOid, /* parentConstraintId */
1451 InvalidRelFileNumber, /* relFileNumber */
1452 newInfo,
1454 indexRelation->rd_rel->relam,
1455 tablespaceOid,
1456 indexRelation->rd_indcollation,
1457 indclass->values,
1459 indcoloptions->values,
1463 0,
1464 true, /* allow table to be a system catalog? */
1465 false, /* is_internal? */
1466 NULL);
1467
1468 /* Close the relations used and clean up */
1469 index_close(indexRelation, NoLock);
1472
1473 return newIndexId;
1474}
#define TextDatumGetCString(d)
Definition builtins.h:99
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:727
#define INDEX_CREATE_SKIP_BUILD
Definition index.h:69
#define INDEX_CREATE_CONCURRENT
Definition index.h:70
List * lappend(List *list, void *datum)
Definition list.c:339
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
void pfree(void *pointer)
Definition mcxt.c:1616
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
void * stringToNode(const char *str)
Definition read.c:90
#define InvalidRelFileNumber
Definition relpath.h:26
bool amsummarizing
Definition amapi.h:282
Definition pg_list.h:54
Oid * rd_indcollation
Definition rel.h:217
Definition c.h:814
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595

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

Referenced by ReindexRelationConcurrently().

◆ index_concurrently_set_dead()

void index_concurrently_set_dead ( Oid  heapId,
Oid  indexId 
)

Definition at line 1824 of file index.c.

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

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

Referenced by index_drop(), and ReindexRelationConcurrently().

◆ index_concurrently_swap()

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

Definition at line 1553 of file index.c.

1554{
1556 pg_index,
1558 pg_trigger;
1569 bool isPartition;
1572 ListCell *lc;
1573
1574 /*
1575 * Take a necessary lock on the old and new index before swapping them.
1576 */
1579
1580 /* Now swap names and dependencies of those indexes */
1582
1586 elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1590 elog(ERROR, "could not find tuple for relation %u", newIndexId);
1591
1594
1595 /* Swap the names */
1596 namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1597 namestrcpy(&oldClassForm->relname, oldName);
1598
1599 /* Swap the partition flags to track inheritance properly */
1600 isPartition = newClassForm->relispartition;
1601 newClassForm->relispartition = oldClassForm->relispartition;
1602 oldClassForm->relispartition = isPartition;
1603
1606
1609
1610 /* Now swap index info */
1612
1616 elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1620 elog(ERROR, "could not find tuple for relation %u", newIndexId);
1621
1624
1625 /*
1626 * Copy constraint flags from the old index. This is safe because the old
1627 * index guaranteed uniqueness.
1628 */
1629 newIndexForm->indisprimary = oldIndexForm->indisprimary;
1630 oldIndexForm->indisprimary = false;
1631 newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1632 oldIndexForm->indisexclusion = false;
1633 newIndexForm->indimmediate = oldIndexForm->indimmediate;
1634 oldIndexForm->indimmediate = true;
1635
1636 /* Preserve indisreplident in the new index */
1637 newIndexForm->indisreplident = oldIndexForm->indisreplident;
1638
1639 /* Preserve indisclustered in the new index */
1640 newIndexForm->indisclustered = oldIndexForm->indisclustered;
1641
1642 /*
1643 * Mark the new index as valid, and the old index as invalid similarly to
1644 * what index_set_state_flags() does.
1645 */
1646 newIndexForm->indisvalid = true;
1647 oldIndexForm->indisvalid = false;
1648 oldIndexForm->indisclustered = false;
1649 oldIndexForm->indisreplident = false;
1650
1653
1656
1657 /*
1658 * Move constraints and triggers over to the new index
1659 */
1660
1662
1664
1667
1670
1671 foreach(lc, constraintOids)
1672 {
1676 ScanKeyData key[1];
1677 SysScanDesc scan;
1679
1680 /* Move the constraint from the old to the new index */
1684 elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1685
1687
1688 if (conForm->conindid == oldIndexId)
1689 {
1690 conForm->conindid = newIndexId;
1691
1693 }
1694
1696
1697 /* Search for trigger records */
1698 ScanKeyInit(&key[0],
1702
1704 NULL, 1, key);
1705
1707 {
1709
1710 if (tgForm->tgconstrindid != oldIndexId)
1711 continue;
1712
1713 /* Make a modifiable copy */
1716
1717 tgForm->tgconstrindid = newIndexId;
1718
1720
1722 }
1723
1724 systable_endscan(scan);
1725 }
1726
1727 /*
1728 * Move comment if any
1729 */
1730 {
1732 ScanKeyData skey[3];
1734 HeapTuple tuple;
1736 bool nulls[Natts_pg_description] = {0};
1737 bool replaces[Natts_pg_description] = {0};
1738
1741
1742 ScanKeyInit(&skey[0],
1746 ScanKeyInit(&skey[1],
1750 ScanKeyInit(&skey[2],
1753 Int32GetDatum(0));
1754
1756
1758 NULL, 3, skey);
1759
1760 while ((tuple = systable_getnext(sd)) != NULL)
1761 {
1763 values, nulls, replaces);
1764 CatalogTupleUpdate(description, &tuple->t_self, tuple);
1765
1766 break; /* Assume there can be only one match */
1767 }
1768
1771 }
1772
1773 /*
1774 * Swap inheritance relationship with parent index
1775 */
1777 {
1779 Oid parentIndexRelid = linitial_oid(ancestors);
1780
1783
1784 list_free(ancestors);
1785 }
1786
1787 /*
1788 * Swap all dependencies of and on the old index to the new one, and
1789 * vice-versa. Note that a call to CommandCounterIncrement() would cause
1790 * duplicate entries in pg_depend, so this should not be done.
1791 */
1794
1797
1798 /* copy over statistics from old to new index */
1800
1801 /* Copy data of pg_statistic from the old index to the new one */
1803
1804 /* Close relations */
1809
1810 /* The lock taken previously is not released until the end of transaction */
1813}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
void CopyStatistics(Oid fromrelid, Oid torelid)
Definition heap.c:3442
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1130
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:698
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
void list_free(List *list)
Definition list.c:1546
bool get_rel_relispartition(Oid relid)
Definition lsyscache.c:2247
List * get_partition_ancestors(Oid relid)
Definition partition.c:134
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition pg_depend.c:567
List * get_index_ref_constraints(Oid indexId)
Definition pg_depend.c:1117
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:623
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1061
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
#define linitial_oid(l)
Definition pg_list.h:180
#define lfirst_oid(lc)
Definition pg_list.h:174
END_CATALOG_STRUCT typedef FormData_pg_trigger * Form_pg_trigger
Definition pg_trigger.h:84
void pgstat_copy_relation_stats(Relation dst, Relation src)
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
#define BTEqualStrategyNumber
Definition stratnum.h:31
ItemPointerData t_self
Definition htup.h:65
const char * description

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

Referenced by ReindexRelationConcurrently().

◆ index_constraint_create()

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

Definition at line 1886 of file index.c.

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

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

Referenced by ATExecAddIndexConstraint(), and index_create().

◆ index_create()

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

Definition at line 727 of file index.c.

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

References AccessExclusiveLock, add_exact_object_address(), AppendAttributeTuples(), Assert, binary_upgrade_next_index_pg_class_oid, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CommandCounterIncrement(), CONSTRAINT_RELATION, ConstraintNameIsUsed(), ConstructTupleDescriptor(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_opclass, free_object_addresses(), get_collation_isdeterministic(), get_relname_relid(), GetNewRelFileNumber(), GETSTRUCT(), heap_create(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, index_build(), index_close(), INDEX_CONSTR_CREATE_DEFERRABLE, index_constraint_create(), INDEX_CREATE_ADD_CONSTRAINT, INDEX_CREATE_CONCURRENT, INDEX_CREATE_IF_NOT_EXISTS, INDEX_CREATE_INVALID, INDEX_CREATE_IS_PRIMARY, INDEX_CREATE_PARTITIONED, INDEX_CREATE_SKIP_BUILD, index_opclass_options(), index_register(), index_update_stats(), InitializeAttributeOids(), InsertPgClassTuple(), invalid, InvalidMultiXactId, InvalidOid, InvalidRelFileNumber, InvalidTransactionId, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsCatalogRelation(), IsNormalProcessingMode, IsSystemRelation(), LockRelation(), LockRelationOid(), NameStr, new_object_addresses(), NoLock, NOTICE, ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), OidIsValid, 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 2123 of file index.c.

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

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

Referenced by doDeletion().

◆ index_set_state_flags()

void index_set_state_flags ( Oid  indexId,
IndexStateFlagsAction  action 
)

Definition at line 3504 of file index.c.

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

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

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

◆ index_update_stats()

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

Definition at line 2810 of file index.c.

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

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

Referenced by index_build(), and index_create().

◆ IndexCheckExclusion()

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

Definition at line 3196 of file index.c.

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

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

Referenced by index_build().

◆ IndexGetRelation()

◆ InitializeAttributeOids()

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

Definition at line 495 of file index.c.

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

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

Referenced by index_create().

◆ reindex_index()

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

Definition at line 3609 of file index.c.

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

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

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

◆ reindex_relation()

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

Definition at line 3949 of file index.c.

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

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

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

◆ ReindexIsCurrentlyProcessingIndex()

static bool ReindexIsCurrentlyProcessingIndex ( Oid  indexOid)
static

Definition at line 4130 of file index.c.

4131{
4132 return indexOid == currentlyReindexedIndex;
4133}
static Oid currentlyReindexedIndex
Definition index.c:4111

References currentlyReindexedIndex.

Referenced by IndexCheckExclusion().

◆ ReindexIsProcessingHeap()

bool ReindexIsProcessingHeap ( Oid  heapOid)

Definition at line 4120 of file index.c.

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

References currentlyReindexedHeap.

◆ ReindexIsProcessingIndex()

bool ReindexIsProcessingIndex ( Oid  indexOid)

Definition at line 4141 of file index.c.

4142{
4143 return indexOid == currentlyReindexedIndex ||
4145}
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722

References currentlyReindexedIndex, list_member_oid(), and pendingReindexedIndexes.

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

◆ relationHasPrimaryKey()

static bool relationHasPrimaryKey ( Relation  rel)
static

Definition at line 149 of file index.c.

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

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

Referenced by index_check_primary_key().

◆ RemoveReindexPending()

static void RemoveReindexPending ( Oid  indexOid)
static

Definition at line 4201 of file index.c.

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

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

Referenced by reindex_relation(), and SetReindexProcessing().

◆ ResetReindexProcessing()

static void ResetReindexProcessing ( void  )
static

Definition at line 4171 of file index.c.

4172{
4175 /* reindexingNestLevel remains set till end of (sub)transaction */
4176}

References currentlyReindexedHeap, currentlyReindexedIndex, and InvalidOid.

Referenced by IndexCheckExclusion(), and reindex_index().

◆ ResetReindexState()

void ResetReindexState ( int  nestLevel)

Definition at line 4214 of file index.c.

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

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

Referenced by AbortSubTransaction(), and AbortTransaction().

◆ RestoreReindexState()

void RestoreReindexState ( const void reindexstate)

Definition at line 4272 of file index.c.

4273{
4275 int c = 0;
4276 MemoryContext oldcontext;
4277
4278 currentlyReindexedHeap = sistate->currentlyReindexedHeap;
4279 currentlyReindexedIndex = sistate->currentlyReindexedIndex;
4280
4283 for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4286 sistate->pendingReindexedIndexes[c]);
4287 MemoryContextSwitchTo(oldcontext);
4288
4289 /* Note the worker has its own transaction nesting level */
4291}
MemoryContext TopMemoryContext
Definition mcxt.c:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
char * c
int GetCurrentTransactionNestLevel(void)
Definition xact.c:931

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

Referenced by ParallelWorkerMain().

◆ SerializeReindexState()

void SerializeReindexState ( Size  maxsize,
char start_address 
)

Definition at line 4254 of file index.c.

4255{
4257 int c = 0;
4258 ListCell *lc;
4259
4260 sistate->currentlyReindexedHeap = currentlyReindexedHeap;
4261 sistate->currentlyReindexedIndex = currentlyReindexedIndex;
4262 sistate->numPendingReindexedIndexes = list_length(pendingReindexedIndexes);
4263 foreach(lc, pendingReindexedIndexes)
4264 sistate->pendingReindexedIndexes[c++] = lfirst_oid(lc);
4265}

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

Referenced by InitializeParallelDSM().

◆ SetReindexPending()

static void SetReindexPending ( List indexes)
static

Definition at line 4185 of file index.c.

4186{
4187 /* Reindexing is not re-entrant. */
4189 elog(ERROR, "cannot reindex while reindexing");
4190 if (IsInParallelMode())
4191 elog(ERROR, "cannot modify reindex state during a parallel operation");
4194}
List * list_copy(const List *oldlist)
Definition list.c:1573

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

Referenced by reindex_relation().

◆ SetReindexProcessing()

static void SetReindexProcessing ( Oid  heapOid,
Oid  indexOid 
)
static

Definition at line 4152 of file index.c.

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

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

Referenced by reindex_index().

◆ UpdateIndexRelation()

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

Definition at line 564 of file index.c.

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

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

Referenced by index_create().

◆ validate_index()

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

Definition at line 3351 of file index.c.

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

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

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ validate_index_callback()

static bool validate_index_callback ( ItemPointer  itemptr,
void opaque 
)
static

Definition at line 3484 of file index.c.

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

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

Referenced by validate_index().

Variable Documentation

◆ binary_upgrade_next_index_pg_class_oid

Oid binary_upgrade_next_index_pg_class_oid = InvalidOid

Definition at line 86 of file index.c.

Referenced by binary_upgrade_set_next_index_pg_class_oid(), and index_create().

◆ binary_upgrade_next_index_pg_class_relfilenumber

RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber

◆ currentlyReindexedHeap

◆ currentlyReindexedIndex

◆ pendingReindexedIndexes

◆ reindexingNestLevel

int reindexingNestLevel = 0
static