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

typedef struct RelationData* Relation

Definition at line 26 of file relcache.h.

◆ RelationPtr

Definition at line 34 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_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 3076 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().

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

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

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

◆ errtable()

int errtable ( Relation  rel)

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5184 of file relcache.c.

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

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

5185 {
5186  TupleDesc reldesc = RelationGetDescr(rel);
5187  const char *colname;
5188 
5189  /* Use reldesc if it's a user attribute, else consult the catalogs */
5190  if (attnum > 0 && attnum <= reldesc->natts)
5191  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5192  else
5193  colname = get_attname(RelationGetRelid(rel), attnum, false);
5194 
5195  return errtablecolname(rel, colname);
5196 }
#define RelationGetDescr(relation)
Definition: rel.h:449
#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:610
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:423
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5208

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5208 of file relcache.c.

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

Referenced by errtablecol().

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

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

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

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

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

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

5089 {
5090  List *puboids;
5091  ListCell *lc;
5092  MemoryContext oldcxt;
5093  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5094 
5095  /*
5096  * If not publishable, it publishes no actions. (pgoutput_change() will
5097  * ignore it.)
5098  */
5099  if (!is_publishable_relation(relation))
5100  return pubactions;
5101 
5102  if (relation->rd_pubactions)
5103  return memcpy(pubactions, relation->rd_pubactions,
5104  sizeof(PublicationActions));
5105 
5106  /* Fetch the publication membership info. */
5107  puboids = GetRelationPublications(RelationGetRelid(relation));
5108  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5109 
5110  foreach(lc, puboids)
5111  {
5112  Oid pubid = lfirst_oid(lc);
5113  HeapTuple tup;
5114  Form_pg_publication pubform;
5115 
5117 
5118  if (!HeapTupleIsValid(tup))
5119  elog(ERROR, "cache lookup failed for publication %u", pubid);
5120 
5121  pubform = (Form_pg_publication) GETSTRUCT(tup);
5122 
5123  pubactions->pubinsert |= pubform->pubinsert;
5124  pubactions->pubupdate |= pubform->pubupdate;
5125  pubactions->pubdelete |= pubform->pubdelete;
5126  pubactions->pubtruncate |= pubform->pubtruncate;
5127 
5128  ReleaseSysCache(tup);
5129 
5130  /*
5131  * If we know everything is replicated, there is no point to check for
5132  * other publications.
5133  */
5134  if (pubactions->pubinsert && pubactions->pubupdate &&
5135  pubactions->pubdelete && pubactions->pubtruncate)
5136  break;
5137  }
5138 
5139  if (relation->rd_pubactions)
5140  {
5141  pfree(relation->rd_pubactions);
5142  relation->rd_pubactions = NULL;
5143  }
5144 
5145  /* Now save copy of the actions in the relcache entry. */
5147  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5148  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5149  MemoryContextSwitchTo(oldcxt);
5150 
5151  return pubactions;
5152 }
#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:1056
#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:1302
bool is_publishable_relation(Relation rel)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void * palloc0(Size size)
Definition: mcxt.c:980
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:423
#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 3175 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().

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

References LWLockRelease().

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

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

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

5939 {
5940  char localinitfname[MAXPGPATH];
5941  char sharedinitfname[MAXPGPATH];
5942 
5943  if (DatabasePath)
5944  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
5946  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
5948 
5949  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
5950 
5951  /*
5952  * The files might not be there if no backend has been started since the
5953  * last removal. But complain about failures other than ENOENT with
5954  * ERROR. Fortunately, it's not too late to abort the transaction if we
5955  * can't get rid of the would-be-obsolete init file.
5956  */
5957  if (DatabasePath)
5958  unlink_initfile(localinitfname, ERROR);
5959  unlink_initfile(sharedinitfname, ERROR);
5960 }
#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:6035
#define snprintf
Definition: port.h:192

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

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

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3579 of file relcache.c.

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

Referenced by InitPostgres().

3580 {
3581  HASHCTL ctl;
3582 
3583  /*
3584  * make sure cache memory context exists
3585  */
3586  if (!CacheMemoryContext)
3588 
3589  /*
3590  * create hashtable that indexes the relcache
3591  */
3592  MemSet(&ctl, 0, sizeof(ctl));
3593  ctl.keysize = sizeof(Oid);
3594  ctl.entrysize = sizeof(RelIdCacheEnt);
3595  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3596  &ctl, HASH_ELEM | HASH_BLOBS);
3597 
3598  /*
3599  * relation mapper needs to be initialized too
3600  */
3602 }
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:956
static HTAB * RelationIdCache
Definition: relcache.c:134
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:3576
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

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

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

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

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

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

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

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

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

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2734 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2735 {
2736  Relation relation;
2737 
2738  RelationIdCacheLookup(relationId, relation);
2739 
2740  if (PointerIsValid(relation))
2741  {
2743  RelationFlushRelation(relation);
2744  }
2745 }
static long relcacheInvalsReceived
Definition: relcache.c:154
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:213
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2666
#define PointerIsValid(pointer)
Definition: c.h:627

◆ RelationClose()

void RelationClose ( Relation  relation)

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

2089 {
2090  /* Note: no locking manipulations needed */
2092 
2093 #ifdef RELCACHE_FORCE_RELEASE
2094  if (RelationHasReferenceCountZero(relation) &&
2095  relation->rd_createSubid == InvalidSubTransactionId &&
2097  RelationClearRelation(relation, false);
2098 #endif
2099 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2398
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2068
SubTransactionId rd_createSubid
Definition: rel.h:79
#define InvalidSubTransactionId
Definition: c.h:514
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:407

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 2881 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

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

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2702 of file relcache.c.

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

Referenced by heap_drop_with_catalog(), and index_drop().

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

◆ RelationGetExclusionInfo()

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

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

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

4239 {
4240  List *result;
4241  Relation conrel;
4242  SysScanDesc conscan;
4243  ScanKeyData skey;
4244  HeapTuple htup;
4245  List *oldlist;
4246  MemoryContext oldcxt;
4247 
4248  /* Quick exit if we already computed the list. */
4249  if (relation->rd_fkeyvalid)
4250  return relation->rd_fkeylist;
4251 
4252  /* Fast path: non-partitioned tables without triggers can't have FKs */
4253  if (!relation->rd_rel->relhastriggers &&
4254  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4255  return NIL;
4256 
4257  /*
4258  * We build the list we intend to return (in the caller's context) while
4259  * doing the scan. After successfully completing the scan, we copy that
4260  * list into the relcache entry. This avoids cache-context memory leakage
4261  * if we get some sort of error partway through.
4262  */
4263  result = NIL;
4264 
4265  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4266  ScanKeyInit(&skey,
4267  Anum_pg_constraint_conrelid,
4268  BTEqualStrategyNumber, F_OIDEQ,
4269  ObjectIdGetDatum(RelationGetRelid(relation)));
4270 
4271  conrel = table_open(ConstraintRelationId, AccessShareLock);
4272  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4273  NULL, 1, &skey);
4274 
4275  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4276  {
4277  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4278  ForeignKeyCacheInfo *info;
4279 
4280  /* consider only foreign keys */
4281  if (constraint->contype != CONSTRAINT_FOREIGN)
4282  continue;
4283 
4284  info = makeNode(ForeignKeyCacheInfo);
4285  info->conoid = constraint->oid;
4286  info->conrelid = constraint->conrelid;
4287  info->confrelid = constraint->confrelid;
4288 
4289  DeconstructFkConstraintRow(htup, &info->nkeys,
4290  info->conkey,
4291  info->confkey,
4292  info->conpfeqop,
4293  NULL, NULL);
4294 
4295  /* Add FK's node to the result list */
4296  result = lappend(result, info);
4297  }
4298 
4299  systable_endscan(conscan);
4300  table_close(conrel, AccessShareLock);
4301 
4302  /* Now save a copy of the completed list in the relcache entry. */
4304  oldlist = relation->rd_fkeylist;
4305  relation->rd_fkeylist = copyObject(result);
4306  relation->rd_fkeyvalid = true;
4307  MemoryContextSwitchTo(oldcxt);
4308 
4309  /* Don't leak the old list, if there is one */
4310  list_free_deep(oldlist);
4311 
4312  return result;
4313 }
#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:1391
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:322
#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:423
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

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

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

4582 {
4583  List *result;
4584  Datum exprsDatum;
4585  bool isnull;
4586  char *exprsString;
4587  MemoryContext oldcxt;
4588 
4589  /* Quick exit if we already computed the result. */
4590  if (relation->rd_indexprs)
4591  return copyObject(relation->rd_indexprs);
4592 
4593  /* Quick exit if there is nothing to do. */
4594  if (relation->rd_indextuple == NULL ||
4595  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4596  return NIL;
4597 
4598  /*
4599  * We build the tree we intend to return in the caller's context. After
4600  * successfully completing the work, we copy it into the relcache entry.
4601  * This avoids problems if we get some sort of error partway through.
4602  */
4603  exprsDatum = heap_getattr(relation->rd_indextuple,
4604  Anum_pg_index_indexprs,
4606  &isnull);
4607  Assert(!isnull);
4608  exprsString = TextDatumGetCString(exprsDatum);
4609  result = (List *) stringToNode(exprsString);
4610  pfree(exprsString);
4611 
4612  /*
4613  * Run the expressions through eval_const_expressions. This is not just an
4614  * optimization, but is necessary, because the planner will be comparing
4615  * them to similarly-processed qual clauses, and may fail to detect valid
4616  * matches without this. We must not use canonicalize_qual, however,
4617  * since these aren't qual expressions.
4618  */
4619  result = (List *) eval_const_expressions(NULL, (Node *) result);
4620 
4621  /* May as well fix opfuncids too */
4622  fix_opfuncids((Node *) result);
4623 
4624  /* Now save a copy of the completed tree in the relcache entry. */
4625  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4626  relation->rd_indexprs = copyObject(result);
4627  MemoryContextSwitchTo(oldcxt);
4628 
4629  return result;
4630 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1587
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:1056
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4058
#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:733
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 4347 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().

4348 {
4349  Relation indrel;
4350  SysScanDesc indscan;
4351  ScanKeyData skey;
4352  HeapTuple htup;
4353  List *result;
4354  List *oldlist;
4355  char replident = relation->rd_rel->relreplident;
4356  Oid pkeyIndex = InvalidOid;
4357  Oid candidateIndex = InvalidOid;
4358  MemoryContext oldcxt;
4359 
4360  /* Quick exit if we already computed the list. */
4361  if (relation->rd_indexvalid)
4362  return list_copy(relation->rd_indexlist);
4363 
4364  /*
4365  * We build the list we intend to return (in the caller's context) while
4366  * doing the scan. After successfully completing the scan, we copy that
4367  * list into the relcache entry. This avoids cache-context memory leakage
4368  * if we get some sort of error partway through.
4369  */
4370  result = NIL;
4371 
4372  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4373  ScanKeyInit(&skey,
4374  Anum_pg_index_indrelid,
4375  BTEqualStrategyNumber, F_OIDEQ,
4376  ObjectIdGetDatum(RelationGetRelid(relation)));
4377 
4378  indrel = table_open(IndexRelationId, AccessShareLock);
4379  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4380  NULL, 1, &skey);
4381 
4382  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4383  {
4385 
4386  /*
4387  * Ignore any indexes that are currently being dropped. This will
4388  * prevent them from being searched, inserted into, or considered in
4389  * HOT-safety decisions. It's unsafe to touch such an index at all
4390  * since its catalog entries could disappear at any instant.
4391  */
4392  if (!index->indislive)
4393  continue;
4394 
4395  /* add index's OID to result list */
4396  result = lappend_oid(result, index->indexrelid);
4397 
4398  /*
4399  * Invalid, non-unique, non-immediate or predicate indexes aren't
4400  * interesting for either oid indexes or replication identity indexes,
4401  * so don't check them.
4402  */
4403  if (!index->indisvalid || !index->indisunique ||
4404  !index->indimmediate ||
4405  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4406  continue;
4407 
4408  /* remember primary key index if any */
4409  if (index->indisprimary)
4410  pkeyIndex = index->indexrelid;
4411 
4412  /* remember explicitly chosen replica index */
4413  if (index->indisreplident)
4414  candidateIndex = index->indexrelid;
4415  }
4416 
4417  systable_endscan(indscan);
4418 
4419  table_close(indrel, AccessShareLock);
4420 
4421  /* Sort the result list into OID order, per API spec. */
4422  list_sort(result, list_oid_cmp);
4423 
4424  /* Now save a copy of the completed list in the relcache entry. */
4426  oldlist = relation->rd_indexlist;
4427  relation->rd_indexlist = list_copy(result);
4428  relation->rd_pkindex = pkeyIndex;
4429  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4430  relation->rd_replidindex = pkeyIndex;
4431  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4432  relation->rd_replidindex = candidateIndex;
4433  else
4434  relation->rd_replidindex = InvalidOid;
4435  relation->rd_indexvalid = true;
4436  MemoryContextSwitchTo(oldcxt);
4437 
4438  /* Don't leak the old list, if there is one */
4439  list_free(oldlist);
4440 
4441  return result;
4442 }
#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:1404
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:358
#define OidIsValid(objectId)
Definition: c.h:639
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:1499
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:1482
void list_free(List *list)
Definition: list.c:1377
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:423
#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 4643 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().

4644 {
4645  List *result;
4646  Datum predDatum;
4647  bool isnull;
4648  char *predString;
4649  MemoryContext oldcxt;
4650 
4651  /* Quick exit if we already computed the result. */
4652  if (relation->rd_indpred)
4653  return copyObject(relation->rd_indpred);
4654 
4655  /* Quick exit if there is nothing to do. */
4656  if (relation->rd_indextuple == NULL ||
4657  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
4658  return NIL;
4659 
4660  /*
4661  * We build the tree we intend to return in the caller's context. After
4662  * successfully completing the work, we copy it into the relcache entry.
4663  * This avoids problems if we get some sort of error partway through.
4664  */
4665  predDatum = heap_getattr(relation->rd_indextuple,
4666  Anum_pg_index_indpred,
4668  &isnull);
4669  Assert(!isnull);
4670  predString = TextDatumGetCString(predDatum);
4671  result = (List *) stringToNode(predString);
4672  pfree(predString);
4673 
4674  /*
4675  * Run the expression through const-simplification and canonicalization.
4676  * This is not just an optimization, but is necessary, because the planner
4677  * will be comparing it to similarly-processed qual clauses, and may fail
4678  * to detect valid matches without this. This must match the processing
4679  * done to qual clauses in preprocess_expression()! (We can skip the
4680  * stuff involving subqueries, however, since we don't allow any in index
4681  * predicates.)
4682  */
4683  result = (List *) eval_const_expressions(NULL, (Node *) result);
4684 
4685  result = (List *) canonicalize_qual((Expr *) result, false);
4686 
4687  /* Also convert to implicit-AND format */
4688  result = make_ands_implicit((Expr *) result);
4689 
4690  /* May as well fix opfuncids too */
4691  fix_opfuncids((Node *) result);
4692 
4693  /* Now save a copy of the completed tree in the relcache entry. */
4694  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4695  relation->rd_indpred = copyObject(result);
4696  MemoryContextSwitchTo(oldcxt);
4697 
4698  return result;
4699 }
#define NIL
Definition: pg_list.h:65
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1587
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:1056
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4058
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:733
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 4535 of file relcache.c.

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

Referenced by GetRelationIdentityOrPK().

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

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

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

4467 {
4468  Relation indrel;
4469  SysScanDesc indscan;
4470  ScanKeyData skey;
4471  HeapTuple htup;
4472  List *result;
4473  List *oldlist;
4474  MemoryContext oldcxt;
4475 
4476  /* Quick exit if we already computed the list. */
4477  if (relation->rd_statvalid != 0)
4478  return list_copy(relation->rd_statlist);
4479 
4480  /*
4481  * We build the list we intend to return (in the caller's context) while
4482  * doing the scan. After successfully completing the scan, we copy that
4483  * list into the relcache entry. This avoids cache-context memory leakage
4484  * if we get some sort of error partway through.
4485  */
4486  result = NIL;
4487 
4488  /*
4489  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4490  * rel.
4491  */
4492  ScanKeyInit(&skey,
4493  Anum_pg_statistic_ext_stxrelid,
4494  BTEqualStrategyNumber, F_OIDEQ,
4495  ObjectIdGetDatum(RelationGetRelid(relation)));
4496 
4497  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4498  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4499  NULL, 1, &skey);
4500 
4501  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4502  {
4503  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4504 
4505  result = lappend_oid(result, oid);
4506  }
4507 
4508  systable_endscan(indscan);
4509 
4510  table_close(indrel, AccessShareLock);
4511 
4512  /* Sort the result list into OID order, per API spec. */
4513  list_sort(result, list_oid_cmp);
4514 
4515  /* Now save a copy of the completed list in the relcache entry. */
4517  oldlist = relation->rd_statlist;
4518  relation->rd_statlist = list_copy(result);
4519 
4520  relation->rd_statvalid = true;
4521  MemoryContextSwitchTo(oldcxt);
4522 
4523  /* Don't leak the old list, if there is one */
4524  list_free(oldlist);
4525 
4526  return result;
4527 }
#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:1404
unsigned int Oid
Definition: postgres_ext.h:31
#define StatisticExtRelidIndexId
Definition: indexing.h:238
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
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:1499
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:1482
void list_free(List *list)
Definition: list.c:1377
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:423
#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 1989 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().

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

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 5898 of file relcache.c.

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

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

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

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

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

1362 {
1363  HeapTuple tuple;
1364  Form_pg_am aform;
1365  Datum indcollDatum;
1366  Datum indclassDatum;
1367  Datum indoptionDatum;
1368  bool isnull;
1369  oidvector *indcoll;
1370  oidvector *indclass;
1371  int2vector *indoption;
1372  MemoryContext indexcxt;
1373  MemoryContext oldcontext;
1374  int indnatts;
1375  int indnkeyatts;
1376  uint16 amsupport;
1377 
1378  /*
1379  * Make a copy of the pg_index entry for the index. Since pg_index
1380  * contains variable-length and possibly-null fields, we have to do this
1381  * honestly rather than just treating it as a Form_pg_index struct.
1382  */
1383  tuple = SearchSysCache1(INDEXRELID,
1384  ObjectIdGetDatum(RelationGetRelid(relation)));
1385  if (!HeapTupleIsValid(tuple))
1386  elog(ERROR, "cache lookup failed for index %u",
1387  RelationGetRelid(relation));
1389  relation->rd_indextuple = heap_copytuple(tuple);
1390  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1391  MemoryContextSwitchTo(oldcontext);
1392  ReleaseSysCache(tuple);
1393 
1394  /*
1395  * Look up the index's access method, save the OID of its handler function
1396  */
1397  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1398  if (!HeapTupleIsValid(tuple))
1399  elog(ERROR, "cache lookup failed for access method %u",
1400  relation->rd_rel->relam);
1401  aform = (Form_pg_am) GETSTRUCT(tuple);
1402  relation->rd_amhandler = aform->amhandler;
1403  ReleaseSysCache(tuple);
1404 
1405  indnatts = RelationGetNumberOfAttributes(relation);
1406  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1407  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1408  RelationGetRelid(relation));
1409  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1410 
1411  /*
1412  * Make the private context to hold index access info. The reason we need
1413  * a context, and not just a couple of pallocs, is so that we won't leak
1414  * any subsidiary info attached to fmgr lookup records.
1415  */
1417  "index info",
1419  relation->rd_indexcxt = indexcxt;
1421  RelationGetRelationName(relation));
1422 
1423  /*
1424  * Now we can fetch the index AM's API struct
1425  */
1426  InitIndexAmRoutine(relation);
1427 
1428  /*
1429  * Allocate arrays to hold data. Opclasses are not used for included
1430  * columns, so allocate them for indnkeyatts only.
1431  */
1432  relation->rd_opfamily = (Oid *)
1433  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1434  relation->rd_opcintype = (Oid *)
1435  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1436 
1437  amsupport = relation->rd_indam->amsupport;
1438  if (amsupport > 0)
1439  {
1440  int nsupport = indnatts * amsupport;
1441 
1442  relation->rd_support = (RegProcedure *)
1443  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1444  relation->rd_supportinfo = (FmgrInfo *)
1445  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1446  }
1447  else
1448  {
1449  relation->rd_support = NULL;
1450  relation->rd_supportinfo = NULL;
1451  }
1452 
1453  relation->rd_indcollation = (Oid *)
1454  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1455 
1456  relation->rd_indoption = (int16 *)
1457  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1458 
1459  /*
1460  * indcollation cannot be referenced directly through the C struct,
1461  * because it comes after the variable-width indkey field. Must extract
1462  * the datum the hard way...
1463  */
1464  indcollDatum = fastgetattr(relation->rd_indextuple,
1465  Anum_pg_index_indcollation,
1467  &isnull);
1468  Assert(!isnull);
1469  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1470  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1471 
1472  /*
1473  * indclass cannot be referenced directly through the C struct, because it
1474  * comes after the variable-width indkey field. Must extract the datum
1475  * the hard way...
1476  */
1477  indclassDatum = fastgetattr(relation->rd_indextuple,
1478  Anum_pg_index_indclass,
1480  &isnull);
1481  Assert(!isnull);
1482  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1483 
1484  /*
1485  * Fill the support procedure OID array, as well as the info about
1486  * opfamilies and opclass input types. (aminfo and supportinfo are left
1487  * as zeroes, and are filled on-the-fly when used)
1488  */
1489  IndexSupportInitialize(indclass, relation->rd_support,
1490  relation->rd_opfamily, relation->rd_opcintype,
1491  amsupport, indnkeyatts);
1492 
1493  /*
1494  * Similarly extract indoption and copy it to the cache entry
1495  */
1496  indoptionDatum = fastgetattr(relation->rd_indextuple,
1497  Anum_pg_index_indoption,
1499  &isnull);
1500  Assert(!isnull);
1501  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1502  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1503 
1504  /*
1505  * expressions, predicate, exclusion caches will be filled later
1506  */
1507  relation->rd_indexprs = NIL;
1508  relation->rd_indpred = NIL;
1509  relation->rd_exclops = NULL;
1510  relation->rd_exclprocs = NULL;
1511  relation->rd_exclstrats = NULL;
1512  relation->rd_amcache = NULL;
1513 }
signed short int16
Definition: c.h:346
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define NIL
Definition: pg_list.h:65
Definition: c.h:589
struct IndexAmRoutine * rd_indam
Definition: rel.h:157
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:173
#define AllocSetContextCreate
Definition: memutils.h:170
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:429
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
regproc RegProcedure
Definition: c.h:506
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:1337
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1529
struct HeapTupleData * rd_indextuple
Definition: rel.h:145
Form_pg_index rd_index
Definition: rel.h:143
unsigned short uint16
Definition: c.h:358
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:97
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4058
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:597
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:435
#define RelationGetRelationName(relation)
Definition: rel.h:457
List * rd_indpred
Definition: rel.h:164
Oid * rd_opfamily
Definition: rel.h:158
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:442
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:1116
Definition: c.h:578
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:733
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:586
#define DatumGetPointer(X)
Definition: postgres.h:549
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define elog(elevel,...)
Definition: elog.h:228
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:423
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

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

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

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence 
)

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

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

bool criticalSharedRelcachesBuilt