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_HOT, INDEX_ATTR_BITMAP_PROJ, 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 RelationGetOidIndex (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (Relation relation)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind keyAttrs)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
void RelationSetIndexList (Relation relation, List *indexIds, Oid oidIndex)
 
void RelationInitIndexAccessInfo (Relation relation)
 
struct PublicationActionsGetRelationPublicationActions (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 relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (void)
 
void RelationCloseSmgrByOid (Oid relationId)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
bool RelationIdIsInInitFile (Oid relationId)
 
void RelationCacheInitFilePreInvalidate (void)
 
void RelationCacheInitFilePostInvalidate (void)
 
void RelationCacheInitFileRemove (void)
 

Variables

bool criticalRelcachesBuilt
 
bool criticalSharedRelcachesBuilt
 

Macro Definition Documentation

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

Definition at line 26 of file relcache.h.

◆ RelationPtr

Definition at line 34 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_HOT 
INDEX_ATTR_BITMAP_PROJ 
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 

Definition at line 54 of file relcache.h.

Function Documentation

◆ AtEOSubXact_RelationCache()

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

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

2914 {
2916  RelIdCacheEnt *idhentry;
2917  int i;
2918 
2919  /*
2920  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2921  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
2922  * logic as in AtEOXact_RelationCache.
2923  */
2925  {
2926  hash_seq_init(&status, RelationIdCache);
2927  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2928  {
2929  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
2930  mySubid, parentSubid);
2931  }
2932  }
2933  else
2934  {
2935  for (i = 0; i < eoxact_list_len; i++)
2936  {
2937  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2938  (void *) &eoxact_list[i],
2939  HASH_FIND,
2940  NULL);
2941  if (idhentry != NULL)
2942  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
2943  mySubid, parentSubid);
2944  }
2945  }
2946 
2947  /* Don't reset the list; we still need more cleanup later */
2948 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:158
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:2959
Relation reldesc
Definition: relcache.c:122
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:125
static bool eoxact_list_overflowed
Definition: relcache.c:160
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:225
static int eoxact_list_len
Definition: relcache.c:159

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

2762 {
2764  RelIdCacheEnt *idhentry;
2765  int i;
2766 
2767  /*
2768  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2769  * listed in it. Otherwise fall back on a hash_seq_search scan.
2770  *
2771  * For simplicity, eoxact_list[] entries are not deleted till end of
2772  * top-level transaction, even though we could remove them at
2773  * subtransaction end in some cases, or remove relations from the list if
2774  * they are cleared for other reasons. Therefore we should expect the
2775  * case that list entries are not found in the hashtable; if not, there's
2776  * nothing to do for them.
2777  */
2779  {
2780  hash_seq_init(&status, RelationIdCache);
2781  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2782  {
2783  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2784  }
2785  }
2786  else
2787  {
2788  for (i = 0; i < eoxact_list_len; i++)
2789  {
2790  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2791  (void *) &eoxact_list[i],
2792  HASH_FIND,
2793  NULL);
2794  if (idhentry != NULL)
2795  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2796  }
2797  }
2798 
2799  if (EOXactTupleDescArrayLen > 0)
2800  {
2801  Assert(EOXactTupleDescArray != NULL);
2802  for (i = 0; i < NextEOXactTupleDescNum; i++)
2805  EOXactTupleDescArray = NULL;
2806  }
2807 
2808  /* Now we're out of the transaction and can clear the lists */
2809  eoxact_list_len = 0;
2810  eoxact_list_overflowed = false;
2811  NextEOXactTupleDescNum = 0;
2813 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:158
static int EOXactTupleDescArrayLen
Definition: relcache.c:177
Relation reldesc
Definition: relcache.c:122
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:125
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:2824
static bool eoxact_list_overflowed
Definition: relcache.c:160
static int NextEOXactTupleDescNum
Definition: relcache.c:176
void pfree(void *pointer)
Definition: mcxt.c:1031
#define Assert(condition)
Definition: c.h:699
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:311
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static int eoxact_list_len
Definition: relcache.c:159
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:175

◆ errtable()

int errtable ( Relation  rel)

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

5194 {
5198 
5199  return 0; /* return value does not matter */
5200 }
#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:3051
#define RelationGetRelationName(relation)
Definition: rel.h:441
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5210 of file relcache.c.

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

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

5211 {
5212  TupleDesc reldesc = RelationGetDescr(rel);
5213  const char *colname;
5214 
5215  /* Use reldesc if it's a user attribute, else consult the catalogs */
5216  if (attnum > 0 && attnum <= reldesc->natts)
5217  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5218  else
5219  colname = get_attname(RelationGetRelid(rel), attnum, false);
5220 
5221  return errtablecolname(rel, colname);
5222 }
#define RelationGetDescr(relation)
Definition: rel.h:433
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
NameData attname
Definition: pg_attribute.h:40
int16 attnum
Definition: pg_attribute.h:79
#define NameStr(name)
Definition: c.h:576
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:407
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5234

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5234 of file relcache.c.

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

Referenced by errtablecol().

5235 {
5236  errtable(rel);
5238 
5239  return 0; /* return value does not matter */
5240 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
int errtable(Relation rel)
Definition: relcache.c:5193

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5247 of file relcache.c.

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

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

5248 {
5249  errtable(rel);
5251 
5252  return 0; /* return value does not matter */
5253 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
int errtable(Relation rel)
Definition: relcache.c:5193

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5121 of file relcache.c.

References CacheMemoryContext, elog, ERROR, GetAllTablesPublications(), GetRelationPublications(), GETSTRUCT, HeapTupleIsValid, 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().

5122 {
5123  List *puboids;
5124  ListCell *lc;
5125  MemoryContext oldcxt;
5126  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5127 
5128  if (relation->rd_pubactions)
5129  return memcpy(pubactions, relation->rd_pubactions,
5130  sizeof(PublicationActions));
5131 
5132  /* Fetch the publication membership info. */
5133  puboids = GetRelationPublications(RelationGetRelid(relation));
5134  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5135 
5136  foreach(lc, puboids)
5137  {
5138  Oid pubid = lfirst_oid(lc);
5139  HeapTuple tup;
5140  Form_pg_publication pubform;
5141 
5143 
5144  if (!HeapTupleIsValid(tup))
5145  elog(ERROR, "cache lookup failed for publication %u", pubid);
5146 
5147  pubform = (Form_pg_publication) GETSTRUCT(tup);
5148 
5149  pubactions->pubinsert |= pubform->pubinsert;
5150  pubactions->pubupdate |= pubform->pubupdate;
5151  pubactions->pubdelete |= pubform->pubdelete;
5152  pubactions->pubtruncate |= pubform->pubtruncate;
5153 
5154  ReleaseSysCache(tup);
5155 
5156  /*
5157  * If we know everything is replicated, there is no point to check for
5158  * other publications.
5159  */
5160  if (pubactions->pubinsert && pubactions->pubupdate &&
5161  pubactions->pubdelete && pubactions->pubtruncate)
5162  break;
5163  }
5164 
5165  if (relation->rd_pubactions)
5166  {
5167  pfree(relation->rd_pubactions);
5168  relation->rd_pubactions = NULL;
5169  }
5170 
5171  /* Now save copy of the actions in the relcache entry. */
5173  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5174  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5175  MemoryContextSwitchTo(oldcxt);
5176 
5177  return pubactions;
5178 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
PublicationActions * rd_pubactions
Definition: rel.h:121
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * list_concat_unique_oid(List *list1, List *list2)
Definition: list.c:1082
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void * palloc0(Size size)
Definition: mcxt.c:955
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:924
#define elog
Definition: elog.h:219
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationBuildLocalRelation()

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

Definition at line 3024 of file relcache.c.

References Assert, AssertArg, BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), tupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsSharedRelation(), IsSystemNamespace(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), tupleDesc::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(), RelationMapUpdateMap(), relfilenode, relkind, relnamespace, relpersistence, reltablespace, tupleDesc::tdhasoid, tupleDesc::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

3034 {
3035  Relation rel;
3036  MemoryContext oldcxt;
3037  int natts = tupDesc->natts;
3038  int i;
3039  bool has_not_null;
3040  bool nailit;
3041 
3042  AssertArg(natts >= 0);
3043 
3044  /*
3045  * check for creation of a rel that must be nailed in cache.
3046  *
3047  * XXX this list had better match the relations specially handled in
3048  * RelationCacheInitializePhase2/3.
3049  */
3050  switch (relid)
3051  {
3052  case DatabaseRelationId:
3053  case AuthIdRelationId:
3054  case AuthMemRelationId:
3055  case RelationRelationId:
3056  case AttributeRelationId:
3057  case ProcedureRelationId:
3058  case TypeRelationId:
3059  nailit = true;
3060  break;
3061  default:
3062  nailit = false;
3063  break;
3064  }
3065 
3066  /*
3067  * check that hardwired list of shared rels matches what's in the
3068  * bootstrap .bki file. If you get a failure here during initdb, you
3069  * probably need to fix IsSharedRelation() to match whatever you've done
3070  * to the set of shared relations.
3071  */
3072  if (shared_relation != IsSharedRelation(relid))
3073  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3074  relname, relid);
3075 
3076  /* Shared relations had better be mapped, too */
3077  Assert(mapped_relation || !shared_relation);
3078 
3079  /*
3080  * switch to the cache context to create the relcache entry.
3081  */
3082  if (!CacheMemoryContext)
3084 
3086 
3087  /*
3088  * allocate a new relation descriptor and fill in basic state fields.
3089  */
3090  rel = (Relation) palloc0(sizeof(RelationData));
3091 
3092  /* make sure relation is marked as having no open file yet */
3093  rel->rd_smgr = NULL;
3094 
3095  /* mark it nailed if appropriate */
3096  rel->rd_isnailed = nailit;
3097 
3098  rel->rd_refcnt = nailit ? 1 : 0;
3099 
3100  /* it's being created in this transaction */
3103 
3104  /*
3105  * create a new tuple descriptor from the one passed in. We do this
3106  * partly to copy it into the cache context, and partly because the new
3107  * relation can't have any defaults or constraints yet; they have to be
3108  * added in later steps, because they require additions to multiple system
3109  * catalogs. We can copy attnotnull constraints here, however.
3110  */
3111  rel->rd_att = CreateTupleDescCopy(tupDesc);
3112  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3113  has_not_null = false;
3114  for (i = 0; i < natts; i++)
3115  {
3116  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3117  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3118 
3119  datt->attidentity = satt->attidentity;
3120  datt->attnotnull = satt->attnotnull;
3121  has_not_null |= satt->attnotnull;
3122  }
3123 
3124  if (has_not_null)
3125  {
3126  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3127 
3128  constr->has_not_null = true;
3129  rel->rd_att->constr = constr;
3130  }
3131 
3132  /*
3133  * initialize relation tuple form (caller may add/override data later)
3134  */
3136 
3137  namestrcpy(&rel->rd_rel->relname, relname);
3138  rel->rd_rel->relnamespace = relnamespace;
3139 
3140  rel->rd_rel->relkind = relkind;
3141  rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
3142  rel->rd_rel->relnatts = natts;
3143  rel->rd_rel->reltype = InvalidOid;
3144  /* needed when bootstrapping: */
3145  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3146 
3147  /* set up persistence and relcache fields dependent on it */
3148  rel->rd_rel->relpersistence = relpersistence;
3149  switch (relpersistence)
3150  {
3151  case RELPERSISTENCE_UNLOGGED:
3152  case RELPERSISTENCE_PERMANENT:
3154  rel->rd_islocaltemp = false;
3155  break;
3156  case RELPERSISTENCE_TEMP:
3159  rel->rd_islocaltemp = true;
3160  break;
3161  default:
3162  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3163  break;
3164  }
3165 
3166  /* if it's a materialized view, it's not populated initially */
3167  if (relkind == RELKIND_MATVIEW)
3168  rel->rd_rel->relispopulated = false;
3169  else
3170  rel->rd_rel->relispopulated = true;
3171 
3172  /* system relations and non-table objects don't have one */
3174  (relkind == RELKIND_RELATION ||
3175  relkind == RELKIND_MATVIEW ||
3176  relkind == RELKIND_PARTITIONED_TABLE))
3177  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3178  else
3179  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3180 
3181  /*
3182  * Insert relation physical and logical identifiers (OIDs) into the right
3183  * places. For a mapped relation, we set relfilenode to zero and rely on
3184  * RelationInitPhysicalAddr to consult the map.
3185  */
3186  rel->rd_rel->relisshared = shared_relation;
3187 
3188  RelationGetRelid(rel) = relid;
3189 
3190  for (i = 0; i < natts; i++)
3191  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3192 
3193  rel->rd_rel->reltablespace = reltablespace;
3194 
3195  if (mapped_relation)
3196  {
3197  rel->rd_rel->relfilenode = InvalidOid;
3198  /* Add it to the active mapping information */
3199  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3200  }
3201  else
3202  rel->rd_rel->relfilenode = relfilenode;
3203 
3204  RelationInitLockInfo(rel); /* see lmgr.c */
3205 
3207 
3208  /*
3209  * Okay to insert into the relcache hash table.
3210  *
3211  * Ordinarily, there should certainly not be an existing hash entry for
3212  * the same OID; but during bootstrap, when we create a "real" relcache
3213  * entry for one of the bootstrap relations, we'll be overwriting the
3214  * phony one created with formrdesc. So allow that to happen for nailed
3215  * rels.
3216  */
3217  RelationCacheInsert(rel, nailit);
3218 
3219  /*
3220  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3221  * can't do this before storing relid in it.
3222  */
3223  EOXactListAdd(rel);
3224 
3225  /*
3226  * done building relcache entry.
3227  */
3228  MemoryContextSwitchTo(oldcxt);
3229 
3230  /* It's fully valid */
3231  rel->rd_isvalid = true;
3232 
3233  /*
3234  * Caller expects us to pin the returned entry.
3235  */
3237 
3238  return rel;
3239 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:112
#define EOXactListAdd(rel)
Definition: relcache.c:162
Oid relnamespace
Definition: pg_class.h:32
bool tdhasoid
Definition: tupdesc.h:85
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3161
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Form_pg_class rd_rel
Definition: rel.h:84
int namestrcpy(Name name, const char *str)
Definition: name.c:216
int natts
Definition: tupdesc.h:82
char relkind
Definition: pg_class.h:51
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:50
Oid relfilenode
Definition: pg_class.h:39
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define BackendIdForTempRelations()
Definition: backendid.h:34
Oid reltablespace
Definition: pg_class.h:42
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define AssertArg(condition)
Definition: c.h:701
bool has_not_null
Definition: tupdesc.h:46
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:955
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:1963
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:220
TupleDesc rd_att
Definition: rel.h:85
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:163
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:182
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:85
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:699
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
TupleConstr * constr
Definition: tupdesc.h:87
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
#define InvalidSubTransactionId
Definition: c.h:480
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
int rd_refcnt
Definition: rel.h:58
int tdrefcount
Definition: tupdesc.h:86
int i
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6032 of file relcache.c.

References LWLockRelease().

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

6033 {
6034  LWLockRelease(RelCacheInitLock);
6035 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6006 of file relcache.c.

References DatabasePath, ereport, errcode_for_file_access(), errmsg(), ERROR, LW_EXCLUSIVE, LWLockAcquire(), MAXPGPATH, RELCACHE_INIT_FILENAME, and snprintf().

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

6007 {
6008  char initfilename[MAXPGPATH];
6009 
6010  snprintf(initfilename, sizeof(initfilename), "%s/%s",
6012 
6013  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6014 
6015  if (unlink(initfilename) < 0)
6016  {
6017  /*
6018  * The file might not be there if no backend has been started since
6019  * the last removal. But complain about failures other than ENOENT.
6020  * Fortunately, it's not too late to abort the transaction if we can't
6021  * get rid of the would-be-obsolete init file.
6022  */
6023  if (errno != ENOENT)
6024  ereport(ERROR,
6026  errmsg("could not remove cache file \"%s\": %m",
6027  initfilename)));
6028  }
6029 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char * DatabasePath
Definition: globals.c:94
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

6048 {
6049  const char *tblspcdir = "pg_tblspc";
6050  DIR *dir;
6051  struct dirent *de;
6052  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6053 
6054  /*
6055  * We zap the shared cache file too. In theory it can't get out of sync
6056  * enough to be a problem, but in data-corruption cases, who knows ...
6057  */
6058  snprintf(path, sizeof(path), "global/%s",
6060  unlink_initfile(path);
6061 
6062  /* Scan everything in the default tablespace */
6064 
6065  /* Scan the tablespace link directory to find non-default tablespaces */
6066  dir = AllocateDir(tblspcdir);
6067 
6068  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6069  {
6070  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6071  {
6072  /* Scan the tablespace dir for per-database dirs */
6073  snprintf(path, sizeof(path), "%s/%s/%s",
6074  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6076  }
6077  }
6078 
6079  FreeDir(dir);
6080 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6084
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2671
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#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:2590
static void unlink_initfile(const char *initfilename)
Definition: relcache.c:6108
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2708

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3376 of file relcache.c.

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

Referenced by InitPostgres().

3377 {
3378  HASHCTL ctl;
3379 
3380  /*
3381  * make sure cache memory context exists
3382  */
3383  if (!CacheMemoryContext)
3385 
3386  /*
3387  * create hashtable that indexes the relcache
3388  */
3389  MemSet(&ctl, 0, sizeof(ctl));
3390  ctl.keysize = sizeof(Oid);
3391  ctl.entrysize = sizeof(RelIdCacheEnt);
3392  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3393  &ctl, HASH_ELEM | HASH_BLOBS);
3394 
3395  /*
3396  * relation mapper needs to be initialized too
3397  */
3399 }
void RelationMapInitialize(void)
Definition: relmapper.c:562
#define HASH_ELEM
Definition: hsearch.h:87
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:908
static HTAB * RelationIdCache
Definition: relcache.c:125
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:636
#define INITRELCACHESIZE
Definition: relcache.c:3373
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

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

3414 {
3415  MemoryContext oldcxt;
3416 
3417  /*
3418  * relation mapper needs initialized too
3419  */
3421 
3422  /*
3423  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3424  * nothing.
3425  */
3427  return;
3428 
3429  /*
3430  * switch to cache memory context
3431  */
3433 
3434  /*
3435  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3436  * the cache with pre-made descriptors for the critical shared catalogs.
3437  */
3438  if (!load_relcache_init_file(true))
3439  {
3440  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3441  true, Natts_pg_database, Desc_pg_database);
3442  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3443  true, Natts_pg_authid, Desc_pg_authid);
3444  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3445  false, Natts_pg_auth_members, Desc_pg_auth_members);
3446  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3447  false, Natts_pg_shseclabel, Desc_pg_shseclabel);
3448  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3449  true, Natts_pg_subscription, Desc_pg_subscription);
3450 
3451 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3452  }
3453 
3454  MemoryContextSwitchTo(oldcxt);
3455 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:108
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5311
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, bool hasoids, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1726
void RelationMapInitializePhase2(void)
Definition: relmapper.c:582
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:107
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:111
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:106
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:110
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3472 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, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIncrementReferenceCount(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, RewriteRelRulenameIndexId, SearchSysCache1(), SharedSecLabelObjectIndexId, status(), tupleDesc::tdhasoid, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, TriggerRelidNameIndexId, and write_relcache_init_file().

Referenced by InitPostgres().

3473 {
3475  RelIdCacheEnt *idhentry;
3476  MemoryContext oldcxt;
3477  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3478 
3479  /*
3480  * relation mapper needs initialized too
3481  */
3483 
3484  /*
3485  * switch to cache memory context
3486  */
3488 
3489  /*
3490  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3491  * the cache with pre-made descriptors for the critical "nailed-in" system
3492  * catalogs.
3493  */
3494  if (IsBootstrapProcessingMode() ||
3495  !load_relcache_init_file(false))
3496  {
3497  needNewCacheFile = true;
3498 
3499  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3500  true, Natts_pg_class, Desc_pg_class);
3501  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3502  false, Natts_pg_attribute, Desc_pg_attribute);
3503  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3504  true, Natts_pg_proc, Desc_pg_proc);
3505  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3506  true, Natts_pg_type, Desc_pg_type);
3507 
3508 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3509  }
3510 
3511  MemoryContextSwitchTo(oldcxt);
3512 
3513  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3515  return;
3516 
3517  /*
3518  * If we didn't get the critical system indexes loaded into relcache, do
3519  * so now. These are critical because the catcache and/or opclass cache
3520  * depend on them for fetches done during relcache load. Thus, we have an
3521  * infinite-recursion problem. We can break the recursion by doing
3522  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3523  * performance, we only want to do that until we have the critical indexes
3524  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3525  * decide whether to do heapscan or indexscan at the key spots, and we set
3526  * it true after we've loaded the critical indexes.
3527  *
3528  * The critical indexes are marked as "nailed in cache", partly to make it
3529  * easy for load_relcache_init_file to count them, but mainly because we
3530  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3531  * true. (NOTE: perhaps it would be possible to reload them by
3532  * temporarily setting criticalRelcachesBuilt to false again. For now,
3533  * though, we just nail 'em in.)
3534  *
3535  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3536  * in the same way as the others, because the critical catalogs don't
3537  * (currently) have any rules or triggers, and so these indexes can be
3538  * rebuilt without inducing recursion. However they are used during
3539  * relcache load when a rel does have rules or triggers, so we choose to
3540  * nail them for performance reasons.
3541  */
3543  {
3545  RelationRelationId);
3547  AttributeRelationId);
3549  IndexRelationId);
3551  OperatorClassRelationId);
3553  AccessMethodProcedureRelationId);
3555  RewriteRelationId);
3557  TriggerRelationId);
3558 
3559 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3560 
3561  criticalRelcachesBuilt = true;
3562  }
3563 
3564  /*
3565  * Process critical shared indexes too.
3566  *
3567  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3568  * initial lookup of MyDatabaseId, without which we'll never find any
3569  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3570  * database OID, so it instead depends on DatabaseOidIndexId. We also
3571  * need to nail up some indexes on pg_authid and pg_auth_members for use
3572  * during client authentication. SharedSecLabelObjectIndexId isn't
3573  * critical for the core system, but authentication hooks might be
3574  * interested in it.
3575  */
3577  {
3579  DatabaseRelationId);
3581  DatabaseRelationId);
3583  AuthIdRelationId);
3585  AuthIdRelationId);
3587  AuthMemRelationId);
3589  SharedSecLabelRelationId);
3590 
3591 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3592 
3594  }
3595 
3596  /*
3597  * Now, scan all the relcache entries and update anything that might be
3598  * wrong in the results from formrdesc or the relcache cache file. If we
3599  * faked up relcache entries using formrdesc, then read the real pg_class
3600  * rows and replace the fake entries with them. Also, if any of the
3601  * relcache entries have rules, triggers, or security policies, load that
3602  * info the hard way since it isn't recorded in the cache file.
3603  *
3604  * Whenever we access the catalogs to read data, there is a possibility of
3605  * a shared-inval cache flush causing relcache entries to be removed.
3606  * Since hash_seq_search only guarantees to still work after the *current*
3607  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3608  * We handle this by restarting the scan from scratch after each access.
3609  * This is theoretically O(N^2), but the number of entries that actually
3610  * need to be fixed is small enough that it doesn't matter.
3611  */
3612  hash_seq_init(&status, RelationIdCache);
3613 
3614  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3615  {
3616  Relation relation = idhentry->reldesc;
3617  bool restart = false;
3618 
3619  /*
3620  * Make sure *this* entry doesn't get flushed while we work with it.
3621  */
3623 
3624  /*
3625  * If it's a faked-up entry, read the real pg_class tuple.
3626  */
3627  if (relation->rd_rel->relowner == InvalidOid)
3628  {
3629  HeapTuple htup;
3630  Form_pg_class relp;
3631 
3632  htup = SearchSysCache1(RELOID,
3633  ObjectIdGetDatum(RelationGetRelid(relation)));
3634  if (!HeapTupleIsValid(htup))
3635  elog(FATAL, "cache lookup failed for relation %u",
3636  RelationGetRelid(relation));
3637  relp = (Form_pg_class) GETSTRUCT(htup);
3638 
3639  /*
3640  * Copy tuple to relation->rd_rel. (See notes in
3641  * AllocateRelationDesc())
3642  */
3643  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
3644 
3645  /* Update rd_options while we have the tuple */
3646  if (relation->rd_options)
3647  pfree(relation->rd_options);
3648  RelationParseRelOptions(relation, htup);
3649 
3650  /*
3651  * Check the values in rd_att were set up correctly. (We cannot
3652  * just copy them over now: formrdesc must have set up the rd_att
3653  * data correctly to start with, because it may already have been
3654  * copied into one or more catcache entries.)
3655  */
3656  Assert(relation->rd_att->tdtypeid == relp->reltype);
3657  Assert(relation->rd_att->tdtypmod == -1);
3658  Assert(relation->rd_att->tdhasoid == relp->relhasoids);
3659 
3660  ReleaseSysCache(htup);
3661 
3662  /* relowner had better be OK now, else we'll loop forever */
3663  if (relation->rd_rel->relowner == InvalidOid)
3664  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
3665  RelationGetRelationName(relation));
3666 
3667  restart = true;
3668  }
3669 
3670  /*
3671  * Fix data that isn't saved in relcache cache file.
3672  *
3673  * relhasrules or relhastriggers could possibly be wrong or out of
3674  * date. If we don't actually find any rules or triggers, clear the
3675  * local copy of the flag so that we don't get into an infinite loop
3676  * here. We don't make any attempt to fix the pg_class entry, though.
3677  */
3678  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
3679  {
3680  RelationBuildRuleLock(relation);
3681  if (relation->rd_rules == NULL)
3682  relation->rd_rel->relhasrules = false;
3683  restart = true;
3684  }
3685  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
3686  {
3687  RelationBuildTriggers(relation);
3688  if (relation->trigdesc == NULL)
3689  relation->rd_rel->relhastriggers = false;
3690  restart = true;
3691  }
3692 
3693  /*
3694  * Re-load the row security policies if the relation has them, since
3695  * they are not preserved in the cache. Note that we can never NOT
3696  * have a policy while relrowsecurity is true,
3697  * RelationBuildRowSecurity will create a single default-deny policy
3698  * if there is no policy defined in pg_policy.
3699  */
3700  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
3701  {
3702  RelationBuildRowSecurity(relation);
3703 
3704  Assert(relation->rd_rsdesc != NULL);
3705  restart = true;
3706  }
3707 
3708  /*
3709  * Reload the partition key and descriptor for a partitioned table.
3710  */
3711  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3712  relation->rd_partkey == NULL)
3713  {
3714  RelationBuildPartitionKey(relation);
3715  Assert(relation->rd_partkey != NULL);
3716 
3717  restart = true;
3718  }
3719 
3720  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3721  relation->rd_partdesc == NULL)
3722  {
3723  RelationBuildPartitionDesc(relation);
3724  Assert(relation->rd_partdesc != NULL);
3725 
3726  restart = true;
3727  }
3728 
3729  /* Release hold on the relation */
3731 
3732  /* Now, restart the hashtable scan if needed */
3733  if (restart)
3734  {
3735  hash_seq_term(&status);
3736  hash_seq_init(&status, RelationIdCache);
3737  }
3738  }
3739 
3740  /*
3741  * Lastly, write out new relcache cache files if needed. We don't bother
3742  * to distinguish cases where only one of the two needs an update.
3743  */
3744  if (needNewCacheFile)
3745  {
3746  /*
3747  * Force all the catcaches to finish initializing and thereby open the
3748  * catalogs and indexes they use. This will preload the relcache with
3749  * entries for all the most important system catalogs and indexes, so
3750  * that the init files will be most useful for future backends.
3751  */
3753 
3754  /* now write the files */
3756  write_relcache_init_file(false);
3757  }
3758 }
#define AttributeRelidNumIndexId
Definition: indexing.h:93
struct PartitionDescData * rd_partdesc
Definition: rel.h:101
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5311
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, bool hasoids, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1726
Oid tdtypeid
Definition: tupdesc.h:83
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define IndexRelidIndexId
Definition: indexing.h:165
bool tdhasoid
Definition: tupdesc.h:85
#define RewriteRelRulenameIndexId
Definition: indexing.h:224
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:191
Relation reldesc
Definition: relcache.c:122
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:137
#define AuthIdOidIndexId
Definition: indexing.h:98
static HTAB * RelationIdCache
Definition: relcache.c:125
Form_pg_class rd_rel
Definition: rel.h:84
int32 tdtypmod
Definition: tupdesc.h:84
#define TriggerRelidNameIndexId
Definition: indexing.h:250
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:1976
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
void RelationBuildPartitionDesc(Relation rel)
Definition: partcache.c:261
#define FATAL
Definition: elog.h:52
static void write_relcache_init_file(bool shared)
Definition: relcache.c:5702
struct PartitionKeyData * rd_partkey
Definition: rel.h:99
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:435
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:3767
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:104
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define DatabaseOidIndexId
Definition: indexing.h:143
#define ClassOidIndexId
Definition: indexing.h:111
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define AccessMethodProcedureIndexId
Definition: indexing.h:81
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:1963
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
TupleDesc rd_att
Definition: rel.h:85
#define OpclassOidIndexId
Definition: indexing.h:201
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:85
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define AuthMemMemRoleIndexId
Definition: indexing.h:103
RuleLock * rd_rules
Definition: rel.h:88
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
#define DatabaseNameIndexId
Definition: indexing.h:141
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define SharedSecLabelObjectIndexId
Definition: indexing.h:317
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
void RelationBuildPartitionKey(Relation relation)
Definition: partcache.c:64
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1910
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:102
void RelationMapInitializePhase3(void)
Definition: relmapper.c:603
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:724
#define elog
Definition: elog.h:219
bool criticalRelcachesBuilt
Definition: relcache.c:131
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define AuthIdRolnameIndexId
Definition: indexing.h:96
void InitCatalogCachePhase2(void)
Definition: syscache.c:1071
#define RelationGetRelid(relation)
Definition: rel.h:407
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:105
bytea * rd_options
Definition: rel.h:128
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:103
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

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

2602 {
2604  RelIdCacheEnt *idhentry;
2605  Relation relation;
2606  List *rebuildFirstList = NIL;
2607  List *rebuildList = NIL;
2608  ListCell *l;
2609 
2610  /*
2611  * Reload relation mapping data before starting to reconstruct cache.
2612  */
2614 
2615  /* Phase 1 */
2616  hash_seq_init(&status, RelationIdCache);
2617 
2618  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2619  {
2620  relation = idhentry->reldesc;
2621 
2622  /* Must close all smgr references to avoid leaving dangling ptrs */
2623  RelationCloseSmgr(relation);
2624 
2625  /*
2626  * Ignore new relations; no other backend will manipulate them before
2627  * we commit. Likewise, before replacing a relation's relfilenode, we
2628  * shall have acquired AccessExclusiveLock and drained any applicable
2629  * pending invalidations.
2630  */
2631  if (relation->rd_createSubid != InvalidSubTransactionId ||
2633  continue;
2634 
2636 
2637  if (RelationHasReferenceCountZero(relation))
2638  {
2639  /* Delete this entry immediately */
2640  Assert(!relation->rd_isnailed);
2641  RelationClearRelation(relation, false);
2642  }
2643  else
2644  {
2645  /*
2646  * If it's a mapped relation, immediately update its rd_node in
2647  * case its relfilenode changed. We must do this during phase 1
2648  * in case the relation is consulted during rebuild of other
2649  * relcache entries in phase 2. It's safe since consulting the
2650  * map doesn't involve any access to relcache entries.
2651  */
2652  if (RelationIsMapped(relation))
2653  RelationInitPhysicalAddr(relation);
2654 
2655  /*
2656  * Add this entry to list of stuff to rebuild in second pass.
2657  * pg_class goes to the front of rebuildFirstList while
2658  * pg_class_oid_index goes to the back of rebuildFirstList, so
2659  * they are done first and second respectively. Other nailed
2660  * relations go to the front of rebuildList, so they'll be done
2661  * next in no particular order; and everything else goes to the
2662  * back of rebuildList.
2663  */
2664  if (RelationGetRelid(relation) == RelationRelationId)
2665  rebuildFirstList = lcons(relation, rebuildFirstList);
2666  else if (RelationGetRelid(relation) == ClassOidIndexId)
2667  rebuildFirstList = lappend(rebuildFirstList, relation);
2668  else if (relation->rd_isnailed)
2669  rebuildList = lcons(relation, rebuildList);
2670  else
2671  rebuildList = lappend(rebuildList, relation);
2672  }
2673  }
2674 
2675  /*
2676  * Now zap any remaining smgr cache entries. This must happen before we
2677  * start to rebuild entries, since that may involve catalog fetches which
2678  * will re-open catalog files.
2679  */
2680  smgrcloseall();
2681 
2682  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2683  foreach(l, rebuildFirstList)
2684  {
2685  relation = (Relation) lfirst(l);
2686  RelationClearRelation(relation, true);
2687  }
2688  list_free(rebuildFirstList);
2689  foreach(l, rebuildList)
2690  {
2691  relation = (Relation) lfirst(l);
2692  RelationClearRelation(relation, true);
2693  }
2694  list_free(rebuildList);
2695 }
#define NIL
Definition: pg_list.h:69
static long relcacheInvalsReceived
Definition: relcache.c:145
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
bool rd_isnailed
Definition: rel.h:61
Relation reldesc
Definition: relcache.c:122
#define RelationCloseSmgr(relation)
Definition: rel.h:477
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
static HTAB * RelationIdCache
Definition: relcache.c:125
void smgrcloseall(void)
Definition: smgr.c:326
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
#define ClassOidIndexId
Definition: indexing.h:111
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RelationIsMapped(relation)
Definition: rel.h:458
SubTransactionId rd_createSubid
Definition: rel.h:80
List * lcons(void *datum, List *list)
Definition: list.c:259
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:480
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:391
void list_free(List *list)
Definition: list.c:1133
void RelationMapInvalidateAll(void)
Definition: relmapper.c:409
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2557 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2558 {
2559  Relation relation;
2560 
2561  RelationIdCacheLookup(relationId, relation);
2562 
2563  if (PointerIsValid(relation))
2564  {
2566  RelationFlushRelation(relation);
2567  }
2568 }
static long relcacheInvalsReceived
Definition: relcache.c:145
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:204
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2489
#define PointerIsValid(pointer)
Definition: c.h:593

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 1996 of file relcache.c.

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

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

1997 {
1998  /* Note: no locking manipulations needed */
2000 
2001 #ifdef RELCACHE_FORCE_RELEASE
2002  if (RelationHasReferenceCountZero(relation) &&
2003  relation->rd_createSubid == InvalidSubTransactionId &&
2005  RelationClearRelation(relation, false);
2006 #endif
2007 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:1976
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidSubTransactionId
Definition: c.h:480
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 2704 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

2705 {
2706  Relation relation;
2707 
2708  RelationIdCacheLookup(relationId, relation);
2709 
2710  if (!PointerIsValid(relation))
2711  return; /* not in cache, nothing to do */
2712 
2713  RelationCloseSmgr(relation);
2714 }
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:204
#define RelationCloseSmgr(relation)
Definition: rel.h:477
#define PointerIsValid(pointer)
Definition: c.h:593

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2525 of file relcache.c.

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

Referenced by heap_drop_with_catalog(), and index_drop().

2526 {
2527  Relation relation;
2528 
2529  RelationIdCacheLookup(rid, relation);
2530 
2531  if (!PointerIsValid(relation))
2532  return; /* not in cache, nothing to do */
2533 
2534  if (!RelationHasReferenceCountZero(relation))
2535  elog(ERROR, "relation %u is still open", rid);
2536 
2537  /* Unconditionally destroy the relcache entry */
2538  RelationClearRelation(relation, false);
2539 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:204
#define ERROR
Definition: elog.h:43
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391
#define elog
Definition: elog.h:219
#define PointerIsValid(pointer)
Definition: c.h:593

◆ RelationGetExclusionInfo()

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

Definition at line 5001 of file relcache.c.

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, ConstraintRelidIndexId, DatumGetArrayTypeP, elog, ERROR, fastgetattr, get_op_opfamily_strategy(), get_opcode(), GETSTRUCT, heap_close, heap_open(), 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(), and val.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

5005 {
5006  int indnkeyatts;
5007  Oid *ops;
5008  Oid *funcs;
5009  uint16 *strats;
5010  Relation conrel;
5011  SysScanDesc conscan;
5012  ScanKeyData skey[1];
5013  HeapTuple htup;
5014  bool found;
5015  MemoryContext oldcxt;
5016  int i;
5017 
5018  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5019 
5020  /* Allocate result space in caller context */
5021  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5022  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5023  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5024 
5025  /* Quick exit if we have the data cached already */
5026  if (indexRelation->rd_exclstrats != NULL)
5027  {
5028  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5029  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5030  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5031  return;
5032  }
5033 
5034  /*
5035  * Search pg_constraint for the constraint associated with the index. To
5036  * make this not too painfully slow, we use the index on conrelid; that
5037  * will hold the parent relation's OID not the index's own OID.
5038  */
5039  ScanKeyInit(&skey[0],
5040  Anum_pg_constraint_conrelid,
5041  BTEqualStrategyNumber, F_OIDEQ,
5042  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5043 
5044  conrel = heap_open(ConstraintRelationId, AccessShareLock);
5045  conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
5046  NULL, 1, skey);
5047  found = false;
5048 
5049  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5050  {
5052  Datum val;
5053  bool isnull;
5054  ArrayType *arr;
5055  int nelem;
5056 
5057  /* We want the exclusion constraint owning the index */
5058  if (conform->contype != CONSTRAINT_EXCLUSION ||
5059  conform->conindid != RelationGetRelid(indexRelation))
5060  continue;
5061 
5062  /* There should be only one */
5063  if (found)
5064  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5065  RelationGetRelationName(indexRelation));
5066  found = true;
5067 
5068  /* Extract the operator OIDS from conexclop */
5069  val = fastgetattr(htup,
5070  Anum_pg_constraint_conexclop,
5071  conrel->rd_att, &isnull);
5072  if (isnull)
5073  elog(ERROR, "null conexclop for rel %s",
5074  RelationGetRelationName(indexRelation));
5075 
5076  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5077  nelem = ARR_DIMS(arr)[0];
5078  if (ARR_NDIM(arr) != 1 ||
5079  nelem != indnkeyatts ||
5080  ARR_HASNULL(arr) ||
5081  ARR_ELEMTYPE(arr) != OIDOID)
5082  elog(ERROR, "conexclop is not a 1-D Oid array");
5083 
5084  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5085  }
5086 
5087  systable_endscan(conscan);
5088  heap_close(conrel, AccessShareLock);
5089 
5090  if (!found)
5091  elog(ERROR, "exclusion constraint record missing for rel %s",
5092  RelationGetRelationName(indexRelation));
5093 
5094  /* We need the func OIDs and strategy numbers too */
5095  for (i = 0; i < indnkeyatts; i++)
5096  {
5097  funcs[i] = get_opcode(ops[i]);
5098  strats[i] = get_op_opfamily_strategy(ops[i],
5099  indexRelation->rd_opfamily[i]);
5100  /* shouldn't fail, since it was checked at index creation */
5101  if (strats[i] == InvalidStrategy)
5102  elog(ERROR, "could not find strategy for operator %u in family %u",
5103  ops[i], indexRelation->rd_opfamily[i]);
5104  }
5105 
5106  /* Save a copy of the results in the relcache entry. */
5107  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5108  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5109  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5110  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5111  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5112  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5113  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5114  MemoryContextSwitchTo(oldcxt);
5115 }
#define InvalidStrategy
Definition: stratnum.h:24
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:731
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:163
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
Oid * rd_exclprocs
Definition: rel.h:162
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:331
Form_pg_index rd_index
Definition: rel.h:131
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
unsigned short uint16
Definition: c.h:324
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:279
#define ARR_DATA_PTR(a)
Definition: array.h:307
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ARR_HASNULL(a)
Definition: array.h:276
Oid * rd_opfamily
Definition: rel.h:154
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:426
Oid * rd_exclops
Definition: rel.h:161
uintptr_t Datum
Definition: postgres.h:367
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ARR_NDIM(a)
Definition: array.h:275
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:80
void * palloc(Size size)
Definition: mcxt.c:924
MemoryContext rd_indexcxt
Definition: rel.h:151
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define ARR_ELEMTYPE(a)
Definition: array.h:277
#define RelationGetRelid(relation)
Definition: rel.h:407
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ConstraintRelidIndexId
Definition: indexing.h:125
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4027 of file relcache.c.

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confkey, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conkey, ForeignKeyCacheInfo::conpfeqop, ForeignKeyCacheInfo::conrelid, ConstraintRelidIndexId, copyObject, DatumGetArrayTypeP, elog, ERROR, fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, INDEX_MAX_KEYS, lappend(), list_free_deep(), makeNode, MemoryContextSwitchTo(), NIL, ForeignKeyCacheInfo::nkeys, ObjectIdGetDatum, RelationData::rd_att, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by get_relation_foreign_keys().

4028 {
4029  List *result;
4030  Relation conrel;
4031  SysScanDesc conscan;
4032  ScanKeyData skey;
4033  HeapTuple htup;
4034  List *oldlist;
4035  MemoryContext oldcxt;
4036 
4037  /* Quick exit if we already computed the list. */
4038  if (relation->rd_fkeyvalid)
4039  return relation->rd_fkeylist;
4040 
4041  /* Fast path: if it doesn't have any triggers, it can't have FKs */
4042  if (!relation->rd_rel->relhastriggers)
4043  return NIL;
4044 
4045  /*
4046  * We build the list we intend to return (in the caller's context) while
4047  * doing the scan. After successfully completing the scan, we copy that
4048  * list into the relcache entry. This avoids cache-context memory leakage
4049  * if we get some sort of error partway through.
4050  */
4051  result = NIL;
4052 
4053  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4054  ScanKeyInit(&skey,
4055  Anum_pg_constraint_conrelid,
4056  BTEqualStrategyNumber, F_OIDEQ,
4057  ObjectIdGetDatum(RelationGetRelid(relation)));
4058 
4059  conrel = heap_open(ConstraintRelationId, AccessShareLock);
4060  conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
4061  NULL, 1, &skey);
4062 
4063  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4064  {
4065  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4066  ForeignKeyCacheInfo *info;
4067  Datum adatum;
4068  bool isnull;
4069  ArrayType *arr;
4070  int nelem;
4071 
4072  /* consider only foreign keys */
4073  if (constraint->contype != CONSTRAINT_FOREIGN)
4074  continue;
4075 
4076  info = makeNode(ForeignKeyCacheInfo);
4077  info->conrelid = constraint->conrelid;
4078  info->confrelid = constraint->confrelid;
4079 
4080  /* Extract data from conkey field */
4081  adatum = fastgetattr(htup, Anum_pg_constraint_conkey,
4082  conrel->rd_att, &isnull);
4083  if (isnull)
4084  elog(ERROR, "null conkey for rel %s",
4085  RelationGetRelationName(relation));
4086 
4087  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
4088  nelem = ARR_DIMS(arr)[0];
4089  if (ARR_NDIM(arr) != 1 ||
4090  nelem < 1 ||
4091  nelem > INDEX_MAX_KEYS ||
4092  ARR_HASNULL(arr) ||
4093  ARR_ELEMTYPE(arr) != INT2OID)
4094  elog(ERROR, "conkey is not a 1-D smallint array");
4095 
4096  info->nkeys = nelem;
4097  memcpy(info->conkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber));
4098 
4099  /* Likewise for confkey */
4100  adatum = fastgetattr(htup, Anum_pg_constraint_confkey,
4101  conrel->rd_att, &isnull);
4102  if (isnull)
4103  elog(ERROR, "null confkey for rel %s",
4104  RelationGetRelationName(relation));
4105 
4106  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
4107  nelem = ARR_DIMS(arr)[0];
4108  if (ARR_NDIM(arr) != 1 ||
4109  nelem != info->nkeys ||
4110  ARR_HASNULL(arr) ||
4111  ARR_ELEMTYPE(arr) != INT2OID)
4112  elog(ERROR, "confkey is not a 1-D smallint array");
4113 
4114  memcpy(info->confkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber));
4115 
4116  /* Likewise for conpfeqop */
4117  adatum = fastgetattr(htup, Anum_pg_constraint_conpfeqop,
4118  conrel->rd_att, &isnull);
4119  if (isnull)
4120  elog(ERROR, "null conpfeqop for rel %s",
4121  RelationGetRelationName(relation));
4122 
4123  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
4124  nelem = ARR_DIMS(arr)[0];
4125  if (ARR_NDIM(arr) != 1 ||
4126  nelem != info->nkeys ||
4127  ARR_HASNULL(arr) ||
4128  ARR_ELEMTYPE(arr) != OIDOID)
4129  elog(ERROR, "conpfeqop is not a 1-D OID array");
4130 
4131  memcpy(info->conpfeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid));
4132 
4133  /* Add FK's node to the result list */
4134  result = lappend(result, info);
4135  }
4136 
4137  systable_endscan(conscan);
4138  heap_close(conrel, AccessShareLock);
4139 
4140  /* Now save a copy of the completed list in the relcache entry. */
4142  oldlist = relation->rd_fkeylist;
4143  relation->rd_fkeylist = copyObject(result);
4144  relation->rd_fkeyvalid = true;
4145  MemoryContextSwitchTo(oldcxt);
4146 
4147  /* Don't leak the old list, if there is one */
4148  list_free_deep(oldlist);
4149 
4150  return result;
4151 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:731
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: rel.h:215
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * rd_fkeylist
Definition: rel.h:95
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
void list_free_deep(List *list)
Definition: list.c:1147
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:279
#define ARR_DATA_PTR(a)
Definition: array.h:307
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ARR_HASNULL(a)
Definition: array.h:276
List * lappend(List *list, void *datum)
Definition: list.c:128
uintptr_t Datum
Definition: postgres.h:367
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
#define makeNode(_type_)
Definition: nodes.h:565
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:217
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define INDEX_MAX_KEYS
#define ARR_NDIM(a)
Definition: array.h:275
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:216
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:630
Definition: pg_list.h:45
bool rd_fkeyvalid
Definition: rel.h:96
#define ARR_ELEMTYPE(a)
Definition: array.h:277
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ConstraintRelidIndexId
Definition: indexing.h:125
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  keyAttrs 
)

Definition at line 4759 of file relcache.c.

References AccessShareLock, bms_add_member(), bms_copy(), bms_free(), BuildIndexInfo(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, i, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, INDEX_ATTR_BITMAP_HOT, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_PROJ, index_close(), index_open(), IsProjectionFunctionalIndex(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, pull_varattnos(), RelationData::rd_idattr, RelationData::rd_indexattr, RelationData::rd_keyattr, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_projidx, RelationData::rd_projindexattr, RelationData::rd_replidindex, RelationGetForm, RelationGetIndexList(), and relhasindex.

Referenced by ExecUpdateLockMode(), heap_update(), logicalrep_rel_open(), logicalrep_write_attrs(), and reindex_relation().

4760 {
4761  Bitmapset *indexattrs; /* columns used in non-projection indexes */
4762  Bitmapset *projindexattrs; /* columns used in projection indexes */
4763  Bitmapset *uindexattrs; /* columns in unique indexes */
4764  Bitmapset *pkindexattrs; /* columns in the primary index */
4765  Bitmapset *idindexattrs; /* columns in the replica identity */
4766  Bitmapset *projindexes; /* projection indexes */
4767  List *indexoidlist;
4768  List *newindexoidlist;
4769  Oid relpkindex;
4770  Oid relreplindex;
4771  ListCell *l;
4772  MemoryContext oldcxt;
4773  int indexno;
4774 
4775  /* Quick exit if we already computed the result. */
4776  if (relation->rd_indexattr != NULL)
4777  {
4778  switch (attrKind)
4779  {
4780  case INDEX_ATTR_BITMAP_HOT:
4781  return bms_copy(relation->rd_indexattr);
4783  return bms_copy(relation->rd_projindexattr);
4784  case INDEX_ATTR_BITMAP_KEY:
4785  return bms_copy(relation->rd_keyattr);
4787  return bms_copy(relation->rd_pkattr);
4789  return bms_copy(relation->rd_idattr);
4790  default:
4791  elog(ERROR, "unknown attrKind %u", attrKind);
4792  }
4793  }
4794 
4795  /* Fast path if definitely no indexes */
4796  if (!RelationGetForm(relation)->relhasindex)
4797  return NULL;
4798 
4799  /*
4800  * Get cached list of index OIDs. If we have to start over, we do so here.
4801  */
4802 restart:
4803  indexoidlist = RelationGetIndexList(relation);
4804 
4805  /* Fall out if no indexes (but relhasindex was set) */
4806  if (indexoidlist == NIL)
4807  return NULL;
4808 
4809  /*
4810  * Copy the rd_pkindex and rd_replidindex values computed by
4811  * RelationGetIndexList before proceeding. This is needed because a
4812  * relcache flush could occur inside index_open below, resetting the
4813  * fields managed by RelationGetIndexList. We need to do the work with
4814  * stable values of these fields.
4815  */
4816  relpkindex = relation->rd_pkindex;
4817  relreplindex = relation->rd_replidindex;
4818 
4819  /*
4820  * For each index, add referenced attributes to indexattrs.
4821  *
4822  * Note: we consider all indexes returned by RelationGetIndexList, even if
4823  * they are not indisready or indisvalid. This is important because an
4824  * index for which CREATE INDEX CONCURRENTLY has just started must be
4825  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
4826  * CONCURRENTLY is far enough along that we should ignore the index, it
4827  * won't be returned at all by RelationGetIndexList.
4828  */
4829  indexattrs = NULL;
4830  projindexattrs = NULL;
4831  uindexattrs = NULL;
4832  pkindexattrs = NULL;
4833  idindexattrs = NULL;
4834  projindexes = NULL;
4835  indexno = 0;
4836  foreach(l, indexoidlist)
4837  {
4838  Oid indexOid = lfirst_oid(l);
4839  Relation indexDesc;
4840  IndexInfo *indexInfo;
4841  int i;
4842  bool isKey; /* candidate key */
4843  bool isPK; /* primary key */
4844  bool isIDKey; /* replica identity index */
4845 
4846  indexDesc = index_open(indexOid, AccessShareLock);
4847 
4848  /* Extract index key information from the index's pg_index row */
4849  indexInfo = BuildIndexInfo(indexDesc);
4850 
4851  /* Can this index be referenced by a foreign key? */
4852  isKey = indexInfo->ii_Unique &&
4853  indexInfo->ii_Expressions == NIL &&
4854  indexInfo->ii_Predicate == NIL;
4855 
4856  /* Is this a primary key? */
4857  isPK = (indexOid == relpkindex);
4858 
4859  /* Is this index the configured (or default) replica identity? */
4860  isIDKey = (indexOid == relreplindex);
4861 
4862  /* Collect simple attribute references */
4863  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
4864  {
4865  int attrnum = indexInfo->ii_IndexAttrNumbers[i];
4866 
4867  /*
4868  * Since we have covering indexes with non-key columns, we must
4869  * handle them accurately here. non-key columns must be added into
4870  * indexattrs, since they are in index, and HOT-update shouldn't
4871  * miss them. Obviously, non-key columns couldn't be referenced by
4872  * foreign key or identity key. Hence we do not include them into
4873  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
4874  */
4875  if (attrnum != 0)
4876  {
4877  indexattrs = bms_add_member(indexattrs,
4879 
4880  if (isKey && i < indexInfo->ii_NumIndexKeyAttrs)
4881  uindexattrs = bms_add_member(uindexattrs,
4883 
4884  if (isPK && i < indexInfo->ii_NumIndexKeyAttrs)
4885  pkindexattrs = bms_add_member(pkindexattrs,
4887 
4888  if (isIDKey && i < indexInfo->ii_NumIndexKeyAttrs)
4889  idindexattrs = bms_add_member(idindexattrs,
4891  }
4892  }
4893 
4894  /* Collect attributes used in expressions, too */
4895  if (IsProjectionFunctionalIndex(indexDesc, indexInfo))
4896  {
4897  projindexes = bms_add_member(projindexes, indexno);
4898  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &projindexattrs);
4899  }
4900  else
4901  {
4902  /* Collect all attributes used in expressions, too */
4903  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
4904  }
4905  /* Collect all attributes in the index predicate, too */
4906  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
4907 
4908  index_close(indexDesc, AccessShareLock);
4909  indexno += 1;
4910  }
4911 
4912  /*
4913  * During one of the index_opens in the above loop, we might have received
4914  * a relcache flush event on this relcache entry, which might have been
4915  * signaling a change in the rel's index list. If so, we'd better start
4916  * over to ensure we deliver up-to-date attribute bitmaps.
4917  */
4918  newindexoidlist = RelationGetIndexList(relation);
4919  if (equal(indexoidlist, newindexoidlist) &&
4920  relpkindex == relation->rd_pkindex &&
4921  relreplindex == relation->rd_replidindex)
4922  {
4923  /* Still the same index set, so proceed */
4924  list_free(newindexoidlist);
4925  list_free(indexoidlist);
4926  }
4927  else
4928  {
4929  /* Gotta do it over ... might as well not leak memory */
4930  list_free(newindexoidlist);
4931  list_free(indexoidlist);
4932  bms_free(uindexattrs);
4933  bms_free(pkindexattrs);
4934  bms_free(idindexattrs);
4935  bms_free(indexattrs);
4936  bms_free(projindexattrs);
4937  bms_free(projindexes);
4938 
4939  goto restart;
4940  }
4941 
4942  /* Don't leak the old values of these bitmaps, if any */
4943  bms_free(relation->rd_indexattr);
4944  relation->rd_indexattr = NULL;
4945  bms_free(relation->rd_projindexattr);
4946  relation->rd_projindexattr = NULL;
4947  bms_free(relation->rd_keyattr);
4948  relation->rd_keyattr = NULL;
4949  bms_free(relation->rd_pkattr);
4950  relation->rd_pkattr = NULL;
4951  bms_free(relation->rd_idattr);
4952  relation->rd_idattr = NULL;
4953  bms_free(relation->rd_projidx);
4954  relation->rd_projidx = NULL;
4955 
4956  /*
4957  * Now save copies of the bitmaps in the relcache entry. We intentionally
4958  * set rd_indexattr last, because that's the one that signals validity of
4959  * the values; if we run out of memory before making that copy, we won't
4960  * leave the relcache entry looking like the other ones are valid but
4961  * empty.
4962  */
4964  relation->rd_keyattr = bms_copy(uindexattrs);
4965  relation->rd_pkattr = bms_copy(pkindexattrs);
4966  relation->rd_idattr = bms_copy(idindexattrs);
4967  relation->rd_indexattr = bms_copy(indexattrs);
4968  relation->rd_projindexattr = bms_copy(projindexattrs);
4969  relation->rd_projidx = bms_copy(projindexes);
4970  MemoryContextSwitchTo(oldcxt);
4971 
4972  /* We return our original working copy for caller to play with */
4973  switch (attrKind)
4974  {
4975  case INDEX_ATTR_BITMAP_HOT:
4976  return indexattrs;
4978  return projindexattrs;
4979  case INDEX_ATTR_BITMAP_KEY:
4980  return uindexattrs;
4982  return bms_copy(relation->rd_pkattr);
4984  return idindexattrs;
4985  default:
4986  elog(ERROR, "unknown attrKind %u", attrKind);
4987  return NULL;
4988  }
4989 }
#define NIL
Definition: pg_list.h:69
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:133
List * ii_Predicate
Definition: execnodes.h:156
Bitmapset * rd_keyattr
Definition: rel.h:116
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2986
Oid rd_replidindex
Definition: rel.h:108
#define RelationGetForm(relation)
Definition: rel.h:401
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:517
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1745
Bitmapset * rd_projidx
Definition: rel.h:119
unsigned int Oid
Definition: postgres_ext.h:31
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:219
#define ERROR
Definition: elog.h:43
Oid rd_pkindex
Definition: rel.h:107
int ii_NumIndexAttrs
Definition: execnodes.h:151
Bitmapset * rd_projindexattr
Definition: rel.h:115
static bool IsProjectionFunctionalIndex(Relation index, IndexInfo *ii)
Definition: relcache.c:4682
Bitmapset * rd_idattr
Definition: rel.h:118
bool ii_Unique
Definition: execnodes.h:164
void bms_free(Bitmapset *a)
Definition: bitmapset.c:267
List * ii_Expressions
Definition: execnodes.h:154
bool relhasindex
Definition: pg_class.h:48
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
Bitmapset * rd_pkattr
Definition: rel.h:117
void list_free(List *list)
Definition: list.c:1133
int i
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
Definition: pg_list.h:45
Bitmapset * rd_indexattr
Definition: rel.h:114
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

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

4547 {
4548  List *result;
4549  Datum exprsDatum;
4550  bool isnull;
4551  char *exprsString;
4552  MemoryContext oldcxt;
4553 
4554  /* Quick exit if we already computed the result. */
4555  if (relation->rd_indexprs)
4556  return copyObject(relation->rd_indexprs);
4557 
4558  /* Quick exit if there is nothing to do. */
4559  if (relation->rd_indextuple == NULL ||
4560  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4561  return NIL;
4562 
4563  /*
4564  * We build the tree we intend to return in the caller's context. After
4565  * successfully completing the work, we copy it into the relcache entry.
4566  * This avoids problems if we get some sort of error partway through.
4567  */
4568  exprsDatum = heap_getattr(relation->rd_indextuple,
4569  Anum_pg_index_indexprs,
4571  &isnull);
4572  Assert(!isnull);
4573  exprsString = TextDatumGetCString(exprsDatum);
4574  result = (List *) stringToNode(exprsString);
4575  pfree(exprsString);
4576 
4577  /*
4578  * Run the expressions through eval_const_expressions. This is not just an
4579  * optimization, but is necessary, because the planner will be comparing
4580  * them to similarly-processed qual clauses, and may fail to detect valid
4581  * matches without this. We must not use canonicalize_qual, however,
4582  * since these aren't qual expressions.
4583  */
4584  result = (List *) eval_const_expressions(NULL, (Node *) result);
4585 
4586  /* May as well fix opfuncids too */
4587  fix_opfuncids((Node *) result);
4588 
4589  /* Now save a copy of the completed tree in the relcache entry. */
4590  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4591  relation->rd_indexprs = copyObject(result);
4592  MemoryContextSwitchTo(oldcxt);
4593 
4594  return result;
4595 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:39
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * rd_indexprs
Definition: rel.h:159
Definition: nodes.h:517
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2460
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
struct HeapTupleData * rd_indextuple
Definition: rel.h:133
void pfree(void *pointer)
Definition: mcxt.c:1031
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:3846
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:781
#define TextDatumGetCString(d)
Definition: builtins.h:96
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:699
MemoryContext rd_indexcxt
Definition: rel.h:151
#define copyObject(obj)
Definition: nodes.h:630
Definition: pg_list.h:45

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4190 of file relcache.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, CacheMemoryContext, DatumGetPointer, GetPgIndexDescriptor(), GETSTRUCT, heap_attisnull(), heap_close, heap_getattr, heap_open(), HeapTupleIsValid, IndexIndrelidIndexId, IndexIsLive, IndexIsValid, insert_ordered_oid(), InvalidOid, list_copy(), list_free(), MemoryContextSwitchTo(), NIL, ObjectIdAttributeNumber, ObjectIdGetDatum, OidIsValid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_oidindex, RelationData::rd_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and oidvector::values.

Referenced by AlterIndexNamespaces(), ATExecChangeOwner(), ATExecDetachPartition(), ATExecDropNotNull(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), get_relation_info(), infer_arbiter_indexes(), mark_index_clustered(), ProjIndexIsUnchanged(), refresh_by_match_merge(), reindex_relation(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetOidIndex(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationHasUnloggedIndex(), RelationTruncateIndexes(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), transformTableLikeClause(), triggered_change_notification(), and vac_open_indexes().

4191 {
4192  Relation indrel;
4193  SysScanDesc indscan;
4194  ScanKeyData skey;
4195  HeapTuple htup;
4196  List *result;
4197  List *oldlist;
4198  char replident = relation->rd_rel->relreplident;
4199  Oid oidIndex = InvalidOid;
4200  Oid pkeyIndex = InvalidOid;
4201  Oid candidateIndex = InvalidOid;
4202  MemoryContext oldcxt;
4203 
4204  /* Quick exit if we already computed the list. */
4205  if (relation->rd_indexvalid != 0)
4206  return list_copy(relation->rd_indexlist);
4207 
4208  /*
4209  * We build the list we intend to return (in the caller's context) while
4210  * doing the scan. After successfully completing the scan, we copy that
4211  * list into the relcache entry. This avoids cache-context memory leakage
4212  * if we get some sort of error partway through.
4213  */
4214  result = NIL;
4215  oidIndex = InvalidOid;
4216 
4217  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4218  ScanKeyInit(&skey,
4219  Anum_pg_index_indrelid,
4220  BTEqualStrategyNumber, F_OIDEQ,
4221  ObjectIdGetDatum(RelationGetRelid(relation)));
4222 
4223  indrel = heap_open(IndexRelationId, AccessShareLock);
4224  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4225  NULL, 1, &skey);
4226 
4227  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4228  {
4230  Datum indclassDatum;
4231  oidvector *indclass;
4232  bool isnull;
4233 
4234  /*
4235  * Ignore any indexes that are currently being dropped. This will
4236  * prevent them from being searched, inserted into, or considered in
4237  * HOT-safety decisions. It's unsafe to touch such an index at all
4238  * since its catalog entries could disappear at any instant.
4239  */
4240  if (!IndexIsLive(index))
4241  continue;
4242 
4243  /* Add index's OID to result list in the proper order */
4244  result = insert_ordered_oid(result, index->indexrelid);
4245 
4246  /*
4247  * indclass cannot be referenced directly through the C struct,
4248  * because it comes after the variable-width indkey field. Must
4249  * extract the datum the hard way...
4250  */
4251  indclassDatum = heap_getattr(htup,
4252  Anum_pg_index_indclass,
4254  &isnull);
4255  Assert(!isnull);
4256  indclass = (oidvector *) DatumGetPointer(indclassDatum);
4257 
4258  /*
4259  * Invalid, non-unique, non-immediate or predicate indexes aren't
4260  * interesting for either oid indexes or replication identity indexes,
4261  * so don't check them.
4262  */
4263  if (!IndexIsValid(index) || !index->indisunique ||
4264  !index->indimmediate ||
4265  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4266  continue;
4267 
4268  /* Check to see if is a usable btree index on OID */
4269  if (index->indnatts == 1 &&
4270  index->indkey.values[0] == ObjectIdAttributeNumber &&
4271  indclass->values[0] == OID_BTREE_OPS_OID)
4272  oidIndex = index->indexrelid;
4273 
4274  /* remember primary key index if any */
4275  if (index->indisprimary)
4276  pkeyIndex = index->indexrelid;
4277 
4278  /* remember explicitly chosen replica index */
4279  if (index->indisreplident)
4280  candidateIndex = index->indexrelid;
4281  }
4282 
4283  systable_endscan(indscan);
4284 
4285  heap_close(indrel, AccessShareLock);
4286 
4287  /* Now save a copy of the completed list in the relcache entry. */
4289  oldlist = relation->rd_indexlist;
4290  relation->rd_indexlist = list_copy(result);
4291  relation->rd_oidindex = oidIndex;
4292  relation->rd_pkindex = pkeyIndex;
4293  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4294  relation->rd_replidindex = pkeyIndex;
4295  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4296  relation->rd_replidindex = candidateIndex;
4297  else
4298  relation->rd_replidindex = InvalidOid;
4299  relation->rd_indexvalid = 1;
4300  MemoryContextSwitchTo(oldcxt);
4301 
4302  /* Don't leak the old list, if there is one */
4303  list_free(oldlist);
4304 
4305  return result;
4306 }
#define NIL
Definition: pg_list.h:69
Definition: c.h:555
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define IndexIsValid(indexForm)
Definition: pg_index.h:85
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
Oid rd_replidindex
Definition: rel.h:108
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
static List * insert_ordered_oid(List *list, Oid datum)
Definition: relcache.c:4396
List * list_copy(const List *oldlist)
Definition: list.c:1160
#define IndexIsLive(indexForm)
Definition: pg_index.h:87
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
Definition: type.h:89
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
Oid rd_pkindex
Definition: rel.h:107
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:3846
char rd_indexvalid
Definition: rel.h:63
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:563
Oid rd_oidindex
Definition: rel.h:106
List * rd_indexlist
Definition: rel.h:105
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:781
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
uintptr_t Datum
Definition: postgres.h:367
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define DatumGetPointer(X)
Definition: postgres.h:534
void list_free(List *list)
Definition: list.c:1133
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define IndexIndrelidIndexId
Definition: indexing.h:163
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

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

4609 {
4610  List *result;
4611  Datum predDatum;
4612  bool isnull;
4613  char *predString;
4614  MemoryContext oldcxt;
4615 
4616  /* Quick exit if we already computed the result. */
4617  if (relation->rd_indpred)
4618  return copyObject(relation->rd_indpred);
4619 
4620  /* Quick exit if there is nothing to do. */
4621  if (relation->rd_indextuple == NULL ||
4622  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
4623  return NIL;
4624 
4625  /*
4626  * We build the tree we intend to return in the caller's context. After
4627  * successfully completing the work, we copy it into the relcache entry.
4628  * This avoids problems if we get some sort of error partway through.
4629  */
4630  predDatum = heap_getattr(relation->rd_indextuple,
4631  Anum_pg_index_indpred,
4633  &isnull);
4634  Assert(!isnull);
4635  predString = TextDatumGetCString(predDatum);
4636  result = (List *) stringToNode(predString);
4637  pfree(predString);
4638 
4639  /*
4640  * Run the expression through const-simplification and canonicalization.
4641  * This is not just an optimization, but is necessary, because the planner
4642  * will be comparing it to similarly-processed qual clauses, and may fail
4643  * to detect valid matches without this. This must match the processing
4644  * done to qual clauses in preprocess_expression()! (We can skip the
4645  * stuff involving subqueries, however, since we don't allow any in index
4646  * predicates.)
4647  */
4648  result = (List *) eval_const_expressions(NULL, (Node *) result);
4649 
4650  result = (List *) canonicalize_qual((Expr *) result, false);
4651 
4652  /* Also convert to implicit-AND format */
4653  result = make_ands_implicit((Expr *) result);
4654 
4655  /* May as well fix opfuncids too */
4656  fix_opfuncids((Node *) result);
4657 
4658  /* Now save a copy of the completed tree in the relcache entry. */
4659  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4660  relation->rd_indpred = copyObject(result);
4661  MemoryContextSwitchTo(oldcxt);
4662 
4663  return result;
4664 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:39
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:517
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2460
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
struct HeapTupleData * rd_indextuple
Definition: rel.h:133
void pfree(void *pointer)
Definition: mcxt.c:1031
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:379
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:3846
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:291
List * rd_indpred
Definition: rel.h:160
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:781
#define TextDatumGetCString(d)
Definition: builtins.h:96
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:699
MemoryContext rd_indexcxt
Definition: rel.h:151
#define copyObject(obj)
Definition: nodes.h:630
Definition: pg_list.h:45

◆ RelationGetOidIndex()

Oid RelationGetOidIndex ( Relation  relation)

Definition at line 4472 of file relcache.c.

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

Referenced by GetNewOid().

4473 {
4474  List *ilist;
4475 
4476  /*
4477  * If relation doesn't have OIDs at all, caller is probably confused. (We
4478  * could just silently return InvalidOid, but it seems better to throw an
4479  * assertion.)
4480  */
4481  Assert(relation->rd_rel->relhasoids);
4482 
4483  if (relation->rd_indexvalid == 0)
4484  {
4485  /* RelationGetIndexList does the heavy lifting. */
4486  ilist = RelationGetIndexList(relation);
4487  list_free(ilist);
4488  Assert(relation->rd_indexvalid != 0);
4489  }
4490 
4491  return relation->rd_oidindex;
4492 }
Form_pg_class rd_rel
Definition: rel.h:84
char rd_indexvalid
Definition: rel.h:63
Oid rd_oidindex
Definition: rel.h:106
#define Assert(condition)
Definition: c.h:699
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4500 of file relcache.c.

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

Referenced by GetRelationIdentityOrPK().

4501 {
4502  List *ilist;
4503 
4504  if (relation->rd_indexvalid == 0)
4505  {
4506  /* RelationGetIndexList does the heavy lifting. */
4507  ilist = RelationGetIndexList(relation);
4508  list_free(ilist);
4509  Assert(relation->rd_indexvalid != 0);
4510  }
4511 
4512  return relation->rd_pkindex;
4513 }
Oid rd_pkindex
Definition: rel.h:107
char rd_indexvalid
Definition: rel.h:63
#define Assert(condition)
Definition: c.h:699
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4521 of file relcache.c.

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

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

4522 {
4523  List *ilist;
4524 
4525  if (relation->rd_indexvalid == 0)
4526  {
4527  /* RelationGetIndexList does the heavy lifting. */
4528  ilist = RelationGetIndexList(relation);
4529  list_free(ilist);
4530  Assert(relation->rd_indexvalid != 0);
4531  }
4532 
4533  return relation->rd_replidindex;
4534 }
Oid rd_replidindex
Definition: rel.h:108
char rd_indexvalid
Definition: rel.h:63
#define Assert(condition)
Definition: c.h:699
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4330 of file relcache.c.

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, insert_ordered_oid(), list_copy(), list_free(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum, RelationData::rd_statlist, RelationData::rd_statvalid, RelationGetRelid, ScanKeyInit(), StatisticExtRelidIndexId, systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by get_relation_statistics(), and transformTableLikeClause().

4331 {
4332  Relation indrel;
4333  SysScanDesc indscan;
4334  ScanKeyData skey;
4335  HeapTuple htup;
4336  List *result;
4337  List *oldlist;
4338  MemoryContext oldcxt;
4339 
4340  /* Quick exit if we already computed the list. */
4341  if (relation->rd_statvalid != 0)
4342  return list_copy(relation->rd_statlist);
4343 
4344  /*
4345  * We build the list we intend to return (in the caller's context) while
4346  * doing the scan. After successfully completing the scan, we copy that
4347  * list into the relcache entry. This avoids cache-context memory leakage
4348  * if we get some sort of error partway through.
4349  */
4350  result = NIL;
4351 
4352  /*
4353  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4354  * rel.
4355  */
4356  ScanKeyInit(&skey,
4357  Anum_pg_statistic_ext_stxrelid,
4358  BTEqualStrategyNumber, F_OIDEQ,
4359  ObjectIdGetDatum(RelationGetRelid(relation)));
4360 
4361  indrel = heap_open(StatisticExtRelationId, AccessShareLock);
4362  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4363  NULL, 1, &skey);
4364 
4365  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4366  result = insert_ordered_oid(result, HeapTupleGetOid(htup));
4367 
4368  systable_endscan(indscan);
4369 
4370  heap_close(indrel, AccessShareLock);
4371 
4372  /* Now save a copy of the completed list in the relcache entry. */
4374  oldlist = relation->rd_statlist;
4375  relation->rd_statlist = list_copy(result);
4376 
4377  relation->rd_statvalid = true;
4378  MemoryContextSwitchTo(oldcxt);
4379 
4380  /* Don't leak the old list, if there is one */
4381  list_free(oldlist);
4382 
4383  return result;
4384 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
static List * insert_ordered_oid(List *list, Oid datum)
Definition: relcache.c:4396
List * list_copy(const List *oldlist)
Definition: list.c:1160
#define heap_close(r, l)
Definition: heapam.h:97
#define StatisticExtRelidIndexId
Definition: indexing.h:191
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool rd_statvalid
Definition: rel.h:65
void list_free(List *list)
Definition: list.c:1133
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
List * rd_statlist
Definition: rel.h:111
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 1906 of file relcache.c.

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

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

1907 {
1908  Relation rd;
1909 
1910  /* Make sure we're in an xact, even if this ends up being a cache hit */
1912 
1913  /*
1914  * first try to find reldesc in the cache
1915  */
1916  RelationIdCacheLookup(relationId, rd);
1917 
1918  if (RelationIsValid(rd))
1919  {
1921  /* revalidate cache entry if necessary */
1922  if (!rd->rd_isvalid)
1923  {
1924  /*
1925  * Indexes only have a limited number of possible schema changes,
1926  * and we don't want to use the full-blown procedure because it's
1927  * a headache for indexes that reload itself depends on.
1928  */
1929  if (rd->rd_rel->relkind == RELKIND_INDEX ||
1930  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
1932  else
1933  RelationClearRelation(rd, true);
1934  Assert(rd->rd_isvalid);
1935  }
1936  return rd;
1937  }
1938 
1939  /*
1940  * no reldesc in the cache, so have RelationBuildDesc() build one and add
1941  * it.
1942  */
1943  rd = RelationBuildDesc(relationId, true);
1944  if (RelationIsValid(rd))
1946  return rd;
1947 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:204
bool rd_isvalid
Definition: rel.h:62
Form_pg_class rd_rel
Definition: rel.h:84
#define RelationIsValid(relation)
Definition: rel.h:380
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:1963
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2037
#define Assert(condition)
Definition: c.h:699
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1071
bool IsTransactionState(void)
Definition: xact.c:350

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 5923 of file relcache.c.

References Assert, RelationSupportsSysCache(), and TriggerRelidNameIndexId.

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

5924 {
5925  if (relationId == TriggerRelidNameIndexId)
5926  {
5927  /* If this Assert fails, we don't need this special case anymore. */
5928  Assert(!RelationSupportsSysCache(relationId));
5929  return true;
5930  }
5931  return RelationSupportsSysCache(relationId);
5932 }
#define TriggerRelidNameIndexId
Definition: indexing.h:250
#define Assert(condition)
Definition: c.h:699
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1512

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1343 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_amroutine, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, 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().

1344 {
1345  HeapTuple tuple;
1346  Form_pg_am aform;
1347  Datum indcollDatum;
1348  Datum indclassDatum;
1349  Datum indoptionDatum;
1350  bool isnull;
1351  oidvector *indcoll;
1352  oidvector *indclass;
1353  int2vector *indoption;
1354  MemoryContext indexcxt;
1355  MemoryContext oldcontext;
1356  int indnatts;
1357  int indnkeyatts;
1358  uint16 amsupport;
1359 
1360  /*
1361  * Make a copy of the pg_index entry for the index. Since pg_index
1362  * contains variable-length and possibly-null fields, we have to do this
1363  * honestly rather than just treating it as a Form_pg_index struct.
1364  */
1365  tuple = SearchSysCache1(INDEXRELID,
1366  ObjectIdGetDatum(RelationGetRelid(relation)));
1367  if (!HeapTupleIsValid(tuple))
1368  elog(ERROR, "cache lookup failed for index %u",
1369  RelationGetRelid(relation));
1371  relation->rd_indextuple = heap_copytuple(tuple);
1372  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1373  MemoryContextSwitchTo(oldcontext);
1374  ReleaseSysCache(tuple);
1375 
1376  /*
1377  * Look up the index's access method, save the OID of its handler function
1378  */
1379  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1380  if (!HeapTupleIsValid(tuple))
1381  elog(ERROR, "cache lookup failed for access method %u",
1382  relation->rd_rel->relam);
1383  aform = (Form_pg_am) GETSTRUCT(tuple);
1384  relation->rd_amhandler = aform->amhandler;
1385  ReleaseSysCache(tuple);
1386 
1387  indnatts = RelationGetNumberOfAttributes(relation);
1388  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1389  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1390  RelationGetRelid(relation));
1391  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1392 
1393  /*
1394  * Make the private context to hold index access info. The reason we need
1395  * a context, and not just a couple of pallocs, is so that we won't leak
1396  * any subsidiary info attached to fmgr lookup records.
1397  */
1399  "index info",
1401  relation->rd_indexcxt = indexcxt;
1403  RelationGetRelationName(relation));
1404 
1405  /*
1406  * Now we can fetch the index AM's API struct
1407  */
1408  InitIndexAmRoutine(relation);
1409 
1410  /*
1411  * Allocate arrays to hold data. Opclasses are not used for included
1412  * columns, so allocate them for indnkeyatts only.
1413  */
1414  relation->rd_opfamily = (Oid *)
1415  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1416  relation->rd_opcintype = (Oid *)
1417  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1418 
1419  amsupport = relation->rd_amroutine->amsupport;
1420  if (amsupport > 0)
1421  {
1422  int nsupport = indnatts * amsupport;
1423 
1424  relation->rd_support = (RegProcedure *)
1425  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1426  relation->rd_supportinfo = (FmgrInfo *)
1427  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1428  }
1429  else
1430  {
1431  relation->rd_support = NULL;
1432  relation->rd_supportinfo = NULL;
1433  }
1434 
1435  relation->rd_indcollation = (Oid *)
1436  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1437 
1438  relation->rd_indoption = (int16 *)
1439  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1440 
1441  /*
1442  * indcollation cannot be referenced directly through the C struct,
1443  * because it comes after the variable-width indkey field. Must extract
1444  * the datum the hard way...
1445  */
1446  indcollDatum = fastgetattr(relation->rd_indextuple,
1447  Anum_pg_index_indcollation,
1449  &isnull);
1450  Assert(!isnull);
1451  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1452  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1453 
1454  /*
1455  * indclass cannot be referenced directly through the C struct, because it
1456  * comes after the variable-width indkey field. Must extract the datum
1457  * the hard way...
1458  */
1459  indclassDatum = fastgetattr(relation->rd_indextuple,
1460  Anum_pg_index_indclass,
1462  &isnull);
1463  Assert(!isnull);
1464  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1465 
1466  /*
1467  * Fill the support procedure OID array, as well as the info about
1468  * opfamilies and opclass input types. (aminfo and supportinfo are left
1469  * as zeroes, and are filled on-the-fly when used)
1470  */
1471  IndexSupportInitialize(indclass, relation->rd_support,
1472  relation->rd_opfamily, relation->rd_opcintype,
1473  amsupport, indnkeyatts);
1474 
1475  /*
1476  * Similarly extract indoption and copy it to the cache entry
1477  */
1478  indoptionDatum = fastgetattr(relation->rd_indextuple,
1479  Anum_pg_index_indoption,
1481  &isnull);
1482  Assert(!isnull);
1483  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1484  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1485 
1486  /*
1487  * expressions, predicate, exclusion caches will be filled later
1488  */
1489  relation->rd_indexprs = NIL;
1490  relation->rd_indpred = NIL;
1491  relation->rd_exclops = NULL;
1492  relation->rd_exclprocs = NULL;
1493  relation->rd_exclstrats = NULL;
1494  relation->rd_amcache = NULL;
1495 }
signed short int16
Definition: c.h:312
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
#define NIL
Definition: pg_list.h:69
Definition: c.h:555
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:170
int16 * rd_indoption
Definition: rel.h:158
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:731
Definition: syscache.h:36
FmgrInfo * rd_supportinfo
Definition: rel.h:157
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
regproc RegProcedure
Definition: c.h:472
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uint16 * rd_exclstrats
Definition: rel.h:163
List * rd_indexprs
Definition: rel.h:159
Oid * rd_exclprocs
Definition: rel.h:162
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:153
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1319
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1511
struct HeapTupleData * rd_indextuple
Definition: rel.h:133
Form_pg_index rd_index
Definition: rel.h:131
unsigned short uint16
Definition: c.h:324
Oid * rd_indcollation
Definition: rel.h:165
Oid rd_amhandler
Definition: rel.h:150
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:96
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:3846
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:563
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:419
#define RelationGetRelationName(relation)
Definition: rel.h:441
List * rd_indpred
Definition: rel.h:160
Oid * rd_opfamily
Definition: rel.h:154
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:426
Oid * rd_exclops
Definition: rel.h:161
RegProcedure * rd_support
Definition: rel.h:156
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
Definition: c.h:544
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:552
#define DatumGetPointer(X)
Definition: postgres.h:534
FormData_pg_am * Form_pg_am
Definition: pg_am.h:46
MemoryContext rd_indexcxt
Definition: rel.h:151
#define elog
Definition: elog.h:219
void * rd_amcache
Definition: rel.h:164
Oid * rd_opcintype
Definition: rel.h:155
#define RelationGetRelid(relation)
Definition: rel.h:407
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationSetIndexList()

void RelationSetIndexList ( Relation  relation,
List indexIds,
Oid  oidIndex 
)

Definition at line 4441 of file relcache.c.

References Assert, CacheMemoryContext, EOXactListAdd, InvalidOid, list_copy(), list_free(), MemoryContextSwitchTo(), RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_isnailed, RelationData::rd_oidindex, RelationData::rd_pkindex, and RelationData::rd_replidindex.

Referenced by reindex_relation().

4442 {
4443  MemoryContext oldcxt;
4444 
4445  Assert(relation->rd_isnailed);
4446  /* Copy the list into the cache context (could fail for lack of mem) */
4448  indexIds = list_copy(indexIds);
4449  MemoryContextSwitchTo(oldcxt);
4450  /* Okay to replace old list */
4451  list_free(relation->rd_indexlist);
4452  relation->rd_indexlist = indexIds;
4453  relation->rd_oidindex = oidIndex;
4454 
4455  /*
4456  * For the moment, assume the target rel hasn't got a pk or replica index.
4457  * We'll load them on demand in the API that wraps access to them.
4458  */
4459  relation->rd_pkindex = InvalidOid;
4460  relation->rd_replidindex = InvalidOid;
4461  relation->rd_indexvalid = 2; /* mark list as forced */
4462  /* Flag relation as needing eoxact cleanup (to reset the list) */
4463  EOXactListAdd(relation);
4464 }
#define EOXactListAdd(rel)
Definition: relcache.c:162
Oid rd_replidindex
Definition: rel.h:108
bool rd_isnailed
Definition: rel.h:61
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * list_copy(const List *oldlist)
Definition: list.c:1160
Oid rd_pkindex
Definition: rel.h:107
char rd_indexvalid
Definition: rel.h:63
Oid rd_oidindex
Definition: rel.h:106
List * rd_indexlist
Definition: rel.h:105
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:699
void list_free(List *list)
Definition: list.c:1133
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence,
TransactionId  freezeXid,
MultiXactId  minmulti 
)

Definition at line 3264 of file relcache.c.

References Assert, RelFileNodeBackend::backend, CatalogTupleUpdate(), CommandCounterIncrement(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), GetNewRelFileNode(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvalidTransactionId, MultiXactIdIsValid, RelFileNodeBackend::node, ObjectIdGetDatum, RelationData::rd_backend, RelationData::rd_newRelfilenodeSubid, RelationData::rd_node, RelationData::rd_rel, RelationCreateStorage(), RelationDropStorage(), RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileNode::relNode, RELOID, RowExclusiveLock, SearchSysCacheCopy1, smgrclosenode(), HeapTupleData::t_self, and TransactionIdIsNormal.

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

3266 {
3267  Oid newrelfilenode;
3268  RelFileNodeBackend newrnode;
3269  Relation pg_class;
3270  HeapTuple tuple;
3271  Form_pg_class classform;
3272 
3273  /* Indexes, sequences must have Invalid frozenxid; other rels must not */
3274  Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
3275  relation->rd_rel->relkind == RELKIND_SEQUENCE) ?
3276  freezeXid == InvalidTransactionId :
3277  TransactionIdIsNormal(freezeXid));
3278  Assert(TransactionIdIsNormal(freezeXid) == MultiXactIdIsValid(minmulti));
3279 
3280  /* Allocate a new relfilenode */
3281  newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
3282  persistence);
3283 
3284  /*
3285  * Get a writable copy of the pg_class tuple for the given relation.
3286  */
3287  pg_class = heap_open(RelationRelationId, RowExclusiveLock);
3288 
3289  tuple = SearchSysCacheCopy1(RELOID,
3290  ObjectIdGetDatum(RelationGetRelid(relation)));
3291  if (!HeapTupleIsValid(tuple))
3292  elog(ERROR, "could not find tuple for relation %u",
3293  RelationGetRelid(relation));
3294  classform = (Form_pg_class) GETSTRUCT(tuple);
3295 
3296  /*
3297  * Create storage for the main fork of the new relfilenode.
3298  *
3299  * NOTE: any conflict in relfilenode value will be caught here, if
3300  * GetNewRelFileNode messes up for any reason.
3301  */
3302  newrnode.node = relation->rd_node;
3303  newrnode.node.relNode = newrelfilenode;
3304  newrnode.backend = relation->rd_backend;
3305  RelationCreateStorage(newrnode.node, persistence);
3306  smgrclosenode(newrnode);
3307 
3308  /*
3309  * Schedule unlinking of the old storage at transaction commit.
3310  */
3311  RelationDropStorage(relation);
3312 
3313  /*
3314  * Now update the pg_class row. However, if we're dealing with a mapped
3315  * index, pg_class.relfilenode doesn't change; instead we have to send the
3316  * update to the relation mapper.
3317  */
3318  if (RelationIsMapped(relation))
3320  newrelfilenode,
3321  relation->rd_rel->relisshared,
3322  false);
3323  else
3324  classform->relfilenode = newrelfilenode;
3325 
3326  /* These changes are safe even for a mapped relation */
3327  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3328  {
3329  classform->relpages = 0; /* it's empty until further notice */
3330  classform->reltuples = 0;
3331  classform->relallvisible = 0;
3332  }
3333  classform->relfrozenxid = freezeXid;
3334  classform->relminmxid = minmulti;
3335  classform->relpersistence = persistence;
3336 
3337  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3338 
3339  heap_freetuple(tuple);
3340 
3341  heap_close(pg_class, RowExclusiveLock);
3342 
3343  /*
3344  * Make the pg_class row change visible, as well as the relation map
3345  * change if any. This will cause the relcache entry to get updated, too.
3346  */
3348 
3349  /*
3350  * Mark the rel as having been given a new relfilenode in the current
3351  * (sub) transaction. This is a hint that can be used to optimize later
3352  * operations on the rel in the same transaction.
3353  */
3355 
3356  /* Flag relation as needing eoxact cleanup (to remove the hint) */
3357  EOXactListAdd(relation);
3358 }
#define EOXactListAdd(rel)
Definition: relcache.c:162
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
void smgrclosenode(RelFileNodeBackend rnode)
Definition: smgr.c:350
#define RelationIsMapped(relation)
Definition: rel.h:458
void RelationDropStorage(Relation rel)
Definition: storage.c:144
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
RelFileNode node
Definition: relfilenode.h:74
RelFileNode rd_node
Definition: rel.h:55
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:699
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
BackendId backend
Definition: relfilenode.h:75
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:396
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define elog
Definition: elog.h:219
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
void RelationCreateStorage(RelFileNode rnode, char relpersistence)
Definition: storage.c:77
#define RelationGetRelid(relation)
Definition: rel.h:407
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

bool criticalSharedRelcachesBuilt