PostgreSQL Source Code  git master
relcache.h File Reference
#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
Include dependency graph for relcache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define RELCACHE_INIT_FILENAME   "pg_internal.init"
 

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)
 
ListRelationGetIndexPredicate (Relation relation)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
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 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

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

Definition at line 26 of file relcache.h.

◆ RelationPtr

Definition at line 34 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_ALL 
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 

Definition at line 53 of file relcache.h.

Function Documentation

◆ AtEOSubXact_RelationCache()

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

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

3079 {
3081  RelIdCacheEnt *idhentry;
3082  int i;
3083 
3084  /*
3085  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3086  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3087  * logic as in AtEOXact_RelationCache.
3088  */
3090  {
3091  hash_seq_init(&status, RelationIdCache);
3092  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3093  {
3094  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3095  mySubid, parentSubid);
3096  }
3097  }
3098  else
3099  {
3100  for (i = 0; i < eoxact_list_len; i++)
3101  {
3102  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3103  (void *) &eoxact_list[i],
3104  HASH_FIND,
3105  NULL);
3106  if (idhentry != NULL)
3107  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3108  mySubid, parentSubid);
3109  }
3110  }
3111 
3112  /* Don't reset the list; we still need more cleanup later */
3113 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:168
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3124
Relation reldesc
Definition: relcache.c:132
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:135
static bool eoxact_list_overflowed
Definition: relcache.c:170
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
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:169

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

2940 {
2942  RelIdCacheEnt *idhentry;
2943  int i;
2944 
2945  /*
2946  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2947  * listed in it. Otherwise fall back on a hash_seq_search scan.
2948  *
2949  * For simplicity, eoxact_list[] entries are not deleted till end of
2950  * top-level transaction, even though we could remove them at
2951  * subtransaction end in some cases, or remove relations from the list if
2952  * they are cleared for other reasons. Therefore we should expect the
2953  * case that list entries are not found in the hashtable; if not, there's
2954  * nothing to do for them.
2955  */
2957  {
2958  hash_seq_init(&status, RelationIdCache);
2959  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2960  {
2961  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2962  }
2963  }
2964  else
2965  {
2966  for (i = 0; i < eoxact_list_len; i++)
2967  {
2968  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2969  (void *) &eoxact_list[i],
2970  HASH_FIND,
2971  NULL);
2972  if (idhentry != NULL)
2973  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2974  }
2975  }
2976 
2977  if (EOXactTupleDescArrayLen > 0)
2978  {
2979  Assert(EOXactTupleDescArray != NULL);
2980  for (i = 0; i < NextEOXactTupleDescNum; i++)
2983  EOXactTupleDescArray = NULL;
2984  }
2985 
2986  /* Now we're out of the transaction and can clear the lists */
2987  eoxact_list_len = 0;
2988  eoxact_list_overflowed = false;
2989  NextEOXactTupleDescNum = 0;
2991 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:168
static int EOXactTupleDescArrayLen
Definition: relcache.c:187
Relation reldesc
Definition: relcache.c:132
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:135
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3002
static bool eoxact_list_overflowed
Definition: relcache.c:170
static int NextEOXactTupleDescNum
Definition: relcache.c:186
void pfree(void *pointer)
Definition: mcxt.c:1031
#define Assert(condition)
Definition: c.h:732
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:313
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:169
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:185

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5168 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(), BuildRelationExtStatistics(), errtablecolname(), and errtableconstraint().

5169 {
5173 
5174  return 0; /* return value does not matter */
5175 }
#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:3094
#define RelationGetRelationName(relation)
Definition: rel.h:450
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
#define RelationGetNamespace(relation)
Definition: rel.h:457

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5185 of file relcache.c.

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

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

5186 {
5187  TupleDesc reldesc = RelationGetDescr(rel);
5188  const char *colname;
5189 
5190  /* Use reldesc if it's a user attribute, else consult the catalogs */
5191  if (attnum > 0 && attnum <= reldesc->natts)
5192  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5193  else
5194  colname = get_attname(RelationGetRelid(rel), attnum, false);
5195 
5196  return errtablecolname(rel, colname);
5197 }
#define RelationGetDescr(relation)
Definition: rel.h:442
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
NameData attname
Definition: pg_attribute.h:40
int16 attnum
Definition: pg_attribute.h:79
#define NameStr(name)
Definition: c.h:609
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:416
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5209

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5209 of file relcache.c.

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

Referenced by errtablecol().

5210 {
5211  errtable(rel);
5213 
5214  return 0; /* return value does not matter */
5215 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
int errtable(Relation rel)
Definition: relcache.c:5168

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5222 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(), ri_ReportViolation(), and validateCheckConstraint().

5223 {
5224  errtable(rel);
5226 
5227  return 0; /* return value does not matter */
5228 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
int errtable(Relation rel)
Definition: relcache.c:5168

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5089 of file relcache.c.

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

Referenced by CheckCmdReplicaIdentity().

5090 {
5091  List *puboids;
5092  ListCell *lc;
5093  MemoryContext oldcxt;
5094  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5095 
5096  /*
5097  * If not publishable, it publishes no actions. (pgoutput_change() will
5098  * ignore it.)
5099  */
5100  if (!is_publishable_relation(relation))
5101  return pubactions;
5102 
5103  if (relation->rd_pubactions)
5104  return memcpy(pubactions, relation->rd_pubactions,
5105  sizeof(PublicationActions));
5106 
5107  /* Fetch the publication membership info. */
5108  puboids = GetRelationPublications(RelationGetRelid(relation));
5109  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5110 
5111  foreach(lc, puboids)
5112  {
5113  Oid pubid = lfirst_oid(lc);
5114  HeapTuple tup;
5115  Form_pg_publication pubform;
5116 
5118 
5119  if (!HeapTupleIsValid(tup))
5120  elog(ERROR, "cache lookup failed for publication %u", pubid);
5121 
5122  pubform = (Form_pg_publication) GETSTRUCT(tup);
5123 
5124  pubactions->pubinsert |= pubform->pubinsert;
5125  pubactions->pubupdate |= pubform->pubupdate;
5126  pubactions->pubdelete |= pubform->pubdelete;
5127  pubactions->pubtruncate |= pubform->pubtruncate;
5128 
5129  ReleaseSysCache(tup);
5130 
5131  /*
5132  * If we know everything is replicated, there is no point to check for
5133  * other publications.
5134  */
5135  if (pubactions->pubinsert && pubactions->pubupdate &&
5136  pubactions->pubdelete && pubactions->pubtruncate)
5137  break;
5138  }
5139 
5140  if (relation->rd_pubactions)
5141  {
5142  pfree(relation->rd_pubactions);
5143  relation->rd_pubactions = NULL;
5144  }
5145 
5146  /* Now save copy of the actions in the relcache entry. */
5148  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5149  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5150  MemoryContextSwitchTo(oldcxt);
5151 
5152  return pubactions;
5153 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:119
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1298
bool is_publishable_relation(Relation rel)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void * palloc0(Size size)
Definition: mcxt.c:955
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:416
#define lfirst_oid(lc)
Definition: pg_list.h:192
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ 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 3176 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_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(), relfilenode, relkind, relpersistence, TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

3187 {
3188  Relation rel;
3189  MemoryContext oldcxt;
3190  int natts = tupDesc->natts;
3191  int i;
3192  bool has_not_null;
3193  bool nailit;
3194 
3195  AssertArg(natts >= 0);
3196 
3197  /*
3198  * check for creation of a rel that must be nailed in cache.
3199  *
3200  * XXX this list had better match the relations specially handled in
3201  * RelationCacheInitializePhase2/3.
3202  */
3203  switch (relid)
3204  {
3205  case DatabaseRelationId:
3206  case AuthIdRelationId:
3207  case AuthMemRelationId:
3208  case RelationRelationId:
3209  case AttributeRelationId:
3210  case ProcedureRelationId:
3211  case TypeRelationId:
3212  nailit = true;
3213  break;
3214  default:
3215  nailit = false;
3216  break;
3217  }
3218 
3219  /*
3220  * check that hardwired list of shared rels matches what's in the
3221  * bootstrap .bki file. If you get a failure here during initdb, you
3222  * probably need to fix IsSharedRelation() to match whatever you've done
3223  * to the set of shared relations.
3224  */
3225  if (shared_relation != IsSharedRelation(relid))
3226  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3227  relname, relid);
3228 
3229  /* Shared relations had better be mapped, too */
3230  Assert(mapped_relation || !shared_relation);
3231 
3232  /*
3233  * switch to the cache context to create the relcache entry.
3234  */
3235  if (!CacheMemoryContext)
3237 
3239 
3240  /*
3241  * allocate a new relation descriptor and fill in basic state fields.
3242  */
3243  rel = (Relation) palloc0(sizeof(RelationData));
3244 
3245  /* make sure relation is marked as having no open file yet */
3246  rel->rd_smgr = NULL;
3247 
3248  /* mark it nailed if appropriate */
3249  rel->rd_isnailed = nailit;
3250 
3251  rel->rd_refcnt = nailit ? 1 : 0;
3252 
3253  /* it's being created in this transaction */
3256 
3257  /*
3258  * create a new tuple descriptor from the one passed in. We do this
3259  * partly to copy it into the cache context, and partly because the new
3260  * relation can't have any defaults or constraints yet; they have to be
3261  * added in later steps, because they require additions to multiple system
3262  * catalogs. We can copy attnotnull constraints here, however.
3263  */
3264  rel->rd_att = CreateTupleDescCopy(tupDesc);
3265  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3266  has_not_null = false;
3267  for (i = 0; i < natts; i++)
3268  {
3269  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3270  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3271 
3272  datt->attidentity = satt->attidentity;
3273  datt->attgenerated = satt->attgenerated;
3274  datt->attnotnull = satt->attnotnull;
3275  has_not_null |= satt->attnotnull;
3276  }
3277 
3278  if (has_not_null)
3279  {
3280  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3281 
3282  constr->has_not_null = true;
3283  rel->rd_att->constr = constr;
3284  }
3285 
3286  /*
3287  * initialize relation tuple form (caller may add/override data later)
3288  */
3290 
3291  namestrcpy(&rel->rd_rel->relname, relname);
3292  rel->rd_rel->relnamespace = relnamespace;
3293 
3294  rel->rd_rel->relkind = relkind;
3295  rel->rd_rel->relnatts = natts;
3296  rel->rd_rel->reltype = InvalidOid;
3297  /* needed when bootstrapping: */
3298  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3299 
3300  /* set up persistence and relcache fields dependent on it */
3301  rel->rd_rel->relpersistence = relpersistence;
3302  switch (relpersistence)
3303  {
3304  case RELPERSISTENCE_UNLOGGED:
3305  case RELPERSISTENCE_PERMANENT:
3307  rel->rd_islocaltemp = false;
3308  break;
3309  case RELPERSISTENCE_TEMP:
3310  Assert(isTempOrTempToastNamespace(relnamespace));
3312  rel->rd_islocaltemp = true;
3313  break;
3314  default:
3315  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3316  break;
3317  }
3318 
3319  /* if it's a materialized view, it's not populated initially */
3320  if (relkind == RELKIND_MATVIEW)
3321  rel->rd_rel->relispopulated = false;
3322  else
3323  rel->rd_rel->relispopulated = true;
3324 
3325  /* set replica identity -- system catalogs and non-tables don't have one */
3326  if (!IsCatalogNamespace(relnamespace) &&
3327  (relkind == RELKIND_RELATION ||
3328  relkind == RELKIND_MATVIEW ||
3329  relkind == RELKIND_PARTITIONED_TABLE))
3330  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3331  else
3332  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3333 
3334  /*
3335  * Insert relation physical and logical identifiers (OIDs) into the right
3336  * places. For a mapped relation, we set relfilenode to zero and rely on
3337  * RelationInitPhysicalAddr to consult the map.
3338  */
3339  rel->rd_rel->relisshared = shared_relation;
3340 
3341  RelationGetRelid(rel) = relid;
3342 
3343  for (i = 0; i < natts; i++)
3344  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3345 
3346  rel->rd_rel->reltablespace = reltablespace;
3347 
3348  if (mapped_relation)
3349  {
3350  rel->rd_rel->relfilenode = InvalidOid;
3351  /* Add it to the active mapping information */
3352  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3353  }
3354  else
3355  rel->rd_rel->relfilenode = relfilenode;
3356 
3357  RelationInitLockInfo(rel); /* see lmgr.c */
3358 
3360 
3361  rel->rd_rel->relam = accessmtd;
3362 
3363  if (relkind == RELKIND_RELATION ||
3364  relkind == RELKIND_SEQUENCE ||
3365  relkind == RELKIND_TOASTVALUE ||
3366  relkind == RELKIND_MATVIEW)
3368 
3369  /*
3370  * Okay to insert into the relcache hash table.
3371  *
3372  * Ordinarily, there should certainly not be an existing hash entry for
3373  * the same OID; but during bootstrap, when we create a "real" relcache
3374  * entry for one of the bootstrap relations, we'll be overwriting the
3375  * phony one created with formrdesc. So allow that to happen for nailed
3376  * rels.
3377  */
3378  RelationCacheInsert(rel, nailit);
3379 
3380  /*
3381  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3382  * can't do this before storing relid in it.
3383  */
3384  EOXactListAdd(rel);
3385 
3386  /*
3387  * done building relcache entry.
3388  */
3389  MemoryContextSwitchTo(oldcxt);
3390 
3391  /* It's fully valid */
3392  rel->rd_isvalid = true;
3393 
3394  /*
3395  * Caller expects us to pin the returned entry.
3396  */
3398 
3399  return rel;
3400 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define EOXactListAdd(rel)
Definition: relcache.c:172
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3173
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1740
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
bool rd_isnailed
Definition: rel.h:60
bool rd_islocaltemp
Definition: rel.h:59
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:61
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
Form_pg_class rd_rel
Definition: rel.h:83
NameData relname
Definition: pg_class.h:35
int namestrcpy(Name name, const char *str)
Definition: name.c:250
char relkind
Definition: pg_class.h:81
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:78
Oid relfilenode
Definition: pg_class.h:54
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1271
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
#define BackendIdForTempRelations()
Definition: backendid.h:34
TupleConstr * constr
Definition: tupdesc.h:85
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define AssertArg(condition)
Definition: c.h:734
SubTransactionId rd_createSubid
Definition: rel.h:79
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:955
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2056
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:240
TupleDesc rd_att
Definition: rel.h:84
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:192
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
BackendId rd_backend
Definition: rel.h:58
#define Assert(condition)
Definition: c.h:732
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define InvalidSubTransactionId
Definition: c.h:513
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:179
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
int rd_refcnt
Definition: rel.h:57
#define elog(elevel,...)
Definition: elog.h:226
int i
int tdrefcount
Definition: tupdesc.h:84
bool has_not_null
Definition: tupdesc.h:44
#define RelationGetRelid(relation)
Definition: rel.h:416
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 5964 of file relcache.c.

References LWLockRelease().

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

5965 {
5966  LWLockRelease(RelCacheInitLock);
5967 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

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

5940 {
5941  char localinitfname[MAXPGPATH];
5942  char sharedinitfname[MAXPGPATH];
5943 
5944  if (DatabasePath)
5945  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
5947  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
5949 
5950  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
5951 
5952  /*
5953  * The files might not be there if no backend has been started since the
5954  * last removal. But complain about failures other than ENOENT with
5955  * ERROR. Fortunately, it's not too late to abort the transaction if we
5956  * can't get rid of the would-be-obsolete init file.
5957  */
5958  if (DatabasePath)
5959  unlink_initfile(localinitfname, ERROR);
5960  unlink_initfile(sharedinitfname, ERROR);
5961 }
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char * DatabasePath
Definition: globals.c:93
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6036
#define snprintf
Definition: port.h:192

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

5980 {
5981  const char *tblspcdir = "pg_tblspc";
5982  DIR *dir;
5983  struct dirent *de;
5984  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
5985 
5986  snprintf(path, sizeof(path), "global/%s",
5988  unlink_initfile(path, LOG);
5989 
5990  /* Scan everything in the default tablespace */
5992 
5993  /* Scan the tablespace link directory to find non-default tablespaces */
5994  dir = AllocateDir(tblspcdir);
5995 
5996  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
5997  {
5998  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
5999  {
6000  /* Scan the tablespace dir for per-database dirs */
6001  snprintf(path, sizeof(path), "%s/%s/%s",
6002  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6004  }
6005  }
6006 
6007  FreeDir(dir);
6008 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6012
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2547
#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:2466
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6036
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2584

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3580 of file relcache.c.

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

Referenced by InitPostgres().

3581 {
3582  HASHCTL ctl;
3583 
3584  /*
3585  * make sure cache memory context exists
3586  */
3587  if (!CacheMemoryContext)
3589 
3590  /*
3591  * create hashtable that indexes the relcache
3592  */
3593  MemSet(&ctl, 0, sizeof(ctl));
3594  ctl.keysize = sizeof(Oid);
3595  ctl.entrysize = sizeof(RelIdCacheEnt);
3596  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3597  &ctl, HASH_ELEM | HASH_BLOBS);
3598 
3599  /*
3600  * relation mapper needs to be initialized too
3601  */
3603 }
void RelationMapInitialize(void)
Definition: relmapper.c:584
#define HASH_ELEM
Definition: hsearch.h:87
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:955
static HTAB * RelationIdCache
Definition: relcache.c:135
unsigned int Oid
Definition: postgres_ext.h:31
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define INITRELCACHESIZE
Definition: relcache.c:3577
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

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

3618 {
3619  MemoryContext oldcxt;
3620 
3621  /*
3622  * relation mapper needs initialized too
3623  */
3625 
3626  /*
3627  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3628  * nothing.
3629  */
3631  return;
3632 
3633  /*
3634  * switch to cache memory context
3635  */
3637 
3638  /*
3639  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3640  * the cache with pre-made descriptors for the critical shared catalogs.
3641  */
3642  if (!load_relcache_init_file(true))
3643  {
3644  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3645  Natts_pg_database, Desc_pg_database);
3646  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3647  Natts_pg_authid, Desc_pg_authid);
3648  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3649  Natts_pg_auth_members, Desc_pg_auth_members);
3650  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3651  Natts_pg_shseclabel, Desc_pg_shseclabel);
3652  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3653  Natts_pg_subscription, Desc_pg_subscription);
3654 
3655 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3656  }
3657 
3658  MemoryContextSwitchTo(oldcxt);
3659 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:118
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5286
void RelationMapInitializePhase2(void)
Definition: relmapper.c:604
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:117
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:121
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:120
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
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:47

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3676 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_partdesc, RelationData::rd_partkey, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), 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().

3677 {
3679  RelIdCacheEnt *idhentry;
3680  MemoryContext oldcxt;
3681  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3682 
3683  /*
3684  * relation mapper needs initialized too
3685  */
3687 
3688  /*
3689  * switch to cache memory context
3690  */
3692 
3693  /*
3694  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3695  * the cache with pre-made descriptors for the critical "nailed-in" system
3696  * catalogs.
3697  */
3698  if (IsBootstrapProcessingMode() ||
3699  !load_relcache_init_file(false))
3700  {
3701  needNewCacheFile = true;
3702 
3703  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3704  Natts_pg_class, Desc_pg_class);
3705  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3706  Natts_pg_attribute, Desc_pg_attribute);
3707  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3708  Natts_pg_proc, Desc_pg_proc);
3709  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3710  Natts_pg_type, Desc_pg_type);
3711 
3712 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3713  }
3714 
3715  MemoryContextSwitchTo(oldcxt);
3716 
3717  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3719  return;
3720 
3721  /*
3722  * If we didn't get the critical system indexes loaded into relcache, do
3723  * so now. These are critical because the catcache and/or opclass cache
3724  * depend on them for fetches done during relcache load. Thus, we have an
3725  * infinite-recursion problem. We can break the recursion by doing
3726  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3727  * performance, we only want to do that until we have the critical indexes
3728  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3729  * decide whether to do heapscan or indexscan at the key spots, and we set
3730  * it true after we've loaded the critical indexes.
3731  *
3732  * The critical indexes are marked as "nailed in cache", partly to make it
3733  * easy for load_relcache_init_file to count them, but mainly because we
3734  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3735  * true. (NOTE: perhaps it would be possible to reload them by
3736  * temporarily setting criticalRelcachesBuilt to false again. For now,
3737  * though, we just nail 'em in.)
3738  *
3739  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3740  * in the same way as the others, because the critical catalogs don't
3741  * (currently) have any rules or triggers, and so these indexes can be
3742  * rebuilt without inducing recursion. However they are used during
3743  * relcache load when a rel does have rules or triggers, so we choose to
3744  * nail them for performance reasons.
3745  */
3747  {
3749  RelationRelationId);
3751  AttributeRelationId);
3753  IndexRelationId);
3755  OperatorClassRelationId);
3757  AccessMethodProcedureRelationId);
3759  RewriteRelationId);
3761  TriggerRelationId);
3762 
3763 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3764 
3765  criticalRelcachesBuilt = true;
3766  }
3767 
3768  /*
3769  * Process critical shared indexes too.
3770  *
3771  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3772  * initial lookup of MyDatabaseId, without which we'll never find any
3773  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3774  * database OID, so it instead depends on DatabaseOidIndexId. We also
3775  * need to nail up some indexes on pg_authid and pg_auth_members for use
3776  * during client authentication. SharedSecLabelObjectIndexId isn't
3777  * critical for the core system, but authentication hooks might be
3778  * interested in it.
3779  */
3781  {
3783  DatabaseRelationId);
3785  DatabaseRelationId);
3787  AuthIdRelationId);
3789  AuthIdRelationId);
3791  AuthMemRelationId);
3793  SharedSecLabelRelationId);
3794 
3795 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3796 
3798  }
3799 
3800  /*
3801  * Now, scan all the relcache entries and update anything that might be
3802  * wrong in the results from formrdesc or the relcache cache file. If we
3803  * faked up relcache entries using formrdesc, then read the real pg_class
3804  * rows and replace the fake entries with them. Also, if any of the
3805  * relcache entries have rules, triggers, or security policies, load that
3806  * info the hard way since it isn't recorded in the cache file.
3807  *
3808  * Whenever we access the catalogs to read data, there is a possibility of
3809  * a shared-inval cache flush causing relcache entries to be removed.
3810  * Since hash_seq_search only guarantees to still work after the *current*
3811  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3812  * We handle this by restarting the scan from scratch after each access.
3813  * This is theoretically O(N^2), but the number of entries that actually
3814  * need to be fixed is small enough that it doesn't matter.
3815  */
3816  hash_seq_init(&status, RelationIdCache);
3817 
3818  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3819  {
3820  Relation relation = idhentry->reldesc;
3821  bool restart = false;
3822 
3823  /*
3824  * Make sure *this* entry doesn't get flushed while we work with it.
3825  */
3827 
3828  /*
3829  * If it's a faked-up entry, read the real pg_class tuple.
3830  */
3831  if (relation->rd_rel->relowner == InvalidOid)
3832  {
3833  HeapTuple htup;
3834  Form_pg_class relp;
3835 
3836  htup = SearchSysCache1(RELOID,
3837  ObjectIdGetDatum(RelationGetRelid(relation)));
3838  if (!HeapTupleIsValid(htup))
3839  elog(FATAL, "cache lookup failed for relation %u",
3840  RelationGetRelid(relation));
3841  relp = (Form_pg_class) GETSTRUCT(htup);
3842 
3843  /*
3844  * Copy tuple to relation->rd_rel. (See notes in
3845  * AllocateRelationDesc())
3846  */
3847  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
3848 
3849  /* Update rd_options while we have the tuple */
3850  if (relation->rd_options)
3851  pfree(relation->rd_options);
3852  RelationParseRelOptions(relation, htup);
3853 
3854  /*
3855  * Check the values in rd_att were set up correctly. (We cannot
3856  * just copy them over now: formrdesc must have set up the rd_att
3857  * data correctly to start with, because it may already have been
3858  * copied into one or more catcache entries.)
3859  */
3860  Assert(relation->rd_att->tdtypeid == relp->reltype);
3861  Assert(relation->rd_att->tdtypmod == -1);
3862 
3863  ReleaseSysCache(htup);
3864 
3865  /* relowner had better be OK now, else we'll loop forever */
3866  if (relation->rd_rel->relowner == InvalidOid)
3867  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
3868  RelationGetRelationName(relation));
3869 
3870  restart = true;
3871  }
3872 
3873  /*
3874  * Fix data that isn't saved in relcache cache file.
3875  *
3876  * relhasrules or relhastriggers could possibly be wrong or out of
3877  * date. If we don't actually find any rules or triggers, clear the
3878  * local copy of the flag so that we don't get into an infinite loop
3879  * here. We don't make any attempt to fix the pg_class entry, though.
3880  */
3881  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
3882  {
3883  RelationBuildRuleLock(relation);
3884  if (relation->rd_rules == NULL)
3885  relation->rd_rel->relhasrules = false;
3886  restart = true;
3887  }
3888  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
3889  {
3890  RelationBuildTriggers(relation);
3891  if (relation->trigdesc == NULL)
3892  relation->rd_rel->relhastriggers = false;
3893  restart = true;
3894  }
3895 
3896  /*
3897  * Re-load the row security policies if the relation has them, since
3898  * they are not preserved in the cache. Note that we can never NOT
3899  * have a policy while relrowsecurity is true,
3900  * RelationBuildRowSecurity will create a single default-deny policy
3901  * if there is no policy defined in pg_policy.
3902  */
3903  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
3904  {
3905  RelationBuildRowSecurity(relation);
3906 
3907  Assert(relation->rd_rsdesc != NULL);
3908  restart = true;
3909  }
3910 
3911  /*
3912  * Reload the partition key and descriptor for a partitioned table.
3913  */
3914  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3915  relation->rd_partkey == NULL)
3916  {
3917  RelationBuildPartitionKey(relation);
3918  Assert(relation->rd_partkey != NULL);
3919 
3920  restart = true;
3921  }
3922 
3923  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3924  relation->rd_partdesc == NULL)
3925  {
3926  RelationBuildPartitionDesc(relation);
3927  Assert(relation->rd_partdesc != NULL);
3928 
3929  restart = true;
3930  }
3931 
3932  if (relation->rd_tableam == NULL &&
3933  (relation->rd_rel->relkind == RELKIND_RELATION ||
3934  relation->rd_rel->relkind == RELKIND_SEQUENCE ||
3935  relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
3936  relation->rd_rel->relkind == RELKIND_MATVIEW))
3937  {
3939  Assert(relation->rd_tableam != NULL);
3940 
3941  restart = true;
3942  }
3943 
3944  /* Release hold on the relation */
3946 
3947  /* Now, restart the hashtable scan if needed */
3948  if (restart)
3949  {
3950  hash_seq_term(&status);
3951  hash_seq_init(&status, RelationIdCache);
3952  }
3953  }
3954 
3955  /*
3956  * Lastly, write out new relcache cache files if needed. We don't bother
3957  * to distinguish cases where only one of the two needs an update.
3958  */
3959  if (needNewCacheFile)
3960  {
3961  /*
3962  * Force all the catcaches to finish initializing and thereby open the
3963  * catalogs and indexes they use. This will preload the relcache with
3964  * entries for all the most important system catalogs and indexes, so
3965  * that the init files will be most useful for future backends.
3966  */
3968 
3969  /* now write the files */
3971  write_relcache_init_file(false);
3972  }
3973 }
#define AttributeRelidNumIndexId
Definition: indexing.h:96
struct PartitionDescData * rd_partdesc
Definition: rel.h:99
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5286
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define IndexRelidIndexId
Definition: indexing.h:168
#define RewriteRelRulenameIndexId
Definition: indexing.h:220
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:192
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1740
Relation reldesc
Definition: relcache.c:132
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:147
#define AuthIdOidIndexId
Definition: indexing.h:101
static HTAB * RelationIdCache
Definition: relcache.c:135
Form_pg_class rd_rel
Definition: rel.h:83
#define TriggerRelidNameIndexId
Definition: indexing.h:256
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2069
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
#define FATAL
Definition: elog.h:52
static void write_relcache_init_file(bool shared)
Definition: relcache.c:5682
struct PartitionKeyData * rd_partkey
Definition: rel.h:97
TriggerDesc * trigdesc
Definition: rel.h:89
void RelationBuildPartitionDesc(Relation rel)
Definition: partdesc.c:61
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:441
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:3982
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:114
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define DatabaseOidIndexId
Definition: indexing.h:146
#define ClassOidIndexId
Definition: indexing.h:114
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:91
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
#define AccessMethodProcedureIndexId
Definition: indexing.h:84
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2056
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
const struct TableAmRoutine * rd_tableam
Definition: rel.h:140
TupleDesc rd_att
Definition: rel.h:84
#define OpclassOidIndexId
Definition: indexing.h:197
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define AuthMemMemRoleIndexId
Definition: indexing.h:106
RuleLock * rd_rules
Definition: rel.h:87
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
#define DatabaseNameIndexId
Definition: indexing.h:144
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define SharedSecLabelObjectIndexId
Definition: indexing.h:323
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
void RelationBuildPartitionKey(Relation relation)
Definition: partcache.c:58
Oid tdtypeid
Definition: tupdesc.h:82
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1930
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:112
#define elog(elevel,...)
Definition: elog.h:226
void RelationMapInitializePhase3(void)
Definition: relmapper.c:625
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:732
bool criticalRelcachesBuilt
Definition: relcache.c:141
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define AuthIdRolnameIndexId
Definition: indexing.h:99
void InitCatalogCachePhase2(void)
Definition: syscache.c:1083
#define RelationGetRelid(relation)
Definition: rel.h:416
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:115
bytea * rd_options
Definition: rel.h:126
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:113
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2779 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_isnailed, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCaches(), and LocalExecuteInvalidationMessage().

2780 {
2782  RelIdCacheEnt *idhentry;
2783  Relation relation;
2784  List *rebuildFirstList = NIL;
2785  List *rebuildList = NIL;
2786  ListCell *l;
2787 
2788  /*
2789  * Reload relation mapping data before starting to reconstruct cache.
2790  */
2792 
2793  /* Phase 1 */
2794  hash_seq_init(&status, RelationIdCache);
2795 
2796  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2797  {
2798  relation = idhentry->reldesc;
2799 
2800  /* Must close all smgr references to avoid leaving dangling ptrs */
2801  RelationCloseSmgr(relation);
2802 
2803  /*
2804  * Ignore new relations; no other backend will manipulate them before
2805  * we commit. Likewise, before replacing a relation's relfilenode, we
2806  * shall have acquired AccessExclusiveLock and drained any applicable
2807  * pending invalidations.
2808  */
2809  if (relation->rd_createSubid != InvalidSubTransactionId ||
2811  continue;
2812 
2814 
2815  if (RelationHasReferenceCountZero(relation))
2816  {
2817  /* Delete this entry immediately */
2818  Assert(!relation->rd_isnailed);
2819  RelationClearRelation(relation, false);
2820  }
2821  else
2822  {
2823  /*
2824  * If it's a mapped relation, immediately update its rd_node in
2825  * case its relfilenode changed. We must do this during phase 1
2826  * in case the relation is consulted during rebuild of other
2827  * relcache entries in phase 2. It's safe since consulting the
2828  * map doesn't involve any access to relcache entries.
2829  */
2830  if (RelationIsMapped(relation))
2831  RelationInitPhysicalAddr(relation);
2832 
2833  /*
2834  * Add this entry to list of stuff to rebuild in second pass.
2835  * pg_class goes to the front of rebuildFirstList while
2836  * pg_class_oid_index goes to the back of rebuildFirstList, so
2837  * they are done first and second respectively. Other nailed
2838  * relations go to the front of rebuildList, so they'll be done
2839  * next in no particular order; and everything else goes to the
2840  * back of rebuildList.
2841  */
2842  if (RelationGetRelid(relation) == RelationRelationId)
2843  rebuildFirstList = lcons(relation, rebuildFirstList);
2844  else if (RelationGetRelid(relation) == ClassOidIndexId)
2845  rebuildFirstList = lappend(rebuildFirstList, relation);
2846  else if (relation->rd_isnailed)
2847  rebuildList = lcons(relation, rebuildList);
2848  else
2849  rebuildList = lappend(rebuildList, relation);
2850  }
2851  }
2852 
2853  /*
2854  * Now zap any remaining smgr cache entries. This must happen before we
2855  * start to rebuild entries, since that may involve catalog fetches which
2856  * will re-open catalog files.
2857  */
2858  smgrcloseall();
2859 
2860  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2861  foreach(l, rebuildFirstList)
2862  {
2863  relation = (Relation) lfirst(l);
2864  RelationClearRelation(relation, true);
2865  }
2866  list_free(rebuildFirstList);
2867  foreach(l, rebuildList)
2868  {
2869  relation = (Relation) lfirst(l);
2870  RelationClearRelation(relation, true);
2871  }
2872  list_free(rebuildList);
2873 }
#define NIL
Definition: pg_list.h:65
static long relcacheInvalsReceived
Definition: relcache.c:155
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2399
bool rd_isnailed
Definition: rel.h:60
Relation reldesc
Definition: relcache.c:132
#define RelationCloseSmgr(relation)
Definition: rel.h:485
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
static HTAB * RelationIdCache
Definition: relcache.c:135
void smgrcloseall(void)
Definition: smgr.c:286
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1271
#define ClassOidIndexId
Definition: indexing.h:114
List * lappend(List *list, void *datum)
Definition: list.c:321
#define RelationIsMapped(relation)
Definition: rel.h:465
SubTransactionId rd_createSubid
Definition: rel.h:79
List * lcons(void *datum, List *list)
Definition: list.c:453
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:513
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:400
void list_free(List *list)
Definition: list.c:1373
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:416

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2735 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2736 {
2737  Relation relation;
2738 
2739  RelationIdCacheLookup(relationId, relation);
2740 
2741  if (PointerIsValid(relation))
2742  {
2744  RelationFlushRelation(relation);
2745  }
2746 }
static long relcacheInvalsReceived
Definition: relcache.c:155
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:214
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2667
#define PointerIsValid(pointer)
Definition: c.h:626

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2089 of file relcache.c.

References InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationDecrementReferenceCount(), and RelationHasReferenceCountZero.

Referenced by index_close(), relation_close(), ReorderBufferCommit(), ReorderBufferToastReplace(), and ResourceOwnerReleaseInternal().

2090 {
2091  /* Note: no locking manipulations needed */
2093 
2094 #ifdef RELCACHE_FORCE_RELEASE
2095  if (RelationHasReferenceCountZero(relation) &&
2096  relation->rd_createSubid == InvalidSubTransactionId &&
2098  RelationClearRelation(relation, false);
2099 #endif
2100 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2399
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2069
SubTransactionId rd_createSubid
Definition: rel.h:79
#define InvalidSubTransactionId
Definition: c.h:513
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:400

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 2882 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

2883 {
2884  Relation relation;
2885 
2886  RelationIdCacheLookup(relationId, relation);
2887 
2888  if (!PointerIsValid(relation))
2889  return; /* not in cache, nothing to do */
2890 
2891  RelationCloseSmgr(relation);
2892 }
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:214
#define RelationCloseSmgr(relation)
Definition: rel.h:485
#define PointerIsValid(pointer)
Definition: c.h:626

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2703 of file relcache.c.

References elog, ERROR, PointerIsValid, RelationClearRelation(), RelationHasReferenceCountZero, and RelationIdCacheLookup.

Referenced by heap_drop_with_catalog(), and index_drop().

2704 {
2705  Relation relation;
2706 
2707  RelationIdCacheLookup(rid, relation);
2708 
2709  if (!PointerIsValid(relation))
2710  return; /* not in cache, nothing to do */
2711 
2712  if (!RelationHasReferenceCountZero(relation))
2713  elog(ERROR, "relation %u is still open", rid);
2714 
2715  /* Unconditionally destroy the relcache entry */
2716  RelationClearRelation(relation, false);
2717 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2399
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:214
#define ERROR
Definition: elog.h:43
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:400
#define elog(elevel,...)
Definition: elog.h:226
#define PointerIsValid(pointer)
Definition: c.h:626

◆ RelationGetExclusionInfo()

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

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

4969 {
4970  int indnkeyatts;
4971  Oid *ops;
4972  Oid *funcs;
4973  uint16 *strats;
4974  Relation conrel;
4975  SysScanDesc conscan;
4976  ScanKeyData skey[1];
4977  HeapTuple htup;
4978  bool found;
4979  MemoryContext oldcxt;
4980  int i;
4981 
4982  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
4983 
4984  /* Allocate result space in caller context */
4985  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
4986  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
4987  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
4988 
4989  /* Quick exit if we have the data cached already */
4990  if (indexRelation->rd_exclstrats != NULL)
4991  {
4992  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
4993  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
4994  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
4995  return;
4996  }
4997 
4998  /*
4999  * Search pg_constraint for the constraint associated with the index. To
5000  * make this not too painfully slow, we use the index on conrelid; that
5001  * will hold the parent relation's OID not the index's own OID.
5002  *
5003  * Note: if we wanted to rely on the constraint name matching the index's
5004  * name, we could just do a direct lookup using pg_constraint's unique
5005  * index. For the moment it doesn't seem worth requiring that.
5006  */
5007  ScanKeyInit(&skey[0],
5008  Anum_pg_constraint_conrelid,
5009  BTEqualStrategyNumber, F_OIDEQ,
5010  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5011 
5012  conrel = table_open(ConstraintRelationId, AccessShareLock);
5013  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5014  NULL, 1, skey);
5015  found = false;
5016 
5017  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5018  {
5020  Datum val;
5021  bool isnull;
5022  ArrayType *arr;
5023  int nelem;
5024 
5025  /* We want the exclusion constraint owning the index */
5026  if (conform->contype != CONSTRAINT_EXCLUSION ||
5027  conform->conindid != RelationGetRelid(indexRelation))
5028  continue;
5029 
5030  /* There should be only one */
5031  if (found)
5032  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5033  RelationGetRelationName(indexRelation));
5034  found = true;
5035 
5036  /* Extract the operator OIDS from conexclop */
5037  val = fastgetattr(htup,
5038  Anum_pg_constraint_conexclop,
5039  conrel->rd_att, &isnull);
5040  if (isnull)
5041  elog(ERROR, "null conexclop for rel %s",
5042  RelationGetRelationName(indexRelation));
5043 
5044  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5045  nelem = ARR_DIMS(arr)[0];
5046  if (ARR_NDIM(arr) != 1 ||
5047  nelem != indnkeyatts ||
5048  ARR_HASNULL(arr) ||
5049  ARR_ELEMTYPE(arr) != OIDOID)
5050  elog(ERROR, "conexclop is not a 1-D Oid array");
5051 
5052  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5053  }
5054 
5055  systable_endscan(conscan);
5056  table_close(conrel, AccessShareLock);
5057 
5058  if (!found)
5059  elog(ERROR, "exclusion constraint record missing for rel %s",
5060  RelationGetRelationName(indexRelation));
5061 
5062  /* We need the func OIDs and strategy numbers too */
5063  for (i = 0; i < indnkeyatts; i++)
5064  {
5065  funcs[i] = get_opcode(ops[i]);
5066  strats[i] = get_op_opfamily_strategy(ops[i],
5067  indexRelation->rd_opfamily[i]);
5068  /* shouldn't fail, since it was checked at index creation */
5069  if (strats[i] == InvalidStrategy)
5070  elog(ERROR, "could not find strategy for operator %u in family %u",
5071  ops[i], indexRelation->rd_opfamily[i]);
5072  }
5073 
5074  /* Save a copy of the results in the relcache entry. */
5075  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5076  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5077  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5078  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5079  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5080  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5081  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5082  MemoryContextSwitchTo(oldcxt);
5083 }
#define InvalidStrategy
Definition: stratnum.h:24
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:167
#define AccessShareLock
Definition: lockdefs.h:36
Oid * rd_exclprocs
Definition: rel.h:166
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:352
Form_pg_index rd_index
Definition: rel.h:143
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
unsigned short uint16
Definition: c.h:357
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define ARR_HASNULL(a)
Definition: array.h:279
Oid * rd_opfamily
Definition: rel.h:158
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:435
Oid * rd_exclops
Definition: rel.h:165
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ARR_NDIM(a)
Definition: array.h:278
#define ConstraintRelidTypidNameIndexId
Definition: indexing.h:128
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:80
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
MemoryContext rd_indexcxt
Definition: rel.h:155
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:280
#define RelationGetRelid(relation)
Definition: rel.h:416
long val
Definition: informix.c:684
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4239 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(), ATExecDetachPartition(), CloneFkReferencing(), and get_relation_foreign_keys().

4240 {
4241  List *result;
4242  Relation conrel;
4243  SysScanDesc conscan;
4244  ScanKeyData skey;
4245  HeapTuple htup;
4246  List *oldlist;
4247  MemoryContext oldcxt;
4248 
4249  /* Quick exit if we already computed the list. */
4250  if (relation->rd_fkeyvalid)
4251  return relation->rd_fkeylist;
4252 
4253  /* Fast path: non-partitioned tables without triggers can't have FKs */
4254  if (!relation->rd_rel->relhastriggers &&
4255  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4256  return NIL;
4257 
4258  /*
4259  * We build the list we intend to return (in the caller's context) while
4260  * doing the scan. After successfully completing the scan, we copy that
4261  * list into the relcache entry. This avoids cache-context memory leakage
4262  * if we get some sort of error partway through.
4263  */
4264  result = NIL;
4265 
4266  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4267  ScanKeyInit(&skey,
4268  Anum_pg_constraint_conrelid,
4269  BTEqualStrategyNumber, F_OIDEQ,
4270  ObjectIdGetDatum(RelationGetRelid(relation)));
4271 
4272  conrel = table_open(ConstraintRelationId, AccessShareLock);
4273  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4274  NULL, 1, &skey);
4275 
4276  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4277  {
4278  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4279  ForeignKeyCacheInfo *info;
4280 
4281  /* consider only foreign keys */
4282  if (constraint->contype != CONSTRAINT_FOREIGN)
4283  continue;
4284 
4285  info = makeNode(ForeignKeyCacheInfo);
4286  info->conoid = constraint->oid;
4287  info->conrelid = constraint->conrelid;
4288  info->confrelid = constraint->confrelid;
4289 
4290  DeconstructFkConstraintRow(htup, &info->nkeys,
4291  info->conkey,
4292  info->confkey,
4293  info->conpfeqop,
4294  NULL, NULL);
4295 
4296  /* Add FK's node to the result list */
4297  result = lappend(result, info);
4298  }
4299 
4300  systable_endscan(conscan);
4301  table_close(conrel, AccessShareLock);
4302 
4303  /* Now save a copy of the completed list in the relcache entry. */
4305  oldlist = relation->rd_fkeylist;
4306  relation->rd_fkeylist = copyObject(result);
4307  relation->rd_fkeyvalid = true;
4308  MemoryContextSwitchTo(oldcxt);
4309 
4310  /* Don't leak the old list, if there is one */
4311  list_free_deep(oldlist);
4312 
4313  return result;
4314 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
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:230
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * rd_fkeylist
Definition: rel.h:94
Form_pg_class rd_rel
Definition: rel.h:83
void list_free_deep(List *list)
Definition: list.c:1387
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
List * lappend(List *list, void *datum)
Definition: list.c:321
#define makeNode(_type_)
Definition: nodes.h:573
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:232
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ConstraintRelidTypidNameIndexId
Definition: indexing.h:128
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:231
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define copyObject(obj)
Definition: nodes.h:641
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
bool rd_fkeyvalid
Definition: rel.h:95
#define RelationGetRelid(relation)
Definition: rel.h:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 4727 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(), relhasindex, stringToNode(), and TextDatumGetCString.

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

4728 {
4729  Bitmapset *indexattrs; /* indexed columns */
4730  Bitmapset *uindexattrs; /* columns in unique indexes */
4731  Bitmapset *pkindexattrs; /* columns in the primary index */
4732  Bitmapset *idindexattrs; /* columns in the replica identity */
4733  List *indexoidlist;
4734  List *newindexoidlist;
4735  Oid relpkindex;
4736  Oid relreplindex;
4737  ListCell *l;
4738  MemoryContext oldcxt;
4739 
4740  /* Quick exit if we already computed the result. */
4741  if (relation->rd_indexattr != NULL)
4742  {
4743  switch (attrKind)
4744  {
4745  case INDEX_ATTR_BITMAP_ALL:
4746  return bms_copy(relation->rd_indexattr);
4747  case INDEX_ATTR_BITMAP_KEY:
4748  return bms_copy(relation->rd_keyattr);
4750  return bms_copy(relation->rd_pkattr);
4752  return bms_copy(relation->rd_idattr);
4753  default:
4754  elog(ERROR, "unknown attrKind %u", attrKind);
4755  }
4756  }
4757 
4758  /* Fast path if definitely no indexes */
4759  if (!RelationGetForm(relation)->relhasindex)
4760  return NULL;
4761 
4762  /*
4763  * Get cached list of index OIDs. If we have to start over, we do so here.
4764  */
4765 restart:
4766  indexoidlist = RelationGetIndexList(relation);
4767 
4768  /* Fall out if no indexes (but relhasindex was set) */
4769  if (indexoidlist == NIL)
4770  return NULL;
4771 
4772  /*
4773  * Copy the rd_pkindex and rd_replidindex values computed by
4774  * RelationGetIndexList before proceeding. This is needed because a
4775  * relcache flush could occur inside index_open below, resetting the
4776  * fields managed by RelationGetIndexList. We need to do the work with
4777  * stable values of these fields.
4778  */
4779  relpkindex = relation->rd_pkindex;
4780  relreplindex = relation->rd_replidindex;
4781 
4782  /*
4783  * For each index, add referenced attributes to indexattrs.
4784  *
4785  * Note: we consider all indexes returned by RelationGetIndexList, even if
4786  * they are not indisready or indisvalid. This is important because an
4787  * index for which CREATE INDEX CONCURRENTLY has just started must be
4788  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
4789  * CONCURRENTLY is far enough along that we should ignore the index, it
4790  * won't be returned at all by RelationGetIndexList.
4791  */
4792  indexattrs = NULL;
4793  uindexattrs = NULL;
4794  pkindexattrs = NULL;
4795  idindexattrs = NULL;
4796  foreach(l, indexoidlist)
4797  {
4798  Oid indexOid = lfirst_oid(l);
4799  Relation indexDesc;
4800  Datum datum;
4801  bool isnull;
4802  Node *indexExpressions;
4803  Node *indexPredicate;
4804  int i;
4805  bool isKey; /* candidate key */
4806  bool isPK; /* primary key */
4807  bool isIDKey; /* replica identity index */
4808 
4809  indexDesc = index_open(indexOid, AccessShareLock);
4810 
4811  /*
4812  * Extract index expressions and index predicate. Note: Don't use
4813  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
4814  * those might run constant expressions evaluation, which needs a
4815  * snapshot, which we might not have here. (Also, it's probably more
4816  * sound to collect the bitmaps before any transformations that might
4817  * eliminate columns, but the practical impact of this is limited.)
4818  */
4819 
4820  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
4821  GetPgIndexDescriptor(), &isnull);
4822  if (!isnull)
4823  indexExpressions = stringToNode(TextDatumGetCString(datum));
4824  else
4825  indexExpressions = NULL;
4826 
4827  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
4828  GetPgIndexDescriptor(), &isnull);
4829  if (!isnull)
4830  indexPredicate = stringToNode(TextDatumGetCString(datum));
4831  else
4832  indexPredicate = NULL;
4833 
4834  /* Can this index be referenced by a foreign key? */
4835  isKey = indexDesc->rd_index->indisunique &&
4836  indexExpressions == NULL &&
4837  indexPredicate == NULL;
4838 
4839  /* Is this a primary key? */
4840  isPK = (indexOid == relpkindex);
4841 
4842  /* Is this index the configured (or default) replica identity? */
4843  isIDKey = (indexOid == relreplindex);
4844 
4845  /* Collect simple attribute references */
4846  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
4847  {
4848  int attrnum = indexDesc->rd_index->indkey.values[i];
4849 
4850  /*
4851  * Since we have covering indexes with non-key columns, we must
4852  * handle them accurately here. non-key columns must be added into
4853  * indexattrs, since they are in index, and HOT-update shouldn't
4854  * miss them. Obviously, non-key columns couldn't be referenced by
4855  * foreign key or identity key. Hence we do not include them into
4856  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
4857  */
4858  if (attrnum != 0)
4859  {
4860  indexattrs = bms_add_member(indexattrs,
4862 
4863  if (isKey && i < indexDesc->rd_index->indnkeyatts)
4864  uindexattrs = bms_add_member(uindexattrs,
4866 
4867  if (isPK && i < indexDesc->rd_index->indnkeyatts)
4868  pkindexattrs = bms_add_member(pkindexattrs,
4870 
4871  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
4872  idindexattrs = bms_add_member(idindexattrs,
4874  }
4875  }
4876 
4877  /* Collect all attributes used in expressions, too */
4878  pull_varattnos(indexExpressions, 1, &indexattrs);
4879 
4880  /* Collect all attributes in the index predicate, too */
4881  pull_varattnos(indexPredicate, 1, &indexattrs);
4882 
4883  index_close(indexDesc, AccessShareLock);
4884  }
4885 
4886  /*
4887  * During one of the index_opens in the above loop, we might have received
4888  * a relcache flush event on this relcache entry, which might have been
4889  * signaling a change in the rel's index list. If so, we'd better start
4890  * over to ensure we deliver up-to-date attribute bitmaps.
4891  */
4892  newindexoidlist = RelationGetIndexList(relation);
4893  if (equal(indexoidlist, newindexoidlist) &&
4894  relpkindex == relation->rd_pkindex &&
4895  relreplindex == relation->rd_replidindex)
4896  {
4897  /* Still the same index set, so proceed */
4898  list_free(newindexoidlist);
4899  list_free(indexoidlist);
4900  }
4901  else
4902  {
4903  /* Gotta do it over ... might as well not leak memory */
4904  list_free(newindexoidlist);
4905  list_free(indexoidlist);
4906  bms_free(uindexattrs);
4907  bms_free(pkindexattrs);
4908  bms_free(idindexattrs);
4909  bms_free(indexattrs);
4910 
4911  goto restart;
4912  }
4913 
4914  /* Don't leak the old values of these bitmaps, if any */
4915  bms_free(relation->rd_indexattr);
4916  relation->rd_indexattr = NULL;
4917  bms_free(relation->rd_keyattr);
4918  relation->rd_keyattr = NULL;
4919  bms_free(relation->rd_pkattr);
4920  relation->rd_pkattr = NULL;
4921  bms_free(relation->rd_idattr);
4922  relation->rd_idattr = NULL;
4923 
4924  /*
4925  * Now save copies of the bitmaps in the relcache entry. We intentionally
4926  * set rd_indexattr last, because that's the one that signals validity of
4927  * the values; if we run out of memory before making that copy, we won't
4928  * leave the relcache entry looking like the other ones are valid but
4929  * empty.
4930  */
4932  relation->rd_keyattr = bms_copy(uindexattrs);
4933  relation->rd_pkattr = bms_copy(pkindexattrs);
4934  relation->rd_idattr = bms_copy(idindexattrs);
4935  relation->rd_indexattr = bms_copy(indexattrs);
4936  MemoryContextSwitchTo(oldcxt);
4937 
4938  /* We return our original working copy for caller to play with */
4939  switch (attrKind)
4940  {
4941  case INDEX_ATTR_BITMAP_ALL:
4942  return indexattrs;
4943  case INDEX_ATTR_BITMAP_KEY:
4944  return uindexattrs;
4946  return pkindexattrs;
4948  return idindexattrs;
4949  default:
4950  elog(ERROR, "unknown attrKind %u", attrKind);
4951  return NULL;
4952  }
4953 }
#define NIL
Definition: pg_list.h:65
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Bitmapset * rd_keyattr
Definition: rel.h:115
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3008
Oid rd_replidindex
Definition: rel.h:108
#define RelationGetForm(relation)
Definition: rel.h:410
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:525
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:219
struct HeapTupleData * rd_indextuple
Definition: rel.h:145
Form_pg_index rd_index
Definition: rel.h:143
#define ERROR
Definition: elog.h:43
Oid rd_pkindex
Definition: rel.h:107
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4059
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
Bitmapset * rd_idattr
Definition: rel.h:117
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
bool relhasindex
Definition: pg_class.h:72
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
Bitmapset * rd_pkattr
Definition: rel.h:116
void list_free(List *list)
Definition: list.c:1373
#define elog(elevel,...)
Definition: elog.h:226
int i
Definition: pg_list.h:50
Bitmapset * rd_indexattr
Definition: rel.h:114
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
#define lfirst_oid(lc)
Definition: pg_list.h:192
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4582 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(), infer_arbiter_indexes(), plan_create_index_workers(), and transformIndexConstraint().

4583 {
4584  List *result;
4585  Datum exprsDatum;
4586  bool isnull;
4587  char *exprsString;
4588  MemoryContext oldcxt;
4589 
4590  /* Quick exit if we already computed the result. */
4591  if (relation->rd_indexprs)
4592  return copyObject(relation->rd_indexprs);
4593 
4594  /* Quick exit if there is nothing to do. */
4595  if (relation->rd_indextuple == NULL ||
4596  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4597  return NIL;
4598 
4599  /*
4600  * We build the tree we intend to return in the caller's context. After
4601  * successfully completing the work, we copy it into the relcache entry.
4602  * This avoids problems if we get some sort of error partway through.
4603  */
4604  exprsDatum = heap_getattr(relation->rd_indextuple,
4605  Anum_pg_index_indexprs,
4607  &isnull);
4608  Assert(!isnull);
4609  exprsString = TextDatumGetCString(exprsDatum);
4610  result = (List *) stringToNode(exprsString);
4611  pfree(exprsString);
4612 
4613  /*
4614  * Run the expressions through eval_const_expressions. This is not just an
4615  * optimization, but is necessary, because the planner will be comparing
4616  * them to similarly-processed qual clauses, and may fail to detect valid
4617  * matches without this. We must not use canonicalize_qual, however,
4618  * since these aren't qual expressions.
4619  */
4620  result = (List *) eval_const_expressions(NULL, (Node *) result);
4621 
4622  /* May as well fix opfuncids too */
4623  fix_opfuncids((Node *) result);
4624 
4625  /* Now save a copy of the completed tree in the relcache entry. */
4626  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4627  relation->rd_indexprs = copyObject(result);
4628  MemoryContextSwitchTo(oldcxt);
4629 
4630  return result;
4631 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1588
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * rd_indexprs
Definition: rel.h:163
Definition: nodes.h:525
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2253
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
struct HeapTupleData * rd_indextuple
Definition: rel.h:145
void pfree(void *pointer)
Definition: mcxt.c:1031
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4059
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:732
MemoryContext rd_indexcxt
Definition: rel.h:155
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4348 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(), ATExecDetachPartition(), ATExecDropNotNull(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), transformTableLikeClause(), triggered_change_notification(), and vac_open_indexes().

4349 {
4350  Relation indrel;
4351  SysScanDesc indscan;
4352  ScanKeyData skey;
4353  HeapTuple htup;
4354  List *result;
4355  List *oldlist;
4356  char replident = relation->rd_rel->relreplident;
4357  Oid pkeyIndex = InvalidOid;
4358  Oid candidateIndex = InvalidOid;
4359  MemoryContext oldcxt;
4360 
4361  /* Quick exit if we already computed the list. */
4362  if (relation->rd_indexvalid)
4363  return list_copy(relation->rd_indexlist);
4364 
4365  /*
4366  * We build the list we intend to return (in the caller's context) while
4367  * doing the scan. After successfully completing the scan, we copy that
4368  * list into the relcache entry. This avoids cache-context memory leakage
4369  * if we get some sort of error partway through.
4370  */
4371  result = NIL;
4372 
4373  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4374  ScanKeyInit(&skey,
4375  Anum_pg_index_indrelid,
4376  BTEqualStrategyNumber, F_OIDEQ,
4377  ObjectIdGetDatum(RelationGetRelid(relation)));
4378 
4379  indrel = table_open(IndexRelationId, AccessShareLock);
4380  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4381  NULL, 1, &skey);
4382 
4383  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4384  {
4386 
4387  /*
4388  * Ignore any indexes that are currently being dropped. This will
4389  * prevent them from being searched, inserted into, or considered in
4390  * HOT-safety decisions. It's unsafe to touch such an index at all
4391  * since its catalog entries could disappear at any instant.
4392  */
4393  if (!index->indislive)
4394  continue;
4395 
4396  /* add index's OID to result list */
4397  result = lappend_oid(result, index->indexrelid);
4398 
4399  /*
4400  * Invalid, non-unique, non-immediate or predicate indexes aren't
4401  * interesting for either oid indexes or replication identity indexes,
4402  * so don't check them.
4403  */
4404  if (!index->indisvalid || !index->indisunique ||
4405  !index->indimmediate ||
4406  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4407  continue;
4408 
4409  /* remember primary key index if any */
4410  if (index->indisprimary)
4411  pkeyIndex = index->indexrelid;
4412 
4413  /* remember explicitly chosen replica index */
4414  if (index->indisreplident)
4415  candidateIndex = index->indexrelid;
4416  }
4417 
4418  systable_endscan(indscan);
4419 
4420  table_close(indrel, AccessShareLock);
4421 
4422  /* Sort the result list into OID order, per API spec. */
4423  list_sort(result, list_oid_cmp);
4424 
4425  /* Now save a copy of the completed list in the relcache entry. */
4427  oldlist = relation->rd_indexlist;
4428  relation->rd_indexlist = list_copy(result);
4429  relation->rd_pkindex = pkeyIndex;
4430  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4431  relation->rd_replidindex = pkeyIndex;
4432  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4433  relation->rd_replidindex = candidateIndex;
4434  else
4435  relation->rd_replidindex = InvalidOid;
4436  relation->rd_indexvalid = true;
4437  MemoryContextSwitchTo(oldcxt);
4438 
4439  /* Don't leak the old list, if there is one */
4440  list_free(oldlist);
4441 
4442  return result;
4443 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid rd_replidindex
Definition: rel.h:108
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_copy(const List *oldlist)
Definition: list.c:1400
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:638
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
Definition: type.h:89
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1495
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
Oid rd_pkindex
Definition: rel.h:107
List * rd_indexlist
Definition: rel.h:106
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
bool rd_indexvalid
Definition: rel.h:62
#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:1478
void list_free(List *list)
Definition: list.c:1373
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:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define IndexIndrelidIndexId
Definition: indexing.h:166
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

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

4645 {
4646  List *result;
4647  Datum predDatum;
4648  bool isnull;
4649  char *predString;
4650  MemoryContext oldcxt;
4651 
4652  /* Quick exit if we already computed the result. */
4653  if (relation->rd_indpred)
4654  return copyObject(relation->rd_indpred);
4655 
4656  /* Quick exit if there is nothing to do. */
4657  if (relation->rd_indextuple == NULL ||
4658  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
4659  return NIL;
4660 
4661  /*
4662  * We build the tree we intend to return in the caller's context. After
4663  * successfully completing the work, we copy it into the relcache entry.
4664  * This avoids problems if we get some sort of error partway through.
4665  */
4666  predDatum = heap_getattr(relation->rd_indextuple,
4667  Anum_pg_index_indpred,
4669  &isnull);
4670  Assert(!isnull);
4671  predString = TextDatumGetCString(predDatum);
4672  result = (List *) stringToNode(predString);
4673  pfree(predString);
4674 
4675  /*
4676  * Run the expression through const-simplification and canonicalization.
4677  * This is not just an optimization, but is necessary, because the planner
4678  * will be comparing it to similarly-processed qual clauses, and may fail
4679  * to detect valid matches without this. This must match the processing
4680  * done to qual clauses in preprocess_expression()! (We can skip the
4681  * stuff involving subqueries, however, since we don't allow any in index
4682  * predicates.)
4683  */
4684  result = (List *) eval_const_expressions(NULL, (Node *) result);
4685 
4686  result = (List *) canonicalize_qual((Expr *) result, false);
4687 
4688  /* Also convert to implicit-AND format */
4689  result = make_ands_implicit((Expr *) result);
4690 
4691  /* May as well fix opfuncids too */
4692  fix_opfuncids((Node *) result);
4693 
4694  /* Now save a copy of the completed tree in the relcache entry. */
4695  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4696  relation->rd_indpred = copyObject(result);
4697  MemoryContextSwitchTo(oldcxt);
4698 
4699  return result;
4700 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1588
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:525
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2253
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
struct HeapTupleData * rd_indextuple
Definition: rel.h:145
void pfree(void *pointer)
Definition: mcxt.c:1031
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4059
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:292
List * rd_indpred
Definition: rel.h:164
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:716
#define Assert(condition)
Definition: c.h:732
MemoryContext rd_indexcxt
Definition: rel.h:155
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4536 of file relcache.c.

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

Referenced by GetRelationIdentityOrPK().

4537 {
4538  List *ilist;
4539 
4540  if (!relation->rd_indexvalid)
4541  {
4542  /* RelationGetIndexList does the heavy lifting. */
4543  ilist = RelationGetIndexList(relation);
4544  list_free(ilist);
4545  Assert(relation->rd_indexvalid);
4546  }
4547 
4548  return relation->rd_pkindex;
4549 }
Oid rd_pkindex
Definition: rel.h:107
bool rd_indexvalid
Definition: rel.h:62
#define Assert(condition)
Definition: c.h:732
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
void list_free(List *list)
Definition: list.c:1373
Definition: pg_list.h:50

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

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

4558 {
4559  List *ilist;
4560 
4561  if (!relation->rd_indexvalid)
4562  {
4563  /* RelationGetIndexList does the heavy lifting. */
4564  ilist = RelationGetIndexList(relation);
4565  list_free(ilist);
4566  Assert(relation->rd_indexvalid);
4567  }
4568 
4569  return relation->rd_replidindex;
4570 }
Oid rd_replidindex
Definition: rel.h:108
bool rd_indexvalid
Definition: rel.h:62
#define Assert(condition)
Definition: c.h:732
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
void list_free(List *list)
Definition: list.c:1373
Definition: pg_list.h:50

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

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

4468 {
4469  Relation indrel;
4470  SysScanDesc indscan;
4471  ScanKeyData skey;
4472  HeapTuple htup;
4473  List *result;
4474  List *oldlist;
4475  MemoryContext oldcxt;
4476 
4477  /* Quick exit if we already computed the list. */
4478  if (relation->rd_statvalid != 0)
4479  return list_copy(relation->rd_statlist);
4480 
4481  /*
4482  * We build the list we intend to return (in the caller's context) while
4483  * doing the scan. After successfully completing the scan, we copy that
4484  * list into the relcache entry. This avoids cache-context memory leakage
4485  * if we get some sort of error partway through.
4486  */
4487  result = NIL;
4488 
4489  /*
4490  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4491  * rel.
4492  */
4493  ScanKeyInit(&skey,
4494  Anum_pg_statistic_ext_stxrelid,
4495  BTEqualStrategyNumber, F_OIDEQ,
4496  ObjectIdGetDatum(RelationGetRelid(relation)));
4497 
4498  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4499  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4500  NULL, 1, &skey);
4501 
4502  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4503  {
4504  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4505 
4506  result = lappend_oid(result, oid);
4507  }
4508 
4509  systable_endscan(indscan);
4510 
4511  table_close(indrel, AccessShareLock);
4512 
4513  /* Sort the result list into OID order, per API spec. */
4514  list_sort(result, list_oid_cmp);
4515 
4516  /* Now save a copy of the completed list in the relcache entry. */
4518  oldlist = relation->rd_statlist;
4519  relation->rd_statlist = list_copy(result);
4520 
4521  relation->rd_statvalid = true;
4522  MemoryContextSwitchTo(oldcxt);
4523 
4524  /* Don't leak the old list, if there is one */
4525  list_free(oldlist);
4526 
4527  return result;
4528 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_copy(const List *oldlist)
Definition: list.c:1400
unsigned int Oid
Definition: postgres_ext.h:31
#define StatisticExtRelidIndexId
Definition: indexing.h:238
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1495
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool rd_statvalid
Definition: rel.h:64
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1478
void list_free(List *list)
Definition: list.c:1373
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
List * rd_statlist
Definition: rel.h:111
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31
FormData_pg_statistic_ext * Form_pg_statistic_ext
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 1990 of file relcache.c.

References Assert, criticalRelcachesBuilt, IsTransactionState(), RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_rel, RelationBuildDesc(), RelationClearRelation(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, and RelationReloadIndexInfo().

Referenced by relation_open(), ReorderBufferCommit(), ReorderBufferToastReplace(), and try_relation_open().

1991 {
1992  Relation rd;
1993 
1994  /* Make sure we're in an xact, even if this ends up being a cache hit */
1996 
1997  /*
1998  * first try to find reldesc in the cache
1999  */
2000  RelationIdCacheLookup(relationId, rd);
2001 
2002  if (RelationIsValid(rd))
2003  {
2005  /* revalidate cache entry if necessary */
2006  if (!rd->rd_isvalid)
2007  {
2008  /*
2009  * Indexes only have a limited number of possible schema changes,
2010  * and we don't want to use the full-blown procedure because it's
2011  * a headache for indexes that reload itself depends on.
2012  */
2013  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2014  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2016  else
2017  RelationClearRelation(rd, true);
2018 
2019  /*
2020  * Normally entries need to be valid here, but before the relcache
2021  * has been initialized, not enough infrastructure exists to
2022  * perform pg_class lookups. The structure of such entries doesn't
2023  * change, but we still want to update the rd_rel entry. So
2024  * rd_isvalid = false is left in place for a later lookup.
2025  */
2026  Assert(rd->rd_isvalid ||
2028  }
2029  return rd;
2030  }
2031 
2032  /*
2033  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2034  * it.
2035  */
2036  rd = RelationBuildDesc(relationId, true);
2037  if (RelationIsValid(rd))
2039  return rd;
2040 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2399
bool rd_isnailed
Definition: rel.h:60
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:214
bool rd_isvalid
Definition: rel.h:61
Form_pg_class rd_rel
Definition: rel.h:83
#define RelationIsValid(relation)
Definition: rel.h:389
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2056
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2130
#define Assert(condition)
Definition: c.h:732
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1025
bool IsTransactionState(void)
Definition: xact.c:356
bool criticalRelcachesBuilt
Definition: relcache.c:141

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 5899 of file relcache.c.

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

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

5900 {
5901  if (relationId == SharedSecLabelRelationId ||
5902  relationId == TriggerRelidNameIndexId ||
5903  relationId == DatabaseNameIndexId ||
5904  relationId == SharedSecLabelObjectIndexId)
5905  {
5906  /*
5907  * If this Assert fails, we don't need the applicable special case
5908  * anymore.
5909  */
5910  Assert(!RelationSupportsSysCache(relationId));
5911  return true;
5912  }
5913  return RelationSupportsSysCache(relationId);
5914 }
#define TriggerRelidNameIndexId
Definition: indexing.h:256
#define Assert(condition)
Definition: c.h:732
#define DatabaseNameIndexId
Definition: indexing.h:144
#define SharedSecLabelObjectIndexId
Definition: indexing.h:323
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1529

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1362 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, RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

1363 {
1364  HeapTuple tuple;
1365  Form_pg_am aform;
1366  Datum indcollDatum;
1367  Datum indclassDatum;
1368  Datum indoptionDatum;
1369  bool isnull;
1370  oidvector *indcoll;
1371  oidvector *indclass;
1372  int2vector *indoption;
1373  MemoryContext indexcxt;
1374  MemoryContext oldcontext;
1375  int indnatts;
1376  int indnkeyatts;
1377  uint16 amsupport;
1378 
1379  /*
1380  * Make a copy of the pg_index entry for the index. Since pg_index
1381  * contains variable-length and possibly-null fields, we have to do this
1382  * honestly rather than just treating it as a Form_pg_index struct.
1383  */
1384  tuple = SearchSysCache1(INDEXRELID,
1385  ObjectIdGetDatum(RelationGetRelid(relation)));
1386  if (!HeapTupleIsValid(tuple))
1387  elog(ERROR, "cache lookup failed for index %u",
1388  RelationGetRelid(relation));
1390  relation->rd_indextuple = heap_copytuple(tuple);
1391  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1392  MemoryContextSwitchTo(oldcontext);
1393  ReleaseSysCache(tuple);
1394 
1395  /*
1396  * Look up the index's access method, save the OID of its handler function
1397  */
1398  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1399  if (!HeapTupleIsValid(tuple))
1400  elog(ERROR, "cache lookup failed for access method %u",
1401  relation->rd_rel->relam);
1402  aform = (Form_pg_am) GETSTRUCT(tuple);
1403  relation->rd_amhandler = aform->amhandler;
1404  ReleaseSysCache(tuple);
1405 
1406  indnatts = RelationGetNumberOfAttributes(relation);
1407  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1408  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1409  RelationGetRelid(relation));
1410  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1411 
1412  /*
1413  * Make the private context to hold index access info. The reason we need
1414  * a context, and not just a couple of pallocs, is so that we won't leak
1415  * any subsidiary info attached to fmgr lookup records.
1416  */
1418  "index info",
1420  relation->rd_indexcxt = indexcxt;
1422  RelationGetRelationName(relation));
1423 
1424  /*
1425  * Now we can fetch the index AM's API struct
1426  */
1427  InitIndexAmRoutine(relation);
1428 
1429  /*
1430  * Allocate arrays to hold data. Opclasses are not used for included
1431  * columns, so allocate them for indnkeyatts only.
1432  */
1433  relation->rd_opfamily = (Oid *)
1434  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1435  relation->rd_opcintype = (Oid *)
1436  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1437 
1438  amsupport = relation->rd_indam->amsupport;
1439  if (amsupport > 0)
1440  {
1441  int nsupport = indnatts * amsupport;
1442 
1443  relation->rd_support = (RegProcedure *)
1444  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1445  relation->rd_supportinfo = (FmgrInfo *)
1446  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1447  }
1448  else
1449  {
1450  relation->rd_support = NULL;
1451  relation->rd_supportinfo = NULL;
1452  }
1453 
1454  relation->rd_indcollation = (Oid *)
1455  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1456 
1457  relation->rd_indoption = (int16 *)
1458  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1459 
1460  /*
1461  * indcollation cannot be referenced directly through the C struct,
1462  * because it comes after the variable-width indkey field. Must extract
1463  * the datum the hard way...
1464  */
1465  indcollDatum = fastgetattr(relation->rd_indextuple,
1466  Anum_pg_index_indcollation,
1468  &isnull);
1469  Assert(!isnull);
1470  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1471  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1472 
1473  /*
1474  * indclass cannot be referenced directly through the C struct, because it
1475  * comes after the variable-width indkey field. Must extract the datum
1476  * the hard way...
1477  */
1478  indclassDatum = fastgetattr(relation->rd_indextuple,
1479  Anum_pg_index_indclass,
1481  &isnull);
1482  Assert(!isnull);
1483  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1484 
1485  /*
1486  * Fill the support procedure OID array, as well as the info about
1487  * opfamilies and opclass input types. (aminfo and supportinfo are left
1488  * as zeroes, and are filled on-the-fly when used)
1489  */
1490  IndexSupportInitialize(indclass, relation->rd_support,
1491  relation->rd_opfamily, relation->rd_opcintype,
1492  amsupport, indnkeyatts);
1493 
1494  /*
1495  * Similarly extract indoption and copy it to the cache entry
1496  */
1497  indoptionDatum = fastgetattr(relation->rd_indextuple,
1498  Anum_pg_index_indoption,
1500  &isnull);
1501  Assert(!isnull);
1502  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1503  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
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:345
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define NIL
Definition: pg_list.h:65
Definition: c.h:588
struct IndexAmRoutine * rd_indam
Definition: rel.h:157
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:173
#define AllocSetContextCreate
Definition: memutils.h:169
int16 * rd_indoption
Definition: rel.h:162
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
Definition: syscache.h:36
struct FmgrInfo * rd_supportinfo
Definition: rel.h:161
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:422
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:201
regproc RegProcedure
Definition: c.h:505
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:167
List * rd_indexprs
Definition: rel.h:163
Oid * rd_exclprocs
Definition: rel.h:166
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1338
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:145
Form_pg_index rd_index
Definition: rel.h:143
unsigned short uint16
Definition: c.h:357
Oid * rd_indcollation
Definition: rel.h:168
Oid rd_amhandler
Definition: rel.h:135
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:96
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4059
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:596
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:428
#define RelationGetRelationName(relation)
Definition: rel.h:450
List * rd_indpred
Definition: rel.h:164
Oid * rd_opfamily
Definition: rel.h:158
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:435
Oid * rd_exclops
Definition: rel.h:165
RegProcedure * rd_support
Definition: rel.h:160
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
Definition: c.h:577
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:585
#define DatumGetPointer(X)
Definition: postgres.h:549
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define elog(elevel,...)
Definition: elog.h:226
MemoryContext rd_indexcxt
Definition: rel.h:155
void * rd_amcache
Definition: rel.h:179
Oid * rd_opcintype
Definition: rel.h:159
#define RelationGetRelid(relation)
Definition: rel.h:416
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ 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 = HEAP_TABLE_AM_HANDLER_OID;
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 = HEAP_TABLE_AM_HANDLER_OID;
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:100
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Definition: syscache.h:36
Form_pg_class rd_rel
Definition: rel.h:83
Oid rd_amhandler
Definition: rel.h:135
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define elog(elevel,...)
Definition: elog.h:226

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence 
)

Definition at line 3418 of file relcache.c.

References Assert, CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), GetCurrentTransactionId(), GetNewRelFileNode(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidMultiXactId, InvalidTransactionId, ObjectIdGetDatum, RelationData::rd_newRelfilenodeSubid, RelationData::rd_node, RelationData::rd_rel, 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().

3419 {
3420  Oid newrelfilenode;
3421  Relation pg_class;
3422  HeapTuple tuple;
3423  Form_pg_class classform;
3424  MultiXactId minmulti = InvalidMultiXactId;
3425  TransactionId freezeXid = InvalidTransactionId;
3426  RelFileNode newrnode;
3427 
3428  /* Allocate a new relfilenode */
3429  newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
3430  persistence);
3431 
3432  /*
3433  * Get a writable copy of the pg_class tuple for the given relation.
3434  */
3435  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3436 
3437  tuple = SearchSysCacheCopy1(RELOID,
3438  ObjectIdGetDatum(RelationGetRelid(relation)));
3439  if (!HeapTupleIsValid(tuple))
3440  elog(ERROR, "could not find tuple for relation %u",
3441  RelationGetRelid(relation));
3442  classform = (Form_pg_class) GETSTRUCT(tuple);
3443 
3444  /*
3445  * Schedule unlinking of the old storage at transaction commit.
3446  */
3447  RelationDropStorage(relation);
3448 
3449  /*
3450  * Create storage for the main fork of the new relfilenode. If it's a
3451  * table-like object, call into the table AM to do so, which'll also
3452  * create the table's init fork if needed.
3453  *
3454  * NOTE: If relevant for the AM, any conflict in relfilenode value will be
3455  * caught here, if GetNewRelFileNode messes up for any reason.
3456  */
3457  newrnode = relation->rd_node;
3458  newrnode.relNode = newrelfilenode;
3459 
3460  switch (relation->rd_rel->relkind)
3461  {
3462  case RELKIND_INDEX:
3463  case RELKIND_SEQUENCE:
3464  {
3465  /* handle these directly, at least for now */
3466  SMgrRelation srel;
3467 
3468  srel = RelationCreateStorage(newrnode, persistence);
3469  smgrclose(srel);
3470  }
3471  break;
3472 
3473  case RELKIND_RELATION:
3474  case RELKIND_TOASTVALUE:
3475  case RELKIND_MATVIEW:
3476  table_relation_set_new_filenode(relation, &newrnode,
3477  persistence,
3478  &freezeXid, &minmulti);
3479  break;
3480 
3481  default:
3482  /* we shouldn't be called for anything else */
3483  elog(ERROR, "relation \"%s\" does not have storage",
3484  RelationGetRelationName(relation));
3485  break;
3486  }
3487 
3488  /*
3489  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3490  * change; instead we have to send the update to the relation mapper.
3491  *
3492  * For mapped indexes, we don't actually change the pg_class entry at all;
3493  * this is essential when reindexing pg_class itself. That leaves us with
3494  * possibly-inaccurate values of relpages etc, but those will be fixed up
3495  * later.
3496  */
3497  if (RelationIsMapped(relation))
3498  {
3499  /* This case is only supported for indexes */
3500  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3501 
3502  /* Since we're not updating pg_class, these had better not change */
3503  Assert(classform->relfrozenxid == freezeXid);
3504  Assert(classform->relminmxid == minmulti);
3505  Assert(classform->relpersistence == persistence);
3506 
3507  /*
3508  * In some code paths it's possible that the tuple update we'd
3509  * otherwise do here is the only thing that would assign an XID for
3510  * the current transaction. However, we must have an XID to delete
3511  * files, so make sure one is assigned.
3512  */
3513  (void) GetCurrentTransactionId();
3514 
3515  /* Do the deed */
3517  newrelfilenode,
3518  relation->rd_rel->relisshared,
3519  false);
3520 
3521  /* Since we're not updating pg_class, must trigger inval manually */
3522  CacheInvalidateRelcache(relation);
3523  }
3524  else
3525  {
3526  /* Normal case, update the pg_class entry */
3527  classform->relfilenode = newrelfilenode;
3528 
3529  /* relpages etc. never change for sequences */
3530  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3531  {
3532  classform->relpages = 0; /* it's empty until further notice */
3533  classform->reltuples = 0;
3534  classform->relallvisible = 0;
3535  }
3536  classform->relfrozenxid = freezeXid;
3537  classform->relminmxid = minmulti;
3538  classform->relpersistence = persistence;
3539 
3540  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3541  }
3542 
3543  heap_freetuple(tuple);
3544 
3545  table_close(pg_class, RowExclusiveLock);
3546 
3547  /*
3548  * Make the pg_class row change or relation map change visible. This will
3549  * cause the relcache entry to get updated, too.
3550  */
3552 
3553  /*
3554  * Mark the rel as having been given a new relfilenode in the current
3555  * (sub) transaction. This is a hint that can be used to optimize later
3556  * operations on the rel in the same transaction.
3557  */
3559 
3560  /* Flag relation as needing eoxact cleanup (to remove the hint) */
3561  EOXactListAdd(relation);
3562 }
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
#define EOXactListAdd(rel)
Definition: relcache.c:172
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
uint32 TransactionId
Definition: c.h:507
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
Form_pg_class rd_rel
Definition: rel.h:83
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:79
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define RelationIsMapped(relation)
Definition: rel.h:465
void RelationDropStorage(Relation rel)
Definition: storage.c:148
void CommandCounterIncrement(void)
Definition: xact.c:1003
#define InvalidMultiXactId
Definition: multixact.h:23
TransactionId MultiXactId
Definition: c.h:517
RelFileNode rd_node
Definition: rel.h:54
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:386
static void table_relation_set_new_filenode(Relation rel, const RelFileNode *newrnode, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1344
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1270
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:416
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

bool criticalSharedRelcachesBuilt