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"
 
#define AssertPendingSyncs_RelationCache()   do {} while (0)
 

Typedefs

typedef struct RelationDataRelation
 
typedef RelationRelationPtr
 
typedef enum IndexAttrBitmapKind IndexAttrBitmapKind
 

Enumerations

enum  IndexAttrBitmapKind { INDEX_ATTR_BITMAP_KEY , INDEX_ATTR_BITMAP_PRIMARY_KEY , INDEX_ATTR_BITMAP_IDENTITY_KEY , INDEX_ATTR_BITMAP_HOT_BLOCKING }
 

Functions

Relation RelationIdGetRelation (Oid relationId)
 
void RelationClose (Relation relation)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetDummyIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (Relation relation)
 
DatumRelationGetIndexRawAttOptions (Relation relation)
 
bytea ** RelationGetIndexAttOptions (Relation relation, bool copy)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
BitmapsetRelationGetIdentityKeyBitmap (Relation relation)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
void RelationInitIndexAccessInfo (Relation relation)
 
void RelationBuildPublicationDesc (Relation relation, struct PublicationDesc *pubdesc)
 
void RelationInitTableAccessMethod (Relation relation)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
void RelationCacheInitialize (void)
 
void RelationCacheInitializePhase2 (void)
 
void RelationCacheInitializePhase3 (void)
 
Relation RelationBuildLocalRelation (const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid accessmtd, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence)
 
void RelationAssumeNewRelfilenode (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (bool debug_discard)
 
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

PGDLLIMPORT bool criticalRelcachesBuilt
 
PGDLLIMPORT bool criticalSharedRelcachesBuilt
 

Macro Definition Documentation

◆ AssertPendingSyncs_RelationCache

#define AssertPendingSyncs_RelationCache ( )    do {} while (0)

Definition at line 133 of file relcache.h.

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Definition at line 24 of file relcache.h.

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

typedef struct RelationData* Relation

Definition at line 26 of file relcache.h.

◆ RelationPtr

Definition at line 34 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 
INDEX_ATTR_BITMAP_HOT_BLOCKING 

Definition at line 56 of file relcache.h.

57 {
IndexAttrBitmapKind
Definition: relcache.h:57
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:58
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:59
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:60

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3320 of file relcache.c.

3322 {
3324  RelIdCacheEnt *idhentry;
3325  int i;
3326 
3327  /*
3328  * Forget in_progress_list. This is relevant when we're aborting due to
3329  * an error during RelationBuildDesc(). We don't commit subtransactions
3330  * during RelationBuildDesc().
3331  */
3332  Assert(in_progress_list_len == 0 || !isCommit);
3334 
3335  /*
3336  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3337  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3338  * logic as in AtEOXact_RelationCache.
3339  */
3341  {
3343  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3344  {
3345  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3346  mySubid, parentSubid);
3347  }
3348  }
3349  else
3350  {
3351  for (i = 0; i < eoxact_list_len; i++)
3352  {
3353  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3354  (void *) &eoxact_list[i],
3355  HASH_FIND,
3356  NULL);
3357  if (idhentry != NULL)
3358  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3359  mySubid, parentSubid);
3360  }
3361  }
3362 
3363  /* Don't reset the list; we still need more cleanup later */
3364 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:184
static int in_progress_list_len
Definition: relcache.c:170
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3375
static int eoxact_list_len
Definition: relcache.c:185
static bool eoxact_list_overflowed
Definition: relcache.c:186
static HTAB * RelationIdCache
Definition: relcache.c:133
Relation reldesc
Definition: relcache.c:130

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3168 of file relcache.c.

3169 {
3171  RelIdCacheEnt *idhentry;
3172  int i;
3173 
3174  /*
3175  * Forget in_progress_list. This is relevant when we're aborting due to
3176  * an error during RelationBuildDesc().
3177  */
3178  Assert(in_progress_list_len == 0 || !isCommit);
3180 
3181  /*
3182  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3183  * listed in it. Otherwise fall back on a hash_seq_search scan.
3184  *
3185  * For simplicity, eoxact_list[] entries are not deleted till end of
3186  * top-level transaction, even though we could remove them at
3187  * subtransaction end in some cases, or remove relations from the list if
3188  * they are cleared for other reasons. Therefore we should expect the
3189  * case that list entries are not found in the hashtable; if not, there's
3190  * nothing to do for them.
3191  */
3193  {
3195  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3196  {
3197  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3198  }
3199  }
3200  else
3201  {
3202  for (i = 0; i < eoxact_list_len; i++)
3203  {
3204  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3205  (void *) &eoxact_list[i],
3206  HASH_FIND,
3207  NULL);
3208  if (idhentry != NULL)
3209  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3210  }
3211  }
3212 
3213  if (EOXactTupleDescArrayLen > 0)
3214  {
3215  Assert(EOXactTupleDescArray != NULL);
3216  for (i = 0; i < NextEOXactTupleDescNum; i++)
3219  EOXactTupleDescArray = NULL;
3220  }
3221 
3222  /* Now we're out of the transaction and can clear the lists */
3223  eoxact_list_len = 0;
3224  eoxact_list_overflowed = false;
3227 }
void pfree(void *pointer)
Definition: mcxt.c:1175
static int NextEOXactTupleDescNum
Definition: relcache.c:202
static int EOXactTupleDescArrayLen
Definition: relcache.c:203
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3238
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:201
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309

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

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5819 of file relcache.c.

5820 {
5824 
5825  return 0; /* return value does not matter */
5826 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1346
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define RelationGetRelationName(relation)
Definition: rel.h:523
#define RelationGetNamespace(relation)
Definition: rel.h:530

References err_generic_string(), get_namespace_name(), PG_DIAG_SCHEMA_NAME, PG_DIAG_TABLE_NAME, RelationGetNamespace, and RelationGetRelationName.

Referenced by ATPrepChangePersistence(), ATRewriteTable(), BuildRelationExtStatistics(), check_default_partition_contents(), errtablecolname(), errtableconstraint(), ExecFindPartition(), and ExecPartitionCheckEmitError().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5836 of file relcache.c.

5837 {
5838  TupleDesc reldesc = RelationGetDescr(rel);
5839  const char *colname;
5840 
5841  /* Use reldesc if it's a user attribute, else consult the catalogs */
5842  if (attnum > 0 && attnum <= reldesc->natts)
5843  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5844  else
5845  colname = get_attname(RelationGetRelid(rel), attnum, false);
5846 
5847  return errtablecolname(rel, colname);
5848 }
#define NameStr(name)
Definition: c.h:681
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:83
#define RelationGetRelid(relation)
Definition: rel.h:489
#define RelationGetDescr(relation)
Definition: rel.h:515
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5860
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References attname, attnum, errtablecolname(), get_attname(), NameStr, RelationGetDescr, RelationGetRelid, and TupleDescAttr.

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5860 of file relcache.c.

5861 {
5862  errtable(rel);
5864 
5865  return 0; /* return value does not matter */
5866 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int errtable(Relation rel)
Definition: relcache.c:5819

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3844 of file relcache.c.

3845 {
3848  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3849 
3850  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3851  EOXactListAdd(relation);
3852 }
#define InvalidSubTransactionId
Definition: c.h:593
#define EOXactListAdd(rel)
Definition: relcache.c:188
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:776

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

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

◆ RelationBuildLocalRelation()

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

Definition at line 3457 of file relcache.c.

3468 {
3469  Relation rel;
3470  MemoryContext oldcxt;
3471  int natts = tupDesc->natts;
3472  int i;
3473  bool has_not_null;
3474  bool nailit;
3475 
3476  AssertArg(natts >= 0);
3477 
3478  /*
3479  * check for creation of a rel that must be nailed in cache.
3480  *
3481  * XXX this list had better match the relations specially handled in
3482  * RelationCacheInitializePhase2/3.
3483  */
3484  switch (relid)
3485  {
3486  case DatabaseRelationId:
3487  case AuthIdRelationId:
3488  case AuthMemRelationId:
3489  case RelationRelationId:
3490  case AttributeRelationId:
3491  case ProcedureRelationId:
3492  case TypeRelationId:
3493  nailit = true;
3494  break;
3495  default:
3496  nailit = false;
3497  break;
3498  }
3499 
3500  /*
3501  * check that hardwired list of shared rels matches what's in the
3502  * bootstrap .bki file. If you get a failure here during initdb, you
3503  * probably need to fix IsSharedRelation() to match whatever you've done
3504  * to the set of shared relations.
3505  */
3506  if (shared_relation != IsSharedRelation(relid))
3507  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3508  relname, relid);
3509 
3510  /* Shared relations had better be mapped, too */
3511  Assert(mapped_relation || !shared_relation);
3512 
3513  /*
3514  * switch to the cache context to create the relcache entry.
3515  */
3516  if (!CacheMemoryContext)
3518 
3520 
3521  /*
3522  * allocate a new relation descriptor and fill in basic state fields.
3523  */
3524  rel = (Relation) palloc0(sizeof(RelationData));
3525 
3526  /* make sure relation is marked as having no open file yet */
3527  rel->rd_smgr = NULL;
3528 
3529  /* mark it nailed if appropriate */
3530  rel->rd_isnailed = nailit;
3531 
3532  rel->rd_refcnt = nailit ? 1 : 0;
3533 
3534  /* it's being created in this transaction */
3539 
3540  /*
3541  * create a new tuple descriptor from the one passed in. We do this
3542  * partly to copy it into the cache context, and partly because the new
3543  * relation can't have any defaults or constraints yet; they have to be
3544  * added in later steps, because they require additions to multiple system
3545  * catalogs. We can copy attnotnull constraints here, however.
3546  */
3547  rel->rd_att = CreateTupleDescCopy(tupDesc);
3548  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3549  has_not_null = false;
3550  for (i = 0; i < natts; i++)
3551  {
3552  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3553  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3554 
3555  datt->attidentity = satt->attidentity;
3556  datt->attgenerated = satt->attgenerated;
3557  datt->attnotnull = satt->attnotnull;
3558  has_not_null |= satt->attnotnull;
3559  }
3560 
3561  if (has_not_null)
3562  {
3563  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3564 
3565  constr->has_not_null = true;
3566  rel->rd_att->constr = constr;
3567  }
3568 
3569  /*
3570  * initialize relation tuple form (caller may add/override data later)
3571  */
3573 
3574  namestrcpy(&rel->rd_rel->relname, relname);
3575  rel->rd_rel->relnamespace = relnamespace;
3576 
3577  rel->rd_rel->relkind = relkind;
3578  rel->rd_rel->relnatts = natts;
3579  rel->rd_rel->reltype = InvalidOid;
3580  /* needed when bootstrapping: */
3581  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3582 
3583  /* set up persistence and relcache fields dependent on it */
3584  rel->rd_rel->relpersistence = relpersistence;
3585  switch (relpersistence)
3586  {
3587  case RELPERSISTENCE_UNLOGGED:
3588  case RELPERSISTENCE_PERMANENT:
3590  rel->rd_islocaltemp = false;
3591  break;
3592  case RELPERSISTENCE_TEMP:
3593  Assert(isTempOrTempToastNamespace(relnamespace));
3595  rel->rd_islocaltemp = true;
3596  break;
3597  default:
3598  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3599  break;
3600  }
3601 
3602  /* if it's a materialized view, it's not populated initially */
3603  if (relkind == RELKIND_MATVIEW)
3604  rel->rd_rel->relispopulated = false;
3605  else
3606  rel->rd_rel->relispopulated = true;
3607 
3608  /* set replica identity -- system catalogs and non-tables don't have one */
3609  if (!IsCatalogNamespace(relnamespace) &&
3610  (relkind == RELKIND_RELATION ||
3611  relkind == RELKIND_MATVIEW ||
3612  relkind == RELKIND_PARTITIONED_TABLE))
3613  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3614  else
3615  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3616 
3617  /*
3618  * Insert relation physical and logical identifiers (OIDs) into the right
3619  * places. For a mapped relation, we set relfilenode to zero and rely on
3620  * RelationInitPhysicalAddr to consult the map.
3621  */
3622  rel->rd_rel->relisshared = shared_relation;
3623 
3624  RelationGetRelid(rel) = relid;
3625 
3626  for (i = 0; i < natts; i++)
3627  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3628 
3629  rel->rd_rel->reltablespace = reltablespace;
3630 
3631  if (mapped_relation)
3632  {
3633  rel->rd_rel->relfilenode = InvalidOid;
3634  /* Add it to the active mapping information */
3635  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3636  }
3637  else
3638  rel->rd_rel->relfilenode = relfilenode;
3639 
3640  RelationInitLockInfo(rel); /* see lmgr.c */
3641 
3643 
3644  rel->rd_rel->relam = accessmtd;
3645 
3646  /*
3647  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3648  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3649  * require a long-lived current context.
3650  */
3651  MemoryContextSwitchTo(oldcxt);
3652 
3653  if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3655 
3656  /*
3657  * Okay to insert into the relcache hash table.
3658  *
3659  * Ordinarily, there should certainly not be an existing hash entry for
3660  * the same OID; but during bootstrap, when we create a "real" relcache
3661  * entry for one of the bootstrap relations, we'll be overwriting the
3662  * phony one created with formrdesc. So allow that to happen for nailed
3663  * rels.
3664  */
3665  RelationCacheInsert(rel, nailit);
3666 
3667  /*
3668  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3669  * can't do this before storing relid in it.
3670  */
3671  EOXactListAdd(rel);
3672 
3673  /* It's fully valid */
3674  rel->rd_isvalid = true;
3675 
3676  /*
3677  * Caller expects us to pin the returned entry.
3678  */
3680 
3681  return rel;
3682 }
#define BackendIdForTempRelations()
Definition: backendid.h:34
#define InvalidBackendId
Definition: backendid.h:23
#define AssertArg(condition)
Definition: c.h:806
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:245
void CreateCacheMemoryContext(void)
Definition: catcache.c:614
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:72
void * palloc0(Size size)
Definition: mcxt.c:1099
MemoryContext CacheMemoryContext
Definition: mcxt.c:51
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3227
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:208
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2126
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1800
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1310
struct RelationData * Relation
Definition: relcache.h:26
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:320
int rd_refcnt
Definition: rel.h:58
bool rd_isvalid
Definition: rel.h:62
bool rd_islocaltemp
Definition: rel.h:60
TupleDesc rd_att
Definition: rel.h:110
bool rd_isnailed
Definition: rel.h:61
BackendId rd_backend
Definition: rel.h:59
SMgrRelation rd_smgr
Definition: rel.h:57
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_droppedSubid
Definition: rel.h:107
Form_pg_class rd_rel
Definition: rel.h:109
bool has_not_null
Definition: tupdesc.h:44
int tdrefcount
Definition: tupdesc.h:84
TupleConstr * constr
Definition: tupdesc.h:85
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111

References Assert(), AssertArg, BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationMapUpdateMap(), relname, TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
struct PublicationDesc pubdesc 
)

Definition at line 5561 of file relcache.c.

5562 {
5563  List *puboids;
5564  ListCell *lc;
5565  MemoryContext oldcxt;
5566  Oid schemaid;
5567  List *ancestors = NIL;
5568  Oid relid = RelationGetRelid(relation);
5569 
5570  /*
5571  * If not publishable, it publishes no actions. (pgoutput_change() will
5572  * ignore it.)
5573  */
5574  if (!is_publishable_relation(relation))
5575  {
5576  memset(pubdesc, 0, sizeof(PublicationDesc));
5577  pubdesc->rf_valid_for_update = true;
5578  pubdesc->rf_valid_for_delete = true;
5579  pubdesc->cols_valid_for_update = true;
5580  pubdesc->cols_valid_for_delete = true;
5581  return;
5582  }
5583 
5584  if (relation->rd_pubdesc)
5585  {
5586  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5587  return;
5588  }
5589 
5590  memset(pubdesc, 0, sizeof(PublicationDesc));
5591  pubdesc->rf_valid_for_update = true;
5592  pubdesc->rf_valid_for_delete = true;
5593  pubdesc->cols_valid_for_update = true;
5594  pubdesc->cols_valid_for_delete = true;
5595 
5596  /* Fetch the publication membership info. */
5597  puboids = GetRelationPublications(relid);
5598  schemaid = RelationGetNamespace(relation);
5599  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5600 
5601  if (relation->rd_rel->relispartition)
5602  {
5603  /* Add publications that the ancestors are in too. */
5604  ancestors = get_partition_ancestors(relid);
5605 
5606  foreach(lc, ancestors)
5607  {
5608  Oid ancestor = lfirst_oid(lc);
5609 
5610  puboids = list_concat_unique_oid(puboids,
5611  GetRelationPublications(ancestor));
5612  schemaid = get_rel_namespace(ancestor);
5613  puboids = list_concat_unique_oid(puboids,
5614  GetSchemaPublications(schemaid));
5615  }
5616  }
5617  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5618 
5619  foreach(lc, puboids)
5620  {
5621  Oid pubid = lfirst_oid(lc);
5622  HeapTuple tup;
5623  Form_pg_publication pubform;
5624 
5626 
5627  if (!HeapTupleIsValid(tup))
5628  elog(ERROR, "cache lookup failed for publication %u", pubid);
5629 
5630  pubform = (Form_pg_publication) GETSTRUCT(tup);
5631 
5632  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5633  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5634  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5635  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5636 
5637  /*
5638  * Check if all columns referenced in the filter expression are part
5639  * of the REPLICA IDENTITY index or not.
5640  *
5641  * If the publication is FOR ALL TABLES then it means the table has no
5642  * row filters and we can skip the validation.
5643  */
5644  if (!pubform->puballtables &&
5645  (pubform->pubupdate || pubform->pubdelete) &&
5646  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5647  pubform->pubviaroot))
5648  {
5649  if (pubform->pubupdate)
5650  pubdesc->rf_valid_for_update = false;
5651  if (pubform->pubdelete)
5652  pubdesc->rf_valid_for_delete = false;
5653  }
5654 
5655  /*
5656  * Check if all columns are part of the REPLICA IDENTITY index or not.
5657  *
5658  * If the publication is FOR ALL TABLES then it means the table has no
5659  * column list and we can skip the validation.
5660  */
5661  if (!pubform->puballtables &&
5662  (pubform->pubupdate || pubform->pubdelete) &&
5663  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5664  pubform->pubviaroot))
5665  {
5666  if (pubform->pubupdate)
5667  pubdesc->cols_valid_for_update = false;
5668  if (pubform->pubdelete)
5669  pubdesc->cols_valid_for_delete = false;
5670  }
5671 
5672  ReleaseSysCache(tup);
5673 
5674  /*
5675  * If we know everything is replicated and the row filter is invalid
5676  * for update and delete, there is no point to check for other
5677  * publications.
5678  */
5679  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5680  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5681  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5682  break;
5683 
5684  /*
5685  * If we know everything is replicated and the column list is invalid
5686  * for update and delete, there is no point to check for other
5687  * publications.
5688  */
5689  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5690  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5691  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5692  break;
5693  }
5694 
5695  if (relation->rd_pubdesc)
5696  {
5697  pfree(relation->rd_pubdesc);
5698  relation->rd_pubdesc = NULL;
5699  }
5700 
5701  /* Now save copy of the descriptor in the relcache entry. */
5703  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5704  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5705  MemoryContextSwitchTo(oldcxt);
5706 }
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1428
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1933
void * palloc(Size size)
Definition: mcxt.c:1068
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define NIL
Definition: pg_list.h:65
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
bool pub_collist_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
Definition: pg_list.h:51
PublicationActions pubactions
bool cols_valid_for_delete
bool cols_valid_for_update
PublicationDesc * rd_pubdesc
Definition: rel.h:164
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ PUBLICATIONOID
Definition: syscache.h:83

References CacheMemoryContext, PublicationDesc::cols_valid_for_delete, PublicationDesc::cols_valid_for_update, elog, ERROR, get_partition_ancestors(), get_rel_namespace(), GetAllTablesPublications(), GetRelationPublications(), GetSchemaPublications(), GETSTRUCT, HeapTupleIsValid, is_publishable_relation(), lfirst_oid, list_concat_unique_oid(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum, palloc(), pfree(), pub_collist_contains_invalid_column(), pub_rf_contains_invalid_column(), PublicationDesc::pubactions, PublicationActions::pubdelete, PublicationActions::pubinsert, PUBLICATIONOID, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubdesc, RelationData::rd_rel, RelationGetNamespace, RelationGetRelid, ReleaseSysCache(), PublicationDesc::rf_valid_for_delete, PublicationDesc::rf_valid_for_update, and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6646 of file relcache.c.

6647 {
6648  LWLockRelease(RelCacheInitLock);
6649 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6621 of file relcache.c.

6622 {
6623  char localinitfname[MAXPGPATH];
6624  char sharedinitfname[MAXPGPATH];
6625 
6626  if (DatabasePath)
6627  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6629  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6631 
6632  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6633 
6634  /*
6635  * The files might not be there if no backend has been started since the
6636  * last removal. But complain about failures other than ENOENT with
6637  * ERROR. Fortunately, it's not too late to abort the transaction if we
6638  * can't get rid of the would-be-obsolete init file.
6639  */
6640  if (DatabasePath)
6641  unlink_initfile(localinitfname, ERROR);
6642  unlink_initfile(sharedinitfname, ERROR);
6643 }
char * DatabasePath
Definition: globals.c:97
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
@ LW_EXCLUSIVE
Definition: lwlock.h:104
#define MAXPGPATH
#define snprintf
Definition: port.h:225
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6718
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24

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

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6661 of file relcache.c.

6662 {
6663  const char *tblspcdir = "pg_tblspc";
6664  DIR *dir;
6665  struct dirent *de;
6666  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6667 
6668  snprintf(path, sizeof(path), "global/%s",
6670  unlink_initfile(path, LOG);
6671 
6672  /* Scan everything in the default tablespace */
6674 
6675  /* Scan the tablespace link directory to find non-default tablespaces */
6676  dir = AllocateDir(tblspcdir);
6677 
6678  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6679  {
6680  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6681  {
6682  /* Scan the tablespace dir for per-database dirs */
6683  snprintf(path, sizeof(path), "%s/%s/%s",
6684  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6686  }
6687  }
6688 
6689  FreeDir(dir);
6690 }
#define LOG
Definition: elog.h:25
int FreeDir(DIR *dir)
Definition: fd.c:2840
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2803
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6694
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3870 of file relcache.c.

3871 {
3872  HASHCTL ctl;
3873  int allocsize;
3874 
3875  /*
3876  * make sure cache memory context exists
3877  */
3878  if (!CacheMemoryContext)
3880 
3881  /*
3882  * create hashtable that indexes the relcache
3883  */
3884  ctl.keysize = sizeof(Oid);
3885  ctl.entrysize = sizeof(RelIdCacheEnt);
3886  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3887  &ctl, HASH_ELEM | HASH_BLOBS);
3888 
3889  /*
3890  * reserve enough in_progress_list slots for many cases
3891  */
3892  allocsize = 4;
3895  allocsize * sizeof(*in_progress_list));
3896  in_progress_list_maxlen = allocsize;
3897 
3898  /*
3899  * relation mapper needs to be initialized too
3900  */
3902 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
static int in_progress_list_maxlen
Definition: relcache.c:171
#define INITRELCACHESIZE
Definition: relcache.c:3867
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:169
void RelationMapInitialize(void)
Definition: relmapper.c:643
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3916 of file relcache.c.

3917 {
3918  MemoryContext oldcxt;
3919 
3920  /*
3921  * relation mapper needs initialized too
3922  */
3924 
3925  /*
3926  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3927  * nothing.
3928  */
3930  return;
3931 
3932  /*
3933  * switch to cache memory context
3934  */
3936 
3937  /*
3938  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3939  * the cache with pre-made descriptors for the critical shared catalogs.
3940  */
3941  if (!load_relcache_init_file(true))
3942  {
3943  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3944  Natts_pg_database, Desc_pg_database);
3945  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3946  Natts_pg_authid, Desc_pg_authid);
3947  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3948  Natts_pg_auth_members, Desc_pg_auth_members);
3949  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3950  Natts_pg_shseclabel, Desc_pg_shseclabel);
3951  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3952  Natts_pg_subscription, Desc_pg_subscription);
3953 
3954 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3955  }
3956 
3957  MemoryContextSwitchTo(oldcxt);
3958 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:406
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5937
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:118
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1865
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:114
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:119
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:116
void RelationMapInitializePhase2(void)
Definition: relmapper.c:663

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

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3975 of file relcache.c.

3976 {
3978  RelIdCacheEnt *idhentry;
3979  MemoryContext oldcxt;
3980  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3981 
3982  /*
3983  * relation mapper needs initialized too
3984  */
3986 
3987  /*
3988  * switch to cache memory context
3989  */
3991 
3992  /*
3993  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3994  * the cache with pre-made descriptors for the critical "nailed-in" system
3995  * catalogs.
3996  */
3997  if (IsBootstrapProcessingMode() ||
3998  !load_relcache_init_file(false))
3999  {
4000  needNewCacheFile = true;
4001 
4002  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4003  Natts_pg_class, Desc_pg_class);
4004  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4005  Natts_pg_attribute, Desc_pg_attribute);
4006  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4007  Natts_pg_proc, Desc_pg_proc);
4008  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4009  Natts_pg_type, Desc_pg_type);
4010 
4011 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4012  }
4013 
4014  MemoryContextSwitchTo(oldcxt);
4015 
4016  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4018  return;
4019 
4020  /*
4021  * If we didn't get the critical system indexes loaded into relcache, do
4022  * so now. These are critical because the catcache and/or opclass cache
4023  * depend on them for fetches done during relcache load. Thus, we have an
4024  * infinite-recursion problem. We can break the recursion by doing
4025  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4026  * performance, we only want to do that until we have the critical indexes
4027  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4028  * decide whether to do heapscan or indexscan at the key spots, and we set
4029  * it true after we've loaded the critical indexes.
4030  *
4031  * The critical indexes are marked as "nailed in cache", partly to make it
4032  * easy for load_relcache_init_file to count them, but mainly because we
4033  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4034  * true. (NOTE: perhaps it would be possible to reload them by
4035  * temporarily setting criticalRelcachesBuilt to false again. For now,
4036  * though, we just nail 'em in.)
4037  *
4038  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4039  * in the same way as the others, because the critical catalogs don't
4040  * (currently) have any rules or triggers, and so these indexes can be
4041  * rebuilt without inducing recursion. However they are used during
4042  * relcache load when a rel does have rules or triggers, so we choose to
4043  * nail them for performance reasons.
4044  */
4046  {
4047  load_critical_index(ClassOidIndexId,
4048  RelationRelationId);
4049  load_critical_index(AttributeRelidNumIndexId,
4050  AttributeRelationId);
4051  load_critical_index(IndexRelidIndexId,
4052  IndexRelationId);
4053  load_critical_index(OpclassOidIndexId,
4054  OperatorClassRelationId);
4055  load_critical_index(AccessMethodProcedureIndexId,
4056  AccessMethodProcedureRelationId);
4057  load_critical_index(RewriteRelRulenameIndexId,
4058  RewriteRelationId);
4059  load_critical_index(TriggerRelidNameIndexId,
4060  TriggerRelationId);
4061 
4062 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4063 
4064  criticalRelcachesBuilt = true;
4065  }
4066 
4067  /*
4068  * Process critical shared indexes too.
4069  *
4070  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4071  * initial lookup of MyDatabaseId, without which we'll never find any
4072  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4073  * database OID, so it instead depends on DatabaseOidIndexId. We also
4074  * need to nail up some indexes on pg_authid and pg_auth_members for use
4075  * during client authentication. SharedSecLabelObjectIndexId isn't
4076  * critical for the core system, but authentication hooks might be
4077  * interested in it.
4078  */
4080  {
4081  load_critical_index(DatabaseNameIndexId,
4082  DatabaseRelationId);
4083  load_critical_index(DatabaseOidIndexId,
4084  DatabaseRelationId);
4085  load_critical_index(AuthIdRolnameIndexId,
4086  AuthIdRelationId);
4087  load_critical_index(AuthIdOidIndexId,
4088  AuthIdRelationId);
4089  load_critical_index(AuthMemMemRoleIndexId,
4090  AuthMemRelationId);
4091  load_critical_index(SharedSecLabelObjectIndexId,
4092  SharedSecLabelRelationId);
4093 
4094 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4095 
4097  }
4098 
4099  /*
4100  * Now, scan all the relcache entries and update anything that might be
4101  * wrong in the results from formrdesc or the relcache cache file. If we
4102  * faked up relcache entries using formrdesc, then read the real pg_class
4103  * rows and replace the fake entries with them. Also, if any of the
4104  * relcache entries have rules, triggers, or security policies, load that
4105  * info the hard way since it isn't recorded in the cache file.
4106  *
4107  * Whenever we access the catalogs to read data, there is a possibility of
4108  * a shared-inval cache flush causing relcache entries to be removed.
4109  * Since hash_seq_search only guarantees to still work after the *current*
4110  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4111  * We handle this by restarting the scan from scratch after each access.
4112  * This is theoretically O(N^2), but the number of entries that actually
4113  * need to be fixed is small enough that it doesn't matter.
4114  */
4116 
4117  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4118  {
4119  Relation relation = idhentry->reldesc;
4120  bool restart = false;
4121 
4122  /*
4123  * Make sure *this* entry doesn't get flushed while we work with it.
4124  */
4126 
4127  /*
4128  * If it's a faked-up entry, read the real pg_class tuple.
4129  */
4130  if (relation->rd_rel->relowner == InvalidOid)
4131  {
4132  HeapTuple htup;
4133  Form_pg_class relp;
4134 
4135  htup = SearchSysCache1(RELOID,
4136  ObjectIdGetDatum(RelationGetRelid(relation)));
4137  if (!HeapTupleIsValid(htup))
4138  elog(FATAL, "cache lookup failed for relation %u",
4139  RelationGetRelid(relation));
4140  relp = (Form_pg_class) GETSTRUCT(htup);
4141 
4142  /*
4143  * Copy tuple to relation->rd_rel. (See notes in
4144  * AllocateRelationDesc())
4145  */
4146  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4147 
4148  /* Update rd_options while we have the tuple */
4149  if (relation->rd_options)
4150  pfree(relation->rd_options);
4151  RelationParseRelOptions(relation, htup);
4152 
4153  /*
4154  * Check the values in rd_att were set up correctly. (We cannot
4155  * just copy them over now: formrdesc must have set up the rd_att
4156  * data correctly to start with, because it may already have been
4157  * copied into one or more catcache entries.)
4158  */
4159  Assert(relation->rd_att->tdtypeid == relp->reltype);
4160  Assert(relation->rd_att->tdtypmod == -1);
4161 
4162  ReleaseSysCache(htup);
4163 
4164  /* relowner had better be OK now, else we'll loop forever */
4165  if (relation->rd_rel->relowner == InvalidOid)
4166  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4167  RelationGetRelationName(relation));
4168 
4169  restart = true;
4170  }
4171 
4172  /*
4173  * Fix data that isn't saved in relcache cache file.
4174  *
4175  * relhasrules or relhastriggers could possibly be wrong or out of
4176  * date. If we don't actually find any rules or triggers, clear the
4177  * local copy of the flag so that we don't get into an infinite loop
4178  * here. We don't make any attempt to fix the pg_class entry, though.
4179  */
4180  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4181  {
4182  RelationBuildRuleLock(relation);
4183  if (relation->rd_rules == NULL)
4184  relation->rd_rel->relhasrules = false;
4185  restart = true;
4186  }
4187  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4188  {
4189  RelationBuildTriggers(relation);
4190  if (relation->trigdesc == NULL)
4191  relation->rd_rel->relhastriggers = false;
4192  restart = true;
4193  }
4194 
4195  /*
4196  * Re-load the row security policies if the relation has them, since
4197  * they are not preserved in the cache. Note that we can never NOT
4198  * have a policy while relrowsecurity is true,
4199  * RelationBuildRowSecurity will create a single default-deny policy
4200  * if there is no policy defined in pg_policy.
4201  */
4202  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4203  {
4204  RelationBuildRowSecurity(relation);
4205 
4206  Assert(relation->rd_rsdesc != NULL);
4207  restart = true;
4208  }
4209 
4210  /* Reload tableam data if needed */
4211  if (relation->rd_tableam == NULL &&
4212  (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4213  {
4215  Assert(relation->rd_tableam != NULL);
4216 
4217  restart = true;
4218  }
4219 
4220  /* Release hold on the relation */
4222 
4223  /* Now, restart the hashtable scan if needed */
4224  if (restart)
4225  {
4228  }
4229  }
4230 
4231  /*
4232  * Lastly, write out new relcache cache files if needed. We don't bother
4233  * to distinguish cases where only one of the two needs an update.
4234  */
4235  if (needNewCacheFile)
4236  {
4237  /*
4238  * Force all the catcaches to finish initializing and thereby open the
4239  * catalogs and indexes they use. This will preload the relcache with
4240  * entries for all the most important system catalogs and indexes, so
4241  * that the init files will be most useful for future backends.
4242  */
4244 
4245  /* now write the files */
4247  write_relcache_init_file(false);
4248  }
4249 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512
#define FATAL
Definition: elog.h:35
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:196
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:461
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2139
bool criticalRelcachesBuilt
Definition: relcache.c:139
bool criticalSharedRelcachesBuilt
Definition: relcache.c:145
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:111
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:110
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:730
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:112
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6354
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:113
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4258
void RelationMapInitializePhase3(void)
Definition: relmapper.c:684
const struct TableAmRoutine * rd_tableam
Definition: rel.h:185
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
TriggerDesc * trigdesc
Definition: rel.h:115
RuleLock * rd_rules
Definition: rel.h:113
bytea * rd_options
Definition: rel.h:171
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void InitCatalogCachePhase2(void)
Definition: syscache.c:1132
@ RELOID
Definition: syscache.h:89
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1870

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ERROR, FATAL, formrdesc(), GETSTRUCT, hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum, pfree(), RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIdCache, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, SearchSysCache1(), status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2924 of file relcache.c.

2925 {
2927  RelIdCacheEnt *idhentry;
2928  Relation relation;
2929  List *rebuildFirstList = NIL;
2930  List *rebuildList = NIL;
2931  ListCell *l;
2932  int i;
2933 
2934  /*
2935  * Reload relation mapping data before starting to reconstruct cache.
2936  */
2938 
2939  /* Phase 1 */
2941 
2942  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2943  {
2944  relation = idhentry->reldesc;
2945 
2946  /* Must close all smgr references to avoid leaving dangling ptrs */
2947  RelationCloseSmgr(relation);
2948 
2949  /*
2950  * Ignore new relations; no other backend will manipulate them before
2951  * we commit. Likewise, before replacing a relation's relfilenode, we
2952  * shall have acquired AccessExclusiveLock and drained any applicable
2953  * pending invalidations.
2954  */
2955  if (relation->rd_createSubid != InvalidSubTransactionId ||
2957  continue;
2958 
2960 
2961  if (RelationHasReferenceCountZero(relation))
2962  {
2963  /* Delete this entry immediately */
2964  Assert(!relation->rd_isnailed);
2965  RelationClearRelation(relation, false);
2966  }
2967  else
2968  {
2969  /*
2970  * If it's a mapped relation, immediately update its rd_node in
2971  * case its relfilenode changed. We must do this during phase 1
2972  * in case the relation is consulted during rebuild of other
2973  * relcache entries in phase 2. It's safe since consulting the
2974  * map doesn't involve any access to relcache entries.
2975  */
2976  if (RelationIsMapped(relation))
2977  RelationInitPhysicalAddr(relation);
2978 
2979  /*
2980  * Add this entry to list of stuff to rebuild in second pass.
2981  * pg_class goes to the front of rebuildFirstList while
2982  * pg_class_oid_index goes to the back of rebuildFirstList, so
2983  * they are done first and second respectively. Other nailed
2984  * relations go to the front of rebuildList, so they'll be done
2985  * next in no particular order; and everything else goes to the
2986  * back of rebuildList.
2987  */
2988  if (RelationGetRelid(relation) == RelationRelationId)
2989  rebuildFirstList = lcons(relation, rebuildFirstList);
2990  else if (RelationGetRelid(relation) == ClassOidIndexId)
2991  rebuildFirstList = lappend(rebuildFirstList, relation);
2992  else if (relation->rd_isnailed)
2993  rebuildList = lcons(relation, rebuildList);
2994  else
2995  rebuildList = lappend(rebuildList, relation);
2996  }
2997  }
2998 
2999  /*
3000  * Now zap any remaining smgr cache entries. This must happen before we
3001  * start to rebuild entries, since that may involve catalog fetches which
3002  * will re-open catalog files.
3003  */
3004  smgrcloseall();
3005 
3006  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3007  foreach(l, rebuildFirstList)
3008  {
3009  relation = (Relation) lfirst(l);
3010  RelationClearRelation(relation, true);
3011  }
3012  list_free(rebuildFirstList);
3013  foreach(l, rebuildList)
3014  {
3015  relation = (Relation) lfirst(l);
3016  RelationClearRelation(relation, true);
3017  }
3018  list_free(rebuildList);
3019 
3020  if (!debug_discard)
3021  /* Any RelationBuildDesc() on the stack must start over. */
3022  for (i = 0; i < in_progress_list_len; i++)
3023  in_progress_list[i].invalidated = true;
3024 }
List * lappend(List *list, void *datum)
Definition: list.c:336
void list_free(List *list)
Definition: list.c:1505
List * lcons(void *datum, List *list)
Definition: list.c:474
#define lfirst(lc)
Definition: pg_list.h:169
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:473
#define RelationIsMapped(relation)
Definition: rel.h:538
#define RelationCloseSmgr(relation)
Definition: rel.h:569
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2493
static long relcacheInvalsReceived
Definition: relcache.c:153
void RelationMapInvalidateAll(void)
Definition: relmapper.c:484
void smgrcloseall(void)
Definition: smgr.c:322

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2868 of file relcache.c.

2869 {
2870  Relation relation;
2871 
2872  RelationIdCacheLookup(relationId, relation);
2873 
2874  if (PointerIsValid(relation))
2875  {
2877  RelationFlushRelation(relation);
2878  }
2879  else
2880  {
2881  int i;
2882 
2883  for (i = 0; i < in_progress_list_len; i++)
2884  if (in_progress_list[i].reloid == relationId)
2885  in_progress_list[i].invalidated = true;
2886  }
2887 }
#define PointerIsValid(pointer)
Definition: c.h:698
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:230
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2791
bool invalidated
Definition: relcache.c:166

References i, in_progress_list, in_progress_list_len, inprogressent::invalidated, PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2159 of file relcache.c.

2160 {
2161  /* Note: no locking manipulations needed */
2163 
2164  /*
2165  * If the relation is no longer open in this session, we can clean up any
2166  * stale partition descriptors it has. This is unlikely, so check to see
2167  * if there are child contexts before expending a call to mcxt.c.
2168  */
2169  if (RelationHasReferenceCountZero(relation))
2170  {
2171  if (relation->rd_pdcxt != NULL &&
2172  relation->rd_pdcxt->firstchild != NULL)
2174 
2175  if (relation->rd_pddcxt != NULL &&
2176  relation->rd_pddcxt->firstchild != NULL)
2178  }
2179 
2180 #ifdef RELCACHE_FORCE_RELEASE
2181  if (RelationHasReferenceCountZero(relation) &&
2182  relation->rd_createSubid == InvalidSubTransactionId &&
2184  RelationClearRelation(relation, false);
2185 #endif
2186 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
MemoryContext firstchild
Definition: memnodes.h:87
MemoryContext rd_pdcxt
Definition: rel.h:129
MemoryContext rd_pddcxt
Definition: rel.h:133

References MemoryContextData::firstchild, InvalidSubTransactionId, MemoryContextDeleteChildren(), RelationData::rd_createSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationClearRelation(), RelationDecrementReferenceCount(), and RelationHasReferenceCountZero.

Referenced by index_close(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_row_filter_init(), relation_close(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and ResourceOwnerReleaseInternal().

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 3033 of file relcache.c.

3034 {
3035  Relation relation;
3036 
3037  RelationIdCacheLookup(relationId, relation);
3038 
3039  if (!PointerIsValid(relation))
3040  return; /* not in cache, nothing to do */
3041 
3042  RelationCloseSmgr(relation);
3043 }

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2824 of file relcache.c.

2825 {
2826  Relation relation;
2827 
2828  RelationIdCacheLookup(rid, relation);
2829 
2830  if (!PointerIsValid(relation))
2831  return; /* not in cache, nothing to do */
2832 
2833  if (!RelationHasReferenceCountZero(relation))
2834  elog(ERROR, "relation %u is still open", rid);
2835 
2837  if (relation->rd_createSubid != InvalidSubTransactionId ||
2839  {
2840  /*
2841  * In the event of subtransaction rollback, we must not forget
2842  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2843  * invalidates it in lieu of destroying it. (If we're in a top
2844  * transaction, we could opt to destroy the entry.)
2845  */
2847  }
2848 
2849  RelationClearRelation(relation, false);
2850 }

References Assert(), elog, ERROR, GetCurrentSubTransactionId(), InvalidSubTransactionId, PointerIsValid, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilenodeSubid, RelationClearRelation(), RelationHasReferenceCountZero, and RelationIdCacheLookup.

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 4968 of file relcache.c.

4969 {
4970  List *result;
4971  Datum exprsDatum;
4972  bool isnull;
4973  char *exprsString;
4974  List *rawExprs;
4975  ListCell *lc;
4976 
4977  /* Quick exit if there is nothing to do. */
4978  if (relation->rd_indextuple == NULL ||
4979  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4980  return NIL;
4981 
4982  /* Extract raw node tree(s) from index tuple. */
4983  exprsDatum = heap_getattr(relation->rd_indextuple,
4984  Anum_pg_index_indexprs,
4986  &isnull);
4987  Assert(!isnull);
4988  exprsString = TextDatumGetCString(exprsDatum);
4989  rawExprs = (List *) stringToNode(exprsString);
4990  pfree(exprsString);
4991 
4992  /* Construct null Consts; the typlen and typbyval are arbitrary. */
4993  result = NIL;
4994  foreach(lc, rawExprs)
4995  {
4996  Node *rawExpr = (Node *) lfirst(lc);
4997 
4998  result = lappend(result,
4999  makeConst(exprType(rawExpr),
5000  exprTypmod(rawExpr),
5001  exprCollation(rawExpr),
5002  1,
5003  (Datum) 0,
5004  true,
5005  true));
5006  }
5007 
5008  return result;
5009 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:300
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:286
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
uintptr_t Datum
Definition: postgres.h:411
void * stringToNode(const char *str)
Definition: read.c:89
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4337
Definition: nodes.h:574
struct HeapTupleData * rd_indextuple
Definition: rel.h:190

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

Referenced by BuildDummyIndexInfo().

◆ RelationGetExclusionInfo()

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

Definition at line 5429 of file relcache.c.

5433 {
5434  int indnkeyatts;
5435  Oid *ops;
5436  Oid *funcs;
5437  uint16 *strats;
5438  Relation conrel;
5439  SysScanDesc conscan;
5440  ScanKeyData skey[1];
5441  HeapTuple htup;
5442  bool found;
5443  MemoryContext oldcxt;
5444  int i;
5445 
5446  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5447 
5448  /* Allocate result space in caller context */
5449  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5450  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5451  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5452 
5453  /* Quick exit if we have the data cached already */
5454  if (indexRelation->rd_exclstrats != NULL)
5455  {
5456  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5457  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5458  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5459  return;
5460  }
5461 
5462  /*
5463  * Search pg_constraint for the constraint associated with the index. To
5464  * make this not too painfully slow, we use the index on conrelid; that
5465  * will hold the parent relation's OID not the index's own OID.
5466  *
5467  * Note: if we wanted to rely on the constraint name matching the index's
5468  * name, we could just do a direct lookup using pg_constraint's unique
5469  * index. For the moment it doesn't seem worth requiring that.
5470  */
5471  ScanKeyInit(&skey[0],
5472  Anum_pg_constraint_conrelid,
5473  BTEqualStrategyNumber, F_OIDEQ,
5474  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5475 
5476  conrel = table_open(ConstraintRelationId, AccessShareLock);
5477  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5478  NULL, 1, skey);
5479  found = false;
5480 
5481  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5482  {
5484  Datum val;
5485  bool isnull;
5486  ArrayType *arr;
5487  int nelem;
5488 
5489  /* We want the exclusion constraint owning the index */
5490  if (conform->contype != CONSTRAINT_EXCLUSION ||
5491  conform->conindid != RelationGetRelid(indexRelation))
5492  continue;
5493 
5494  /* There should be only one */
5495  if (found)
5496  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5497  RelationGetRelationName(indexRelation));
5498  found = true;
5499 
5500  /* Extract the operator OIDS from conexclop */
5501  val = fastgetattr(htup,
5502  Anum_pg_constraint_conexclop,
5503  conrel->rd_att, &isnull);
5504  if (isnull)
5505  elog(ERROR, "null conexclop for rel %s",
5506  RelationGetRelationName(indexRelation));
5507 
5508  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5509  nelem = ARR_DIMS(arr)[0];
5510  if (ARR_NDIM(arr) != 1 ||
5511  nelem != indnkeyatts ||
5512  ARR_HASNULL(arr) ||
5513  ARR_ELEMTYPE(arr) != OIDOID)
5514  elog(ERROR, "conexclop is not a 1-D Oid array");
5515 
5516  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5517  }
5518 
5519  systable_endscan(conscan);
5520  table_close(conrel, AccessShareLock);
5521 
5522  if (!found)
5523  elog(ERROR, "exclusion constraint record missing for rel %s",
5524  RelationGetRelationName(indexRelation));
5525 
5526  /* We need the func OIDs and strategy numbers too */
5527  for (i = 0; i < indnkeyatts; i++)
5528  {
5529  funcs[i] = get_opcode(ops[i]);
5530  strats[i] = get_op_opfamily_strategy(ops[i],
5531  indexRelation->rd_opfamily[i]);
5532  /* shouldn't fail, since it was checked at index creation */
5533  if (strats[i] == InvalidStrategy)
5534  elog(ERROR, "could not find strategy for operator %u in family %u",
5535  ops[i], indexRelation->rd_opfamily[i]);
5536  }
5537 
5538  /* Save a copy of the results in the relcache entry. */
5539  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5540  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5541  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5542  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5543  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5544  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5545  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5546  MemoryContextSwitchTo(oldcxt);
5547 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
unsigned short uint16
Definition: c.h:440
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:745
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1266
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:81
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:508
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define InvalidStrategy
Definition: stratnum.h:24
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid * rd_exclprocs
Definition: rel.h:211
uint16 * rd_exclstrats
Definition: rel.h:212
Oid * rd_exclops
Definition: rel.h:210
Form_pg_index rd_index
Definition: rel.h:188
MemoryContext rd_indexcxt
Definition: rel.h:200
Oid * rd_opfamily
Definition: rel.h:203
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, DatumGetArrayTypeP, elog, ERROR, fastgetattr(), get_op_opfamily_strategy(), get_opcode(), GETSTRUCT, HeapTupleIsValid, i, IndexRelationGetNumberOfKeyAttributes, InvalidStrategy, MemoryContextSwitchTo(), ObjectIdGetDatum, palloc(), RelationData::rd_att, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_opfamily, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and val.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4566 of file relcache.c.

4567 {
4568  List *result;
4569  Relation conrel;
4570  SysScanDesc conscan;
4571  ScanKeyData skey;
4572  HeapTuple htup;
4573  List *oldlist;
4574  MemoryContext oldcxt;
4575 
4576  /* Quick exit if we already computed the list. */
4577  if (relation->rd_fkeyvalid)
4578  return relation->rd_fkeylist;
4579 
4580  /* Fast path: non-partitioned tables without triggers can't have FKs */
4581  if (!relation->rd_rel->relhastriggers &&
4582  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4583  return NIL;
4584 
4585  /*
4586  * We build the list we intend to return (in the caller's context) while
4587  * doing the scan. After successfully completing the scan, we copy that
4588  * list into the relcache entry. This avoids cache-context memory leakage
4589  * if we get some sort of error partway through.
4590  */
4591  result = NIL;
4592 
4593  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4594  ScanKeyInit(&skey,
4595  Anum_pg_constraint_conrelid,
4596  BTEqualStrategyNumber, F_OIDEQ,
4597  ObjectIdGetDatum(RelationGetRelid(relation)));
4598 
4599  conrel = table_open(ConstraintRelationId, AccessShareLock);
4600  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4601  NULL, 1, &skey);
4602 
4603  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4604  {
4605  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4606  ForeignKeyCacheInfo *info;
4607 
4608  /* consider only foreign keys */
4609  if (constraint->contype != CONSTRAINT_FOREIGN)
4610  continue;
4611 
4612  info = makeNode(ForeignKeyCacheInfo);
4613  info->conoid = constraint->oid;
4614  info->conrelid = constraint->conrelid;
4615  info->confrelid = constraint->confrelid;
4616 
4617  DeconstructFkConstraintRow(htup, &info->nkeys,
4618  info->conkey,
4619  info->confkey,
4620  info->conpfeqop,
4621  NULL, NULL, NULL, NULL);
4622 
4623  /* Add FK's node to the result list */
4624  result = lappend(result, info);
4625  }
4626 
4627  systable_endscan(conscan);
4628  table_close(conrel, AccessShareLock);
4629 
4630  /* Now save a copy of the completed list in the relcache entry. */
4632  oldlist = relation->rd_fkeylist;
4633  relation->rd_fkeylist = copyObject(result);
4634  relation->rd_fkeyvalid = true;
4635  MemoryContextSwitchTo(oldcxt);
4636 
4637  /* Don't leak the old list, if there is one */
4638  list_free_deep(oldlist);
4639 
4640  return result;
4641 }
void list_free_deep(List *list)
Definition: list.c:1519
#define copyObject(obj)
Definition: nodes.h:689
#define makeNode(_type_)
Definition: nodes.h:621
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:279
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:278
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: rel.h:277
List * rd_fkeylist
Definition: rel.h:120
bool rd_fkeyvalid
Definition: rel.h:121

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confkey, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conkey, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conpfeqop, ForeignKeyCacheInfo::conrelid, copyObject, DeconstructFkConstraintRow(), GETSTRUCT, HeapTupleIsValid, lappend(), list_free_deep(), makeNode, MemoryContextSwitchTo(), NIL, ForeignKeyCacheInfo::nkeys, ObjectIdGetDatum, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_rel, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferencing(), CloneFkReferencing(), DetachPartitionFinalize(), and get_relation_foreign_keys().

◆ RelationGetIdentityKeyBitmap()

Bitmapset* RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5355 of file relcache.c.

5356 {
5357  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5358  Relation indexDesc;
5359  int i;
5360  Oid replidindex;
5361  MemoryContext oldcxt;
5362 
5363  /* Quick exit if we already computed the result */
5364  if (relation->rd_idattr != NULL)
5365  return bms_copy(relation->rd_idattr);
5366 
5367  /* Fast path if definitely no indexes */
5368  if (!RelationGetForm(relation)->relhasindex)
5369  return NULL;
5370 
5371  /* Historic snapshot must be set. */
5373 
5374  replidindex = RelationGetReplicaIndex(relation);
5375 
5376  /* Fall out if there is no replica identity index */
5377  if (!OidIsValid(replidindex))
5378  return NULL;
5379 
5380  /* Look up the description for the replica identity index */
5381  indexDesc = RelationIdGetRelation(replidindex);
5382 
5383  if (!RelationIsValid(indexDesc))
5384  elog(ERROR, "could not open relation with OID %u",
5385  relation->rd_replidindex);
5386 
5387  /* Add referenced attributes to idindexattrs */
5388  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5389  {
5390  int attrnum = indexDesc->rd_index->indkey.values[i];
5391 
5392  /*
5393  * We don't include non-key columns into idindexattrs bitmaps. See
5394  * RelationGetIndexAttrBitmap.
5395  */
5396  if (attrnum != 0)
5397  {
5398  if (i < indexDesc->rd_index->indnkeyatts)
5399  idindexattrs = bms_add_member(idindexattrs,
5401  }
5402  }
5403 
5404  RelationClose(indexDesc);
5405 
5406  /* Don't leak the old values of these bitmaps, if any */
5407  bms_free(relation->rd_idattr);
5408  relation->rd_idattr = NULL;
5409 
5410  /* Now save copy of the bitmap in the relcache entry */
5412  relation->rd_idattr = bms_copy(idindexattrs);
5413  MemoryContextSwitchTo(oldcxt);
5414 
5415  /* We return our original working copy for caller to play with */
5416  return idindexattrs;
5417 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define OidIsValid(objectId)
Definition: c.h:710
#define RelationGetForm(relation)
Definition: rel.h:483
#define RelationIsValid(relation)
Definition: rel.h:462
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4884
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2053
void RelationClose(Relation relation)
Definition: relcache.c:2159
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2101
Oid rd_replidindex
Definition: rel.h:152
Bitmapset * rd_idattr
Definition: rel.h:161
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References Assert(), bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, ERROR, FirstLowInvalidHeapAttributeNumber, HistoricSnapshotActive(), i, MemoryContextSwitchTo(), OidIsValid, RelationData::rd_idattr, RelationData::rd_index, RelationData::rd_replidindex, RelationClose(), RelationGetForm, RelationGetReplicaIndex(), RelationIdGetRelation(), and RelationIsValid.

Referenced by logicalrep_write_attrs().

◆ RelationGetIndexAttOptions()

bytea** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5758 of file relcache.c.

5759 {
5760  MemoryContext oldcxt;
5761  bytea **opts = relation->rd_opcoptions;
5762  Oid relid = RelationGetRelid(relation);
5763  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5764  * IndexRelationGetNumberOfKeyAttributes */
5765  int i;
5766 
5767  /* Try to copy cached options. */
5768  if (opts)
5769  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5770 
5771  /* Get and parse opclass options. */
5772  opts = palloc0(sizeof(*opts) * natts);
5773 
5774  for (i = 0; i < natts; i++)
5775  {
5776  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5777  {
5778  Datum attoptions = get_attoptions(relid, i + 1);
5779 
5780  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5781 
5782  if (attoptions != (Datum) 0)
5783  pfree(DatumGetPointer(attoptions));
5784  }
5785  }
5786 
5787  /* Copy parsed options to the cache. */
5788  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5789  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5790  MemoryContextSwitchTo(oldcxt);
5791 
5792  if (copy)
5793  return opts;
5794 
5795  for (i = 0; i < natts; i++)
5796  {
5797  if (opts[i])
5798  pfree(opts[i]);
5799  }
5800 
5801  pfree(opts);
5802 
5803  return relation->rd_opcoptions;
5804 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:939
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:995
static AmcheckOptions opts
Definition: pg_amcheck.c:110
#define DatumGetPointer(X)
Definition: postgres.h:593
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:495
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5738
bytea ** rd_opcoptions
Definition: rel.h:214
Definition: c.h:622

References CopyIndexAttOptions(), criticalRelcachesBuilt, DatumGetPointer, get_attoptions(), i, index_opclass_options(), MemoryContextSwitchTo(), opts, palloc0(), pfree(), RelationData::rd_indexcxt, RelationData::rd_opcoptions, RelationGetNumberOfAttributes, and RelationGetRelid.

Referenced by get_relation_info(), index_getprocinfo(), load_critical_index(), and RelationInitIndexAccessInfo().

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5105 of file relcache.c.

5106 {
5107  Bitmapset *uindexattrs; /* columns in unique indexes */
5108  Bitmapset *pkindexattrs; /* columns in the primary index */
5109  Bitmapset *idindexattrs; /* columns in the replica identity */
5110  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5111  List *indexoidlist;
5112  List *newindexoidlist;
5113  Oid relpkindex;
5114  Oid relreplindex;
5115  ListCell *l;
5116  MemoryContext oldcxt;
5117 
5118  /* Quick exit if we already computed the result. */
5119  if (relation->rd_attrsvalid)
5120  {
5121  switch (attrKind)
5122  {
5123  case INDEX_ATTR_BITMAP_KEY:
5124  return bms_copy(relation->rd_keyattr);
5126  return bms_copy(relation->rd_pkattr);
5128  return bms_copy(relation->rd_idattr);
5130  return bms_copy(relation->rd_hotblockingattr);
5131  default:
5132  elog(ERROR, "unknown attrKind %u", attrKind);
5133  }
5134  }
5135 
5136  /* Fast path if definitely no indexes */
5137  if (!RelationGetForm(relation)->relhasindex)
5138  return NULL;
5139 
5140  /*
5141  * Get cached list of index OIDs. If we have to start over, we do so here.
5142  */
5143 restart:
5144  indexoidlist = RelationGetIndexList(relation);
5145 
5146  /* Fall out if no indexes (but relhasindex was set) */
5147  if (indexoidlist == NIL)
5148  return NULL;
5149 
5150  /*
5151  * Copy the rd_pkindex and rd_replidindex values computed by
5152  * RelationGetIndexList before proceeding. This is needed because a
5153  * relcache flush could occur inside index_open below, resetting the
5154  * fields managed by RelationGetIndexList. We need to do the work with
5155  * stable values of these fields.
5156  */
5157  relpkindex = relation->rd_pkindex;
5158  relreplindex = relation->rd_replidindex;
5159 
5160  /*
5161  * For each index, add referenced attributes to appropriate bitmaps.
5162  *
5163  * Note: we consider all indexes returned by RelationGetIndexList, even if
5164  * they are not indisready or indisvalid. This is important because an
5165  * index for which CREATE INDEX CONCURRENTLY has just started must be
5166  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5167  * CONCURRENTLY is far enough along that we should ignore the index, it
5168  * won't be returned at all by RelationGetIndexList.
5169  */
5170  uindexattrs = NULL;
5171  pkindexattrs = NULL;
5172  idindexattrs = NULL;
5173  hotblockingattrs = NULL;
5174  foreach(l, indexoidlist)
5175  {
5176  Oid indexOid = lfirst_oid(l);
5177  Relation indexDesc;
5178  Datum datum;
5179  bool isnull;
5180  Node *indexExpressions;
5181  Node *indexPredicate;
5182  int i;
5183  bool isKey; /* candidate key */
5184  bool isPK; /* primary key */
5185  bool isIDKey; /* replica identity index */
5186 
5187  indexDesc = index_open(indexOid, AccessShareLock);
5188 
5189  /*
5190  * Extract index expressions and index predicate. Note: Don't use
5191  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5192  * those might run constant expressions evaluation, which needs a
5193  * snapshot, which we might not have here. (Also, it's probably more
5194  * sound to collect the bitmaps before any transformations that might
5195  * eliminate columns, but the practical impact of this is limited.)
5196  */
5197 
5198  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5199  GetPgIndexDescriptor(), &isnull);
5200  if (!isnull)
5201  indexExpressions = stringToNode(TextDatumGetCString(datum));
5202  else
5203  indexExpressions = NULL;
5204 
5205  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5206  GetPgIndexDescriptor(), &isnull);
5207  if (!isnull)
5208  indexPredicate = stringToNode(TextDatumGetCString(datum));
5209  else
5210  indexPredicate = NULL;
5211 
5212  /* Can this index be referenced by a foreign key? */
5213  isKey = indexDesc->rd_index->indisunique &&
5214  indexExpressions == NULL &&
5215  indexPredicate == NULL;
5216 
5217  /* Is this a primary key? */
5218  isPK = (indexOid == relpkindex);
5219 
5220  /* Is this index the configured (or default) replica identity? */
5221  isIDKey = (indexOid == relreplindex);
5222 
5223  /* Collect simple attribute references */
5224  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5225  {
5226  int attrnum = indexDesc->rd_index->indkey.values[i];
5227 
5228  /*
5229  * Since we have covering indexes with non-key columns, we must
5230  * handle them accurately here. non-key columns must be added into
5231  * indexattrs, since they are in index, and HOT-update shouldn't
5232  * miss them. Obviously, non-key columns couldn't be referenced by
5233  * foreign key or identity key. Hence we do not include them into
5234  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5235  */
5236  if (attrnum != 0)
5237  {
5238  if (indexDesc->rd_indam->amhotblocking)
5239  hotblockingattrs = bms_add_member(hotblockingattrs,
5241 
5242  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5243  uindexattrs = bms_add_member(uindexattrs,
5245 
5246  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5247  pkindexattrs = bms_add_member(pkindexattrs,
5249 
5250  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5251  idindexattrs = bms_add_member(idindexattrs,
5253  }
5254  }
5255 
5256  /* Collect all attributes used in expressions, too */
5257  if (indexDesc->rd_indam->amhotblocking)
5258  pull_varattnos(indexExpressions, 1, &hotblockingattrs);
5259 
5260  /*
5261  * Collect all attributes in the index predicate, too. We have to
5262  * ignore amhotblocking flag, because the row might become indexable,
5263  * in which case we have to add it to the index.
5264  */
5265  pull_varattnos(indexPredicate, 1, &hotblockingattrs);
5266 
5267  index_close(indexDesc, AccessShareLock);
5268  }
5269 
5270  /*
5271  * During one of the index_opens in the above loop, we might have received
5272  * a relcache flush event on this relcache entry, which might have been
5273  * signaling a change in the rel's index list. If so, we'd better start
5274  * over to ensure we deliver up-to-date attribute bitmaps.
5275  */
5276  newindexoidlist = RelationGetIndexList(relation);
5277  if (equal(indexoidlist, newindexoidlist) &&
5278  relpkindex == relation->rd_pkindex &&
5279  relreplindex == relation->rd_replidindex)
5280  {
5281  /* Still the same index set, so proceed */
5282  list_free(newindexoidlist);
5283  list_free(indexoidlist);
5284  }
5285  else
5286  {
5287  /* Gotta do it over ... might as well not leak memory */
5288  list_free(newindexoidlist);
5289  list_free(indexoidlist);
5290  bms_free(uindexattrs);
5291  bms_free(pkindexattrs);
5292  bms_free(idindexattrs);
5293  bms_free(hotblockingattrs);
5294 
5295  goto restart;
5296  }
5297 
5298  /* Don't leak the old values of these bitmaps, if any */
5299  bms_free(relation->rd_keyattr);
5300  relation->rd_keyattr = NULL;
5301  bms_free(relation->rd_pkattr);
5302  relation->rd_pkattr = NULL;
5303  bms_free(relation->rd_idattr);
5304  relation->rd_idattr = NULL;
5305  bms_free(relation->rd_hotblockingattr);
5306  relation->rd_hotblockingattr = NULL;
5307 
5308  /*
5309  * Now save copies of the bitmaps in the relcache entry. We intentionally
5310  * set rd_attrsvalid last, because that's what signals validity of the
5311  * values; if we run out of memory before making that copy, we won't leave
5312  * the relcache entry looking like the other ones are valid but empty.
5313  */
5315  relation->rd_keyattr = bms_copy(uindexattrs);
5316  relation->rd_pkattr = bms_copy(pkindexattrs);
5317  relation->rd_idattr = bms_copy(idindexattrs);
5318  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5319  relation->rd_attrsvalid = true;
5320  MemoryContextSwitchTo(oldcxt);
5321 
5322  /* We return our original working copy for caller to play with */
5323  switch (attrKind)
5324  {
5325  case INDEX_ATTR_BITMAP_KEY:
5326  return uindexattrs;
5328  return pkindexattrs;
5330  return idindexattrs;
5332  return hotblockingattrs;
5333  default:
5334  elog(ERROR, "unknown attrKind %u", attrKind);
5335  return NULL;
5336  }
5337 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3564
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4675
bool amhotblocking
Definition: amapi.h:248
Bitmapset * rd_keyattr
Definition: rel.h:159
struct IndexAmRoutine * rd_indam
Definition: rel.h:202
bool rd_attrsvalid
Definition: rel.h:158
Bitmapset * rd_hotblockingattr
Definition: rel.h:162
Oid rd_pkindex
Definition: rel.h:151
Bitmapset * rd_pkattr
Definition: rel.h:160
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:288

References AccessShareLock, IndexAmRoutine::amhotblocking, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, GetPgIndexDescriptor(), heap_getattr(), i, INDEX_ATTR_BITMAP_HOT_BLOCKING, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, index_close(), index_open(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, pull_varattnos(), RelationData::rd_attrsvalid, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_replidindex, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

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

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4909 of file relcache.c.

4910 {
4911  List *result;
4912  Datum exprsDatum;
4913  bool isnull;
4914  char *exprsString;
4915  MemoryContext oldcxt;
4916 
4917  /* Quick exit if we already computed the result. */
4918  if (relation->rd_indexprs)
4919  return copyObject(relation->rd_indexprs);
4920 
4921  /* Quick exit if there is nothing to do. */
4922  if (relation->rd_indextuple == NULL ||
4923  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4924  return NIL;
4925 
4926  /*
4927  * We build the tree we intend to return in the caller's context. After
4928  * successfully completing the work, we copy it into the relcache entry.
4929  * This avoids problems if we get some sort of error partway through.
4930  */
4931  exprsDatum = heap_getattr(relation->rd_indextuple,
4932  Anum_pg_index_indexprs,
4934  &isnull);
4935  Assert(!isnull);
4936  exprsString = TextDatumGetCString(exprsDatum);
4937  result = (List *) stringToNode(exprsString);
4938  pfree(exprsString);
4939 
4940  /*
4941  * Run the expressions through eval_const_expressions. This is not just an
4942  * optimization, but is necessary, because the planner will be comparing
4943  * them to similarly-processed qual clauses, and may fail to detect valid
4944  * matches without this. We must not use canonicalize_qual, however,
4945  * since these aren't qual expressions.
4946  */
4947  result = (List *) eval_const_expressions(NULL, (Node *) result);
4948 
4949  /* May as well fix opfuncids too */
4950  fix_opfuncids((Node *) result);
4951 
4952  /* Now save a copy of the completed tree in the relcache entry. */
4953  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
4954  relation->rd_indexprs = copyObject(result);
4955  MemoryContextSwitchTo(oldcxt);
4956 
4957  return result;
4958 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2150
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1763
List * rd_indexprs
Definition: rel.h:208

References Assert(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_relation_info(), GetIndexInputType(), index_unchanged_by_update(), infer_arbiter_indexes(), plan_create_index_workers(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4675 of file relcache.c.

4676 {
4677  Relation indrel;
4678  SysScanDesc indscan;
4679  ScanKeyData skey;
4680  HeapTuple htup;
4681  List *result;
4682  List *oldlist;
4683  char replident = relation->rd_rel->relreplident;
4684  Oid pkeyIndex = InvalidOid;
4685  Oid candidateIndex = InvalidOid;
4686  MemoryContext oldcxt;
4687 
4688  /* Quick exit if we already computed the list. */
4689  if (relation->rd_indexvalid)
4690  return list_copy(relation->rd_indexlist);
4691 
4692  /*
4693  * We build the list we intend to return (in the caller's context) while
4694  * doing the scan. After successfully completing the scan, we copy that
4695  * list into the relcache entry. This avoids cache-context memory leakage
4696  * if we get some sort of error partway through.
4697  */
4698  result = NIL;
4699 
4700  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4701  ScanKeyInit(&skey,
4702  Anum_pg_index_indrelid,
4703  BTEqualStrategyNumber, F_OIDEQ,
4704  ObjectIdGetDatum(RelationGetRelid(relation)));
4705 
4706  indrel = table_open(IndexRelationId, AccessShareLock);
4707  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4708  NULL, 1, &skey);
4709 
4710  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4711  {
4713 
4714  /*
4715  * Ignore any indexes that are currently being dropped. This will
4716  * prevent them from being searched, inserted into, or considered in
4717  * HOT-safety decisions. It's unsafe to touch such an index at all
4718  * since its catalog entries could disappear at any instant.
4719  */
4720  if (!index->indislive)
4721  continue;
4722 
4723  /* add index's OID to result list */
4724  result = lappend_oid(result, index->indexrelid);
4725 
4726  /*
4727  * Invalid, non-unique, non-immediate or predicate indexes aren't
4728  * interesting for either oid indexes or replication identity indexes,
4729  * so don't check them.
4730  */
4731  if (!index->indisvalid || !index->indisunique ||
4732  !index->indimmediate ||
4733  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4734  continue;
4735 
4736  /* remember primary key index if any */
4737  if (index->indisprimary)
4738  pkeyIndex = index->indexrelid;
4739 
4740  /* remember explicitly chosen replica index */
4741  if (index->indisreplident)
4742  candidateIndex = index->indexrelid;
4743  }
4744 
4745  systable_endscan(indscan);
4746 
4747  table_close(indrel, AccessShareLock);
4748 
4749  /* Sort the result list into OID order, per API spec. */
4750  list_sort(result, list_oid_cmp);
4751 
4752  /* Now save a copy of the completed list in the relcache entry. */
4754  oldlist = relation->rd_indexlist;
4755  relation->rd_indexlist = list_copy(result);
4756  relation->rd_pkindex = pkeyIndex;
4757  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4758  relation->rd_replidindex = pkeyIndex;
4759  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4760  relation->rd_replidindex = candidateIndex;
4761  else
4762  relation->rd_replidindex = InvalidOid;
4763  relation->rd_indexvalid = true;
4764  MemoryContextSwitchTo(oldcxt);
4765 
4766  /* Don't leak the old list, if there is one */
4767  list_free(oldlist);
4768 
4769  return result;
4770 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1612
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
List * list_copy(const List *oldlist)
Definition: list.c:1532
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1645
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool rd_indexvalid
Definition: rel.h:63
List * rd_indexlist
Definition: rel.h:150
Definition: type.h:90

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT, heap_attisnull(), HeapTupleIsValid, InvalidOid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum, OidIsValid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterIndexNamespaces(), ATExecChangeOwner(), ATExecDropNotNull(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), expandTableLikeClause(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5022 of file relcache.c.

5023 {
5024  List *result;
5025  Datum predDatum;
5026  bool isnull;
5027  char *predString;
5028  MemoryContext oldcxt;
5029 
5030  /* Quick exit if we already computed the result. */
5031  if (relation->rd_indpred)
5032  return copyObject(relation->rd_indpred);
5033 
5034  /* Quick exit if there is nothing to do. */
5035  if (relation->rd_indextuple == NULL ||
5036  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5037  return NIL;
5038 
5039  /*
5040  * We build the tree we intend to return in the caller's context. After
5041  * successfully completing the work, we copy it into the relcache entry.
5042  * This avoids problems if we get some sort of error partway through.
5043  */
5044  predDatum = heap_getattr(relation->rd_indextuple,
5045  Anum_pg_index_indpred,
5047  &isnull);
5048  Assert(!isnull);
5049  predString = TextDatumGetCString(predDatum);
5050  result = (List *) stringToNode(predString);
5051  pfree(predString);
5052 
5053  /*
5054  * Run the expression through const-simplification and canonicalization.
5055  * This is not just an optimization, but is necessary, because the planner
5056  * will be comparing it to similarly-processed qual clauses, and may fail
5057  * to detect valid matches without this. This must match the processing
5058  * done to qual clauses in preprocess_expression()! (We can skip the
5059  * stuff involving subqueries, however, since we don't allow any in index
5060  * predicates.)
5061  */
5062  result = (List *) eval_const_expressions(NULL, (Node *) result);
5063 
5064  result = (List *) canonicalize_qual((Expr *) result, false);
5065 
5066  /* Also convert to implicit-AND format */
5067  result = make_ands_implicit((Expr *) result);
5068 
5069  /* May as well fix opfuncids too */
5070  fix_opfuncids((Node *) result);
5071 
5072  /* Now save a copy of the completed tree in the relcache entry. */
5073  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5074  relation->rd_indpred = copyObject(result);
5075  MemoryContextSwitchTo(oldcxt);
5076 
5077  return result;
5078 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:720
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:294
List * rd_indpred
Definition: rel.h:209

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

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  relation)

Definition at line 5712 of file relcache.c.

5713 {
5714  Oid indexrelid = RelationGetRelid(indexrel);
5715  int16 natts = RelationGetNumberOfAttributes(indexrel);
5716  Datum *options = NULL;
5717  int16 attnum;
5718 
5719  for (attnum = 1; attnum <= natts; attnum++)
5720  {
5721  if (indexrel->rd_indam->amoptsprocnum == 0)
5722  continue;
5723 
5724  if (!OidIsValid(index_getprocid(indexrel, attnum,
5725  indexrel->rd_indam->amoptsprocnum)))
5726  continue;
5727 
5728  if (!options)
5729  options = palloc0(sizeof(Datum) * natts);
5730 
5731  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5732  }
5733 
5734  return options;
5735 }
signed short int16
Definition: c.h:428
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769
static char ** options

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

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4863 of file relcache.c.

4864 {
4865  List *ilist;
4866 
4867  if (!relation->rd_indexvalid)
4868  {
4869  /* RelationGetIndexList does the heavy lifting. */
4870  ilist = RelationGetIndexList(relation);
4871  list_free(ilist);
4872  Assert(relation->rd_indexvalid);
4873  }
4874 
4875  return relation->rd_pkindex;
4876 }

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

Referenced by build_replindex_scan_key(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4884 of file relcache.c.

4885 {
4886  List *ilist;
4887 
4888  if (!relation->rd_indexvalid)
4889  {
4890  /* RelationGetIndexList does the heavy lifting. */
4891  ilist = RelationGetIndexList(relation);
4892  list_free(ilist);
4893  Assert(relation->rd_indexvalid);
4894  }
4895 
4896  return relation->rd_replidindex;
4897 }

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4794 of file relcache.c.

4795 {
4796  Relation indrel;
4797  SysScanDesc indscan;
4798  ScanKeyData skey;
4799  HeapTuple htup;
4800  List *result;
4801  List *oldlist;
4802  MemoryContext oldcxt;
4803 
4804  /* Quick exit if we already computed the list. */
4805  if (relation->rd_statvalid != 0)
4806  return list_copy(relation->rd_statlist);
4807 
4808  /*
4809  * We build the list we intend to return (in the caller's context) while
4810  * doing the scan. After successfully completing the scan, we copy that
4811  * list into the relcache entry. This avoids cache-context memory leakage
4812  * if we get some sort of error partway through.
4813  */
4814  result = NIL;
4815 
4816  /*
4817  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4818  * rel.
4819  */
4820  ScanKeyInit(&skey,
4821  Anum_pg_statistic_ext_stxrelid,
4822  BTEqualStrategyNumber, F_OIDEQ,
4823  ObjectIdGetDatum(RelationGetRelid(relation)));
4824 
4825  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4826  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4827  NULL, 1, &skey);
4828 
4829  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4830  {
4831  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4832 
4833  result = lappend_oid(result, oid);
4834  }
4835 
4836  systable_endscan(indscan);
4837 
4838  table_close(indrel, AccessShareLock);
4839 
4840  /* Sort the result list into OID order, per API spec. */
4841  list_sort(result, list_oid_cmp);
4842 
4843  /* Now save a copy of the completed list in the relcache entry. */
4845  oldlist = relation->rd_statlist;
4846  relation->rd_statlist = list_copy(result);
4847 
4848  relation->rd_statvalid = true;
4849  MemoryContextSwitchTo(oldcxt);
4850 
4851  /* Don't leak the old list, if there is one */
4852  list_free(oldlist);
4853 
4854  return result;
4855 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:65
List * rd_statlist
Definition: rel.h:155

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT, HeapTupleIsValid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum, RelationData::rd_statlist, RelationData::rd_statvalid, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_relation_statistics(), and transformTableLikeClause().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2053 of file relcache.c.

2054 {
2055  Relation rd;
2056 
2057  /* Make sure we're in an xact, even if this ends up being a cache hit */
2059 
2060  /*
2061  * first try to find reldesc in the cache
2062  */
2063  RelationIdCacheLookup(relationId, rd);
2064 
2065  if (RelationIsValid(rd))
2066  {
2067  /* return NULL for dropped relations */
2069  {
2070  Assert(!rd->rd_isvalid);
2071  return NULL;
2072  }
2073 
2075  /* revalidate cache entry if necessary */
2076  if (!rd->rd_isvalid)
2077  {
2078  /*
2079  * Indexes only have a limited number of possible schema changes,
2080  * and we don't want to use the full-blown procedure because it's
2081  * a headache for indexes that reload itself depends on.
2082  */
2083  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2084  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2086  else
2087  RelationClearRelation(rd, true);
2088 
2089  /*
2090  * Normally entries need to be valid here, but before the relcache
2091  * has been initialized, not enough infrastructure exists to
2092  * perform pg_class lookups. The structure of such entries doesn't
2093  * change, but we still want to update the rd_rel entry. So
2094  * rd_isvalid = false is left in place for a later lookup.
2095  */
2096  Assert(rd->rd_isvalid ||
2098  }
2099  return rd;
2100  }
2101 
2102  /*
2103  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2104  * it.
2105  */
2106  rd = RelationBuildDesc(relationId, true);
2107  if (RelationIsValid(rd))
2109  return rd;
2110 }
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1037
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2216
bool IsTransactionState(void)
Definition: xact.c:374

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

Referenced by init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_ensure_entry_cxt(), pgoutput_row_filter_init(), relation_open(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6581 of file relcache.c.

6582 {
6583  if (relationId == SharedSecLabelRelationId ||
6584  relationId == TriggerRelidNameIndexId ||
6585  relationId == DatabaseNameIndexId ||
6586  relationId == SharedSecLabelObjectIndexId)
6587  {
6588  /*
6589  * If this Assert fails, we don't need the applicable special case
6590  * anymore.
6591  */
6592  Assert(!RelationSupportsSysCache(relationId));
6593  return true;
6594  }
6595  return RelationSupportsSysCache(relationId);
6596 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1578

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1416 of file relcache.c.

1417 {
1418  HeapTuple tuple;
1419  Form_pg_am aform;
1420  Datum indcollDatum;
1421  Datum indclassDatum;
1422  Datum indoptionDatum;
1423  bool isnull;
1424  oidvector *indcoll;
1425  oidvector *indclass;
1426  int2vector *indoption;
1427  MemoryContext indexcxt;
1428  MemoryContext oldcontext;
1429  int indnatts;
1430  int indnkeyatts;
1431  uint16 amsupport;
1432 
1433  /*
1434  * Make a copy of the pg_index entry for the index. Since pg_index
1435  * contains variable-length and possibly-null fields, we have to do this
1436  * honestly rather than just treating it as a Form_pg_index struct.
1437  */
1438  tuple = SearchSysCache1(INDEXRELID,
1439  ObjectIdGetDatum(RelationGetRelid(relation)));
1440  if (!HeapTupleIsValid(tuple))
1441  elog(ERROR, "cache lookup failed for index %u",
1442  RelationGetRelid(relation));
1444  relation->rd_indextuple = heap_copytuple(tuple);
1445  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1446  MemoryContextSwitchTo(oldcontext);
1447  ReleaseSysCache(tuple);
1448 
1449  /*
1450  * Look up the index's access method, save the OID of its handler function
1451  */
1452  Assert(relation->rd_rel->relam != InvalidOid);
1453  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1454  if (!HeapTupleIsValid(tuple))
1455  elog(ERROR, "cache lookup failed for access method %u",
1456  relation->rd_rel->relam);
1457  aform = (Form_pg_am) GETSTRUCT(tuple);
1458  relation->rd_amhandler = aform->amhandler;
1459  ReleaseSysCache(tuple);
1460 
1461  indnatts = RelationGetNumberOfAttributes(relation);
1462  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1463  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1464  RelationGetRelid(relation));
1465  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1466 
1467  /*
1468  * Make the private context to hold index access info. The reason we need
1469  * a context, and not just a couple of pallocs, is so that we won't leak
1470  * any subsidiary info attached to fmgr lookup records.
1471  */
1473  "index info",
1475  relation->rd_indexcxt = indexcxt;
1477  RelationGetRelationName(relation));
1478 
1479  /*
1480  * Now we can fetch the index AM's API struct
1481  */
1482  InitIndexAmRoutine(relation);
1483 
1484  /*
1485  * Allocate arrays to hold data. Opclasses are not used for included
1486  * columns, so allocate them for indnkeyatts only.
1487  */
1488  relation->rd_opfamily = (Oid *)
1489  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1490  relation->rd_opcintype = (Oid *)
1491  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1492 
1493  amsupport = relation->rd_indam->amsupport;
1494  if (amsupport > 0)
1495  {
1496  int nsupport = indnatts * amsupport;
1497 
1498  relation->rd_support = (RegProcedure *)
1499  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1500  relation->rd_supportinfo = (FmgrInfo *)
1501  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1502  }
1503  else
1504  {
1505  relation->rd_support = NULL;
1506  relation->rd_supportinfo = NULL;
1507  }
1508 
1509  relation->rd_indcollation = (Oid *)
1510  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1511 
1512  relation->rd_indoption = (int16 *)
1513  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1514 
1515  /*
1516  * indcollation cannot be referenced directly through the C struct,
1517  * because it comes after the variable-width indkey field. Must extract
1518  * the datum the hard way...
1519  */
1520  indcollDatum = fastgetattr(relation->rd_indextuple,
1521  Anum_pg_index_indcollation,
1523  &isnull);
1524  Assert(!isnull);
1525  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1526  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1527 
1528  /*
1529  * indclass cannot be referenced directly through the C struct, because it
1530  * comes after the variable-width indkey field. Must extract the datum
1531  * the hard way...
1532  */
1533  indclassDatum = fastgetattr(relation->rd_indextuple,
1534  Anum_pg_index_indclass,
1536  &isnull);
1537  Assert(!isnull);
1538  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1539 
1540  /*
1541  * Fill the support procedure OID array, as well as the info about
1542  * opfamilies and opclass input types. (aminfo and supportinfo are left
1543  * as zeroes, and are filled on-the-fly when used)
1544  */
1545  IndexSupportInitialize(indclass, relation->rd_support,
1546  relation->rd_opfamily, relation->rd_opcintype,
1547  amsupport, indnkeyatts);
1548 
1549  /*
1550  * Similarly extract indoption and copy it to the cache entry
1551  */
1552  indoptionDatum = fastgetattr(relation->rd_indextuple,
1553  Anum_pg_index_indoption,
1555  &isnull);
1556  Assert(!isnull);
1557  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1558  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1559 
1560  (void) RelationGetIndexAttOptions(relation, false);
1561 
1562  /*
1563  * expressions, predicate, exclusion caches will be filled later
1564  */
1565  relation->rd_indexprs = NIL;
1566  relation->rd_indpred = NIL;
1567  relation->rd_exclops = NULL;
1568  relation->rd_exclprocs = NULL;
1569  relation->rd_exclstrats = NULL;
1570  relation->rd_amcache = NULL;
1571 }
regproc RegProcedure
Definition: c.h:585
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:207
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:98
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:501
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1392
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1587
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5758
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:216
RegProcedure * rd_support
Definition: rel.h:205
Oid * rd_opcintype
Definition: rel.h:204
int16 * rd_indoption
Definition: rel.h:207
void * rd_amcache
Definition: rel.h:225
Oid rd_amhandler
Definition: rel.h:180
struct FmgrInfo * rd_supportinfo
Definition: rel.h:206
Oid * rd_indcollation
Definition: rel.h:213
Definition: c.h:650
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:657
Definition: c.h:661
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:668
@ AMOID
Definition: syscache.h:36
@ INDEXRELID
Definition: syscache.h:66

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, AMOID, IndexAmRoutine::amsupport, Assert(), CacheMemoryContext, DatumGetPointer, elog, ERROR, fastgetattr(), GetPgIndexDescriptor(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, INDEXRELID, IndexSupportInitialize(), InitIndexAmRoutine(), InvalidOid, MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, ObjectIdGetDatum, RelationData::rd_amcache, RelationData::rd_amhandler, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_support, RelationData::rd_supportinfo, RelationGetIndexAttOptions(), RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1800 of file relcache.c.

1801 {
1802  HeapTuple tuple;
1803  Form_pg_am aform;
1804 
1805  if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1806  {
1807  /*
1808  * Sequences are currently accessed like heap tables, but it doesn't
1809  * seem prudent to show that in the catalog. So just overwrite it
1810  * here.
1811  */
1812  Assert(relation->rd_rel->relam == InvalidOid);
1813  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1814  }
1815  else if (IsCatalogRelation(relation))
1816  {
1817  /*
1818  * Avoid doing a syscache lookup for catalog tables.
1819  */
1820  Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1821  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1822  }
1823  else
1824  {
1825  /*
1826  * Look up the table access method, save the OID of its handler
1827  * function.
1828  */
1829  Assert(relation->rd_rel->relam != InvalidOid);
1830  tuple = SearchSysCache1(AMOID,
1831  ObjectIdGetDatum(relation->rd_rel->relam));
1832  if (!HeapTupleIsValid(tuple))
1833  elog(ERROR, "cache lookup failed for access method %u",
1834  relation->rd_rel->relam);
1835  aform = (Form_pg_am) GETSTRUCT(tuple);
1836  relation->rd_amhandler = aform->amhandler;
1837  ReleaseSysCache(tuple);
1838  }
1839 
1840  /*
1841  * Now we can fetch the table AM's API struct
1842  */
1843  InitTableAmRoutine(relation);
1844 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:105
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1791

References AMOID, Assert(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, InitTableAmRoutine(), InvalidOid, IsCatalogRelation(), ObjectIdGetDatum, RelationData::rd_amhandler, RelationData::rd_rel, ReleaseSysCache(), and SearchSysCache1().

Referenced by load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), and RelationCacheInitializePhase3().

◆ RelationSetNewRelfilenode()

void RelationSetNewRelfilenode ( Relation  relation,
char  persistence 
)

Definition at line 3700 of file relcache.c.

3701 {
3702  Oid newrelfilenode;
3703  Relation pg_class;
3704  HeapTuple tuple;
3705  Form_pg_class classform;
3706  MultiXactId minmulti = InvalidMultiXactId;
3707  TransactionId freezeXid = InvalidTransactionId;
3708  RelFileNode newrnode;
3709 
3710  /* Allocate a new relfilenode */
3711  newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
3712  persistence);
3713 
3714  /*
3715  * Get a writable copy of the pg_class tuple for the given relation.
3716  */
3717  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3718 
3719  tuple = SearchSysCacheCopy1(RELOID,
3720  ObjectIdGetDatum(RelationGetRelid(relation)));
3721  if (!HeapTupleIsValid(tuple))
3722  elog(ERROR, "could not find tuple for relation %u",
3723  RelationGetRelid(relation));
3724  classform = (Form_pg_class) GETSTRUCT(tuple);
3725 
3726  /*
3727  * Schedule unlinking of the old storage at transaction commit.
3728  */
3729  RelationDropStorage(relation);
3730 
3731  /*
3732  * Create storage for the main fork of the new relfilenode. If it's a
3733  * table-like object, call into the table AM to do so, which'll also
3734  * create the table's init fork if needed.
3735  *
3736  * NOTE: If relevant for the AM, any conflict in relfilenode value will be
3737  * caught here, if GetNewRelFileNode messes up for any reason.
3738  */
3739  newrnode = relation->rd_node;
3740  newrnode.relNode = newrelfilenode;
3741 
3742  if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3743  {
3744  table_relation_set_new_filenode(relation, &newrnode,
3745  persistence,
3746  &freezeXid, &minmulti);
3747  }
3748  else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3749  {
3750  /* handle these directly, at least for now */
3751  SMgrRelation srel;
3752 
3753  srel = RelationCreateStorage(newrnode, persistence, true);
3754  smgrclose(srel);
3755  }
3756  else
3757  {
3758  /* we shouldn't be called for anything else */
3759  elog(ERROR, "relation \"%s\" does not have storage",
3760  RelationGetRelationName(relation));
3761  }
3762 
3763  /*
3764  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3765  * change; instead we have to send the update to the relation mapper.
3766  *
3767  * For mapped indexes, we don't actually change the pg_class entry at all;
3768  * this is essential when reindexing pg_class itself. That leaves us with
3769  * possibly-inaccurate values of relpages etc, but those will be fixed up
3770  * later.
3771  */
3772  if (RelationIsMapped(relation))
3773  {
3774  /* This case is only supported for indexes */
3775  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3776 
3777  /* Since we're not updating pg_class, these had better not change */
3778  Assert(classform->relfrozenxid == freezeXid);
3779  Assert(classform->relminmxid == minmulti);
3780  Assert(classform->relpersistence == persistence);
3781 
3782  /*
3783  * In some code paths it's possible that the tuple update we'd
3784  * otherwise do here is the only thing that would assign an XID for
3785  * the current transaction. However, we must have an XID to delete
3786  * files, so make sure one is assigned.
3787  */
3788  (void) GetCurrentTransactionId();
3789 
3790  /* Do the deed */
3792  newrelfilenode,
3793  relation->rd_rel->relisshared,
3794  false);
3795 
3796  /* Since we're not updating pg_class, must trigger inval manually */
3797  CacheInvalidateRelcache(relation);
3798  }
3799  else
3800  {
3801  /* Normal case, update the pg_class entry */
3802  classform->relfilenode = newrelfilenode;
3803 
3804  /* relpages etc. never change for sequences */
3805  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3806  {
3807  classform->relpages = 0; /* it's empty until further notice */
3808  classform->reltuples = -1;
3809  classform->relallvisible = 0;
3810  }
3811  classform->relfrozenxid = freezeXid;
3812  classform->relminmxid = minmulti;
3813  classform->relpersistence = persistence;
3814 
3815  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3816  }
3817 
3818  heap_freetuple(tuple);
3819 
3820  table_close(pg_class, RowExclusiveLock);
3821 
3822  /*
3823  * Make the pg_class row change or relation map change visible. This will
3824  * cause the relcache entry to get updated, too.
3825  */
3827 
3828  RelationAssumeNewRelfilenode(relation);
3829 }
TransactionId MultiXactId
Definition: c.h:597
uint32 TransactionId
Definition: c.h:587
Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1363
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilenode(Relation relation)
Definition: relcache.c:3844
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
SMgrRelation RelationCreateStorage(RelFileNode rnode, char relpersistence, bool register_delete)
Definition: storage.c:120
void RelationDropStorage(Relation rel)
Definition: storage.c:205
ItemPointerData t_self
Definition: htup.h:65
RelFileNode rd_node
Definition: rel.h:56
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
static void table_relation_set_new_filenode(Relation rel, const RelFileNode *newrnode, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1592
#define InvalidTransactionId
Definition: transam.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1074
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:441

References Assert(), CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ERROR, GetCurrentTransactionId(), GetNewRelFileNode(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidMultiXactId, InvalidTransactionId, ObjectIdGetDatum, RelationData::rd_node, RelationData::rd_rel, RelationAssumeNewRelfilenode(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileNode::relNode, RELOID, RowExclusiveLock, SearchSysCacheCopy1, smgrclose(), HeapTupleData::t_self, table_close(), table_open(), and table_relation_set_new_filenode().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt