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

3222 {
3224  RelIdCacheEnt *idhentry;
3225  int i;
3226 
3227  /*
3228  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3229  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3230  * logic as in AtEOXact_RelationCache.
3231  */
3233  {
3234  hash_seq_init(&status, RelationIdCache);
3235  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3236  {
3237  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3238  mySubid, parentSubid);
3239  }
3240  }
3241  else
3242  {
3243  for (i = 0; i < eoxact_list_len; i++)
3244  {
3245  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3246  (void *) &eoxact_list[i],
3247  HASH_FIND,
3248  NULL);
3249  if (idhentry != NULL)
3250  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3251  mySubid, parentSubid);
3252  }
3253  }
3254 
3255  /* Don't reset the list; we still need more cleanup later */
3256 }
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:3267
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 3075 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().

3076 {
3078  RelIdCacheEnt *idhentry;
3079  int i;
3080 
3081  /*
3082  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3083  * listed in it. Otherwise fall back on a hash_seq_search scan.
3084  *
3085  * For simplicity, eoxact_list[] entries are not deleted till end of
3086  * top-level transaction, even though we could remove them at
3087  * subtransaction end in some cases, or remove relations from the list if
3088  * they are cleared for other reasons. Therefore we should expect the
3089  * case that list entries are not found in the hashtable; if not, there's
3090  * nothing to do for them.
3091  */
3093  {
3094  hash_seq_init(&status, RelationIdCache);
3095  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3096  {
3097  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3098  }
3099  }
3100  else
3101  {
3102  for (i = 0; i < eoxact_list_len; i++)
3103  {
3104  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3105  (void *) &eoxact_list[i],
3106  HASH_FIND,
3107  NULL);
3108  if (idhentry != NULL)
3109  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3110  }
3111  }
3112 
3113  if (EOXactTupleDescArrayLen > 0)
3114  {
3115  Assert(EOXactTupleDescArray != NULL);
3116  for (i = 0; i < NextEOXactTupleDescNum; i++)
3119  EOXactTupleDescArray = NULL;
3120  }
3121 
3122  /* Now we're out of the transaction and can clear the lists */
3123  eoxact_list_len = 0;
3124  eoxact_list_overflowed = false;
3125  NextEOXactTupleDescNum = 0;
3127 }
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:3138
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 5628 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().

5629 {
5633 
5634  return 0; /* return value does not matter */
5635 }
#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:503
int err_generic_string(int field, const char *str)
Definition: elog.c:1351
#define RelationGetNamespace(relation)
Definition: rel.h:510

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5645 of file relcache.c.

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

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

5646 {
5647  TupleDesc reldesc = RelationGetDescr(rel);
5648  const char *colname;
5649 
5650  /* Use reldesc if it's a user attribute, else consult the catalogs */
5651  if (attnum > 0 && attnum <= reldesc->natts)
5652  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5653  else
5654  colname = get_attname(RelationGetRelid(rel), attnum, false);
5655 
5656  return errtablecolname(rel, colname);
5657 }
#define RelationGetDescr(relation)
Definition: rel.h:495
#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:469
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5669

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5669 of file relcache.c.

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

Referenced by errtablecol().

5670 {
5671  errtable(rel);
5673 
5674  return 0; /* return value does not matter */
5675 }
#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:5628

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5682 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().

5683 {
5684  errtable(rel);
5686 
5687  return 0; /* return value does not matter */
5688 }
#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:5628

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5437 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().

5438 {
5439  List *puboids;
5440  ListCell *lc;
5441  MemoryContext oldcxt;
5442  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5443 
5444  /*
5445  * If not publishable, it publishes no actions. (pgoutput_change() will
5446  * ignore it.)
5447  */
5448  if (!is_publishable_relation(relation))
5449  return pubactions;
5450 
5451  if (relation->rd_pubactions)
5452  return memcpy(pubactions, relation->rd_pubactions,
5453  sizeof(PublicationActions));
5454 
5455  /* Fetch the publication membership info. */
5456  puboids = GetRelationPublications(RelationGetRelid(relation));
5457  if (relation->rd_rel->relispartition)
5458  {
5459  /* Add publications that the ancestors are in too. */
5460  List *ancestors = get_partition_ancestors(RelationGetRelid(relation));
5461  ListCell *lc;
5462 
5463  foreach(lc, ancestors)
5464  {
5465  Oid ancestor = lfirst_oid(lc);
5466 
5467  puboids = list_concat_unique_oid(puboids,
5468  GetRelationPublications(ancestor));
5469  }
5470  }
5471  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5472 
5473  foreach(lc, puboids)
5474  {
5475  Oid pubid = lfirst_oid(lc);
5476  HeapTuple tup;
5477  Form_pg_publication pubform;
5478 
5480 
5481  if (!HeapTupleIsValid(tup))
5482  elog(ERROR, "cache lookup failed for publication %u", pubid);
5483 
5484  pubform = (Form_pg_publication) GETSTRUCT(tup);
5485 
5486  pubactions->pubinsert |= pubform->pubinsert;
5487  pubactions->pubupdate |= pubform->pubupdate;
5488  pubactions->pubdelete |= pubform->pubdelete;
5489  pubactions->pubtruncate |= pubform->pubtruncate;
5490 
5491  ReleaseSysCache(tup);
5492 
5493  /*
5494  * If we know everything is replicated, there is no point to check for
5495  * other publications.
5496  */
5497  if (pubactions->pubinsert && pubactions->pubupdate &&
5498  pubactions->pubdelete && pubactions->pubtruncate)
5499  break;
5500  }
5501 
5502  if (relation->rd_pubactions)
5503  {
5504  pfree(relation->rd_pubactions);
5505  relation->rd_pubactions = NULL;
5506  }
5507 
5508  /* Now save copy of the actions in the relcache entry. */
5510  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5511  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5512  MemoryContextSwitchTo(oldcxt);
5513 
5514  return pubactions;
5515 }
#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:469
#define lfirst_oid(lc)
Definition: pg_list.h:171
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3746 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().

3747 {
3750  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3751 
3752  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3753  EOXactListAdd(relation);
3754 }
#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 3349 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().

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

References LWLockRelease().

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

6458 {
6459  LWLockRelease(RelCacheInitLock);
6460 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6432 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().

6433 {
6434  char localinitfname[MAXPGPATH];
6435  char sharedinitfname[MAXPGPATH];
6436 
6437  if (DatabasePath)
6438  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6440  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6442 
6443  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6444 
6445  /*
6446  * The files might not be there if no backend has been started since the
6447  * last removal. But complain about failures other than ENOENT with
6448  * ERROR. Fortunately, it's not too late to abort the transaction if we
6449  * can't get rid of the would-be-obsolete init file.
6450  */
6451  if (DatabasePath)
6452  unlink_initfile(localinitfname, ERROR);
6453  unlink_initfile(sharedinitfname, ERROR);
6454 }
#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:1203
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6529
#define snprintf
Definition: port.h:216

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6472 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().

6473 {
6474  const char *tblspcdir = "pg_tblspc";
6475  DIR *dir;
6476  struct dirent *de;
6477  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6478 
6479  snprintf(path, sizeof(path), "global/%s",
6481  unlink_initfile(path, LOG);
6482 
6483  /* Scan everything in the default tablespace */
6485 
6486  /* Scan the tablespace link directory to find non-default tablespaces */
6487  dir = AllocateDir(tblspcdir);
6488 
6489  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6490  {
6491  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6492  {
6493  /* Scan the tablespace dir for per-database dirs */
6494  snprintf(path, sizeof(path), "%s/%s/%s",
6495  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6497  }
6498  }
6499 
6500  FreeDir(dir);
6501 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6505
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2715
#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:2634
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6529
char d_name[MAX_PATH]
Definition: dirent.h:15
#define snprintf
Definition: port.h:216
int FreeDir(DIR *dir)
Definition: fd.c:2752

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3772 of file relcache.c.

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

Referenced by InitPostgres().

3773 {
3774  HASHCTL ctl;
3775 
3776  /*
3777  * make sure cache memory context exists
3778  */
3779  if (!CacheMemoryContext)
3781 
3782  /*
3783  * create hashtable that indexes the relcache
3784  */
3785  ctl.keysize = sizeof(Oid);
3786  ctl.entrysize = sizeof(RelIdCacheEnt);
3787  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3788  &ctl, HASH_ELEM | HASH_BLOBS);
3789 
3790  /*
3791  * relation mapper needs to be initialized too
3792  */
3794 }
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:3769
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3808 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().

3809 {
3810  MemoryContext oldcxt;
3811 
3812  /*
3813  * relation mapper needs initialized too
3814  */
3816 
3817  /*
3818  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3819  * nothing.
3820  */
3822  return;
3823 
3824  /*
3825  * switch to cache memory context
3826  */
3828 
3829  /*
3830  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3831  * the cache with pre-made descriptors for the critical shared catalogs.
3832  */
3833  if (!load_relcache_init_file(true))
3834  {
3835  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3836  Natts_pg_database, Desc_pg_database);
3837  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3838  Natts_pg_authid, Desc_pg_authid);
3839  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3840  Natts_pg_auth_members, Desc_pg_auth_members);
3841  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3842  Natts_pg_shseclabel, Desc_pg_shseclabel);
3843  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3844  Natts_pg_subscription, Desc_pg_subscription);
3845 
3846 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3847  }
3848 
3849  MemoryContextSwitchTo(oldcxt);
3850 }
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:5746
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:1804
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3867 of file relcache.c.

References AccessMethodProcedureIndexId, Assert, AttributeRelidNumIndexId, AuthIdOidIndexId, AuthIdRolnameIndexId, AuthMemMemRoleIndexId, CacheMemoryContext, CLASS_TUPLE_SIZE, ClassOidIndexId, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabaseNameIndexId, DatabaseOidIndexId, 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, IndexRelidIndexId, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum, OpclassOidIndexId, 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, RewriteRelRulenameIndexId, SearchSysCache1(), SharedSecLabelObjectIndexId, status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, TriggerRelidNameIndexId, and write_relcache_init_file().

Referenced by InitPostgres().

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

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

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

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2794 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2795 {
2796  Relation relation;
2797 
2798  RelationIdCacheLookup(relationId, relation);
2799 
2800  if (PointerIsValid(relation))
2801  {
2803  RelationFlushRelation(relation);
2804  }
2805 }
static long relcacheInvalsReceived
Definition: relcache.c:151
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2717
#define PointerIsValid(pointer)
Definition: c.h:698

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2098 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().

2099 {
2100  /* Note: no locking manipulations needed */
2102 
2103  /*
2104  * If the relation is no longer open in this session, we can clean up any
2105  * stale partition descriptors it has. This is unlikely, so check to see
2106  * if there are child contexts before expending a call to mcxt.c.
2107  */
2108  if (RelationHasReferenceCountZero(relation))
2109  {
2110  if (relation->rd_pdcxt != NULL &&
2111  relation->rd_pdcxt->firstchild != NULL)
2113 
2114  if (relation->rd_pddcxt != NULL &&
2115  relation->rd_pddcxt->firstchild != NULL)
2117  }
2118 
2119 #ifdef RELCACHE_FORCE_RELEASE
2120  if (RelationHasReferenceCountZero(relation) &&
2121  relation->rd_createSubid == InvalidSubTransactionId &&
2123  RelationClearRelation(relation, false);
2124 #endif
2125 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2428
MemoryContext firstchild
Definition: memnodes.h:87
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2078
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:453

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 2940 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

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

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2750 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().

2751 {
2752  Relation relation;
2753 
2754  RelationIdCacheLookup(rid, relation);
2755 
2756  if (!PointerIsValid(relation))
2757  return; /* not in cache, nothing to do */
2758 
2759  if (!RelationHasReferenceCountZero(relation))
2760  elog(ERROR, "relation %u is still open", rid);
2761 
2763  if (relation->rd_createSubid != InvalidSubTransactionId ||
2765  {
2766  /*
2767  * In the event of subtransaction rollback, we must not forget
2768  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2769  * invalidates it in lieu of destroying it. (If we're in a top
2770  * transaction, we could opt to destroy the entry.)
2771  */
2773  }
2774 
2775  RelationClearRelation(relation, false);
2776 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2428
#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:453
#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 4863 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().

4864 {
4865  List *result;
4866  Datum exprsDatum;
4867  bool isnull;
4868  char *exprsString;
4869  List *rawExprs;
4870  ListCell *lc;
4871 
4872  /* Quick exit if there is nothing to do. */
4873  if (relation->rd_indextuple == NULL ||
4874  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4875  return NIL;
4876 
4877  /* Extract raw node tree(s) from index tuple. */
4878  exprsDatum = heap_getattr(relation->rd_indextuple,
4879  Anum_pg_index_indexprs,
4881  &isnull);
4882  Assert(!isnull);
4883  exprsString = TextDatumGetCString(exprsDatum);
4884  rawExprs = (List *) stringToNode(exprsString);
4885  pfree(exprsString);
4886 
4887  /* Construct null Consts; the typlen and typbyval are arbitrary. */
4888  result = NIL;
4889  foreach(lc, rawExprs)
4890  {
4891  Node *rawExpr = (Node *) lfirst(lc);
4892 
4893  result = lappend(result,
4894  makeConst(exprType(rawExpr),
4895  exprTypmod(rawExpr),
4896  exprCollation(rawExpr),
4897  1,
4898  (Datum) 0,
4899  true,
4900  true));
4901  }
4902 
4903  return result;
4904 }
#define NIL
Definition: pg_list.h:65
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Definition: nodes.h:539
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:4232
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:83
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 5313 of file relcache.c.

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, ConstraintRelidTypidNameIndexId, 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().

5317 {
5318  int indnkeyatts;
5319  Oid *ops;
5320  Oid *funcs;
5321  uint16 *strats;
5322  Relation conrel;
5323  SysScanDesc conscan;
5324  ScanKeyData skey[1];
5325  HeapTuple htup;
5326  bool found;
5327  MemoryContext oldcxt;
5328  int i;
5329 
5330  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5331 
5332  /* Allocate result space in caller context */
5333  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5334  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5335  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5336 
5337  /* Quick exit if we have the data cached already */
5338  if (indexRelation->rd_exclstrats != NULL)
5339  {
5340  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5341  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5342  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5343  return;
5344  }
5345 
5346  /*
5347  * Search pg_constraint for the constraint associated with the index. To
5348  * make this not too painfully slow, we use the index on conrelid; that
5349  * will hold the parent relation's OID not the index's own OID.
5350  *
5351  * Note: if we wanted to rely on the constraint name matching the index's
5352  * name, we could just do a direct lookup using pg_constraint's unique
5353  * index. For the moment it doesn't seem worth requiring that.
5354  */
5355  ScanKeyInit(&skey[0],
5356  Anum_pg_constraint_conrelid,
5357  BTEqualStrategyNumber, F_OIDEQ,
5358  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5359 
5360  conrel = table_open(ConstraintRelationId, AccessShareLock);
5361  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5362  NULL, 1, skey);
5363  found = false;
5364 
5365  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5366  {
5368  Datum val;
5369  bool isnull;
5370  ArrayType *arr;
5371  int nelem;
5372 
5373  /* We want the exclusion constraint owning the index */
5374  if (conform->contype != CONSTRAINT_EXCLUSION ||
5375  conform->conindid != RelationGetRelid(indexRelation))
5376  continue;
5377 
5378  /* There should be only one */
5379  if (found)
5380  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5381  RelationGetRelationName(indexRelation));
5382  found = true;
5383 
5384  /* Extract the operator OIDS from conexclop */
5385  val = fastgetattr(htup,
5386  Anum_pg_constraint_conexclop,
5387  conrel->rd_att, &isnull);
5388  if (isnull)
5389  elog(ERROR, "null conexclop for rel %s",
5390  RelationGetRelationName(indexRelation));
5391 
5392  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5393  nelem = ARR_DIMS(arr)[0];
5394  if (ARR_NDIM(arr) != 1 ||
5395  nelem != indnkeyatts ||
5396  ARR_HASNULL(arr) ||
5397  ARR_ELEMTYPE(arr) != OIDOID)
5398  elog(ERROR, "conexclop is not a 1-D Oid array");
5399 
5400  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5401  }
5402 
5403  systable_endscan(conscan);
5404  table_close(conrel, AccessShareLock);
5405 
5406  if (!found)
5407  elog(ERROR, "exclusion constraint record missing for rel %s",
5408  RelationGetRelationName(indexRelation));
5409 
5410  /* We need the func OIDs and strategy numbers too */
5411  for (i = 0; i < indnkeyatts; i++)
5412  {
5413  funcs[i] = get_opcode(ops[i]);
5414  strats[i] = get_op_opfamily_strategy(ops[i],
5415  indexRelation->rd_opfamily[i]);
5416  /* shouldn't fail, since it was checked at index creation */
5417  if (strats[i] == InvalidStrategy)
5418  elog(ERROR, "could not find strategy for operator %u in family %u",
5419  ops[i], indexRelation->rd_opfamily[i]);
5420  }
5421 
5422  /* Save a copy of the results in the relcache entry. */
5423  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5424  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5425  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5426  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5427  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5428  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5429  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5430  MemoryContextSwitchTo(oldcxt);
5431 }
#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 ConstraintRelidTypidNameIndexId
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define RelationGetRelationName(relation)
Definition: rel.h:503
#define ARR_HASNULL(a)
Definition: array.h:284
Oid * rd_opfamily
Definition: rel.h:202
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:488
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:469
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 4461 of file relcache.c.

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confkey, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conkey, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conpfeqop, ForeignKeyCacheInfo::conrelid, ConstraintRelidTypidNameIndexId, 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().

4462 {
4463  List *result;
4464  Relation conrel;
4465  SysScanDesc conscan;
4466  ScanKeyData skey;
4467  HeapTuple htup;
4468  List *oldlist;
4469  MemoryContext oldcxt;
4470 
4471  /* Quick exit if we already computed the list. */
4472  if (relation->rd_fkeyvalid)
4473  return relation->rd_fkeylist;
4474 
4475  /* Fast path: non-partitioned tables without triggers can't have FKs */
4476  if (!relation->rd_rel->relhastriggers &&
4477  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4478  return NIL;
4479 
4480  /*
4481  * We build the list we intend to return (in the caller's context) while
4482  * doing the scan. After successfully completing the scan, we copy that
4483  * list into the relcache entry. This avoids cache-context memory leakage
4484  * if we get some sort of error partway through.
4485  */
4486  result = NIL;
4487 
4488  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4489  ScanKeyInit(&skey,
4490  Anum_pg_constraint_conrelid,
4491  BTEqualStrategyNumber, F_OIDEQ,
4492  ObjectIdGetDatum(RelationGetRelid(relation)));
4493 
4494  conrel = table_open(ConstraintRelationId, AccessShareLock);
4495  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4496  NULL, 1, &skey);
4497 
4498  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4499  {
4500  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4501  ForeignKeyCacheInfo *info;
4502 
4503  /* consider only foreign keys */
4504  if (constraint->contype != CONSTRAINT_FOREIGN)
4505  continue;
4506 
4507  info = makeNode(ForeignKeyCacheInfo);
4508  info->conoid = constraint->oid;
4509  info->conrelid = constraint->conrelid;
4510  info->confrelid = constraint->confrelid;
4511 
4512  DeconstructFkConstraintRow(htup, &info->nkeys,
4513  info->conkey,
4514  info->confkey,
4515  info->conpfeqop,
4516  NULL, NULL);
4517 
4518  /* Add FK's node to the result list */
4519  result = lappend(result, info);
4520  }
4521 
4522  systable_endscan(conscan);
4523  table_close(conrel, AccessShareLock);
4524 
4525  /* Now save a copy of the completed list in the relcache entry. */
4527  oldlist = relation->rd_fkeylist;
4528  relation->rd_fkeylist = copyObject(result);
4529  relation->rd_fkeyvalid = true;
4530  MemoryContextSwitchTo(oldcxt);
4531 
4532  /* Don't leak the old list, if there is one */
4533  list_free_deep(oldlist);
4534 
4535  return result;
4536 }
#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
#define ConstraintRelidTypidNameIndexId
List * lappend(List *list, void *datum)
Definition: list.c:336
#define makeNode(_type_)
Definition: nodes.h:587
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:655
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:469
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIdentityKeyBitmap()

Bitmapset* RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5244 of file relcache.c.

References Assert, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, FirstLowInvalidHeapAttributeNumber, HistoricSnapshotActive(), i, list_free(), MemoryContextSwitchTo(), NIL, RelationData::rd_idattr, RelationData::rd_index, RelationData::rd_replidindex, RelationClose(), RelationGetForm, RelationGetIndexList(), and RelationIdGetRelation().

Referenced by logicalrep_write_attrs().

5245 {
5246  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5247  List *indexoidlist;
5248  Relation indexDesc;
5249  int i;
5250  MemoryContext oldcxt;
5251 
5252  /* Quick exit if we already computed the result */
5253  if (relation->rd_idattr != NULL)
5254  return bms_copy(relation->rd_idattr);
5255 
5256  /* Fast path if definitely no indexes */
5257  if (!RelationGetForm(relation)->relhasindex)
5258  return NULL;
5259 
5260  /* Historic snapshot must be set. */
5262 
5263  indexoidlist = RelationGetIndexList(relation);
5264 
5265  /* Fall out if no indexes (but relhasindex was set) */
5266  if (indexoidlist == NIL)
5267  return NULL;
5268 
5269  /* Add referenced attributes to idindexattrs */
5270  indexDesc = RelationIdGetRelation(relation->rd_replidindex);
5271  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5272  {
5273  int attrnum = indexDesc->rd_index->indkey.values[i];
5274 
5275  /*
5276  * We don't include non-key columns into idindexattrs bitmaps. See
5277  * RelationGetIndexAttrBitmap.
5278  */
5279  if (attrnum != 0)
5280  {
5281  if (i < indexDesc->rd_index->indnkeyatts)
5282  idindexattrs = bms_add_member(idindexattrs,
5284  }
5285  }
5286 
5287  RelationClose(indexDesc);
5288  list_free(indexoidlist);
5289 
5290  /* Don't leak the old values of these bitmaps, if any */
5291  bms_free(relation->rd_idattr);
5292  relation->rd_idattr = NULL;
5293 
5294  /* Now save copy of the bitmap in the relcache entry */
5296  relation->rd_idattr = bms_copy(idindexattrs);
5297  MemoryContextSwitchTo(oldcxt);
5298 
5299  /* We return our original working copy for caller to play with */
5300  return idindexattrs;
5301 }
#define NIL
Definition: pg_list.h:65
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Oid rd_replidindex
Definition: rel.h:152
#define RelationGetForm(relation)
Definition: rel.h:463
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Form_pg_index rd_index
Definition: rel.h:187
void RelationClose(Relation relation)
Definition: relcache.c:2098
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
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4570
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058
void list_free(List *list)
Definition: list.c:1391
int i
Definition: pg_list.h:50
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:1992
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIndexAttOptions()

bytea** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5567 of file relcache.c.

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

5568 {
5569  MemoryContext oldcxt;
5570  bytea **opts = relation->rd_opcoptions;
5571  Oid relid = RelationGetRelid(relation);
5572  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5573  * IndexRelationGetNumberOfKeyAttributes */
5574  int i;
5575 
5576  /* Try to copy cached options. */
5577  if (opts)
5578  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5579 
5580  /* Get and parse opclass options. */
5581  opts = palloc0(sizeof(*opts) * natts);
5582 
5583  for (i = 0; i < natts; i++)
5584  {
5586  {
5587  Datum attoptions = get_attoptions(relid, i + 1);
5588 
5589  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5590 
5591  if (attoptions != (Datum) 0)
5592  pfree(DatumGetPointer(attoptions));
5593  }
5594  }
5595 
5596  /* Copy parsed options to the cache. */
5597  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5598  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5599  MemoryContextSwitchTo(oldcxt);
5600 
5601  if (copy)
5602  return opts;
5603 
5604  for (i = 0; i < natts; i++)
5605  {
5606  if (opts[i])
5607  pfree(opts[i]);
5608  }
5609 
5610  pfree(opts);
5611 
5612  return relation->rd_opcoptions;
5613 }
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:475
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
#define AttributeRelidNumIndexId
Definition: pg_attribute.h:212
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5547
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:469

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5000 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().

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

4805 {
4806  List *result;
4807  Datum exprsDatum;
4808  bool isnull;
4809  char *exprsString;
4810  MemoryContext oldcxt;
4811 
4812  /* Quick exit if we already computed the result. */
4813  if (relation->rd_indexprs)
4814  return copyObject(relation->rd_indexprs);
4815 
4816  /* Quick exit if there is nothing to do. */
4817  if (relation->rd_indextuple == NULL ||
4818  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4819  return NIL;
4820 
4821  /*
4822  * We build the tree we intend to return in the caller's context. After
4823  * successfully completing the work, we copy it into the relcache entry.
4824  * This avoids problems if we get some sort of error partway through.
4825  */
4826  exprsDatum = heap_getattr(relation->rd_indextuple,
4827  Anum_pg_index_indexprs,
4829  &isnull);
4830  Assert(!isnull);
4831  exprsString = TextDatumGetCString(exprsDatum);
4832  result = (List *) stringToNode(exprsString);
4833  pfree(exprsString);
4834 
4835  /*
4836  * Run the expressions through eval_const_expressions. This is not just an
4837  * optimization, but is necessary, because the planner will be comparing
4838  * them to similarly-processed qual clauses, and may fail to detect valid
4839  * matches without this. We must not use canonicalize_qual, however,
4840  * since these aren't qual expressions.
4841  */
4842  result = (List *) eval_const_expressions(NULL, (Node *) result);
4843 
4844  /* May as well fix opfuncids too */
4845  fix_opfuncids((Node *) result);
4846 
4847  /* Now save a copy of the completed tree in the relcache entry. */
4848  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4849  relation->rd_indexprs = copyObject(result);
4850  MemoryContextSwitchTo(oldcxt);
4851 
4852  return result;
4853 }
#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:539
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2093
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:4232
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
#define TextDatumGetCString(d)
Definition: builtins.h:83
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:655
Definition: pg_list.h:50

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4570 of file relcache.c.

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT, heap_attisnull(), HeapTupleIsValid, IndexIndrelidIndexId, 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(), 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(), RelationGetIdentityKeyBitmap(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

4571 {
4572  Relation indrel;
4573  SysScanDesc indscan;
4574  ScanKeyData skey;
4575  HeapTuple htup;
4576  List *result;
4577  List *oldlist;
4578  char replident = relation->rd_rel->relreplident;
4579  Oid pkeyIndex = InvalidOid;
4580  Oid candidateIndex = InvalidOid;
4581  MemoryContext oldcxt;
4582 
4583  /* Quick exit if we already computed the list. */
4584  if (relation->rd_indexvalid)
4585  return list_copy(relation->rd_indexlist);
4586 
4587  /*
4588  * We build the list we intend to return (in the caller's context) while
4589  * doing the scan. After successfully completing the scan, we copy that
4590  * list into the relcache entry. This avoids cache-context memory leakage
4591  * if we get some sort of error partway through.
4592  */
4593  result = NIL;
4594 
4595  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4596  ScanKeyInit(&skey,
4597  Anum_pg_index_indrelid,
4598  BTEqualStrategyNumber, F_OIDEQ,
4599  ObjectIdGetDatum(RelationGetRelid(relation)));
4600 
4601  indrel = table_open(IndexRelationId, AccessShareLock);
4602  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4603  NULL, 1, &skey);
4604 
4605  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4606  {
4608 
4609  /*
4610  * Ignore any indexes that are currently being dropped. This will
4611  * prevent them from being searched, inserted into, or considered in
4612  * HOT-safety decisions. It's unsafe to touch such an index at all
4613  * since its catalog entries could disappear at any instant.
4614  */
4615  if (!index->indislive)
4616  continue;
4617 
4618  /* add index's OID to result list */
4619  result = lappend_oid(result, index->indexrelid);
4620 
4621  /*
4622  * Invalid, non-unique, non-immediate or predicate indexes aren't
4623  * interesting for either oid indexes or replication identity indexes,
4624  * so don't check them.
4625  */
4626  if (!index->indisvalid || !index->indisunique ||
4627  !index->indimmediate ||
4628  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4629  continue;
4630 
4631  /* remember primary key index if any */
4632  if (index->indisprimary)
4633  pkeyIndex = index->indexrelid;
4634 
4635  /* remember explicitly chosen replica index */
4636  if (index->indisreplident)
4637  candidateIndex = index->indexrelid;
4638  }
4639 
4640  systable_endscan(indscan);
4641 
4642  table_close(indrel, AccessShareLock);
4643 
4644  /* Sort the result list into OID order, per API spec. */
4645  list_sort(result, list_oid_cmp);
4646 
4647  /* Now save a copy of the completed list in the relcache entry. */
4649  oldlist = relation->rd_indexlist;
4650  relation->rd_indexlist = list_copy(result);
4651  relation->rd_pkindex = pkeyIndex;
4652  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4653  relation->rd_replidindex = pkeyIndex;
4654  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4655  relation->rd_replidindex = candidateIndex;
4656  else
4657  relation->rd_replidindex = InvalidOid;
4658  relation->rd_indexvalid = true;
4659  MemoryContextSwitchTo(oldcxt);
4660 
4661  /* Don't leak the old list, if there is one */
4662  list_free(oldlist);
4663 
4664  return result;
4665 }
#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
#define IndexIndrelidIndexId
Definition: pg_index.h:72
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:469
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 4917 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().

4918 {
4919  List *result;
4920  Datum predDatum;
4921  bool isnull;
4922  char *predString;
4923  MemoryContext oldcxt;
4924 
4925  /* Quick exit if we already computed the result. */
4926  if (relation->rd_indpred)
4927  return copyObject(relation->rd_indpred);
4928 
4929  /* Quick exit if there is nothing to do. */
4930  if (relation->rd_indextuple == NULL ||
4931  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
4932  return NIL;
4933 
4934  /*
4935  * We build the tree we intend to return in the caller's context. After
4936  * successfully completing the work, we copy it into the relcache entry.
4937  * This avoids problems if we get some sort of error partway through.
4938  */
4939  predDatum = heap_getattr(relation->rd_indextuple,
4940  Anum_pg_index_indpred,
4942  &isnull);
4943  Assert(!isnull);
4944  predString = TextDatumGetCString(predDatum);
4945  result = (List *) stringToNode(predString);
4946  pfree(predString);
4947 
4948  /*
4949  * Run the expression through const-simplification and canonicalization.
4950  * This is not just an optimization, but is necessary, because the planner
4951  * will be comparing it to similarly-processed qual clauses, and may fail
4952  * to detect valid matches without this. This must match the processing
4953  * done to qual clauses in preprocess_expression()! (We can skip the
4954  * stuff involving subqueries, however, since we don't allow any in index
4955  * predicates.)
4956  */
4957  result = (List *) eval_const_expressions(NULL, (Node *) result);
4958 
4959  result = (List *) canonicalize_qual((Expr *) result, false);
4960 
4961  /* Also convert to implicit-AND format */
4962  result = make_ands_implicit((Expr *) result);
4963 
4964  /* May as well fix opfuncids too */
4965  fix_opfuncids((Node *) result);
4966 
4967  /* Now save a copy of the completed tree in the relcache entry. */
4968  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4969  relation->rd_indpred = copyObject(result);
4970  MemoryContextSwitchTo(oldcxt);
4971 
4972  return result;
4973 }
#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:539
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2093
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:4232
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
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:83
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:655
Definition: pg_list.h:50

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  relation)

Definition at line 5521 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().

5522 {
5523  Oid indexrelid = RelationGetRelid(indexrel);
5524  int16 natts = RelationGetNumberOfAttributes(indexrel);
5525  Datum *options = NULL;
5526  int16 attnum;
5527 
5528  for (attnum = 1; attnum <= natts; attnum++)
5529  {
5530  if (indexrel->rd_indam->amoptsprocnum == 0)
5531  continue;
5532 
5533  if (!OidIsValid(index_getprocid(indexrel, attnum,
5534  indexrel->rd_indam->amoptsprocnum)))
5535  continue;
5536 
5537  if (!options)
5538  options = palloc0(sizeof(Datum) * natts);
5539 
5540  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5541  }
5542 
5543  return options;
5544 }
signed short int16
Definition: c.h:428
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:475
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:469
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4758 of file relcache.c.

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

Referenced by build_replindex_scan_key(), and GetRelationIdentityOrPK().

4759 {
4760  List *ilist;
4761 
4762  if (!relation->rd_indexvalid)
4763  {
4764  /* RelationGetIndexList does the heavy lifting. */
4765  ilist = RelationGetIndexList(relation);
4766  list_free(ilist);
4767  Assert(relation->rd_indexvalid);
4768  }
4769 
4770  return relation->rd_pkindex;
4771 }
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:4570
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4779 of file relcache.c.

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

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

4780 {
4781  List *ilist;
4782 
4783  if (!relation->rd_indexvalid)
4784  {
4785  /* RelationGetIndexList does the heavy lifting. */
4786  ilist = RelationGetIndexList(relation);
4787  list_free(ilist);
4788  Assert(relation->rd_indexvalid);
4789  }
4790 
4791  return relation->rd_replidindex;
4792 }
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:4570
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4689 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(), StatisticExtRelidIndexId, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_relation_statistics(), and transformTableLikeClause().

4690 {
4691  Relation indrel;
4692  SysScanDesc indscan;
4693  ScanKeyData skey;
4694  HeapTuple htup;
4695  List *result;
4696  List *oldlist;
4697  MemoryContext oldcxt;
4698 
4699  /* Quick exit if we already computed the list. */
4700  if (relation->rd_statvalid != 0)
4701  return list_copy(relation->rd_statlist);
4702 
4703  /*
4704  * We build the list we intend to return (in the caller's context) while
4705  * doing the scan. After successfully completing the scan, we copy that
4706  * list into the relcache entry. This avoids cache-context memory leakage
4707  * if we get some sort of error partway through.
4708  */
4709  result = NIL;
4710 
4711  /*
4712  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4713  * rel.
4714  */
4715  ScanKeyInit(&skey,
4716  Anum_pg_statistic_ext_stxrelid,
4717  BTEqualStrategyNumber, F_OIDEQ,
4718  ObjectIdGetDatum(RelationGetRelid(relation)));
4719 
4720  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4721  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4722  NULL, 1, &skey);
4723 
4724  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4725  {
4726  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4727 
4728  result = lappend_oid(result, oid);
4729  }
4730 
4731  systable_endscan(indscan);
4732 
4733  table_close(indrel, AccessShareLock);
4734 
4735  /* Sort the result list into OID order, per API spec. */
4736  list_sort(result, list_oid_cmp);
4737 
4738  /* Now save a copy of the completed list in the relcache entry. */
4740  oldlist = relation->rd_statlist;
4741  relation->rd_statlist = list_copy(result);
4742 
4743  relation->rd_statvalid = true;
4744  MemoryContextSwitchTo(oldcxt);
4745 
4746  /* Don't leak the old list, if there is one */
4747  list_free(oldlist);
4748 
4749  return result;
4750 }
#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
#define StatisticExtRelidIndexId
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:469
#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 1992 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().

1993 {
1994  Relation rd;
1995 
1996  /* Make sure we're in an xact, even if this ends up being a cache hit */
1998 
1999  /*
2000  * first try to find reldesc in the cache
2001  */
2002  RelationIdCacheLookup(relationId, rd);
2003 
2004  if (RelationIsValid(rd))
2005  {
2006  /* return NULL for dropped relations */
2008  {
2009  Assert(!rd->rd_isvalid);
2010  return NULL;
2011  }
2012 
2014  /* revalidate cache entry if necessary */
2015  if (!rd->rd_isvalid)
2016  {
2017  /*
2018  * Indexes only have a limited number of possible schema changes,
2019  * and we don't want to use the full-blown procedure because it's
2020  * a headache for indexes that reload itself depends on.
2021  */
2022  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2023  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2025  else
2026  RelationClearRelation(rd, true);
2027 
2028  /*
2029  * Normally entries need to be valid here, but before the relcache
2030  * has been initialized, not enough infrastructure exists to
2031  * perform pg_class lookups. The structure of such entries doesn't
2032  * change, but we still want to update the rd_rel entry. So
2033  * rd_isvalid = false is left in place for a later lookup.
2034  */
2035  Assert(rd->rd_isvalid ||
2037  }
2038  return rd;
2039  }
2040 
2041  /*
2042  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2043  * it.
2044  */
2045  rd = RelationBuildDesc(relationId, true);
2046  if (RelationIsValid(rd))
2048  return rd;
2049 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2428
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:442
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2065
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2155
#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 6392 of file relcache.c.

References Assert, DatabaseNameIndexId, RelationSupportsSysCache(), SharedSecLabelObjectIndexId, and TriggerRelidNameIndexId.

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

6393 {
6394  if (relationId == SharedSecLabelRelationId ||
6395  relationId == TriggerRelidNameIndexId ||
6396  relationId == DatabaseNameIndexId ||
6397  relationId == SharedSecLabelObjectIndexId)
6398  {
6399  /*
6400  * If this Assert fails, we don't need the applicable special case
6401  * anymore.
6402  */
6403  Assert(!RelationSupportsSysCache(relationId));
6404  return true;
6405  }
6406  return RelationSupportsSysCache(relationId);
6407 }
#define TriggerRelidNameIndexId
Definition: pg_trigger.h:87
#define DatabaseNameIndexId
Definition: pg_database.h:88
#define SharedSecLabelObjectIndexId
Definition: pg_shseclabel.h:47
#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:475
#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:4232
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:668
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:481
#define RelationGetRelationName(relation)
Definition: rel.h:503
List * rd_indpred
Definition: rel.h:208
Oid * rd_opfamily
Definition: rel.h:202
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:488
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:5567
void * rd_amcache
Definition: rel.h:224
Oid * rd_opcintype
Definition: rel.h:203
#define RelationGetRelid(relation)
Definition: rel.h:469
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1740 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().

1741 {
1742  HeapTuple tuple;
1743  Form_pg_am aform;
1744 
1745  if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1746  {
1747  /*
1748  * Sequences are currently accessed like heap tables, but it doesn't
1749  * seem prudent to show that in the catalog. So just overwrite it
1750  * here.
1751  */
1752  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1753  }
1754  else if (IsCatalogRelation(relation))
1755  {
1756  /*
1757  * Avoid doing a syscache lookup for catalog tables.
1758  */
1759  Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1760  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1761  }
1762  else
1763  {
1764  /*
1765  * Look up the table access method, save the OID of its handler
1766  * function.
1767  */
1768  Assert(relation->rd_rel->relam != InvalidOid);
1769  tuple = SearchSysCache1(AMOID,
1770  ObjectIdGetDatum(relation->rd_rel->relam));
1771  if (!HeapTupleIsValid(tuple))
1772  elog(ERROR, "cache lookup failed for access method %u",
1773  relation->rd_rel->relam);
1774  aform = (Form_pg_am) GETSTRUCT(tuple);
1775  relation->rd_amhandler = aform->amhandler;
1776  ReleaseSysCache(tuple);
1777  }
1778 
1779  /*
1780  * Now we can fetch the table AM's API struct
1781  */
1782  InitTableAmRoutine(relation);
1783 }
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1731
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
#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 3595 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().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

bool criticalSharedRelcachesBuilt