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:858
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
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 5952 of file relcache.c.

5953 {
5957 
5958  return 0; /* return value does not matter */
5959 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1510
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(), ExecPartitionCheckEmitError(), and moveSplitTableRows().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5969 of file relcache.c.

5970 {
5971  TupleDesc reldesc = RelationGetDescr(rel);
5972  const char *colname;
5973 
5974  /* Use reldesc if it's a user attribute, else consult the catalogs */
5975  if (attnum > 0 && attnum <= reldesc->natts)
5976  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5977  else
5978  colname = get_attname(RelationGetRelid(rel), attnum, false);
5979 
5980  return errtablecolname(rel, colname);
5981 }
#define NameStr(name)
Definition: c.h:746
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:5993
#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 5993 of file relcache.c.

5994 {
5995  errtable(rel);
5997 
5998  return 0; /* return value does not matter */
5999 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5952

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

3967 {
3971 
3972  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3973  EOXactListAdd(relation);
3974 }
#define InvalidSubTransactionId
Definition: c.h:658
#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:789

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:203
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:264
void CreateCacheMemoryContext(void)
Definition: catcache.c:680
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
void * palloc0(Size size)
Definition: mcxt.c: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:3658
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:319
#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 5723 of file relcache.c.

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

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6786 of file relcache.c.

6787 {
6788  LWLockRelease(RelCacheInitLock);
6789 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6761 of file relcache.c.

6762 {
6763  char localinitfname[MAXPGPATH];
6764  char sharedinitfname[MAXPGPATH];
6765 
6766  if (DatabasePath)
6767  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6769  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6771 
6772  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6773 
6774  /*
6775  * The files might not be there if no backend has been started since the
6776  * last removal. But complain about failures other than ENOENT with
6777  * ERROR. Fortunately, it's not too late to abort the transaction if we
6778  * can't get rid of the would-be-obsolete init file.
6779  */
6780  if (DatabasePath)
6781  unlink_initfile(localinitfname, ERROR);
6782  unlink_initfile(sharedinitfname, ERROR);
6783 }
char * DatabasePath
Definition: globals.c:102
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:6858
#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 6801 of file relcache.c.

6802 {
6803  const char *tblspcdir = "pg_tblspc";
6804  DIR *dir;
6805  struct dirent *de;
6806  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6807 
6808  snprintf(path, sizeof(path), "global/%s",
6810  unlink_initfile(path, LOG);
6811 
6812  /* Scan everything in the default tablespace */
6814 
6815  /* Scan the tablespace link directory to find non-default tablespaces */
6816  dir = AllocateDir(tblspcdir);
6817 
6818  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6819  {
6820  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6821  {
6822  /* Scan the tablespace dir for per-database dirs */
6823  snprintf(path, sizeof(path), "%s/%s/%s",
6824  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6826  }
6827  }
6828 
6829  FreeDir(dir);
6830 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2961
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2924
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6834
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3992 of file relcache.c.

3993 {
3994  HASHCTL ctl;
3995  int allocsize;
3996 
3997  /*
3998  * make sure cache memory context exists
3999  */
4000  if (!CacheMemoryContext)
4002 
4003  /*
4004  * create hashtable that indexes the relcache
4005  */
4006  ctl.keysize = sizeof(Oid);
4007  ctl.entrysize = sizeof(RelIdCacheEnt);
4008  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4009  &ctl, HASH_ELEM | HASH_BLOBS);
4010 
4011  /*
4012  * reserve enough in_progress_list slots for many cases
4013  */
4014  allocsize = 4;
4017  allocsize * sizeof(*in_progress_list));
4018  in_progress_list_maxlen = allocsize;
4019 
4020  /*
4021  * relation mapper needs to be initialized too
4022  */
4024 }
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:3989
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 4038 of file relcache.c.

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

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

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, 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:353

References Assert, hash_seq_init(), hash_seq_search(), i, in_progress_list, in_progress_list_len, InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationClearRelation(), 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:763
#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 5097 of file relcache.c.

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

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

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

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

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

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

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

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

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

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

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4801 of file relcache.c.

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

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5151 of file relcache.c.

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4992 of file relcache.c.

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

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

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

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

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

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

6722 {
6723  if (relationId == SharedSecLabelRelationId ||
6724  relationId == TriggerRelidNameIndexId ||
6725  relationId == DatabaseNameIndexId ||
6726  relationId == SharedSecLabelObjectIndexId)
6727  {
6728  /*
6729  * If this Assert fails, we don't need the applicable special case
6730  * anymore.
6731  */
6732  Assert(!RelationSupportsSysCache(relationId));
6733  return true;
6734  }
6735  return RelationSupportsSysCache(relationId);
6736 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:649

References Assert, and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 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:493
regproc RegProcedure
Definition: c.h:650
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:5891
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:220
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:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733

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

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

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt