PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
relcache.h File Reference
#include "access/tupdesc.h"
#include "common/relpath.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 ,
  INDEX_ATTR_BITMAP_SUMMARIZED
}
 

Functions

Relation RelationIdGetRelation (Oid relationId)
 
void RelationClose (Relation relation)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation, bool deferrable_ok)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetDummyIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (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, RelFileNumber relfilenumber, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenumber (Relation relation, char persistence)
 
void RelationAssumeNewRelfilelocator (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (bool debug_discard)
 
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 135 of file relcache.h.

◆ RELCACHE_INIT_FILENAME

#define RELCACHE_INIT_FILENAME   "pg_internal.init"

Definition at line 25 of file relcache.h.

Typedef Documentation

◆ IndexAttrBitmapKind

◆ Relation

typedef struct RelationData* Relation

Definition at line 27 of file relcache.h.

◆ RelationPtr

Definition at line 35 of file relcache.h.

Enumeration Type Documentation

◆ IndexAttrBitmapKind

Enumerator
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 
INDEX_ATTR_BITMAP_HOT_BLOCKING 
INDEX_ATTR_BITMAP_SUMMARIZED 

Definition at line 59 of file relcache.h.

60 {
IndexAttrBitmapKind
Definition: relcache.h:60
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:64
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:65
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3344 of file relcache.c.

3346 {
3347  HASH_SEQ_STATUS status;
3348  RelIdCacheEnt *idhentry;
3349  int i;
3350 
3351  /*
3352  * Forget in_progress_list. This is relevant when we're aborting due to
3353  * an error during RelationBuildDesc(). We don't commit subtransactions
3354  * during RelationBuildDesc().
3355  */
3356  Assert(in_progress_list_len == 0 || !isCommit);
3358 
3359  /*
3360  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3361  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3362  * logic as in AtEOXact_RelationCache.
3363  */
3365  {
3366  hash_seq_init(&status, RelationIdCache);
3367  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3368  {
3369  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3370  mySubid, parentSubid);
3371  }
3372  }
3373  else
3374  {
3375  for (i = 0; i < eoxact_list_len; i++)
3376  {
3377  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3378  &eoxact_list[i],
3379  HASH_FIND,
3380  NULL);
3381  if (idhentry != NULL)
3382  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3383  mySubid, parentSubid);
3384  }
3385  }
3386 
3387  /* Don't reset the list; we still need more cleanup later */
3388 }
#define Assert(condition)
Definition: c.h:863
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:72
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3399
static int eoxact_list_len
Definition: relcache.c:186
static bool eoxact_list_overflowed
Definition: relcache.c:187
static HTAB * RelationIdCache
Definition: relcache.c:134
Relation reldesc
Definition: relcache.c:131

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, and relidcacheent::reldesc.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3192 of file relcache.c.

3193 {
3194  HASH_SEQ_STATUS status;
3195  RelIdCacheEnt *idhentry;
3196  int i;
3197 
3198  /*
3199  * Forget in_progress_list. This is relevant when we're aborting due to
3200  * an error during RelationBuildDesc().
3201  */
3202  Assert(in_progress_list_len == 0 || !isCommit);
3204 
3205  /*
3206  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3207  * listed in it. Otherwise fall back on a hash_seq_search scan.
3208  *
3209  * For simplicity, eoxact_list[] entries are not deleted till end of
3210  * top-level transaction, even though we could remove them at
3211  * subtransaction end in some cases, or remove relations from the list if
3212  * they are cleared for other reasons. Therefore we should expect the
3213  * case that list entries are not found in the hashtable; if not, there's
3214  * nothing to do for them.
3215  */
3217  {
3218  hash_seq_init(&status, RelationIdCache);
3219  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3220  {
3221  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3222  }
3223  }
3224  else
3225  {
3226  for (i = 0; i < eoxact_list_len; i++)
3227  {
3228  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3229  &eoxact_list[i],
3230  HASH_FIND,
3231  NULL);
3232  if (idhentry != NULL)
3233  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3234  }
3235  }
3236 
3237  if (EOXactTupleDescArrayLen > 0)
3238  {
3239  Assert(EOXactTupleDescArray != NULL);
3240  for (i = 0; i < NextEOXactTupleDescNum; i++)
3243  EOXactTupleDescArray = NULL;
3244  }
3245 
3246  /* Now we're out of the transaction and can clear the lists */
3247  eoxact_list_len = 0;
3248  eoxact_list_overflowed = false;
3251 }
void pfree(void *pointer)
Definition: mcxt.c:1521
static int NextEOXactTupleDescNum
Definition: relcache.c:203
static int EOXactTupleDescArrayLen
Definition: relcache.c:204
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3262
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331

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, and relidcacheent::reldesc.

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5948 of file relcache.c.

5949 {
5953 
5954  return 0; /* return value does not matter */
5955 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546

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 5965 of file relcache.c.

5966 {
5967  TupleDesc reldesc = RelationGetDescr(rel);
5968  const char *colname;
5969 
5970  /* Use reldesc if it's a user attribute, else consult the catalogs */
5971  if (attnum > 0 && attnum <= reldesc->natts)
5972  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5973  else
5974  colname = get_attname(RelationGetRelid(rel), attnum, false);
5975 
5976  return errtablecolname(rel, colname);
5977 }
#define NameStr(name)
Definition: c.h:751
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5989
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

Referenced by ATRewriteTable(), ExecConstraints(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5989 of file relcache.c.

5990 {
5991  errtable(rel);
5993 
5994  return 0; /* return value does not matter */
5995 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5948

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3932 of file relcache.c.

3933 {
3937 
3938  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3939  EOXactListAdd(relation);
3940 }
#define InvalidSubTransactionId
Definition: c.h:663
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilelocatorSubid, and RelationData::rd_newRelfilelocatorSubid.

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

◆ RelationBuildLocalRelation()

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

Definition at line 3481 of file relcache.c.

3492 {
3493  Relation rel;
3494  MemoryContext oldcxt;
3495  int natts = tupDesc->natts;
3496  int i;
3497  bool has_not_null;
3498  bool nailit;
3499 
3500  Assert(natts >= 0);
3501 
3502  /*
3503  * check for creation of a rel that must be nailed in cache.
3504  *
3505  * XXX this list had better match the relations specially handled in
3506  * RelationCacheInitializePhase2/3.
3507  */
3508  switch (relid)
3509  {
3510  case DatabaseRelationId:
3511  case AuthIdRelationId:
3512  case AuthMemRelationId:
3513  case RelationRelationId:
3514  case AttributeRelationId:
3515  case ProcedureRelationId:
3516  case TypeRelationId:
3517  nailit = true;
3518  break;
3519  default:
3520  nailit = false;
3521  break;
3522  }
3523 
3524  /*
3525  * check that hardwired list of shared rels matches what's in the
3526  * bootstrap .bki file. If you get a failure here during initdb, you
3527  * probably need to fix IsSharedRelation() to match whatever you've done
3528  * to the set of shared relations.
3529  */
3530  if (shared_relation != IsSharedRelation(relid))
3531  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3532  relname, relid);
3533 
3534  /* Shared relations had better be mapped, too */
3535  Assert(mapped_relation || !shared_relation);
3536 
3537  /*
3538  * switch to the cache context to create the relcache entry.
3539  */
3540  if (!CacheMemoryContext)
3542 
3544 
3545  /*
3546  * allocate a new relation descriptor and fill in basic state fields.
3547  */
3548  rel = (Relation) palloc0(sizeof(RelationData));
3549 
3550  /* make sure relation is marked as having no open file yet */
3551  rel->rd_smgr = NULL;
3552 
3553  /* mark it nailed if appropriate */
3554  rel->rd_isnailed = nailit;
3555 
3556  rel->rd_refcnt = nailit ? 1 : 0;
3557 
3558  /* it's being created in this transaction */
3563 
3564  /*
3565  * create a new tuple descriptor from the one passed in. We do this
3566  * partly to copy it into the cache context, and partly because the new
3567  * relation can't have any defaults or constraints yet; they have to be
3568  * added in later steps, because they require additions to multiple system
3569  * catalogs. We can copy attnotnull constraints here, however.
3570  */
3571  rel->rd_att = CreateTupleDescCopy(tupDesc);
3572  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3573  has_not_null = false;
3574  for (i = 0; i < natts; i++)
3575  {
3576  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3577  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3578 
3579  datt->attidentity = satt->attidentity;
3580  datt->attgenerated = satt->attgenerated;
3581  datt->attnotnull = satt->attnotnull;
3582  has_not_null |= satt->attnotnull;
3583  }
3584 
3585  if (has_not_null)
3586  {
3587  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3588 
3589  constr->has_not_null = true;
3590  rel->rd_att->constr = constr;
3591  }
3592 
3593  /*
3594  * initialize relation tuple form (caller may add/override data later)
3595  */
3597 
3598  namestrcpy(&rel->rd_rel->relname, relname);
3599  rel->rd_rel->relnamespace = relnamespace;
3600 
3601  rel->rd_rel->relkind = relkind;
3602  rel->rd_rel->relnatts = natts;
3603  rel->rd_rel->reltype = InvalidOid;
3604  /* needed when bootstrapping: */
3605  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3606 
3607  /* set up persistence and relcache fields dependent on it */
3608  rel->rd_rel->relpersistence = relpersistence;
3609  switch (relpersistence)
3610  {
3611  case RELPERSISTENCE_UNLOGGED:
3612  case RELPERSISTENCE_PERMANENT:
3614  rel->rd_islocaltemp = false;
3615  break;
3616  case RELPERSISTENCE_TEMP:
3617  Assert(isTempOrTempToastNamespace(relnamespace));
3619  rel->rd_islocaltemp = true;
3620  break;
3621  default:
3622  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3623  break;
3624  }
3625 
3626  /* if it's a materialized view, it's not populated initially */
3627  if (relkind == RELKIND_MATVIEW)
3628  rel->rd_rel->relispopulated = false;
3629  else
3630  rel->rd_rel->relispopulated = true;
3631 
3632  /* set replica identity -- system catalogs and non-tables don't have one */
3633  if (!IsCatalogNamespace(relnamespace) &&
3634  (relkind == RELKIND_RELATION ||
3635  relkind == RELKIND_MATVIEW ||
3636  relkind == RELKIND_PARTITIONED_TABLE))
3637  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3638  else
3639  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3640 
3641  /*
3642  * Insert relation physical and logical identifiers (OIDs) into the right
3643  * places. For a mapped relation, we set relfilenumber to zero and rely
3644  * on RelationInitPhysicalAddr to consult the map.
3645  */
3646  rel->rd_rel->relisshared = shared_relation;
3647 
3648  RelationGetRelid(rel) = relid;
3649 
3650  for (i = 0; i < natts; i++)
3651  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3652 
3653  rel->rd_rel->reltablespace = reltablespace;
3654 
3655  if (mapped_relation)
3656  {
3657  rel->rd_rel->relfilenode = InvalidRelFileNumber;
3658  /* Add it to the active mapping information */
3659  RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3660  }
3661  else
3662  rel->rd_rel->relfilenode = relfilenumber;
3663 
3664  RelationInitLockInfo(rel); /* see lmgr.c */
3665 
3667 
3668  rel->rd_rel->relam = accessmtd;
3669 
3670  /*
3671  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3672  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3673  * require a long-lived current context.
3674  */
3675  MemoryContextSwitchTo(oldcxt);
3676 
3677  if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3679 
3680  /*
3681  * Leave index access method uninitialized, because the pg_index row has
3682  * not been inserted at this stage of index creation yet. The cache
3683  * invalidation after pg_index row has been inserted will initialize it.
3684  */
3685 
3686  /*
3687  * Okay to insert into the relcache hash table.
3688  *
3689  * Ordinarily, there should certainly not be an existing hash entry for
3690  * the same OID; but during bootstrap, when we create a "real" relcache
3691  * entry for one of the bootstrap relations, we'll be overwriting the
3692  * phony one created with formrdesc. So allow that to happen for nailed
3693  * rels.
3694  */
3695  RelationCacheInsert(rel, nailit);
3696 
3697  /*
3698  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3699  * can't do this before storing relid in it.
3700  */
3701  EOXactListAdd(rel);
3702 
3703  /* It's fully valid */
3704  rel->rd_isvalid = true;
3705 
3706  /*
3707  * Caller expects us to pin the returned entry.
3708  */
3710 
3711  return rel;
3712 }
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:273
void CreateCacheMemoryContext(void)
Definition: catcache.c:680
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:70
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
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 ProcNumberForTempRelations()
Definition: proc.h:324
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
MemoryContextSwitchTo(old_ctx)
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:209
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2151
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1809
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1319
struct RelationData * Relation
Definition: relcache.h:27
void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared, bool immediate)
Definition: relmapper.c:325
#define InvalidRelFileNumber
Definition: relpath.h:26
ProcNumber rd_backend
Definition: rel.h:60
int rd_refcnt
Definition: rel.h:59
bool rd_isvalid
Definition: rel.h:63
bool rd_islocaltemp
Definition: rel.h:61
TupleDesc rd_att
Definition: rel.h:112
bool rd_isnailed
Definition: rel.h:62
SMgrRelation rd_smgr
Definition: rel.h:58
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_droppedSubid
Definition: rel.h:109
Form_pg_class rd_rel
Definition: rel.h:111
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:133

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), ProcNumberForTempRelations, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, 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 5719 of file relcache.c.

5720 {
5721  List *puboids;
5722  ListCell *lc;
5723  MemoryContext oldcxt;
5724  Oid schemaid;
5725  List *ancestors = NIL;
5726  Oid relid = RelationGetRelid(relation);
5727 
5728  /*
5729  * If not publishable, it publishes no actions. (pgoutput_change() will
5730  * ignore it.)
5731  */
5732  if (!is_publishable_relation(relation))
5733  {
5734  memset(pubdesc, 0, sizeof(PublicationDesc));
5735  pubdesc->rf_valid_for_update = true;
5736  pubdesc->rf_valid_for_delete = true;
5737  pubdesc->cols_valid_for_update = true;
5738  pubdesc->cols_valid_for_delete = true;
5739  return;
5740  }
5741 
5742  if (relation->rd_pubdesc)
5743  {
5744  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5745  return;
5746  }
5747 
5748  memset(pubdesc, 0, sizeof(PublicationDesc));
5749  pubdesc->rf_valid_for_update = true;
5750  pubdesc->rf_valid_for_delete = true;
5751  pubdesc->cols_valid_for_update = true;
5752  pubdesc->cols_valid_for_delete = true;
5753 
5754  /* Fetch the publication membership info. */
5755  puboids = GetRelationPublications(relid);
5756  schemaid = RelationGetNamespace(relation);
5757  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5758 
5759  if (relation->rd_rel->relispartition)
5760  {
5761  /* Add publications that the ancestors are in too. */
5762  ancestors = get_partition_ancestors(relid);
5763 
5764  foreach(lc, ancestors)
5765  {
5766  Oid ancestor = lfirst_oid(lc);
5767 
5768  puboids = list_concat_unique_oid(puboids,
5769  GetRelationPublications(ancestor));
5770  schemaid = get_rel_namespace(ancestor);
5771  puboids = list_concat_unique_oid(puboids,
5772  GetSchemaPublications(schemaid));
5773  }
5774  }
5775  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5776 
5777  foreach(lc, puboids)
5778  {
5779  Oid pubid = lfirst_oid(lc);
5780  HeapTuple tup;
5781  Form_pg_publication pubform;
5782 
5783  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5784 
5785  if (!HeapTupleIsValid(tup))
5786  elog(ERROR, "cache lookup failed for publication %u", pubid);
5787 
5788  pubform = (Form_pg_publication) GETSTRUCT(tup);
5789 
5790  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5791  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5792  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5793  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5794 
5795  /*
5796  * Check if all columns referenced in the filter expression are part
5797  * of the REPLICA IDENTITY index or not.
5798  *
5799  * If the publication is FOR ALL TABLES then it means the table has no
5800  * row filters and we can skip the validation.
5801  */
5802  if (!pubform->puballtables &&
5803  (pubform->pubupdate || pubform->pubdelete) &&
5804  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5805  pubform->pubviaroot))
5806  {
5807  if (pubform->pubupdate)
5808  pubdesc->rf_valid_for_update = false;
5809  if (pubform->pubdelete)
5810  pubdesc->rf_valid_for_delete = false;
5811  }
5812 
5813  /*
5814  * Check if all columns are part of the REPLICA IDENTITY index or not.
5815  *
5816  * If the publication is FOR ALL TABLES then it means the table has no
5817  * column list and we can skip the validation.
5818  */
5819  if (!pubform->puballtables &&
5820  (pubform->pubupdate || pubform->pubdelete) &&
5821  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5822  pubform->pubviaroot))
5823  {
5824  if (pubform->pubupdate)
5825  pubdesc->cols_valid_for_update = false;
5826  if (pubform->pubdelete)
5827  pubdesc->cols_valid_for_delete = false;
5828  }
5829 
5830  ReleaseSysCache(tup);
5831 
5832  /*
5833  * If we know everything is replicated and the row filter is invalid
5834  * for update and delete, there is no point to check for other
5835  * publications.
5836  */
5837  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5838  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5839  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5840  break;
5841 
5842  /*
5843  * If we know everything is replicated and the column list is invalid
5844  * for update and delete, there is no point to check for other
5845  * publications.
5846  */
5847  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5848  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5849  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5850  break;
5851  }
5852 
5853  if (relation->rd_pubdesc)
5854  {
5855  pfree(relation->rd_pubdesc);
5856  relation->rd_pubdesc = NULL;
5857  }
5858 
5859  /* Now save copy of the descriptor in the relcache entry. */
5861  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5862  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5863  MemoryContextSwitchTo(oldcxt);
5864 }
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1952
void * palloc(Size size)
Definition: mcxt.c:1317
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
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:54
PublicationActions pubactions
bool cols_valid_for_update
PublicationDesc * rd_pubdesc
Definition: rel.h:168
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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, 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 6782 of file relcache.c.

6783 {
6784  LWLockRelease(RelCacheInitLock);
6785 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6757 of file relcache.c.

6758 {
6759  char localinitfname[MAXPGPATH];
6760  char sharedinitfname[MAXPGPATH];
6761 
6762  if (DatabasePath)
6763  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6765  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6767 
6768  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6769 
6770  /*
6771  * The files might not be there if no backend has been started since the
6772  * last removal. But complain about failures other than ENOENT with
6773  * ERROR. Fortunately, it's not too late to abort the transaction if we
6774  * can't get rid of the would-be-obsolete init file.
6775  */
6776  if (DatabasePath)
6777  unlink_initfile(localinitfname, ERROR);
6778  unlink_initfile(sharedinitfname, ERROR);
6779 }
char * DatabasePath
Definition: globals.c:103
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define MAXPGPATH
#define snprintf
Definition: port.h:238
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6854
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25

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

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6797 of file relcache.c.

6798 {
6799  const char *tblspcdir = PG_TBLSPC_DIR;
6800  DIR *dir;
6801  struct dirent *de;
6802  char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6803 
6804  snprintf(path, sizeof(path), "global/%s",
6806  unlink_initfile(path, LOG);
6807 
6808  /* Scan everything in the default tablespace */
6810 
6811  /* Scan the tablespace link directory to find non-default tablespaces */
6812  dir = AllocateDir(tblspcdir);
6813 
6814  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6815  {
6816  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6817  {
6818  /* Scan the tablespace dir for per-database dirs */
6819  snprintf(path, sizeof(path), "%s/%s/%s",
6820  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6822  }
6823  }
6824 
6825  FreeDir(dir);
6826 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2983
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2946
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6830
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
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, PG_TBLSPC_DIR, ReadDirExtended(), RelationCacheInitFileRemoveInDir(), RELCACHE_INIT_FILENAME, snprintf, TABLESPACE_VERSION_DIRECTORY, and unlink_initfile().

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3958 of file relcache.c.

3959 {
3960  HASHCTL ctl;
3961  int allocsize;
3962 
3963  /*
3964  * make sure cache memory context exists
3965  */
3966  if (!CacheMemoryContext)
3968 
3969  /*
3970  * create hashtable that indexes the relcache
3971  */
3972  ctl.keysize = sizeof(Oid);
3973  ctl.entrysize = sizeof(RelIdCacheEnt);
3974  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3975  &ctl, HASH_ELEM | HASH_BLOBS);
3976 
3977  /*
3978  * reserve enough in_progress_list slots for many cases
3979  */
3980  allocsize = 4;
3983  allocsize * sizeof(*in_progress_list));
3984  in_progress_list_maxlen = allocsize;
3985 
3986  /*
3987  * relation mapper needs to be initialized too
3988  */
3990 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
tree ctl
Definition: radixtree.h:1853
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3955
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:170
void RelationMapInitialize(void)
Definition: relmapper.c:651

References CacheMemoryContext, CreateCacheMemoryContext(), ctl, HASH_BLOBS, hash_create(), HASH_ELEM, in_progress_list, in_progress_list_maxlen, INITRELCACHESIZE, MemoryContextAlloc(), RelationIdCache, and RelationMapInitialize().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 4004 of file relcache.c.

4005 {
4006  MemoryContext oldcxt;
4007 
4008  /*
4009  * relation mapper needs initialized too
4010  */
4012 
4013  /*
4014  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4015  * nothing.
4016  */
4018  return;
4019 
4020  /*
4021  * switch to cache memory context
4022  */
4024 
4025  /*
4026  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4027  * the cache with pre-made descriptors for the critical shared catalogs.
4028  */
4029  if (!load_relcache_init_file(true))
4030  {
4031  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4032  Natts_pg_database, Desc_pg_database);
4033  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4034  Natts_pg_authid, Desc_pg_authid);
4035  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4036  Natts_pg_auth_members, Desc_pg_auth_members);
4037  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4038  Natts_pg_shseclabel, Desc_pg_shseclabel);
4039  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4040  Natts_pg_subscription, Desc_pg_subscription);
4041 
4042 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4043  }
4044 
4045  MemoryContextSwitchTo(oldcxt);
4046 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6066
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:119
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1874
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:120
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:117
void RelationMapInitializePhase2(void)
Definition: relmapper.c:671

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 4063 of file relcache.c.

4064 {
4065  HASH_SEQ_STATUS status;
4066  RelIdCacheEnt *idhentry;
4067  MemoryContext oldcxt;
4068  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
4069 
4070  /*
4071  * relation mapper needs initialized too
4072  */
4074 
4075  /*
4076  * switch to cache memory context
4077  */
4079 
4080  /*
4081  * Try to load the local relcache cache file. If unsuccessful, bootstrap
4082  * the cache with pre-made descriptors for the critical "nailed-in" system
4083  * catalogs.
4084  */
4085  if (IsBootstrapProcessingMode() ||
4086  !load_relcache_init_file(false))
4087  {
4088  needNewCacheFile = true;
4089 
4090  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4091  Natts_pg_class, Desc_pg_class);
4092  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4093  Natts_pg_attribute, Desc_pg_attribute);
4094  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4095  Natts_pg_proc, Desc_pg_proc);
4096  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4097  Natts_pg_type, Desc_pg_type);
4098 
4099 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4100  }
4101 
4102  MemoryContextSwitchTo(oldcxt);
4103 
4104  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4106  return;
4107 
4108  /*
4109  * If we didn't get the critical system indexes loaded into relcache, do
4110  * so now. These are critical because the catcache and/or opclass cache
4111  * depend on them for fetches done during relcache load. Thus, we have an
4112  * infinite-recursion problem. We can break the recursion by doing
4113  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4114  * performance, we only want to do that until we have the critical indexes
4115  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4116  * decide whether to do heapscan or indexscan at the key spots, and we set
4117  * it true after we've loaded the critical indexes.
4118  *
4119  * The critical indexes are marked as "nailed in cache", partly to make it
4120  * easy for load_relcache_init_file to count them, but mainly because we
4121  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4122  * true. (NOTE: perhaps it would be possible to reload them by
4123  * temporarily setting criticalRelcachesBuilt to false again. For now,
4124  * though, we just nail 'em in.)
4125  *
4126  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4127  * in the same way as the others, because the critical catalogs don't
4128  * (currently) have any rules or triggers, and so these indexes can be
4129  * rebuilt without inducing recursion. However they are used during
4130  * relcache load when a rel does have rules or triggers, so we choose to
4131  * nail them for performance reasons.
4132  */
4134  {
4135  load_critical_index(ClassOidIndexId,
4136  RelationRelationId);
4137  load_critical_index(AttributeRelidNumIndexId,
4138  AttributeRelationId);
4139  load_critical_index(IndexRelidIndexId,
4140  IndexRelationId);
4141  load_critical_index(OpclassOidIndexId,
4142  OperatorClassRelationId);
4143  load_critical_index(AccessMethodProcedureIndexId,
4144  AccessMethodProcedureRelationId);
4145  load_critical_index(RewriteRelRulenameIndexId,
4146  RewriteRelationId);
4147  load_critical_index(TriggerRelidNameIndexId,
4148  TriggerRelationId);
4149 
4150 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4151 
4152  criticalRelcachesBuilt = true;
4153  }
4154 
4155  /*
4156  * Process critical shared indexes too.
4157  *
4158  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4159  * initial lookup of MyDatabaseId, without which we'll never find any
4160  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4161  * database OID, so it instead depends on DatabaseOidIndexId. We also
4162  * need to nail up some indexes on pg_authid and pg_auth_members for use
4163  * during client authentication. SharedSecLabelObjectIndexId isn't
4164  * critical for the core system, but authentication hooks might be
4165  * interested in it.
4166  */
4168  {
4169  load_critical_index(DatabaseNameIndexId,
4170  DatabaseRelationId);
4171  load_critical_index(DatabaseOidIndexId,
4172  DatabaseRelationId);
4173  load_critical_index(AuthIdRolnameIndexId,
4174  AuthIdRelationId);
4175  load_critical_index(AuthIdOidIndexId,
4176  AuthIdRelationId);
4177  load_critical_index(AuthMemMemRoleIndexId,
4178  AuthMemRelationId);
4179  load_critical_index(SharedSecLabelObjectIndexId,
4180  SharedSecLabelRelationId);
4181 
4182 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4183 
4185  }
4186 
4187  /*
4188  * Now, scan all the relcache entries and update anything that might be
4189  * wrong in the results from formrdesc or the relcache cache file. If we
4190  * faked up relcache entries using formrdesc, then read the real pg_class
4191  * rows and replace the fake entries with them. Also, if any of the
4192  * relcache entries have rules, triggers, or security policies, load that
4193  * info the hard way since it isn't recorded in the cache file.
4194  *
4195  * Whenever we access the catalogs to read data, there is a possibility of
4196  * a shared-inval cache flush causing relcache entries to be removed.
4197  * Since hash_seq_search only guarantees to still work after the *current*
4198  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4199  * We handle this by restarting the scan from scratch after each access.
4200  * This is theoretically O(N^2), but the number of entries that actually
4201  * need to be fixed is small enough that it doesn't matter.
4202  */
4203  hash_seq_init(&status, RelationIdCache);
4204 
4205  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4206  {
4207  Relation relation = idhentry->reldesc;
4208  bool restart = false;
4209 
4210  /*
4211  * Make sure *this* entry doesn't get flushed while we work with it.
4212  */
4214 
4215  /*
4216  * If it's a faked-up entry, read the real pg_class tuple.
4217  */
4218  if (relation->rd_rel->relowner == InvalidOid)
4219  {
4220  HeapTuple htup;
4221  Form_pg_class relp;
4222 
4223  htup = SearchSysCache1(RELOID,
4224  ObjectIdGetDatum(RelationGetRelid(relation)));
4225  if (!HeapTupleIsValid(htup))
4226  ereport(FATAL,
4227  errcode(ERRCODE_UNDEFINED_OBJECT),
4228  errmsg_internal("cache lookup failed for relation %u",
4229  RelationGetRelid(relation)));
4230  relp = (Form_pg_class) GETSTRUCT(htup);
4231 
4232  /*
4233  * Copy tuple to relation->rd_rel. (See notes in
4234  * AllocateRelationDesc())
4235  */
4236  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4237 
4238  /* Update rd_options while we have the tuple */
4239  if (relation->rd_options)
4240  pfree(relation->rd_options);
4241  RelationParseRelOptions(relation, htup);
4242 
4243  /*
4244  * Check the values in rd_att were set up correctly. (We cannot
4245  * just copy them over now: formrdesc must have set up the rd_att
4246  * data correctly to start with, because it may already have been
4247  * copied into one or more catcache entries.)
4248  */
4249  Assert(relation->rd_att->tdtypeid == relp->reltype);
4250  Assert(relation->rd_att->tdtypmod == -1);
4251 
4252  ReleaseSysCache(htup);
4253 
4254  /* relowner had better be OK now, else we'll loop forever */
4255  if (relation->rd_rel->relowner == InvalidOid)
4256  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4257  RelationGetRelationName(relation));
4258 
4259  restart = true;
4260  }
4261 
4262  /*
4263  * Fix data that isn't saved in relcache cache file.
4264  *
4265  * relhasrules or relhastriggers could possibly be wrong or out of
4266  * date. If we don't actually find any rules or triggers, clear the
4267  * local copy of the flag so that we don't get into an infinite loop
4268  * here. We don't make any attempt to fix the pg_class entry, though.
4269  */
4270  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4271  {
4272  RelationBuildRuleLock(relation);
4273  if (relation->rd_rules == NULL)
4274  relation->rd_rel->relhasrules = false;
4275  restart = true;
4276  }
4277  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4278  {
4279  RelationBuildTriggers(relation);
4280  if (relation->trigdesc == NULL)
4281  relation->rd_rel->relhastriggers = false;
4282  restart = true;
4283  }
4284 
4285  /*
4286  * Re-load the row security policies if the relation has them, since
4287  * they are not preserved in the cache. Note that we can never NOT
4288  * have a policy while relrowsecurity is true,
4289  * RelationBuildRowSecurity will create a single default-deny policy
4290  * if there is no policy defined in pg_policy.
4291  */
4292  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4293  {
4294  RelationBuildRowSecurity(relation);
4295 
4296  Assert(relation->rd_rsdesc != NULL);
4297  restart = true;
4298  }
4299 
4300  /* Reload tableam data if needed */
4301  if (relation->rd_tableam == NULL &&
4302  (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4303  {
4305  Assert(relation->rd_tableam != NULL);
4306 
4307  restart = true;
4308  }
4309 
4310  /* Release hold on the relation */
4312 
4313  /* Now, restart the hashtable scan if needed */
4314  if (restart)
4315  {
4316  hash_seq_term(&status);
4317  hash_seq_init(&status, RelationIdCache);
4318  }
4319  }
4320 
4321  /*
4322  * Lastly, write out new relcache cache files if needed. We don't bother
4323  * to distinguish cases where only one of the two needs an update.
4324  */
4325  if (needNewCacheFile)
4326  {
4327  /*
4328  * Force all the catcaches to finish initializing and thereby open the
4329  * catalogs and indexes they use. This will preload the relcache with
4330  * entries for all the most important system catalogs and indexes, so
4331  * that the init files will be most useful for future backends.
4332  */
4334 
4335  /* now write the files */
4337  write_relcache_init_file(false);
4338  }
4339 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1514
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode(int sqlerrcode)
Definition: elog.c:853
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:465
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2164
bool criticalRelcachesBuilt
Definition: relcache.c:140
bool criticalSharedRelcachesBuilt
Definition: relcache.c:146
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:732
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:113
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6482
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:114
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4348
void RelationMapInitializePhase3(void)
Definition: relmapper.c:692
const struct TableAmRoutine * rd_tableam
Definition: rel.h:189
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:119
TriggerDesc * trigdesc
Definition: rel.h:117
RuleLock * rd_rules
Definition: rel.h:115
bytea * rd_options
Definition: rel.h:175
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void InitCatalogCachePhase2(void)
Definition: syscache.c:180
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1857

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ereport, errcode(), errmsg_internal(), 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(), SearchSysCache1(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2960 of file relcache.c.

2961 {
2962  HASH_SEQ_STATUS status;
2963  RelIdCacheEnt *idhentry;
2964  Relation relation;
2965  List *rebuildFirstList = NIL;
2966  List *rebuildList = NIL;
2967  ListCell *l;
2968  int i;
2969 
2970  /*
2971  * Reload relation mapping data before starting to reconstruct cache.
2972  */
2974 
2975  /* Phase 1 */
2976  hash_seq_init(&status, RelationIdCache);
2977 
2978  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2979  {
2980  relation = idhentry->reldesc;
2981 
2982  /*
2983  * Ignore new relations; no other backend will manipulate them before
2984  * we commit. Likewise, before replacing a relation's relfilelocator,
2985  * we shall have acquired AccessExclusiveLock and drained any
2986  * applicable pending invalidations.
2987  */
2988  if (relation->rd_createSubid != InvalidSubTransactionId ||
2990  continue;
2991 
2993 
2994  if (RelationHasReferenceCountZero(relation))
2995  {
2996  /* Delete this entry immediately */
2997  RelationClearRelation(relation);
2998  }
2999  else
3000  {
3001  /*
3002  * If it's a mapped relation, immediately update its rd_locator in
3003  * case its relfilenumber changed. We must do this during phase 1
3004  * in case the relation is consulted during rebuild of other
3005  * relcache entries in phase 2. It's safe since consulting the
3006  * map doesn't involve any access to relcache entries.
3007  */
3008  if (RelationIsMapped(relation))
3009  {
3010  RelationCloseSmgr(relation);
3011  RelationInitPhysicalAddr(relation);
3012  }
3013 
3014  /*
3015  * Add this entry to list of stuff to rebuild in second pass.
3016  * pg_class goes to the front of rebuildFirstList while
3017  * pg_class_oid_index goes to the back of rebuildFirstList, so
3018  * they are done first and second respectively. Other nailed
3019  * relations go to the front of rebuildList, so they'll be done
3020  * next in no particular order; and everything else goes to the
3021  * back of rebuildList.
3022  */
3023  if (RelationGetRelid(relation) == RelationRelationId)
3024  rebuildFirstList = lcons(relation, rebuildFirstList);
3025  else if (RelationGetRelid(relation) == ClassOidIndexId)
3026  rebuildFirstList = lappend(rebuildFirstList, relation);
3027  else if (relation->rd_isnailed)
3028  rebuildList = lcons(relation, rebuildList);
3029  else
3030  rebuildList = lappend(rebuildList, relation);
3031  }
3032  }
3033 
3034  /*
3035  * We cannot destroy the SMgrRelations as there might still be references
3036  * to them, but close the underlying file descriptors.
3037  */
3038  smgrreleaseall();
3039 
3040  /*
3041  * Phase 2: rebuild (or invalidate) the items found to need rebuild in
3042  * phase 1
3043  */
3044  foreach(l, rebuildFirstList)
3045  {
3046  relation = (Relation) lfirst(l);
3047  if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3048  RelationInvalidateRelation(relation);
3049  else
3050  RelationRebuildRelation(relation);
3051  }
3052  list_free(rebuildFirstList);
3053  foreach(l, rebuildList)
3054  {
3055  relation = (Relation) lfirst(l);
3056  if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3057  RelationInvalidateRelation(relation);
3058  else
3059  RelationRebuildRelation(relation);
3060  }
3061  list_free(rebuildList);
3062 
3063  if (!debug_discard)
3064  /* Any RelationBuildDesc() on the stack must start over. */
3065  for (i = 0; i < in_progress_list_len; i++)
3066  in_progress_list[i].invalidated = true;
3067 }
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
List * lcons(void *datum, List *list)
Definition: list.c:495
#define lfirst(lc)
Definition: pg_list.h:172
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:489
#define RelationIsMapped(relation)
Definition: rel.h:554
static void RelationCloseSmgr(Relation relation)
Definition: rel.h:582
static void RelationClearRelation(Relation relation)
Definition: relcache.c:2511
static void RelationRebuildRelation(Relation relation)
Definition: relcache.c:2550
static long relcacheInvalsReceived
Definition: relcache.c:154
static void RelationInvalidateRelation(Relation relation)
Definition: relcache.c:2483
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:356
bool IsTransactionState(void)
Definition: xact.c:386

References hash_seq_init(), hash_seq_search(), i, in_progress_list, in_progress_list_len, InvalidSubTransactionId, IsTransactionState(), lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationClearRelation(), RelationCloseSmgr(), RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationInvalidateRelation(), RelationIsMapped, RelationMapInvalidateAll(), RelationRebuildRelation(), relcacheInvalsReceived, relidcacheent::reldesc, and smgrreleaseall().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2904 of file relcache.c.

2905 {
2906  Relation relation;
2907 
2908  RelationIdCacheLookup(relationId, relation);
2909 
2910  if (PointerIsValid(relation))
2911  {
2913  RelationFlushRelation(relation);
2914  }
2915  else
2916  {
2917  int i;
2918 
2919  for (i = 0; i < in_progress_list_len; i++)
2920  if (in_progress_list[i].reloid == relationId)
2921  in_progress_list[i].invalidated = true;
2922  }
2923 }
#define PointerIsValid(pointer)
Definition: c.h:768
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2793
bool invalidated
Definition: relcache.c:167

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 2184 of file relcache.c.

2185 {
2186  /* Note: no locking manipulations needed */
2188 
2189  RelationCloseCleanup(relation);
2190 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2193

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

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

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2859 of file relcache.c.

2860 {
2861  Relation relation;
2862 
2863  RelationIdCacheLookup(rid, relation);
2864 
2865  if (!PointerIsValid(relation))
2866  return; /* not in cache, nothing to do */
2867 
2868  if (!RelationHasReferenceCountZero(relation))
2869  elog(ERROR, "relation %u is still open", rid);
2870 
2872  if (relation->rd_createSubid != InvalidSubTransactionId ||
2874  {
2875  /*
2876  * In the event of subtransaction rollback, we must not forget
2877  * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2878  * destroying it right away. (If we're in a top transaction, we could
2879  * opt to destroy the entry.)
2880  */
2882  RelationInvalidateRelation(relation);
2883  }
2884  else
2885  RelationClearRelation(relation);
2886 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5087 of file relcache.c.

5088 {
5089  List *result;
5090  Datum exprsDatum;
5091  bool isnull;
5092  char *exprsString;
5093  List *rawExprs;
5094  ListCell *lc;
5095 
5096  /* Quick exit if there is nothing to do. */
5097  if (relation->rd_indextuple == NULL ||
5098  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5099  return NIL;
5100 
5101  /* Extract raw node tree(s) from index tuple. */
5102  exprsDatum = heap_getattr(relation->rd_indextuple,
5103  Anum_pg_index_indexprs,
5105  &isnull);
5106  Assert(!isnull);
5107  exprsString = TextDatumGetCString(exprsDatum);
5108  rawExprs = (List *) stringToNode(exprsString);
5109  pfree(exprsString);
5110 
5111  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5112  result = NIL;
5113  foreach(lc, rawExprs)
5114  {
5115  Node *rawExpr = (Node *) lfirst(lc);
5116 
5117  result = lappend(result,
5118  makeConst(exprType(rawExpr),
5119  exprTypmod(rawExpr),
5120  exprCollation(rawExpr),
5121  1,
5122  (Datum) 0,
5123  true,
5124  true));
5125  }
5126 
5127  return result;
5128 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
uintptr_t Datum
Definition: postgres.h:64
void * stringToNode(const char *str)
Definition: read.c:90
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4429
Definition: nodes.h:129
struct HeapTupleData * rd_indextuple
Definition: rel.h:194

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 5584 of file relcache.c.

5588 {
5589  int indnkeyatts;
5590  Oid *ops;
5591  Oid *funcs;
5592  uint16 *strats;
5593  Relation conrel;
5594  SysScanDesc conscan;
5595  ScanKeyData skey[1];
5596  HeapTuple htup;
5597  bool found;
5598  MemoryContext oldcxt;
5599  int i;
5600 
5601  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5602 
5603  /* Allocate result space in caller context */
5604  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5605  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5606  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5607 
5608  /* Quick exit if we have the data cached already */
5609  if (indexRelation->rd_exclstrats != NULL)
5610  {
5611  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5612  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5613  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5614  return;
5615  }
5616 
5617  /*
5618  * Search pg_constraint for the constraint associated with the index. To
5619  * make this not too painfully slow, we use the index on conrelid; that
5620  * will hold the parent relation's OID not the index's own OID.
5621  *
5622  * Note: if we wanted to rely on the constraint name matching the index's
5623  * name, we could just do a direct lookup using pg_constraint's unique
5624  * index. For the moment it doesn't seem worth requiring that.
5625  */
5626  ScanKeyInit(&skey[0],
5627  Anum_pg_constraint_conrelid,
5628  BTEqualStrategyNumber, F_OIDEQ,
5629  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5630 
5631  conrel = table_open(ConstraintRelationId, AccessShareLock);
5632  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5633  NULL, 1, skey);
5634  found = false;
5635 
5636  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5637  {
5639  Datum val;
5640  bool isnull;
5641  ArrayType *arr;
5642  int nelem;
5643 
5644  /* We want the exclusion constraint owning the index */
5645  if ((conform->contype != CONSTRAINT_EXCLUSION &&
5646  !(conform->conperiod && (
5647  conform->contype == CONSTRAINT_PRIMARY
5648  || conform->contype == CONSTRAINT_UNIQUE))) ||
5649  conform->conindid != RelationGetRelid(indexRelation))
5650  continue;
5651 
5652  /* There should be only one */
5653  if (found)
5654  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5655  RelationGetRelationName(indexRelation));
5656  found = true;
5657 
5658  /* Extract the operator OIDS from conexclop */
5659  val = fastgetattr(htup,
5660  Anum_pg_constraint_conexclop,
5661  conrel->rd_att, &isnull);
5662  if (isnull)
5663  elog(ERROR, "null conexclop for rel %s",
5664  RelationGetRelationName(indexRelation));
5665 
5666  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5667  nelem = ARR_DIMS(arr)[0];
5668  if (ARR_NDIM(arr) != 1 ||
5669  nelem != indnkeyatts ||
5670  ARR_HASNULL(arr) ||
5671  ARR_ELEMTYPE(arr) != OIDOID)
5672  elog(ERROR, "conexclop is not a 1-D Oid array");
5673 
5674  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5675  }
5676 
5677  systable_endscan(conscan);
5678  table_close(conrel, AccessShareLock);
5679 
5680  if (!found)
5681  elog(ERROR, "exclusion constraint record missing for rel %s",
5682  RelationGetRelationName(indexRelation));
5683 
5684  /* We need the func OIDs and strategy numbers too */
5685  for (i = 0; i < indnkeyatts; i++)
5686  {
5687  funcs[i] = get_opcode(ops[i]);
5688  strats[i] = get_op_opfamily_strategy(ops[i],
5689  indexRelation->rd_opfamily[i]);
5690  /* shouldn't fail, since it was checked at index creation */
5691  if (strats[i] == InvalidStrategy)
5692  elog(ERROR, "could not find strategy for operator %u in family %u",
5693  ops[i], indexRelation->rd_opfamily[i]);
5694  }
5695 
5696  /* Save a copy of the results in the relcache entry. */
5697  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5698  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5699  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5700  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5701  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5702  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5703  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5704  MemoryContextSwitchTo(oldcxt);
5705 }
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
unsigned short uint16
Definition: c.h:517
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:83
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
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:215
uint16 * rd_exclstrats
Definition: rel.h:216
Oid * rd_exclops
Definition: rel.h:214
Form_pg_index rd_index
Definition: rel.h:192
MemoryContext rd_indexcxt
Definition: rel.h:204
Oid * rd_opfamily
Definition: rel.h:207
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

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 4658 of file relcache.c.

4659 {
4660  List *result;
4661  Relation conrel;
4662  SysScanDesc conscan;
4663  ScanKeyData skey;
4664  HeapTuple htup;
4665  List *oldlist;
4666  MemoryContext oldcxt;
4667 
4668  /* Quick exit if we already computed the list. */
4669  if (relation->rd_fkeyvalid)
4670  return relation->rd_fkeylist;
4671 
4672  /* Fast path: non-partitioned tables without triggers can't have FKs */
4673  if (!relation->rd_rel->relhastriggers &&
4674  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4675  return NIL;
4676 
4677  /*
4678  * We build the list we intend to return (in the caller's context) while
4679  * doing the scan. After successfully completing the scan, we copy that
4680  * list into the relcache entry. This avoids cache-context memory leakage
4681  * if we get some sort of error partway through.
4682  */
4683  result = NIL;
4684 
4685  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4686  ScanKeyInit(&skey,
4687  Anum_pg_constraint_conrelid,
4688  BTEqualStrategyNumber, F_OIDEQ,
4689  ObjectIdGetDatum(RelationGetRelid(relation)));
4690 
4691  conrel = table_open(ConstraintRelationId, AccessShareLock);
4692  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4693  NULL, 1, &skey);
4694 
4695  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4696  {
4697  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4698  ForeignKeyCacheInfo *info;
4699 
4700  /* consider only foreign keys */
4701  if (constraint->contype != CONSTRAINT_FOREIGN)
4702  continue;
4703 
4704  info = makeNode(ForeignKeyCacheInfo);
4705  info->conoid = constraint->oid;
4706  info->conrelid = constraint->conrelid;
4707  info->confrelid = constraint->confrelid;
4708 
4709  DeconstructFkConstraintRow(htup, &info->nkeys,
4710  info->conkey,
4711  info->confkey,
4712  info->conpfeqop,
4713  NULL, NULL, NULL, NULL);
4714 
4715  /* Add FK's node to the result list */
4716  result = lappend(result, info);
4717  }
4718 
4719  systable_endscan(conscan);
4720  table_close(conrel, AccessShareLock);
4721 
4722  /* Now save a copy of the completed list in the relcache entry. */
4724  oldlist = relation->rd_fkeylist;
4725  relation->rd_fkeylist = copyObject(result);
4726  relation->rd_fkeyvalid = true;
4727  MemoryContextSwitchTo(oldcxt);
4728 
4729  /* Don't leak the old list, if there is one */
4730  list_free_deep(oldlist);
4731 
4732  return result;
4733 }
void list_free_deep(List *list)
Definition: list.c:1560
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
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)
List * rd_fkeylist
Definition: rel.h:122
bool rd_fkeyvalid
Definition: rel.h:123

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conoid, 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 5507 of file relcache.c.

5508 {
5509  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5510  Relation indexDesc;
5511  int i;
5512  Oid replidindex;
5513  MemoryContext oldcxt;
5514 
5515  /* Quick exit if we already computed the result */
5516  if (relation->rd_idattr != NULL)
5517  return bms_copy(relation->rd_idattr);
5518 
5519  /* Fast path if definitely no indexes */
5520  if (!RelationGetForm(relation)->relhasindex)
5521  return NULL;
5522 
5523  /* Historic snapshot must be set. */
5525 
5526  replidindex = RelationGetReplicaIndex(relation);
5527 
5528  /* Fall out if there is no replica identity index */
5529  if (!OidIsValid(replidindex))
5530  return NULL;
5531 
5532  /* Look up the description for the replica identity index */
5533  indexDesc = RelationIdGetRelation(replidindex);
5534 
5535  if (!RelationIsValid(indexDesc))
5536  elog(ERROR, "could not open relation with OID %u",
5537  relation->rd_replidindex);
5538 
5539  /* Add referenced attributes to idindexattrs */
5540  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5541  {
5542  int attrnum = indexDesc->rd_index->indkey.values[i];
5543 
5544  /*
5545  * We don't include non-key columns into idindexattrs bitmaps. See
5546  * RelationGetIndexAttrBitmap.
5547  */
5548  if (attrnum != 0)
5549  {
5550  if (i < indexDesc->rd_index->indnkeyatts)
5551  idindexattrs = bms_add_member(idindexattrs,
5553  }
5554  }
5555 
5556  RelationClose(indexDesc);
5557 
5558  /* Don't leak the old values of these bitmaps, if any */
5559  bms_free(relation->rd_idattr);
5560  relation->rd_idattr = NULL;
5561 
5562  /* Now save copy of the bitmap in the relcache entry */
5564  relation->rd_idattr = bms_copy(idindexattrs);
5565  MemoryContextSwitchTo(oldcxt);
5566 
5567  /* We return our original working copy for caller to play with */
5568  return idindexattrs;
5569 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
#define OidIsValid(objectId)
Definition: c.h:780
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationIsValid(relation)
Definition: rel.h:478
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:5003
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2062
void RelationClose(Relation relation)
Definition: relcache.c:2184
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
Oid rd_replidindex
Definition: rel.h:155
Bitmapset * rd_idattr
Definition: rel.h:164
#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 5887 of file relcache.c.

5888 {
5889  MemoryContext oldcxt;
5890  bytea **opts = relation->rd_opcoptions;
5891  Oid relid = RelationGetRelid(relation);
5892  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5893  * IndexRelationGetNumberOfKeyAttributes */
5894  int i;
5895 
5896  /* Try to copy cached options. */
5897  if (opts)
5898  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5899 
5900  /* Get and parse opclass options. */
5901  opts = palloc0(sizeof(*opts) * natts);
5902 
5903  for (i = 0; i < natts; i++)
5904  {
5905  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5906  {
5907  Datum attoptions = get_attoptions(relid, i + 1);
5908 
5909  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5910 
5911  if (attoptions != (Datum) 0)
5912  pfree(DatumGetPointer(attoptions));
5913  }
5914  }
5915 
5916  /* Copy parsed options to the cache. */
5917  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5918  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5919  MemoryContextSwitchTo(oldcxt);
5920 
5921  if (copy)
5922  return opts;
5923 
5924  for (i = 0; i < natts; i++)
5925  {
5926  if (opts[i])
5927  pfree(opts[i]);
5928  }
5929 
5930  pfree(opts);
5931 
5932  return relation->rd_opcoptions;
5933 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:998
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
static AmcheckOptions opts
Definition: pg_amcheck.c:111
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5867
bytea ** rd_opcoptions
Definition: rel.h:218
Definition: c.h:692

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 5234 of file relcache.c.

5235 {
5236  Bitmapset *uindexattrs; /* columns in unique indexes */
5237  Bitmapset *pkindexattrs; /* columns in the primary index */
5238  Bitmapset *idindexattrs; /* columns in the replica identity */
5239  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5240  Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5241  List *indexoidlist;
5242  List *newindexoidlist;
5243  Oid relpkindex;
5244  Oid relreplindex;
5245  ListCell *l;
5246  MemoryContext oldcxt;
5247 
5248  /* Quick exit if we already computed the result. */
5249  if (relation->rd_attrsvalid)
5250  {
5251  switch (attrKind)
5252  {
5253  case INDEX_ATTR_BITMAP_KEY:
5254  return bms_copy(relation->rd_keyattr);
5256  return bms_copy(relation->rd_pkattr);
5258  return bms_copy(relation->rd_idattr);
5260  return bms_copy(relation->rd_hotblockingattr);
5262  return bms_copy(relation->rd_summarizedattr);
5263  default:
5264  elog(ERROR, "unknown attrKind %u", attrKind);
5265  }
5266  }
5267 
5268  /* Fast path if definitely no indexes */
5269  if (!RelationGetForm(relation)->relhasindex)
5270  return NULL;
5271 
5272  /*
5273  * Get cached list of index OIDs. If we have to start over, we do so here.
5274  */
5275 restart:
5276  indexoidlist = RelationGetIndexList(relation);
5277 
5278  /* Fall out if no indexes (but relhasindex was set) */
5279  if (indexoidlist == NIL)
5280  return NULL;
5281 
5282  /*
5283  * Copy the rd_pkindex and rd_replidindex values computed by
5284  * RelationGetIndexList before proceeding. This is needed because a
5285  * relcache flush could occur inside index_open below, resetting the
5286  * fields managed by RelationGetIndexList. We need to do the work with
5287  * stable values of these fields.
5288  */
5289  relpkindex = relation->rd_pkindex;
5290  relreplindex = relation->rd_replidindex;
5291 
5292  /*
5293  * For each index, add referenced attributes to indexattrs.
5294  *
5295  * Note: we consider all indexes returned by RelationGetIndexList, even if
5296  * they are not indisready or indisvalid. This is important because an
5297  * index for which CREATE INDEX CONCURRENTLY has just started must be
5298  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5299  * CONCURRENTLY is far enough along that we should ignore the index, it
5300  * won't be returned at all by RelationGetIndexList.
5301  */
5302  uindexattrs = NULL;
5303  pkindexattrs = NULL;
5304  idindexattrs = NULL;
5305  hotblockingattrs = NULL;
5306  summarizedattrs = NULL;
5307  foreach(l, indexoidlist)
5308  {
5309  Oid indexOid = lfirst_oid(l);
5310  Relation indexDesc;
5311  Datum datum;
5312  bool isnull;
5313  Node *indexExpressions;
5314  Node *indexPredicate;
5315  int i;
5316  bool isKey; /* candidate key */
5317  bool isPK; /* primary key */
5318  bool isIDKey; /* replica identity index */
5319  Bitmapset **attrs;
5320 
5321  indexDesc = index_open(indexOid, AccessShareLock);
5322 
5323  /*
5324  * Extract index expressions and index predicate. Note: Don't use
5325  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5326  * those might run constant expressions evaluation, which needs a
5327  * snapshot, which we might not have here. (Also, it's probably more
5328  * sound to collect the bitmaps before any transformations that might
5329  * eliminate columns, but the practical impact of this is limited.)
5330  */
5331 
5332  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5333  GetPgIndexDescriptor(), &isnull);
5334  if (!isnull)
5335  indexExpressions = stringToNode(TextDatumGetCString(datum));
5336  else
5337  indexExpressions = NULL;
5338 
5339  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5340  GetPgIndexDescriptor(), &isnull);
5341  if (!isnull)
5342  indexPredicate = stringToNode(TextDatumGetCString(datum));
5343  else
5344  indexPredicate = NULL;
5345 
5346  /* Can this index be referenced by a foreign key? */
5347  isKey = indexDesc->rd_index->indisunique &&
5348  indexExpressions == NULL &&
5349  indexPredicate == NULL;
5350 
5351  /* Is this a primary key? */
5352  isPK = (indexOid == relpkindex);
5353 
5354  /* Is this index the configured (or default) replica identity? */
5355  isIDKey = (indexOid == relreplindex);
5356 
5357  /*
5358  * If the index is summarizing, it doesn't block HOT updates, but we
5359  * may still need to update it (if the attributes were modified). So
5360  * decide which bitmap we'll update in the following loop.
5361  */
5362  if (indexDesc->rd_indam->amsummarizing)
5363  attrs = &summarizedattrs;
5364  else
5365  attrs = &hotblockingattrs;
5366 
5367  /* Collect simple attribute references */
5368  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5369  {
5370  int attrnum = indexDesc->rd_index->indkey.values[i];
5371 
5372  /*
5373  * Since we have covering indexes with non-key columns, we must
5374  * handle them accurately here. non-key columns must be added into
5375  * hotblockingattrs or summarizedattrs, since they are in index,
5376  * and update shouldn't miss them.
5377  *
5378  * Summarizing indexes do not block HOT, but do need to be updated
5379  * when the column value changes, thus require a separate
5380  * attribute bitmapset.
5381  *
5382  * Obviously, non-key columns couldn't be referenced by foreign
5383  * key or identity key. Hence we do not include them into
5384  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5385  */
5386  if (attrnum != 0)
5387  {
5388  *attrs = bms_add_member(*attrs,
5390 
5391  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5392  uindexattrs = bms_add_member(uindexattrs,
5394 
5395  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5396  pkindexattrs = bms_add_member(pkindexattrs,
5398 
5399  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5400  idindexattrs = bms_add_member(idindexattrs,
5402  }
5403  }
5404 
5405  /* Collect all attributes used in expressions, too */
5406  pull_varattnos(indexExpressions, 1, attrs);
5407 
5408  /* Collect all attributes in the index predicate, too */
5409  pull_varattnos(indexPredicate, 1, attrs);
5410 
5411  index_close(indexDesc, AccessShareLock);
5412  }
5413 
5414  /*
5415  * During one of the index_opens in the above loop, we might have received
5416  * a relcache flush event on this relcache entry, which might have been
5417  * signaling a change in the rel's index list. If so, we'd better start
5418  * over to ensure we deliver up-to-date attribute bitmaps.
5419  */
5420  newindexoidlist = RelationGetIndexList(relation);
5421  if (equal(indexoidlist, newindexoidlist) &&
5422  relpkindex == relation->rd_pkindex &&
5423  relreplindex == relation->rd_replidindex)
5424  {
5425  /* Still the same index set, so proceed */
5426  list_free(newindexoidlist);
5427  list_free(indexoidlist);
5428  }
5429  else
5430  {
5431  /* Gotta do it over ... might as well not leak memory */
5432  list_free(newindexoidlist);
5433  list_free(indexoidlist);
5434  bms_free(uindexattrs);
5435  bms_free(pkindexattrs);
5436  bms_free(idindexattrs);
5437  bms_free(hotblockingattrs);
5438  bms_free(summarizedattrs);
5439 
5440  goto restart;
5441  }
5442 
5443  /* Don't leak the old values of these bitmaps, if any */
5444  relation->rd_attrsvalid = false;
5445  bms_free(relation->rd_keyattr);
5446  relation->rd_keyattr = NULL;
5447  bms_free(relation->rd_pkattr);
5448  relation->rd_pkattr = NULL;
5449  bms_free(relation->rd_idattr);
5450  relation->rd_idattr = NULL;
5451  bms_free(relation->rd_hotblockingattr);
5452  relation->rd_hotblockingattr = NULL;
5453  bms_free(relation->rd_summarizedattr);
5454  relation->rd_summarizedattr = NULL;
5455 
5456  /*
5457  * Now save copies of the bitmaps in the relcache entry. We intentionally
5458  * set rd_attrsvalid last, because that's the one that signals validity of
5459  * the values; if we run out of memory before making that copy, we won't
5460  * leave the relcache entry looking like the other ones are valid but
5461  * empty.
5462  */
5464  relation->rd_keyattr = bms_copy(uindexattrs);
5465  relation->rd_pkattr = bms_copy(pkindexattrs);
5466  relation->rd_idattr = bms_copy(idindexattrs);
5467  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5468  relation->rd_summarizedattr = bms_copy(summarizedattrs);
5469  relation->rd_attrsvalid = true;
5470  MemoryContextSwitchTo(oldcxt);
5471 
5472  /* We return our original working copy for caller to play with */
5473  switch (attrKind)
5474  {
5475  case INDEX_ATTR_BITMAP_KEY:
5476  return uindexattrs;
5478  return pkindexattrs;
5480  return idindexattrs;
5482  return hotblockingattrs;
5484  return summarizedattrs;
5485  default:
5486  elog(ERROR, "unknown attrKind %u", attrKind);
5487  return NULL;
5488  }
5489 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4767
bool amsummarizing
Definition: amapi.h:261
Bitmapset * rd_keyattr
Definition: rel.h:162
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
bool rd_attrsvalid
Definition: rel.h:161
Bitmapset * rd_hotblockingattr
Definition: rel.h:165
Oid rd_pkindex
Definition: rel.h:153
Bitmapset * rd_summarizedattr
Definition: rel.h:166
Bitmapset * rd_pkattr
Definition: rel.h:163
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References AccessShareLock, IndexAmRoutine::amsummarizing, 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_ATTR_BITMAP_SUMMARIZED, 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, RelationData::rd_summarizedattr, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

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

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5028 of file relcache.c.

5029 {
5030  List *result;
5031  Datum exprsDatum;
5032  bool isnull;
5033  char *exprsString;
5034  MemoryContext oldcxt;
5035 
5036  /* Quick exit if we already computed the result. */
5037  if (relation->rd_indexprs)
5038  return copyObject(relation->rd_indexprs);
5039 
5040  /* Quick exit if there is nothing to do. */
5041  if (relation->rd_indextuple == NULL ||
5042  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5043  return NIL;
5044 
5045  /*
5046  * We build the tree we intend to return in the caller's context. After
5047  * successfully completing the work, we copy it into the relcache entry.
5048  * This avoids problems if we get some sort of error partway through.
5049  */
5050  exprsDatum = heap_getattr(relation->rd_indextuple,
5051  Anum_pg_index_indexprs,
5053  &isnull);
5054  Assert(!isnull);
5055  exprsString = TextDatumGetCString(exprsDatum);
5056  result = (List *) stringToNode(exprsString);
5057  pfree(exprsString);
5058 
5059  /*
5060  * Run the expressions through eval_const_expressions. This is not just an
5061  * optimization, but is necessary, because the planner will be comparing
5062  * them to similarly-processed qual clauses, and may fail to detect valid
5063  * matches without this. We must not use canonicalize_qual, however,
5064  * since these aren't qual expressions.
5065  */
5066  result = (List *) eval_const_expressions(NULL, (Node *) result);
5067 
5068  /* May as well fix opfuncids too */
5069  fix_opfuncids((Node *) result);
5070 
5071  /* Now save a copy of the completed tree in the relcache entry. */
5072  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5073  relation->rd_indexprs = copyObject(result);
5074  MemoryContextSwitchTo(oldcxt);
5075 
5076  return result;
5077 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1830
List * rd_indexprs
Definition: rel.h:212

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(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4767 of file relcache.c.

4768 {
4769  Relation indrel;
4770  SysScanDesc indscan;
4771  ScanKeyData skey;
4772  HeapTuple htup;
4773  List *result;
4774  List *oldlist;
4775  char replident = relation->rd_rel->relreplident;
4776  Oid pkeyIndex = InvalidOid;
4777  Oid candidateIndex = InvalidOid;
4778  bool pkdeferrable = false;
4779  MemoryContext oldcxt;
4780 
4781  /* Quick exit if we already computed the list. */
4782  if (relation->rd_indexvalid)
4783  return list_copy(relation->rd_indexlist);
4784 
4785  /*
4786  * We build the list we intend to return (in the caller's context) while
4787  * doing the scan. After successfully completing the scan, we copy that
4788  * list into the relcache entry. This avoids cache-context memory leakage
4789  * if we get some sort of error partway through.
4790  */
4791  result = NIL;
4792 
4793  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4794  ScanKeyInit(&skey,
4795  Anum_pg_index_indrelid,
4796  BTEqualStrategyNumber, F_OIDEQ,
4797  ObjectIdGetDatum(RelationGetRelid(relation)));
4798 
4799  indrel = table_open(IndexRelationId, AccessShareLock);
4800  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4801  NULL, 1, &skey);
4802 
4803  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4804  {
4806 
4807  /*
4808  * Ignore any indexes that are currently being dropped. This will
4809  * prevent them from being searched, inserted into, or considered in
4810  * HOT-safety decisions. It's unsafe to touch such an index at all
4811  * since its catalog entries could disappear at any instant.
4812  */
4813  if (!index->indislive)
4814  continue;
4815 
4816  /* add index's OID to result list */
4817  result = lappend_oid(result, index->indexrelid);
4818 
4819  /*
4820  * Non-unique or predicate indexes aren't interesting for either oid
4821  * indexes or replication identity indexes, so don't check them.
4822  * Deferred ones are not useful for replication identity either; but
4823  * we do include them if they are PKs.
4824  */
4825  if (!index->indisunique ||
4826  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4827  continue;
4828 
4829  /*
4830  * Remember primary key index, if any. For regular tables we do this
4831  * only if the index is valid; but for partitioned tables, then we do
4832  * it even if it's invalid.
4833  *
4834  * The reason for returning invalid primary keys for partitioned
4835  * tables is that we need it to prevent drop of not-null constraints
4836  * that may underlie such a primary key, which is only a problem for
4837  * partitioned tables.
4838  */
4839  if (index->indisprimary &&
4840  (index->indisvalid ||
4841  relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4842  {
4843  pkeyIndex = index->indexrelid;
4844  pkdeferrable = !index->indimmediate;
4845  }
4846 
4847  if (!index->indimmediate)
4848  continue;
4849 
4850  if (!index->indisvalid)
4851  continue;
4852 
4853  /* remember explicitly chosen replica index */
4854  if (index->indisreplident)
4855  candidateIndex = index->indexrelid;
4856  }
4857 
4858  systable_endscan(indscan);
4859 
4860  table_close(indrel, AccessShareLock);
4861 
4862  /* Sort the result list into OID order, per API spec. */
4863  list_sort(result, list_oid_cmp);
4864 
4865  /* Now save a copy of the completed list in the relcache entry. */
4867  oldlist = relation->rd_indexlist;
4868  relation->rd_indexlist = list_copy(result);
4869  relation->rd_pkindex = pkeyIndex;
4870  relation->rd_ispkdeferrable = pkdeferrable;
4871  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4872  relation->rd_replidindex = pkeyIndex;
4873  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4874  relation->rd_replidindex = candidateIndex;
4875  else
4876  relation->rd_replidindex = InvalidOid;
4877  relation->rd_indexvalid = true;
4878  MemoryContextSwitchTo(oldcxt);
4879 
4880  /* Don't leak the old list, if there is one */
4881  list_free(oldlist);
4882 
4883  return result;
4884 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool rd_ispkdeferrable
Definition: rel.h:154
bool rd_indexvalid
Definition: rel.h:64
List * rd_indexlist
Definition: rel.h:152
Definition: type.h:95

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_ispkdeferrable, 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(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), RefreshMatViewByOid(), 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 5141 of file relcache.c.

5142 {
5143  List *result;
5144  Datum predDatum;
5145  bool isnull;
5146  char *predString;
5147  MemoryContext oldcxt;
5148 
5149  /* Quick exit if we already computed the result. */
5150  if (relation->rd_indpred)
5151  return copyObject(relation->rd_indpred);
5152 
5153  /* Quick exit if there is nothing to do. */
5154  if (relation->rd_indextuple == NULL ||
5155  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5156  return NIL;
5157 
5158  /*
5159  * We build the tree we intend to return in the caller's context. After
5160  * successfully completing the work, we copy it into the relcache entry.
5161  * This avoids problems if we get some sort of error partway through.
5162  */
5163  predDatum = heap_getattr(relation->rd_indextuple,
5164  Anum_pg_index_indpred,
5166  &isnull);
5167  Assert(!isnull);
5168  predString = TextDatumGetCString(predDatum);
5169  result = (List *) stringToNode(predString);
5170  pfree(predString);
5171 
5172  /*
5173  * Run the expression through const-simplification and canonicalization.
5174  * This is not just an optimization, but is necessary, because the planner
5175  * will be comparing it to similarly-processed qual clauses, and may fail
5176  * to detect valid matches without this. This must match the processing
5177  * done to qual clauses in preprocess_expression()! (We can skip the
5178  * stuff involving subqueries, however, since we don't allow any in index
5179  * predicates.)
5180  */
5181  result = (List *) eval_const_expressions(NULL, (Node *) result);
5182 
5183  result = (List *) canonicalize_qual((Expr *) result, false);
5184 
5185  /* Also convert to implicit-AND format */
5186  result = make_ands_implicit((Expr *) result);
5187 
5188  /* May as well fix opfuncids too */
5189  fix_opfuncids((Node *) result);
5190 
5191  /* Now save a copy of the completed tree in the relcache entry. */
5192  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5193  relation->rd_indpred = copyObject(result);
5194  MemoryContextSwitchTo(oldcxt);
5195 
5196  return result;
5197 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:760
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
List * rd_indpred
Definition: rel.h:213

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(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation,
bool  deferrable_ok 
)

Definition at line 4978 of file relcache.c.

4979 {
4980  List *ilist;
4981 
4982  if (!relation->rd_indexvalid)
4983  {
4984  /* RelationGetIndexList does the heavy lifting. */
4985  ilist = RelationGetIndexList(relation);
4986  list_free(ilist);
4987  Assert(relation->rd_indexvalid);
4988  }
4989 
4990  if (deferrable_ok)
4991  return relation->rd_pkindex;
4992  else if (relation->rd_ispkdeferrable)
4993  return InvalidOid;
4994  return relation->rd_pkindex;
4995 }

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

Referenced by dropconstraint_internal(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5003 of file relcache.c.

5004 {
5005  List *ilist;
5006 
5007  if (!relation->rd_indexvalid)
5008  {
5009  /* RelationGetIndexList does the heavy lifting. */
5010  ilist = RelationGetIndexList(relation);
5011  list_free(ilist);
5012  Assert(relation->rd_indexvalid);
5013  }
5014 
5015  return relation->rd_replidindex;
5016 }

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4908 of file relcache.c.

4909 {
4910  Relation indrel;
4911  SysScanDesc indscan;
4912  ScanKeyData skey;
4913  HeapTuple htup;
4914  List *result;
4915  List *oldlist;
4916  MemoryContext oldcxt;
4917 
4918  /* Quick exit if we already computed the list. */
4919  if (relation->rd_statvalid != 0)
4920  return list_copy(relation->rd_statlist);
4921 
4922  /*
4923  * We build the list we intend to return (in the caller's context) while
4924  * doing the scan. After successfully completing the scan, we copy that
4925  * list into the relcache entry. This avoids cache-context memory leakage
4926  * if we get some sort of error partway through.
4927  */
4928  result = NIL;
4929 
4930  /*
4931  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4932  * rel.
4933  */
4934  ScanKeyInit(&skey,
4935  Anum_pg_statistic_ext_stxrelid,
4936  BTEqualStrategyNumber, F_OIDEQ,
4937  ObjectIdGetDatum(RelationGetRelid(relation)));
4938 
4939  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4940  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4941  NULL, 1, &skey);
4942 
4943  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4944  {
4945  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4946 
4947  result = lappend_oid(result, oid);
4948  }
4949 
4950  systable_endscan(indscan);
4951 
4952  table_close(indrel, AccessShareLock);
4953 
4954  /* Sort the result list into OID order, per API spec. */
4955  list_sort(result, list_oid_cmp);
4956 
4957  /* Now save a copy of the completed list in the relcache entry. */
4959  oldlist = relation->rd_statlist;
4960  relation->rd_statlist = list_copy(result);
4961 
4962  relation->rd_statvalid = true;
4963  MemoryContextSwitchTo(oldcxt);
4964 
4965  /* Don't leak the old list, if there is one */
4966  list_free(oldlist);
4967 
4968  return result;
4969 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:66
List * rd_statlist
Definition: rel.h:158

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 expandTableLikeClause(), and get_relation_statistics().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2062 of file relcache.c.

2063 {
2064  Relation rd;
2065 
2066  /* Make sure we're in an xact, even if this ends up being a cache hit */
2068 
2069  /*
2070  * first try to find reldesc in the cache
2071  */
2072  RelationIdCacheLookup(relationId, rd);
2073 
2074  if (RelationIsValid(rd))
2075  {
2076  /* return NULL for dropped relations */
2078  {
2079  Assert(!rd->rd_isvalid);
2080  return NULL;
2081  }
2082 
2084  /* revalidate cache entry if necessary */
2085  if (!rd->rd_isvalid)
2086  {
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:1039

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

Referenced by check_and_init_gencol(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), 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 6717 of file relcache.c.

6718 {
6719  if (relationId == SharedSecLabelRelationId ||
6720  relationId == TriggerRelidNameIndexId ||
6721  relationId == DatabaseNameIndexId ||
6722  relationId == SharedSecLabelObjectIndexId)
6723  {
6724  /*
6725  * If this Assert fails, we don't need the applicable special case
6726  * anymore.
6727  */
6728  Assert(!RelationSupportsSysCache(relationId));
6729  return true;
6730  }
6731  return RelationSupportsSysCache(relationId);
6732 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:765

References Assert, and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1425 of file relcache.c.

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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert, CacheMemoryContext, DatumGetPointer(), elog, ERROR, fastgetattr(), GetPgIndexDescriptor(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, 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 1809 of file relcache.c.

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

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

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3730 of file relcache.c.

3731 {
3732  RelFileNumber newrelfilenumber;
3733  Relation pg_class;
3734  ItemPointerData otid;
3735  HeapTuple tuple;
3736  Form_pg_class classform;
3737  MultiXactId minmulti = InvalidMultiXactId;
3738  TransactionId freezeXid = InvalidTransactionId;
3739  RelFileLocator newrlocator;
3740 
3741  if (!IsBinaryUpgrade)
3742  {
3743  /* Allocate a new relfilenumber */
3744  newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3745  NULL, persistence);
3746  }
3747  else if (relation->rd_rel->relkind == RELKIND_INDEX)
3748  {
3750  ereport(ERROR,
3751  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3752  errmsg("index relfilenumber value not set when in binary upgrade mode")));
3753 
3756  }
3757  else if (relation->rd_rel->relkind == RELKIND_RELATION)
3758  {
3760  ereport(ERROR,
3761  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3762  errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3763 
3766  }
3767  else
3768  ereport(ERROR,
3769  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3770  errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3771 
3772  /*
3773  * Get a writable copy of the pg_class tuple for the given relation.
3774  */
3775  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3776 
3777  tuple = SearchSysCacheLockedCopy1(RELOID,
3778  ObjectIdGetDatum(RelationGetRelid(relation)));
3779  if (!HeapTupleIsValid(tuple))
3780  elog(ERROR, "could not find tuple for relation %u",
3781  RelationGetRelid(relation));
3782  otid = tuple->t_self;
3783  classform = (Form_pg_class) GETSTRUCT(tuple);
3784 
3785  /*
3786  * Schedule unlinking of the old storage at transaction commit, except
3787  * when performing a binary upgrade, when we must do it immediately.
3788  */
3789  if (IsBinaryUpgrade)
3790  {
3791  SMgrRelation srel;
3792 
3793  /*
3794  * During a binary upgrade, we use this code path to ensure that
3795  * pg_largeobject and its index have the same relfilenumbers as in the
3796  * old cluster. This is necessary because pg_upgrade treats
3797  * pg_largeobject like a user table, not a system table. It is however
3798  * possible that a table or index may need to end up with the same
3799  * relfilenumber in the new cluster as what it had in the old cluster.
3800  * Hence, we can't wait until commit time to remove the old storage.
3801  *
3802  * In general, this function needs to have transactional semantics,
3803  * and removing the old storage before commit time surely isn't.
3804  * However, it doesn't really matter, because if a binary upgrade
3805  * fails at this stage, the new cluster will need to be recreated
3806  * anyway.
3807  */
3808  srel = smgropen(relation->rd_locator, relation->rd_backend);
3809  smgrdounlinkall(&srel, 1, false);
3810  smgrclose(srel);
3811  }
3812  else
3813  {
3814  /* Not a binary upgrade, so just schedule it to happen later. */
3815  RelationDropStorage(relation);
3816  }
3817 
3818  /*
3819  * Create storage for the main fork of the new relfilenumber. If it's a
3820  * table-like object, call into the table AM to do so, which'll also
3821  * create the table's init fork if needed.
3822  *
3823  * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3824  * be caught here, if GetNewRelFileNumber messes up for any reason.
3825  */
3826  newrlocator = relation->rd_locator;
3827  newrlocator.relNumber = newrelfilenumber;
3828 
3829  if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3830  {
3831  table_relation_set_new_filelocator(relation, &newrlocator,
3832  persistence,
3833  &freezeXid, &minmulti);
3834  }
3835  else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3836  {
3837  /* handle these directly, at least for now */
3838  SMgrRelation srel;
3839 
3840  srel = RelationCreateStorage(newrlocator, persistence, true);
3841  smgrclose(srel);
3842  }
3843  else
3844  {
3845  /* we shouldn't be called for anything else */
3846  elog(ERROR, "relation \"%s\" does not have storage",
3847  RelationGetRelationName(relation));
3848  }
3849 
3850  /*
3851  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3852  * change; instead we have to send the update to the relation mapper.
3853  *
3854  * For mapped indexes, we don't actually change the pg_class entry at all;
3855  * this is essential when reindexing pg_class itself. That leaves us with
3856  * possibly-inaccurate values of relpages etc, but those will be fixed up
3857  * later.
3858  */
3859  if (RelationIsMapped(relation))
3860  {
3861  /* This case is only supported for indexes */
3862  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3863 
3864  /* Since we're not updating pg_class, these had better not change */
3865  Assert(classform->relfrozenxid == freezeXid);
3866  Assert(classform->relminmxid == minmulti);
3867  Assert(classform->relpersistence == persistence);
3868 
3869  /*
3870  * In some code paths it's possible that the tuple update we'd
3871  * otherwise do here is the only thing that would assign an XID for
3872  * the current transaction. However, we must have an XID to delete
3873  * files, so make sure one is assigned.
3874  */
3875  (void) GetCurrentTransactionId();
3876 
3877  /* Do the deed */
3879  newrelfilenumber,
3880  relation->rd_rel->relisshared,
3881  false);
3882 
3883  /* Since we're not updating pg_class, must trigger inval manually */
3884  CacheInvalidateRelcache(relation);
3885  }
3886  else
3887  {
3888  /* Normal case, update the pg_class entry */
3889  classform->relfilenode = newrelfilenumber;
3890 
3891  /* relpages etc. never change for sequences */
3892  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3893  {
3894  classform->relpages = 0; /* it's empty until further notice */
3895  classform->reltuples = -1;
3896  classform->relallvisible = 0;
3897  }
3898  classform->relfrozenxid = freezeXid;
3899  classform->relminmxid = minmulti;
3900  classform->relpersistence = persistence;
3901 
3902  CatalogTupleUpdate(pg_class, &otid, tuple);
3903  }
3904 
3905  UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3906  heap_freetuple(tuple);
3907 
3908  table_close(pg_class, RowExclusiveLock);
3909 
3910  /*
3911  * Make the pg_class row change or relation map change visible. This will
3912  * cause the relcache entry to get updated, too.
3913  */
3915 
3917 }
TransactionId MultiXactId
Definition: c.h:667
uint32 TransactionId
Definition: c.h:657
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:528
int errmsg(const char *fmt,...)
Definition: elog.c:1070
bool IsBinaryUpgrade
Definition: globals.c:120
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:82
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:85
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1553
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:594
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3932
Oid RelFileNumber
Definition: relpath.h:25
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:201
void smgrclose(SMgrRelation reln)
Definition: smgr.c:323
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:465
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
void RelationDropStorage(Relation rel)
Definition: storage.c:206
ItemPointerData t_self
Definition: htup.h:65
RelFileNumber relNumber
RelFileLocator rd_locator
Definition: rel.h:57
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:399
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1630
#define InvalidTransactionId
Definition: transam.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1099
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:453

References Assert, binary_upgrade_next_heap_pg_class_relfilenumber, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, GetCurrentTransactionId(), GetNewRelFileNumber(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidMultiXactId, InvalidOid, InvalidTransactionId, IsBinaryUpgrade, ObjectIdGetDatum(), OidIsValid, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, RelationAssumeNewRelfilelocator(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileLocator::relNumber, RowExclusiveLock, SearchSysCacheLockedCopy1(), smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), table_relation_set_new_filelocator(), and UnlockTuple().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt