PostgreSQL Source Code  git master
relcache.h File Reference
#include "access/tupdesc.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 }
 

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)
 
DatumRelationGetIndexRawAttOptions (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)
 
struct PublicationActionsGetRelationPublicationActions (Relation relation)
 
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, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence)
 
void RelationAssumeNewRelfilenode (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (bool debug_discard)
 
void RelationCloseSmgrByOid (Oid relationId)
 
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

bool criticalRelcachesBuilt
 
bool criticalSharedRelcachesBuilt
 

Macro Definition Documentation

◆ AssertPendingSyncs_RelationCache

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

Definition at line 132 of file relcache.h.

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Definition at line 24 of file relcache.h.

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

typedef struct RelationData* Relation

Definition at line 26 of file relcache.h.

◆ RelationPtr

Definition at line 34 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 

Definition at line 56 of file relcache.h.

57 {
IndexAttrBitmapKind
Definition: relcache.h:57
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:58
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:59
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:60

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3308 of file relcache.c.

3310 {
3312  RelIdCacheEnt *idhentry;
3313  int i;
3314 
3315  /*
3316  * Forget in_progress_list. This is relevant when we're aborting due to
3317  * an error during RelationBuildDesc(). We don't commit subtransactions
3318  * during RelationBuildDesc().
3319  */
3320  Assert(in_progress_list_len == 0 || !isCommit);
3322 
3323  /*
3324  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3325  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3326  * logic as in AtEOXact_RelationCache.
3327  */
3329  {
3331  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3332  {
3333  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3334  mySubid, parentSubid);
3335  }
3336  }
3337  else
3338  {
3339  for (i = 0; i < eoxact_list_len; i++)
3340  {
3341  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3342  (void *) &eoxact_list[i],
3343  HASH_FIND,
3344  NULL);
3345  if (idhentry != NULL)
3346  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3347  mySubid, parentSubid);
3348  }
3349  }
3350 
3351  /* Don't reset the list; we still need more cleanup later */
3352 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:182
static int in_progress_list_len
Definition: relcache.c:168
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3363
static int eoxact_list_len
Definition: relcache.c:183
static bool eoxact_list_overflowed
Definition: relcache.c:184
static HTAB * RelationIdCache
Definition: relcache.c:131
Relation reldesc
Definition: relcache.c:128

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, relidcacheent::reldesc, and status().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3156 of file relcache.c.

3157 {
3159  RelIdCacheEnt *idhentry;
3160  int i;
3161 
3162  /*
3163  * Forget in_progress_list. This is relevant when we're aborting due to
3164  * an error during RelationBuildDesc().
3165  */
3166  Assert(in_progress_list_len == 0 || !isCommit);
3168 
3169  /*
3170  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3171  * listed in it. Otherwise fall back on a hash_seq_search scan.
3172  *
3173  * For simplicity, eoxact_list[] entries are not deleted till end of
3174  * top-level transaction, even though we could remove them at
3175  * subtransaction end in some cases, or remove relations from the list if
3176  * they are cleared for other reasons. Therefore we should expect the
3177  * case that list entries are not found in the hashtable; if not, there's
3178  * nothing to do for them.
3179  */
3181  {
3183  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3184  {
3185  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3186  }
3187  }
3188  else
3189  {
3190  for (i = 0; i < eoxact_list_len; i++)
3191  {
3192  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3193  (void *) &eoxact_list[i],
3194  HASH_FIND,
3195  NULL);
3196  if (idhentry != NULL)
3197  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3198  }
3199  }
3200 
3201  if (EOXactTupleDescArrayLen > 0)
3202  {
3203  Assert(EOXactTupleDescArray != NULL);
3204  for (i = 0; i < NextEOXactTupleDescNum; i++)
3207  EOXactTupleDescArray = NULL;
3208  }
3209 
3210  /* Now we're out of the transaction and can clear the lists */
3211  eoxact_list_len = 0;
3212  eoxact_list_overflowed = false;
3215 }
void pfree(void *pointer)
Definition: mcxt.c:1169
static int NextEOXactTupleDescNum
Definition: relcache.c:200
static int EOXactTupleDescArrayLen
Definition: relcache.c:201
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3226
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:199
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309

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, relidcacheent::reldesc, and status().

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5753 of file relcache.c.

5754 {
5758 
5759  return 0; /* return value does not matter */
5760 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1351
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define RelationGetRelationName(relation)
Definition: rel.h:512
#define RelationGetNamespace(relation)
Definition: rel.h:519

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5770 of file relcache.c.

5771 {
5772  TupleDesc reldesc = RelationGetDescr(rel);
5773  const char *colname;
5774 
5775  /* Use reldesc if it's a user attribute, else consult the catalogs */
5776  if (attnum > 0 && attnum <= reldesc->natts)
5777  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5778  else
5779  colname = get_attname(RelationGetRelid(rel), attnum, false);
5780 
5781  return errtablecolname(rel, colname);
5782 }
#define NameStr(name)
Definition: c.h:681
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:83
#define RelationGetRelid(relation)
Definition: rel.h:478
#define RelationGetDescr(relation)
Definition: rel.h:504
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5794
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5794 of file relcache.c.

5795 {
5796  errtable(rel);
5798 
5799  return 0; /* return value does not matter */
5800 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int errtable(Relation rel)
Definition: relcache.c:5753

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5555 of file relcache.c.

5556 {
5557  List *puboids;
5558  ListCell *lc;
5559  MemoryContext oldcxt;
5560  Oid schemaid;
5561  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5562 
5563  /*
5564  * If not publishable, it publishes no actions. (pgoutput_change() will
5565  * ignore it.)
5566  */
5567  if (!is_publishable_relation(relation))
5568  return pubactions;
5569 
5570  if (relation->rd_pubactions)
5571  return memcpy(pubactions, relation->rd_pubactions,
5572  sizeof(PublicationActions));
5573 
5574  /* Fetch the publication membership info. */
5575  puboids = GetRelationPublications(RelationGetRelid(relation));
5576  schemaid = RelationGetNamespace(relation);
5577  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5578 
5579  if (relation->rd_rel->relispartition)
5580  {
5581  /* Add publications that the ancestors are in too. */
5582  List *ancestors = get_partition_ancestors(RelationGetRelid(relation));
5583  ListCell *lc;
5584 
5585  foreach(lc, ancestors)
5586  {
5587  Oid ancestor = lfirst_oid(lc);
5588 
5589  puboids = list_concat_unique_oid(puboids,
5590  GetRelationPublications(ancestor));
5591  schemaid = get_rel_namespace(ancestor);
5592  puboids = list_concat_unique_oid(puboids,
5593  GetSchemaPublications(schemaid));
5594  }
5595  }
5596  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5597 
5598  foreach(lc, puboids)
5599  {
5600  Oid pubid = lfirst_oid(lc);
5601  HeapTuple tup;
5602  Form_pg_publication pubform;
5603 
5605 
5606  if (!HeapTupleIsValid(tup))
5607  elog(ERROR, "cache lookup failed for publication %u", pubid);
5608 
5609  pubform = (Form_pg_publication) GETSTRUCT(tup);
5610 
5611  pubactions->pubinsert |= pubform->pubinsert;
5612  pubactions->pubupdate |= pubform->pubupdate;
5613  pubactions->pubdelete |= pubform->pubdelete;
5614  pubactions->pubtruncate |= pubform->pubtruncate;
5615 
5616  ReleaseSysCache(tup);
5617 
5618  /*
5619  * If we know everything is replicated, there is no point to check for
5620  * other publications.
5621  */
5622  if (pubactions->pubinsert && pubactions->pubupdate &&
5623  pubactions->pubdelete && pubactions->pubtruncate)
5624  break;
5625  }
5626 
5627  if (relation->rd_pubactions)
5628  {
5629  pfree(relation->rd_pubactions);
5630  relation->rd_pubactions = NULL;
5631  }
5632 
5633  /* Now save copy of the actions in the relcache entry. */
5635  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5636  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5637  MemoryContextSwitchTo(oldcxt);
5638 
5639  return pubactions;
5640 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1428
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1923
void * palloc0(Size size)
Definition: mcxt.c:1093
MemoryContext CacheMemoryContext
Definition: mcxt.c:51
void * palloc(Size size)
Definition: mcxt.c:1062
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
Definition: pg_list.h:51
PublicationActions * rd_pubactions
Definition: rel.h:164
Form_pg_class rd_rel
Definition: rel.h:109
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
@ PUBLICATIONOID
Definition: syscache.h:81

References CacheMemoryContext, elog, ERROR, get_partition_ancestors(), get_rel_namespace(), GetAllTablesPublications(), GetRelationPublications(), GetSchemaPublications(), GETSTRUCT, HeapTupleIsValid, is_publishable_relation(), lfirst_oid, list_concat_unique_oid(), MemoryContextSwitchTo(), ObjectIdGetDatum, palloc(), palloc0(), pfree(), PublicationActions::pubdelete, PublicationActions::pubinsert, PUBLICATIONOID, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubactions, RelationData::rd_rel, RelationGetNamespace, RelationGetRelid, ReleaseSysCache(), and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3842 of file relcache.c.

3843 {
3846  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3847 
3848  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3849  EOXactListAdd(relation);
3850 }
#define InvalidSubTransactionId
Definition: c.h:593
#define EOXactListAdd(rel)
Definition: relcache.c:186
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:775

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilenodeSubid, and RelationData::rd_newRelfilenodeSubid.

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

◆ RelationBuildLocalRelation()

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

Definition at line 3445 of file relcache.c.

3456 {
3457  Relation rel;
3458  MemoryContext oldcxt;
3459  int natts = tupDesc->natts;
3460  int i;
3461  bool has_not_null;
3462  bool nailit;
3463 
3464  AssertArg(natts >= 0);
3465 
3466  /*
3467  * check for creation of a rel that must be nailed in cache.
3468  *
3469  * XXX this list had better match the relations specially handled in
3470  * RelationCacheInitializePhase2/3.
3471  */
3472  switch (relid)
3473  {
3474  case DatabaseRelationId:
3475  case AuthIdRelationId:
3476  case AuthMemRelationId:
3477  case RelationRelationId:
3478  case AttributeRelationId:
3479  case ProcedureRelationId:
3480  case TypeRelationId:
3481  nailit = true;
3482  break;
3483  default:
3484  nailit = false;
3485  break;
3486  }
3487 
3488  /*
3489  * check that hardwired list of shared rels matches what's in the
3490  * bootstrap .bki file. If you get a failure here during initdb, you
3491  * probably need to fix IsSharedRelation() to match whatever you've done
3492  * to the set of shared relations.
3493  */
3494  if (shared_relation != IsSharedRelation(relid))
3495  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3496  relname, relid);
3497 
3498  /* Shared relations had better be mapped, too */
3499  Assert(mapped_relation || !shared_relation);
3500 
3501  /*
3502  * switch to the cache context to create the relcache entry.
3503  */
3504  if (!CacheMemoryContext)
3506 
3508 
3509  /*
3510  * allocate a new relation descriptor and fill in basic state fields.
3511  */
3512  rel = (Relation) palloc0(sizeof(RelationData));
3513 
3514  /* make sure relation is marked as having no open file yet */
3515  rel->rd_smgr = NULL;
3516 
3517  /* mark it nailed if appropriate */
3518  rel->rd_isnailed = nailit;
3519 
3520  rel->rd_refcnt = nailit ? 1 : 0;
3521 
3522  /* it's being created in this transaction */
3527 
3528  /*
3529  * create a new tuple descriptor from the one passed in. We do this
3530  * partly to copy it into the cache context, and partly because the new
3531  * relation can't have any defaults or constraints yet; they have to be
3532  * added in later steps, because they require additions to multiple system
3533  * catalogs. We can copy attnotnull constraints here, however.
3534  */
3535  rel->rd_att = CreateTupleDescCopy(tupDesc);
3536  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3537  has_not_null = false;
3538  for (i = 0; i < natts; i++)
3539  {
3540  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3541  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3542 
3543  datt->attidentity = satt->attidentity;
3544  datt->attgenerated = satt->attgenerated;
3545  datt->attnotnull = satt->attnotnull;
3546  has_not_null |= satt->attnotnull;
3547  }
3548 
3549  if (has_not_null)
3550  {
3551  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3552 
3553  constr->has_not_null = true;
3554  rel->rd_att->constr = constr;
3555  }
3556 
3557  /*
3558  * initialize relation tuple form (caller may add/override data later)
3559  */
3561 
3562  namestrcpy(&rel->rd_rel->relname, relname);
3563  rel->rd_rel->relnamespace = relnamespace;
3564 
3565  rel->rd_rel->relkind = relkind;
3566  rel->rd_rel->relnatts = natts;
3567  rel->rd_rel->reltype = InvalidOid;
3568  /* needed when bootstrapping: */
3569  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3570 
3571  /* set up persistence and relcache fields dependent on it */
3572  rel->rd_rel->relpersistence = relpersistence;
3573  switch (relpersistence)
3574  {
3575  case RELPERSISTENCE_UNLOGGED:
3576  case RELPERSISTENCE_PERMANENT:
3578  rel->rd_islocaltemp = false;
3579  break;
3580  case RELPERSISTENCE_TEMP:
3581  Assert(isTempOrTempToastNamespace(relnamespace));
3583  rel->rd_islocaltemp = true;
3584  break;
3585  default:
3586  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3587  break;
3588  }
3589 
3590  /* if it's a materialized view, it's not populated initially */
3591  if (relkind == RELKIND_MATVIEW)
3592  rel->rd_rel->relispopulated = false;
3593  else
3594  rel->rd_rel->relispopulated = true;
3595 
3596  /* set replica identity -- system catalogs and non-tables don't have one */
3597  if (!IsCatalogNamespace(relnamespace) &&
3598  (relkind == RELKIND_RELATION ||
3599  relkind == RELKIND_MATVIEW ||
3600  relkind == RELKIND_PARTITIONED_TABLE))
3601  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3602  else
3603  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3604 
3605  /*
3606  * Insert relation physical and logical identifiers (OIDs) into the right
3607  * places. For a mapped relation, we set relfilenode to zero and rely on
3608  * RelationInitPhysicalAddr to consult the map.
3609  */
3610  rel->rd_rel->relisshared = shared_relation;
3611 
3612  RelationGetRelid(rel) = relid;
3613 
3614  for (i = 0; i < natts; i++)
3615  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3616 
3617  rel->rd_rel->reltablespace = reltablespace;
3618 
3619  if (mapped_relation)
3620  {
3621  rel->rd_rel->relfilenode = InvalidOid;
3622  /* Add it to the active mapping information */
3623  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3624  }
3625  else
3626  rel->rd_rel->relfilenode = relfilenode;
3627 
3628  RelationInitLockInfo(rel); /* see lmgr.c */
3629 
3631 
3632  rel->rd_rel->relam = accessmtd;
3633 
3634  /*
3635  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3636  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3637  * require a long-lived current context.
3638  */
3639  MemoryContextSwitchTo(oldcxt);
3640 
3641  if (relkind == RELKIND_RELATION ||
3642  relkind == RELKIND_SEQUENCE ||
3643  relkind == RELKIND_TOASTVALUE ||
3644  relkind == RELKIND_MATVIEW)
3646 
3647  /*
3648  * Okay to insert into the relcache hash table.
3649  *
3650  * Ordinarily, there should certainly not be an existing hash entry for
3651  * the same OID; but during bootstrap, when we create a "real" relcache
3652  * entry for one of the bootstrap relations, we'll be overwriting the
3653  * phony one created with formrdesc. So allow that to happen for nailed
3654  * rels.
3655  */
3656  RelationCacheInsert(rel, nailit);
3657 
3658  /*
3659  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3660  * can't do this before storing relid in it.
3661  */
3662  EOXactListAdd(rel);
3663 
3664  /* It's fully valid */
3665  rel->rd_isvalid = true;
3666 
3667  /*
3668  * Caller expects us to pin the returned entry.
3669  */
3671 
3672  return rel;
3673 }
#define BackendIdForTempRelations()
Definition: backendid.h:34
#define InvalidBackendId
Definition: backendid.h:23
#define AssertArg(condition)
Definition: c.h:806
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:183
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:244
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:72
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3226
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
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 RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:206
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2119
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1794
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1305
struct RelationData * Relation
Definition: relcache.h:26
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261
int rd_refcnt
Definition: rel.h:58
bool rd_isvalid
Definition: rel.h:62
bool rd_islocaltemp
Definition: rel.h:60
TupleDesc rd_att
Definition: rel.h:110
bool rd_isnailed
Definition: rel.h:61
BackendId rd_backend
Definition: rel.h:59
SMgrRelation rd_smgr
Definition: rel.h:57
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_droppedSubid
Definition: rel.h:107
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:111

References Assert(), AssertArg, BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, 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().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6583 of file relcache.c.

6584 {
6585  LWLockRelease(RelCacheInitLock);
6586 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6558 of file relcache.c.

6559 {
6560  char localinitfname[MAXPGPATH];
6561  char sharedinitfname[MAXPGPATH];
6562 
6563  if (DatabasePath)
6564  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6566  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6568 
6569  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6570 
6571  /*
6572  * The files might not be there if no backend has been started since the
6573  * last removal. But complain about failures other than ENOENT with
6574  * ERROR. Fortunately, it's not too late to abort the transaction if we
6575  * can't get rid of the would-be-obsolete init file.
6576  */
6577  if (DatabasePath)
6578  unlink_initfile(localinitfname, ERROR);
6579  unlink_initfile(sharedinitfname, ERROR);
6580 }
char * DatabasePath
Definition: globals.c:96
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
@ LW_EXCLUSIVE
Definition: lwlock.h:104
#define MAXPGPATH
#define snprintf
Definition: port.h:222
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6655
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24

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

6599 {
6600  const char *tblspcdir = "pg_tblspc";
6601  DIR *dir;
6602  struct dirent *de;
6603  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6604 
6605  snprintf(path, sizeof(path), "global/%s",
6607  unlink_initfile(path, LOG);
6608 
6609  /* Scan everything in the default tablespace */
6611 
6612  /* Scan the tablespace link directory to find non-default tablespaces */
6613  dir = AllocateDir(tblspcdir);
6614 
6615  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6616  {
6617  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6618  {
6619  /* Scan the tablespace dir for per-database dirs */
6620  snprintf(path, sizeof(path), "%s/%s/%s",
6621  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6623  }
6624  }
6625 
6626  FreeDir(dir);
6627 }
#define LOG
Definition: elog.h:25
int FreeDir(DIR *dir)
Definition: fd.c:2840
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2803
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6631
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
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 3868 of file relcache.c.

3869 {
3870  HASHCTL ctl;
3871  int allocsize;
3872 
3873  /*
3874  * make sure cache memory context exists
3875  */
3876  if (!CacheMemoryContext)
3878 
3879  /*
3880  * create hashtable that indexes the relcache
3881  */
3882  ctl.keysize = sizeof(Oid);
3883  ctl.entrysize = sizeof(RelIdCacheEnt);
3884  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3885  &ctl, HASH_ELEM | HASH_BLOBS);
3886 
3887  /*
3888  * reserve enough in_progress_list slots for many cases
3889  */
3890  allocsize = 4;
3893  allocsize * sizeof(*in_progress_list));
3894  in_progress_list_maxlen = allocsize;
3895 
3896  /*
3897  * relation mapper needs to be initialized too
3898  */
3900 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
static int in_progress_list_maxlen
Definition: relcache.c:169
#define INITRELCACHESIZE
Definition: relcache.c:3865
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:167
void RelationMapInitialize(void)
Definition: relmapper.c:584
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3914 of file relcache.c.

3915 {
3916  MemoryContext oldcxt;
3917 
3918  /*
3919  * relation mapper needs initialized too
3920  */
3922 
3923  /*
3924  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3925  * nothing.
3926  */
3928  return;
3929 
3930  /*
3931  * switch to cache memory context
3932  */
3934 
3935  /*
3936  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3937  * the cache with pre-made descriptors for the critical shared catalogs.
3938  */
3939  if (!load_relcache_init_file(true))
3940  {
3941  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3942  Natts_pg_database, Desc_pg_database);
3943  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3944  Natts_pg_authid, Desc_pg_authid);
3945  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3946  Natts_pg_auth_members, Desc_pg_auth_members);
3947  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3948  Natts_pg_shseclabel, Desc_pg_shseclabel);
3949  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3950  Natts_pg_subscription, Desc_pg_subscription);
3951 
3952 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3953  }
3954 
3955  MemoryContextSwitchTo(oldcxt);
3956 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:406
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5871
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:116
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1858
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:113
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:117
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:114
void RelationMapInitializePhase2(void)
Definition: relmapper.c:604

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

3974 {
3976  RelIdCacheEnt *idhentry;
3977  MemoryContext oldcxt;
3978  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3979 
3980  /*
3981  * relation mapper needs initialized too
3982  */
3984 
3985  /*
3986  * switch to cache memory context
3987  */
3989 
3990  /*
3991  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3992  * the cache with pre-made descriptors for the critical "nailed-in" system
3993  * catalogs.
3994  */
3995  if (IsBootstrapProcessingMode() ||
3996  !load_relcache_init_file(false))
3997  {
3998  needNewCacheFile = true;
3999 
4000  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4001  Natts_pg_class, Desc_pg_class);
4002  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4003  Natts_pg_attribute, Desc_pg_attribute);
4004  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4005  Natts_pg_proc, Desc_pg_proc);
4006  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4007  Natts_pg_type, Desc_pg_type);
4008 
4009 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4010  }
4011 
4012  MemoryContextSwitchTo(oldcxt);
4013 
4014  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4016  return;
4017 
4018  /*
4019  * If we didn't get the critical system indexes loaded into relcache, do
4020  * so now. These are critical because the catcache and/or opclass cache
4021  * depend on them for fetches done during relcache load. Thus, we have an
4022  * infinite-recursion problem. We can break the recursion by doing
4023  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4024  * performance, we only want to do that until we have the critical indexes
4025  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4026  * decide whether to do heapscan or indexscan at the key spots, and we set
4027  * it true after we've loaded the critical indexes.
4028  *
4029  * The critical indexes are marked as "nailed in cache", partly to make it
4030  * easy for load_relcache_init_file to count them, but mainly because we
4031  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4032  * true. (NOTE: perhaps it would be possible to reload them by
4033  * temporarily setting criticalRelcachesBuilt to false again. For now,
4034  * though, we just nail 'em in.)
4035  *
4036  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4037  * in the same way as the others, because the critical catalogs don't
4038  * (currently) have any rules or triggers, and so these indexes can be
4039  * rebuilt without inducing recursion. However they are used during
4040  * relcache load when a rel does have rules or triggers, so we choose to
4041  * nail them for performance reasons.
4042  */
4044  {
4045  load_critical_index(ClassOidIndexId,
4046  RelationRelationId);
4047  load_critical_index(AttributeRelidNumIndexId,
4048  AttributeRelationId);
4049  load_critical_index(IndexRelidIndexId,
4050  IndexRelationId);
4051  load_critical_index(OpclassOidIndexId,
4052  OperatorClassRelationId);
4053  load_critical_index(AccessMethodProcedureIndexId,
4054  AccessMethodProcedureRelationId);
4055  load_critical_index(RewriteRelRulenameIndexId,
4056  RewriteRelationId);
4057  load_critical_index(TriggerRelidNameIndexId,
4058  TriggerRelationId);
4059 
4060 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4061 
4062  criticalRelcachesBuilt = true;
4063  }
4064 
4065  /*
4066  * Process critical shared indexes too.
4067  *
4068  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4069  * initial lookup of MyDatabaseId, without which we'll never find any
4070  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4071  * database OID, so it instead depends on DatabaseOidIndexId. We also
4072  * need to nail up some indexes on pg_authid and pg_auth_members for use
4073  * during client authentication. SharedSecLabelObjectIndexId isn't
4074  * critical for the core system, but authentication hooks might be
4075  * interested in it.
4076  */
4078  {
4079  load_critical_index(DatabaseNameIndexId,
4080  DatabaseRelationId);
4081  load_critical_index(DatabaseOidIndexId,
4082  DatabaseRelationId);
4083  load_critical_index(AuthIdRolnameIndexId,
4084  AuthIdRelationId);
4085  load_critical_index(AuthIdOidIndexId,
4086  AuthIdRelationId);
4087  load_critical_index(AuthMemMemRoleIndexId,
4088  AuthMemRelationId);
4089  load_critical_index(SharedSecLabelObjectIndexId,
4090  SharedSecLabelRelationId);
4091 
4092 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4093 
4095  }
4096 
4097  /*
4098  * Now, scan all the relcache entries and update anything that might be
4099  * wrong in the results from formrdesc or the relcache cache file. If we
4100  * faked up relcache entries using formrdesc, then read the real pg_class
4101  * rows and replace the fake entries with them. Also, if any of the
4102  * relcache entries have rules, triggers, or security policies, load that
4103  * info the hard way since it isn't recorded in the cache file.
4104  *
4105  * Whenever we access the catalogs to read data, there is a possibility of
4106  * a shared-inval cache flush causing relcache entries to be removed.
4107  * Since hash_seq_search only guarantees to still work after the *current*
4108  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4109  * We handle this by restarting the scan from scratch after each access.
4110  * This is theoretically O(N^2), but the number of entries that actually
4111  * need to be fixed is small enough that it doesn't matter.
4112  */
4114 
4115  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4116  {
4117  Relation relation = idhentry->reldesc;
4118  bool restart = false;
4119 
4120  /*
4121  * Make sure *this* entry doesn't get flushed while we work with it.
4122  */
4124 
4125  /*
4126  * If it's a faked-up entry, read the real pg_class tuple.
4127  */
4128  if (relation->rd_rel->relowner == InvalidOid)
4129  {
4130  HeapTuple htup;
4131  Form_pg_class relp;
4132 
4133  htup = SearchSysCache1(RELOID,
4134  ObjectIdGetDatum(RelationGetRelid(relation)));
4135  if (!HeapTupleIsValid(htup))
4136  elog(FATAL, "cache lookup failed for relation %u",
4137  RelationGetRelid(relation));
4138  relp = (Form_pg_class) GETSTRUCT(htup);
4139 
4140  /*
4141  * Copy tuple to relation->rd_rel. (See notes in
4142  * AllocateRelationDesc())
4143  */
4144  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4145 
4146  /* Update rd_options while we have the tuple */
4147  if (relation->rd_options)
4148  pfree(relation->rd_options);
4149  RelationParseRelOptions(relation, htup);
4150 
4151  /*
4152  * Check the values in rd_att were set up correctly. (We cannot
4153  * just copy them over now: formrdesc must have set up the rd_att
4154  * data correctly to start with, because it may already have been
4155  * copied into one or more catcache entries.)
4156  */
4157  Assert(relation->rd_att->tdtypeid == relp->reltype);
4158  Assert(relation->rd_att->tdtypmod == -1);
4159 
4160  ReleaseSysCache(htup);
4161 
4162  /* relowner had better be OK now, else we'll loop forever */
4163  if (relation->rd_rel->relowner == InvalidOid)
4164  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4165  RelationGetRelationName(relation));
4166 
4167  restart = true;
4168  }
4169 
4170  /*
4171  * Fix data that isn't saved in relcache cache file.
4172  *
4173  * relhasrules or relhastriggers could possibly be wrong or out of
4174  * date. If we don't actually find any rules or triggers, clear the
4175  * local copy of the flag so that we don't get into an infinite loop
4176  * here. We don't make any attempt to fix the pg_class entry, though.
4177  */
4178  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4179  {
4180  RelationBuildRuleLock(relation);
4181  if (relation->rd_rules == NULL)
4182  relation->rd_rel->relhasrules = false;
4183  restart = true;
4184  }
4185  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4186  {
4187  RelationBuildTriggers(relation);
4188  if (relation->trigdesc == NULL)
4189  relation->rd_rel->relhastriggers = false;
4190  restart = true;
4191  }
4192 
4193  /*
4194  * Re-load the row security policies if the relation has them, since
4195  * they are not preserved in the cache. Note that we can never NOT
4196  * have a policy while relrowsecurity is true,
4197  * RelationBuildRowSecurity will create a single default-deny policy
4198  * if there is no policy defined in pg_policy.
4199  */
4200  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4201  {
4202  RelationBuildRowSecurity(relation);
4203 
4204  Assert(relation->rd_rsdesc != NULL);
4205  restart = true;
4206  }
4207 
4208  /* Reload tableam data if needed */
4209  if (relation->rd_tableam == NULL &&
4210  (relation->rd_rel->relkind == RELKIND_RELATION ||
4211  relation->rd_rel->relkind == RELKIND_SEQUENCE ||
4212  relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
4213  relation->rd_rel->relkind == RELKIND_MATVIEW))
4214  {
4216  Assert(relation->rd_tableam != NULL);
4217 
4218  restart = true;
4219  }
4220 
4221  /* Release hold on the relation */
4223 
4224  /* Now, restart the hashtable scan if needed */
4225  if (restart)
4226  {
4229  }
4230  }
4231 
4232  /*
4233  * Lastly, write out new relcache cache files if needed. We don't bother
4234  * to distinguish cases where only one of the two needs an update.
4235  */
4236  if (needNewCacheFile)
4237  {
4238  /*
4239  * Force all the catcaches to finish initializing and thereby open the
4240  * catalogs and indexes they use. This will preload the relcache with
4241  * entries for all the most important system catalogs and indexes, so
4242  * that the init files will be most useful for future backends.
4243  */
4245 
4246  /* now write the files */
4248  write_relcache_init_file(false);
4249  }
4250 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512
#define FATAL
Definition: elog.h:35
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:196
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:459
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2132
bool criticalRelcachesBuilt
Definition: relcache.c:137
bool criticalSharedRelcachesBuilt
Definition: relcache.c:143
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:109
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:108
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:726
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:110
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6291
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:111
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4259
void RelationMapInitializePhase3(void)
Definition: relmapper.c:625
const struct TableAmRoutine * rd_tableam
Definition: rel.h:185
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
TriggerDesc * trigdesc
Definition: rel.h:115
RuleLock * rd_rules
Definition: rel.h:113
bytea * rd_options
Definition: rel.h:171
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void InitCatalogCachePhase2(void)
Definition: syscache.c:1109
@ RELOID
Definition: syscache.h:87
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1785

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2912 of file relcache.c.

2913 {
2915  RelIdCacheEnt *idhentry;
2916  Relation relation;
2917  List *rebuildFirstList = NIL;
2918  List *rebuildList = NIL;
2919  ListCell *l;
2920  int i;
2921 
2922  /*
2923  * Reload relation mapping data before starting to reconstruct cache.
2924  */
2926 
2927  /* Phase 1 */
2929 
2930  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2931  {
2932  relation = idhentry->reldesc;
2933 
2934  /* Must close all smgr references to avoid leaving dangling ptrs */
2935  RelationCloseSmgr(relation);
2936 
2937  /*
2938  * Ignore new relations; no other backend will manipulate them before
2939  * we commit. Likewise, before replacing a relation's relfilenode, we
2940  * shall have acquired AccessExclusiveLock and drained any applicable
2941  * pending invalidations.
2942  */
2943  if (relation->rd_createSubid != InvalidSubTransactionId ||
2945  continue;
2946 
2948 
2949  if (RelationHasReferenceCountZero(relation))
2950  {
2951  /* Delete this entry immediately */
2952  Assert(!relation->rd_isnailed);
2953  RelationClearRelation(relation, false);
2954  }
2955  else
2956  {
2957  /*
2958  * If it's a mapped relation, immediately update its rd_node in
2959  * case its relfilenode changed. We must do this during phase 1
2960  * in case the relation is consulted during rebuild of other
2961  * relcache entries in phase 2. It's safe since consulting the
2962  * map doesn't involve any access to relcache entries.
2963  */
2964  if (RelationIsMapped(relation))
2965  RelationInitPhysicalAddr(relation);
2966 
2967  /*
2968  * Add this entry to list of stuff to rebuild in second pass.
2969  * pg_class goes to the front of rebuildFirstList while
2970  * pg_class_oid_index goes to the back of rebuildFirstList, so
2971  * they are done first and second respectively. Other nailed
2972  * relations go to the front of rebuildList, so they'll be done
2973  * next in no particular order; and everything else goes to the
2974  * back of rebuildList.
2975  */
2976  if (RelationGetRelid(relation) == RelationRelationId)
2977  rebuildFirstList = lcons(relation, rebuildFirstList);
2978  else if (RelationGetRelid(relation) == ClassOidIndexId)
2979  rebuildFirstList = lappend(rebuildFirstList, relation);
2980  else if (relation->rd_isnailed)
2981  rebuildList = lcons(relation, rebuildList);
2982  else
2983  rebuildList = lappend(rebuildList, relation);
2984  }
2985  }
2986 
2987  /*
2988  * Now zap any remaining smgr cache entries. This must happen before we
2989  * start to rebuild entries, since that may involve catalog fetches which
2990  * will re-open catalog files.
2991  */
2992  smgrcloseall();
2993 
2994  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2995  foreach(l, rebuildFirstList)
2996  {
2997  relation = (Relation) lfirst(l);
2998  RelationClearRelation(relation, true);
2999  }
3000  list_free(rebuildFirstList);
3001  foreach(l, rebuildList)
3002  {
3003  relation = (Relation) lfirst(l);
3004  RelationClearRelation(relation, true);
3005  }
3006  list_free(rebuildList);
3007 
3008  if (!debug_discard)
3009  /* Any RelationBuildDesc() on the stack must start over. */
3010  for (i = 0; i < in_progress_list_len; i++)
3011  in_progress_list[i].invalidated = true;
3012 }
List * lappend(List *list, void *datum)
Definition: list.c:336
void list_free(List *list)
Definition: list.c:1505
List * lcons(void *datum, List *list)
Definition: list.c:474
#define lfirst(lc)
Definition: pg_list.h:169
#define NIL
Definition: pg_list.h:65
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:462
#define RelationIsMapped(relation)
Definition: rel.h:527
#define RelationCloseSmgr(relation)
Definition: rel.h:558
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2482
static long relcacheInvalsReceived
Definition: relcache.c:151
void RelationMapInvalidateAll(void)
Definition: relmapper.c:425
void smgrcloseall(void)
Definition: smgr.c:286

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_firstRelfilenodeSubid, RelationData::rd_isnailed, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2856 of file relcache.c.

2857 {
2858  Relation relation;
2859 
2860  RelationIdCacheLookup(relationId, relation);
2861 
2862  if (PointerIsValid(relation))
2863  {
2865  RelationFlushRelation(relation);
2866  }
2867  else
2868  {
2869  int i;
2870 
2871  for (i = 0; i < in_progress_list_len; i++)
2872  if (in_progress_list[i].reloid == relationId)
2873  in_progress_list[i].invalidated = true;
2874  }
2875 }
#define PointerIsValid(pointer)
Definition: c.h:698
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:228
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2779
bool invalidated
Definition: relcache.c:164

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

2153 {
2154  /* Note: no locking manipulations needed */
2156 
2157  /*
2158  * If the relation is no longer open in this session, we can clean up any
2159  * stale partition descriptors it has. This is unlikely, so check to see
2160  * if there are child contexts before expending a call to mcxt.c.
2161  */
2162  if (RelationHasReferenceCountZero(relation))
2163  {
2164  if (relation->rd_pdcxt != NULL &&
2165  relation->rd_pdcxt->firstchild != NULL)
2167 
2168  if (relation->rd_pddcxt != NULL &&
2169  relation->rd_pddcxt->firstchild != NULL)
2171  }
2172 
2173 #ifdef RELCACHE_FORCE_RELEASE
2174  if (RelationHasReferenceCountZero(relation) &&
2175  relation->rd_createSubid == InvalidSubTransactionId &&
2177  RelationClearRelation(relation, false);
2178 #endif
2179 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
MemoryContext firstchild
Definition: memnodes.h:87
MemoryContext rd_pdcxt
Definition: rel.h:129
MemoryContext rd_pddcxt
Definition: rel.h:133

References MemoryContextData::firstchild, InvalidSubTransactionId, MemoryContextDeleteChildren(), RelationData::rd_createSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationClearRelation(), RelationDecrementReferenceCount(), and RelationHasReferenceCountZero.

Referenced by index_close(), maybe_send_schema(), pgoutput_change(), relation_close(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and ResourceOwnerReleaseInternal().

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 3021 of file relcache.c.

3022 {
3023  Relation relation;
3024 
3025  RelationIdCacheLookup(relationId, relation);
3026 
3027  if (!PointerIsValid(relation))
3028  return; /* not in cache, nothing to do */
3029 
3030  RelationCloseSmgr(relation);
3031 }

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2812 of file relcache.c.

2813 {
2814  Relation relation;
2815 
2816  RelationIdCacheLookup(rid, relation);
2817 
2818  if (!PointerIsValid(relation))
2819  return; /* not in cache, nothing to do */
2820 
2821  if (!RelationHasReferenceCountZero(relation))
2822  elog(ERROR, "relation %u is still open", rid);
2823 
2825  if (relation->rd_createSubid != InvalidSubTransactionId ||
2827  {
2828  /*
2829  * In the event of subtransaction rollback, we must not forget
2830  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2831  * invalidates it in lieu of destroying it. (If we're in a top
2832  * transaction, we could opt to destroy the entry.)
2833  */
2835  }
2836 
2837  RelationClearRelation(relation, false);
2838 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 4969 of file relcache.c.

4970 {
4971  List *result;
4972  Datum exprsDatum;
4973  bool isnull;
4974  char *exprsString;
4975  List *rawExprs;
4976  ListCell *lc;
4977 
4978  /* Quick exit if there is nothing to do. */
4979  if (relation->rd_indextuple == NULL ||
4980  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4981  return NIL;
4982 
4983  /* Extract raw node tree(s) from index tuple. */
4984  exprsDatum = heap_getattr(relation->rd_indextuple,
4985  Anum_pg_index_indexprs,
4987  &isnull);
4988  Assert(!isnull);
4989  exprsString = TextDatumGetCString(exprsDatum);
4990  rawExprs = (List *) stringToNode(exprsString);
4991  pfree(exprsString);
4992 
4993  /* Construct null Consts; the typlen and typbyval are arbitrary. */
4994  result = NIL;
4995  foreach(lc, rawExprs)
4996  {
4997  Node *rawExpr = (Node *) lfirst(lc);
4998 
4999  result = lappend(result,
5000  makeConst(exprType(rawExpr),
5001  exprTypmod(rawExpr),
5002  exprCollation(rawExpr),
5003  1,
5004  (Datum) 0,
5005  true,
5006  true));
5007  }
5008 
5009  return result;
5010 }
#define TextDatumGetCString(d)
Definition: builtins.h:87
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:756
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
uintptr_t Datum
Definition: postgres.h:411
void * stringToNode(const char *str)
Definition: read.c:89
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4338
Definition: nodes.h:539
struct HeapTupleData * rd_indextuple
Definition: rel.h:190

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

5435 {
5436  int indnkeyatts;
5437  Oid *ops;
5438  Oid *funcs;
5439  uint16 *strats;
5440  Relation conrel;
5441  SysScanDesc conscan;
5442  ScanKeyData skey[1];
5443  HeapTuple htup;
5444  bool found;
5445  MemoryContext oldcxt;
5446  int i;
5447 
5448  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5449 
5450  /* Allocate result space in caller context */
5451  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5452  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5453  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5454 
5455  /* Quick exit if we have the data cached already */
5456  if (indexRelation->rd_exclstrats != NULL)
5457  {
5458  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5459  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5460  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5461  return;
5462  }
5463 
5464  /*
5465  * Search pg_constraint for the constraint associated with the index. To
5466  * make this not too painfully slow, we use the index on conrelid; that
5467  * will hold the parent relation's OID not the index's own OID.
5468  *
5469  * Note: if we wanted to rely on the constraint name matching the index's
5470  * name, we could just do a direct lookup using pg_constraint's unique
5471  * index. For the moment it doesn't seem worth requiring that.
5472  */
5473  ScanKeyInit(&skey[0],
5474  Anum_pg_constraint_conrelid,
5475  BTEqualStrategyNumber, F_OIDEQ,
5476  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5477 
5478  conrel = table_open(ConstraintRelationId, AccessShareLock);
5479  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5480  NULL, 1, skey);
5481  found = false;
5482 
5483  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5484  {
5486  Datum val;
5487  bool isnull;
5488  ArrayType *arr;
5489  int nelem;
5490 
5491  /* We want the exclusion constraint owning the index */
5492  if (conform->contype != CONSTRAINT_EXCLUSION ||
5493  conform->conindid != RelationGetRelid(indexRelation))
5494  continue;
5495 
5496  /* There should be only one */
5497  if (found)
5498  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5499  RelationGetRelationName(indexRelation));
5500  found = true;
5501 
5502  /* Extract the operator OIDS from conexclop */
5503  val = fastgetattr(htup,
5504  Anum_pg_constraint_conexclop,
5505  conrel->rd_att, &isnull);
5506  if (isnull)
5507  elog(ERROR, "null conexclop for rel %s",
5508  RelationGetRelationName(indexRelation));
5509 
5510  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5511  nelem = ARR_DIMS(arr)[0];
5512  if (ARR_NDIM(arr) != 1 ||
5513  nelem != indnkeyatts ||
5514  ARR_HASNULL(arr) ||
5515  ARR_ELEMTYPE(arr) != OIDOID)
5516  elog(ERROR, "conexclop is not a 1-D Oid array");
5517 
5518  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5519  }
5520 
5521  systable_endscan(conscan);
5522  table_close(conrel, AccessShareLock);
5523 
5524  if (!found)
5525  elog(ERROR, "exclusion constraint record missing for rel %s",
5526  RelationGetRelationName(indexRelation));
5527 
5528  /* We need the func OIDs and strategy numbers too */
5529  for (i = 0; i < indnkeyatts; i++)
5530  {
5531  funcs[i] = get_opcode(ops[i]);
5532  strats[i] = get_op_opfamily_strategy(ops[i],
5533  indexRelation->rd_opfamily[i]);
5534  /* shouldn't fail, since it was checked at index creation */
5535  if (strats[i] == InvalidStrategy)
5536  elog(ERROR, "could not find strategy for operator %u in family %u",
5537  ops[i], indexRelation->rd_opfamily[i]);
5538  }
5539 
5540  /* Save a copy of the results in the relcache entry. */
5541  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5542  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5543  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5544  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5545  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5546  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5547  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5548  MemoryContextSwitchTo(oldcxt);
5549 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
unsigned short uint16
Definition: c.h:440
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:706
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:81
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:497
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:211
uint16 * rd_exclstrats
Definition: rel.h:212
Oid * rd_exclops
Definition: rel.h:210
Form_pg_index rd_index
Definition: rel.h:188
MemoryContext rd_indexcxt
Definition: rel.h:200
Oid * rd_opfamily
Definition: rel.h:203
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

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

4568 {
4569  List *result;
4570  Relation conrel;
4571  SysScanDesc conscan;
4572  ScanKeyData skey;
4573  HeapTuple htup;
4574  List *oldlist;
4575  MemoryContext oldcxt;
4576 
4577  /* Quick exit if we already computed the list. */
4578  if (relation->rd_fkeyvalid)
4579  return relation->rd_fkeylist;
4580 
4581  /* Fast path: non-partitioned tables without triggers can't have FKs */
4582  if (!relation->rd_rel->relhastriggers &&
4583  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4584  return NIL;
4585 
4586  /*
4587  * We build the list we intend to return (in the caller's context) while
4588  * doing the scan. After successfully completing the scan, we copy that
4589  * list into the relcache entry. This avoids cache-context memory leakage
4590  * if we get some sort of error partway through.
4591  */
4592  result = NIL;
4593 
4594  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4595  ScanKeyInit(&skey,
4596  Anum_pg_constraint_conrelid,
4597  BTEqualStrategyNumber, F_OIDEQ,
4598  ObjectIdGetDatum(RelationGetRelid(relation)));
4599 
4600  conrel = table_open(ConstraintRelationId, AccessShareLock);
4601  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4602  NULL, 1, &skey);
4603 
4604  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4605  {
4606  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4607  ForeignKeyCacheInfo *info;
4608 
4609  /* consider only foreign keys */
4610  if (constraint->contype != CONSTRAINT_FOREIGN)
4611  continue;
4612 
4613  info = makeNode(ForeignKeyCacheInfo);
4614  info->conoid = constraint->oid;
4615  info->conrelid = constraint->conrelid;
4616  info->confrelid = constraint->confrelid;
4617 
4618  DeconstructFkConstraintRow(htup, &info->nkeys,
4619  info->conkey,
4620  info->confkey,
4621  info->conpfeqop,
4622  NULL, NULL);
4623 
4624  /* Add FK's node to the result list */
4625  result = lappend(result, info);
4626  }
4627 
4628  systable_endscan(conscan);
4629  table_close(conrel, AccessShareLock);
4630 
4631  /* Now save a copy of the completed list in the relcache entry. */
4633  oldlist = relation->rd_fkeylist;
4634  relation->rd_fkeylist = copyObject(result);
4635  relation->rd_fkeyvalid = true;
4636  MemoryContextSwitchTo(oldcxt);
4637 
4638  /* Don't leak the old list, if there is one */
4639  list_free_deep(oldlist);
4640 
4641  return result;
4642 }
void list_free_deep(List *list)
Definition: list.c:1519
#define copyObject(obj)
Definition: nodes.h:654
#define makeNode(_type_)
Definition: nodes.h:586
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs)
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:278
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:277
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: rel.h:276
List * rd_fkeylist
Definition: rel.h:120
bool rd_fkeyvalid
Definition: rel.h:121

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confkey, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conkey, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conpfeqop, 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 5357 of file relcache.c.

5358 {
5359  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5360  Relation indexDesc;
5361  int i;
5362  Oid replidindex;
5363  MemoryContext oldcxt;
5364 
5365  /* Quick exit if we already computed the result */
5366  if (relation->rd_idattr != NULL)
5367  return bms_copy(relation->rd_idattr);
5368 
5369  /* Fast path if definitely no indexes */
5370  if (!RelationGetForm(relation)->relhasindex)
5371  return NULL;
5372 
5373  /* Historic snapshot must be set. */
5375 
5376  replidindex = RelationGetReplicaIndex(relation);
5377 
5378  /* Fall out if there is no replica identity index */
5379  if (!OidIsValid(replidindex))
5380  return NULL;
5381 
5382  /* Look up the description for the replica identity index */
5383  indexDesc = RelationIdGetRelation(replidindex);
5384 
5385  if (!RelationIsValid(indexDesc))
5386  elog(ERROR, "could not open relation with OID %u",
5387  relation->rd_replidindex);
5388 
5389  /* Add referenced attributes to idindexattrs */
5390  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5391  {
5392  int attrnum = indexDesc->rd_index->indkey.values[i];
5393 
5394  /*
5395  * We don't include non-key columns into idindexattrs bitmaps. See
5396  * RelationGetIndexAttrBitmap.
5397  */
5398  if (attrnum != 0)
5399  {
5400  if (i < indexDesc->rd_index->indnkeyatts)
5401  idindexattrs = bms_add_member(idindexattrs,
5403  }
5404  }
5405 
5406  RelationClose(indexDesc);
5407 
5408  /* Don't leak the old values of these bitmaps, if any */
5409  bms_free(relation->rd_idattr);
5410  relation->rd_idattr = NULL;
5411 
5412  /* Now save copy of the bitmap in the relcache entry */
5414  relation->rd_idattr = bms_copy(idindexattrs);
5415  MemoryContextSwitchTo(oldcxt);
5416 
5417  /* We return our original working copy for caller to play with */
5418  return idindexattrs;
5419 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define OidIsValid(objectId)
Definition: c.h:710
#define RelationGetForm(relation)
Definition: rel.h:472
#define RelationIsValid(relation)
Definition: rel.h:451
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4885
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2046
void RelationClose(Relation relation)
Definition: relcache.c:2152
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2073
Oid rd_replidindex
Definition: rel.h:152
Bitmapset * rd_idattr
Definition: rel.h:161
#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 5692 of file relcache.c.

5693 {
5694  MemoryContext oldcxt;
5695  bytea **opts = relation->rd_opcoptions;
5696  Oid relid = RelationGetRelid(relation);
5697  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5698  * IndexRelationGetNumberOfKeyAttributes */
5699  int i;
5700 
5701  /* Try to copy cached options. */
5702  if (opts)
5703  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5704 
5705  /* Get and parse opclass options. */
5706  opts = palloc0(sizeof(*opts) * natts);
5707 
5708  for (i = 0; i < natts; i++)
5709  {
5710  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5711  {
5712  Datum attoptions = get_attoptions(relid, i + 1);
5713 
5714  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5715 
5716  if (attoptions != (Datum) 0)
5717  pfree(DatumGetPointer(attoptions));
5718  }
5719  }
5720 
5721  /* Copy parsed options to the cache. */
5722  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5723  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5724  MemoryContextSwitchTo(oldcxt);
5725 
5726  if (copy)
5727  return opts;
5728 
5729  for (i = 0; i < natts; i++)
5730  {
5731  if (opts[i])
5732  pfree(opts[i]);
5733  }
5734 
5735  pfree(opts);
5736 
5737  return relation->rd_opcoptions;
5738 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:939
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:995
static AmcheckOptions opts
Definition: pg_amcheck.c:110
#define DatumGetPointer(X)
Definition: postgres.h:593
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:484
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5672
bytea ** rd_opcoptions
Definition: rel.h:214
Definition: c.h:622

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

5107 {
5108  Bitmapset *uindexattrs; /* columns in unique indexes */
5109  Bitmapset *pkindexattrs; /* columns in the primary index */
5110  Bitmapset *idindexattrs; /* columns in the replica identity */
5111  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5112  List *indexoidlist;
5113  List *newindexoidlist;
5114  Oid relpkindex;
5115  Oid relreplindex;
5116  ListCell *l;
5117  MemoryContext oldcxt;
5118 
5119  /* Quick exit if we already computed the result. */
5120  if (relation->rd_attrsvalid)
5121  {
5122  switch (attrKind)
5123  {
5124  case INDEX_ATTR_BITMAP_KEY:
5125  return bms_copy(relation->rd_keyattr);
5127  return bms_copy(relation->rd_pkattr);
5129  return bms_copy(relation->rd_idattr);
5131  return bms_copy(relation->rd_hotblockingattr);
5132  default:
5133  elog(ERROR, "unknown attrKind %u", attrKind);
5134  }
5135  }
5136 
5137  /* Fast path if definitely no indexes */
5138  if (!RelationGetForm(relation)->relhasindex)
5139  return NULL;
5140 
5141  /*
5142  * Get cached list of index OIDs. If we have to start over, we do so here.
5143  */
5144 restart:
5145  indexoidlist = RelationGetIndexList(relation);
5146 
5147  /* Fall out if no indexes (but relhasindex was set) */
5148  if (indexoidlist == NIL)
5149  return NULL;
5150 
5151  /*
5152  * Copy the rd_pkindex and rd_replidindex values computed by
5153  * RelationGetIndexList before proceeding. This is needed because a
5154  * relcache flush could occur inside index_open below, resetting the
5155  * fields managed by RelationGetIndexList. We need to do the work with
5156  * stable values of these fields.
5157  */
5158  relpkindex = relation->rd_pkindex;
5159  relreplindex = relation->rd_replidindex;
5160 
5161  /*
5162  * For each index, add referenced attributes to appropriate bitmaps.
5163  *
5164  * Note: we consider all indexes returned by RelationGetIndexList, even if
5165  * they are not indisready or indisvalid. This is important because an
5166  * index for which CREATE INDEX CONCURRENTLY has just started must be
5167  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5168  * CONCURRENTLY is far enough along that we should ignore the index, it
5169  * won't be returned at all by RelationGetIndexList.
5170  */
5171  uindexattrs = NULL;
5172  pkindexattrs = NULL;
5173  idindexattrs = NULL;
5174  hotblockingattrs = NULL;
5175  foreach(l, indexoidlist)
5176  {
5177  Oid indexOid = lfirst_oid(l);
5178  Relation indexDesc;
5179  Datum datum;
5180  bool isnull;
5181  Node *indexExpressions;
5182  Node *indexPredicate;
5183  int i;
5184  bool isKey; /* candidate key */
5185  bool isPK; /* primary key */
5186  bool isIDKey; /* replica identity index */
5187 
5188  indexDesc = index_open(indexOid, AccessShareLock);
5189 
5190  /*
5191  * Extract index expressions and index predicate. Note: Don't use
5192  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5193  * those might run constant expressions evaluation, which needs a
5194  * snapshot, which we might not have here. (Also, it's probably more
5195  * sound to collect the bitmaps before any transformations that might
5196  * eliminate columns, but the practical impact of this is limited.)
5197  */
5198 
5199  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5200  GetPgIndexDescriptor(), &isnull);
5201  if (!isnull)
5202  indexExpressions = stringToNode(TextDatumGetCString(datum));
5203  else
5204  indexExpressions = NULL;
5205 
5206  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5207  GetPgIndexDescriptor(), &isnull);
5208  if (!isnull)
5209  indexPredicate = stringToNode(TextDatumGetCString(datum));
5210  else
5211  indexPredicate = NULL;
5212 
5213  /* Can this index be referenced by a foreign key? */
5214  isKey = indexDesc->rd_index->indisunique &&
5215  indexExpressions == NULL &&
5216  indexPredicate == NULL;
5217 
5218  /* Is this a primary key? */
5219  isPK = (indexOid == relpkindex);
5220 
5221  /* Is this index the configured (or default) replica identity? */
5222  isIDKey = (indexOid == relreplindex);
5223 
5224  /* Collect simple attribute references */
5225  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5226  {
5227  int attrnum = indexDesc->rd_index->indkey.values[i];
5228 
5229  /*
5230  * Since we have covering indexes with non-key columns, we must
5231  * handle them accurately here. non-key columns must be added into
5232  * indexattrs, since they are in index, and HOT-update shouldn't
5233  * miss them. Obviously, non-key columns couldn't be referenced by
5234  * foreign key or identity key. Hence we do not include them into
5235  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5236  */
5237  if (attrnum != 0)
5238  {
5239  if (indexDesc->rd_indam->amhotblocking)
5240  hotblockingattrs = bms_add_member(hotblockingattrs,
5242 
5243  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5244  uindexattrs = bms_add_member(uindexattrs,
5246 
5247  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5248  pkindexattrs = bms_add_member(pkindexattrs,
5250 
5251  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5252  idindexattrs = bms_add_member(idindexattrs,
5254  }
5255  }
5256 
5257  /* Collect all attributes used in expressions, too */
5258  if (indexDesc->rd_indam->amhotblocking)
5259  pull_varattnos(indexExpressions, 1, &hotblockingattrs);
5260 
5261  /*
5262  * Collect all attributes in the index predicate, too. We have to ignore
5263  * amhotblocking flag, because the row might become indexable, in which
5264  * case we have to add it to the index.
5265  */
5266  pull_varattnos(indexPredicate, 1, &hotblockingattrs);
5267 
5268  index_close(indexDesc, AccessShareLock);
5269  }
5270 
5271  /*
5272  * During one of the index_opens in the above loop, we might have received
5273  * a relcache flush event on this relcache entry, which might have been
5274  * signaling a change in the rel's index list. If so, we'd better start
5275  * over to ensure we deliver up-to-date attribute bitmaps.
5276  */
5277  newindexoidlist = RelationGetIndexList(relation);
5278  if (equal(indexoidlist, newindexoidlist) &&
5279  relpkindex == relation->rd_pkindex &&
5280  relreplindex == relation->rd_replidindex)
5281  {
5282  /* Still the same index set, so proceed */
5283  list_free(newindexoidlist);
5284  list_free(indexoidlist);
5285  }
5286  else
5287  {
5288  /* Gotta do it over ... might as well not leak memory */
5289  list_free(newindexoidlist);
5290  list_free(indexoidlist);
5291  bms_free(uindexattrs);
5292  bms_free(pkindexattrs);
5293  bms_free(idindexattrs);
5294  bms_free(hotblockingattrs);
5295 
5296  goto restart;
5297  }
5298 
5299  /* Don't leak the old values of these bitmaps, if any */
5300  bms_free(relation->rd_keyattr);
5301  relation->rd_keyattr = NULL;
5302  bms_free(relation->rd_pkattr);
5303  relation->rd_pkattr = NULL;
5304  bms_free(relation->rd_idattr);
5305  relation->rd_idattr = NULL;
5306  bms_free(relation->rd_hotblockingattr);
5307  relation->rd_hotblockingattr = NULL;
5308 
5309  /*
5310  * Now save copies of the bitmaps in the relcache entry. We intentionally
5311  * set rd_attrsvalid last, because that's what signals validity of the
5312  * values; if we run out of memory before making that copy, we won't
5313  * leave the relcache entry looking like the other ones are valid but
5314  * empty.
5315  */
5317  relation->rd_keyattr = bms_copy(uindexattrs);
5318  relation->rd_pkattr = bms_copy(pkindexattrs);
5319  relation->rd_idattr = bms_copy(idindexattrs);
5320  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5321  relation->rd_attrsvalid = true;
5322  MemoryContextSwitchTo(oldcxt);
5323 
5324  /* We return our original working copy for caller to play with */
5325  switch (attrKind)
5326  {
5327  case INDEX_ATTR_BITMAP_KEY:
5328  return uindexattrs;
5330  return pkindexattrs;
5332  return idindexattrs;
5334  return hotblockingattrs;
5335  default:
5336  elog(ERROR, "unknown attrKind %u", attrKind);
5337  return NULL;
5338  }
5339 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3161
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4676
bool amhotblocking
Definition: amapi.h:248
Bitmapset * rd_keyattr
Definition: rel.h:159
struct IndexAmRoutine * rd_indam
Definition: rel.h:202
bool rd_attrsvalid
Definition: rel.h:158
Bitmapset * rd_hotblockingattr
Definition: rel.h:162
Oid rd_pkindex
Definition: rel.h:151
Bitmapset * rd_pkattr
Definition: rel.h:160
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:281

References AccessShareLock, IndexAmRoutine::amhotblocking, 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_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, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

Referenced by ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), and logicalrep_rel_open().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4910 of file relcache.c.

4911 {
4912  List *result;
4913  Datum exprsDatum;
4914  bool isnull;
4915  char *exprsString;
4916  MemoryContext oldcxt;
4917 
4918  /* Quick exit if we already computed the result. */
4919  if (relation->rd_indexprs)
4920  return copyObject(relation->rd_indexprs);
4921 
4922  /* Quick exit if there is nothing to do. */
4923  if (relation->rd_indextuple == NULL ||
4924  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4925  return NIL;
4926 
4927  /*
4928  * We build the tree we intend to return in the caller's context. After
4929  * successfully completing the work, we copy it into the relcache entry.
4930  * This avoids problems if we get some sort of error partway through.
4931  */
4932  exprsDatum = heap_getattr(relation->rd_indextuple,
4933  Anum_pg_index_indexprs,
4935  &isnull);
4936  Assert(!isnull);
4937  exprsString = TextDatumGetCString(exprsDatum);
4938  result = (List *) stringToNode(exprsString);
4939  pfree(exprsString);
4940 
4941  /*
4942  * Run the expressions through eval_const_expressions. This is not just an
4943  * optimization, but is necessary, because the planner will be comparing
4944  * them to similarly-processed qual clauses, and may fail to detect valid
4945  * matches without this. We must not use canonicalize_qual, however,
4946  * since these aren't qual expressions.
4947  */
4948  result = (List *) eval_const_expressions(NULL, (Node *) result);
4949 
4950  /* May as well fix opfuncids too */
4951  fix_opfuncids((Node *) result);
4952 
4953  /* Now save a copy of the completed tree in the relcache entry. */
4954  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4955  relation->rd_indexprs = copyObject(result);
4956  MemoryContextSwitchTo(oldcxt);
4957 
4958  return result;
4959 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2095
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1652
List * rd_indexprs
Definition: rel.h:208

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

4677 {
4678  Relation indrel;
4679  SysScanDesc indscan;
4680  ScanKeyData skey;
4681  HeapTuple htup;
4682  List *result;
4683  List *oldlist;
4684  char replident = relation->rd_rel->relreplident;
4685  Oid pkeyIndex = InvalidOid;
4686  Oid candidateIndex = InvalidOid;
4687  MemoryContext oldcxt;
4688 
4689  /* Quick exit if we already computed the list. */
4690  if (relation->rd_indexvalid)
4691  return list_copy(relation->rd_indexlist);
4692 
4693  /*
4694  * We build the list we intend to return (in the caller's context) while
4695  * doing the scan. After successfully completing the scan, we copy that
4696  * list into the relcache entry. This avoids cache-context memory leakage
4697  * if we get some sort of error partway through.
4698  */
4699  result = NIL;
4700 
4701  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4702  ScanKeyInit(&skey,
4703  Anum_pg_index_indrelid,
4704  BTEqualStrategyNumber, F_OIDEQ,
4705  ObjectIdGetDatum(RelationGetRelid(relation)));
4706 
4707  indrel = table_open(IndexRelationId, AccessShareLock);
4708  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4709  NULL, 1, &skey);
4710 
4711  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4712  {
4714 
4715  /*
4716  * Ignore any indexes that are currently being dropped. This will
4717  * prevent them from being searched, inserted into, or considered in
4718  * HOT-safety decisions. It's unsafe to touch such an index at all
4719  * since its catalog entries could disappear at any instant.
4720  */
4721  if (!index->indislive)
4722  continue;
4723 
4724  /* add index's OID to result list */
4725  result = lappend_oid(result, index->indexrelid);
4726 
4727  /*
4728  * Invalid, non-unique, non-immediate or predicate indexes aren't
4729  * interesting for either oid indexes or replication identity indexes,
4730  * so don't check them.
4731  */
4732  if (!index->indisvalid || !index->indisunique ||
4733  !index->indimmediate ||
4734  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4735  continue;
4736 
4737  /* remember primary key index if any */
4738  if (index->indisprimary)
4739  pkeyIndex = index->indexrelid;
4740 
4741  /* remember explicitly chosen replica index */
4742  if (index->indisreplident)
4743  candidateIndex = index->indexrelid;
4744  }
4745 
4746  systable_endscan(indscan);
4747 
4748  table_close(indrel, AccessShareLock);
4749 
4750  /* Sort the result list into OID order, per API spec. */
4751  list_sort(result, list_oid_cmp);
4752 
4753  /* Now save a copy of the completed list in the relcache entry. */
4755  oldlist = relation->rd_indexlist;
4756  relation->rd_indexlist = list_copy(result);
4757  relation->rd_pkindex = pkeyIndex;
4758  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4759  relation->rd_replidindex = pkeyIndex;
4760  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4761  relation->rd_replidindex = candidateIndex;
4762  else
4763  relation->rd_replidindex = InvalidOid;
4764  relation->rd_indexvalid = true;
4765  MemoryContextSwitchTo(oldcxt);
4766 
4767  /* Don't leak the old list, if there is one */
4768  list_free(oldlist);
4769 
4770  return result;
4771 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1612
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
List * list_copy(const List *oldlist)
Definition: list.c:1532
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1645
FormData_pg_index * Form_pg_index
Definition: pg_index.h:69
bool rd_indexvalid
Definition: rel.h:63
List * rd_indexlist
Definition: rel.h:150
Definition: type.h:90

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_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(), 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 5023 of file relcache.c.

5024 {
5025  List *result;
5026  Datum predDatum;
5027  bool isnull;
5028  char *predString;
5029  MemoryContext oldcxt;
5030 
5031  /* Quick exit if we already computed the result. */
5032  if (relation->rd_indpred)
5033  return copyObject(relation->rd_indpred);
5034 
5035  /* Quick exit if there is nothing to do. */
5036  if (relation->rd_indextuple == NULL ||
5037  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5038  return NIL;
5039 
5040  /*
5041  * We build the tree we intend to return in the caller's context. After
5042  * successfully completing the work, we copy it into the relcache entry.
5043  * This avoids problems if we get some sort of error partway through.
5044  */
5045  predDatum = heap_getattr(relation->rd_indextuple,
5046  Anum_pg_index_indpred,
5048  &isnull);
5049  Assert(!isnull);
5050  predString = TextDatumGetCString(predDatum);
5051  result = (List *) stringToNode(predString);
5052  pfree(predString);
5053 
5054  /*
5055  * Run the expression through const-simplification and canonicalization.
5056  * This is not just an optimization, but is necessary, because the planner
5057  * will be comparing it to similarly-processed qual clauses, and may fail
5058  * to detect valid matches without this. This must match the processing
5059  * done to qual clauses in preprocess_expression()! (We can skip the
5060  * stuff involving subqueries, however, since we don't allow any in index
5061  * predicates.)
5062  */
5063  result = (List *) eval_const_expressions(NULL, (Node *) result);
5064 
5065  result = (List *) canonicalize_qual((Expr *) result, false);
5066 
5067  /* Also convert to implicit-AND format */
5068  result = make_ands_implicit((Expr *) result);
5069 
5070  /* May as well fix opfuncids too */
5071  fix_opfuncids((Node *) result);
5072 
5073  /* Now save a copy of the completed tree in the relcache entry. */
5074  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5075  relation->rd_indpred = copyObject(result);
5076  MemoryContextSwitchTo(oldcxt);
5077 
5078  return result;
5079 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:719
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:294
List * rd_indpred
Definition: rel.h:209

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().

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  relation)

Definition at line 5646 of file relcache.c.

5647 {
5648  Oid indexrelid = RelationGetRelid(indexrel);
5649  int16 natts = RelationGetNumberOfAttributes(indexrel);
5650  Datum *options = NULL;
5651  int16 attnum;
5652 
5653  for (attnum = 1; attnum <= natts; attnum++)
5654  {
5655  if (indexrel->rd_indam->amoptsprocnum == 0)
5656  continue;
5657 
5658  if (!OidIsValid(index_getprocid(indexrel, attnum,
5659  indexrel->rd_indam->amoptsprocnum)))
5660  continue;
5661 
5662  if (!options)
5663  options = palloc0(sizeof(Datum) * natts);
5664 
5665  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5666  }
5667 
5668  return options;
5669 }
signed short int16
Definition: c.h:428
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769
static char ** options

References IndexAmRoutine::amoptsprocnum, attnum, get_attoptions(), index_getprocid(), OidIsValid, options, palloc0(), RelationData::rd_indam, RelationGetNumberOfAttributes, and RelationGetRelid.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4864 of file relcache.c.

4865 {
4866  List *ilist;
4867 
4868  if (!relation->rd_indexvalid)
4869  {
4870  /* RelationGetIndexList does the heavy lifting. */
4871  ilist = RelationGetIndexList(relation);
4872  list_free(ilist);
4873  Assert(relation->rd_indexvalid);
4874  }
4875 
4876  return relation->rd_pkindex;
4877 }

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

Referenced by build_replindex_scan_key(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4885 of file relcache.c.

4886 {
4887  List *ilist;
4888 
4889  if (!relation->rd_indexvalid)
4890  {
4891  /* RelationGetIndexList does the heavy lifting. */
4892  ilist = RelationGetIndexList(relation);
4893  list_free(ilist);
4894  Assert(relation->rd_indexvalid);
4895  }
4896 
4897  return relation->rd_replidindex;
4898 }

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4795 of file relcache.c.

4796 {
4797  Relation indrel;
4798  SysScanDesc indscan;
4799  ScanKeyData skey;
4800  HeapTuple htup;
4801  List *result;
4802  List *oldlist;
4803  MemoryContext oldcxt;
4804 
4805  /* Quick exit if we already computed the list. */
4806  if (relation->rd_statvalid != 0)
4807  return list_copy(relation->rd_statlist);
4808 
4809  /*
4810  * We build the list we intend to return (in the caller's context) while
4811  * doing the scan. After successfully completing the scan, we copy that
4812  * list into the relcache entry. This avoids cache-context memory leakage
4813  * if we get some sort of error partway through.
4814  */
4815  result = NIL;
4816 
4817  /*
4818  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4819  * rel.
4820  */
4821  ScanKeyInit(&skey,
4822  Anum_pg_statistic_ext_stxrelid,
4823  BTEqualStrategyNumber, F_OIDEQ,
4824  ObjectIdGetDatum(RelationGetRelid(relation)));
4825 
4826  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4827  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4828  NULL, 1, &skey);
4829 
4830  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4831  {
4832  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4833 
4834  result = lappend_oid(result, oid);
4835  }
4836 
4837  systable_endscan(indscan);
4838 
4839  table_close(indrel, AccessShareLock);
4840 
4841  /* Sort the result list into OID order, per API spec. */
4842  list_sort(result, list_oid_cmp);
4843 
4844  /* Now save a copy of the completed list in the relcache entry. */
4846  oldlist = relation->rd_statlist;
4847  relation->rd_statlist = list_copy(result);
4848 
4849  relation->rd_statvalid = true;
4850  MemoryContextSwitchTo(oldcxt);
4851 
4852  /* Don't leak the old list, if there is one */
4853  list_free(oldlist);
4854 
4855  return result;
4856 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:65
List * rd_statlist
Definition: rel.h:155

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

Referenced by get_relation_statistics(), and transformTableLikeClause().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2046 of file relcache.c.

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

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 maybe_send_schema(), pgoutput_change(), relation_open(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6518 of file relcache.c.

6519 {
6520  if (relationId == SharedSecLabelRelationId ||
6521  relationId == TriggerRelidNameIndexId ||
6522  relationId == DatabaseNameIndexId ||
6523  relationId == SharedSecLabelObjectIndexId)
6524  {
6525  /*
6526  * If this Assert fails, we don't need the applicable special case
6527  * anymore.
6528  */
6529  Assert(!RelationSupportsSysCache(relationId));
6530  return true;
6531  }
6532  return RelationSupportsSysCache(relationId);
6533 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1555

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1411 of file relcache.c.

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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, AMOID, IndexAmRoutine::amsupport, Assert(), CacheMemoryContext, DatumGetPointer, elog, ERROR, fastgetattr, GetPgIndexDescriptor(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, INDEXRELID, IndexSupportInitialize(), InitIndexAmRoutine(), 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 1794 of file relcache.c.

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

References AMOID, 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().

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence 
)

Definition at line 3691 of file relcache.c.

3692 {
3693  Oid newrelfilenode;
3694  Relation pg_class;
3695  HeapTuple tuple;
3696  Form_pg_class classform;
3697  MultiXactId minmulti = InvalidMultiXactId;
3698  TransactionId freezeXid = InvalidTransactionId;
3699  RelFileNode newrnode;
3700 
3701  /* Allocate a new relfilenode */
3702  newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
3703  persistence);
3704 
3705  /*
3706  * Get a writable copy of the pg_class tuple for the given relation.
3707  */
3708  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3709 
3710  tuple = SearchSysCacheCopy1(RELOID,
3711  ObjectIdGetDatum(RelationGetRelid(relation)));
3712  if (!HeapTupleIsValid(tuple))
3713  elog(ERROR, "could not find tuple for relation %u",
3714  RelationGetRelid(relation));
3715  classform = (Form_pg_class) GETSTRUCT(tuple);
3716 
3717  /*
3718  * Schedule unlinking of the old storage at transaction commit.
3719  */
3720  RelationDropStorage(relation);
3721 
3722  /*
3723  * Create storage for the main fork of the new relfilenode. If it's a
3724  * table-like object, call into the table AM to do so, which'll also
3725  * create the table's init fork if needed.
3726  *
3727  * NOTE: If relevant for the AM, any conflict in relfilenode value will be
3728  * caught here, if GetNewRelFileNode messes up for any reason.
3729  */
3730  newrnode = relation->rd_node;
3731  newrnode.relNode = newrelfilenode;
3732 
3733  switch (relation->rd_rel->relkind)
3734  {
3735  case RELKIND_INDEX:
3736  case RELKIND_SEQUENCE:
3737  {
3738  /* handle these directly, at least for now */
3739  SMgrRelation srel;
3740 
3741  srel = RelationCreateStorage(newrnode, persistence);
3742  smgrclose(srel);
3743  }
3744  break;
3745 
3746  case RELKIND_RELATION:
3747  case RELKIND_TOASTVALUE:
3748  case RELKIND_MATVIEW:
3749  table_relation_set_new_filenode(relation, &newrnode,
3750  persistence,
3751  &freezeXid, &minmulti);
3752  break;
3753 
3754  default:
3755  /* we shouldn't be called for anything else */
3756  elog(ERROR, "relation \"%s\" does not have storage",
3757  RelationGetRelationName(relation));
3758  break;
3759  }
3760 
3761  /*
3762  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3763  * change; instead we have to send the update to the relation mapper.
3764  *
3765  * For mapped indexes, we don't actually change the pg_class entry at all;
3766  * this is essential when reindexing pg_class itself. That leaves us with
3767  * possibly-inaccurate values of relpages etc, but those will be fixed up
3768  * later.
3769  */
3770  if (RelationIsMapped(relation))
3771  {
3772  /* This case is only supported for indexes */
3773  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3774 
3775  /* Since we're not updating pg_class, these had better not change */
3776  Assert(classform->relfrozenxid == freezeXid);
3777  Assert(classform->relminmxid == minmulti);
3778  Assert(classform->relpersistence == persistence);
3779 
3780  /*
3781  * In some code paths it's possible that the tuple update we'd
3782  * otherwise do here is the only thing that would assign an XID for
3783  * the current transaction. However, we must have an XID to delete
3784  * files, so make sure one is assigned.
3785  */
3786  (void) GetCurrentTransactionId();
3787 
3788  /* Do the deed */
3790  newrelfilenode,
3791  relation->rd_rel->relisshared,
3792  false);
3793 
3794  /* Since we're not updating pg_class, must trigger inval manually */
3795  CacheInvalidateRelcache(relation);
3796  }
3797  else
3798  {
3799  /* Normal case, update the pg_class entry */
3800  classform->relfilenode = newrelfilenode;
3801 
3802  /* relpages etc. never change for sequences */
3803  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3804  {
3805  classform->relpages = 0; /* it's empty until further notice */
3806  classform->reltuples = -1;
3807  classform->relallvisible = 0;
3808  }
3809  classform->relfrozenxid = freezeXid;
3810  classform->relminmxid = minmulti;
3811  classform->relpersistence = persistence;
3812 
3813  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3814  }
3815 
3816  heap_freetuple(tuple);
3817 
3818  table_close(pg_class, RowExclusiveLock);
3819 
3820  /*
3821  * Make the pg_class row change or relation map change visible. This will
3822  * cause the relcache entry to get updated, too.
3823  */
3825 
3826  RelationAssumeNewRelfilenode(relation);
3827 }
TransactionId MultiXactId
Definition: c.h:597
uint32 TransactionId
Definition: c.h:587
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:490
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1362
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilenode(Relation relation)
Definition: relcache.c:3842
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
void RelationDropStorage(Relation rel)
Definition: storage.c:195
SMgrRelation RelationCreateStorage(RelFileNode rnode, char relpersistence)
Definition: storage.c:118
ItemPointerData t_self
Definition: htup.h:65
RelFileNode rd_node
Definition: rel.h:56
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:177
static void table_relation_set_new_filenode(Relation rel, const RelFileNode *newrnode, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1592
#define InvalidTransactionId
Definition: transam.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1073
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:440

References Assert(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ERROR, GetCurrentTransactionId(), GetNewRelFileNode(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidMultiXactId, InvalidTransactionId, ObjectIdGetDatum, RelationData::rd_node, RelationData::rd_rel, RelationAssumeNewRelfilenode(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileNode::relNode, RELOID, RowExclusiveLock, SearchSysCacheCopy1, smgrclose(), HeapTupleData::t_self, table_close(), table_open(), and table_relation_set_new_filenode().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt