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

3389 {
3390  HASH_SEQ_STATUS status;
3391  RelIdCacheEnt *idhentry;
3392  int i;
3393 
3394  /*
3395  * Forget in_progress_list. This is relevant when we're aborting due to
3396  * an error during RelationBuildDesc(). We don't commit subtransactions
3397  * during RelationBuildDesc().
3398  */
3399  Assert(in_progress_list_len == 0 || !isCommit);
3401 
3402  /*
3403  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3404  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3405  * logic as in AtEOXact_RelationCache.
3406  */
3408  {
3409  hash_seq_init(&status, RelationIdCache);
3410  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3411  {
3412  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3413  mySubid, parentSubid);
3414  }
3415  }
3416  else
3417  {
3418  for (i = 0; i < eoxact_list_len; i++)
3419  {
3420  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3421  &eoxact_list[i],
3422  HASH_FIND,
3423  NULL);
3424  if (idhentry != NULL)
3425  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3426  mySubid, parentSubid);
3427  }
3428  }
3429 
3430  /* Don't reset the list; we still need more cleanup later */
3431 }
#define Assert(condition)
Definition: c.h:849
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:1420
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
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:3442
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 3235 of file relcache.c.

3236 {
3237  HASH_SEQ_STATUS status;
3238  RelIdCacheEnt *idhentry;
3239  int i;
3240 
3241  /*
3242  * Forget in_progress_list. This is relevant when we're aborting due to
3243  * an error during RelationBuildDesc().
3244  */
3245  Assert(in_progress_list_len == 0 || !isCommit);
3247 
3248  /*
3249  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3250  * listed in it. Otherwise fall back on a hash_seq_search scan.
3251  *
3252  * For simplicity, eoxact_list[] entries are not deleted till end of
3253  * top-level transaction, even though we could remove them at
3254  * subtransaction end in some cases, or remove relations from the list if
3255  * they are cleared for other reasons. Therefore we should expect the
3256  * case that list entries are not found in the hashtable; if not, there's
3257  * nothing to do for them.
3258  */
3260  {
3261  hash_seq_init(&status, RelationIdCache);
3262  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3263  {
3264  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3265  }
3266  }
3267  else
3268  {
3269  for (i = 0; i < eoxact_list_len; i++)
3270  {
3271  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3272  &eoxact_list[i],
3273  HASH_FIND,
3274  NULL);
3275  if (idhentry != NULL)
3276  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3277  }
3278  }
3279 
3280  if (EOXactTupleDescArrayLen > 0)
3281  {
3282  Assert(EOXactTupleDescArray != NULL);
3283  for (i = 0; i < NextEOXactTupleDescNum; i++)
3286  EOXactTupleDescArray = NULL;
3287  }
3288 
3289  /* Now we're out of the transaction and can clear the lists */
3290  eoxact_list_len = 0;
3291  eoxact_list_overflowed = false;
3294 }
void pfree(void *pointer)
Definition: mcxt.c:1521
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:3305
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 5961 of file relcache.c.

5962 {
5966 
5967  return 0; /* return value does not matter */
5968 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#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 5978 of file relcache.c.

5979 {
5980  TupleDesc reldesc = RelationGetDescr(rel);
5981  const char *colname;
5982 
5983  /* Use reldesc if it's a user attribute, else consult the catalogs */
5984  if (attnum > 0 && attnum <= reldesc->natts)
5985  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5986  else
5987  colname = get_attname(RelationGetRelid(rel), attnum, false);
5988 
5989  return errtablecolname(rel, colname);
5990 }
#define NameStr(name)
Definition: c.h:737
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:6002
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 6002 of file relcache.c.

6003 {
6004  errtable(rel);
6006 
6007  return 0; /* return value does not matter */
6008 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5961

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

3970 {
3974 
3975  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3976  EOXactListAdd(relation);
3977 }
#define InvalidSubTransactionId
Definition: c.h:649
#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:790

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

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

5733 {
5734  List *puboids;
5735  ListCell *lc;
5736  MemoryContext oldcxt;
5737  Oid schemaid;
5738  List *ancestors = NIL;
5739  Oid relid = RelationGetRelid(relation);
5740 
5741  /*
5742  * If not publishable, it publishes no actions. (pgoutput_change() will
5743  * ignore it.)
5744  */
5745  if (!is_publishable_relation(relation))
5746  {
5747  memset(pubdesc, 0, sizeof(PublicationDesc));
5748  pubdesc->rf_valid_for_update = true;
5749  pubdesc->rf_valid_for_delete = true;
5750  pubdesc->cols_valid_for_update = true;
5751  pubdesc->cols_valid_for_delete = true;
5752  return;
5753  }
5754 
5755  if (relation->rd_pubdesc)
5756  {
5757  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5758  return;
5759  }
5760 
5761  memset(pubdesc, 0, sizeof(PublicationDesc));
5762  pubdesc->rf_valid_for_update = true;
5763  pubdesc->rf_valid_for_delete = true;
5764  pubdesc->cols_valid_for_update = true;
5765  pubdesc->cols_valid_for_delete = true;
5766 
5767  /* Fetch the publication membership info. */
5768  puboids = GetRelationPublications(relid);
5769  schemaid = RelationGetNamespace(relation);
5770  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5771 
5772  if (relation->rd_rel->relispartition)
5773  {
5774  /* Add publications that the ancestors are in too. */
5775  ancestors = get_partition_ancestors(relid);
5776 
5777  foreach(lc, ancestors)
5778  {
5779  Oid ancestor = lfirst_oid(lc);
5780 
5781  puboids = list_concat_unique_oid(puboids,
5782  GetRelationPublications(ancestor));
5783  schemaid = get_rel_namespace(ancestor);
5784  puboids = list_concat_unique_oid(puboids,
5785  GetSchemaPublications(schemaid));
5786  }
5787  }
5788  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5789 
5790  foreach(lc, puboids)
5791  {
5792  Oid pubid = lfirst_oid(lc);
5793  HeapTuple tup;
5794  Form_pg_publication pubform;
5795 
5796  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5797 
5798  if (!HeapTupleIsValid(tup))
5799  elog(ERROR, "cache lookup failed for publication %u", pubid);
5800 
5801  pubform = (Form_pg_publication) GETSTRUCT(tup);
5802 
5803  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5804  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5805  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5806  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5807 
5808  /*
5809  * Check if all columns referenced in the filter expression are part
5810  * of the REPLICA IDENTITY index or not.
5811  *
5812  * If the publication is FOR ALL TABLES then it means the table has no
5813  * row filters and we can skip the validation.
5814  */
5815  if (!pubform->puballtables &&
5816  (pubform->pubupdate || pubform->pubdelete) &&
5817  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5818  pubform->pubviaroot))
5819  {
5820  if (pubform->pubupdate)
5821  pubdesc->rf_valid_for_update = false;
5822  if (pubform->pubdelete)
5823  pubdesc->rf_valid_for_delete = false;
5824  }
5825 
5826  /*
5827  * Check if all columns are part of the REPLICA IDENTITY index or not.
5828  *
5829  * If the publication is FOR ALL TABLES then it means the table has no
5830  * column list and we can skip the validation.
5831  */
5832  if (!pubform->puballtables &&
5833  (pubform->pubupdate || pubform->pubdelete) &&
5834  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5835  pubform->pubviaroot))
5836  {
5837  if (pubform->pubupdate)
5838  pubdesc->cols_valid_for_update = false;
5839  if (pubform->pubdelete)
5840  pubdesc->cols_valid_for_delete = false;
5841  }
5842 
5843  ReleaseSysCache(tup);
5844 
5845  /*
5846  * If we know everything is replicated and the row filter is invalid
5847  * for update and delete, there is no point to check for other
5848  * publications.
5849  */
5850  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5851  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5852  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5853  break;
5854 
5855  /*
5856  * If we know everything is replicated and the column list is invalid
5857  * for update and delete, there is no point to check for other
5858  * publications.
5859  */
5860  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5861  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5862  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5863  break;
5864  }
5865 
5866  if (relation->rd_pubdesc)
5867  {
5868  pfree(relation->rd_pubdesc);
5869  relation->rd_pubdesc = NULL;
5870  }
5871 
5872  /* Now save copy of the descriptor in the relcache entry. */
5874  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5875  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5876  MemoryContextSwitchTo(oldcxt);
5877 }
#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:1952
void * palloc(Size size)
Definition: mcxt.c:1317
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:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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

6796 {
6797  LWLockRelease(RelCacheInitLock);
6798 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6770 of file relcache.c.

6771 {
6772  char localinitfname[MAXPGPATH];
6773  char sharedinitfname[MAXPGPATH];
6774 
6775  if (DatabasePath)
6776  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6778  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6780 
6781  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6782 
6783  /*
6784  * The files might not be there if no backend has been started since the
6785  * last removal. But complain about failures other than ENOENT with
6786  * ERROR. Fortunately, it's not too late to abort the transaction if we
6787  * can't get rid of the would-be-obsolete init file.
6788  */
6789  if (DatabasePath)
6790  unlink_initfile(localinitfname, ERROR);
6791  unlink_initfile(sharedinitfname, ERROR);
6792 }
char * DatabasePath
Definition: globals.c:103
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define MAXPGPATH
#define snprintf
Definition: port.h:238
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6867
#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 6810 of file relcache.c.

6811 {
6812  const char *tblspcdir = PG_TBLSPC_DIR;
6813  DIR *dir;
6814  struct dirent *de;
6815  char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6816 
6817  snprintf(path, sizeof(path), "global/%s",
6819  unlink_initfile(path, LOG);
6820 
6821  /* Scan everything in the default tablespace */
6823 
6824  /* Scan the tablespace link directory to find non-default tablespaces */
6825  dir = AllocateDir(tblspcdir);
6826 
6827  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6828  {
6829  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6830  {
6831  /* Scan the tablespace dir for per-database dirs */
6832  snprintf(path, sizeof(path), "%s/%s/%s",
6833  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6835  }
6836  }
6837 
6838  FreeDir(dir);
6839 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2984
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2947
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2866
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6843
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3995 of file relcache.c.

3996 {
3997  HASHCTL ctl;
3998  int allocsize;
3999 
4000  /*
4001  * make sure cache memory context exists
4002  */
4003  if (!CacheMemoryContext)
4005 
4006  /*
4007  * create hashtable that indexes the relcache
4008  */
4009  ctl.keysize = sizeof(Oid);
4010  ctl.entrysize = sizeof(RelIdCacheEnt);
4011  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4012  &ctl, HASH_ELEM | HASH_BLOBS);
4013 
4014  /*
4015  * reserve enough in_progress_list slots for many cases
4016  */
4017  allocsize = 4;
4020  allocsize * sizeof(*in_progress_list));
4021  in_progress_list_maxlen = allocsize;
4022 
4023  /*
4024  * relation mapper needs to be initialized too
4025  */
4027 }
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:1181
tree ctl
Definition: radixtree.h:1853
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3992
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:170
void RelationMapInitialize(void)
Definition: relmapper.c:651

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 4041 of file relcache.c.

4042 {
4043  MemoryContext oldcxt;
4044 
4045  /*
4046  * relation mapper needs initialized too
4047  */
4049 
4050  /*
4051  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4052  * nothing.
4053  */
4055  return;
4056 
4057  /*
4058  * switch to cache memory context
4059  */
4061 
4062  /*
4063  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4064  * the cache with pre-made descriptors for the critical shared catalogs.
4065  */
4066  if (!load_relcache_init_file(true))
4067  {
4068  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4069  Natts_pg_database, Desc_pg_database);
4070  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4071  Natts_pg_authid, Desc_pg_authid);
4072  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4073  Natts_pg_auth_members, Desc_pg_auth_members);
4074  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4075  Natts_pg_shseclabel, Desc_pg_shseclabel);
4076  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4077  Natts_pg_subscription, Desc_pg_subscription);
4078 
4079 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4080  }
4081 
4082  MemoryContextSwitchTo(oldcxt);
4083 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6079
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:1873
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 4100 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 3011 of file relcache.c.

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

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(), RelationCloseSmgr(), RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, and smgrreleaseall().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2955 of file relcache.c.

2956 {
2957  Relation relation;
2958 
2959  RelationIdCacheLookup(relationId, relation);
2960 
2961  if (PointerIsValid(relation))
2962  {
2964  RelationFlushRelation(relation);
2965  }
2966  else
2967  {
2968  int i;
2969 
2970  for (i = 0; i < in_progress_list_len; i++)
2971  if (in_progress_list[i].reloid == relationId)
2972  in_progress_list[i].invalidated = true;
2973  }
2974 }
#define PointerIsValid(pointer)
Definition: c.h:754
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2864
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 2192 of file relcache.c.

2193 {
2194  /* Note: no locking manipulations needed */
2196 
2197  RelationCloseCleanup(relation);
2198 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2201

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

2912 {
2913  Relation relation;
2914 
2915  RelationIdCacheLookup(rid, relation);
2916 
2917  if (!PointerIsValid(relation))
2918  return; /* not in cache, nothing to do */
2919 
2920  if (!RelationHasReferenceCountZero(relation))
2921  elog(ERROR, "relation %u is still open", rid);
2922 
2924  if (relation->rd_createSubid != InvalidSubTransactionId ||
2926  {
2927  /*
2928  * In the event of subtransaction rollback, we must not forget
2929  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2930  * invalidates it in lieu of destroying it. (If we're in a top
2931  * transaction, we could opt to destroy the entry.)
2932  */
2934  }
2935 
2936  RelationClearRelation(relation, false);
2937 }

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

5101 {
5102  List *result;
5103  Datum exprsDatum;
5104  bool isnull;
5105  char *exprsString;
5106  List *rawExprs;
5107  ListCell *lc;
5108 
5109  /* Quick exit if there is nothing to do. */
5110  if (relation->rd_indextuple == NULL ||
5111  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5112  return NIL;
5113 
5114  /* Extract raw node tree(s) from index tuple. */
5115  exprsDatum = heap_getattr(relation->rd_indextuple,
5116  Anum_pg_index_indexprs,
5118  &isnull);
5119  Assert(!isnull);
5120  exprsString = TextDatumGetCString(exprsDatum);
5121  rawExprs = (List *) stringToNode(exprsString);
5122  pfree(exprsString);
5123 
5124  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5125  result = NIL;
5126  foreach(lc, rawExprs)
5127  {
5128  Node *rawExpr = (Node *) lfirst(lc);
5129 
5130  result = lappend(result,
5131  makeConst(exprType(rawExpr),
5132  exprTypmod(rawExpr),
5133  exprCollation(rawExpr),
5134  1,
5135  (Datum) 0,
5136  true,
5137  true));
5138  }
5139 
5140  return result;
5141 }
#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:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
uintptr_t Datum
Definition: postgres.h:64
void * stringToNode(const char *str)
Definition: read.c:90
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4466
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 5597 of file relcache.c.

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

4696 {
4697  List *result;
4698  Relation conrel;
4699  SysScanDesc conscan;
4700  ScanKeyData skey;
4701  HeapTuple htup;
4702  List *oldlist;
4703  MemoryContext oldcxt;
4704 
4705  /* Quick exit if we already computed the list. */
4706  if (relation->rd_fkeyvalid)
4707  return relation->rd_fkeylist;
4708 
4709  /* Fast path: non-partitioned tables without triggers can't have FKs */
4710  if (!relation->rd_rel->relhastriggers &&
4711  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4712  return NIL;
4713 
4714  /*
4715  * We build the list we intend to return (in the caller's context) while
4716  * doing the scan. After successfully completing the scan, we copy that
4717  * list into the relcache entry. This avoids cache-context memory leakage
4718  * if we get some sort of error partway through.
4719  */
4720  result = NIL;
4721 
4722  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4723  ScanKeyInit(&skey,
4724  Anum_pg_constraint_conrelid,
4725  BTEqualStrategyNumber, F_OIDEQ,
4726  ObjectIdGetDatum(RelationGetRelid(relation)));
4727 
4728  conrel = table_open(ConstraintRelationId, AccessShareLock);
4729  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4730  NULL, 1, &skey);
4731 
4732  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4733  {
4734  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4735  ForeignKeyCacheInfo *info;
4736 
4737  /* consider only foreign keys */
4738  if (constraint->contype != CONSTRAINT_FOREIGN)
4739  continue;
4740 
4741  info = makeNode(ForeignKeyCacheInfo);
4742  info->conoid = constraint->oid;
4743  info->conrelid = constraint->conrelid;
4744  info->confrelid = constraint->confrelid;
4745 
4746  DeconstructFkConstraintRow(htup, &info->nkeys,
4747  info->conkey,
4748  info->confkey,
4749  info->conpfeqop,
4750  NULL, NULL, NULL, NULL);
4751 
4752  /* Add FK's node to the result list */
4753  result = lappend(result, info);
4754  }
4755 
4756  systable_endscan(conscan);
4757  table_close(conrel, AccessShareLock);
4758 
4759  /* Now save a copy of the completed list in the relcache entry. */
4761  oldlist = relation->rd_fkeylist;
4762  relation->rd_fkeylist = copyObject(result);
4763  relation->rd_fkeyvalid = true;
4764  MemoryContextSwitchTo(oldcxt);
4765 
4766  /* Don't leak the old list, if there is one */
4767  list_free_deep(oldlist);
4768 
4769  return result;
4770 }
void list_free_deep(List *list)
Definition: list.c:1560
#define copyObject(obj)
Definition: nodes.h:224
#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 5520 of file relcache.c.

5521 {
5522  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5523  Relation indexDesc;
5524  int i;
5525  Oid replidindex;
5526  MemoryContext oldcxt;
5527 
5528  /* Quick exit if we already computed the result */
5529  if (relation->rd_idattr != NULL)
5530  return bms_copy(relation->rd_idattr);
5531 
5532  /* Fast path if definitely no indexes */
5533  if (!RelationGetForm(relation)->relhasindex)
5534  return NULL;
5535 
5536  /* Historic snapshot must be set. */
5538 
5539  replidindex = RelationGetReplicaIndex(relation);
5540 
5541  /* Fall out if there is no replica identity index */
5542  if (!OidIsValid(replidindex))
5543  return NULL;
5544 
5545  /* Look up the description for the replica identity index */
5546  indexDesc = RelationIdGetRelation(replidindex);
5547 
5548  if (!RelationIsValid(indexDesc))
5549  elog(ERROR, "could not open relation with OID %u",
5550  relation->rd_replidindex);
5551 
5552  /* Add referenced attributes to idindexattrs */
5553  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5554  {
5555  int attrnum = indexDesc->rd_index->indkey.values[i];
5556 
5557  /*
5558  * We don't include non-key columns into idindexattrs bitmaps. See
5559  * RelationGetIndexAttrBitmap.
5560  */
5561  if (attrnum != 0)
5562  {
5563  if (i < indexDesc->rd_index->indnkeyatts)
5564  idindexattrs = bms_add_member(idindexattrs,
5566  }
5567  }
5568 
5569  RelationClose(indexDesc);
5570 
5571  /* Don't leak the old values of these bitmaps, if any */
5572  bms_free(relation->rd_idattr);
5573  relation->rd_idattr = NULL;
5574 
5575  /* Now save copy of the bitmap in the relcache entry */
5577  relation->rd_idattr = bms_copy(idindexattrs);
5578  MemoryContextSwitchTo(oldcxt);
5579 
5580  /* We return our original working copy for caller to play with */
5581  return idindexattrs;
5582 }
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:766
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationIsValid(relation)
Definition: rel.h:478
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:5016
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2061
void RelationClose(Relation relation)
Definition: relcache.c:2192
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 5900 of file relcache.c.

5901 {
5902  MemoryContext oldcxt;
5903  bytea **opts = relation->rd_opcoptions;
5904  Oid relid = RelationGetRelid(relation);
5905  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5906  * IndexRelationGetNumberOfKeyAttributes */
5907  int i;
5908 
5909  /* Try to copy cached options. */
5910  if (opts)
5911  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5912 
5913  /* Get and parse opclass options. */
5914  opts = palloc0(sizeof(*opts) * natts);
5915 
5916  for (i = 0; i < natts; i++)
5917  {
5918  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5919  {
5920  Datum attoptions = get_attoptions(relid, i + 1);
5921 
5922  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5923 
5924  if (attoptions != (Datum) 0)
5925  pfree(DatumGetPointer(attoptions));
5926  }
5927  }
5928 
5929  /* Copy parsed options to the cache. */
5930  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5931  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5932  MemoryContextSwitchTo(oldcxt);
5933 
5934  if (copy)
5935  return opts;
5936 
5937  for (i = 0; i < natts; i++)
5938  {
5939  if (opts[i])
5940  pfree(opts[i]);
5941  }
5942 
5943  pfree(opts);
5944 
5945  return relation->rd_opcoptions;
5946 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:998
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:5880
bytea ** rd_opcoptions
Definition: rel.h:218
Definition: c.h:678

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

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

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

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

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5041 of file relcache.c.

5042 {
5043  List *result;
5044  Datum exprsDatum;
5045  bool isnull;
5046  char *exprsString;
5047  MemoryContext oldcxt;
5048 
5049  /* Quick exit if we already computed the result. */
5050  if (relation->rd_indexprs)
5051  return copyObject(relation->rd_indexprs);
5052 
5053  /* Quick exit if there is nothing to do. */
5054  if (relation->rd_indextuple == NULL ||
5055  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5056  return NIL;
5057 
5058  /*
5059  * We build the tree we intend to return in the caller's context. After
5060  * successfully completing the work, we copy it into the relcache entry.
5061  * This avoids problems if we get some sort of error partway through.
5062  */
5063  exprsDatum = heap_getattr(relation->rd_indextuple,
5064  Anum_pg_index_indexprs,
5066  &isnull);
5067  Assert(!isnull);
5068  exprsString = TextDatumGetCString(exprsDatum);
5069  result = (List *) stringToNode(exprsString);
5070  pfree(exprsString);
5071 
5072  /*
5073  * Run the expressions through eval_const_expressions. This is not just an
5074  * optimization, but is necessary, because the planner will be comparing
5075  * them to similarly-processed qual clauses, and may fail to detect valid
5076  * matches without this. We must not use canonicalize_qual, however,
5077  * since these aren't qual expressions.
5078  */
5079  result = (List *) eval_const_expressions(NULL, (Node *) result);
5080 
5081  /* May as well fix opfuncids too */
5082  fix_opfuncids((Node *) result);
5083 
5084  /* Now save a copy of the completed tree in the relcache entry. */
5085  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5086  relation->rd_indexprs = copyObject(result);
5087  MemoryContextSwitchTo(oldcxt);
5088 
5089  return result;
5090 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1831
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(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4804 of file relcache.c.

4805 {
4806  Relation indrel;
4807  SysScanDesc indscan;
4808  ScanKeyData skey;
4809  HeapTuple htup;
4810  List *result;
4811  List *oldlist;
4812  char replident = relation->rd_rel->relreplident;
4813  Oid pkeyIndex = InvalidOid;
4814  Oid candidateIndex = InvalidOid;
4815  bool pkdeferrable = false;
4816  MemoryContext oldcxt;
4817 
4818  /* Quick exit if we already computed the list. */
4819  if (relation->rd_indexvalid)
4820  return list_copy(relation->rd_indexlist);
4821 
4822  /*
4823  * We build the list we intend to return (in the caller's context) while
4824  * doing the scan. After successfully completing the scan, we copy that
4825  * list into the relcache entry. This avoids cache-context memory leakage
4826  * if we get some sort of error partway through.
4827  */
4828  result = NIL;
4829 
4830  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4831  ScanKeyInit(&skey,
4832  Anum_pg_index_indrelid,
4833  BTEqualStrategyNumber, F_OIDEQ,
4834  ObjectIdGetDatum(RelationGetRelid(relation)));
4835 
4836  indrel = table_open(IndexRelationId, AccessShareLock);
4837  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4838  NULL, 1, &skey);
4839 
4840  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4841  {
4843 
4844  /*
4845  * Ignore any indexes that are currently being dropped. This will
4846  * prevent them from being searched, inserted into, or considered in
4847  * HOT-safety decisions. It's unsafe to touch such an index at all
4848  * since its catalog entries could disappear at any instant.
4849  */
4850  if (!index->indislive)
4851  continue;
4852 
4853  /* add index's OID to result list */
4854  result = lappend_oid(result, index->indexrelid);
4855 
4856  /*
4857  * Invalid, non-unique, non-immediate or predicate indexes aren't
4858  * interesting for either oid indexes or replication identity indexes,
4859  * so don't check them.
4860  */
4861  if (!index->indisvalid || !index->indisunique ||
4862  !index->indimmediate ||
4863  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4864  continue;
4865 
4866  /* remember primary key index if any */
4867  if (index->indisprimary)
4868  pkeyIndex = index->indexrelid;
4869 
4870  /* remember explicitly chosen replica index */
4871  if (index->indisreplident)
4872  candidateIndex = index->indexrelid;
4873  }
4874 
4875  systable_endscan(indscan);
4876 
4877  table_close(indrel, AccessShareLock);
4878 
4879  /* Sort the result list into OID order, per API spec. */
4880  list_sort(result, list_oid_cmp);
4881 
4882  /* Now save a copy of the completed list in the relcache entry. */
4884  oldlist = relation->rd_indexlist;
4885  relation->rd_indexlist = list_copy(result);
4886  relation->rd_pkindex = pkeyIndex;
4887  relation->rd_ispkdeferrable = pkdeferrable;
4888  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4889  relation->rd_replidindex = pkeyIndex;
4890  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4891  relation->rd_replidindex = candidateIndex;
4892  else
4893  relation->rd_replidindex = InvalidOid;
4894  relation->rd_indexvalid = true;
4895  MemoryContextSwitchTo(oldcxt);
4896 
4897  /* Don't leak the old list, if there is one */
4898  list_free(oldlist);
4899 
4900  return result;
4901 }
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(), ATExecDropNotNull(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), RefreshMatViewByOid(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5154 of file relcache.c.

5155 {
5156  List *result;
5157  Datum predDatum;
5158  bool isnull;
5159  char *predString;
5160  MemoryContext oldcxt;
5161 
5162  /* Quick exit if we already computed the result. */
5163  if (relation->rd_indpred)
5164  return copyObject(relation->rd_indpred);
5165 
5166  /* Quick exit if there is nothing to do. */
5167  if (relation->rd_indextuple == NULL ||
5168  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5169  return NIL;
5170 
5171  /*
5172  * We build the tree we intend to return in the caller's context. After
5173  * successfully completing the work, we copy it into the relcache entry.
5174  * This avoids problems if we get some sort of error partway through.
5175  */
5176  predDatum = heap_getattr(relation->rd_indextuple,
5177  Anum_pg_index_indpred,
5179  &isnull);
5180  Assert(!isnull);
5181  predString = TextDatumGetCString(predDatum);
5182  result = (List *) stringToNode(predString);
5183  pfree(predString);
5184 
5185  /*
5186  * Run the expression through const-simplification and canonicalization.
5187  * This is not just an optimization, but is necessary, because the planner
5188  * will be comparing it to similarly-processed qual clauses, and may fail
5189  * to detect valid matches without this. This must match the processing
5190  * done to qual clauses in preprocess_expression()! (We can skip the
5191  * stuff involving subqueries, however, since we don't allow any in index
5192  * predicates.)
5193  */
5194  result = (List *) eval_const_expressions(NULL, (Node *) result);
5195 
5196  result = (List *) canonicalize_qual((Expr *) result, false);
5197 
5198  /* Also convert to implicit-AND format */
5199  result = make_ands_implicit((Expr *) result);
5200 
5201  /* May as well fix opfuncids too */
5202  fix_opfuncids((Node *) result);
5203 
5204  /* Now save a copy of the completed tree in the relcache entry. */
5205  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5206  relation->rd_indpred = copyObject(result);
5207  MemoryContextSwitchTo(oldcxt);
5208 
5209  return result;
5210 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:737
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
List * rd_indpred
Definition: rel.h:213

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

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4995 of file relcache.c.

4996 {
4997  List *ilist;
4998 
4999  if (!relation->rd_indexvalid)
5000  {
5001  /* RelationGetIndexList does the heavy lifting. */
5002  ilist = RelationGetIndexList(relation);
5003  list_free(ilist);
5004  Assert(relation->rd_indexvalid);
5005  }
5006 
5007  return relation->rd_ispkdeferrable ? InvalidOid : relation->rd_pkindex;
5008 }

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

5017 {
5018  List *ilist;
5019 
5020  if (!relation->rd_indexvalid)
5021  {
5022  /* RelationGetIndexList does the heavy lifting. */
5023  ilist = RelationGetIndexList(relation);
5024  list_free(ilist);
5025  Assert(relation->rd_indexvalid);
5026  }
5027 
5028  return relation->rd_replidindex;
5029 }

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

4926 {
4927  Relation indrel;
4928  SysScanDesc indscan;
4929  ScanKeyData skey;
4930  HeapTuple htup;
4931  List *result;
4932  List *oldlist;
4933  MemoryContext oldcxt;
4934 
4935  /* Quick exit if we already computed the list. */
4936  if (relation->rd_statvalid != 0)
4937  return list_copy(relation->rd_statlist);
4938 
4939  /*
4940  * We build the list we intend to return (in the caller's context) while
4941  * doing the scan. After successfully completing the scan, we copy that
4942  * list into the relcache entry. This avoids cache-context memory leakage
4943  * if we get some sort of error partway through.
4944  */
4945  result = NIL;
4946 
4947  /*
4948  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4949  * rel.
4950  */
4951  ScanKeyInit(&skey,
4952  Anum_pg_statistic_ext_stxrelid,
4953  BTEqualStrategyNumber, F_OIDEQ,
4954  ObjectIdGetDatum(RelationGetRelid(relation)));
4955 
4956  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4957  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4958  NULL, 1, &skey);
4959 
4960  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4961  {
4962  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4963 
4964  result = lappend_oid(result, oid);
4965  }
4966 
4967  systable_endscan(indscan);
4968 
4969  table_close(indrel, AccessShareLock);
4970 
4971  /* Sort the result list into OID order, per API spec. */
4972  list_sort(result, list_oid_cmp);
4973 
4974  /* Now save a copy of the completed list in the relcache entry. */
4976  oldlist = relation->rd_statlist;
4977  relation->rd_statlist = list_copy(result);
4978 
4979  relation->rd_statvalid = true;
4980  MemoryContextSwitchTo(oldcxt);
4981 
4982  /* Don't leak the old list, if there is one */
4983  list_free(oldlist);
4984 
4985  return result;
4986 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:66
List * rd_statlist
Definition: rel.h:158

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

Referenced by expandTableLikeClause(), and get_relation_statistics().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2061 of file relcache.c.

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

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

6731 {
6732  if (relationId == SharedSecLabelRelationId ||
6733  relationId == TriggerRelidNameIndexId ||
6734  relationId == DatabaseNameIndexId ||
6735  relationId == SharedSecLabelObjectIndexId)
6736  {
6737  /*
6738  * If this Assert fails, we don't need the applicable special case
6739  * anymore.
6740  */
6741  Assert(!RelationSupportsSysCache(relationId));
6742  return true;
6743  }
6744  return RelationSupportsSysCache(relationId);
6745 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:766

References Assert, and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1424 of file relcache.c.

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

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

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

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

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

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

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt