PostgreSQL Source Code  git master
relcache.h File Reference
#include "postgres.h"
#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_ALL, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_IDENTITY_KEY }
 

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 (void)
 
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 133 of file relcache.h.

Referenced by RememberToFreeTupleDescAtEOX(), and smgrDoPendingSyncs().

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

typedef struct RelationData* Relation

Definition at line 27 of file relcache.h.

◆ RelationPtr

Definition at line 35 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_ALL 
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 

Definition at line 57 of file relcache.h.

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3223 of file relcache.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

3225 {
3227  RelIdCacheEnt *idhentry;
3228  int i;
3229 
3230  /*
3231  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3232  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3233  * logic as in AtEOXact_RelationCache.
3234  */
3236  {
3237  hash_seq_init(&status, RelationIdCache);
3238  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3239  {
3240  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3241  mySubid, parentSubid);
3242  }
3243  }
3244  else
3245  {
3246  for (i = 0; i < eoxact_list_len; i++)
3247  {
3248  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3249  (void *) &eoxact_list[i],
3250  HASH_FIND,
3251  NULL);
3252  if (idhentry != NULL)
3253  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3254  mySubid, parentSubid);
3255  }
3256  }
3257 
3258  /* Don't reset the list; we still need more cleanup later */
3259 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:164
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3270
Relation reldesc
Definition: relcache.c:128
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * RelationIdCache
Definition: relcache.c:131
static bool eoxact_list_overflowed
Definition: relcache.c:166
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
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
static int eoxact_list_len
Definition: relcache.c:165

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3078 of file relcache.c.

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

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

3079 {
3081  RelIdCacheEnt *idhentry;
3082  int i;
3083 
3084  /*
3085  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3086  * listed in it. Otherwise fall back on a hash_seq_search scan.
3087  *
3088  * For simplicity, eoxact_list[] entries are not deleted till end of
3089  * top-level transaction, even though we could remove them at
3090  * subtransaction end in some cases, or remove relations from the list if
3091  * they are cleared for other reasons. Therefore we should expect the
3092  * case that list entries are not found in the hashtable; if not, there's
3093  * nothing to do for them.
3094  */
3096  {
3097  hash_seq_init(&status, RelationIdCache);
3098  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3099  {
3100  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3101  }
3102  }
3103  else
3104  {
3105  for (i = 0; i < eoxact_list_len; i++)
3106  {
3107  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3108  (void *) &eoxact_list[i],
3109  HASH_FIND,
3110  NULL);
3111  if (idhentry != NULL)
3112  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3113  }
3114  }
3115 
3116  if (EOXactTupleDescArrayLen > 0)
3117  {
3118  Assert(EOXactTupleDescArray != NULL);
3119  for (i = 0; i < NextEOXactTupleDescNum; i++)
3122  EOXactTupleDescArray = NULL;
3123  }
3124 
3125  /* Now we're out of the transaction and can clear the lists */
3126  eoxact_list_len = 0;
3127  eoxact_list_overflowed = false;
3128  NextEOXactTupleDescNum = 0;
3130 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:164
static int EOXactTupleDescArrayLen
Definition: relcache.c:183
Relation reldesc
Definition: relcache.c:128
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * RelationIdCache
Definition: relcache.c:131
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3141
static bool eoxact_list_overflowed
Definition: relcache.c:166
static int NextEOXactTupleDescNum
Definition: relcache.c:182
void pfree(void *pointer)
Definition: mcxt.c:1169
#define Assert(condition)
Definition: c.h:804
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
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
static int eoxact_list_len
Definition: relcache.c:165
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:181

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5636 of file relcache.c.

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

5637 {
5641 
5642  return 0; /* return value does not matter */
5643 }
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define RelationGetRelationName(relation)
Definition: rel.h:511
int err_generic_string(int field, const char *str)
Definition: elog.c:1351
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5653 of file relcache.c.

References attname, errtablecolname(), get_attname(), NameStr, RelationGetDescr, RelationGetRelid, relidcacheent::reldesc, and TupleDescAttr.

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

5654 {
5655  TupleDesc reldesc = RelationGetDescr(rel);
5656  const char *colname;
5657 
5658  /* Use reldesc if it's a user attribute, else consult the catalogs */
5659  if (attnum > 0 && attnum <= reldesc->natts)
5660  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5661  else
5662  colname = get_attname(RelationGetRelid(rel), attnum, false);
5663 
5664  return errtablecolname(rel, colname);
5665 }
#define RelationGetDescr(relation)
Definition: rel.h:503
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:83
#define NameStr(name)
Definition: c.h:681
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
#define RelationGetRelid(relation)
Definition: rel.h:477
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5677

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5677 of file relcache.c.

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

Referenced by errtablecol().

5678 {
5679  errtable(rel);
5681 
5682  return 0; /* return value does not matter */
5683 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1351
int errtable(Relation rel)
Definition: relcache.c:5636

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5690 of file relcache.c.

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

Referenced by _bt_check_third_page(), _bt_check_unique(), ATPrepChangePersistence(), ATRewriteTable(), check_exclusion_or_unique_constraint(), comparetup_index_btree(), ExecCheckIndexConstraints(), ExecConstraints(), RI_FKey_check(), RI_Initial_Check(), and ri_ReportViolation().

5691 {
5692  errtable(rel);
5694 
5695  return 0; /* return value does not matter */
5696 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1351
int errtable(Relation rel)
Definition: relcache.c:5636

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5445 of file relcache.c.

References CacheMemoryContext, elog, ERROR, get_partition_ancestors(), GetAllTablesPublications(), GetRelationPublications(), 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, RelationGetRelid, ReleaseSysCache(), and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

5446 {
5447  List *puboids;
5448  ListCell *lc;
5449  MemoryContext oldcxt;
5450  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5451 
5452  /*
5453  * If not publishable, it publishes no actions. (pgoutput_change() will
5454  * ignore it.)
5455  */
5456  if (!is_publishable_relation(relation))
5457  return pubactions;
5458 
5459  if (relation->rd_pubactions)
5460  return memcpy(pubactions, relation->rd_pubactions,
5461  sizeof(PublicationActions));
5462 
5463  /* Fetch the publication membership info. */
5464  puboids = GetRelationPublications(RelationGetRelid(relation));
5465  if (relation->rd_rel->relispartition)
5466  {
5467  /* Add publications that the ancestors are in too. */
5468  List *ancestors = get_partition_ancestors(RelationGetRelid(relation));
5469  ListCell *lc;
5470 
5471  foreach(lc, ancestors)
5472  {
5473  Oid ancestor = lfirst_oid(lc);
5474 
5475  puboids = list_concat_unique_oid(puboids,
5476  GetRelationPublications(ancestor));
5477  }
5478  }
5479  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5480 
5481  foreach(lc, puboids)
5482  {
5483  Oid pubid = lfirst_oid(lc);
5484  HeapTuple tup;
5485  Form_pg_publication pubform;
5486 
5488 
5489  if (!HeapTupleIsValid(tup))
5490  elog(ERROR, "cache lookup failed for publication %u", pubid);
5491 
5492  pubform = (Form_pg_publication) GETSTRUCT(tup);
5493 
5494  pubactions->pubinsert |= pubform->pubinsert;
5495  pubactions->pubupdate |= pubform->pubupdate;
5496  pubactions->pubdelete |= pubform->pubdelete;
5497  pubactions->pubtruncate |= pubform->pubtruncate;
5498 
5499  ReleaseSysCache(tup);
5500 
5501  /*
5502  * If we know everything is replicated, there is no point to check for
5503  * other publications.
5504  */
5505  if (pubactions->pubinsert && pubactions->pubupdate &&
5506  pubactions->pubdelete && pubactions->pubtruncate)
5507  break;
5508  }
5509 
5510  if (relation->rd_pubactions)
5511  {
5512  pfree(relation->rd_pubactions);
5513  relation->rd_pubactions = NULL;
5514  }
5515 
5516  /* Now save copy of the actions in the relcache entry. */
5518  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5519  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5520  MemoryContextSwitchTo(oldcxt);
5521 
5522  return pubactions;
5523 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
PublicationActions * rd_pubactions
Definition: rel.h:163
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1316
bool is_publishable_relation(Relation rel)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void * palloc0(Size size)
Definition: mcxt.c:1093
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3749 of file relcache.c.

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

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

3750 {
3753  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3754 
3755  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3756  EOXactListAdd(relation);
3757 }
#define EOXactListAdd(rel)
Definition: relcache.c:168
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define InvalidSubTransactionId
Definition: c.h:593

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

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(), TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

3363 {
3364  Relation rel;
3365  MemoryContext oldcxt;
3366  int natts = tupDesc->natts;
3367  int i;
3368  bool has_not_null;
3369  bool nailit;
3370 
3371  AssertArg(natts >= 0);
3372 
3373  /*
3374  * check for creation of a rel that must be nailed in cache.
3375  *
3376  * XXX this list had better match the relations specially handled in
3377  * RelationCacheInitializePhase2/3.
3378  */
3379  switch (relid)
3380  {
3381  case DatabaseRelationId:
3382  case AuthIdRelationId:
3383  case AuthMemRelationId:
3384  case RelationRelationId:
3385  case AttributeRelationId:
3386  case ProcedureRelationId:
3387  case TypeRelationId:
3388  nailit = true;
3389  break;
3390  default:
3391  nailit = false;
3392  break;
3393  }
3394 
3395  /*
3396  * check that hardwired list of shared rels matches what's in the
3397  * bootstrap .bki file. If you get a failure here during initdb, you
3398  * probably need to fix IsSharedRelation() to match whatever you've done
3399  * to the set of shared relations.
3400  */
3401  if (shared_relation != IsSharedRelation(relid))
3402  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3403  relname, relid);
3404 
3405  /* Shared relations had better be mapped, too */
3406  Assert(mapped_relation || !shared_relation);
3407 
3408  /*
3409  * switch to the cache context to create the relcache entry.
3410  */
3411  if (!CacheMemoryContext)
3413 
3415 
3416  /*
3417  * allocate a new relation descriptor and fill in basic state fields.
3418  */
3419  rel = (Relation) palloc0(sizeof(RelationData));
3420 
3421  /* make sure relation is marked as having no open file yet */
3422  rel->rd_smgr = NULL;
3423 
3424  /* mark it nailed if appropriate */
3425  rel->rd_isnailed = nailit;
3426 
3427  rel->rd_refcnt = nailit ? 1 : 0;
3428 
3429  /* it's being created in this transaction */
3434 
3435  /*
3436  * create a new tuple descriptor from the one passed in. We do this
3437  * partly to copy it into the cache context, and partly because the new
3438  * relation can't have any defaults or constraints yet; they have to be
3439  * added in later steps, because they require additions to multiple system
3440  * catalogs. We can copy attnotnull constraints here, however.
3441  */
3442  rel->rd_att = CreateTupleDescCopy(tupDesc);
3443  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3444  has_not_null = false;
3445  for (i = 0; i < natts; i++)
3446  {
3447  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3448  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3449 
3450  datt->attidentity = satt->attidentity;
3451  datt->attgenerated = satt->attgenerated;
3452  datt->attnotnull = satt->attnotnull;
3453  has_not_null |= satt->attnotnull;
3454  }
3455 
3456  if (has_not_null)
3457  {
3458  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3459 
3460  constr->has_not_null = true;
3461  rel->rd_att->constr = constr;
3462  }
3463 
3464  /*
3465  * initialize relation tuple form (caller may add/override data later)
3466  */
3468 
3469  namestrcpy(&rel->rd_rel->relname, relname);
3470  rel->rd_rel->relnamespace = relnamespace;
3471 
3472  rel->rd_rel->relkind = relkind;
3473  rel->rd_rel->relnatts = natts;
3474  rel->rd_rel->reltype = InvalidOid;
3475  /* needed when bootstrapping: */
3476  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3477 
3478  /* set up persistence and relcache fields dependent on it */
3479  rel->rd_rel->relpersistence = relpersistence;
3480  switch (relpersistence)
3481  {
3482  case RELPERSISTENCE_UNLOGGED:
3483  case RELPERSISTENCE_PERMANENT:
3485  rel->rd_islocaltemp = false;
3486  break;
3487  case RELPERSISTENCE_TEMP:
3488  Assert(isTempOrTempToastNamespace(relnamespace));
3490  rel->rd_islocaltemp = true;
3491  break;
3492  default:
3493  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3494  break;
3495  }
3496 
3497  /* if it's a materialized view, it's not populated initially */
3498  if (relkind == RELKIND_MATVIEW)
3499  rel->rd_rel->relispopulated = false;
3500  else
3501  rel->rd_rel->relispopulated = true;
3502 
3503  /* set replica identity -- system catalogs and non-tables don't have one */
3504  if (!IsCatalogNamespace(relnamespace) &&
3505  (relkind == RELKIND_RELATION ||
3506  relkind == RELKIND_MATVIEW ||
3507  relkind == RELKIND_PARTITIONED_TABLE))
3508  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3509  else
3510  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3511 
3512  /*
3513  * Insert relation physical and logical identifiers (OIDs) into the right
3514  * places. For a mapped relation, we set relfilenode to zero and rely on
3515  * RelationInitPhysicalAddr to consult the map.
3516  */
3517  rel->rd_rel->relisshared = shared_relation;
3518 
3519  RelationGetRelid(rel) = relid;
3520 
3521  for (i = 0; i < natts; i++)
3522  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3523 
3524  rel->rd_rel->reltablespace = reltablespace;
3525 
3526  if (mapped_relation)
3527  {
3528  rel->rd_rel->relfilenode = InvalidOid;
3529  /* Add it to the active mapping information */
3530  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3531  }
3532  else
3533  rel->rd_rel->relfilenode = relfilenode;
3534 
3535  RelationInitLockInfo(rel); /* see lmgr.c */
3536 
3538 
3539  rel->rd_rel->relam = accessmtd;
3540 
3541  /*
3542  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3543  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3544  * require a long-lived current context.
3545  */
3546  MemoryContextSwitchTo(oldcxt);
3547 
3548  if (relkind == RELKIND_RELATION ||
3549  relkind == RELKIND_SEQUENCE ||
3550  relkind == RELKIND_TOASTVALUE ||
3551  relkind == RELKIND_MATVIEW)
3553 
3554  /*
3555  * Okay to insert into the relcache hash table.
3556  *
3557  * Ordinarily, there should certainly not be an existing hash entry for
3558  * the same OID; but during bootstrap, when we create a "real" relcache
3559  * entry for one of the bootstrap relations, we'll be overwriting the
3560  * phony one created with formrdesc. So allow that to happen for nailed
3561  * rels.
3562  */
3563  RelationCacheInsert(rel, nailit);
3564 
3565  /*
3566  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3567  * can't do this before storing relid in it.
3568  */
3569  EOXactListAdd(rel);
3570 
3571  /* It's fully valid */
3572  rel->rd_isvalid = true;
3573 
3574  /*
3575  * Caller expects us to pin the returned entry.
3576  */
3578 
3579  return rel;
3580 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
#define EOXactListAdd(rel)
Definition: relcache.c:168
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3226
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1743
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
Form_pg_class rd_rel
Definition: rel.h:109
NameData relname
Definition: pg_class.h:38
struct RelationData * Relation
Definition: relcache.h:27
#define ERROR
Definition: elog.h:46
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1254
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:72
#define BackendIdForTempRelations()
Definition: backendid.h:34
TupleConstr * constr
Definition: tupdesc.h:85
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define AssertArg(condition)
Definition: c.h:806
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:1093
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2068
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:244
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:188
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:804
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
SMgrRelation rd_smgr
Definition: rel.h:57
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define InvalidSubTransactionId
Definition: c.h:593
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:183
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:232
int i
int tdrefcount
Definition: tupdesc.h:84
bool has_not_null
Definition: tupdesc.h:44
#define RelationGetRelid(relation)
Definition: rel.h:477
SubTransactionId rd_droppedSubid
Definition: rel.h:107
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6465 of file relcache.c.

References LWLockRelease().

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

6466 {
6467  LWLockRelease(RelCacheInitLock);
6468 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6440 of file relcache.c.

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

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

6441 {
6442  char localinitfname[MAXPGPATH];
6443  char sharedinitfname[MAXPGPATH];
6444 
6445  if (DatabasePath)
6446  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6448  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6450 
6451  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6452 
6453  /*
6454  * The files might not be there if no backend has been started since the
6455  * last removal. But complain about failures other than ENOENT with
6456  * ERROR. Fortunately, it's not too late to abort the transaction if we
6457  * can't get rid of the would-be-obsolete init file.
6458  */
6459  if (DatabasePath)
6460  unlink_initfile(localinitfname, ERROR);
6461  unlink_initfile(sharedinitfname, ERROR);
6462 }
#define ERROR
Definition: elog.h:46
#define MAXPGPATH
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
char * DatabasePath
Definition: globals.c:96
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6537
#define snprintf
Definition: port.h:216

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6480 of file relcache.c.

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

Referenced by StartupXLOG().

6481 {
6482  const char *tblspcdir = "pg_tblspc";
6483  DIR *dir;
6484  struct dirent *de;
6485  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6486 
6487  snprintf(path, sizeof(path), "global/%s",
6489  unlink_initfile(path, LOG);
6490 
6491  /* Scan everything in the default tablespace */
6493 
6494  /* Scan the tablespace link directory to find non-default tablespaces */
6495  dir = AllocateDir(tblspcdir);
6496 
6497  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6498  {
6499  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6500  {
6501  /* Scan the tablespace dir for per-database dirs */
6502  snprintf(path, sizeof(path), "%s/%s/%s",
6503  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6505  }
6506  }
6507 
6508  FreeDir(dir);
6509 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6513
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2801
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2720
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6537
char d_name[MAX_PATH]
Definition: dirent.h:15
#define snprintf
Definition: port.h:216
int FreeDir(DIR *dir)
Definition: fd.c:2838

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3775 of file relcache.c.

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

Referenced by InitPostgres().

3776 {
3777  HASHCTL ctl;
3778 
3779  /*
3780  * make sure cache memory context exists
3781  */
3782  if (!CacheMemoryContext)
3784 
3785  /*
3786  * create hashtable that indexes the relcache
3787  */
3788  ctl.keysize = sizeof(Oid);
3789  ctl.entrysize = sizeof(RelIdCacheEnt);
3790  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3791  &ctl, HASH_ELEM | HASH_BLOBS);
3792 
3793  /*
3794  * relation mapper needs to be initialized too
3795  */
3797 }
void RelationMapInitialize(void)
Definition: relmapper.c:584
#define HASH_ELEM
Definition: hsearch.h:95
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:76
static HTAB * RelationIdCache
Definition: relcache.c:131
unsigned int Oid
Definition: postgres_ext.h:31
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
#define HASH_BLOBS
Definition: hsearch.h:97
Size keysize
Definition: hsearch.h:75
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define INITRELCACHESIZE
Definition: relcache.c:3772
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3811 of file relcache.c.

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

3812 {
3813  MemoryContext oldcxt;
3814 
3815  /*
3816  * relation mapper needs initialized too
3817  */
3819 
3820  /*
3821  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3822  * nothing.
3823  */
3825  return;
3826 
3827  /*
3828  * switch to cache memory context
3829  */
3831 
3832  /*
3833  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3834  * the cache with pre-made descriptors for the critical shared catalogs.
3835  */
3836  if (!load_relcache_init_file(true))
3837  {
3838  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3839  Natts_pg_database, Desc_pg_database);
3840  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3841  Natts_pg_authid, Desc_pg_authid);
3842  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3843  Natts_pg_auth_members, Desc_pg_auth_members);
3844  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3845  Natts_pg_shseclabel, Desc_pg_shseclabel);
3846  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3847  Natts_pg_subscription, Desc_pg_subscription);
3848 
3849 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3850  }
3851 
3852  MemoryContextSwitchTo(oldcxt);
3853 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:114
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5754
void RelationMapInitializePhase2(void)
Definition: relmapper.c:604
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 MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:116
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:406
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1807
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3870 of file relcache.c.

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, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, SearchSysCache1(), status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

3871 {
3873  RelIdCacheEnt *idhentry;
3874  MemoryContext oldcxt;
3875  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3876 
3877  /*
3878  * relation mapper needs initialized too
3879  */
3881 
3882  /*
3883  * switch to cache memory context
3884  */
3886 
3887  /*
3888  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3889  * the cache with pre-made descriptors for the critical "nailed-in" system
3890  * catalogs.
3891  */
3892  if (IsBootstrapProcessingMode() ||
3893  !load_relcache_init_file(false))
3894  {
3895  needNewCacheFile = true;
3896 
3897  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3898  Natts_pg_class, Desc_pg_class);
3899  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3900  Natts_pg_attribute, Desc_pg_attribute);
3901  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3902  Natts_pg_proc, Desc_pg_proc);
3903  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3904  Natts_pg_type, Desc_pg_type);
3905 
3906 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3907  }
3908 
3909  MemoryContextSwitchTo(oldcxt);
3910 
3911  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3913  return;
3914 
3915  /*
3916  * If we didn't get the critical system indexes loaded into relcache, do
3917  * so now. These are critical because the catcache and/or opclass cache
3918  * depend on them for fetches done during relcache load. Thus, we have an
3919  * infinite-recursion problem. We can break the recursion by doing
3920  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3921  * performance, we only want to do that until we have the critical indexes
3922  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3923  * decide whether to do heapscan or indexscan at the key spots, and we set
3924  * it true after we've loaded the critical indexes.
3925  *
3926  * The critical indexes are marked as "nailed in cache", partly to make it
3927  * easy for load_relcache_init_file to count them, but mainly because we
3928  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3929  * true. (NOTE: perhaps it would be possible to reload them by
3930  * temporarily setting criticalRelcachesBuilt to false again. For now,
3931  * though, we just nail 'em in.)
3932  *
3933  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3934  * in the same way as the others, because the critical catalogs don't
3935  * (currently) have any rules or triggers, and so these indexes can be
3936  * rebuilt without inducing recursion. However they are used during
3937  * relcache load when a rel does have rules or triggers, so we choose to
3938  * nail them for performance reasons.
3939  */
3941  {
3942  load_critical_index(ClassOidIndexId,
3943  RelationRelationId);
3944  load_critical_index(AttributeRelidNumIndexId,
3945  AttributeRelationId);
3946  load_critical_index(IndexRelidIndexId,
3947  IndexRelationId);
3948  load_critical_index(OpclassOidIndexId,
3949  OperatorClassRelationId);
3950  load_critical_index(AccessMethodProcedureIndexId,
3951  AccessMethodProcedureRelationId);
3952  load_critical_index(RewriteRelRulenameIndexId,
3953  RewriteRelationId);
3954  load_critical_index(TriggerRelidNameIndexId,
3955  TriggerRelationId);
3956 
3957 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3958 
3959  criticalRelcachesBuilt = true;
3960  }
3961 
3962  /*
3963  * Process critical shared indexes too.
3964  *
3965  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3966  * initial lookup of MyDatabaseId, without which we'll never find any
3967  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3968  * database OID, so it instead depends on DatabaseOidIndexId. We also
3969  * need to nail up some indexes on pg_authid and pg_auth_members for use
3970  * during client authentication. SharedSecLabelObjectIndexId isn't
3971  * critical for the core system, but authentication hooks might be
3972  * interested in it.
3973  */
3975  {
3976  load_critical_index(DatabaseNameIndexId,
3977  DatabaseRelationId);
3978  load_critical_index(DatabaseOidIndexId,
3979  DatabaseRelationId);
3980  load_critical_index(AuthIdRolnameIndexId,
3981  AuthIdRelationId);
3982  load_critical_index(AuthIdOidIndexId,
3983  AuthIdRelationId);
3984  load_critical_index(AuthMemMemRoleIndexId,
3985  AuthMemRelationId);
3986  load_critical_index(SharedSecLabelObjectIndexId,
3987  SharedSecLabelRelationId);
3988 
3989 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3990 
3992  }
3993 
3994  /*
3995  * Now, scan all the relcache entries and update anything that might be
3996  * wrong in the results from formrdesc or the relcache cache file. If we
3997  * faked up relcache entries using formrdesc, then read the real pg_class
3998  * rows and replace the fake entries with them. Also, if any of the
3999  * relcache entries have rules, triggers, or security policies, load that
4000  * info the hard way since it isn't recorded in the cache file.
4001  *
4002  * Whenever we access the catalogs to read data, there is a possibility of
4003  * a shared-inval cache flush causing relcache entries to be removed.
4004  * Since hash_seq_search only guarantees to still work after the *current*
4005  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4006  * We handle this by restarting the scan from scratch after each access.
4007  * This is theoretically O(N^2), but the number of entries that actually
4008  * need to be fixed is small enough that it doesn't matter.
4009  */
4010  hash_seq_init(&status, RelationIdCache);
4011 
4012  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4013  {
4014  Relation relation = idhentry->reldesc;
4015  bool restart = false;
4016 
4017  /*
4018  * Make sure *this* entry doesn't get flushed while we work with it.
4019  */
4021 
4022  /*
4023  * If it's a faked-up entry, read the real pg_class tuple.
4024  */
4025  if (relation->rd_rel->relowner == InvalidOid)
4026  {
4027  HeapTuple htup;
4028  Form_pg_class relp;
4029 
4030  htup = SearchSysCache1(RELOID,
4031  ObjectIdGetDatum(RelationGetRelid(relation)));
4032  if (!HeapTupleIsValid(htup))
4033  elog(FATAL, "cache lookup failed for relation %u",
4034  RelationGetRelid(relation));
4035  relp = (Form_pg_class) GETSTRUCT(htup);
4036 
4037  /*
4038  * Copy tuple to relation->rd_rel. (See notes in
4039  * AllocateRelationDesc())
4040  */
4041  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4042 
4043  /* Update rd_options while we have the tuple */
4044  if (relation->rd_options)
4045  pfree(relation->rd_options);
4046  RelationParseRelOptions(relation, htup);
4047 
4048  /*
4049  * Check the values in rd_att were set up correctly. (We cannot
4050  * just copy them over now: formrdesc must have set up the rd_att
4051  * data correctly to start with, because it may already have been
4052  * copied into one or more catcache entries.)
4053  */
4054  Assert(relation->rd_att->tdtypeid == relp->reltype);
4055  Assert(relation->rd_att->tdtypmod == -1);
4056 
4057  ReleaseSysCache(htup);
4058 
4059  /* relowner had better be OK now, else we'll loop forever */
4060  if (relation->rd_rel->relowner == InvalidOid)
4061  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4062  RelationGetRelationName(relation));
4063 
4064  restart = true;
4065  }
4066 
4067  /*
4068  * Fix data that isn't saved in relcache cache file.
4069  *
4070  * relhasrules or relhastriggers could possibly be wrong or out of
4071  * date. If we don't actually find any rules or triggers, clear the
4072  * local copy of the flag so that we don't get into an infinite loop
4073  * here. We don't make any attempt to fix the pg_class entry, though.
4074  */
4075  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4076  {
4077  RelationBuildRuleLock(relation);
4078  if (relation->rd_rules == NULL)
4079  relation->rd_rel->relhasrules = false;
4080  restart = true;
4081  }
4082  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4083  {
4084  RelationBuildTriggers(relation);
4085  if (relation->trigdesc == NULL)
4086  relation->rd_rel->relhastriggers = false;
4087  restart = true;
4088  }
4089 
4090  /*
4091  * Re-load the row security policies if the relation has them, since
4092  * they are not preserved in the cache. Note that we can never NOT
4093  * have a policy while relrowsecurity is true,
4094  * RelationBuildRowSecurity will create a single default-deny policy
4095  * if there is no policy defined in pg_policy.
4096  */
4097  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4098  {
4099  RelationBuildRowSecurity(relation);
4100 
4101  Assert(relation->rd_rsdesc != NULL);
4102  restart = true;
4103  }
4104 
4105  /* Reload tableam data if needed */
4106  if (relation->rd_tableam == NULL &&
4107  (relation->rd_rel->relkind == RELKIND_RELATION ||
4108  relation->rd_rel->relkind == RELKIND_SEQUENCE ||
4109  relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
4110  relation->rd_rel->relkind == RELKIND_MATVIEW))
4111  {
4113  Assert(relation->rd_tableam != NULL);
4114 
4115  restart = true;
4116  }
4117 
4118  /* Release hold on the relation */
4120 
4121  /* Now, restart the hashtable scan if needed */
4122  if (restart)
4123  {
4124  hash_seq_term(&status);
4125  hash_seq_init(&status, RelationIdCache);
4126  }
4127  }
4128 
4129  /*
4130  * Lastly, write out new relcache cache files if needed. We don't bother
4131  * to distinguish cases where only one of the two needs an update.
4132  */
4133  if (needNewCacheFile)
4134  {
4135  /*
4136  * Force all the catcaches to finish initializing and thereby open the
4137  * catalogs and indexes they use. This will preload the relcache with
4138  * entries for all the most important system catalogs and indexes, so
4139  * that the init files will be most useful for future backends.
4140  */
4142 
4143  /* now write the files */
4145  write_relcache_init_file(false);
4146  }
4147 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5754
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:196
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1743
Relation reldesc
Definition: relcache.c:128
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:143
static HTAB * RelationIdCache
Definition: relcache.c:131
Form_pg_class rd_rel
Definition: rel.h:109
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2081
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
int32 tdtypmod
Definition: tupdesc.h:83
#define FATAL
Definition: elog.h:49
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6173
TriggerDesc * trigdesc
Definition: rel.h:115
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:441
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4156
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:110
#define RelationGetRelationName(relation)
Definition: rel.h:511
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2068
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
const struct TableAmRoutine * rd_tableam
Definition: rel.h:184
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
RuleLock * rd_rules
Definition: rel.h:113
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
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:406
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
Oid tdtypeid
Definition: tupdesc.h:82
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1785
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1807
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:108
#define elog(elevel,...)
Definition: elog.h:232
void RelationMapInitializePhase3(void)
Definition: relmapper.c:625
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:708
bool criticalRelcachesBuilt
Definition: relcache.c:137
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
void InitCatalogCachePhase2(void)
Definition: syscache.c:1086
#define RelationGetRelid(relation)
Definition: rel.h:477
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:111
bytea * rd_options
Definition: rel.h:170
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:109
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2840 of file relcache.c.

References Assert, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_isnailed, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCaches(), and LocalExecuteInvalidationMessage().

2841 {
2843  RelIdCacheEnt *idhentry;
2844  Relation relation;
2845  List *rebuildFirstList = NIL;
2846  List *rebuildList = NIL;
2847  ListCell *l;
2848 
2849  /*
2850  * Reload relation mapping data before starting to reconstruct cache.
2851  */
2853 
2854  /* Phase 1 */
2855  hash_seq_init(&status, RelationIdCache);
2856 
2857  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2858  {
2859  relation = idhentry->reldesc;
2860 
2861  /* Must close all smgr references to avoid leaving dangling ptrs */
2862  RelationCloseSmgr(relation);
2863 
2864  /*
2865  * Ignore new relations; no other backend will manipulate them before
2866  * we commit. Likewise, before replacing a relation's relfilenode, we
2867  * shall have acquired AccessExclusiveLock and drained any applicable
2868  * pending invalidations.
2869  */
2870  if (relation->rd_createSubid != InvalidSubTransactionId ||
2872  continue;
2873 
2875 
2876  if (RelationHasReferenceCountZero(relation))
2877  {
2878  /* Delete this entry immediately */
2879  Assert(!relation->rd_isnailed);
2880  RelationClearRelation(relation, false);
2881  }
2882  else
2883  {
2884  /*
2885  * If it's a mapped relation, immediately update its rd_node in
2886  * case its relfilenode changed. We must do this during phase 1
2887  * in case the relation is consulted during rebuild of other
2888  * relcache entries in phase 2. It's safe since consulting the
2889  * map doesn't involve any access to relcache entries.
2890  */
2891  if (RelationIsMapped(relation))
2892  RelationInitPhysicalAddr(relation);
2893 
2894  /*
2895  * Add this entry to list of stuff to rebuild in second pass.
2896  * pg_class goes to the front of rebuildFirstList while
2897  * pg_class_oid_index goes to the back of rebuildFirstList, so
2898  * they are done first and second respectively. Other nailed
2899  * relations go to the front of rebuildList, so they'll be done
2900  * next in no particular order; and everything else goes to the
2901  * back of rebuildList.
2902  */
2903  if (RelationGetRelid(relation) == RelationRelationId)
2904  rebuildFirstList = lcons(relation, rebuildFirstList);
2905  else if (RelationGetRelid(relation) == ClassOidIndexId)
2906  rebuildFirstList = lappend(rebuildFirstList, relation);
2907  else if (relation->rd_isnailed)
2908  rebuildList = lcons(relation, rebuildList);
2909  else
2910  rebuildList = lappend(rebuildList, relation);
2911  }
2912  }
2913 
2914  /*
2915  * Now zap any remaining smgr cache entries. This must happen before we
2916  * start to rebuild entries, since that may involve catalog fetches which
2917  * will re-open catalog files.
2918  */
2919  smgrcloseall();
2920 
2921  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2922  foreach(l, rebuildFirstList)
2923  {
2924  relation = (Relation) lfirst(l);
2925  RelationClearRelation(relation, true);
2926  }
2927  list_free(rebuildFirstList);
2928  foreach(l, rebuildList)
2929  {
2930  relation = (Relation) lfirst(l);
2931  RelationClearRelation(relation, true);
2932  }
2933  list_free(rebuildList);
2934 }
#define NIL
Definition: pg_list.h:65
static long relcacheInvalsReceived
Definition: relcache.c:151
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
bool rd_isnailed
Definition: rel.h:61
Relation reldesc
Definition: relcache.c:128
#define RelationCloseSmgr(relation)
Definition: rel.h:557
static HTAB * RelationIdCache
Definition: relcache.c:131
void smgrcloseall(void)
Definition: smgr.c:286
struct RelationData * Relation
Definition: relcache.h:27
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1254
List * lappend(List *list, void *datum)
Definition: list.c:336
#define RelationIsMapped(relation)
Definition: rel.h:526
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
List * lcons(void *datum, List *list)
Definition: list.c:468
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593
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
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:461
void list_free(List *list)
Definition: list.c:1391
void RelationMapInvalidateAll(void)
Definition: relmapper.c:425
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2797 of file relcache.c.

References PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.

Referenced by LocalExecuteInvalidationMessage().

2798 {
2799  Relation relation;
2800 
2801  RelationIdCacheLookup(relationId, relation);
2802 
2803  if (PointerIsValid(relation))
2804  {
2806  RelationFlushRelation(relation);
2807  }
2808 }
static long relcacheInvalsReceived
Definition: relcache.c:151
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2720
#define PointerIsValid(pointer)
Definition: c.h:698

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2101 of file relcache.c.

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(), RememberToFreeTupleDescAtEOX(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and ResourceOwnerReleaseInternal().

2102 {
2103  /* Note: no locking manipulations needed */
2105 
2106  /*
2107  * If the relation is no longer open in this session, we can clean up any
2108  * stale partition descriptors it has. This is unlikely, so check to see
2109  * if there are child contexts before expending a call to mcxt.c.
2110  */
2111  if (RelationHasReferenceCountZero(relation))
2112  {
2113  if (relation->rd_pdcxt != NULL &&
2114  relation->rd_pdcxt->firstchild != NULL)
2116 
2117  if (relation->rd_pddcxt != NULL &&
2118  relation->rd_pddcxt->firstchild != NULL)
2120  }
2121 
2122 #ifdef RELCACHE_FORCE_RELEASE
2123  if (RelationHasReferenceCountZero(relation) &&
2124  relation->rd_createSubid == InvalidSubTransactionId &&
2126  RelationClearRelation(relation, false);
2127 #endif
2128 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
MemoryContext firstchild
Definition: memnodes.h:87
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2081
MemoryContext rd_pddcxt
Definition: rel.h:133
SubTransactionId rd_createSubid
Definition: rel.h:102
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
MemoryContext rd_pdcxt
Definition: rel.h:129
#define InvalidSubTransactionId
Definition: c.h:593
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:461

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 2943 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

2944 {
2945  Relation relation;
2946 
2947  RelationIdCacheLookup(relationId, relation);
2948 
2949  if (!PointerIsValid(relation))
2950  return; /* not in cache, nothing to do */
2951 
2952  RelationCloseSmgr(relation);
2953 }
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
#define RelationCloseSmgr(relation)
Definition: rel.h:557
#define PointerIsValid(pointer)
Definition: c.h:698

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2753 of file relcache.c.

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

2754 {
2755  Relation relation;
2756 
2757  RelationIdCacheLookup(rid, relation);
2758 
2759  if (!PointerIsValid(relation))
2760  return; /* not in cache, nothing to do */
2761 
2762  if (!RelationHasReferenceCountZero(relation))
2763  elog(ERROR, "relation %u is still open", rid);
2764 
2766  if (relation->rd_createSubid != InvalidSubTransactionId ||
2768  {
2769  /*
2770  * In the event of subtransaction rollback, we must not forget
2771  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2772  * invalidates it in lieu of destroying it. (If we're in a top
2773  * transaction, we could opt to destroy the entry.)
2774  */
2776  }
2777 
2778  RelationClearRelation(relation, false);
2779 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
#define ERROR
Definition: elog.h:46
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define Assert(condition)
Definition: c.h:804
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define InvalidSubTransactionId
Definition: c.h:593
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:461
#define elog(elevel,...)
Definition: elog.h:232
#define PointerIsValid(pointer)
Definition: c.h:698
SubTransactionId rd_droppedSubid
Definition: rel.h:107

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 4866 of file relcache.c.

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

Referenced by BuildDummyIndexInfo().

4867 {
4868  List *result;
4869  Datum exprsDatum;
4870  bool isnull;
4871  char *exprsString;
4872  List *rawExprs;
4873  ListCell *lc;
4874 
4875  /* Quick exit if there is nothing to do. */
4876  if (relation->rd_indextuple == NULL ||
4877  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4878  return NIL;
4879 
4880  /* Extract raw node tree(s) from index tuple. */
4881  exprsDatum = heap_getattr(relation->rd_indextuple,
4882  Anum_pg_index_indexprs,
4884  &isnull);
4885  Assert(!isnull);
4886  exprsString = TextDatumGetCString(exprsDatum);
4887  rawExprs = (List *) stringToNode(exprsString);
4888  pfree(exprsString);
4889 
4890  /* Construct null Consts; the typlen and typbyval are arbitrary. */
4891  result = NIL;
4892  foreach(lc, rawExprs)
4893  {
4894  Node *rawExpr = (Node *) lfirst(lc);
4895 
4896  result = lappend(result,
4897  makeConst(exprType(rawExpr),
4898  exprTypmod(rawExpr),
4899  exprCollation(rawExpr),
4900  1,
4901  (Datum) 0,
4902  true,
4903  true));
4904  }
4905 
4906  return result;
4907 }
#define NIL
Definition: pg_list.h:65
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Definition: nodes.h:536
void * stringToNode(const char *str)
Definition: read.c:89
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:299
struct HeapTupleData * rd_indextuple
Definition: rel.h:189
void pfree(void *pointer)
Definition: mcxt.c:1169
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4235
List * lappend(List *list, void *datum)
Definition: list.c:336
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
Definition: pg_list.h:50

◆ RelationGetExclusionInfo()

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

Definition at line 5321 of file relcache.c.

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

5325 {
5326  int indnkeyatts;
5327  Oid *ops;
5328  Oid *funcs;
5329  uint16 *strats;
5330  Relation conrel;
5331  SysScanDesc conscan;
5332  ScanKeyData skey[1];
5333  HeapTuple htup;
5334  bool found;
5335  MemoryContext oldcxt;
5336  int i;
5337 
5338  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5339 
5340  /* Allocate result space in caller context */
5341  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5342  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5343  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5344 
5345  /* Quick exit if we have the data cached already */
5346  if (indexRelation->rd_exclstrats != NULL)
5347  {
5348  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5349  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5350  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5351  return;
5352  }
5353 
5354  /*
5355  * Search pg_constraint for the constraint associated with the index. To
5356  * make this not too painfully slow, we use the index on conrelid; that
5357  * will hold the parent relation's OID not the index's own OID.
5358  *
5359  * Note: if we wanted to rely on the constraint name matching the index's
5360  * name, we could just do a direct lookup using pg_constraint's unique
5361  * index. For the moment it doesn't seem worth requiring that.
5362  */
5363  ScanKeyInit(&skey[0],
5364  Anum_pg_constraint_conrelid,
5365  BTEqualStrategyNumber, F_OIDEQ,
5366  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5367 
5368  conrel = table_open(ConstraintRelationId, AccessShareLock);
5369  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5370  NULL, 1, skey);
5371  found = false;
5372 
5373  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5374  {
5376  Datum val;
5377  bool isnull;
5378  ArrayType *arr;
5379  int nelem;
5380 
5381  /* We want the exclusion constraint owning the index */
5382  if (conform->contype != CONSTRAINT_EXCLUSION ||
5383  conform->conindid != RelationGetRelid(indexRelation))
5384  continue;
5385 
5386  /* There should be only one */
5387  if (found)
5388  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5389  RelationGetRelationName(indexRelation));
5390  found = true;
5391 
5392  /* Extract the operator OIDS from conexclop */
5393  val = fastgetattr(htup,
5394  Anum_pg_constraint_conexclop,
5395  conrel->rd_att, &isnull);
5396  if (isnull)
5397  elog(ERROR, "null conexclop for rel %s",
5398  RelationGetRelationName(indexRelation));
5399 
5400  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5401  nelem = ARR_DIMS(arr)[0];
5402  if (ARR_NDIM(arr) != 1 ||
5403  nelem != indnkeyatts ||
5404  ARR_HASNULL(arr) ||
5405  ARR_ELEMTYPE(arr) != OIDOID)
5406  elog(ERROR, "conexclop is not a 1-D Oid array");
5407 
5408  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5409  }
5410 
5411  systable_endscan(conscan);
5412  table_close(conrel, AccessShareLock);
5413 
5414  if (!found)
5415  elog(ERROR, "exclusion constraint record missing for rel %s",
5416  RelationGetRelationName(indexRelation));
5417 
5418  /* We need the func OIDs and strategy numbers too */
5419  for (i = 0; i < indnkeyatts; i++)
5420  {
5421  funcs[i] = get_opcode(ops[i]);
5422  strats[i] = get_op_opfamily_strategy(ops[i],
5423  indexRelation->rd_opfamily[i]);
5424  /* shouldn't fail, since it was checked at index creation */
5425  if (strats[i] == InvalidStrategy)
5426  elog(ERROR, "could not find strategy for operator %u in family %u",
5427  ops[i], indexRelation->rd_opfamily[i]);
5428  }
5429 
5430  /* Save a copy of the results in the relcache entry. */
5431  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5432  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5433  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5434  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5435  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5436  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5437  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5438  MemoryContextSwitchTo(oldcxt);
5439 }
#define InvalidStrategy
Definition: stratnum.h:24
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:711
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:211
#define AccessShareLock
Definition: lockdefs.h:36
Oid * rd_exclprocs
Definition: rel.h:210
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
Form_pg_index rd_index
Definition: rel.h:187
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
unsigned short uint16
Definition: c.h:440
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define ARR_HASNULL(a)
Definition: array.h:284
Oid * rd_opfamily
Definition: rel.h:202
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:496
Oid * rd_exclops
Definition: rel.h:209
uintptr_t Datum
Definition: postgres.h:411
TupleDesc rd_att
Definition: rel.h:110
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ARR_NDIM(a)
Definition: array.h:283
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:81
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
MemoryContext rd_indexcxt
Definition: rel.h:199
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define RelationGetRelid(relation)
Definition: rel.h:477
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:254

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4464 of file relcache.c.

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

4465 {
4466  List *result;
4467  Relation conrel;
4468  SysScanDesc conscan;
4469  ScanKeyData skey;
4470  HeapTuple htup;
4471  List *oldlist;
4472  MemoryContext oldcxt;
4473 
4474  /* Quick exit if we already computed the list. */
4475  if (relation->rd_fkeyvalid)
4476  return relation->rd_fkeylist;
4477 
4478  /* Fast path: non-partitioned tables without triggers can't have FKs */
4479  if (!relation->rd_rel->relhastriggers &&
4480  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4481  return NIL;
4482 
4483  /*
4484  * We build the list we intend to return (in the caller's context) while
4485  * doing the scan. After successfully completing the scan, we copy that
4486  * list into the relcache entry. This avoids cache-context memory leakage
4487  * if we get some sort of error partway through.
4488  */
4489  result = NIL;
4490 
4491  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4492  ScanKeyInit(&skey,
4493  Anum_pg_constraint_conrelid,
4494  BTEqualStrategyNumber, F_OIDEQ,
4495  ObjectIdGetDatum(RelationGetRelid(relation)));
4496 
4497  conrel = table_open(ConstraintRelationId, AccessShareLock);
4498  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4499  NULL, 1, &skey);
4500 
4501  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4502  {
4503  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4504  ForeignKeyCacheInfo *info;
4505 
4506  /* consider only foreign keys */
4507  if (constraint->contype != CONSTRAINT_FOREIGN)
4508  continue;
4509 
4510  info = makeNode(ForeignKeyCacheInfo);
4511  info->conoid = constraint->oid;
4512  info->conrelid = constraint->conrelid;
4513  info->confrelid = constraint->confrelid;
4514 
4515  DeconstructFkConstraintRow(htup, &info->nkeys,
4516  info->conkey,
4517  info->confkey,
4518  info->conpfeqop,
4519  NULL, NULL);
4520 
4521  /* Add FK's node to the result list */
4522  result = lappend(result, info);
4523  }
4524 
4525  systable_endscan(conscan);
4526  table_close(conrel, AccessShareLock);
4527 
4528  /* Now save a copy of the completed list in the relcache entry. */
4530  oldlist = relation->rd_fkeylist;
4531  relation->rd_fkeylist = copyObject(result);
4532  relation->rd_fkeyvalid = true;
4533  MemoryContextSwitchTo(oldcxt);
4534 
4535  /* Don't leak the old list, if there is one */
4536  list_free_deep(oldlist);
4537 
4538  return result;
4539 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs)
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: rel.h:275
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * rd_fkeylist
Definition: rel.h:120
Form_pg_class rd_rel
Definition: rel.h:109
void list_free_deep(List *list)
Definition: list.c:1405
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
List * lappend(List *list, void *datum)
Definition: list.c:336
#define makeNode(_type_)
Definition: nodes.h:584
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:277
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:276
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define copyObject(obj)
Definition: nodes.h:652
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
bool rd_fkeyvalid
Definition: rel.h:121
#define RelationGetRelid(relation)
Definition: rel.h:477
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIdentityKeyBitmap()

Bitmapset* RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5247 of file relcache.c.

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

5248 {
5249  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5250  Relation indexDesc;
5251  int i;
5252  Oid replidindex;
5253  MemoryContext oldcxt;
5254 
5255  /* Quick exit if we already computed the result */
5256  if (relation->rd_idattr != NULL)
5257  return bms_copy(relation->rd_idattr);
5258 
5259  /* Fast path if definitely no indexes */
5260  if (!RelationGetForm(relation)->relhasindex)
5261  return NULL;
5262 
5263  /* Historic snapshot must be set. */
5265 
5266  replidindex = RelationGetReplicaIndex(relation);
5267 
5268  /* Fall out if there is no replica identity index */
5269  if (!OidIsValid(replidindex))
5270  return NULL;
5271 
5272  /* Look up the description for the replica identity index */
5273  indexDesc = RelationIdGetRelation(replidindex);
5274 
5275  if (!RelationIsValid(indexDesc))
5276  elog(ERROR, "could not open relation with OID %u",
5277  relation->rd_replidindex);
5278 
5279  /* Add referenced attributes to idindexattrs */
5280  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5281  {
5282  int attrnum = indexDesc->rd_index->indkey.values[i];
5283 
5284  /*
5285  * We don't include non-key columns into idindexattrs bitmaps. See
5286  * RelationGetIndexAttrBitmap.
5287  */
5288  if (attrnum != 0)
5289  {
5290  if (i < indexDesc->rd_index->indnkeyatts)
5291  idindexattrs = bms_add_member(idindexattrs,
5293  }
5294  }
5295 
5296  RelationClose(indexDesc);
5297 
5298  /* Don't leak the old values of these bitmaps, if any */
5299  bms_free(relation->rd_idattr);
5300  relation->rd_idattr = NULL;
5301 
5302  /* Now save copy of the bitmap in the relcache entry */
5304  relation->rd_idattr = bms_copy(idindexattrs);
5305  MemoryContextSwitchTo(oldcxt);
5306 
5307  /* We return our original working copy for caller to play with */
5308  return idindexattrs;
5309 }
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4782
Oid rd_replidindex
Definition: rel.h:152
#define RelationGetForm(relation)
Definition: rel.h:471
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Form_pg_index rd_index
Definition: rel.h:187
#define ERROR
Definition: elog.h:46
#define RelationIsValid(relation)
Definition: rel.h:450
void RelationClose(Relation relation)
Definition: relcache.c:2101
Bitmapset * rd_idattr
Definition: rel.h:161
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:804
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058
#define elog(elevel,...)
Definition: elog.h:232
int i
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:1995
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIndexAttOptions()

bytea** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5575 of file relcache.c.

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

5576 {
5577  MemoryContext oldcxt;
5578  bytea **opts = relation->rd_opcoptions;
5579  Oid relid = RelationGetRelid(relation);
5580  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5581  * IndexRelationGetNumberOfKeyAttributes */
5582  int i;
5583 
5584  /* Try to copy cached options. */
5585  if (opts)
5586  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5587 
5588  /* Get and parse opclass options. */
5589  opts = palloc0(sizeof(*opts) * natts);
5590 
5591  for (i = 0; i < natts; i++)
5592  {
5593  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5594  {
5595  Datum attoptions = get_attoptions(relid, i + 1);
5596 
5597  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5598 
5599  if (attoptions != (Datum) 0)
5600  pfree(DatumGetPointer(attoptions));
5601  }
5602  }
5603 
5604  /* Copy parsed options to the cache. */
5605  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5606  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5607  MemoryContextSwitchTo(oldcxt);
5608 
5609  if (copy)
5610  return opts;
5611 
5612  for (i = 0; i < natts; i++)
5613  {
5614  if (opts[i])
5615  pfree(opts[i]);
5616  }
5617 
5618  pfree(opts);
5619 
5620  return relation->rd_opcoptions;
5621 }
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:483
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bytea ** rd_opcoptions
Definition: rel.h:213
unsigned int Oid
Definition: postgres_ext.h:31
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:995
void pfree(void *pointer)
Definition: mcxt.c:1169
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5555
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:939
static AmcheckOptions opts
Definition: pg_amcheck.c:110
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetPointer(X)
Definition: postgres.h:593
MemoryContext rd_indexcxt
Definition: rel.h:199
int i
Definition: c.h:621
bool criticalRelcachesBuilt
Definition: relcache.c:137
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5003 of file relcache.c.

References AccessShareLock, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, GetPgIndexDescriptor(), heap_getattr, i, INDEX_ATTR_BITMAP_ALL, 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_idattr, RelationData::rd_index, RelationData::rd_indexattr, 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().

5004 {
5005  Bitmapset *indexattrs; /* indexed columns */
5006  Bitmapset *uindexattrs; /* columns in unique indexes */
5007  Bitmapset *pkindexattrs; /* columns in the primary index */
5008  Bitmapset *idindexattrs; /* columns in the replica identity */
5009  List *indexoidlist;
5010  List *newindexoidlist;
5011  Oid relpkindex;
5012  Oid relreplindex;
5013  ListCell *l;
5014  MemoryContext oldcxt;
5015 
5016  /* Quick exit if we already computed the result. */
5017  if (relation->rd_indexattr != NULL)
5018  {
5019  switch (attrKind)
5020  {
5021  case INDEX_ATTR_BITMAP_ALL:
5022  return bms_copy(relation->rd_indexattr);
5023  case INDEX_ATTR_BITMAP_KEY:
5024  return bms_copy(relation->rd_keyattr);
5026  return bms_copy(relation->rd_pkattr);
5028  return bms_copy(relation->rd_idattr);
5029  default:
5030  elog(ERROR, "unknown attrKind %u", attrKind);
5031  }
5032  }
5033 
5034  /* Fast path if definitely no indexes */
5035  if (!RelationGetForm(relation)->relhasindex)
5036  return NULL;
5037 
5038  /*
5039  * Get cached list of index OIDs. If we have to start over, we do so here.
5040  */
5041 restart:
5042  indexoidlist = RelationGetIndexList(relation);
5043 
5044  /* Fall out if no indexes (but relhasindex was set) */
5045  if (indexoidlist == NIL)
5046  return NULL;
5047 
5048  /*
5049  * Copy the rd_pkindex and rd_replidindex values computed by
5050  * RelationGetIndexList before proceeding. This is needed because a
5051  * relcache flush could occur inside index_open below, resetting the
5052  * fields managed by RelationGetIndexList. We need to do the work with
5053  * stable values of these fields.
5054  */
5055  relpkindex = relation->rd_pkindex;
5056  relreplindex = relation->rd_replidindex;
5057 
5058  /*
5059  * For each index, add referenced attributes to indexattrs.
5060  *
5061  * Note: we consider all indexes returned by RelationGetIndexList, even if
5062  * they are not indisready or indisvalid. This is important because an
5063  * index for which CREATE INDEX CONCURRENTLY has just started must be
5064  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5065  * CONCURRENTLY is far enough along that we should ignore the index, it
5066  * won't be returned at all by RelationGetIndexList.
5067  */
5068  indexattrs = NULL;
5069  uindexattrs = NULL;
5070  pkindexattrs = NULL;
5071  idindexattrs = NULL;
5072  foreach(l, indexoidlist)
5073  {
5074  Oid indexOid = lfirst_oid(l);
5075  Relation indexDesc;
5076  Datum datum;
5077  bool isnull;
5078  Node *indexExpressions;
5079  Node *indexPredicate;
5080  int i;
5081  bool isKey; /* candidate key */
5082  bool isPK; /* primary key */
5083  bool isIDKey; /* replica identity index */
5084 
5085  indexDesc = index_open(indexOid, AccessShareLock);
5086 
5087  /*
5088  * Extract index expressions and index predicate. Note: Don't use
5089  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5090  * those might run constant expressions evaluation, which needs a
5091  * snapshot, which we might not have here. (Also, it's probably more
5092  * sound to collect the bitmaps before any transformations that might
5093  * eliminate columns, but the practical impact of this is limited.)
5094  */
5095 
5096  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5097  GetPgIndexDescriptor(), &isnull);
5098  if (!isnull)
5099  indexExpressions = stringToNode(TextDatumGetCString(datum));
5100  else
5101  indexExpressions = NULL;
5102 
5103  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5104  GetPgIndexDescriptor(), &isnull);
5105  if (!isnull)
5106  indexPredicate = stringToNode(TextDatumGetCString(datum));
5107  else
5108  indexPredicate = NULL;
5109 
5110  /* Can this index be referenced by a foreign key? */
5111  isKey = indexDesc->rd_index->indisunique &&
5112  indexExpressions == NULL &&
5113  indexPredicate == NULL;
5114 
5115  /* Is this a primary key? */
5116  isPK = (indexOid == relpkindex);
5117 
5118  /* Is this index the configured (or default) replica identity? */
5119  isIDKey = (indexOid == relreplindex);
5120 
5121  /* Collect simple attribute references */
5122  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5123  {
5124  int attrnum = indexDesc->rd_index->indkey.values[i];
5125 
5126  /*
5127  * Since we have covering indexes with non-key columns, we must
5128  * handle them accurately here. non-key columns must be added into
5129  * indexattrs, since they are in index, and HOT-update shouldn't
5130  * miss them. Obviously, non-key columns couldn't be referenced by
5131  * foreign key or identity key. Hence we do not include them into
5132  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5133  */
5134  if (attrnum != 0)
5135  {
5136  indexattrs = bms_add_member(indexattrs,
5138 
5139  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5140  uindexattrs = bms_add_member(uindexattrs,
5142 
5143  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5144  pkindexattrs = bms_add_member(pkindexattrs,
5146 
5147  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5148  idindexattrs = bms_add_member(idindexattrs,
5150  }
5151  }
5152 
5153  /* Collect all attributes used in expressions, too */
5154  pull_varattnos(indexExpressions, 1, &indexattrs);
5155 
5156  /* Collect all attributes in the index predicate, too */
5157  pull_varattnos(indexPredicate, 1, &indexattrs);
5158 
5159  index_close(indexDesc, AccessShareLock);
5160  }
5161 
5162  /*
5163  * During one of the index_opens in the above loop, we might have received
5164  * a relcache flush event on this relcache entry, which might have been
5165  * signaling a change in the rel's index list. If so, we'd better start
5166  * over to ensure we deliver up-to-date attribute bitmaps.
5167  */
5168  newindexoidlist = RelationGetIndexList(relation);
5169  if (equal(indexoidlist, newindexoidlist) &&
5170  relpkindex == relation->rd_pkindex &&
5171  relreplindex == relation->rd_replidindex)
5172  {
5173  /* Still the same index set, so proceed */
5174  list_free(newindexoidlist);
5175  list_free(indexoidlist);
5176  }
5177  else
5178  {
5179  /* Gotta do it over ... might as well not leak memory */
5180  list_free(newindexoidlist);
5181  list_free(indexoidlist);
5182  bms_free(uindexattrs);
5183  bms_free(pkindexattrs);
5184  bms_free(idindexattrs);
5185  bms_free(indexattrs);
5186 
5187  goto restart;
5188  }
5189 
5190  /* Don't leak the old values of these bitmaps, if any */
5191  bms_free(relation->rd_indexattr);
5192  relation->rd_indexattr = NULL;
5193  bms_free(relation->rd_keyattr);
5194  relation->rd_keyattr = NULL;
5195  bms_free(relation->rd_pkattr);
5196  relation->rd_pkattr = NULL;
5197  bms_free(relation->rd_idattr);
5198  relation->rd_idattr = NULL;
5199 
5200  /*
5201  * Now save copies of the bitmaps in the relcache entry. We intentionally
5202  * set rd_indexattr last, because that's the one that signals validity of
5203  * the values; if we run out of memory before making that copy, we won't
5204  * leave the relcache entry looking like the other ones are valid but
5205  * empty.
5206  */
5208  relation->rd_keyattr = bms_copy(uindexattrs);
5209  relation->rd_pkattr = bms_copy(pkindexattrs);
5210  relation->rd_idattr = bms_copy(idindexattrs);
5211  relation->rd_indexattr = bms_copy(indexattrs);
5212  MemoryContextSwitchTo(oldcxt);
5213 
5214  /* We return our original working copy for caller to play with */
5215  switch (attrKind)
5216  {
5217  case INDEX_ATTR_BITMAP_ALL:
5218  return indexattrs;
5219  case INDEX_ATTR_BITMAP_KEY:
5220  return uindexattrs;
5222  return pkindexattrs;
5224  return idindexattrs;
5225  default:
5226  elog(ERROR, "unknown attrKind %u", attrKind);
5227  return NULL;
5228  }
5229 }
#define NIL
Definition: pg_list.h:65
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Bitmapset * rd_keyattr
Definition: rel.h:159
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3149
Oid rd_replidindex
Definition: rel.h:152
#define RelationGetForm(relation)
Definition: rel.h:471
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:536
void * stringToNode(const char *str)
Definition: read.c:89
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
unsigned int Oid
Definition: postgres_ext.h:31
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:281
struct HeapTupleData * rd_indextuple
Definition: rel.h:189
Form_pg_index rd_index
Definition: rel.h:187
#define ERROR
Definition: elog.h:46
Oid rd_pkindex
Definition: rel.h:151
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4235
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
Bitmapset * rd_idattr
Definition: rel.h:161
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Bitmapset * rd_pkattr
Definition: rel.h:160
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
int i
Definition: pg_list.h:50
Bitmapset * rd_indexattr
Definition: rel.h:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define lfirst_oid(lc)
Definition: pg_list.h:171
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4807 of file relcache.c.

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

4808 {
4809  List *result;
4810  Datum exprsDatum;
4811  bool isnull;
4812  char *exprsString;
4813  MemoryContext oldcxt;
4814 
4815  /* Quick exit if we already computed the result. */
4816  if (relation->rd_indexprs)
4817  return copyObject(relation->rd_indexprs);
4818 
4819  /* Quick exit if there is nothing to do. */
4820  if (relation->rd_indextuple == NULL ||
4821  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4822  return NIL;
4823 
4824  /*
4825  * We build the tree we intend to return in the caller's context. After
4826  * successfully completing the work, we copy it into the relcache entry.
4827  * This avoids problems if we get some sort of error partway through.
4828  */
4829  exprsDatum = heap_getattr(relation->rd_indextuple,
4830  Anum_pg_index_indexprs,
4832  &isnull);
4833  Assert(!isnull);
4834  exprsString = TextDatumGetCString(exprsDatum);
4835  result = (List *) stringToNode(exprsString);
4836  pfree(exprsString);
4837 
4838  /*
4839  * Run the expressions through eval_const_expressions. This is not just an
4840  * optimization, but is necessary, because the planner will be comparing
4841  * them to similarly-processed qual clauses, and may fail to detect valid
4842  * matches without this. We must not use canonicalize_qual, however,
4843  * since these aren't qual expressions.
4844  */
4845  result = (List *) eval_const_expressions(NULL, (Node *) result);
4846 
4847  /* May as well fix opfuncids too */
4848  fix_opfuncids((Node *) result);
4849 
4850  /* Now save a copy of the completed tree in the relcache entry. */
4851  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4852  relation->rd_indexprs = copyObject(result);
4853  MemoryContextSwitchTo(oldcxt);
4854 
4855  return result;
4856 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1652
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * rd_indexprs
Definition: rel.h:207
Definition: nodes.h:536
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2094
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
struct HeapTupleData * rd_indextuple
Definition: rel.h:189
void pfree(void *pointer)
Definition: mcxt.c:1169
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4235
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
#define Assert(condition)
Definition: c.h:804
MemoryContext rd_indexcxt
Definition: rel.h:199
#define copyObject(obj)
Definition: nodes.h:652
Definition: pg_list.h:50

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4573 of file relcache.c.

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

4574 {
4575  Relation indrel;
4576  SysScanDesc indscan;
4577  ScanKeyData skey;
4578  HeapTuple htup;
4579  List *result;
4580  List *oldlist;
4581  char replident = relation->rd_rel->relreplident;
4582  Oid pkeyIndex = InvalidOid;
4583  Oid candidateIndex = InvalidOid;
4584  MemoryContext oldcxt;
4585 
4586  /* Quick exit if we already computed the list. */
4587  if (relation->rd_indexvalid)
4588  return list_copy(relation->rd_indexlist);
4589 
4590  /*
4591  * We build the list we intend to return (in the caller's context) while
4592  * doing the scan. After successfully completing the scan, we copy that
4593  * list into the relcache entry. This avoids cache-context memory leakage
4594  * if we get some sort of error partway through.
4595  */
4596  result = NIL;
4597 
4598  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4599  ScanKeyInit(&skey,
4600  Anum_pg_index_indrelid,
4601  BTEqualStrategyNumber, F_OIDEQ,
4602  ObjectIdGetDatum(RelationGetRelid(relation)));
4603 
4604  indrel = table_open(IndexRelationId, AccessShareLock);
4605  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4606  NULL, 1, &skey);
4607 
4608  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4609  {
4611 
4612  /*
4613  * Ignore any indexes that are currently being dropped. This will
4614  * prevent them from being searched, inserted into, or considered in
4615  * HOT-safety decisions. It's unsafe to touch such an index at all
4616  * since its catalog entries could disappear at any instant.
4617  */
4618  if (!index->indislive)
4619  continue;
4620 
4621  /* add index's OID to result list */
4622  result = lappend_oid(result, index->indexrelid);
4623 
4624  /*
4625  * Invalid, non-unique, non-immediate or predicate indexes aren't
4626  * interesting for either oid indexes or replication identity indexes,
4627  * so don't check them.
4628  */
4629  if (!index->indisvalid || !index->indisunique ||
4630  !index->indimmediate ||
4631  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4632  continue;
4633 
4634  /* remember primary key index if any */
4635  if (index->indisprimary)
4636  pkeyIndex = index->indexrelid;
4637 
4638  /* remember explicitly chosen replica index */
4639  if (index->indisreplident)
4640  candidateIndex = index->indexrelid;
4641  }
4642 
4643  systable_endscan(indscan);
4644 
4645  table_close(indrel, AccessShareLock);
4646 
4647  /* Sort the result list into OID order, per API spec. */
4648  list_sort(result, list_oid_cmp);
4649 
4650  /* Now save a copy of the completed list in the relcache entry. */
4652  oldlist = relation->rd_indexlist;
4653  relation->rd_indexlist = list_copy(result);
4654  relation->rd_pkindex = pkeyIndex;
4655  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4656  relation->rd_replidindex = pkeyIndex;
4657  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4658  relation->rd_replidindex = candidateIndex;
4659  else
4660  relation->rd_replidindex = InvalidOid;
4661  relation->rd_indexvalid = true;
4662  MemoryContextSwitchTo(oldcxt);
4663 
4664  /* Don't leak the old list, if there is one */
4665  list_free(oldlist);
4666 
4667  return result;
4668 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Oid rd_replidindex
Definition: rel.h:152
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_copy(const List *oldlist)
Definition: list.c:1418
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
Definition: type.h:89
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1529
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
Oid rd_pkindex
Definition: rel.h:151
List * rd_indexlist
Definition: rel.h:150
FormData_pg_index * Form_pg_index
Definition: pg_index.h:69
bool rd_indexvalid
Definition: rel.h:63
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1496
void list_free(List *list)
Definition: list.c:1391
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 4920 of file relcache.c.

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

4921 {
4922  List *result;
4923  Datum predDatum;
4924  bool isnull;
4925  char *predString;
4926  MemoryContext oldcxt;
4927 
4928  /* Quick exit if we already computed the result. */
4929  if (relation->rd_indpred)
4930  return copyObject(relation->rd_indpred);
4931 
4932  /* Quick exit if there is nothing to do. */
4933  if (relation->rd_indextuple == NULL ||
4934  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
4935  return NIL;
4936 
4937  /*
4938  * We build the tree we intend to return in the caller's context. After
4939  * successfully completing the work, we copy it into the relcache entry.
4940  * This avoids problems if we get some sort of error partway through.
4941  */
4942  predDatum = heap_getattr(relation->rd_indextuple,
4943  Anum_pg_index_indpred,
4945  &isnull);
4946  Assert(!isnull);
4947  predString = TextDatumGetCString(predDatum);
4948  result = (List *) stringToNode(predString);
4949  pfree(predString);
4950 
4951  /*
4952  * Run the expression through const-simplification and canonicalization.
4953  * This is not just an optimization, but is necessary, because the planner
4954  * will be comparing it to similarly-processed qual clauses, and may fail
4955  * to detect valid matches without this. This must match the processing
4956  * done to qual clauses in preprocess_expression()! (We can skip the
4957  * stuff involving subqueries, however, since we don't allow any in index
4958  * predicates.)
4959  */
4960  result = (List *) eval_const_expressions(NULL, (Node *) result);
4961 
4962  result = (List *) canonicalize_qual((Expr *) result, false);
4963 
4964  /* Also convert to implicit-AND format */
4965  result = make_ands_implicit((Expr *) result);
4966 
4967  /* May as well fix opfuncids too */
4968  fix_opfuncids((Node *) result);
4969 
4970  /* Now save a copy of the completed tree in the relcache entry. */
4971  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4972  relation->rd_indpred = copyObject(result);
4973  MemoryContextSwitchTo(oldcxt);
4974 
4975  return result;
4976 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1652
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:536
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2094
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
struct HeapTupleData * rd_indextuple
Definition: rel.h:189
void pfree(void *pointer)
Definition: mcxt.c:1169
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4235
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:294
List * rd_indpred
Definition: rel.h:208
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:719
#define Assert(condition)
Definition: c.h:804
MemoryContext rd_indexcxt
Definition: rel.h:199
#define copyObject(obj)
Definition: nodes.h:652
Definition: pg_list.h:50

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  relation)

Definition at line 5529 of file relcache.c.

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

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

5530 {
5531  Oid indexrelid = RelationGetRelid(indexrel);
5532  int16 natts = RelationGetNumberOfAttributes(indexrel);
5533  Datum *options = NULL;
5534  int16 attnum;
5535 
5536  for (attnum = 1; attnum <= natts; attnum++)
5537  {
5538  if (indexrel->rd_indam->amoptsprocnum == 0)
5539  continue;
5540 
5541  if (!OidIsValid(index_getprocid(indexrel, attnum,
5542  indexrel->rd_indam->amoptsprocnum)))
5543  continue;
5544 
5545  if (!options)
5546  options = palloc0(sizeof(Datum) * natts);
5547 
5548  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5549  }
5550 
5551  return options;
5552 }
signed short int16
Definition: c.h:428
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:483
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:995
static char ** options
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
int16 attnum
Definition: pg_attribute.h:83
#define RelationGetRelid(relation)
Definition: rel.h:477
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4761 of file relcache.c.

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

Referenced by build_replindex_scan_key(), and GetRelationIdentityOrPK().

4762 {
4763  List *ilist;
4764 
4765  if (!relation->rd_indexvalid)
4766  {
4767  /* RelationGetIndexList does the heavy lifting. */
4768  ilist = RelationGetIndexList(relation);
4769  list_free(ilist);
4770  Assert(relation->rd_indexvalid);
4771  }
4772 
4773  return relation->rd_pkindex;
4774 }
Oid rd_pkindex
Definition: rel.h:151
bool rd_indexvalid
Definition: rel.h:63
#define Assert(condition)
Definition: c.h:804
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4782 of file relcache.c.

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

4783 {
4784  List *ilist;
4785 
4786  if (!relation->rd_indexvalid)
4787  {
4788  /* RelationGetIndexList does the heavy lifting. */
4789  ilist = RelationGetIndexList(relation);
4790  list_free(ilist);
4791  Assert(relation->rd_indexvalid);
4792  }
4793 
4794  return relation->rd_replidindex;
4795 }
Oid rd_replidindex
Definition: rel.h:152
bool rd_indexvalid
Definition: rel.h:63
#define Assert(condition)
Definition: c.h:804
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4692 of file relcache.c.

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

4693 {
4694  Relation indrel;
4695  SysScanDesc indscan;
4696  ScanKeyData skey;
4697  HeapTuple htup;
4698  List *result;
4699  List *oldlist;
4700  MemoryContext oldcxt;
4701 
4702  /* Quick exit if we already computed the list. */
4703  if (relation->rd_statvalid != 0)
4704  return list_copy(relation->rd_statlist);
4705 
4706  /*
4707  * We build the list we intend to return (in the caller's context) while
4708  * doing the scan. After successfully completing the scan, we copy that
4709  * list into the relcache entry. This avoids cache-context memory leakage
4710  * if we get some sort of error partway through.
4711  */
4712  result = NIL;
4713 
4714  /*
4715  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4716  * rel.
4717  */
4718  ScanKeyInit(&skey,
4719  Anum_pg_statistic_ext_stxrelid,
4720  BTEqualStrategyNumber, F_OIDEQ,
4721  ObjectIdGetDatum(RelationGetRelid(relation)));
4722 
4723  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4724  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4725  NULL, 1, &skey);
4726 
4727  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4728  {
4729  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4730 
4731  result = lappend_oid(result, oid);
4732  }
4733 
4734  systable_endscan(indscan);
4735 
4736  table_close(indrel, AccessShareLock);
4737 
4738  /* Sort the result list into OID order, per API spec. */
4739  list_sort(result, list_oid_cmp);
4740 
4741  /* Now save a copy of the completed list in the relcache entry. */
4743  oldlist = relation->rd_statlist;
4744  relation->rd_statlist = list_copy(result);
4745 
4746  relation->rd_statvalid = true;
4747  MemoryContextSwitchTo(oldcxt);
4748 
4749  /* Don't leak the old list, if there is one */
4750  list_free(oldlist);
4751 
4752  return result;
4753 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_copy(const List *oldlist)
Definition: list.c:1418
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1529
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool rd_statvalid
Definition: rel.h:65
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1496
void list_free(List *list)
Definition: list.c:1391
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
List * rd_statlist
Definition: rel.h:155
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define BTEqualStrategyNumber
Definition: stratnum.h:31
FormData_pg_statistic_ext * Form_pg_statistic_ext
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 1995 of file relcache.c.

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(), RememberToFreeTupleDescAtEOX(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

1996 {
1997  Relation rd;
1998 
1999  /* Make sure we're in an xact, even if this ends up being a cache hit */
2001 
2002  /*
2003  * first try to find reldesc in the cache
2004  */
2005  RelationIdCacheLookup(relationId, rd);
2006 
2007  if (RelationIsValid(rd))
2008  {
2009  /* return NULL for dropped relations */
2011  {
2012  Assert(!rd->rd_isvalid);
2013  return NULL;
2014  }
2015 
2017  /* revalidate cache entry if necessary */
2018  if (!rd->rd_isvalid)
2019  {
2020  /*
2021  * Indexes only have a limited number of possible schema changes,
2022  * and we don't want to use the full-blown procedure because it's
2023  * a headache for indexes that reload itself depends on.
2024  */
2025  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2026  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2028  else
2029  RelationClearRelation(rd, true);
2030 
2031  /*
2032  * Normally entries need to be valid here, but before the relcache
2033  * has been initialized, not enough infrastructure exists to
2034  * perform pg_class lookups. The structure of such entries doesn't
2035  * change, but we still want to update the rd_rel entry. So
2036  * rd_isvalid = false is left in place for a later lookup.
2037  */
2038  Assert(rd->rd_isvalid ||
2040  }
2041  return rd;
2042  }
2043 
2044  /*
2045  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2046  * it.
2047  */
2048  rd = RelationBuildDesc(relationId, true);
2049  if (RelationIsValid(rd))
2051  return rd;
2052 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
bool rd_isnailed
Definition: rel.h:61
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
bool rd_isvalid
Definition: rel.h:62
Form_pg_class rd_rel
Definition: rel.h:109
#define RelationIsValid(relation)
Definition: rel.h:450
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2068
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2158
#define Assert(condition)
Definition: c.h:804
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1001
bool IsTransactionState(void)
Definition: xact.c:371
#define InvalidSubTransactionId
Definition: c.h:593
bool criticalRelcachesBuilt
Definition: relcache.c:137
SubTransactionId rd_droppedSubid
Definition: rel.h:107

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6400 of file relcache.c.

References Assert, and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

6401 {
6402  if (relationId == SharedSecLabelRelationId ||
6403  relationId == TriggerRelidNameIndexId ||
6404  relationId == DatabaseNameIndexId ||
6405  relationId == SharedSecLabelObjectIndexId)
6406  {
6407  /*
6408  * If this Assert fails, we don't need the applicable special case
6409  * anymore.
6410  */
6411  Assert(!RelationSupportsSysCache(relationId));
6412  return true;
6413  }
6414  return RelationSupportsSysCache(relationId);
6415 }
#define Assert(condition)
Definition: c.h:804
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1532

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1360 of file relcache.c.

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

1361 {
1362  HeapTuple tuple;
1363  Form_pg_am aform;
1364  Datum indcollDatum;
1365  Datum indclassDatum;
1366  Datum indoptionDatum;
1367  bool isnull;
1368  oidvector *indcoll;
1369  oidvector *indclass;
1370  int2vector *indoption;
1371  MemoryContext indexcxt;
1372  MemoryContext oldcontext;
1373  int indnatts;
1374  int indnkeyatts;
1375  uint16 amsupport;
1376 
1377  /*
1378  * Make a copy of the pg_index entry for the index. Since pg_index
1379  * contains variable-length and possibly-null fields, we have to do this
1380  * honestly rather than just treating it as a Form_pg_index struct.
1381  */
1382  tuple = SearchSysCache1(INDEXRELID,
1383  ObjectIdGetDatum(RelationGetRelid(relation)));
1384  if (!HeapTupleIsValid(tuple))
1385  elog(ERROR, "cache lookup failed for index %u",
1386  RelationGetRelid(relation));
1388  relation->rd_indextuple = heap_copytuple(tuple);
1389  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1390  MemoryContextSwitchTo(oldcontext);
1391  ReleaseSysCache(tuple);
1392 
1393  /*
1394  * Look up the index's access method, save the OID of its handler function
1395  */
1396  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1397  if (!HeapTupleIsValid(tuple))
1398  elog(ERROR, "cache lookup failed for access method %u",
1399  relation->rd_rel->relam);
1400  aform = (Form_pg_am) GETSTRUCT(tuple);
1401  relation->rd_amhandler = aform->amhandler;
1402  ReleaseSysCache(tuple);
1403 
1404  indnatts = RelationGetNumberOfAttributes(relation);
1405  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1406  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1407  RelationGetRelid(relation));
1408  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1409 
1410  /*
1411  * Make the private context to hold index access info. The reason we need
1412  * a context, and not just a couple of pallocs, is so that we won't leak
1413  * any subsidiary info attached to fmgr lookup records.
1414  */
1416  "index info",
1418  relation->rd_indexcxt = indexcxt;
1420  RelationGetRelationName(relation));
1421 
1422  /*
1423  * Now we can fetch the index AM's API struct
1424  */
1425  InitIndexAmRoutine(relation);
1426 
1427  /*
1428  * Allocate arrays to hold data. Opclasses are not used for included
1429  * columns, so allocate them for indnkeyatts only.
1430  */
1431  relation->rd_opfamily = (Oid *)
1432  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1433  relation->rd_opcintype = (Oid *)
1434  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1435 
1436  amsupport = relation->rd_indam->amsupport;
1437  if (amsupport > 0)
1438  {
1439  int nsupport = indnatts * amsupport;
1440 
1441  relation->rd_support = (RegProcedure *)
1442  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1443  relation->rd_supportinfo = (FmgrInfo *)
1444  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1445  }
1446  else
1447  {
1448  relation->rd_support = NULL;
1449  relation->rd_supportinfo = NULL;
1450  }
1451 
1452  relation->rd_indcollation = (Oid *)
1453  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1454 
1455  relation->rd_indoption = (int16 *)
1456  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1457 
1458  /*
1459  * indcollation cannot be referenced directly through the C struct,
1460  * because it comes after the variable-width indkey field. Must extract
1461  * the datum the hard way...
1462  */
1463  indcollDatum = fastgetattr(relation->rd_indextuple,
1464  Anum_pg_index_indcollation,
1466  &isnull);
1467  Assert(!isnull);
1468  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1469  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1470 
1471  /*
1472  * indclass cannot be referenced directly through the C struct, because it
1473  * comes after the variable-width indkey field. Must extract the datum
1474  * the hard way...
1475  */
1476  indclassDatum = fastgetattr(relation->rd_indextuple,
1477  Anum_pg_index_indclass,
1479  &isnull);
1480  Assert(!isnull);
1481  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1482 
1483  /*
1484  * Fill the support procedure OID array, as well as the info about
1485  * opfamilies and opclass input types. (aminfo and supportinfo are left
1486  * as zeroes, and are filled on-the-fly when used)
1487  */
1488  IndexSupportInitialize(indclass, relation->rd_support,
1489  relation->rd_opfamily, relation->rd_opcintype,
1490  amsupport, indnkeyatts);
1491 
1492  /*
1493  * Similarly extract indoption and copy it to the cache entry
1494  */
1495  indoptionDatum = fastgetattr(relation->rd_indextuple,
1496  Anum_pg_index_indoption,
1498  &isnull);
1499  Assert(!isnull);
1500  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1501  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1502 
1503  (void) RelationGetIndexAttOptions(relation, false);
1504 
1505  /*
1506  * expressions, predicate, exclusion caches will be filled later
1507  */
1508  relation->rd_indexprs = NIL;
1509  relation->rd_indpred = NIL;
1510  relation->rd_exclops = NULL;
1511  relation->rd_exclprocs = NULL;
1512  relation->rd_exclstrats = NULL;
1513  relation->rd_amcache = NULL;
1514 }
signed short int16
Definition: c.h:428
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define NIL
Definition: pg_list.h:65
Definition: c.h:660
struct IndexAmRoutine * rd_indam
Definition: rel.h:201
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:216
#define AllocSetContextCreate
Definition: memutils.h:173
int16 * rd_indoption
Definition: rel.h:206
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:711
Definition: syscache.h:36
struct FmgrInfo * rd_supportinfo
Definition: rel.h:205
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:483
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:205
regproc RegProcedure
Definition: c.h:585
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:211
List * rd_indexprs
Definition: rel.h:207
Oid * rd_exclprocs
Definition: rel.h:210
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1336
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1530
struct HeapTupleData * rd_indextuple
Definition: rel.h:189
Form_pg_index rd_index
Definition: rel.h:187
unsigned short uint16
Definition: c.h:440
Oid * rd_indcollation
Definition: rel.h:212
Oid rd_amhandler
Definition: rel.h:179
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:98
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4235
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:668
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:489
#define RelationGetRelationName(relation)
Definition: rel.h:511
List * rd_indpred
Definition: rel.h:208
Oid * rd_opfamily
Definition: rel.h:202
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:496
Oid * rd_exclops
Definition: rel.h:209
RegProcedure * rd_support
Definition: rel.h:204
FormData_pg_index * Form_pg_index
Definition: pg_index.h:69
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
Definition: c.h:649
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:657
#define DatumGetPointer(X)
Definition: postgres.h:593
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define elog(elevel,...)
Definition: elog.h:232
MemoryContext rd_indexcxt
Definition: rel.h:199
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5575
void * rd_amcache
Definition: rel.h:224
Oid * rd_opcintype
Definition: rel.h:203
#define RelationGetRelid(relation)
Definition: rel.h:477
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1743 of file relcache.c.

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

1744 {
1745  HeapTuple tuple;
1746  Form_pg_am aform;
1747 
1748  if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1749  {
1750  /*
1751  * Sequences are currently accessed like heap tables, but it doesn't
1752  * seem prudent to show that in the catalog. So just overwrite it
1753  * here.
1754  */
1755  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1756  }
1757  else if (IsCatalogRelation(relation))
1758  {
1759  /*
1760  * Avoid doing a syscache lookup for catalog tables.
1761  */
1762  Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1763  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1764  }
1765  else
1766  {
1767  /*
1768  * Look up the table access method, save the OID of its handler
1769  * function.
1770  */
1771  Assert(relation->rd_rel->relam != InvalidOid);
1772  tuple = SearchSysCache1(AMOID,
1773  ObjectIdGetDatum(relation->rd_rel->relam));
1774  if (!HeapTupleIsValid(tuple))
1775  elog(ERROR, "cache lookup failed for access method %u",
1776  relation->rd_rel->relam);
1777  aform = (Form_pg_am) GETSTRUCT(tuple);
1778  relation->rd_amhandler = aform->amhandler;
1779  ReleaseSysCache(tuple);
1780  }
1781 
1782  /*
1783  * Now we can fetch the table AM's API struct
1784  */
1785  InitTableAmRoutine(relation);
1786 }
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1734
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:104
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Definition: syscache.h:36
Form_pg_class rd_rel
Definition: rel.h:109
Oid rd_amhandler
Definition: rel.h:179
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define elog(elevel,...)
Definition: elog.h:232

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence 
)

Definition at line 3598 of file relcache.c.

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

3599 {
3600  Oid newrelfilenode;
3601  Relation pg_class;
3602  HeapTuple tuple;
3603  Form_pg_class classform;
3604  MultiXactId minmulti = InvalidMultiXactId;
3605  TransactionId freezeXid = InvalidTransactionId;
3606  RelFileNode newrnode;
3607 
3608  /* Allocate a new relfilenode */
3609  newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
3610  persistence);
3611 
3612  /*
3613  * Get a writable copy of the pg_class tuple for the given relation.
3614  */
3615  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3616 
3617  tuple = SearchSysCacheCopy1(RELOID,
3618  ObjectIdGetDatum(RelationGetRelid(relation)));
3619  if (!HeapTupleIsValid(tuple))
3620  elog(ERROR, "could not find tuple for relation %u",
3621  RelationGetRelid(relation));
3622  classform = (Form_pg_class) GETSTRUCT(tuple);
3623 
3624  /*
3625  * Schedule unlinking of the old storage at transaction commit.
3626  */
3627  RelationDropStorage(relation);
3628 
3629  /*
3630  * Create storage for the main fork of the new relfilenode. If it's a
3631  * table-like object, call into the table AM to do so, which'll also
3632  * create the table's init fork if needed.
3633  *
3634  * NOTE: If relevant for the AM, any conflict in relfilenode value will be
3635  * caught here, if GetNewRelFileNode messes up for any reason.
3636  */
3637  newrnode = relation->rd_node;
3638  newrnode.relNode = newrelfilenode;
3639 
3640  switch (relation->rd_rel->relkind)
3641  {
3642  case RELKIND_INDEX:
3643  case RELKIND_SEQUENCE:
3644  {
3645  /* handle these directly, at least for now */
3646  SMgrRelation srel;
3647 
3648  srel = RelationCreateStorage(newrnode, persistence);
3649  smgrclose(srel);
3650  }
3651  break;
3652 
3653  case RELKIND_RELATION:
3654  case RELKIND_TOASTVALUE:
3655  case RELKIND_MATVIEW:
3656  table_relation_set_new_filenode(relation, &newrnode,
3657  persistence,
3658  &freezeXid, &minmulti);
3659  break;
3660 
3661  default:
3662  /* we shouldn't be called for anything else */
3663  elog(ERROR, "relation \"%s\" does not have storage",
3664  RelationGetRelationName(relation));
3665  break;
3666  }
3667 
3668  /*
3669  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3670  * change; instead we have to send the update to the relation mapper.
3671  *
3672  * For mapped indexes, we don't actually change the pg_class entry at all;
3673  * this is essential when reindexing pg_class itself. That leaves us with
3674  * possibly-inaccurate values of relpages etc, but those will be fixed up
3675  * later.
3676  */
3677  if (RelationIsMapped(relation))
3678  {
3679  /* This case is only supported for indexes */
3680  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3681 
3682  /* Since we're not updating pg_class, these had better not change */
3683  Assert(classform->relfrozenxid == freezeXid);
3684  Assert(classform->relminmxid == minmulti);
3685  Assert(classform->relpersistence == persistence);
3686 
3687  /*
3688  * In some code paths it's possible that the tuple update we'd
3689  * otherwise do here is the only thing that would assign an XID for
3690  * the current transaction. However, we must have an XID to delete
3691  * files, so make sure one is assigned.
3692  */
3693  (void) GetCurrentTransactionId();
3694 
3695  /* Do the deed */
3697  newrelfilenode,
3698  relation->rd_rel->relisshared,
3699  false);
3700 
3701  /* Since we're not updating pg_class, must trigger inval manually */
3702  CacheInvalidateRelcache(relation);
3703  }
3704  else
3705  {
3706  /* Normal case, update the pg_class entry */
3707  classform->relfilenode = newrelfilenode;
3708 
3709  /* relpages etc. never change for sequences */
3710  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3711  {
3712  classform->relpages = 0; /* it's empty until further notice */
3713  classform->reltuples = -1;
3714  classform->relallvisible = 0;
3715  }
3716  classform->relfrozenxid = freezeXid;
3717  classform->relminmxid = minmulti;
3718  classform->relpersistence = persistence;
3719 
3720  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3721  }
3722 
3723  heap_freetuple(tuple);
3724 
3725  table_close(pg_class, RowExclusiveLock);
3726 
3727  /*
3728  * Make the pg_class row change or relation map change visible. This will
3729  * cause the relcache entry to get updated, too.
3730  */
3732 
3733  RelationAssumeNewRelfilenode(relation);
3734 }
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
uint32 TransactionId
Definition: c.h:587
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
SMgrRelation RelationCreateStorage(RelFileNode rnode, char relpersistence)
Definition: storage.c:118
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define RelationIsMapped(relation)
Definition: rel.h:526
void RelationAssumeNewRelfilenode(Relation relation)
Definition: relcache.c:3749
void RelationDropStorage(Relation rel)
Definition: storage.c:195
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:597
RelFileNode rd_node
Definition: rel.h:56
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:490
static void table_relation_set_new_filenode(Relation rel, const RelFileNode *newrnode, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1590
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1342
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define elog(elevel,...)
Definition: elog.h:232
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

bool criticalSharedRelcachesBuilt