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

Relation RelationIdGetRelation (Oid relationId)
 
void RelationClose (Relation relation)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation)
 
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 135 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 59 of file relcache.h.

60 {
IndexAttrBitmapKind
Definition: relcache.h:60
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:64
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:65
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3339 of file relcache.c.

3341 {
3342  HASH_SEQ_STATUS status;
3343  RelIdCacheEnt *idhentry;
3344  int i;
3345 
3346  /*
3347  * Forget in_progress_list. This is relevant when we're aborting due to
3348  * an error during RelationBuildDesc(). We don't commit subtransactions
3349  * during RelationBuildDesc().
3350  */
3351  Assert(in_progress_list_len == 0 || !isCommit);
3353 
3354  /*
3355  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3356  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3357  * logic as in AtEOXact_RelationCache.
3358  */
3360  {
3361  hash_seq_init(&status, RelationIdCache);
3362  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3363  {
3364  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3365  mySubid, parentSubid);
3366  }
3367  }
3368  else
3369  {
3370  for (i = 0; i < eoxact_list_len; i++)
3371  {
3372  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3373  &eoxact_list[i],
3374  HASH_FIND,
3375  NULL);
3376  if (idhentry != NULL)
3377  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3378  mySubid, parentSubid);
3379  }
3380  }
3381 
3382  /* Don't reset the list; we still need more cleanup later */
3383 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
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:3394
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 3187 of file relcache.c.

3188 {
3189  HASH_SEQ_STATUS status;
3190  RelIdCacheEnt *idhentry;
3191  int i;
3192 
3193  /*
3194  * Forget in_progress_list. This is relevant when we're aborting due to
3195  * an error during RelationBuildDesc().
3196  */
3197  Assert(in_progress_list_len == 0 || !isCommit);
3199 
3200  /*
3201  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3202  * listed in it. Otherwise fall back on a hash_seq_search scan.
3203  *
3204  * For simplicity, eoxact_list[] entries are not deleted till end of
3205  * top-level transaction, even though we could remove them at
3206  * subtransaction end in some cases, or remove relations from the list if
3207  * they are cleared for other reasons. Therefore we should expect the
3208  * case that list entries are not found in the hashtable; if not, there's
3209  * nothing to do for them.
3210  */
3212  {
3213  hash_seq_init(&status, RelationIdCache);
3214  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3215  {
3216  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3217  }
3218  }
3219  else
3220  {
3221  for (i = 0; i < eoxact_list_len; i++)
3222  {
3223  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3224  &eoxact_list[i],
3225  HASH_FIND,
3226  NULL);
3227  if (idhentry != NULL)
3228  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3229  }
3230  }
3231 
3232  if (EOXactTupleDescArrayLen > 0)
3233  {
3234  Assert(EOXactTupleDescArray != NULL);
3235  for (i = 0; i < NextEOXactTupleDescNum; i++)
3238  EOXactTupleDescArray = NULL;
3239  }
3240 
3241  /* Now we're out of the transaction and can clear the lists */
3242  eoxact_list_len = 0;
3243  eoxact_list_overflowed = false;
3246 }
void pfree(void *pointer)
Definition: mcxt.c:1508
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:3257
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331

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 5934 of file relcache.c.

5935 {
5939 
5940  return 0; /* return value does not matter */
5941 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3322
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546

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 5951 of file relcache.c.

5952 {
5953  TupleDesc reldesc = RelationGetDescr(rel);
5954  const char *colname;
5955 
5956  /* Use reldesc if it's a user attribute, else consult the catalogs */
5957  if (attnum > 0 && attnum <= reldesc->natts)
5958  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5959  else
5960  colname = get_attname(RelationGetRelid(rel), attnum, false);
5961 
5962  return errtablecolname(rel, colname);
5963 }
#define NameStr(name)
Definition: c.h:733
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5975
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

Referenced by AlterDomainNotNull(), ATRewriteTable(), ExecConstraints(), and validateDomainConstraint().

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5975 of file relcache.c.

5976 {
5977  errtable(rel);
5979 
5980  return 0; /* return value does not matter */
5981 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5934

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 3918 of file relcache.c.

3919 {
3923 
3924  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3925  EOXactListAdd(relation);
3926 }
#define InvalidSubTransactionId
Definition: c.h:645
#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:781

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

3487 {
3488  Relation rel;
3489  MemoryContext oldcxt;
3490  int natts = tupDesc->natts;
3491  int i;
3492  bool has_not_null;
3493  bool nailit;
3494 
3495  Assert(natts >= 0);
3496 
3497  /*
3498  * check for creation of a rel that must be nailed in cache.
3499  *
3500  * XXX this list had better match the relations specially handled in
3501  * RelationCacheInitializePhase2/3.
3502  */
3503  switch (relid)
3504  {
3505  case DatabaseRelationId:
3506  case AuthIdRelationId:
3507  case AuthMemRelationId:
3508  case RelationRelationId:
3509  case AttributeRelationId:
3510  case ProcedureRelationId:
3511  case TypeRelationId:
3512  nailit = true;
3513  break;
3514  default:
3515  nailit = false;
3516  break;
3517  }
3518 
3519  /*
3520  * check that hardwired list of shared rels matches what's in the
3521  * bootstrap .bki file. If you get a failure here during initdb, you
3522  * probably need to fix IsSharedRelation() to match whatever you've done
3523  * to the set of shared relations.
3524  */
3525  if (shared_relation != IsSharedRelation(relid))
3526  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3527  relname, relid);
3528 
3529  /* Shared relations had better be mapped, too */
3530  Assert(mapped_relation || !shared_relation);
3531 
3532  /*
3533  * switch to the cache context to create the relcache entry.
3534  */
3535  if (!CacheMemoryContext)
3537 
3539 
3540  /*
3541  * allocate a new relation descriptor and fill in basic state fields.
3542  */
3543  rel = (Relation) palloc0(sizeof(RelationData));
3544 
3545  /* make sure relation is marked as having no open file yet */
3546  rel->rd_smgr = NULL;
3547 
3548  /* mark it nailed if appropriate */
3549  rel->rd_isnailed = nailit;
3550 
3551  rel->rd_refcnt = nailit ? 1 : 0;
3552 
3553  /* it's being created in this transaction */
3558 
3559  /*
3560  * create a new tuple descriptor from the one passed in. We do this
3561  * partly to copy it into the cache context, and partly because the new
3562  * relation can't have any defaults or constraints yet; they have to be
3563  * added in later steps, because they require additions to multiple system
3564  * catalogs. We can copy attnotnull constraints here, however.
3565  */
3566  rel->rd_att = CreateTupleDescCopy(tupDesc);
3567  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3568  has_not_null = false;
3569  for (i = 0; i < natts; i++)
3570  {
3571  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3572  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3573 
3574  datt->attidentity = satt->attidentity;
3575  datt->attgenerated = satt->attgenerated;
3576  datt->attnotnull = satt->attnotnull;
3577  has_not_null |= satt->attnotnull;
3578  }
3579 
3580  if (has_not_null)
3581  {
3582  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3583 
3584  constr->has_not_null = true;
3585  rel->rd_att->constr = constr;
3586  }
3587 
3588  /*
3589  * initialize relation tuple form (caller may add/override data later)
3590  */
3592 
3593  namestrcpy(&rel->rd_rel->relname, relname);
3594  rel->rd_rel->relnamespace = relnamespace;
3595 
3596  rel->rd_rel->relkind = relkind;
3597  rel->rd_rel->relnatts = natts;
3598  rel->rd_rel->reltype = InvalidOid;
3599  /* needed when bootstrapping: */
3600  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3601 
3602  /* set up persistence and relcache fields dependent on it */
3603  rel->rd_rel->relpersistence = relpersistence;
3604  switch (relpersistence)
3605  {
3606  case RELPERSISTENCE_UNLOGGED:
3607  case RELPERSISTENCE_PERMANENT:
3609  rel->rd_islocaltemp = false;
3610  break;
3611  case RELPERSISTENCE_TEMP:
3612  Assert(isTempOrTempToastNamespace(relnamespace));
3614  rel->rd_islocaltemp = true;
3615  break;
3616  default:
3617  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3618  break;
3619  }
3620 
3621  /* if it's a materialized view, it's not populated initially */
3622  if (relkind == RELKIND_MATVIEW)
3623  rel->rd_rel->relispopulated = false;
3624  else
3625  rel->rd_rel->relispopulated = true;
3626 
3627  /* set replica identity -- system catalogs and non-tables don't have one */
3628  if (!IsCatalogNamespace(relnamespace) &&
3629  (relkind == RELKIND_RELATION ||
3630  relkind == RELKIND_MATVIEW ||
3631  relkind == RELKIND_PARTITIONED_TABLE))
3632  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3633  else
3634  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3635 
3636  /*
3637  * Insert relation physical and logical identifiers (OIDs) into the right
3638  * places. For a mapped relation, we set relfilenumber to zero and rely
3639  * on RelationInitPhysicalAddr to consult the map.
3640  */
3641  rel->rd_rel->relisshared = shared_relation;
3642 
3643  RelationGetRelid(rel) = relid;
3644 
3645  for (i = 0; i < natts; i++)
3646  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3647 
3648  rel->rd_rel->reltablespace = reltablespace;
3649 
3650  if (mapped_relation)
3651  {
3652  rel->rd_rel->relfilenode = InvalidRelFileNumber;
3653  /* Add it to the active mapping information */
3654  RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3655  }
3656  else
3657  rel->rd_rel->relfilenode = relfilenumber;
3658 
3659  RelationInitLockInfo(rel); /* see lmgr.c */
3660 
3662 
3663  rel->rd_rel->relam = accessmtd;
3664 
3665  /*
3666  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3667  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3668  * require a long-lived current context.
3669  */
3670  MemoryContextSwitchTo(oldcxt);
3671 
3672  if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3674 
3675  /*
3676  * Okay to insert into the relcache hash table.
3677  *
3678  * Ordinarily, there should certainly not be an existing hash entry for
3679  * the same OID; but during bootstrap, when we create a "real" relcache
3680  * entry for one of the bootstrap relations, we'll be overwriting the
3681  * phony one created with formrdesc. So allow that to happen for nailed
3682  * rels.
3683  */
3684  RelationCacheInsert(rel, nailit);
3685 
3686  /*
3687  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3688  * can't do this before storing relid in it.
3689  */
3690  EOXactListAdd(rel);
3691 
3692  /* It's fully valid */
3693  rel->rd_isvalid = true;
3694 
3695  /*
3696  * Caller expects us to pin the returned entry.
3697  */
3699 
3700  return rel;
3701 }
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:243
void CreateCacheMemoryContext(void)
Definition: catcache.c:666
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
void * palloc0(Size size)
Definition: mcxt.c:1334
MemoryContext CacheMemoryContext
Definition: mcxt.c:140
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3658
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
#define InvalidOid
Definition: postgres_ext.h:36
#define ProcNumberForTempRelations()
Definition: proc.h:320
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:209
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2153
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1802
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1312
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
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:44
int tdrefcount
Definition: tupdesc.h:84
TupleConstr * constr
Definition: tupdesc.h:85
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133

References Assert(), 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(), 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, and TupleDescAttr.

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
struct PublicationDesc pubdesc 
)

Definition at line 5705 of file relcache.c.

5706 {
5707  List *puboids;
5708  ListCell *lc;
5709  MemoryContext oldcxt;
5710  Oid schemaid;
5711  List *ancestors = NIL;
5712  Oid relid = RelationGetRelid(relation);
5713 
5714  /*
5715  * If not publishable, it publishes no actions. (pgoutput_change() will
5716  * ignore it.)
5717  */
5718  if (!is_publishable_relation(relation))
5719  {
5720  memset(pubdesc, 0, sizeof(PublicationDesc));
5721  pubdesc->rf_valid_for_update = true;
5722  pubdesc->rf_valid_for_delete = true;
5723  pubdesc->cols_valid_for_update = true;
5724  pubdesc->cols_valid_for_delete = true;
5725  return;
5726  }
5727 
5728  if (relation->rd_pubdesc)
5729  {
5730  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5731  return;
5732  }
5733 
5734  memset(pubdesc, 0, sizeof(PublicationDesc));
5735  pubdesc->rf_valid_for_update = true;
5736  pubdesc->rf_valid_for_delete = true;
5737  pubdesc->cols_valid_for_update = true;
5738  pubdesc->cols_valid_for_delete = true;
5739 
5740  /* Fetch the publication membership info. */
5741  puboids = GetRelationPublications(relid);
5742  schemaid = RelationGetNamespace(relation);
5743  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5744 
5745  if (relation->rd_rel->relispartition)
5746  {
5747  /* Add publications that the ancestors are in too. */
5748  ancestors = get_partition_ancestors(relid);
5749 
5750  foreach(lc, ancestors)
5751  {
5752  Oid ancestor = lfirst_oid(lc);
5753 
5754  puboids = list_concat_unique_oid(puboids,
5755  GetRelationPublications(ancestor));
5756  schemaid = get_rel_namespace(ancestor);
5757  puboids = list_concat_unique_oid(puboids,
5758  GetSchemaPublications(schemaid));
5759  }
5760  }
5761  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5762 
5763  foreach(lc, puboids)
5764  {
5765  Oid pubid = lfirst_oid(lc);
5766  HeapTuple tup;
5767  Form_pg_publication pubform;
5768 
5769  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5770 
5771  if (!HeapTupleIsValid(tup))
5772  elog(ERROR, "cache lookup failed for publication %u", pubid);
5773 
5774  pubform = (Form_pg_publication) GETSTRUCT(tup);
5775 
5776  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5777  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5778  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5779  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5780 
5781  /*
5782  * Check if all columns referenced in the filter expression are part
5783  * of the REPLICA IDENTITY index or not.
5784  *
5785  * If the publication is FOR ALL TABLES then it means the table has no
5786  * row filters and we can skip the validation.
5787  */
5788  if (!pubform->puballtables &&
5789  (pubform->pubupdate || pubform->pubdelete) &&
5790  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5791  pubform->pubviaroot))
5792  {
5793  if (pubform->pubupdate)
5794  pubdesc->rf_valid_for_update = false;
5795  if (pubform->pubdelete)
5796  pubdesc->rf_valid_for_delete = false;
5797  }
5798 
5799  /*
5800  * Check if all columns are part of the REPLICA IDENTITY index or not.
5801  *
5802  * If the publication is FOR ALL TABLES then it means the table has no
5803  * column list and we can skip the validation.
5804  */
5805  if (!pubform->puballtables &&
5806  (pubform->pubupdate || pubform->pubdelete) &&
5807  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5808  pubform->pubviaroot))
5809  {
5810  if (pubform->pubupdate)
5811  pubdesc->cols_valid_for_update = false;
5812  if (pubform->pubdelete)
5813  pubdesc->cols_valid_for_delete = false;
5814  }
5815 
5816  ReleaseSysCache(tup);
5817 
5818  /*
5819  * If we know everything is replicated and the row filter is invalid
5820  * for update and delete, there is no point to check for other
5821  * publications.
5822  */
5823  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5824  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5825  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5826  break;
5827 
5828  /*
5829  * If we know everything is replicated and the column list is invalid
5830  * for update and delete, there is no point to check for other
5831  * publications.
5832  */
5833  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5834  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5835  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5836  break;
5837  }
5838 
5839  if (relation->rd_pubdesc)
5840  {
5841  pfree(relation->rd_pubdesc);
5842  relation->rd_pubdesc = NULL;
5843  }
5844 
5845  /* Now save copy of the descriptor in the relcache entry. */
5847  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5848  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5849  MemoryContextSwitchTo(oldcxt);
5850 }
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1930
void * palloc(Size size)
Definition: mcxt.c:1304
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 * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
bool pub_collist_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
Definition: pg_list.h:54
PublicationActions pubactions
bool cols_valid_for_delete
bool cols_valid_for_update
PublicationDesc * rd_pubdesc
Definition: rel.h:168
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References CacheMemoryContext, PublicationDesc::cols_valid_for_delete, PublicationDesc::cols_valid_for_update, elog, ERROR, 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_collist_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 6760 of file relcache.c.

6761 {
6762  LWLockRelease(RelCacheInitLock);
6763 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1785

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6735 of file relcache.c.

6736 {
6737  char localinitfname[MAXPGPATH];
6738  char sharedinitfname[MAXPGPATH];
6739 
6740  if (DatabasePath)
6741  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6743  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6745 
6746  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6747 
6748  /*
6749  * The files might not be there if no backend has been started since the
6750  * last removal. But complain about failures other than ENOENT with
6751  * ERROR. Fortunately, it's not too late to abort the transaction if we
6752  * can't get rid of the would-be-obsolete init file.
6753  */
6754  if (DatabasePath)
6755  unlink_initfile(localinitfname, ERROR);
6756  unlink_initfile(sharedinitfname, ERROR);
6757 }
char * DatabasePath
Definition: globals.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1172
@ LW_EXCLUSIVE
Definition: lwlock.h:116
#define MAXPGPATH
#define snprintf
Definition: port.h:238
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6832
#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(), and ProcessCommittedInvalidationMessages().

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6775 of file relcache.c.

6776 {
6777  const char *tblspcdir = "pg_tblspc";
6778  DIR *dir;
6779  struct dirent *de;
6780  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6781 
6782  snprintf(path, sizeof(path), "global/%s",
6784  unlink_initfile(path, LOG);
6785 
6786  /* Scan everything in the default tablespace */
6788 
6789  /* Scan the tablespace link directory to find non-default tablespaces */
6790  dir = AllocateDir(tblspcdir);
6791 
6792  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6793  {
6794  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6795  {
6796  /* Scan the tablespace dir for per-database dirs */
6797  snprintf(path, sizeof(path), "%s/%s/%s",
6798  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6800  }
6801  }
6802 
6803  FreeDir(dir);
6804 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2961
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2924
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6808
#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, ReadDirExtended(), RelationCacheInitFileRemoveInDir(), RELCACHE_INIT_FILENAME, snprintf, TABLESPACE_VERSION_DIRECTORY, and unlink_initfile().

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3944 of file relcache.c.

3945 {
3946  HASHCTL ctl;
3947  int allocsize;
3948 
3949  /*
3950  * make sure cache memory context exists
3951  */
3952  if (!CacheMemoryContext)
3954 
3955  /*
3956  * create hashtable that indexes the relcache
3957  */
3958  ctl.keysize = sizeof(Oid);
3959  ctl.entrysize = sizeof(RelIdCacheEnt);
3960  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3961  &ctl, HASH_ELEM | HASH_BLOBS);
3962 
3963  /*
3964  * reserve enough in_progress_list slots for many cases
3965  */
3966  allocsize = 4;
3969  allocsize * sizeof(*in_progress_list));
3970  in_progress_list_maxlen = allocsize;
3971 
3972  /*
3973  * relation mapper needs to be initialized too
3974  */
3976 }
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:1168
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3941
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:170
void RelationMapInitialize(void)
Definition: relmapper.c:651
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References CacheMemoryContext, CreateCacheMemoryContext(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, in_progress_list, in_progress_list_maxlen, INITRELCACHESIZE, HASHCTL::keysize, MemoryContextAlloc(), RelationIdCache, and RelationMapInitialize().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3990 of file relcache.c.

3991 {
3992  MemoryContext oldcxt;
3993 
3994  /*
3995  * relation mapper needs initialized too
3996  */
3998 
3999  /*
4000  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4001  * nothing.
4002  */
4004  return;
4005 
4006  /*
4007  * switch to cache memory context
4008  */
4010 
4011  /*
4012  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4013  * the cache with pre-made descriptors for the critical shared catalogs.
4014  */
4015  if (!load_relcache_init_file(true))
4016  {
4017  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4018  Natts_pg_database, Desc_pg_database);
4019  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4020  Natts_pg_authid, Desc_pg_authid);
4021  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4022  Natts_pg_auth_members, Desc_pg_auth_members);
4023  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4024  Natts_pg_shseclabel, Desc_pg_shseclabel);
4025  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4026  Natts_pg_subscription, Desc_pg_subscription);
4027 
4028 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4029  }
4030 
4031  MemoryContextSwitchTo(oldcxt);
4032 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6052
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:1867
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 4049 of file relcache.c.

4050 {
4051  HASH_SEQ_STATUS status;
4052  RelIdCacheEnt *idhentry;
4053  MemoryContext oldcxt;
4054  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
4055 
4056  /*
4057  * relation mapper needs initialized too
4058  */
4060 
4061  /*
4062  * switch to cache memory context
4063  */
4065 
4066  /*
4067  * Try to load the local relcache cache file. If unsuccessful, bootstrap
4068  * the cache with pre-made descriptors for the critical "nailed-in" system
4069  * catalogs.
4070  */
4071  if (IsBootstrapProcessingMode() ||
4072  !load_relcache_init_file(false))
4073  {
4074  needNewCacheFile = true;
4075 
4076  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4077  Natts_pg_class, Desc_pg_class);
4078  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4079  Natts_pg_attribute, Desc_pg_attribute);
4080  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4081  Natts_pg_proc, Desc_pg_proc);
4082  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4083  Natts_pg_type, Desc_pg_type);
4084 
4085 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4086  }
4087 
4088  MemoryContextSwitchTo(oldcxt);
4089 
4090  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4092  return;
4093 
4094  /*
4095  * If we didn't get the critical system indexes loaded into relcache, do
4096  * so now. These are critical because the catcache and/or opclass cache
4097  * depend on them for fetches done during relcache load. Thus, we have an
4098  * infinite-recursion problem. We can break the recursion by doing
4099  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4100  * performance, we only want to do that until we have the critical indexes
4101  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4102  * decide whether to do heapscan or indexscan at the key spots, and we set
4103  * it true after we've loaded the critical indexes.
4104  *
4105  * The critical indexes are marked as "nailed in cache", partly to make it
4106  * easy for load_relcache_init_file to count them, but mainly because we
4107  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4108  * true. (NOTE: perhaps it would be possible to reload them by
4109  * temporarily setting criticalRelcachesBuilt to false again. For now,
4110  * though, we just nail 'em in.)
4111  *
4112  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4113  * in the same way as the others, because the critical catalogs don't
4114  * (currently) have any rules or triggers, and so these indexes can be
4115  * rebuilt without inducing recursion. However they are used during
4116  * relcache load when a rel does have rules or triggers, so we choose to
4117  * nail them for performance reasons.
4118  */
4120  {
4121  load_critical_index(ClassOidIndexId,
4122  RelationRelationId);
4123  load_critical_index(AttributeRelidNumIndexId,
4124  AttributeRelationId);
4125  load_critical_index(IndexRelidIndexId,
4126  IndexRelationId);
4127  load_critical_index(OpclassOidIndexId,
4128  OperatorClassRelationId);
4129  load_critical_index(AccessMethodProcedureIndexId,
4130  AccessMethodProcedureRelationId);
4131  load_critical_index(RewriteRelRulenameIndexId,
4132  RewriteRelationId);
4133  load_critical_index(TriggerRelidNameIndexId,
4134  TriggerRelationId);
4135 
4136 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4137 
4138  criticalRelcachesBuilt = true;
4139  }
4140 
4141  /*
4142  * Process critical shared indexes too.
4143  *
4144  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4145  * initial lookup of MyDatabaseId, without which we'll never find any
4146  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4147  * database OID, so it instead depends on DatabaseOidIndexId. We also
4148  * need to nail up some indexes on pg_authid and pg_auth_members for use
4149  * during client authentication. SharedSecLabelObjectIndexId isn't
4150  * critical for the core system, but authentication hooks might be
4151  * interested in it.
4152  */
4154  {
4155  load_critical_index(DatabaseNameIndexId,
4156  DatabaseRelationId);
4157  load_critical_index(DatabaseOidIndexId,
4158  DatabaseRelationId);
4159  load_critical_index(AuthIdRolnameIndexId,
4160  AuthIdRelationId);
4161  load_critical_index(AuthIdOidIndexId,
4162  AuthIdRelationId);
4163  load_critical_index(AuthMemMemRoleIndexId,
4164  AuthMemRelationId);
4165  load_critical_index(SharedSecLabelObjectIndexId,
4166  SharedSecLabelRelationId);
4167 
4168 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4169 
4171  }
4172 
4173  /*
4174  * Now, scan all the relcache entries and update anything that might be
4175  * wrong in the results from formrdesc or the relcache cache file. If we
4176  * faked up relcache entries using formrdesc, then read the real pg_class
4177  * rows and replace the fake entries with them. Also, if any of the
4178  * relcache entries have rules, triggers, or security policies, load that
4179  * info the hard way since it isn't recorded in the cache file.
4180  *
4181  * Whenever we access the catalogs to read data, there is a possibility of
4182  * a shared-inval cache flush causing relcache entries to be removed.
4183  * Since hash_seq_search only guarantees to still work after the *current*
4184  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4185  * We handle this by restarting the scan from scratch after each access.
4186  * This is theoretically O(N^2), but the number of entries that actually
4187  * need to be fixed is small enough that it doesn't matter.
4188  */
4189  hash_seq_init(&status, RelationIdCache);
4190 
4191  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4192  {
4193  Relation relation = idhentry->reldesc;
4194  bool restart = false;
4195 
4196  /*
4197  * Make sure *this* entry doesn't get flushed while we work with it.
4198  */
4200 
4201  /*
4202  * If it's a faked-up entry, read the real pg_class tuple.
4203  */
4204  if (relation->rd_rel->relowner == InvalidOid)
4205  {
4206  HeapTuple htup;
4207  Form_pg_class relp;
4208 
4209  htup = SearchSysCache1(RELOID,
4210  ObjectIdGetDatum(RelationGetRelid(relation)));
4211  if (!HeapTupleIsValid(htup))
4212  elog(FATAL, "cache lookup failed for relation %u",
4213  RelationGetRelid(relation));
4214  relp = (Form_pg_class) GETSTRUCT(htup);
4215 
4216  /*
4217  * Copy tuple to relation->rd_rel. (See notes in
4218  * AllocateRelationDesc())
4219  */
4220  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4221 
4222  /* Update rd_options while we have the tuple */
4223  if (relation->rd_options)
4224  pfree(relation->rd_options);
4225  RelationParseRelOptions(relation, htup);
4226 
4227  /*
4228  * Check the values in rd_att were set up correctly. (We cannot
4229  * just copy them over now: formrdesc must have set up the rd_att
4230  * data correctly to start with, because it may already have been
4231  * copied into one or more catcache entries.)
4232  */
4233  Assert(relation->rd_att->tdtypeid == relp->reltype);
4234  Assert(relation->rd_att->tdtypmod == -1);
4235 
4236  ReleaseSysCache(htup);
4237 
4238  /* relowner had better be OK now, else we'll loop forever */
4239  if (relation->rd_rel->relowner == InvalidOid)
4240  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4241  RelationGetRelationName(relation));
4242 
4243  restart = true;
4244  }
4245 
4246  /*
4247  * Fix data that isn't saved in relcache cache file.
4248  *
4249  * relhasrules or relhastriggers could possibly be wrong or out of
4250  * date. If we don't actually find any rules or triggers, clear the
4251  * local copy of the flag so that we don't get into an infinite loop
4252  * here. We don't make any attempt to fix the pg_class entry, though.
4253  */
4254  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4255  {
4256  RelationBuildRuleLock(relation);
4257  if (relation->rd_rules == NULL)
4258  relation->rd_rel->relhasrules = false;
4259  restart = true;
4260  }
4261  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4262  {
4263  RelationBuildTriggers(relation);
4264  if (relation->trigdesc == NULL)
4265  relation->rd_rel->relhastriggers = false;
4266  restart = true;
4267  }
4268 
4269  /*
4270  * Re-load the row security policies if the relation has them, since
4271  * they are not preserved in the cache. Note that we can never NOT
4272  * have a policy while relrowsecurity is true,
4273  * RelationBuildRowSecurity will create a single default-deny policy
4274  * if there is no policy defined in pg_policy.
4275  */
4276  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4277  {
4278  RelationBuildRowSecurity(relation);
4279 
4280  Assert(relation->rd_rsdesc != NULL);
4281  restart = true;
4282  }
4283 
4284  /* Reload tableam data if needed */
4285  if (relation->rd_tableam == NULL &&
4286  (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4287  {
4289  Assert(relation->rd_tableam != NULL);
4290 
4291  restart = true;
4292  }
4293 
4294  /* Release hold on the relation */
4296 
4297  /* Now, restart the hashtable scan if needed */
4298  if (restart)
4299  {
4300  hash_seq_term(&status);
4301  hash_seq_init(&status, RelationIdCache);
4302  }
4303  }
4304 
4305  /*
4306  * Lastly, write out new relcache cache files if needed. We don't bother
4307  * to distinguish cases where only one of the two needs an update.
4308  */
4309  if (needNewCacheFile)
4310  {
4311  /*
4312  * Force all the catcaches to finish initializing and thereby open the
4313  * catalogs and indexes they use. This will preload the relcache with
4314  * entries for all the most important system catalogs and indexes, so
4315  * that the init files will be most useful for future backends.
4316  */
4318 
4319  /* now write the files */
4321  write_relcache_init_file(false);
4322  }
4323 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1471
#define FATAL
Definition: elog.h:41
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:463
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2166
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:732
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:6468
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:4332
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:83
Oid tdtypeid
Definition: tupdesc.h:82
void InitCatalogCachePhase2(void)
Definition: syscache.c:177
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1856

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, 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 2966 of file relcache.c.

2967 {
2968  HASH_SEQ_STATUS status;
2969  RelIdCacheEnt *idhentry;
2970  Relation relation;
2971  List *rebuildFirstList = NIL;
2972  List *rebuildList = NIL;
2973  ListCell *l;
2974  int i;
2975 
2976  /*
2977  * Reload relation mapping data before starting to reconstruct cache.
2978  */
2980 
2981  /* Phase 1 */
2982  hash_seq_init(&status, RelationIdCache);
2983 
2984  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2985  {
2986  relation = idhentry->reldesc;
2987 
2988  /*
2989  * Ignore new relations; no other backend will manipulate them before
2990  * we commit. Likewise, before replacing a relation's relfilelocator,
2991  * we shall have acquired AccessExclusiveLock and drained any
2992  * applicable pending invalidations.
2993  */
2994  if (relation->rd_createSubid != InvalidSubTransactionId ||
2996  continue;
2997 
2999 
3000  if (RelationHasReferenceCountZero(relation))
3001  {
3002  /* Delete this entry immediately */
3003  Assert(!relation->rd_isnailed);
3004  RelationClearRelation(relation, false);
3005  }
3006  else
3007  {
3008  /*
3009  * If it's a mapped relation, immediately update its rd_locator in
3010  * case its relfilenumber changed. We must do this during phase 1
3011  * in case the relation is consulted during rebuild of other
3012  * relcache entries in phase 2. It's safe since consulting the
3013  * map doesn't involve any access to relcache entries.
3014  */
3015  if (RelationIsMapped(relation))
3016  RelationInitPhysicalAddr(relation);
3017 
3018  /*
3019  * Add this entry to list of stuff to rebuild in second pass.
3020  * pg_class goes to the front of rebuildFirstList while
3021  * pg_class_oid_index goes to the back of rebuildFirstList, so
3022  * they are done first and second respectively. Other nailed
3023  * relations go to the front of rebuildList, so they'll be done
3024  * next in no particular order; and everything else goes to the
3025  * back of rebuildList.
3026  */
3027  if (RelationGetRelid(relation) == RelationRelationId)
3028  rebuildFirstList = lcons(relation, rebuildFirstList);
3029  else if (RelationGetRelid(relation) == ClassOidIndexId)
3030  rebuildFirstList = lappend(rebuildFirstList, relation);
3031  else if (relation->rd_isnailed)
3032  rebuildList = lcons(relation, rebuildList);
3033  else
3034  rebuildList = lappend(rebuildList, relation);
3035  }
3036  }
3037 
3038  /*
3039  * We cannot destroy the SMgrRelations as there might still be references
3040  * to them, but close the underlying file descriptors.
3041  */
3042  smgrreleaseall();
3043 
3044  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3045  foreach(l, rebuildFirstList)
3046  {
3047  relation = (Relation) lfirst(l);
3048  RelationClearRelation(relation, true);
3049  }
3050  list_free(rebuildFirstList);
3051  foreach(l, rebuildList)
3052  {
3053  relation = (Relation) lfirst(l);
3054  RelationClearRelation(relation, true);
3055  }
3056  list_free(rebuildList);
3057 
3058  if (!debug_discard)
3059  /* Any RelationBuildDesc() on the stack must start over. */
3060  for (i = 0; i < in_progress_list_len; i++)
3061  in_progress_list[i].invalidated = true;
3062 }
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
List * lcons(void *datum, List *list)
Definition: list.c:495
#define lfirst(lc)
Definition: pg_list.h:172
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:489
#define RelationIsMapped(relation)
Definition: rel.h:554
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2528
static long relcacheInvalsReceived
Definition: relcache.c:154
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:353

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2910 of file relcache.c.

2911 {
2912  Relation relation;
2913 
2914  RelationIdCacheLookup(relationId, relation);
2915 
2916  if (PointerIsValid(relation))
2917  {
2919  RelationFlushRelation(relation);
2920  }
2921  else
2922  {
2923  int i;
2924 
2925  for (i = 0; i < in_progress_list_len; i++)
2926  if (in_progress_list[i].reloid == relationId)
2927  in_progress_list[i].invalidated = true;
2928  }
2929 }
#define PointerIsValid(pointer)
Definition: c.h:750
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2833
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 2186 of file relcache.c.

2187 {
2188  /* Note: no locking manipulations needed */
2190 
2191  RelationCloseCleanup(relation);
2192 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2195

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 2866 of file relcache.c.

2867 {
2868  Relation relation;
2869 
2870  RelationIdCacheLookup(rid, relation);
2871 
2872  if (!PointerIsValid(relation))
2873  return; /* not in cache, nothing to do */
2874 
2875  if (!RelationHasReferenceCountZero(relation))
2876  elog(ERROR, "relation %u is still open", rid);
2877 
2879  if (relation->rd_createSubid != InvalidSubTransactionId ||
2881  {
2882  /*
2883  * In the event of subtransaction rollback, we must not forget
2884  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2885  * invalidates it in lieu of destroying it. (If we're in a top
2886  * transaction, we could opt to destroy the entry.)
2887  */
2889  }
2890 
2891  RelationClearRelation(relation, false);
2892 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5073 of file relcache.c.

5074 {
5075  List *result;
5076  Datum exprsDatum;
5077  bool isnull;
5078  char *exprsString;
5079  List *rawExprs;
5080  ListCell *lc;
5081 
5082  /* Quick exit if there is nothing to do. */
5083  if (relation->rd_indextuple == NULL ||
5084  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5085  return NIL;
5086 
5087  /* Extract raw node tree(s) from index tuple. */
5088  exprsDatum = heap_getattr(relation->rd_indextuple,
5089  Anum_pg_index_indexprs,
5091  &isnull);
5092  Assert(!isnull);
5093  exprsString = TextDatumGetCString(exprsDatum);
5094  rawExprs = (List *) stringToNode(exprsString);
5095  pfree(exprsString);
5096 
5097  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5098  result = NIL;
5099  foreach(lc, rawExprs)
5100  {
5101  Node *rawExpr = (Node *) lfirst(lc);
5102 
5103  result = lappend(result,
5104  makeConst(exprType(rawExpr),
5105  exprTypmod(rawExpr),
5106  exprCollation(rawExpr),
5107  1,
5108  (Datum) 0,
5109  true,
5110  true));
5111  }
5112 
5113  return result;
5114 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:284
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
uintptr_t Datum
Definition: postgres.h:64
void * stringToNode(const char *str)
Definition: read.c:90
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4411
Definition: nodes.h:129
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 5570 of file relcache.c.

5574 {
5575  int indnkeyatts;
5576  Oid *ops;
5577  Oid *funcs;
5578  uint16 *strats;
5579  Relation conrel;
5580  SysScanDesc conscan;
5581  ScanKeyData skey[1];
5582  HeapTuple htup;
5583  bool found;
5584  MemoryContext oldcxt;
5585  int i;
5586 
5587  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5588 
5589  /* Allocate result space in caller context */
5590  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5591  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5592  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5593 
5594  /* Quick exit if we have the data cached already */
5595  if (indexRelation->rd_exclstrats != NULL)
5596  {
5597  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5598  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5599  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5600  return;
5601  }
5602 
5603  /*
5604  * Search pg_constraint for the constraint associated with the index. To
5605  * make this not too painfully slow, we use the index on conrelid; that
5606  * will hold the parent relation's OID not the index's own OID.
5607  *
5608  * Note: if we wanted to rely on the constraint name matching the index's
5609  * name, we could just do a direct lookup using pg_constraint's unique
5610  * index. For the moment it doesn't seem worth requiring that.
5611  */
5612  ScanKeyInit(&skey[0],
5613  Anum_pg_constraint_conrelid,
5614  BTEqualStrategyNumber, F_OIDEQ,
5615  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5616 
5617  conrel = table_open(ConstraintRelationId, AccessShareLock);
5618  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5619  NULL, 1, skey);
5620  found = false;
5621 
5622  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5623  {
5625  Datum val;
5626  bool isnull;
5627  ArrayType *arr;
5628  int nelem;
5629 
5630  /* We want the exclusion constraint owning the index */
5631  if ((conform->contype != CONSTRAINT_EXCLUSION &&
5632  !(conform->conperiod && (
5633  conform->contype == CONSTRAINT_PRIMARY
5634  || conform->contype == CONSTRAINT_UNIQUE))) ||
5635  conform->conindid != RelationGetRelid(indexRelation))
5636  continue;
5637 
5638  /* There should be only one */
5639  if (found)
5640  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5641  RelationGetRelationName(indexRelation));
5642  found = true;
5643 
5644  /* Extract the operator OIDS from conexclop */
5645  val = fastgetattr(htup,
5646  Anum_pg_constraint_conexclop,
5647  conrel->rd_att, &isnull);
5648  if (isnull)
5649  elog(ERROR, "null conexclop for rel %s",
5650  RelationGetRelationName(indexRelation));
5651 
5652  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5653  nelem = ARR_DIMS(arr)[0];
5654  if (ARR_NDIM(arr) != 1 ||
5655  nelem != indnkeyatts ||
5656  ARR_HASNULL(arr) ||
5657  ARR_ELEMTYPE(arr) != OIDOID)
5658  elog(ERROR, "conexclop is not a 1-D Oid array");
5659 
5660  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5661  }
5662 
5663  systable_endscan(conscan);
5664  table_close(conrel, AccessShareLock);
5665 
5666  if (!found)
5667  elog(ERROR, "exclusion constraint record missing for rel %s",
5668  RelationGetRelationName(indexRelation));
5669 
5670  /* We need the func OIDs and strategy numbers too */
5671  for (i = 0; i < indnkeyatts; i++)
5672  {
5673  funcs[i] = get_opcode(ops[i]);
5674  strats[i] = get_op_opfamily_strategy(ops[i],
5675  indexRelation->rd_opfamily[i]);
5676  /* shouldn't fail, since it was checked at index creation */
5677  if (strats[i] == InvalidStrategy)
5678  elog(ERROR, "could not find strategy for operator %u in family %u",
5679  ops[i], indexRelation->rd_opfamily[i]);
5680  }
5681 
5682  /* Save a copy of the results in the relcache entry. */
5683  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5684  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5685  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5686  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5687  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5688  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5689  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5690  MemoryContextSwitchTo(oldcxt);
5691 }
#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
unsigned short uint16
Definition: c.h:492
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1263
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:83
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
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 4640 of file relcache.c.

4641 {
4642  List *result;
4643  Relation conrel;
4644  SysScanDesc conscan;
4645  ScanKeyData skey;
4646  HeapTuple htup;
4647  List *oldlist;
4648  MemoryContext oldcxt;
4649 
4650  /* Quick exit if we already computed the list. */
4651  if (relation->rd_fkeyvalid)
4652  return relation->rd_fkeylist;
4653 
4654  /* Fast path: non-partitioned tables without triggers can't have FKs */
4655  if (!relation->rd_rel->relhastriggers &&
4656  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4657  return NIL;
4658 
4659  /*
4660  * We build the list we intend to return (in the caller's context) while
4661  * doing the scan. After successfully completing the scan, we copy that
4662  * list into the relcache entry. This avoids cache-context memory leakage
4663  * if we get some sort of error partway through.
4664  */
4665  result = NIL;
4666 
4667  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4668  ScanKeyInit(&skey,
4669  Anum_pg_constraint_conrelid,
4670  BTEqualStrategyNumber, F_OIDEQ,
4671  ObjectIdGetDatum(RelationGetRelid(relation)));
4672 
4673  conrel = table_open(ConstraintRelationId, AccessShareLock);
4674  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4675  NULL, 1, &skey);
4676 
4677  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4678  {
4679  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4680  ForeignKeyCacheInfo *info;
4681 
4682  /* consider only foreign keys */
4683  if (constraint->contype != CONSTRAINT_FOREIGN)
4684  continue;
4685 
4686  info = makeNode(ForeignKeyCacheInfo);
4687  info->conoid = constraint->oid;
4688  info->conrelid = constraint->conrelid;
4689  info->confrelid = constraint->confrelid;
4690 
4691  DeconstructFkConstraintRow(htup, &info->nkeys,
4692  info->conkey,
4693  info->confkey,
4694  info->conpfeqop,
4695  NULL, NULL, NULL, NULL);
4696 
4697  /* Add FK's node to the result list */
4698  result = lappend(result, info);
4699  }
4700 
4701  systable_endscan(conscan);
4702  table_close(conrel, AccessShareLock);
4703 
4704  /* Now save a copy of the completed list in the relcache entry. */
4706  oldlist = relation->rd_fkeylist;
4707  relation->rd_fkeylist = copyObject(result);
4708  relation->rd_fkeyvalid = true;
4709  MemoryContextSwitchTo(oldcxt);
4710 
4711  /* Don't leak the old list, if there is one */
4712  list_free_deep(oldlist);
4713 
4714  return result;
4715 }
void list_free_deep(List *list)
Definition: list.c:1560
#define copyObject(obj)
Definition: nodes.h:223
#define makeNode(_type_)
Definition: nodes.h:155
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)
List * rd_fkeylist
Definition: rel.h:122
bool rd_fkeyvalid
Definition: rel.h:123

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, 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, RelationData::rd_rel, 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 5493 of file relcache.c.

5494 {
5495  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5496  Relation indexDesc;
5497  int i;
5498  Oid replidindex;
5499  MemoryContext oldcxt;
5500 
5501  /* Quick exit if we already computed the result */
5502  if (relation->rd_idattr != NULL)
5503  return bms_copy(relation->rd_idattr);
5504 
5505  /* Fast path if definitely no indexes */
5506  if (!RelationGetForm(relation)->relhasindex)
5507  return NULL;
5508 
5509  /* Historic snapshot must be set. */
5511 
5512  replidindex = RelationGetReplicaIndex(relation);
5513 
5514  /* Fall out if there is no replica identity index */
5515  if (!OidIsValid(replidindex))
5516  return NULL;
5517 
5518  /* Look up the description for the replica identity index */
5519  indexDesc = RelationIdGetRelation(replidindex);
5520 
5521  if (!RelationIsValid(indexDesc))
5522  elog(ERROR, "could not open relation with OID %u",
5523  relation->rd_replidindex);
5524 
5525  /* Add referenced attributes to idindexattrs */
5526  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5527  {
5528  int attrnum = indexDesc->rd_index->indkey.values[i];
5529 
5530  /*
5531  * We don't include non-key columns into idindexattrs bitmaps. See
5532  * RelationGetIndexAttrBitmap.
5533  */
5534  if (attrnum != 0)
5535  {
5536  if (i < indexDesc->rd_index->indnkeyatts)
5537  idindexattrs = bms_add_member(idindexattrs,
5539  }
5540  }
5541 
5542  RelationClose(indexDesc);
5543 
5544  /* Don't leak the old values of these bitmaps, if any */
5545  bms_free(relation->rd_idattr);
5546  relation->rd_idattr = NULL;
5547 
5548  /* Now save copy of the bitmap in the relcache entry */
5550  relation->rd_idattr = bms_copy(idindexattrs);
5551  MemoryContextSwitchTo(oldcxt);
5552 
5553  /* We return our original working copy for caller to play with */
5554  return idindexattrs;
5555 }
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:762
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationIsValid(relation)
Definition: rel.h:478
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4989
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2055
void RelationClose(Relation relation)
Definition: relcache.c:2186
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
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 5873 of file relcache.c.

5874 {
5875  MemoryContext oldcxt;
5876  bytea **opts = relation->rd_opcoptions;
5877  Oid relid = RelationGetRelid(relation);
5878  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5879  * IndexRelationGetNumberOfKeyAttributes */
5880  int i;
5881 
5882  /* Try to copy cached options. */
5883  if (opts)
5884  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5885 
5886  /* Get and parse opclass options. */
5887  opts = palloc0(sizeof(*opts) * natts);
5888 
5889  for (i = 0; i < natts; i++)
5890  {
5891  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5892  {
5893  Datum attoptions = get_attoptions(relid, i + 1);
5894 
5895  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5896 
5897  if (attoptions != (Datum) 0)
5898  pfree(DatumGetPointer(attoptions));
5899  }
5900  }
5901 
5902  /* Copy parsed options to the cache. */
5903  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5904  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5905  MemoryContextSwitchTo(oldcxt);
5906 
5907  if (copy)
5908  return opts;
5909 
5910  for (i = 0; i < natts; i++)
5911  {
5912  if (opts[i])
5913  pfree(opts[i]);
5914  }
5915 
5916  pfree(opts);
5917 
5918  return relation->rd_opcoptions;
5919 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:999
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
static AmcheckOptions opts
Definition: pg_amcheck.c:111
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5853
bytea ** rd_opcoptions
Definition: rel.h:218
Definition: c.h:674

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 5220 of file relcache.c.

5221 {
5222  Bitmapset *uindexattrs; /* columns in unique indexes */
5223  Bitmapset *pkindexattrs; /* columns in the primary index */
5224  Bitmapset *idindexattrs; /* columns in the replica identity */
5225  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5226  Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5227  List *indexoidlist;
5228  List *newindexoidlist;
5229  Oid relpkindex;
5230  Oid relreplindex;
5231  ListCell *l;
5232  MemoryContext oldcxt;
5233 
5234  /* Quick exit if we already computed the result. */
5235  if (relation->rd_attrsvalid)
5236  {
5237  switch (attrKind)
5238  {
5239  case INDEX_ATTR_BITMAP_KEY:
5240  return bms_copy(relation->rd_keyattr);
5242  return bms_copy(relation->rd_pkattr);
5244  return bms_copy(relation->rd_idattr);
5246  return bms_copy(relation->rd_hotblockingattr);
5248  return bms_copy(relation->rd_summarizedattr);
5249  default:
5250  elog(ERROR, "unknown attrKind %u", attrKind);
5251  }
5252  }
5253 
5254  /* Fast path if definitely no indexes */
5255  if (!RelationGetForm(relation)->relhasindex)
5256  return NULL;
5257 
5258  /*
5259  * Get cached list of index OIDs. If we have to start over, we do so here.
5260  */
5261 restart:
5262  indexoidlist = RelationGetIndexList(relation);
5263 
5264  /* Fall out if no indexes (but relhasindex was set) */
5265  if (indexoidlist == NIL)
5266  return NULL;
5267 
5268  /*
5269  * Copy the rd_pkindex and rd_replidindex values computed by
5270  * RelationGetIndexList before proceeding. This is needed because a
5271  * relcache flush could occur inside index_open below, resetting the
5272  * fields managed by RelationGetIndexList. We need to do the work with
5273  * stable values of these fields.
5274  */
5275  relpkindex = relation->rd_pkindex;
5276  relreplindex = relation->rd_replidindex;
5277 
5278  /*
5279  * For each index, add referenced attributes to indexattrs.
5280  *
5281  * Note: we consider all indexes returned by RelationGetIndexList, even if
5282  * they are not indisready or indisvalid. This is important because an
5283  * index for which CREATE INDEX CONCURRENTLY has just started must be
5284  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5285  * CONCURRENTLY is far enough along that we should ignore the index, it
5286  * won't be returned at all by RelationGetIndexList.
5287  */
5288  uindexattrs = NULL;
5289  pkindexattrs = NULL;
5290  idindexattrs = NULL;
5291  hotblockingattrs = NULL;
5292  summarizedattrs = NULL;
5293  foreach(l, indexoidlist)
5294  {
5295  Oid indexOid = lfirst_oid(l);
5296  Relation indexDesc;
5297  Datum datum;
5298  bool isnull;
5299  Node *indexExpressions;
5300  Node *indexPredicate;
5301  int i;
5302  bool isKey; /* candidate key */
5303  bool isPK; /* primary key */
5304  bool isIDKey; /* replica identity index */
5305  Bitmapset **attrs;
5306 
5307  indexDesc = index_open(indexOid, AccessShareLock);
5308 
5309  /*
5310  * Extract index expressions and index predicate. Note: Don't use
5311  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5312  * those might run constant expressions evaluation, which needs a
5313  * snapshot, which we might not have here. (Also, it's probably more
5314  * sound to collect the bitmaps before any transformations that might
5315  * eliminate columns, but the practical impact of this is limited.)
5316  */
5317 
5318  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5319  GetPgIndexDescriptor(), &isnull);
5320  if (!isnull)
5321  indexExpressions = stringToNode(TextDatumGetCString(datum));
5322  else
5323  indexExpressions = NULL;
5324 
5325  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5326  GetPgIndexDescriptor(), &isnull);
5327  if (!isnull)
5328  indexPredicate = stringToNode(TextDatumGetCString(datum));
5329  else
5330  indexPredicate = NULL;
5331 
5332  /* Can this index be referenced by a foreign key? */
5333  isKey = indexDesc->rd_index->indisunique &&
5334  indexExpressions == NULL &&
5335  indexPredicate == NULL;
5336 
5337  /* Is this a primary key? */
5338  isPK = (indexOid == relpkindex);
5339 
5340  /* Is this index the configured (or default) replica identity? */
5341  isIDKey = (indexOid == relreplindex);
5342 
5343  /*
5344  * If the index is summarizing, it doesn't block HOT updates, but we
5345  * may still need to update it (if the attributes were modified). So
5346  * decide which bitmap we'll update in the following loop.
5347  */
5348  if (indexDesc->rd_indam->amsummarizing)
5349  attrs = &summarizedattrs;
5350  else
5351  attrs = &hotblockingattrs;
5352 
5353  /* Collect simple attribute references */
5354  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5355  {
5356  int attrnum = indexDesc->rd_index->indkey.values[i];
5357 
5358  /*
5359  * Since we have covering indexes with non-key columns, we must
5360  * handle them accurately here. non-key columns must be added into
5361  * hotblockingattrs or summarizedattrs, since they are in index,
5362  * and update shouldn't miss them.
5363  *
5364  * Summarizing indexes do not block HOT, but do need to be updated
5365  * when the column value changes, thus require a separate
5366  * attribute bitmapset.
5367  *
5368  * Obviously, non-key columns couldn't be referenced by foreign
5369  * key or identity key. Hence we do not include them into
5370  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5371  */
5372  if (attrnum != 0)
5373  {
5374  *attrs = bms_add_member(*attrs,
5376 
5377  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5378  uindexattrs = bms_add_member(uindexattrs,
5380 
5381  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5382  pkindexattrs = bms_add_member(pkindexattrs,
5384 
5385  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5386  idindexattrs = bms_add_member(idindexattrs,
5388  }
5389  }
5390 
5391  /* Collect all attributes used in expressions, too */
5392  pull_varattnos(indexExpressions, 1, attrs);
5393 
5394  /* Collect all attributes in the index predicate, too */
5395  pull_varattnos(indexPredicate, 1, attrs);
5396 
5397  index_close(indexDesc, AccessShareLock);
5398  }
5399 
5400  /*
5401  * During one of the index_opens in the above loop, we might have received
5402  * a relcache flush event on this relcache entry, which might have been
5403  * signaling a change in the rel's index list. If so, we'd better start
5404  * over to ensure we deliver up-to-date attribute bitmaps.
5405  */
5406  newindexoidlist = RelationGetIndexList(relation);
5407  if (equal(indexoidlist, newindexoidlist) &&
5408  relpkindex == relation->rd_pkindex &&
5409  relreplindex == relation->rd_replidindex)
5410  {
5411  /* Still the same index set, so proceed */
5412  list_free(newindexoidlist);
5413  list_free(indexoidlist);
5414  }
5415  else
5416  {
5417  /* Gotta do it over ... might as well not leak memory */
5418  list_free(newindexoidlist);
5419  list_free(indexoidlist);
5420  bms_free(uindexattrs);
5421  bms_free(pkindexattrs);
5422  bms_free(idindexattrs);
5423  bms_free(hotblockingattrs);
5424  bms_free(summarizedattrs);
5425 
5426  goto restart;
5427  }
5428 
5429  /* Don't leak the old values of these bitmaps, if any */
5430  relation->rd_attrsvalid = false;
5431  bms_free(relation->rd_keyattr);
5432  relation->rd_keyattr = NULL;
5433  bms_free(relation->rd_pkattr);
5434  relation->rd_pkattr = NULL;
5435  bms_free(relation->rd_idattr);
5436  relation->rd_idattr = NULL;
5437  bms_free(relation->rd_hotblockingattr);
5438  relation->rd_hotblockingattr = NULL;
5439  bms_free(relation->rd_summarizedattr);
5440  relation->rd_summarizedattr = NULL;
5441 
5442  /*
5443  * Now save copies of the bitmaps in the relcache entry. We intentionally
5444  * set rd_attrsvalid last, because that's the one that signals validity of
5445  * the values; if we run out of memory before making that copy, we won't
5446  * leave the relcache entry looking like the other ones are valid but
5447  * empty.
5448  */
5450  relation->rd_keyattr = bms_copy(uindexattrs);
5451  relation->rd_pkattr = bms_copy(pkindexattrs);
5452  relation->rd_idattr = bms_copy(idindexattrs);
5453  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5454  relation->rd_summarizedattr = bms_copy(summarizedattrs);
5455  relation->rd_attrsvalid = true;
5456  MemoryContextSwitchTo(oldcxt);
5457 
5458  /* We return our original working copy for caller to play with */
5459  switch (attrKind)
5460  {
5461  case INDEX_ATTR_BITMAP_KEY:
5462  return uindexattrs;
5464  return pkindexattrs;
5466  return idindexattrs;
5468  return hotblockingattrs;
5470  return summarizedattrs;
5471  default:
5472  elog(ERROR, "unknown attrKind %u", attrKind);
5473  return NULL;
5474  }
5475 }
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:4749
bool amsummarizing
Definition: amapi.h:253
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:291

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 ATExecDropNotNull(), ATInheritAdjustNotNulls(), dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), MergeAttributes(), pub_collist_contains_invalid_column(), pub_rf_contains_invalid_column(), and transformTableLikeClause().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5014 of file relcache.c.

5015 {
5016  List *result;
5017  Datum exprsDatum;
5018  bool isnull;
5019  char *exprsString;
5020  MemoryContext oldcxt;
5021 
5022  /* Quick exit if we already computed the result. */
5023  if (relation->rd_indexprs)
5024  return copyObject(relation->rd_indexprs);
5025 
5026  /* Quick exit if there is nothing to do. */
5027  if (relation->rd_indextuple == NULL ||
5028  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5029  return NIL;
5030 
5031  /*
5032  * We build the tree we intend to return in the caller's context. After
5033  * successfully completing the work, we copy it into the relcache entry.
5034  * This avoids problems if we get some sort of error partway through.
5035  */
5036  exprsDatum = heap_getattr(relation->rd_indextuple,
5037  Anum_pg_index_indexprs,
5039  &isnull);
5040  Assert(!isnull);
5041  exprsString = TextDatumGetCString(exprsDatum);
5042  result = (List *) stringToNode(exprsString);
5043  pfree(exprsString);
5044 
5045  /*
5046  * Run the expressions through eval_const_expressions. This is not just an
5047  * optimization, but is necessary, because the planner will be comparing
5048  * them to similarly-processed qual clauses, and may fail to detect valid
5049  * matches without this. We must not use canonicalize_qual, however,
5050  * since these aren't qual expressions.
5051  */
5052  result = (List *) eval_const_expressions(NULL, (Node *) result);
5053 
5054  /* May as well fix opfuncids too */
5055  fix_opfuncids((Node *) result);
5056 
5057  /* Now save a copy of the completed tree in the relcache entry. */
5058  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5059  relation->rd_indexprs = copyObject(result);
5060  MemoryContextSwitchTo(oldcxt);
5061 
5062  return result;
5063 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2234
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1759
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_relation_info(), GetIndexInputType(), index_unchanged_by_update(), infer_arbiter_indexes(), plan_create_index_workers(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4749 of file relcache.c.

4750 {
4751  Relation indrel;
4752  SysScanDesc indscan;
4753  ScanKeyData skey;
4754  HeapTuple htup;
4755  List *result;
4756  List *oldlist;
4757  char replident = relation->rd_rel->relreplident;
4758  Oid pkeyIndex = InvalidOid;
4759  Oid candidateIndex = InvalidOid;
4760  bool pkdeferrable = false;
4761  MemoryContext oldcxt;
4762 
4763  /* Quick exit if we already computed the list. */
4764  if (relation->rd_indexvalid)
4765  return list_copy(relation->rd_indexlist);
4766 
4767  /*
4768  * We build the list we intend to return (in the caller's context) while
4769  * doing the scan. After successfully completing the scan, we copy that
4770  * list into the relcache entry. This avoids cache-context memory leakage
4771  * if we get some sort of error partway through.
4772  */
4773  result = NIL;
4774 
4775  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4776  ScanKeyInit(&skey,
4777  Anum_pg_index_indrelid,
4778  BTEqualStrategyNumber, F_OIDEQ,
4779  ObjectIdGetDatum(RelationGetRelid(relation)));
4780 
4781  indrel = table_open(IndexRelationId, AccessShareLock);
4782  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4783  NULL, 1, &skey);
4784 
4785  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4786  {
4788 
4789  /*
4790  * Ignore any indexes that are currently being dropped. This will
4791  * prevent them from being searched, inserted into, or considered in
4792  * HOT-safety decisions. It's unsafe to touch such an index at all
4793  * since its catalog entries could disappear at any instant.
4794  */
4795  if (!index->indislive)
4796  continue;
4797 
4798  /* add index's OID to result list */
4799  result = lappend_oid(result, index->indexrelid);
4800 
4801  /*
4802  * Non-unique or predicate indexes aren't interesting for either oid
4803  * indexes or replication identity indexes, so don't check them.
4804  * Deferred ones are not useful for replication identity either; but
4805  * we do include them if they are PKs.
4806  */
4807  if (!index->indisunique ||
4808  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4809  continue;
4810 
4811  /*
4812  * Remember primary key index, if any. We do this only if the index
4813  * is valid; but if the table is partitioned, then we do it even if
4814  * it's invalid.
4815  *
4816  * The reason for returning invalid primary keys for foreign tables is
4817  * because of pg_dump of NOT NULL constraints, and the fact that PKs
4818  * remain marked invalid until the partitions' PKs are attached to it.
4819  * If we make rd_pkindex invalid, then the attnotnull flag is reset
4820  * after the PK is created, which causes the ALTER INDEX ATTACH
4821  * PARTITION to fail with 'column ... is not marked NOT NULL'. With
4822  * this, dropconstraint_internal() will believe that the columns must
4823  * not have attnotnull reset, so the PKs-on-partitions can be attached
4824  * correctly, until finally the PK-on-parent is marked valid.
4825  *
4826  * Also, this doesn't harm anything, because rd_pkindex is not a
4827  * "real" index anyway, but a RELKIND_PARTITIONED_INDEX.
4828  */
4829  if (index->indisprimary &&
4830  (index->indisvalid ||
4831  relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4832  {
4833  pkeyIndex = index->indexrelid;
4834  pkdeferrable = !index->indimmediate;
4835  }
4836 
4837  if (!index->indimmediate)
4838  continue;
4839 
4840  if (!index->indisvalid)
4841  continue;
4842 
4843  /* remember explicitly chosen replica index */
4844  if (index->indisreplident)
4845  candidateIndex = index->indexrelid;
4846  }
4847 
4848  systable_endscan(indscan);
4849 
4850  table_close(indrel, AccessShareLock);
4851 
4852  /* Sort the result list into OID order, per API spec. */
4853  list_sort(result, list_oid_cmp);
4854 
4855  /* Now save a copy of the completed list in the relcache entry. */
4857  oldlist = relation->rd_indexlist;
4858  relation->rd_indexlist = list_copy(result);
4859  relation->rd_pkindex = pkeyIndex;
4860  relation->rd_ispkdeferrable = pkdeferrable;
4861  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4862  relation->rd_replidindex = pkeyIndex;
4863  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4864  relation->rd_replidindex = candidateIndex;
4865  else
4866  relation->rd_replidindex = InvalidOid;
4867  relation->rd_indexvalid = true;
4868  MemoryContextSwitchTo(oldcxt);
4869 
4870  /* Don't leak the old list, if there is one */
4871  list_free(oldlist);
4872 
4873  return result;
4874 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
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:95

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(), ATExecChangeOwner(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), 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 5127 of file relcache.c.

5128 {
5129  List *result;
5130  Datum predDatum;
5131  bool isnull;
5132  char *predString;
5133  MemoryContext oldcxt;
5134 
5135  /* Quick exit if we already computed the result. */
5136  if (relation->rd_indpred)
5137  return copyObject(relation->rd_indpred);
5138 
5139  /* Quick exit if there is nothing to do. */
5140  if (relation->rd_indextuple == NULL ||
5141  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5142  return NIL;
5143 
5144  /*
5145  * We build the tree we intend to return in the caller's context. After
5146  * successfully completing the work, we copy it into the relcache entry.
5147  * This avoids problems if we get some sort of error partway through.
5148  */
5149  predDatum = heap_getattr(relation->rd_indextuple,
5150  Anum_pg_index_indpred,
5152  &isnull);
5153  Assert(!isnull);
5154  predString = TextDatumGetCString(predDatum);
5155  result = (List *) stringToNode(predString);
5156  pfree(predString);
5157 
5158  /*
5159  * Run the expression through const-simplification and canonicalization.
5160  * This is not just an optimization, but is necessary, because the planner
5161  * will be comparing it to similarly-processed qual clauses, and may fail
5162  * to detect valid matches without this. This must match the processing
5163  * done to qual clauses in preprocess_expression()! (We can skip the
5164  * stuff involving subqueries, however, since we don't allow any in index
5165  * predicates.)
5166  */
5167  result = (List *) eval_const_expressions(NULL, (Node *) result);
5168 
5169  result = (List *) canonicalize_qual((Expr *) result, false);
5170 
5171  /* Also convert to implicit-AND format */
5172  result = make_ands_implicit((Expr *) result);
5173 
5174  /* May as well fix opfuncids too */
5175  fix_opfuncids((Node *) result);
5176 
5177  /* Now save a copy of the completed tree in the relcache entry. */
5178  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5179  relation->rd_indpred = copyObject(result);
5180  MemoryContextSwitchTo(oldcxt);
5181 
5182  return result;
5183 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:721
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(), and transformIndexConstraint().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4968 of file relcache.c.

4969 {
4970  List *ilist;
4971 
4972  if (!relation->rd_indexvalid)
4973  {
4974  /* RelationGetIndexList does the heavy lifting. */
4975  ilist = RelationGetIndexList(relation);
4976  list_free(ilist);
4977  Assert(relation->rd_indexvalid);
4978  }
4979 
4980  return relation->rd_ispkdeferrable ? InvalidOid : relation->rd_pkindex;
4981 }

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

Referenced by GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4989 of file relcache.c.

4990 {
4991  List *ilist;
4992 
4993  if (!relation->rd_indexvalid)
4994  {
4995  /* RelationGetIndexList does the heavy lifting. */
4996  ilist = RelationGetIndexList(relation);
4997  list_free(ilist);
4998  Assert(relation->rd_indexvalid);
4999  }
5000 
5001  return relation->rd_replidindex;
5002 }

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 4898 of file relcache.c.

4899 {
4900  Relation indrel;
4901  SysScanDesc indscan;
4902  ScanKeyData skey;
4903  HeapTuple htup;
4904  List *result;
4905  List *oldlist;
4906  MemoryContext oldcxt;
4907 
4908  /* Quick exit if we already computed the list. */
4909  if (relation->rd_statvalid != 0)
4910  return list_copy(relation->rd_statlist);
4911 
4912  /*
4913  * We build the list we intend to return (in the caller's context) while
4914  * doing the scan. After successfully completing the scan, we copy that
4915  * list into the relcache entry. This avoids cache-context memory leakage
4916  * if we get some sort of error partway through.
4917  */
4918  result = NIL;
4919 
4920  /*
4921  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4922  * rel.
4923  */
4924  ScanKeyInit(&skey,
4925  Anum_pg_statistic_ext_stxrelid,
4926  BTEqualStrategyNumber, F_OIDEQ,
4927  ObjectIdGetDatum(RelationGetRelid(relation)));
4928 
4929  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4930  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4931  NULL, 1, &skey);
4932 
4933  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4934  {
4935  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4936 
4937  result = lappend_oid(result, oid);
4938  }
4939 
4940  systable_endscan(indscan);
4941 
4942  table_close(indrel, AccessShareLock);
4943 
4944  /* Sort the result list into OID order, per API spec. */
4945  list_sort(result, list_oid_cmp);
4946 
4947  /* Now save a copy of the completed list in the relcache entry. */
4949  oldlist = relation->rd_statlist;
4950  relation->rd_statlist = list_copy(result);
4951 
4952  relation->rd_statvalid = true;
4953  MemoryContextSwitchTo(oldcxt);
4954 
4955  /* Don't leak the old list, if there is one */
4956  list_free(oldlist);
4957 
4958  return result;
4959 }
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 get_relation_statistics(), and transformTableLikeClause().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2055 of file relcache.c.

2056 {
2057  Relation rd;
2058 
2059  /* Make sure we're in an xact, even if this ends up being a cache hit */
2061 
2062  /*
2063  * first try to find reldesc in the cache
2064  */
2065  RelationIdCacheLookup(relationId, rd);
2066 
2067  if (RelationIsValid(rd))
2068  {
2069  /* return NULL for dropped relations */
2071  {
2072  Assert(!rd->rd_isvalid);
2073  return NULL;
2074  }
2075 
2077  /* revalidate cache entry if necessary */
2078  if (!rd->rd_isvalid)
2079  {
2080  /*
2081  * Indexes only have a limited number of possible schema changes,
2082  * and we don't want to use the full-blown procedure because it's
2083  * a headache for indexes that reload itself depends on.
2084  */
2085  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2086  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2088  else
2089  RelationClearRelation(rd, true);
2090 
2091  /*
2092  * Normally entries need to be valid here, but before the relcache
2093  * has been initialized, not enough infrastructure exists to
2094  * perform pg_class lookups. The structure of such entries doesn't
2095  * change, but we still want to update the rd_rel entry. So
2096  * rd_isvalid = false is left in place for a later lookup.
2097  */
2098  Assert(rd->rd_isvalid ||
2100  }
2101  return rd;
2102  }
2103 
2104  /*
2105  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2106  * it.
2107  */
2108  rd = RelationBuildDesc(relationId, true);
2109  if (RelationIsValid(rd))
2111  return rd;
2112 }
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1039
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2249
bool IsTransactionState(void)
Definition: xact.c:379

References Assert(), criticalRelcachesBuilt, InvalidSubTransactionId, IsTransactionState(), RelationData::rd_droppedSubid, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_rel, RelationBuildDesc(), RelationClearRelation(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, and RelationReloadIndexInfo().

Referenced by 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 6695 of file relcache.c.

6696 {
6697  if (relationId == SharedSecLabelRelationId ||
6698  relationId == TriggerRelidNameIndexId ||
6699  relationId == DatabaseNameIndexId ||
6700  relationId == SharedSecLabelObjectIndexId)
6701  {
6702  /*
6703  * If this Assert fails, we don't need the applicable special case
6704  * anymore.
6705  */
6706  Assert(!RelationSupportsSysCache(relationId));
6707  return true;
6708  }
6709  return RelationSupportsSysCache(relationId);
6710 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:649

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1418 of file relcache.c.

1419 {
1420  HeapTuple tuple;
1421  Form_pg_am aform;
1422  Datum indcollDatum;
1423  Datum indclassDatum;
1424  Datum indoptionDatum;
1425  bool isnull;
1426  oidvector *indcoll;
1427  oidvector *indclass;
1428  int2vector *indoption;
1429  MemoryContext indexcxt;
1430  MemoryContext oldcontext;
1431  int indnatts;
1432  int indnkeyatts;
1433  uint16 amsupport;
1434 
1435  /*
1436  * Make a copy of the pg_index entry for the index. Since pg_index
1437  * contains variable-length and possibly-null fields, we have to do this
1438  * honestly rather than just treating it as a Form_pg_index struct.
1439  */
1440  tuple = SearchSysCache1(INDEXRELID,
1441  ObjectIdGetDatum(RelationGetRelid(relation)));
1442  if (!HeapTupleIsValid(tuple))
1443  elog(ERROR, "cache lookup failed for index %u",
1444  RelationGetRelid(relation));
1446  relation->rd_indextuple = heap_copytuple(tuple);
1447  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1448  MemoryContextSwitchTo(oldcontext);
1449  ReleaseSysCache(tuple);
1450 
1451  /*
1452  * Look up the index's access method, save the OID of its handler function
1453  */
1454  Assert(relation->rd_rel->relam != InvalidOid);
1455  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1456  if (!HeapTupleIsValid(tuple))
1457  elog(ERROR, "cache lookup failed for access method %u",
1458  relation->rd_rel->relam);
1459  aform = (Form_pg_am) GETSTRUCT(tuple);
1460  relation->rd_amhandler = aform->amhandler;
1461  ReleaseSysCache(tuple);
1462 
1463  indnatts = RelationGetNumberOfAttributes(relation);
1464  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1465  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1466  RelationGetRelid(relation));
1467  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1468 
1469  /*
1470  * Make the private context to hold index access info. The reason we need
1471  * a context, and not just a couple of pallocs, is so that we won't leak
1472  * any subsidiary info attached to fmgr lookup records.
1473  */
1475  "index info",
1477  relation->rd_indexcxt = indexcxt;
1479  RelationGetRelationName(relation));
1480 
1481  /*
1482  * Now we can fetch the index AM's API struct
1483  */
1484  InitIndexAmRoutine(relation);
1485 
1486  /*
1487  * Allocate arrays to hold data. Opclasses are not used for included
1488  * columns, so allocate them for indnkeyatts only.
1489  */
1490  relation->rd_opfamily = (Oid *)
1491  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1492  relation->rd_opcintype = (Oid *)
1493  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1494 
1495  amsupport = relation->rd_indam->amsupport;
1496  if (amsupport > 0)
1497  {
1498  int nsupport = indnatts * amsupport;
1499 
1500  relation->rd_support = (RegProcedure *)
1501  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1502  relation->rd_supportinfo = (FmgrInfo *)
1503  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1504  }
1505  else
1506  {
1507  relation->rd_support = NULL;
1508  relation->rd_supportinfo = NULL;
1509  }
1510 
1511  relation->rd_indcollation = (Oid *)
1512  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1513 
1514  relation->rd_indoption = (int16 *)
1515  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1516 
1517  /*
1518  * indcollation cannot be referenced directly through the C struct,
1519  * because it comes after the variable-width indkey field. Must extract
1520  * the datum the hard way...
1521  */
1522  indcollDatum = fastgetattr(relation->rd_indextuple,
1523  Anum_pg_index_indcollation,
1525  &isnull);
1526  Assert(!isnull);
1527  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1528  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1529 
1530  /*
1531  * indclass cannot be referenced directly through the C struct, because it
1532  * comes after the variable-width indkey field. Must extract the datum
1533  * the hard way...
1534  */
1535  indclassDatum = fastgetattr(relation->rd_indextuple,
1536  Anum_pg_index_indclass,
1538  &isnull);
1539  Assert(!isnull);
1540  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1541 
1542  /*
1543  * Fill the support procedure OID array, as well as the info about
1544  * opfamilies and opclass input types. (aminfo and supportinfo are left
1545  * as zeroes, and are filled on-the-fly when used)
1546  */
1547  IndexSupportInitialize(indclass, relation->rd_support,
1548  relation->rd_opfamily, relation->rd_opcintype,
1549  amsupport, indnkeyatts);
1550 
1551  /*
1552  * Similarly extract indoption and copy it to the cache entry
1553  */
1554  indoptionDatum = fastgetattr(relation->rd_indextuple,
1555  Anum_pg_index_indoption,
1557  &isnull);
1558  Assert(!isnull);
1559  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1560  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1561 
1562  (void) RelationGetIndexAttOptions(relation, false);
1563 
1564  /*
1565  * expressions, predicate, exclusion caches will be filled later
1566  */
1567  relation->rd_indexprs = NIL;
1568  relation->rd_indpred = NIL;
1569  relation->rd_exclops = NULL;
1570  relation->rd_exclprocs = NULL;
1571  relation->rd_exclstrats = NULL;
1572  relation->rd_amcache = NULL;
1573 }
signed short int16
Definition: c.h:480
regproc RegProcedure
Definition: c.h:637
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1202
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:517
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1394
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1589
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5873
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:219
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:702
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:709
Definition: c.h:713
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:720

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 1802 of file relcache.c.

1803 {
1804  HeapTuple tuple;
1805  Form_pg_am aform;
1806 
1807  if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1808  {
1809  /*
1810  * Sequences are currently accessed like heap tables, but it doesn't
1811  * seem prudent to show that in the catalog. So just overwrite it
1812  * here.
1813  */
1814  Assert(relation->rd_rel->relam == InvalidOid);
1815  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1816  }
1817  else if (IsCatalogRelation(relation))
1818  {
1819  /*
1820  * Avoid doing a syscache lookup for catalog tables.
1821  */
1822  Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1823  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1824  }
1825  else
1826  {
1827  /*
1828  * Look up the table access method, save the OID of its handler
1829  * function.
1830  */
1831  Assert(relation->rd_rel->relam != InvalidOid);
1832  tuple = SearchSysCache1(AMOID,
1833  ObjectIdGetDatum(relation->rd_rel->relam));
1834  if (!HeapTupleIsValid(tuple))
1835  elog(ERROR, "cache lookup failed for access method %u",
1836  relation->rd_rel->relam);
1837  aform = (Form_pg_am) GETSTRUCT(tuple);
1838  relation->rd_amhandler = aform->amhandler;
1839  ReleaseSysCache(tuple);
1840  }
1841 
1842  /*
1843  * Now we can fetch the table AM's API struct
1844  */
1845  InitTableAmRoutine(relation);
1846 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1793

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 3719 of file relcache.c.

3720 {
3721  RelFileNumber newrelfilenumber;
3722  Relation pg_class;
3723  HeapTuple tuple;
3724  Form_pg_class classform;
3725  MultiXactId minmulti = InvalidMultiXactId;
3726  TransactionId freezeXid = InvalidTransactionId;
3727  RelFileLocator newrlocator;
3728 
3729  if (!IsBinaryUpgrade)
3730  {
3731  /* Allocate a new relfilenumber */
3732  newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3733  NULL, persistence);
3734  }
3735  else if (relation->rd_rel->relkind == RELKIND_INDEX)
3736  {
3738  ereport(ERROR,
3739  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3740  errmsg("index relfilenumber value not set when in binary upgrade mode")));
3741 
3744  }
3745  else if (relation->rd_rel->relkind == RELKIND_RELATION)
3746  {
3748  ereport(ERROR,
3749  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3750  errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3751 
3754  }
3755  else
3756  ereport(ERROR,
3757  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3758  errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3759 
3760  /*
3761  * Get a writable copy of the pg_class tuple for the given relation.
3762  */
3763  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3764 
3765  tuple = SearchSysCacheCopy1(RELOID,
3766  ObjectIdGetDatum(RelationGetRelid(relation)));
3767  if (!HeapTupleIsValid(tuple))
3768  elog(ERROR, "could not find tuple for relation %u",
3769  RelationGetRelid(relation));
3770  classform = (Form_pg_class) GETSTRUCT(tuple);
3771 
3772  /*
3773  * Schedule unlinking of the old storage at transaction commit, except
3774  * when performing a binary upgrade, when we must do it immediately.
3775  */
3776  if (IsBinaryUpgrade)
3777  {
3778  SMgrRelation srel;
3779 
3780  /*
3781  * During a binary upgrade, we use this code path to ensure that
3782  * pg_largeobject and its index have the same relfilenumbers as in the
3783  * old cluster. This is necessary because pg_upgrade treats
3784  * pg_largeobject like a user table, not a system table. It is however
3785  * possible that a table or index may need to end up with the same
3786  * relfilenumber in the new cluster as what it had in the old cluster.
3787  * Hence, we can't wait until commit time to remove the old storage.
3788  *
3789  * In general, this function needs to have transactional semantics,
3790  * and removing the old storage before commit time surely isn't.
3791  * However, it doesn't really matter, because if a binary upgrade
3792  * fails at this stage, the new cluster will need to be recreated
3793  * anyway.
3794  */
3795  srel = smgropen(relation->rd_locator, relation->rd_backend);
3796  smgrdounlinkall(&srel, 1, false);
3797  smgrclose(srel);
3798  }
3799  else
3800  {
3801  /* Not a binary upgrade, so just schedule it to happen later. */
3802  RelationDropStorage(relation);
3803  }
3804 
3805  /*
3806  * Create storage for the main fork of the new relfilenumber. If it's a
3807  * table-like object, call into the table AM to do so, which'll also
3808  * create the table's init fork if needed.
3809  *
3810  * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3811  * be caught here, if GetNewRelFileNumber messes up for any reason.
3812  */
3813  newrlocator = relation->rd_locator;
3814  newrlocator.relNumber = newrelfilenumber;
3815 
3816  if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3817  {
3818  table_relation_set_new_filelocator(relation, &newrlocator,
3819  persistence,
3820  &freezeXid, &minmulti);
3821  }
3822  else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3823  {
3824  /* handle these directly, at least for now */
3825  SMgrRelation srel;
3826 
3827  srel = RelationCreateStorage(newrlocator, persistence, true);
3828  smgrclose(srel);
3829  }
3830  else
3831  {
3832  /* we shouldn't be called for anything else */
3833  elog(ERROR, "relation \"%s\" does not have storage",
3834  RelationGetRelationName(relation));
3835  }
3836 
3837  /*
3838  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3839  * change; instead we have to send the update to the relation mapper.
3840  *
3841  * For mapped indexes, we don't actually change the pg_class entry at all;
3842  * this is essential when reindexing pg_class itself. That leaves us with
3843  * possibly-inaccurate values of relpages etc, but those will be fixed up
3844  * later.
3845  */
3846  if (RelationIsMapped(relation))
3847  {
3848  /* This case is only supported for indexes */
3849  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3850 
3851  /* Since we're not updating pg_class, these had better not change */
3852  Assert(classform->relfrozenxid == freezeXid);
3853  Assert(classform->relminmxid == minmulti);
3854  Assert(classform->relpersistence == persistence);
3855 
3856  /*
3857  * In some code paths it's possible that the tuple update we'd
3858  * otherwise do here is the only thing that would assign an XID for
3859  * the current transaction. However, we must have an XID to delete
3860  * files, so make sure one is assigned.
3861  */
3862  (void) GetCurrentTransactionId();
3863 
3864  /* Do the deed */
3866  newrelfilenumber,
3867  relation->rd_rel->relisshared,
3868  false);
3869 
3870  /* Since we're not updating pg_class, must trigger inval manually */
3871  CacheInvalidateRelcache(relation);
3872  }
3873  else
3874  {
3875  /* Normal case, update the pg_class entry */
3876  classform->relfilenode = newrelfilenumber;
3877 
3878  /* relpages etc. never change for sequences */
3879  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3880  {
3881  classform->relpages = 0; /* it's empty until further notice */
3882  classform->reltuples = -1;
3883  classform->relallvisible = 0;
3884  }
3885  classform->relfrozenxid = freezeXid;
3886  classform->relminmxid = minmulti;
3887  classform->relpersistence = persistence;
3888 
3889  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3890  }
3891 
3892  heap_freetuple(tuple);
3893 
3894  table_close(pg_class, RowExclusiveLock);
3895 
3896  /*
3897  * Make the pg_class row change or relation map change visible. This will
3898  * cause the relcache entry to get updated, too.
3899  */
3901 
3903 }
TransactionId MultiXactId
Definition: c.h:649
uint32 TransactionId
Definition: c.h:639
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
bool IsBinaryUpgrade
Definition: globals.c:118
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:82
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:85
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3918
Oid RelFileNumber
Definition: relpath.h:25
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:198
void smgrclose(SMgrRelation reln)
Definition: smgr.c:320
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:462
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
void RelationDropStorage(Relation rel)
Definition: storage.c:206
ItemPointerData t_self
Definition: htup.h:65
RelFileNumber relNumber
RelFileLocator rd_locator
Definition: rel.h:57
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1611
#define InvalidTransactionId
Definition: transam.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1079
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:446

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, 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, SearchSysCacheCopy1, smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), and table_relation_set_new_filelocator().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt