PostgreSQL Source Code git master
relcache.h File Reference
#include "access/tupdesc.h"
#include "common/relpath.h"
#include "nodes/bitmapset.h"
Include dependency graph for relcache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define RELCACHE_INIT_FILENAME   "pg_internal.init"
 
#define AssertPendingSyncs_RelationCache()   do {} while (0)
 

Typedefs

typedef struct RelationDataRelation
 
typedef RelationRelationPtr
 
typedef enum IndexAttrBitmapKind IndexAttrBitmapKind
 

Enumerations

enum  IndexAttrBitmapKind {
  INDEX_ATTR_BITMAP_KEY , INDEX_ATTR_BITMAP_PRIMARY_KEY , INDEX_ATTR_BITMAP_IDENTITY_KEY , INDEX_ATTR_BITMAP_HOT_BLOCKING ,
  INDEX_ATTR_BITMAP_SUMMARIZED
}
 

Functions

static void AssertCouldGetRelation (void)
 
Relation RelationIdGetRelation (Oid relationId)
 
void RelationClose (Relation relation)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation, bool deferrable_ok)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetDummyIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (Relation relation)
 
bytea ** RelationGetIndexAttOptions (Relation relation, bool copy)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
BitmapsetRelationGetIdentityKeyBitmap (Relation relation)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
void RelationInitIndexAccessInfo (Relation relation)
 
void RelationBuildPublicationDesc (Relation relation, struct PublicationDesc *pubdesc)
 
void RelationInitTableAccessMethod (Relation relation)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
void RelationCacheInitialize (void)
 
void RelationCacheInitializePhase2 (void)
 
void RelationCacheInitializePhase3 (void)
 
Relation RelationBuildLocalRelation (const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid accessmtd, RelFileNumber relfilenumber, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenumber (Relation relation, char persistence)
 
void RelationAssumeNewRelfilelocator (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (bool debug_discard)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
bool RelationIdIsInInitFile (Oid relationId)
 
void RelationCacheInitFilePreInvalidate (void)
 
void RelationCacheInitFilePostInvalidate (void)
 
void RelationCacheInitFileRemove (void)
 

Variables

PGDLLIMPORT bool criticalRelcachesBuilt
 
PGDLLIMPORT bool criticalSharedRelcachesBuilt
 

Macro Definition Documentation

◆ AssertPendingSyncs_RelationCache

#define AssertPendingSyncs_RelationCache ( )    do {} while (0)

Definition at line 143 of file relcache.h.

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Definition at line 25 of file relcache.h.

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

typedef struct RelationData* Relation

Definition at line 27 of file relcache.h.

◆ RelationPtr

Definition at line 35 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 
INDEX_ATTR_BITMAP_HOT_BLOCKING 
INDEX_ATTR_BITMAP_SUMMARIZED 

Definition at line 67 of file relcache.h.

68{
IndexAttrBitmapKind
Definition: relcache.h:68
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:69
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:72
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:70
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:73
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:71

Function Documentation

◆ AssertCouldGetRelation()

◆ AtEOSubXact_RelationCache()

void AtEOSubXact_RelationCache ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 3378 of file relcache.c.

3380{
3381 HASH_SEQ_STATUS status;
3382 RelIdCacheEnt *idhentry;
3383 int i;
3384
3385 /*
3386 * Forget in_progress_list. This is relevant when we're aborting due to
3387 * an error during RelationBuildDesc(). We don't commit subtransactions
3388 * during RelationBuildDesc().
3389 */
3390 Assert(in_progress_list_len == 0 || !isCommit);
3392
3393 /*
3394 * Unless the eoxact_list[] overflowed, we only need to examine the rels
3395 * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3396 * logic as in AtEOXact_RelationCache.
3397 */
3399 {
3401 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3402 {
3403 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3404 mySubid, parentSubid);
3405 }
3406 }
3407 else
3408 {
3409 for (i = 0; i < eoxact_list_len; i++)
3410 {
3412 &eoxact_list[i],
3413 HASH_FIND,
3414 NULL);
3415 if (idhentry != NULL)
3416 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3417 mySubid, parentSubid);
3418 }
3419 }
3420
3421 /* Don't reset the list; we still need more cleanup later */
3422}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:956
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1421
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1386
Assert(PointerIsAligned(start, uint64))
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:77
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3433
static int eoxact_list_len
Definition: relcache.c:186
static bool eoxact_list_overflowed
Definition: relcache.c:187
static HTAB * RelationIdCache
Definition: relcache.c:134
Relation reldesc
Definition: relcache.c:131

References Assert(), AtEOSubXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, RelationIdCache, and relidcacheent::reldesc.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3226 of file relcache.c.

3227{
3228 HASH_SEQ_STATUS status;
3229 RelIdCacheEnt *idhentry;
3230 int i;
3231
3232 /*
3233 * Forget in_progress_list. This is relevant when we're aborting due to
3234 * an error during RelationBuildDesc().
3235 */
3236 Assert(in_progress_list_len == 0 || !isCommit);
3238
3239 /*
3240 * Unless the eoxact_list[] overflowed, we only need to examine the rels
3241 * listed in it. Otherwise fall back on a hash_seq_search scan.
3242 *
3243 * For simplicity, eoxact_list[] entries are not deleted till end of
3244 * top-level transaction, even though we could remove them at
3245 * subtransaction end in some cases, or remove relations from the list if
3246 * they are cleared for other reasons. Therefore we should expect the
3247 * case that list entries are not found in the hashtable; if not, there's
3248 * nothing to do for them.
3249 */
3251 {
3253 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3254 {
3255 AtEOXact_cleanup(idhentry->reldesc, isCommit);
3256 }
3257 }
3258 else
3259 {
3260 for (i = 0; i < eoxact_list_len; i++)
3261 {
3263 &eoxact_list[i],
3264 HASH_FIND,
3265 NULL);
3266 if (idhentry != NULL)
3267 AtEOXact_cleanup(idhentry->reldesc, isCommit);
3268 }
3269 }
3270
3272 {
3274 for (i = 0; i < NextEOXactTupleDescNum; i++)
3277 EOXactTupleDescArray = NULL;
3278 }
3279
3280 /* Now we're out of the transaction and can clear the lists */
3281 eoxact_list_len = 0;
3282 eoxact_list_overflowed = false;
3285}
void pfree(void *pointer)
Definition: mcxt.c:2152
static int NextEOXactTupleDescNum
Definition: relcache.c:203
static int EOXactTupleDescArrayLen
Definition: relcache.c:204
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3296
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495

References Assert(), AtEOXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, EOXactTupleDescArray, EOXactTupleDescArrayLen, FreeTupleDesc(), HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, NextEOXactTupleDescNum, pfree(), RelationIdCache, and relidcacheent::reldesc.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 6046 of file relcache.c.

6047{
6051
6052 return 0; /* return value does not matter */
6053}
int err_generic_string(int field, const char *str)
Definition: elog.c:1534
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3506
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:60
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:61
#define RelationGetRelationName(relation)
Definition: rel.h:550
#define RelationGetNamespace(relation)
Definition: rel.h:557

References err_generic_string(), get_namespace_name(), PG_DIAG_SCHEMA_NAME, PG_DIAG_TABLE_NAME, RelationGetNamespace, and RelationGetRelationName.

Referenced by ATPrepChangePersistence(), ATRewriteTable(), BuildRelationExtStatistics(), check_default_partition_contents(), errtablecolname(), errtableconstraint(), ExecFindPartition(), and ExecPartitionCheckEmitError().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 6063 of file relcache.c.

6064{
6065 TupleDesc reldesc = RelationGetDescr(rel);
6066 const char *colname;
6067
6068 /* Use reldesc if it's a user attribute, else consult the catalogs */
6069 if (attnum > 0 && attnum <= reldesc->natts)
6070 colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
6071 else
6072 colname = get_attname(RelationGetRelid(rel), attnum, false);
6073
6074 return errtablecolname(rel, colname);
6075}
#define NameStr(name)
Definition: c.h:717
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:919
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetRelid(relation)
Definition: rel.h:516
#define RelationGetDescr(relation)
Definition: rel.h:542
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:6087
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References attname, attnum, errtablecolname(), get_attname(), NameStr, RelationGetDescr, RelationGetRelid, and TupleDescAttr().

Referenced by ATRewriteTable(), ReportNotNullViolationError(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 6087 of file relcache.c.

6088{
6089 errtable(rel);
6091
6092 return 0; /* return value does not matter */
6093}
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:62
int errtable(Relation rel)
Definition: relcache.c:6046

References err_generic_string(), errtable(), and PG_DIAG_COLUMN_NAME.

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3976 of file relcache.c.

3977{
3981
3982 /* Flag relation as needing eoxact cleanup (to clear these fields) */
3983 EOXactListAdd(relation);
3984}
#define InvalidSubTransactionId
Definition: c.h:629
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilelocatorSubid, and RelationData::rd_newRelfilelocatorSubid.

Referenced by ATExecSetTableSpace(), reindex_index(), RelationSetNewRelfilenumber(), and swap_relation_files().

◆ RelationBuildLocalRelation()

Relation RelationBuildLocalRelation ( const char *  relname,
Oid  relnamespace,
TupleDesc  tupDesc,
Oid  relid,
Oid  accessmtd,
RelFileNumber  relfilenumber,
Oid  reltablespace,
bool  shared_relation,
bool  mapped_relation,
char  relpersistence,
char  relkind 
)

Definition at line 3515 of file relcache.c.

3526{
3527 Relation rel;
3528 MemoryContext oldcxt;
3529 int natts = tupDesc->natts;
3530 int i;
3531 bool has_not_null;
3532 bool nailit;
3533
3534 Assert(natts >= 0);
3535
3536 /*
3537 * check for creation of a rel that must be nailed in cache.
3538 *
3539 * XXX this list had better match the relations specially handled in
3540 * RelationCacheInitializePhase2/3.
3541 */
3542 switch (relid)
3543 {
3544 case DatabaseRelationId:
3545 case AuthIdRelationId:
3546 case AuthMemRelationId:
3547 case RelationRelationId:
3548 case AttributeRelationId:
3549 case ProcedureRelationId:
3550 case TypeRelationId:
3551 nailit = true;
3552 break;
3553 default:
3554 nailit = false;
3555 break;
3556 }
3557
3558 /*
3559 * check that hardwired list of shared rels matches what's in the
3560 * bootstrap .bki file. If you get a failure here during initdb, you
3561 * probably need to fix IsSharedRelation() to match whatever you've done
3562 * to the set of shared relations.
3563 */
3564 if (shared_relation != IsSharedRelation(relid))
3565 elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3566 relname, relid);
3567
3568 /* Shared relations had better be mapped, too */
3569 Assert(mapped_relation || !shared_relation);
3570
3571 /*
3572 * switch to the cache context to create the relcache entry.
3573 */
3574 if (!CacheMemoryContext)
3576
3578
3579 /*
3580 * allocate a new relation descriptor and fill in basic state fields.
3581 */
3582 rel = (Relation) palloc0(sizeof(RelationData));
3583
3584 /* make sure relation is marked as having no open file yet */
3585 rel->rd_smgr = NULL;
3586
3587 /* mark it nailed if appropriate */
3588 rel->rd_isnailed = nailit;
3589
3590 rel->rd_refcnt = nailit ? 1 : 0;
3591
3592 /* it's being created in this transaction */
3597
3598 /*
3599 * create a new tuple descriptor from the one passed in. We do this
3600 * partly to copy it into the cache context, and partly because the new
3601 * relation can't have any defaults or constraints yet; they have to be
3602 * added in later steps, because they require additions to multiple system
3603 * catalogs. We can copy attnotnull constraints here, however.
3604 */
3605 rel->rd_att = CreateTupleDescCopy(tupDesc);
3606 rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3607 has_not_null = false;
3608 for (i = 0; i < natts; i++)
3609 {
3610 Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3612
3613 datt->attidentity = satt->attidentity;
3614 datt->attgenerated = satt->attgenerated;
3615 datt->attnotnull = satt->attnotnull;
3616 has_not_null |= satt->attnotnull;
3618
3619 if (satt->attnotnull)
3620 {
3621 CompactAttribute *scatt = TupleDescCompactAttr(tupDesc, i);
3623
3624 dcatt->attnullability = scatt->attnullability;
3625 }
3626 }
3627
3628 if (has_not_null)
3629 {
3630 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3631
3632 constr->has_not_null = true;
3633 rel->rd_att->constr = constr;
3634 }
3635
3636 /*
3637 * initialize relation tuple form (caller may add/override data later)
3638 */
3640
3641 namestrcpy(&rel->rd_rel->relname, relname);
3642 rel->rd_rel->relnamespace = relnamespace;
3643
3644 rel->rd_rel->relkind = relkind;
3645 rel->rd_rel->relnatts = natts;
3646 rel->rd_rel->reltype = InvalidOid;
3647 /* needed when bootstrapping: */
3648 rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3649
3650 /* set up persistence and relcache fields dependent on it */
3651 rel->rd_rel->relpersistence = relpersistence;
3652 switch (relpersistence)
3653 {
3654 case RELPERSISTENCE_UNLOGGED:
3655 case RELPERSISTENCE_PERMANENT:
3657 rel->rd_islocaltemp = false;
3658 break;
3659 case RELPERSISTENCE_TEMP:
3660 Assert(isTempOrTempToastNamespace(relnamespace));
3662 rel->rd_islocaltemp = true;
3663 break;
3664 default:
3665 elog(ERROR, "invalid relpersistence: %c", relpersistence);
3666 break;
3667 }
3668
3669 /* if it's a materialized view, it's not populated initially */
3670 if (relkind == RELKIND_MATVIEW)
3671 rel->rd_rel->relispopulated = false;
3672 else
3673 rel->rd_rel->relispopulated = true;
3674
3675 /* set replica identity -- system catalogs and non-tables don't have one */
3676 if (!IsCatalogNamespace(relnamespace) &&
3677 (relkind == RELKIND_RELATION ||
3678 relkind == RELKIND_MATVIEW ||
3679 relkind == RELKIND_PARTITIONED_TABLE))
3680 rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3681 else
3682 rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3683
3684 /*
3685 * Insert relation physical and logical identifiers (OIDs) into the right
3686 * places. For a mapped relation, we set relfilenumber to zero and rely
3687 * on RelationInitPhysicalAddr to consult the map.
3688 */
3689 rel->rd_rel->relisshared = shared_relation;
3690
3691 RelationGetRelid(rel) = relid;
3692
3693 for (i = 0; i < natts; i++)
3694 TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3695
3696 rel->rd_rel->reltablespace = reltablespace;
3697
3698 if (mapped_relation)
3699 {
3700 rel->rd_rel->relfilenode = InvalidRelFileNumber;
3701 /* Add it to the active mapping information */
3702 RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3703 }
3704 else
3705 rel->rd_rel->relfilenode = relfilenumber;
3706
3707 RelationInitLockInfo(rel); /* see lmgr.c */
3708
3710
3711 rel->rd_rel->relam = accessmtd;
3712
3713 /*
3714 * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3715 * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3716 * require a long-lived current context.
3717 */
3718 MemoryContextSwitchTo(oldcxt);
3719
3720 if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3722
3723 /*
3724 * Leave index access method uninitialized, because the pg_index row has
3725 * not been inserted at this stage of index creation yet. The cache
3726 * invalidation after pg_index row has been inserted will initialize it.
3727 */
3728
3729 /*
3730 * Okay to insert into the relcache hash table.
3731 *
3732 * Ordinarily, there should certainly not be an existing hash entry for
3733 * the same OID; but during bootstrap, when we create a "real" relcache
3734 * entry for one of the bootstrap relations, we'll be overwriting the
3735 * phony one created with formrdesc. So allow that to happen for nailed
3736 * rels.
3737 */
3738 RelationCacheInsert(rel, nailit);
3739
3740 /*
3741 * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3742 * can't do this before storing relid in it.
3743 */
3744 EOXactListAdd(rel);
3745
3746 /* It's fully valid */
3747 rel->rd_isvalid = true;
3748
3749 /*
3750 * Caller expects us to pin the returned entry.
3751 */
3753
3754 return rel;
3755}
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:243
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:304
void CreateCacheMemoryContext(void)
Definition: catcache.c:708
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:70
void * palloc0(Size size)
Definition: mcxt.c:1975
MemoryContext CacheMemoryContext
Definition: mcxt.c:168
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:148
#define InvalidOid
Definition: postgres_ext.h:35
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
#define ProcNumberForTempRelations()
Definition: procnumber.h:53
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:209
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2187
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1829
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1339
struct RelationData * Relation
Definition: relcache.h:27
void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared, bool immediate)
Definition: relmapper.c:325
#define InvalidRelFileNumber
Definition: relpath.h:26
char attnullability
Definition: tupdesc.h:79
ProcNumber rd_backend
Definition: rel.h:60
int rd_refcnt
Definition: rel.h:59
bool rd_isvalid
Definition: rel.h:63
bool rd_islocaltemp
Definition: rel.h:61
TupleDesc rd_att
Definition: rel.h:112
bool rd_isnailed
Definition: rel.h:62
SMgrRelation rd_smgr
Definition: rel.h:58
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_droppedSubid
Definition: rel.h:109
Form_pg_class rd_rel
Definition: rel.h:111
bool has_not_null
Definition: tupdesc.h:45
int tdrefcount
Definition: tupdesc.h:140
TupleConstr * constr
Definition: tupdesc.h:141
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:117
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175

References Assert(), CompactAttribute::attnullability, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), populate_compact_attribute(), ProcNumberForTempRelations, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationMapUpdateMap(), relname, TupleDescData::tdrefcount, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
struct PublicationDesc pubdesc 
)

Definition at line 5791 of file relcache.c.

5792{
5793 List *puboids;
5794 ListCell *lc;
5795 MemoryContext oldcxt;
5796 Oid schemaid;
5797 List *ancestors = NIL;
5798 Oid relid = RelationGetRelid(relation);
5799
5800 /*
5801 * If not publishable, it publishes no actions. (pgoutput_change() will
5802 * ignore it.)
5803 */
5804 if (!is_publishable_relation(relation))
5805 {
5806 memset(pubdesc, 0, sizeof(PublicationDesc));
5807 pubdesc->rf_valid_for_update = true;
5808 pubdesc->rf_valid_for_delete = true;
5809 pubdesc->cols_valid_for_update = true;
5810 pubdesc->cols_valid_for_delete = true;
5811 pubdesc->gencols_valid_for_update = true;
5812 pubdesc->gencols_valid_for_delete = true;
5813 return;
5814 }
5815
5816 if (relation->rd_pubdesc)
5817 {
5818 memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5819 return;
5820 }
5821
5822 memset(pubdesc, 0, sizeof(PublicationDesc));
5823 pubdesc->rf_valid_for_update = true;
5824 pubdesc->rf_valid_for_delete = true;
5825 pubdesc->cols_valid_for_update = true;
5826 pubdesc->cols_valid_for_delete = true;
5827 pubdesc->gencols_valid_for_update = true;
5828 pubdesc->gencols_valid_for_delete = true;
5829
5830 /* Fetch the publication membership info. */
5831 puboids = GetRelationPublications(relid);
5832 schemaid = RelationGetNamespace(relation);
5833 puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5834
5835 if (relation->rd_rel->relispartition)
5836 {
5837 /* Add publications that the ancestors are in too. */
5838 ancestors = get_partition_ancestors(relid);
5839
5840 foreach(lc, ancestors)
5841 {
5842 Oid ancestor = lfirst_oid(lc);
5843
5844 puboids = list_concat_unique_oid(puboids,
5845 GetRelationPublications(ancestor));
5846 schemaid = get_rel_namespace(ancestor);
5847 puboids = list_concat_unique_oid(puboids,
5848 GetSchemaPublications(schemaid));
5849 }
5850 }
5852
5853 foreach(lc, puboids)
5854 {
5855 Oid pubid = lfirst_oid(lc);
5856 HeapTuple tup;
5857 Form_pg_publication pubform;
5858 bool invalid_column_list;
5859 bool invalid_gen_col;
5860
5861 tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5862
5863 if (!HeapTupleIsValid(tup))
5864 elog(ERROR, "cache lookup failed for publication %u", pubid);
5865
5866 pubform = (Form_pg_publication) GETSTRUCT(tup);
5867
5868 pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5869 pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5870 pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5871 pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5872
5873 /*
5874 * Check if all columns referenced in the filter expression are part
5875 * of the REPLICA IDENTITY index or not.
5876 *
5877 * If the publication is FOR ALL TABLES then it means the table has no
5878 * row filters and we can skip the validation.
5879 */
5880 if (!pubform->puballtables &&
5881 (pubform->pubupdate || pubform->pubdelete) &&
5882 pub_rf_contains_invalid_column(pubid, relation, ancestors,
5883 pubform->pubviaroot))
5884 {
5885 if (pubform->pubupdate)
5886 pubdesc->rf_valid_for_update = false;
5887 if (pubform->pubdelete)
5888 pubdesc->rf_valid_for_delete = false;
5889 }
5890
5891 /*
5892 * Check if all columns are part of the REPLICA IDENTITY index or not.
5893 *
5894 * Check if all generated columns included in the REPLICA IDENTITY are
5895 * published.
5896 */
5897 if ((pubform->pubupdate || pubform->pubdelete) &&
5898 pub_contains_invalid_column(pubid, relation, ancestors,
5899 pubform->pubviaroot,
5900 pubform->pubgencols,
5901 &invalid_column_list,
5902 &invalid_gen_col))
5903 {
5904 if (pubform->pubupdate)
5905 {
5906 pubdesc->cols_valid_for_update = !invalid_column_list;
5907 pubdesc->gencols_valid_for_update = !invalid_gen_col;
5908 }
5909
5910 if (pubform->pubdelete)
5911 {
5912 pubdesc->cols_valid_for_delete = !invalid_column_list;
5913 pubdesc->gencols_valid_for_delete = !invalid_gen_col;
5914 }
5915 }
5916
5917 ReleaseSysCache(tup);
5918
5919 /*
5920 * If we know everything is replicated and the row filter is invalid
5921 * for update and delete, there is no point to check for other
5922 * publications.
5923 */
5924 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5925 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5926 !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5927 break;
5928
5929 /*
5930 * If we know everything is replicated and the column list is invalid
5931 * for update and delete, there is no point to check for other
5932 * publications.
5933 */
5934 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5935 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5936 !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5937 break;
5938
5939 /*
5940 * If we know everything is replicated and replica identity has an
5941 * unpublished generated column, there is no point to check for other
5942 * publications.
5943 */
5944 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5945 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5946 !pubdesc->gencols_valid_for_update &&
5947 !pubdesc->gencols_valid_for_delete)
5948 break;
5949 }
5950
5951 if (relation->rd_pubdesc)
5952 {
5953 pfree(relation->rd_pubdesc);
5954 relation->rd_pubdesc = NULL;
5955 }
5956
5957 /* Now save copy of the descriptor in the relcache entry. */
5959 relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5960 memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5961 MemoryContextSwitchTo(oldcxt);
5962}
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2092
void * palloc(Size size)
Definition: mcxt.c:1945
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
List * GetSchemaPublications(Oid schemaid)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:30
bool pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot, char pubgencols_type, bool *invalid_column_list, bool *invalid_gen_col)
bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
Definition: pg_list.h:54
PublicationActions pubactions
bool gencols_valid_for_update
bool gencols_valid_for_delete
PublicationDesc * rd_pubdesc
Definition: rel.h:168
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References CacheMemoryContext, PublicationDesc::cols_valid_for_delete, PublicationDesc::cols_valid_for_update, elog, ERROR, PublicationDesc::gencols_valid_for_delete, PublicationDesc::gencols_valid_for_update, get_partition_ancestors(), get_rel_namespace(), GetAllTablesPublications(), GetRelationPublications(), GetSchemaPublications(), GETSTRUCT(), HeapTupleIsValid, is_publishable_relation(), lfirst_oid, list_concat_unique_oid(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), palloc(), pfree(), pub_contains_invalid_column(), pub_rf_contains_invalid_column(), PublicationDesc::pubactions, PublicationActions::pubdelete, PublicationActions::pubinsert, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubdesc, RelationData::rd_rel, RelationGetNamespace, RelationGetRelid, ReleaseSysCache(), PublicationDesc::rf_valid_for_delete, PublicationDesc::rf_valid_for_update, and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6882 of file relcache.c.

6883{
6884 LWLockRelease(RelCacheInitLock);
6885}
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1902

References LWLockRelease().

Referenced by AtEOXact_Inval(), AtInplace_Inval(), FinishPreparedTransaction(), and ProcessCommittedInvalidationMessages().

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6857 of file relcache.c.

6858{
6859 char localinitfname[MAXPGPATH];
6860 char sharedinitfname[MAXPGPATH];
6861
6862 if (DatabasePath)
6863 snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6865 snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6867
6868 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6869
6870 /*
6871 * The files might not be there if no backend has been started since the
6872 * last removal. But complain about failures other than ENOENT with
6873 * ERROR. Fortunately, it's not too late to abort the transaction if we
6874 * can't get rid of the would-be-obsolete init file.
6875 */
6876 if (DatabasePath)
6877 unlink_initfile(localinitfname, ERROR);
6878 unlink_initfile(sharedinitfname, ERROR);
6879}
char * DatabasePath
Definition: globals.c:105
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1182
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define MAXPGPATH
#define snprintf
Definition: port.h:239
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6954
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25

References DatabasePath, ERROR, LW_EXCLUSIVE, LWLockAcquire(), MAXPGPATH, RELCACHE_INIT_FILENAME, snprintf, and unlink_initfile().

Referenced by AtEOXact_Inval(), FinishPreparedTransaction(), PreInplace_Inval(), and ProcessCommittedInvalidationMessages().

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6897 of file relcache.c.

6898{
6899 const char *tblspcdir = PG_TBLSPC_DIR;
6900 DIR *dir;
6901 struct dirent *de;
6902 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6903
6904 snprintf(path, sizeof(path), "global/%s",
6906 unlink_initfile(path, LOG);
6907
6908 /* Scan everything in the default tablespace */
6910
6911 /* Scan the tablespace link directory to find non-default tablespaces */
6912 dir = AllocateDir(tblspcdir);
6913
6914 while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6915 {
6916 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6917 {
6918 /* Scan the tablespace dir for per-database dirs */
6919 snprintf(path, sizeof(path), "%s/%s/%s",
6920 tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6922 }
6923 }
6924
6925 FreeDir(dir);
6926}
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:3025
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2988
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2907
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6930
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), dirent::d_name, FreeDir(), LOG, MAXPGPATH, PG_TBLSPC_DIR, ReadDirExtended(), RelationCacheInitFileRemoveInDir(), RELCACHE_INIT_FILENAME, snprintf, TABLESPACE_VERSION_DIRECTORY, and unlink_initfile().

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 4002 of file relcache.c.

4003{
4004 HASHCTL ctl;
4005 int allocsize;
4006
4007 /*
4008 * make sure cache memory context exists
4009 */
4010 if (!CacheMemoryContext)
4012
4013 /*
4014 * create hashtable that indexes the relcache
4015 */
4016 ctl.keysize = sizeof(Oid);
4017 ctl.entrysize = sizeof(RelIdCacheEnt);
4018 RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4020
4021 /*
4022 * reserve enough in_progress_list slots for many cases
4023 */
4024 allocsize = 4;
4027 allocsize * sizeof(*in_progress_list));
4028 in_progress_list_maxlen = allocsize;
4029
4030 /*
4031 * relation mapper needs to be initialized too
4032 */
4034}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1260
tree ctl
Definition: radixtree.h:1838
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3999
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:170
void RelationMapInitialize(void)
Definition: relmapper.c:651

References CacheMemoryContext, CreateCacheMemoryContext(), ctl, HASH_BLOBS, hash_create(), HASH_ELEM, in_progress_list, in_progress_list_maxlen, INITRELCACHESIZE, MemoryContextAlloc(), RelationIdCache, and RelationMapInitialize().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 4048 of file relcache.c.

4049{
4050 MemoryContext oldcxt;
4051
4052 /*
4053 * relation mapper needs initialized too
4054 */
4056
4057 /*
4058 * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4059 * nothing.
4060 */
4062 return;
4063
4064 /*
4065 * switch to cache memory context
4066 */
4068
4069 /*
4070 * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4071 * the cache with pre-made descriptors for the critical shared catalogs.
4072 */
4073 if (!load_relcache_init_file(true))
4074 {
4075 formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4076 Natts_pg_database, Desc_pg_database);
4077 formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4078 Natts_pg_authid, Desc_pg_authid);
4079 formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4080 Natts_pg_auth_members, Desc_pg_auth_members);
4081 formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4082 Natts_pg_shseclabel, Desc_pg_shseclabel);
4083 formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4084 Natts_pg_subscription, Desc_pg_subscription);
4085
4086#define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4087 }
4088
4089 MemoryContextSwitchTo(oldcxt);
4090}
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:477
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6164
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:119
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1894
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:120
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:117
void RelationMapInitializePhase2(void)
Definition: relmapper.c:671

References CacheMemoryContext, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, Desc_pg_shseclabel, Desc_pg_subscription, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), and RelationMapInitializePhase2().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 4107 of file relcache.c.

4108{
4109 HASH_SEQ_STATUS status;
4110 RelIdCacheEnt *idhentry;
4111 MemoryContext oldcxt;
4112 bool needNewCacheFile = !criticalSharedRelcachesBuilt;
4113
4114 /*
4115 * relation mapper needs initialized too
4116 */
4118
4119 /*
4120 * switch to cache memory context
4121 */
4123
4124 /*
4125 * Try to load the local relcache cache file. If unsuccessful, bootstrap
4126 * the cache with pre-made descriptors for the critical "nailed-in" system
4127 * catalogs.
4128 */
4131 {
4132 needNewCacheFile = true;
4133
4134 formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4135 Natts_pg_class, Desc_pg_class);
4136 formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4137 Natts_pg_attribute, Desc_pg_attribute);
4138 formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4139 Natts_pg_proc, Desc_pg_proc);
4140 formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4141 Natts_pg_type, Desc_pg_type);
4142
4143#define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4144 }
4145
4146 MemoryContextSwitchTo(oldcxt);
4147
4148 /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4150 return;
4151
4152 /*
4153 * If we didn't get the critical system indexes loaded into relcache, do
4154 * so now. These are critical because the catcache and/or opclass cache
4155 * depend on them for fetches done during relcache load. Thus, we have an
4156 * infinite-recursion problem. We can break the recursion by doing
4157 * heapscans instead of indexscans at certain key spots. To avoid hobbling
4158 * performance, we only want to do that until we have the critical indexes
4159 * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4160 * decide whether to do heapscan or indexscan at the key spots, and we set
4161 * it true after we've loaded the critical indexes.
4162 *
4163 * The critical indexes are marked as "nailed in cache", partly to make it
4164 * easy for load_relcache_init_file to count them, but mainly because we
4165 * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4166 * true. (NOTE: perhaps it would be possible to reload them by
4167 * temporarily setting criticalRelcachesBuilt to false again. For now,
4168 * though, we just nail 'em in.)
4169 *
4170 * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4171 * in the same way as the others, because the critical catalogs don't
4172 * (currently) have any rules or triggers, and so these indexes can be
4173 * rebuilt without inducing recursion. However they are used during
4174 * relcache load when a rel does have rules or triggers, so we choose to
4175 * nail them for performance reasons.
4176 */
4178 {
4179 load_critical_index(ClassOidIndexId,
4180 RelationRelationId);
4181 load_critical_index(AttributeRelidNumIndexId,
4182 AttributeRelationId);
4183 load_critical_index(IndexRelidIndexId,
4184 IndexRelationId);
4185 load_critical_index(OpclassOidIndexId,
4186 OperatorClassRelationId);
4187 load_critical_index(AccessMethodProcedureIndexId,
4188 AccessMethodProcedureRelationId);
4189 load_critical_index(RewriteRelRulenameIndexId,
4190 RewriteRelationId);
4191 load_critical_index(TriggerRelidNameIndexId,
4192 TriggerRelationId);
4193
4194#define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4195
4197 }
4198
4199 /*
4200 * Process critical shared indexes too.
4201 *
4202 * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4203 * initial lookup of MyDatabaseId, without which we'll never find any
4204 * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4205 * database OID, so it instead depends on DatabaseOidIndexId. We also
4206 * need to nail up some indexes on pg_authid and pg_auth_members for use
4207 * during client authentication. SharedSecLabelObjectIndexId isn't
4208 * critical for the core system, but authentication hooks might be
4209 * interested in it.
4210 */
4212 {
4213 load_critical_index(DatabaseNameIndexId,
4214 DatabaseRelationId);
4215 load_critical_index(DatabaseOidIndexId,
4216 DatabaseRelationId);
4217 load_critical_index(AuthIdRolnameIndexId,
4218 AuthIdRelationId);
4219 load_critical_index(AuthIdOidIndexId,
4220 AuthIdRelationId);
4221 load_critical_index(AuthMemMemRoleIndexId,
4222 AuthMemRelationId);
4223 load_critical_index(SharedSecLabelObjectIndexId,
4224 SharedSecLabelRelationId);
4225
4226#define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4227
4229 }
4230
4231 /*
4232 * Now, scan all the relcache entries and update anything that might be
4233 * wrong in the results from formrdesc or the relcache cache file. If we
4234 * faked up relcache entries using formrdesc, then read the real pg_class
4235 * rows and replace the fake entries with them. Also, if any of the
4236 * relcache entries have rules, triggers, or security policies, load that
4237 * info the hard way since it isn't recorded in the cache file.
4238 *
4239 * Whenever we access the catalogs to read data, there is a possibility of
4240 * a shared-inval cache flush causing relcache entries to be removed.
4241 * Since hash_seq_search only guarantees to still work after the *current*
4242 * entry is removed, it's unsafe to continue the hashtable scan afterward.
4243 * We handle this by restarting the scan from scratch after each access.
4244 * This is theoretically O(N^2), but the number of entries that actually
4245 * need to be fixed is small enough that it doesn't matter.
4246 */
4248
4249 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4250 {
4251 Relation relation = idhentry->reldesc;
4252 bool restart = false;
4253
4254 /*
4255 * Make sure *this* entry doesn't get flushed while we work with it.
4256 */
4258
4259 /*
4260 * If it's a faked-up entry, read the real pg_class tuple.
4261 */
4262 if (relation->rd_rel->relowner == InvalidOid)
4263 {
4264 HeapTuple htup;
4265 Form_pg_class relp;
4266
4267 htup = SearchSysCache1(RELOID,
4269 if (!HeapTupleIsValid(htup))
4270 ereport(FATAL,
4271 errcode(ERRCODE_UNDEFINED_OBJECT),
4272 errmsg_internal("cache lookup failed for relation %u",
4273 RelationGetRelid(relation)));
4274 relp = (Form_pg_class) GETSTRUCT(htup);
4275
4276 /*
4277 * Copy tuple to relation->rd_rel. (See notes in
4278 * AllocateRelationDesc())
4279 */
4280 memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4281
4282 /* Update rd_options while we have the tuple */
4283 if (relation->rd_options)
4284 pfree(relation->rd_options);
4285 RelationParseRelOptions(relation, htup);
4286
4287 /*
4288 * Check the values in rd_att were set up correctly. (We cannot
4289 * just copy them over now: formrdesc must have set up the rd_att
4290 * data correctly to start with, because it may already have been
4291 * copied into one or more catcache entries.)
4292 */
4293 Assert(relation->rd_att->tdtypeid == relp->reltype);
4294 Assert(relation->rd_att->tdtypmod == -1);
4295
4296 ReleaseSysCache(htup);
4297
4298 /* relowner had better be OK now, else we'll loop forever */
4299 if (relation->rd_rel->relowner == InvalidOid)
4300 elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4301 RelationGetRelationName(relation));
4302
4303 restart = true;
4304 }
4305
4306 /*
4307 * Fix data that isn't saved in relcache cache file.
4308 *
4309 * relhasrules or relhastriggers could possibly be wrong or out of
4310 * date. If we don't actually find any rules or triggers, clear the
4311 * local copy of the flag so that we don't get into an infinite loop
4312 * here. We don't make any attempt to fix the pg_class entry, though.
4313 */
4314 if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4315 {
4316 RelationBuildRuleLock(relation);
4317 if (relation->rd_rules == NULL)
4318 relation->rd_rel->relhasrules = false;
4319 restart = true;
4320 }
4321 if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4322 {
4323 RelationBuildTriggers(relation);
4324 if (relation->trigdesc == NULL)
4325 relation->rd_rel->relhastriggers = false;
4326 restart = true;
4327 }
4328
4329 /*
4330 * Re-load the row security policies if the relation has them, since
4331 * they are not preserved in the cache. Note that we can never NOT
4332 * have a policy while relrowsecurity is true,
4333 * RelationBuildRowSecurity will create a single default-deny policy
4334 * if there is no policy defined in pg_policy.
4335 */
4336 if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4337 {
4338 RelationBuildRowSecurity(relation);
4339
4340 Assert(relation->rd_rsdesc != NULL);
4341 restart = true;
4342 }
4343
4344 /* Reload tableam data if needed */
4345 if (relation->rd_tableam == NULL &&
4346 (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4347 {
4349 Assert(relation->rd_tableam != NULL);
4350
4351 restart = true;
4352 }
4353
4354 /* Release hold on the relation */
4356
4357 /* Now, restart the hashtable scan if needed */
4358 if (restart)
4359 {
4360 hash_seq_term(&status);
4362 }
4363 }
4364
4365 /*
4366 * Lastly, write out new relcache cache files if needed. We don't bother
4367 * to distinguish cases where only one of the two needs an update.
4368 */
4369 if (needNewCacheFile)
4370 {
4371 /*
4372 * Force all the catcaches to finish initializing and thereby open the
4373 * catalogs and indexes they use. This will preload the relcache with
4374 * entries for all the most important system catalogs and indexes, so
4375 * that the init files will be most useful for future backends.
4376 */
4378
4379 /* now write the files */
4382 }
4383}
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1515
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1158
int errcode(int sqlerrcode)
Definition: elog.c:854
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:468
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2200
bool criticalRelcachesBuilt
Definition: relcache.c:140
bool criticalSharedRelcachesBuilt
Definition: relcache.c:146
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:752
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:113
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6582
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:114
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4392
void RelationMapInitializePhase3(void)
Definition: relmapper.c:692
const struct TableAmRoutine * rd_tableam
Definition: rel.h:189
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:119
TriggerDesc * trigdesc
Definition: rel.h:117
RuleLock * rd_rules
Definition: rel.h:115
bytea * rd_options
Definition: rel.h:175
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
void InitCatalogCachePhase2(void)
Definition: syscache.c:180
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1861

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ereport, errcode(), errmsg_internal(), ERROR, FATAL, formrdesc(), GETSTRUCT(), hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum(), pfree(), RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIdCache, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), SearchSysCache1(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2994 of file relcache.c.

2995{
2996 HASH_SEQ_STATUS status;
2997 RelIdCacheEnt *idhentry;
2998 Relation relation;
2999 List *rebuildFirstList = NIL;
3000 List *rebuildList = NIL;
3001 ListCell *l;
3002 int i;
3003
3004 /*
3005 * Reload relation mapping data before starting to reconstruct cache.
3006 */
3008
3009 /* Phase 1 */
3011
3012 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3013 {
3014 relation = idhentry->reldesc;
3015
3016 /*
3017 * Ignore new relations; no other backend will manipulate them before
3018 * we commit. Likewise, before replacing a relation's relfilelocator,
3019 * we shall have acquired AccessExclusiveLock and drained any
3020 * applicable pending invalidations.
3021 */
3022 if (relation->rd_createSubid != InvalidSubTransactionId ||
3024 continue;
3025
3027
3028 if (RelationHasReferenceCountZero(relation))
3029 {
3030 /* Delete this entry immediately */
3031 RelationClearRelation(relation);
3032 }
3033 else
3034 {
3035 /*
3036 * If it's a mapped relation, immediately update its rd_locator in
3037 * case its relfilenumber changed. We must do this during phase 1
3038 * in case the relation is consulted during rebuild of other
3039 * relcache entries in phase 2. It's safe since consulting the
3040 * map doesn't involve any access to relcache entries.
3041 */
3042 if (RelationIsMapped(relation))
3043 {
3044 RelationCloseSmgr(relation);
3045 RelationInitPhysicalAddr(relation);
3046 }
3047
3048 /*
3049 * Add this entry to list of stuff to rebuild in second pass.
3050 * pg_class goes to the front of rebuildFirstList while
3051 * pg_class_oid_index goes to the back of rebuildFirstList, so
3052 * they are done first and second respectively. Other nailed
3053 * relations go to the front of rebuildList, so they'll be done
3054 * next in no particular order; and everything else goes to the
3055 * back of rebuildList.
3056 */
3057 if (RelationGetRelid(relation) == RelationRelationId)
3058 rebuildFirstList = lcons(relation, rebuildFirstList);
3059 else if (RelationGetRelid(relation) == ClassOidIndexId)
3060 rebuildFirstList = lappend(rebuildFirstList, relation);
3061 else if (relation->rd_isnailed)
3062 rebuildList = lcons(relation, rebuildList);
3063 else
3064 rebuildList = lappend(rebuildList, relation);
3065 }
3066 }
3067
3068 /*
3069 * We cannot destroy the SMgrRelations as there might still be references
3070 * to them, but close the underlying file descriptors.
3071 */
3073
3074 /*
3075 * Phase 2: rebuild (or invalidate) the items found to need rebuild in
3076 * phase 1
3077 */
3078 foreach(l, rebuildFirstList)
3079 {
3080 relation = (Relation) lfirst(l);
3081 if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3083 else
3084 RelationRebuildRelation(relation);
3085 }
3086 list_free(rebuildFirstList);
3087 foreach(l, rebuildList)
3088 {
3089 relation = (Relation) lfirst(l);
3090 if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3092 else
3093 RelationRebuildRelation(relation);
3094 }
3095 list_free(rebuildList);
3096
3097 if (!debug_discard)
3098 /* Any RelationBuildDesc() on the stack must start over. */
3099 for (i = 0; i < in_progress_list_len; i++)
3100 in_progress_list[i].invalidated = true;
3101}
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lcons(void *datum, List *list)
Definition: list.c:495
void list_free(List *list)
Definition: list.c:1546
#define lfirst(lc)
Definition: pg_list.h:172
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:500
#define RelationIsMapped(relation)
Definition: rel.h:565
static void RelationCloseSmgr(Relation relation)
Definition: rel.h:593
static void RelationClearRelation(Relation relation)
Definition: relcache.c:2546
static void RelationRebuildRelation(Relation relation)
Definition: relcache.c:2585
static long relcacheInvalsReceived
Definition: relcache.c:154
static void RelationInvalidateRelation(Relation relation)
Definition: relcache.c:2518
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:412
bool IsTransactionState(void)
Definition: xact.c:387

References hash_seq_init(), hash_seq_search(), i, in_progress_list, in_progress_list_len, InvalidSubTransactionId, IsTransactionState(), lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationClearRelation(), RelationCloseSmgr(), RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationInvalidateRelation(), RelationIsMapped, RelationMapInvalidateAll(), RelationRebuildRelation(), relcacheInvalsReceived, relidcacheent::reldesc, and smgrreleaseall().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2938 of file relcache.c.

2939{
2940 Relation relation;
2941
2942 RelationIdCacheLookup(relationId, relation);
2943
2944 if (PointerIsValid(relation))
2945 {
2947 RelationFlushRelation(relation);
2948 }
2949 else
2950 {
2951 int i;
2952
2953 for (i = 0; i < in_progress_list_len; i++)
2954 if (in_progress_list[i].reloid == relationId)
2956 }
2957}
#define PointerIsValid(pointer)
Definition: c.h:734
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2827
bool invalidated
Definition: relcache.c:167

References i, in_progress_list, in_progress_list_len, inprogressent::invalidated, PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2220 of file relcache.c.

2221{
2222 /* Note: no locking manipulations needed */
2224
2225 RelationCloseCleanup(relation);
2226}
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2229

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

Referenced by index_close(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), pgoutput_row_filter_init(), relation_close(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), and ReorderBufferToastReplace().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2893 of file relcache.c.

2894{
2895 Relation relation;
2896
2897 RelationIdCacheLookup(rid, relation);
2898
2899 if (!PointerIsValid(relation))
2900 return; /* not in cache, nothing to do */
2901
2902 if (!RelationHasReferenceCountZero(relation))
2903 elog(ERROR, "relation %u is still open", rid);
2904
2906 if (relation->rd_createSubid != InvalidSubTransactionId ||
2908 {
2909 /*
2910 * In the event of subtransaction rollback, we must not forget
2911 * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2912 * destroying it right away. (If we're in a top transaction, we could
2913 * opt to destroy the entry.)
2914 */
2917 }
2918 else
2919 RelationClearRelation(relation);
2920}

References Assert(), elog, ERROR, GetCurrentSubTransactionId(), InvalidSubTransactionId, PointerIsValid, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationClearRelation(), RelationHasReferenceCountZero, RelationIdCacheLookup, and RelationInvalidateRelation().

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List * RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5153 of file relcache.c.

5154{
5155 List *result;
5156 Datum exprsDatum;
5157 bool isnull;
5158 char *exprsString;
5159 List *rawExprs;
5160 ListCell *lc;
5161
5162 /* Quick exit if there is nothing to do. */
5163 if (relation->rd_indextuple == NULL ||
5164 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5165 return NIL;
5166
5167 /* Extract raw node tree(s) from index tuple. */
5168 exprsDatum = heap_getattr(relation->rd_indextuple,
5169 Anum_pg_index_indexprs,
5171 &isnull);
5172 Assert(!isnull);
5173 exprsString = TextDatumGetCString(exprsDatum);
5174 rawExprs = (List *) stringToNode(exprsString);
5175 pfree(exprsString);
5176
5177 /* Construct null Consts; the typlen and typbyval are arbitrary. */
5178 result = NIL;
5179 foreach(lc, rawExprs)
5180 {
5181 Node *rawExpr = (Node *) lfirst(lc);
5182
5183 result = lappend(result,
5184 makeConst(exprType(rawExpr),
5185 exprTypmod(rawExpr),
5186 exprCollation(rawExpr),
5187 1,
5188 (Datum) 0,
5189 true,
5190 true));
5191 }
5192
5193 return result;
5194}
#define TextDatumGetCString(d)
Definition: builtins.h:98
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:350
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
uintptr_t Datum
Definition: postgres.h:69
void * stringToNode(const char *str)
Definition: read.c:90
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4473
Definition: nodes.h:135
struct HeapTupleData * rd_indextuple
Definition: rel.h:194

References Assert(), exprCollation(), exprType(), exprTypmod(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), lappend(), lfirst, makeConst(), NIL, pfree(), RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by BuildDummyIndexInfo().

◆ RelationGetExclusionInfo()

void RelationGetExclusionInfo ( Relation  indexRelation,
Oid **  operators,
Oid **  procs,
uint16 **  strategies 
)

Definition at line 5650 of file relcache.c.

5654{
5655 int indnkeyatts;
5656 Oid *ops;
5657 Oid *funcs;
5658 uint16 *strats;
5659 Relation conrel;
5660 SysScanDesc conscan;
5661 ScanKeyData skey[1];
5662 HeapTuple htup;
5663 bool found;
5664 MemoryContext oldcxt;
5665 int i;
5666
5667 indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5668
5669 /* Allocate result space in caller context */
5670 *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5671 *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5672 *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5673
5674 /* Quick exit if we have the data cached already */
5675 if (indexRelation->rd_exclstrats != NULL)
5676 {
5677 memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5678 memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5679 memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5680 return;
5681 }
5682
5683 /*
5684 * Search pg_constraint for the constraint associated with the index. To
5685 * make this not too painfully slow, we use the index on conrelid; that
5686 * will hold the parent relation's OID not the index's own OID.
5687 *
5688 * Note: if we wanted to rely on the constraint name matching the index's
5689 * name, we could just do a direct lookup using pg_constraint's unique
5690 * index. For the moment it doesn't seem worth requiring that.
5691 */
5692 ScanKeyInit(&skey[0],
5693 Anum_pg_constraint_conrelid,
5694 BTEqualStrategyNumber, F_OIDEQ,
5695 ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5696
5697 conrel = table_open(ConstraintRelationId, AccessShareLock);
5698 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5699 NULL, 1, skey);
5700 found = false;
5701
5702 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5703 {
5705 Datum val;
5706 bool isnull;
5707 ArrayType *arr;
5708 int nelem;
5709
5710 /* We want the exclusion constraint owning the index */
5711 if ((conform->contype != CONSTRAINT_EXCLUSION &&
5712 !(conform->conperiod && (conform->contype == CONSTRAINT_PRIMARY
5713 || conform->contype == CONSTRAINT_UNIQUE))) ||
5714 conform->conindid != RelationGetRelid(indexRelation))
5715 continue;
5716
5717 /* There should be only one */
5718 if (found)
5719 elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5720 RelationGetRelationName(indexRelation));
5721 found = true;
5722
5723 /* Extract the operator OIDS from conexclop */
5724 val = fastgetattr(htup,
5725 Anum_pg_constraint_conexclop,
5726 conrel->rd_att, &isnull);
5727 if (isnull)
5728 elog(ERROR, "null conexclop for rel %s",
5729 RelationGetRelationName(indexRelation));
5730
5731 arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5732 nelem = ARR_DIMS(arr)[0];
5733 if (ARR_NDIM(arr) != 1 ||
5734 nelem != indnkeyatts ||
5735 ARR_HASNULL(arr) ||
5736 ARR_ELEMTYPE(arr) != OIDOID)
5737 elog(ERROR, "conexclop is not a 1-D Oid array");
5738
5739 memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5740 }
5741
5742 systable_endscan(conscan);
5744
5745 if (!found)
5746 elog(ERROR, "exclusion constraint record missing for rel %s",
5747 RelationGetRelationName(indexRelation));
5748
5749 /* We need the func OIDs and strategy numbers too */
5750 for (i = 0; i < indnkeyatts; i++)
5751 {
5752 funcs[i] = get_opcode(ops[i]);
5753 strats[i] = get_op_opfamily_strategy(ops[i],
5754 indexRelation->rd_opfamily[i]);
5755 /* shouldn't fail, since it was checked at index creation */
5756 if (strats[i] == InvalidStrategy)
5757 elog(ERROR, "could not find strategy for operator %u in family %u",
5758 ops[i], indexRelation->rd_opfamily[i]);
5759 }
5760
5761 /* Save a copy of the results in the relcache entry. */
5762 oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5763 indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5764 indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5765 indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5766 memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5767 memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5768 memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5769 MemoryContextSwitchTo(oldcxt);
5770}
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
uint16_t uint16
Definition: c.h:501
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
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:861
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1425
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:84
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:535
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define InvalidStrategy
Definition: stratnum.h:24
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid * rd_exclprocs
Definition: rel.h:215
uint16 * rd_exclstrats
Definition: rel.h:216
Oid * rd_exclops
Definition: rel.h:214
Form_pg_index rd_index
Definition: rel.h:192
MemoryContext rd_indexcxt
Definition: rel.h:204
Oid * rd_opfamily
Definition: rel.h:207
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, DatumGetArrayTypeP, elog, ERROR, fastgetattr(), get_op_opfamily_strategy(), get_opcode(), GETSTRUCT(), HeapTupleIsValid, i, IndexRelationGetNumberOfKeyAttributes, InvalidStrategy, MemoryContextSwitchTo(), ObjectIdGetDatum(), palloc(), RelationData::rd_att, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_opfamily, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and val.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetFKeyList()

List * RelationGetFKeyList ( Relation  relation)

Definition at line 4728 of file relcache.c.

4729{
4730 List *result;
4731 Relation conrel;
4732 SysScanDesc conscan;
4733 ScanKeyData skey;
4734 HeapTuple htup;
4735 List *oldlist;
4736 MemoryContext oldcxt;
4737
4738 /* Quick exit if we already computed the list. */
4739 if (relation->rd_fkeyvalid)
4740 return relation->rd_fkeylist;
4741
4742 /*
4743 * We build the list we intend to return (in the caller's context) while
4744 * doing the scan. After successfully completing the scan, we copy that
4745 * list into the relcache entry. This avoids cache-context memory leakage
4746 * if we get some sort of error partway through.
4747 */
4748 result = NIL;
4749
4750 /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4751 ScanKeyInit(&skey,
4752 Anum_pg_constraint_conrelid,
4753 BTEqualStrategyNumber, F_OIDEQ,
4755
4756 conrel = table_open(ConstraintRelationId, AccessShareLock);
4757 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4758 NULL, 1, &skey);
4759
4760 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4761 {
4762 Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4763 ForeignKeyCacheInfo *info;
4764
4765 /* consider only foreign keys */
4766 if (constraint->contype != CONSTRAINT_FOREIGN)
4767 continue;
4768
4770 info->conoid = constraint->oid;
4771 info->conrelid = constraint->conrelid;
4772 info->confrelid = constraint->confrelid;
4773 info->conenforced = constraint->conenforced;
4774
4775 DeconstructFkConstraintRow(htup, &info->nkeys,
4776 info->conkey,
4777 info->confkey,
4778 info->conpfeqop,
4779 NULL, NULL, NULL, NULL);
4780
4781 /* Add FK's node to the result list */
4782 result = lappend(result, info);
4783 }
4784
4785 systable_endscan(conscan);
4787
4788 /* Now save a copy of the completed list in the relcache entry. */
4790 oldlist = relation->rd_fkeylist;
4791 relation->rd_fkeylist = copyObject(result);
4792 relation->rd_fkeyvalid = true;
4793 MemoryContextSwitchTo(oldcxt);
4794
4795 /* Don't leak the old list, if there is one */
4796 list_free_deep(oldlist);
4797
4798 return result;
4799}
void list_free_deep(List *list)
Definition: list.c:1560
#define copyObject(obj)
Definition: nodes.h:230
#define makeNode(_type_)
Definition: nodes.h:161
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
bool conenforced
Definition: rel.h:288
List * rd_fkeylist
Definition: rel.h:122
bool rd_fkeyvalid
Definition: rel.h:123

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::conenforced, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conrelid, copyObject, DeconstructFkConstraintRow(), GETSTRUCT(), HeapTupleIsValid, lappend(), list_free_deep(), makeNode, MemoryContextSwitchTo(), NIL, ForeignKeyCacheInfo::nkeys, ObjectIdGetDatum(), RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferencing(), CloneFkReferencing(), DetachPartitionFinalize(), and get_relation_foreign_keys().

◆ RelationGetIdentityKeyBitmap()

Bitmapset * RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5573 of file relcache.c.

5574{
5575 Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5576 Relation indexDesc;
5577 int i;
5578 Oid replidindex;
5579 MemoryContext oldcxt;
5580
5581 /* Quick exit if we already computed the result */
5582 if (relation->rd_idattr != NULL)
5583 return bms_copy(relation->rd_idattr);
5584
5585 /* Fast path if definitely no indexes */
5586 if (!RelationGetForm(relation)->relhasindex)
5587 return NULL;
5588
5589 /* Historic snapshot must be set. */
5591
5592 replidindex = RelationGetReplicaIndex(relation);
5593
5594 /* Fall out if there is no replica identity index */
5595 if (!OidIsValid(replidindex))
5596 return NULL;
5597
5598 /* Look up the description for the replica identity index */
5599 indexDesc = RelationIdGetRelation(replidindex);
5600
5601 if (!RelationIsValid(indexDesc))
5602 elog(ERROR, "could not open relation with OID %u",
5603 relation->rd_replidindex);
5604
5605 /* Add referenced attributes to idindexattrs */
5606 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5607 {
5608 int attrnum = indexDesc->rd_index->indkey.values[i];
5609
5610 /*
5611 * We don't include non-key columns into idindexattrs bitmaps. See
5612 * RelationGetIndexAttrBitmap.
5613 */
5614 if (attrnum != 0)
5615 {
5616 if (i < indexDesc->rd_index->indnkeyatts)
5617 idindexattrs = bms_add_member(idindexattrs,
5619 }
5620 }
5621
5622 RelationClose(indexDesc);
5623
5624 /* Don't leak the old values of these bitmaps, if any */
5625 bms_free(relation->rd_idattr);
5626 relation->rd_idattr = NULL;
5627
5628 /* Now save copy of the bitmap in the relcache entry */
5630 relation->rd_idattr = bms_copy(idindexattrs);
5631 MemoryContextSwitchTo(oldcxt);
5632
5633 /* We return our original working copy for caller to play with */
5634 return idindexattrs;
5635}
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
#define OidIsValid(objectId)
Definition: c.h:746
#define RelationGetForm(relation)
Definition: rel.h:510
#define RelationIsValid(relation)
Definition: rel.h:489
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:5069
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2099
void RelationClose(Relation relation)
Definition: relcache.c:2220
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1679
Oid rd_replidindex
Definition: rel.h:155
Bitmapset * rd_idattr
Definition: rel.h:164
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References Assert(), bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, ERROR, FirstLowInvalidHeapAttributeNumber, HistoricSnapshotActive(), i, MemoryContextSwitchTo(), OidIsValid, RelationData::rd_idattr, RelationData::rd_index, RelationData::rd_replidindex, RelationClose(), RelationGetForm, RelationGetReplicaIndex(), RelationIdGetRelation(), and RelationIsValid.

Referenced by logicalrep_write_attrs().

◆ RelationGetIndexAttOptions()

bytea ** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5985 of file relcache.c.

5986{
5987 MemoryContext oldcxt;
5988 bytea **opts = relation->rd_opcoptions;
5989 Oid relid = RelationGetRelid(relation);
5990 int natts = RelationGetNumberOfAttributes(relation); /* XXX
5991 * IndexRelationGetNumberOfKeyAttributes */
5992 int i;
5993
5994 /* Try to copy cached options. */
5995 if (opts)
5996 return copy ? CopyIndexAttOptions(opts, natts) : opts;
5997
5998 /* Get and parse opclass options. */
5999 opts = palloc0(sizeof(*opts) * natts);
6000
6001 for (i = 0; i < natts; i++)
6002 {
6003 if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
6004 {
6005 Datum attoptions = get_attoptions(relid, i + 1);
6006
6007 opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
6008
6009 if (attoptions != (Datum) 0)
6010 pfree(DatumGetPointer(attoptions));
6011 }
6012 }
6013
6014 /* Copy parsed options to the cache. */
6015 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
6016 relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
6017 MemoryContextSwitchTo(oldcxt);
6018
6019 if (copy)
6020 return opts;
6021
6022 for (i = 0; i < natts; i++)
6023 {
6024 if (opts[i])
6025 pfree(opts[i]);
6026 }
6027
6028 pfree(opts);
6029
6030 return relation->rd_opcoptions;
6031}
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:1043
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:1062
static AmcheckOptions opts
Definition: pg_amcheck.c:112
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:522
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5965
bytea ** rd_opcoptions
Definition: rel.h:218
Definition: c.h:658

References CopyIndexAttOptions(), criticalRelcachesBuilt, DatumGetPointer(), get_attoptions(), i, index_opclass_options(), MemoryContextSwitchTo(), opts, palloc0(), pfree(), RelationData::rd_indexcxt, RelationData::rd_opcoptions, RelationGetNumberOfAttributes, and RelationGetRelid.

Referenced by get_relation_info(), index_getprocinfo(), load_critical_index(), and RelationInitIndexAccessInfo().

◆ RelationGetIndexAttrBitmap()

Bitmapset * RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5300 of file relcache.c.

5301{
5302 Bitmapset *uindexattrs; /* columns in unique indexes */
5303 Bitmapset *pkindexattrs; /* columns in the primary index */
5304 Bitmapset *idindexattrs; /* columns in the replica identity */
5305 Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5306 Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5307 List *indexoidlist;
5308 List *newindexoidlist;
5309 Oid relpkindex;
5310 Oid relreplindex;
5311 ListCell *l;
5312 MemoryContext oldcxt;
5313
5314 /* Quick exit if we already computed the result. */
5315 if (relation->rd_attrsvalid)
5316 {
5317 switch (attrKind)
5318 {
5320 return bms_copy(relation->rd_keyattr);
5322 return bms_copy(relation->rd_pkattr);
5324 return bms_copy(relation->rd_idattr);
5326 return bms_copy(relation->rd_hotblockingattr);
5328 return bms_copy(relation->rd_summarizedattr);
5329 default:
5330 elog(ERROR, "unknown attrKind %u", attrKind);
5331 }
5332 }
5333
5334 /* Fast path if definitely no indexes */
5335 if (!RelationGetForm(relation)->relhasindex)
5336 return NULL;
5337
5338 /*
5339 * Get cached list of index OIDs. If we have to start over, we do so here.
5340 */
5341restart:
5342 indexoidlist = RelationGetIndexList(relation);
5343
5344 /* Fall out if no indexes (but relhasindex was set) */
5345 if (indexoidlist == NIL)
5346 return NULL;
5347
5348 /*
5349 * Copy the rd_pkindex and rd_replidindex values computed by
5350 * RelationGetIndexList before proceeding. This is needed because a
5351 * relcache flush could occur inside index_open below, resetting the
5352 * fields managed by RelationGetIndexList. We need to do the work with
5353 * stable values of these fields.
5354 */
5355 relpkindex = relation->rd_pkindex;
5356 relreplindex = relation->rd_replidindex;
5357
5358 /*
5359 * For each index, add referenced attributes to indexattrs.
5360 *
5361 * Note: we consider all indexes returned by RelationGetIndexList, even if
5362 * they are not indisready or indisvalid. This is important because an
5363 * index for which CREATE INDEX CONCURRENTLY has just started must be
5364 * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5365 * CONCURRENTLY is far enough along that we should ignore the index, it
5366 * won't be returned at all by RelationGetIndexList.
5367 */
5368 uindexattrs = NULL;
5369 pkindexattrs = NULL;
5370 idindexattrs = NULL;
5371 hotblockingattrs = NULL;
5372 summarizedattrs = NULL;
5373 foreach(l, indexoidlist)
5374 {
5375 Oid indexOid = lfirst_oid(l);
5376 Relation indexDesc;
5377 Datum datum;
5378 bool isnull;
5379 Node *indexExpressions;
5380 Node *indexPredicate;
5381 int i;
5382 bool isKey; /* candidate key */
5383 bool isPK; /* primary key */
5384 bool isIDKey; /* replica identity index */
5385 Bitmapset **attrs;
5386
5387 indexDesc = index_open(indexOid, AccessShareLock);
5388
5389 /*
5390 * Extract index expressions and index predicate. Note: Don't use
5391 * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5392 * those might run constant expressions evaluation, which needs a
5393 * snapshot, which we might not have here. (Also, it's probably more
5394 * sound to collect the bitmaps before any transformations that might
5395 * eliminate columns, but the practical impact of this is limited.)
5396 */
5397
5398 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5399 GetPgIndexDescriptor(), &isnull);
5400 if (!isnull)
5401 indexExpressions = stringToNode(TextDatumGetCString(datum));
5402 else
5403 indexExpressions = NULL;
5404
5405 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5406 GetPgIndexDescriptor(), &isnull);
5407 if (!isnull)
5408 indexPredicate = stringToNode(TextDatumGetCString(datum));
5409 else
5410 indexPredicate = NULL;
5411
5412 /* Can this index be referenced by a foreign key? */
5413 isKey = indexDesc->rd_index->indisunique &&
5414 indexExpressions == NULL &&
5415 indexPredicate == NULL;
5416
5417 /* Is this a primary key? */
5418 isPK = (indexOid == relpkindex);
5419
5420 /* Is this index the configured (or default) replica identity? */
5421 isIDKey = (indexOid == relreplindex);
5422
5423 /*
5424 * If the index is summarizing, it doesn't block HOT updates, but we
5425 * may still need to update it (if the attributes were modified). So
5426 * decide which bitmap we'll update in the following loop.
5427 */
5428 if (indexDesc->rd_indam->amsummarizing)
5429 attrs = &summarizedattrs;
5430 else
5431 attrs = &hotblockingattrs;
5432
5433 /* Collect simple attribute references */
5434 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5435 {
5436 int attrnum = indexDesc->rd_index->indkey.values[i];
5437
5438 /*
5439 * Since we have covering indexes with non-key columns, we must
5440 * handle them accurately here. non-key columns must be added into
5441 * hotblockingattrs or summarizedattrs, since they are in index,
5442 * and update shouldn't miss them.
5443 *
5444 * Summarizing indexes do not block HOT, but do need to be updated
5445 * when the column value changes, thus require a separate
5446 * attribute bitmapset.
5447 *
5448 * Obviously, non-key columns couldn't be referenced by foreign
5449 * key or identity key. Hence we do not include them into
5450 * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5451 */
5452 if (attrnum != 0)
5453 {
5454 *attrs = bms_add_member(*attrs,
5456
5457 if (isKey && i < indexDesc->rd_index->indnkeyatts)
5458 uindexattrs = bms_add_member(uindexattrs,
5460
5461 if (isPK && i < indexDesc->rd_index->indnkeyatts)
5462 pkindexattrs = bms_add_member(pkindexattrs,
5464
5465 if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5466 idindexattrs = bms_add_member(idindexattrs,
5468 }
5469 }
5470
5471 /* Collect all attributes used in expressions, too */
5472 pull_varattnos(indexExpressions, 1, attrs);
5473
5474 /* Collect all attributes in the index predicate, too */
5475 pull_varattnos(indexPredicate, 1, attrs);
5476
5477 index_close(indexDesc, AccessShareLock);
5478 }
5479
5480 /*
5481 * During one of the index_opens in the above loop, we might have received
5482 * a relcache flush event on this relcache entry, which might have been
5483 * signaling a change in the rel's index list. If so, we'd better start
5484 * over to ensure we deliver up-to-date attribute bitmaps.
5485 */
5486 newindexoidlist = RelationGetIndexList(relation);
5487 if (equal(indexoidlist, newindexoidlist) &&
5488 relpkindex == relation->rd_pkindex &&
5489 relreplindex == relation->rd_replidindex)
5490 {
5491 /* Still the same index set, so proceed */
5492 list_free(newindexoidlist);
5493 list_free(indexoidlist);
5494 }
5495 else
5496 {
5497 /* Gotta do it over ... might as well not leak memory */
5498 list_free(newindexoidlist);
5499 list_free(indexoidlist);
5500 bms_free(uindexattrs);
5501 bms_free(pkindexattrs);
5502 bms_free(idindexattrs);
5503 bms_free(hotblockingattrs);
5504 bms_free(summarizedattrs);
5505
5506 goto restart;
5507 }
5508
5509 /* Don't leak the old values of these bitmaps, if any */
5510 relation->rd_attrsvalid = false;
5511 bms_free(relation->rd_keyattr);
5512 relation->rd_keyattr = NULL;
5513 bms_free(relation->rd_pkattr);
5514 relation->rd_pkattr = NULL;
5515 bms_free(relation->rd_idattr);
5516 relation->rd_idattr = NULL;
5517 bms_free(relation->rd_hotblockingattr);
5518 relation->rd_hotblockingattr = NULL;
5519 bms_free(relation->rd_summarizedattr);
5520 relation->rd_summarizedattr = NULL;
5521
5522 /*
5523 * Now save copies of the bitmaps in the relcache entry. We intentionally
5524 * set rd_attrsvalid last, because that's the one that signals validity of
5525 * the values; if we run out of memory before making that copy, we won't
5526 * leave the relcache entry looking like the other ones are valid but
5527 * empty.
5528 */
5530 relation->rd_keyattr = bms_copy(uindexattrs);
5531 relation->rd_pkattr = bms_copy(pkindexattrs);
5532 relation->rd_idattr = bms_copy(idindexattrs);
5533 relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5534 relation->rd_summarizedattr = bms_copy(summarizedattrs);
5535 relation->rd_attrsvalid = true;
5536 MemoryContextSwitchTo(oldcxt);
5537
5538 /* We return our original working copy for caller to play with */
5539 switch (attrKind)
5540 {
5542 return uindexattrs;
5544 return pkindexattrs;
5546 return idindexattrs;
5548 return hotblockingattrs;
5550 return summarizedattrs;
5551 default:
5552 elog(ERROR, "unknown attrKind %u", attrKind);
5553 return NULL;
5554 }
5555}
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4833
bool amsummarizing
Definition: amapi.h:280
Bitmapset * rd_keyattr
Definition: rel.h:162
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
bool rd_attrsvalid
Definition: rel.h:161
Bitmapset * rd_hotblockingattr
Definition: rel.h:165
Oid rd_pkindex
Definition: rel.h:153
Bitmapset * rd_summarizedattr
Definition: rel.h:166
Bitmapset * rd_pkattr
Definition: rel.h:163
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References AccessShareLock, IndexAmRoutine::amsummarizing, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, GetPgIndexDescriptor(), heap_getattr(), i, INDEX_ATTR_BITMAP_HOT_BLOCKING, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_SUMMARIZED, index_close(), index_open(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, pull_varattnos(), RelationData::rd_attrsvalid, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_replidindex, RelationData::rd_summarizedattr, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

Referenced by dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), pub_contains_invalid_column(), and pub_rf_contains_invalid_column().

◆ RelationGetIndexExpressions()

List * RelationGetIndexExpressions ( Relation  relation)

Definition at line 5094 of file relcache.c.

5095{
5096 List *result;
5097 Datum exprsDatum;
5098 bool isnull;
5099 char *exprsString;
5100 MemoryContext oldcxt;
5101
5102 /* Quick exit if we already computed the result. */
5103 if (relation->rd_indexprs)
5104 return copyObject(relation->rd_indexprs);
5105
5106 /* Quick exit if there is nothing to do. */
5107 if (relation->rd_indextuple == NULL ||
5108 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5109 return NIL;
5110
5111 /*
5112 * We build the tree we intend to return in the caller's context. After
5113 * successfully completing the work, we copy it into the relcache entry.
5114 * This avoids problems if we get some sort of error partway through.
5115 */
5116 exprsDatum = heap_getattr(relation->rd_indextuple,
5117 Anum_pg_index_indexprs,
5119 &isnull);
5120 Assert(!isnull);
5121 exprsString = TextDatumGetCString(exprsDatum);
5122 result = (List *) stringToNode(exprsString);
5123 pfree(exprsString);
5124
5125 /*
5126 * Run the expressions through eval_const_expressions. This is not just an
5127 * optimization, but is necessary, because the planner will be comparing
5128 * them to similarly-processed qual clauses, and may fail to detect valid
5129 * matches without this. We must not use canonicalize_qual, however,
5130 * since these aren't qual expressions.
5131 */
5132 result = (List *) eval_const_expressions(NULL, (Node *) result);
5133
5134 /* May as well fix opfuncids too */
5135 fix_opfuncids((Node *) result);
5136
5137 /* Now save a copy of the completed tree in the relcache entry. */
5138 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5139 relation->rd_indexprs = copyObject(result);
5140 MemoryContextSwitchTo(oldcxt);
5141
5142 return result;
5143}
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2256
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1841
List * rd_indexprs
Definition: rel.h:212

References Assert(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_attr_expr(), get_relation_info(), GetIndexInputType(), index_unchanged_by_update(), infer_arbiter_indexes(), plan_create_index_workers(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetIndexList()

List * RelationGetIndexList ( Relation  relation)

Definition at line 4833 of file relcache.c.

4834{
4835 Relation indrel;
4836 SysScanDesc indscan;
4837 ScanKeyData skey;
4838 HeapTuple htup;
4839 List *result;
4840 List *oldlist;
4841 char replident = relation->rd_rel->relreplident;
4842 Oid pkeyIndex = InvalidOid;
4843 Oid candidateIndex = InvalidOid;
4844 bool pkdeferrable = false;
4845 MemoryContext oldcxt;
4846
4847 /* Quick exit if we already computed the list. */
4848 if (relation->rd_indexvalid)
4849 return list_copy(relation->rd_indexlist);
4850
4851 /*
4852 * We build the list we intend to return (in the caller's context) while
4853 * doing the scan. After successfully completing the scan, we copy that
4854 * list into the relcache entry. This avoids cache-context memory leakage
4855 * if we get some sort of error partway through.
4856 */
4857 result = NIL;
4858
4859 /* Prepare to scan pg_index for entries having indrelid = this rel. */
4860 ScanKeyInit(&skey,
4861 Anum_pg_index_indrelid,
4862 BTEqualStrategyNumber, F_OIDEQ,
4864
4865 indrel = table_open(IndexRelationId, AccessShareLock);
4866 indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4867 NULL, 1, &skey);
4868
4869 while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4870 {
4872
4873 /*
4874 * Ignore any indexes that are currently being dropped. This will
4875 * prevent them from being searched, inserted into, or considered in
4876 * HOT-safety decisions. It's unsafe to touch such an index at all
4877 * since its catalog entries could disappear at any instant.
4878 */
4879 if (!index->indislive)
4880 continue;
4881
4882 /* add index's OID to result list */
4883 result = lappend_oid(result, index->indexrelid);
4884
4885 /*
4886 * Non-unique or predicate indexes aren't interesting for either oid
4887 * indexes or replication identity indexes, so don't check them.
4888 * Deferred ones are not useful for replication identity either; but
4889 * we do include them if they are PKs.
4890 */
4891 if (!index->indisunique ||
4892 !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4893 continue;
4894
4895 /*
4896 * Remember primary key index, if any. For regular tables we do this
4897 * only if the index is valid; but for partitioned tables, then we do
4898 * it even if it's invalid.
4899 *
4900 * The reason for returning invalid primary keys for partitioned
4901 * tables is that we need it to prevent drop of not-null constraints
4902 * that may underlie such a primary key, which is only a problem for
4903 * partitioned tables.
4904 */
4905 if (index->indisprimary &&
4906 (index->indisvalid ||
4907 relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4908 {
4909 pkeyIndex = index->indexrelid;
4910 pkdeferrable = !index->indimmediate;
4911 }
4912
4913 if (!index->indimmediate)
4914 continue;
4915
4916 if (!index->indisvalid)
4917 continue;
4918
4919 /* remember explicitly chosen replica index */
4920 if (index->indisreplident)
4921 candidateIndex = index->indexrelid;
4922 }
4923
4924 systable_endscan(indscan);
4925
4927
4928 /* Sort the result list into OID order, per API spec. */
4929 list_sort(result, list_oid_cmp);
4930
4931 /* Now save a copy of the completed list in the relcache entry. */
4933 oldlist = relation->rd_indexlist;
4934 relation->rd_indexlist = list_copy(result);
4935 relation->rd_pkindex = pkeyIndex;
4936 relation->rd_ispkdeferrable = pkdeferrable;
4937 if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4938 relation->rd_replidindex = pkeyIndex;
4939 else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4940 relation->rd_replidindex = candidateIndex;
4941 else
4942 relation->rd_replidindex = InvalidOid;
4943 relation->rd_indexvalid = true;
4944 MemoryContextSwitchTo(oldcxt);
4945
4946 /* Don't leak the old list, if there is one */
4947 list_free(oldlist);
4948
4949 return result;
4950}
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool rd_ispkdeferrable
Definition: rel.h:154
bool rd_indexvalid
Definition: rel.h:64
List * rd_indexlist
Definition: rel.h:152
Definition: type.h:96

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT(), heap_attisnull(), HeapTupleIsValid, InvalidOid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), OidIsValid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterIndexNamespaces(), apply_handle_delete_internal(), apply_handle_insert_internal(), ATExecChangeOwner(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), RefreshMatViewByOid(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List * RelationGetIndexPredicate ( Relation  relation)

Definition at line 5207 of file relcache.c.

5208{
5209 List *result;
5210 Datum predDatum;
5211 bool isnull;
5212 char *predString;
5213 MemoryContext oldcxt;
5214
5215 /* Quick exit if we already computed the result. */
5216 if (relation->rd_indpred)
5217 return copyObject(relation->rd_indpred);
5218
5219 /* Quick exit if there is nothing to do. */
5220 if (relation->rd_indextuple == NULL ||
5221 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5222 return NIL;
5223
5224 /*
5225 * We build the tree we intend to return in the caller's context. After
5226 * successfully completing the work, we copy it into the relcache entry.
5227 * This avoids problems if we get some sort of error partway through.
5228 */
5229 predDatum = heap_getattr(relation->rd_indextuple,
5230 Anum_pg_index_indpred,
5232 &isnull);
5233 Assert(!isnull);
5234 predString = TextDatumGetCString(predDatum);
5235 result = (List *) stringToNode(predString);
5236 pfree(predString);
5237
5238 /*
5239 * Run the expression through const-simplification and canonicalization.
5240 * This is not just an optimization, but is necessary, because the planner
5241 * will be comparing it to similarly-processed qual clauses, and may fail
5242 * to detect valid matches without this. This must match the processing
5243 * done to qual clauses in preprocess_expression()! (We can skip the
5244 * stuff involving subqueries, however, since we don't allow any in index
5245 * predicates.)
5246 */
5247 result = (List *) eval_const_expressions(NULL, (Node *) result);
5248
5249 result = (List *) canonicalize_qual((Expr *) result, false);
5250
5251 /* Also convert to implicit-AND format */
5252 result = make_ands_implicit((Expr *) result);
5253
5254 /* May as well fix opfuncids too */
5255 fix_opfuncids((Node *) result);
5256
5257 /* Now save a copy of the completed tree in the relcache entry. */
5258 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5259 relation->rd_indpred = copyObject(result);
5260 MemoryContextSwitchTo(oldcxt);
5261
5262 return result;
5263}
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:810
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
List * rd_indpred
Definition: rel.h:213

References Assert(), canonicalize_qual(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), make_ands_implicit(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indextuple, RelationData::rd_indpred, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_relation_info(), infer_arbiter_indexes(), is_usable_unique_index(), plan_create_index_workers(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation,
bool  deferrable_ok 
)

Definition at line 5044 of file relcache.c.

5045{
5046 List *ilist;
5047
5048 if (!relation->rd_indexvalid)
5049 {
5050 /* RelationGetIndexList does the heavy lifting. */
5051 ilist = RelationGetIndexList(relation);
5052 list_free(ilist);
5053 Assert(relation->rd_indexvalid);
5054 }
5055
5056 if (deferrable_ok)
5057 return relation->rd_pkindex;
5058 else if (relation->rd_ispkdeferrable)
5059 return InvalidOid;
5060 return relation->rd_pkindex;
5061}

References Assert(), InvalidOid, list_free(), RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, and RelationGetIndexList().

Referenced by dropconstraint_internal(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5069 of file relcache.c.

5070{
5071 List *ilist;
5072
5073 if (!relation->rd_indexvalid)
5074 {
5075 /* RelationGetIndexList does the heavy lifting. */
5076 ilist = RelationGetIndexList(relation);
5077 list_free(ilist);
5078 Assert(relation->rd_indexvalid);
5079 }
5080
5081 return relation->rd_replidindex;
5082}

References Assert(), list_free(), RelationData::rd_indexvalid, RelationData::rd_replidindex, and RelationGetIndexList().

Referenced by CheckCmdReplicaIdentity(), GetRelationIdentityOrPK(), pg_get_replica_identity_index(), and RelationGetIdentityKeyBitmap().

◆ RelationGetStatExtList()

List * RelationGetStatExtList ( Relation  relation)

Definition at line 4974 of file relcache.c.

4975{
4976 Relation indrel;
4977 SysScanDesc indscan;
4978 ScanKeyData skey;
4979 HeapTuple htup;
4980 List *result;
4981 List *oldlist;
4982 MemoryContext oldcxt;
4983
4984 /* Quick exit if we already computed the list. */
4985 if (relation->rd_statvalid != 0)
4986 return list_copy(relation->rd_statlist);
4987
4988 /*
4989 * We build the list we intend to return (in the caller's context) while
4990 * doing the scan. After successfully completing the scan, we copy that
4991 * list into the relcache entry. This avoids cache-context memory leakage
4992 * if we get some sort of error partway through.
4993 */
4994 result = NIL;
4995
4996 /*
4997 * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4998 * rel.
4999 */
5000 ScanKeyInit(&skey,
5001 Anum_pg_statistic_ext_stxrelid,
5002 BTEqualStrategyNumber, F_OIDEQ,
5004
5005 indrel = table_open(StatisticExtRelationId, AccessShareLock);
5006 indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
5007 NULL, 1, &skey);
5008
5009 while (HeapTupleIsValid(htup = systable_getnext(indscan)))
5010 {
5011 Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
5012
5013 result = lappend_oid(result, oid);
5014 }
5015
5016 systable_endscan(indscan);
5017
5019
5020 /* Sort the result list into OID order, per API spec. */
5021 list_sort(result, list_oid_cmp);
5022
5023 /* Now save a copy of the completed list in the relcache entry. */
5025 oldlist = relation->rd_statlist;
5026 relation->rd_statlist = list_copy(result);
5027
5028 relation->rd_statvalid = true;
5029 MemoryContextSwitchTo(oldcxt);
5030
5031 /* Don't leak the old list, if there is one */
5032 list_free(oldlist);
5033
5034 return result;
5035}
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:66
List * rd_statlist
Definition: rel.h:158

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT(), HeapTupleIsValid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_statlist, RelationData::rd_statvalid, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by expandTableLikeClause(), and get_relation_statistics().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2099 of file relcache.c.

2100{
2101 Relation rd;
2102
2104
2105 /*
2106 * first try to find reldesc in the cache
2107 */
2108 RelationIdCacheLookup(relationId, rd);
2109
2110 if (RelationIsValid(rd))
2111 {
2112 /* return NULL for dropped relations */
2114 {
2115 Assert(!rd->rd_isvalid);
2116 return NULL;
2117 }
2118
2120 /* revalidate cache entry if necessary */
2121 if (!rd->rd_isvalid)
2122 {
2124
2125 /*
2126 * Normally entries need to be valid here, but before the relcache
2127 * has been initialized, not enough infrastructure exists to
2128 * perform pg_class lookups. The structure of such entries doesn't
2129 * change, but we still want to update the rd_rel entry. So
2130 * rd_isvalid = false is left in place for a later lookup.
2131 */
2132 Assert(rd->rd_isvalid ||
2134 }
2135 return rd;
2136 }
2137
2138 /*
2139 * no reldesc in the cache, so have RelationBuildDesc() build one and add
2140 * it.
2141 */
2142 rd = RelationBuildDesc(relationId, true);
2143 if (RelationIsValid(rd))
2145 return rd;
2146}
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1059
static void AssertCouldGetRelation(void)
Definition: relcache.h:44

References Assert(), AssertCouldGetRelation(), criticalRelcachesBuilt, InvalidSubTransactionId, RelationData::rd_droppedSubid, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationBuildDesc(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, and RelationRebuildRelation().

Referenced by check_and_init_gencol(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), pgoutput_ensure_entry_cxt(), pgoutput_row_filter_init(), relation_open(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6817 of file relcache.c.

6818{
6819 if (relationId == SharedSecLabelRelationId ||
6820 relationId == TriggerRelidNameIndexId ||
6821 relationId == DatabaseNameIndexId ||
6822 relationId == SharedSecLabelObjectIndexId)
6823 {
6824 /*
6825 * If this Assert fails, we don't need the applicable special case
6826 * anymore.
6827 */
6828 Assert(!RelationSupportsSysCache(relationId));
6829 return true;
6830 }
6831 return RelationSupportsSysCache(relationId);
6832}
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:770

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1445 of file relcache.c.

1446{
1447 HeapTuple tuple;
1448 Form_pg_am aform;
1449 Datum indcollDatum;
1450 Datum indclassDatum;
1451 Datum indoptionDatum;
1452 bool isnull;
1453 oidvector *indcoll;
1454 oidvector *indclass;
1455 int2vector *indoption;
1456 MemoryContext indexcxt;
1457 MemoryContext oldcontext;
1458 int indnatts;
1459 int indnkeyatts;
1460 uint16 amsupport;
1461
1462 /*
1463 * Make a copy of the pg_index entry for the index. Since pg_index
1464 * contains variable-length and possibly-null fields, we have to do this
1465 * honestly rather than just treating it as a Form_pg_index struct.
1466 */
1467 tuple = SearchSysCache1(INDEXRELID,
1469 if (!HeapTupleIsValid(tuple))
1470 elog(ERROR, "cache lookup failed for index %u",
1471 RelationGetRelid(relation));
1473 relation->rd_indextuple = heap_copytuple(tuple);
1474 relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1475 MemoryContextSwitchTo(oldcontext);
1476 ReleaseSysCache(tuple);
1477
1478 /*
1479 * Look up the index's access method, save the OID of its handler function
1480 */
1481 Assert(relation->rd_rel->relam != InvalidOid);
1482 tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1483 if (!HeapTupleIsValid(tuple))
1484 elog(ERROR, "cache lookup failed for access method %u",
1485 relation->rd_rel->relam);
1486 aform = (Form_pg_am) GETSTRUCT(tuple);
1487 relation->rd_amhandler = aform->amhandler;
1488 ReleaseSysCache(tuple);
1489
1490 indnatts = RelationGetNumberOfAttributes(relation);
1491 if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1492 elog(ERROR, "relnatts disagrees with indnatts for index %u",
1493 RelationGetRelid(relation));
1494 indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1495
1496 /*
1497 * Make the private context to hold index access info. The reason we need
1498 * a context, and not just a couple of pallocs, is so that we won't leak
1499 * any subsidiary info attached to fmgr lookup records.
1500 */
1502 "index info",
1504 relation->rd_indexcxt = indexcxt;
1506 RelationGetRelationName(relation));
1507
1508 /*
1509 * Now we can fetch the index AM's API struct
1510 */
1511 InitIndexAmRoutine(relation);
1512
1513 /*
1514 * Allocate arrays to hold data. Opclasses are not used for included
1515 * columns, so allocate them for indnkeyatts only.
1516 */
1517 relation->rd_opfamily = (Oid *)
1518 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1519 relation->rd_opcintype = (Oid *)
1520 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1521
1522 amsupport = relation->rd_indam->amsupport;
1523 if (amsupport > 0)
1524 {
1525 int nsupport = indnatts * amsupport;
1526
1527 relation->rd_support = (RegProcedure *)
1528 MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1529 relation->rd_supportinfo = (FmgrInfo *)
1530 MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1531 }
1532 else
1533 {
1534 relation->rd_support = NULL;
1535 relation->rd_supportinfo = NULL;
1536 }
1537
1538 relation->rd_indcollation = (Oid *)
1539 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1540
1541 relation->rd_indoption = (int16 *)
1542 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1543
1544 /*
1545 * indcollation cannot be referenced directly through the C struct,
1546 * because it comes after the variable-width indkey field. Must extract
1547 * the datum the hard way...
1548 */
1549 indcollDatum = fastgetattr(relation->rd_indextuple,
1550 Anum_pg_index_indcollation,
1552 &isnull);
1553 Assert(!isnull);
1554 indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1555 memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1556
1557 /*
1558 * indclass cannot be referenced directly through the C struct, because it
1559 * comes after the variable-width indkey field. Must extract the datum
1560 * the hard way...
1561 */
1562 indclassDatum = fastgetattr(relation->rd_indextuple,
1563 Anum_pg_index_indclass,
1565 &isnull);
1566 Assert(!isnull);
1567 indclass = (oidvector *) DatumGetPointer(indclassDatum);
1568
1569 /*
1570 * Fill the support procedure OID array, as well as the info about
1571 * opfamilies and opclass input types. (aminfo and supportinfo are left
1572 * as zeroes, and are filled on-the-fly when used)
1573 */
1574 IndexSupportInitialize(indclass, relation->rd_support,
1575 relation->rd_opfamily, relation->rd_opcintype,
1576 amsupport, indnkeyatts);
1577
1578 /*
1579 * Similarly extract indoption and copy it to the cache entry
1580 */
1581 indoptionDatum = fastgetattr(relation->rd_indextuple,
1582 Anum_pg_index_indoption,
1584 &isnull);
1585 Assert(!isnull);
1586 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1587 memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1588
1589 (void) RelationGetIndexAttOptions(relation, false);
1590
1591 /*
1592 * expressions, predicate, exclusion caches will be filled later
1593 */
1594 relation->rd_indexprs = NIL;
1595 relation->rd_indpred = NIL;
1596 relation->rd_exclops = NULL;
1597 relation->rd_exclprocs = NULL;
1598 relation->rd_exclstrats = NULL;
1599 relation->rd_amcache = NULL;
1600}
int16_t int16
Definition: c.h:497
regproc RegProcedure
Definition: c.h:621
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1294
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:121
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:528
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1421
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1616
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5985
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:240
RegProcedure * rd_support
Definition: rel.h:209
Oid * rd_opcintype
Definition: rel.h:208
int16 * rd_indoption
Definition: rel.h:211
void * rd_amcache
Definition: rel.h:229
Oid rd_amhandler
Definition: rel.h:184
struct FmgrInfo * rd_supportinfo
Definition: rel.h:210
Oid * rd_indcollation
Definition: rel.h:217
Definition: c.h:686
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:693
Definition: c.h:697
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:704

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert(), CacheMemoryContext, DatumGetPointer(), elog, ERROR, fastgetattr(), GetPgIndexDescriptor(), GETSTRUCT(), heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, IndexSupportInitialize(), InitIndexAmRoutine(), InvalidOid, MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_amcache, RelationData::rd_amhandler, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_support, RelationData::rd_supportinfo, RelationGetIndexAttOptions(), RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1829 of file relcache.c.

1830{
1831 HeapTuple tuple;
1832 Form_pg_am aform;
1833
1834 if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1835 {
1836 /*
1837 * Sequences are currently accessed like heap tables, but it doesn't
1838 * seem prudent to show that in the catalog. So just overwrite it
1839 * here.
1840 */
1841 Assert(relation->rd_rel->relam == InvalidOid);
1842 relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1843 }
1844 else if (IsCatalogRelation(relation))
1845 {
1846 /*
1847 * Avoid doing a syscache lookup for catalog tables.
1848 */
1849 Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1850 relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1851 }
1852 else
1853 {
1854 /*
1855 * Look up the table access method, save the OID of its handler
1856 * function.
1857 */
1858 Assert(relation->rd_rel->relam != InvalidOid);
1859 tuple = SearchSysCache1(AMOID,
1860 ObjectIdGetDatum(relation->rd_rel->relam));
1861 if (!HeapTupleIsValid(tuple))
1862 elog(ERROR, "cache lookup failed for access method %u",
1863 relation->rd_rel->relam);
1864 aform = (Form_pg_am) GETSTRUCT(tuple);
1865 relation->rd_amhandler = aform->amhandler;
1866 ReleaseSysCache(tuple);
1867 }
1868
1869 /*
1870 * Now we can fetch the table AM's API struct
1871 */
1872 InitTableAmRoutine(relation);
1873}
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:104
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1820

References Assert(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, InitTableAmRoutine(), InvalidOid, IsCatalogRelation(), ObjectIdGetDatum(), RelationData::rd_amhandler, RelationData::rd_rel, ReleaseSysCache(), and SearchSysCache1().

Referenced by load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), and RelationCacheInitializePhase3().

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3773 of file relcache.c.

3774{
3775 RelFileNumber newrelfilenumber;
3776 Relation pg_class;
3777 ItemPointerData otid;
3778 HeapTuple tuple;
3779 Form_pg_class classform;
3782 RelFileLocator newrlocator;
3783
3784 if (!IsBinaryUpgrade)
3785 {
3786 /* Allocate a new relfilenumber */
3787 newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3788 NULL, persistence);
3789 }
3790 else if (relation->rd_rel->relkind == RELKIND_INDEX)
3791 {
3793 ereport(ERROR,
3794 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3795 errmsg("index relfilenumber value not set when in binary upgrade mode")));
3796
3799 }
3800 else if (relation->rd_rel->relkind == RELKIND_RELATION)
3801 {
3803 ereport(ERROR,
3804 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3805 errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3806
3809 }
3810 else
3811 ereport(ERROR,
3812 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3813 errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3814
3815 /*
3816 * Get a writable copy of the pg_class tuple for the given relation.
3817 */
3818 pg_class = table_open(RelationRelationId, RowExclusiveLock);
3819
3820 tuple = SearchSysCacheLockedCopy1(RELOID,
3822 if (!HeapTupleIsValid(tuple))
3823 elog(ERROR, "could not find tuple for relation %u",
3824 RelationGetRelid(relation));
3825 otid = tuple->t_self;
3826 classform = (Form_pg_class) GETSTRUCT(tuple);
3827
3828 /*
3829 * Schedule unlinking of the old storage at transaction commit, except
3830 * when performing a binary upgrade, when we must do it immediately.
3831 */
3832 if (IsBinaryUpgrade)
3833 {
3834 SMgrRelation srel;
3835
3836 /*
3837 * During a binary upgrade, we use this code path to ensure that
3838 * pg_largeobject and its index have the same relfilenumbers as in the
3839 * old cluster. This is necessary because pg_upgrade treats
3840 * pg_largeobject like a user table, not a system table. It is however
3841 * possible that a table or index may need to end up with the same
3842 * relfilenumber in the new cluster as what it had in the old cluster.
3843 * Hence, we can't wait until commit time to remove the old storage.
3844 *
3845 * In general, this function needs to have transactional semantics,
3846 * and removing the old storage before commit time surely isn't.
3847 * However, it doesn't really matter, because if a binary upgrade
3848 * fails at this stage, the new cluster will need to be recreated
3849 * anyway.
3850 */
3851 srel = smgropen(relation->rd_locator, relation->rd_backend);
3852 smgrdounlinkall(&srel, 1, false);
3853 smgrclose(srel);
3854 }
3855 else
3856 {
3857 /* Not a binary upgrade, so just schedule it to happen later. */
3858 RelationDropStorage(relation);
3859 }
3860
3861 /*
3862 * Create storage for the main fork of the new relfilenumber. If it's a
3863 * table-like object, call into the table AM to do so, which'll also
3864 * create the table's init fork if needed.
3865 *
3866 * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3867 * be caught here, if GetNewRelFileNumber messes up for any reason.
3868 */
3869 newrlocator = relation->rd_locator;
3870 newrlocator.relNumber = newrelfilenumber;
3871
3872 if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3873 {
3874 table_relation_set_new_filelocator(relation, &newrlocator,
3875 persistence,
3876 &freezeXid, &minmulti);
3877 }
3878 else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3879 {
3880 /* handle these directly, at least for now */
3881 SMgrRelation srel;
3882
3883 srel = RelationCreateStorage(newrlocator, persistence, true);
3884 smgrclose(srel);
3885 }
3886 else
3887 {
3888 /* we shouldn't be called for anything else */
3889 elog(ERROR, "relation \"%s\" does not have storage",
3890 RelationGetRelationName(relation));
3891 }
3892
3893 /*
3894 * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3895 * change; instead we have to send the update to the relation mapper.
3896 *
3897 * For mapped indexes, we don't actually change the pg_class entry at all;
3898 * this is essential when reindexing pg_class itself. That leaves us with
3899 * possibly-inaccurate values of relpages etc, but those will be fixed up
3900 * later.
3901 */
3902 if (RelationIsMapped(relation))
3903 {
3904 /* This case is only supported for indexes */
3905 Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3906
3907 /* Since we're not updating pg_class, these had better not change */
3908 Assert(classform->relfrozenxid == freezeXid);
3909 Assert(classform->relminmxid == minmulti);
3910 Assert(classform->relpersistence == persistence);
3911
3912 /*
3913 * In some code paths it's possible that the tuple update we'd
3914 * otherwise do here is the only thing that would assign an XID for
3915 * the current transaction. However, we must have an XID to delete
3916 * files, so make sure one is assigned.
3917 */
3918 (void) GetCurrentTransactionId();
3919
3920 /* Do the deed */
3922 newrelfilenumber,
3923 relation->rd_rel->relisshared,
3924 false);
3925
3926 /* Since we're not updating pg_class, must trigger inval manually */
3927 CacheInvalidateRelcache(relation);
3928 }
3929 else
3930 {
3931 /* Normal case, update the pg_class entry */
3932 classform->relfilenode = newrelfilenumber;
3933
3934 /* relpages etc. never change for sequences */
3935 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3936 {
3937 classform->relpages = 0; /* it's empty until further notice */
3938 classform->reltuples = -1;
3939 classform->relallvisible = 0;
3940 classform->relallfrozen = 0;
3941 }
3942 classform->relfrozenxid = freezeXid;
3943 classform->relminmxid = minmulti;
3944 classform->relpersistence = persistence;
3945
3946 CatalogTupleUpdate(pg_class, &otid, tuple);
3947 }
3948
3949 UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3950 heap_freetuple(tuple);
3951
3952 table_close(pg_class, RowExclusiveLock);
3953
3954 /*
3955 * Make the pg_class row change or relation map change visible. This will
3956 * cause the relcache entry to get updated, too.
3957 */
3959
3961}
TransactionId MultiXactId
Definition: c.h:633
uint32 TransactionId
Definition: c.h:623
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:559
int errmsg(const char *fmt,...)
Definition: elog.c:1071
bool IsBinaryUpgrade
Definition: globals.c:122
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:86
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1631
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:601
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3976
Oid RelFileNumber
Definition: relpath.h:25
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:240
void smgrclose(SMgrRelation reln)
Definition: smgr.c:374
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:538
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:122
void RelationDropStorage(Relation rel)
Definition: storage.c:207
ItemPointerData t_self
Definition: htup.h:65
RelFileNumber relNumber
RelFileLocator rd_locator
Definition: rel.h:57
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:404
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1581
#define InvalidTransactionId
Definition: transam.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1100
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:454

References Assert(), binary_upgrade_next_heap_pg_class_relfilenumber, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, GetCurrentTransactionId(), GetNewRelFileNumber(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidMultiXactId, InvalidOid, InvalidTransactionId, IsBinaryUpgrade, ObjectIdGetDatum(), OidIsValid, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, RelationAssumeNewRelfilelocator(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileLocator::relNumber, RowExclusiveLock, SearchSysCacheLockedCopy1(), smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), table_relation_set_new_filelocator(), and UnlockTuple().

Referenced by AlterSequence(), ExecuteTruncateGuts(), reindex_index(), ResetSequence(), and SequenceChangePersistence().

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt