PostgreSQL Source Code  git master
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)
 
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 3346 of file relcache.c.

3348 {
3349  HASH_SEQ_STATUS status;
3350  RelIdCacheEnt *idhentry;
3351  int i;
3352 
3353  /*
3354  * Forget in_progress_list. This is relevant when we're aborting due to
3355  * an error during RelationBuildDesc(). We don't commit subtransactions
3356  * during RelationBuildDesc().
3357  */
3358  Assert(in_progress_list_len == 0 || !isCommit);
3360 
3361  /*
3362  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3363  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3364  * logic as in AtEOXact_RelationCache.
3365  */
3367  {
3368  hash_seq_init(&status, RelationIdCache);
3369  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3370  {
3371  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3372  mySubid, parentSubid);
3373  }
3374  }
3375  else
3376  {
3377  for (i = 0; i < eoxact_list_len; i++)
3378  {
3379  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3380  &eoxact_list[i],
3381  HASH_FIND,
3382  NULL);
3383  if (idhentry != NULL)
3384  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3385  mySubid, parentSubid);
3386  }
3387  }
3388 
3389  /* Don't reset the list; we still need more cleanup later */
3390 }
#define Assert(condition)
Definition: c.h:858
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:1395
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:73
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:3401
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 3194 of file relcache.c.

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

5946 {
5950 
5951  return 0; /* return value does not matter */
5952 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
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(), ExecPartitionCheckEmitError(), and moveSplitTableRows().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5962 of file relcache.c.

5963 {
5964  TupleDesc reldesc = RelationGetDescr(rel);
5965  const char *colname;
5966 
5967  /* Use reldesc if it's a user attribute, else consult the catalogs */
5968  if (attnum > 0 && attnum <= reldesc->natts)
5969  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5970  else
5971  colname = get_attname(RelationGetRelid(rel), attnum, false);
5972 
5973  return errtablecolname(rel, colname);
5974 }
#define NameStr(name)
Definition: c.h:746
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:5986
#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 5986 of file relcache.c.

5987 {
5988  errtable(rel);
5990 
5991  return 0; /* return value does not matter */
5992 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5945

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

3926 {
3930 
3931  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3932  EOXactListAdd(relation);
3933 }
#define InvalidSubTransactionId
Definition: c.h:658
#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:788

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

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

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

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

6780 {
6781  LWLockRelease(RelCacheInitLock);
6782 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6754 of file relcache.c.

6755 {
6756  char localinitfname[MAXPGPATH];
6757  char sharedinitfname[MAXPGPATH];
6758 
6759  if (DatabasePath)
6760  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6762  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6764 
6765  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6766 
6767  /*
6768  * The files might not be there if no backend has been started since the
6769  * last removal. But complain about failures other than ENOENT with
6770  * ERROR. Fortunately, it's not too late to abort the transaction if we
6771  * can't get rid of the would-be-obsolete init file.
6772  */
6773  if (DatabasePath)
6774  unlink_initfile(localinitfname, ERROR);
6775  unlink_initfile(sharedinitfname, ERROR);
6776 }
char * DatabasePath
Definition: globals.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
@ 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:6851
#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(), and ProcessCommittedInvalidationMessages().

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6794 of file relcache.c.

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

Referenced by StartupXLOG().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3951 of file relcache.c.

3952 {
3953  HASHCTL ctl;
3954  int allocsize;
3955 
3956  /*
3957  * make sure cache memory context exists
3958  */
3959  if (!CacheMemoryContext)
3961 
3962  /*
3963  * create hashtable that indexes the relcache
3964  */
3965  ctl.keysize = sizeof(Oid);
3966  ctl.entrysize = sizeof(RelIdCacheEnt);
3967  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3968  &ctl, HASH_ELEM | HASH_BLOBS);
3969 
3970  /*
3971  * reserve enough in_progress_list slots for many cases
3972  */
3973  allocsize = 4;
3976  allocsize * sizeof(*in_progress_list));
3977  in_progress_list_maxlen = allocsize;
3978 
3979  /*
3980  * relation mapper needs to be initialized too
3981  */
3983 }
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:1180
tree ctl
Definition: radixtree.h:1847
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3948
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 3997 of file relcache.c.

3998 {
3999  MemoryContext oldcxt;
4000 
4001  /*
4002  * relation mapper needs initialized too
4003  */
4005 
4006  /*
4007  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4008  * nothing.
4009  */
4011  return;
4012 
4013  /*
4014  * switch to cache memory context
4015  */
4017 
4018  /*
4019  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4020  * the cache with pre-made descriptors for the critical shared catalogs.
4021  */
4022  if (!load_relcache_init_file(true))
4023  {
4024  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4025  Natts_pg_database, Desc_pg_database);
4026  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4027  Natts_pg_authid, Desc_pg_authid);
4028  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4029  Natts_pg_auth_members, Desc_pg_auth_members);
4030  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4031  Natts_pg_shseclabel, Desc_pg_shseclabel);
4032  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4033  Natts_pg_subscription, Desc_pg_subscription);
4034 
4035 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4036  }
4037 
4038  MemoryContextSwitchTo(oldcxt);
4039 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6063
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 4056 of file relcache.c.

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

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

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2917 of file relcache.c.

2918 {
2919  Relation relation;
2920 
2921  RelationIdCacheLookup(relationId, relation);
2922 
2923  if (PointerIsValid(relation))
2924  {
2926  RelationFlushRelation(relation);
2927  }
2928  else
2929  {
2930  int i;
2931 
2932  for (i = 0; i < in_progress_list_len; i++)
2933  if (in_progress_list[i].reloid == relationId)
2934  in_progress_list[i].invalidated = true;
2935  }
2936 }
#define PointerIsValid(pointer)
Definition: c.h:763
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2840
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 2193 of file relcache.c.

2194 {
2195  /* Note: no locking manipulations needed */
2197 
2198  RelationCloseCleanup(relation);
2199 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2202

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

2874 {
2875  Relation relation;
2876 
2877  RelationIdCacheLookup(rid, relation);
2878 
2879  if (!PointerIsValid(relation))
2880  return; /* not in cache, nothing to do */
2881 
2882  if (!RelationHasReferenceCountZero(relation))
2883  elog(ERROR, "relation %u is still open", rid);
2884 
2886  if (relation->rd_createSubid != InvalidSubTransactionId ||
2888  {
2889  /*
2890  * In the event of subtransaction rollback, we must not forget
2891  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2892  * invalidates it in lieu of destroying it. (If we're in a top
2893  * transaction, we could opt to destroy the entry.)
2894  */
2896  }
2897 
2898  RelationClearRelation(relation, false);
2899 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5084 of file relcache.c.

5085 {
5086  List *result;
5087  Datum exprsDatum;
5088  bool isnull;
5089  char *exprsString;
5090  List *rawExprs;
5091  ListCell *lc;
5092 
5093  /* Quick exit if there is nothing to do. */
5094  if (relation->rd_indextuple == NULL ||
5095  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5096  return NIL;
5097 
5098  /* Extract raw node tree(s) from index tuple. */
5099  exprsDatum = heap_getattr(relation->rd_indextuple,
5100  Anum_pg_index_indexprs,
5102  &isnull);
5103  Assert(!isnull);
5104  exprsString = TextDatumGetCString(exprsDatum);
5105  rawExprs = (List *) stringToNode(exprsString);
5106  pfree(exprsString);
5107 
5108  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5109  result = NIL;
5110  foreach(lc, rawExprs)
5111  {
5112  Node *rawExpr = (Node *) lfirst(lc);
5113 
5114  result = lappend(result,
5115  makeConst(exprType(rawExpr),
5116  exprTypmod(rawExpr),
5117  exprCollation(rawExpr),
5118  1,
5119  (Datum) 0,
5120  true,
5121  true));
5122  }
5123 
5124  return result;
5125 }
#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:4422
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 5581 of file relcache.c.

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

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

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

5885 {
5886  MemoryContext oldcxt;
5887  bytea **opts = relation->rd_opcoptions;
5888  Oid relid = RelationGetRelid(relation);
5889  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5890  * IndexRelationGetNumberOfKeyAttributes */
5891  int i;
5892 
5893  /* Try to copy cached options. */
5894  if (opts)
5895  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5896 
5897  /* Get and parse opclass options. */
5898  opts = palloc0(sizeof(*opts) * natts);
5899 
5900  for (i = 0; i < natts; i++)
5901  {
5902  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5903  {
5904  Datum attoptions = get_attoptions(relid, i + 1);
5905 
5906  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5907 
5908  if (attoptions != (Datum) 0)
5909  pfree(DatumGetPointer(attoptions));
5910  }
5911  }
5912 
5913  /* Copy parsed options to the cache. */
5914  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5915  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5916  MemoryContextSwitchTo(oldcxt);
5917 
5918  if (copy)
5919  return opts;
5920 
5921  for (i = 0; i < natts; i++)
5922  {
5923  if (opts[i])
5924  pfree(opts[i]);
5925  }
5926 
5927  pfree(opts);
5928 
5929  return relation->rd_opcoptions;
5930 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:997
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:5864
bytea ** rd_opcoptions
Definition: rel.h:218
Definition: c.h:687

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

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

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 ATExecDropNotNull(), ATInheritAdjustNotNulls(), dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), MergeAttributes(), pub_collist_contains_invalid_column(), pub_rf_contains_invalid_column(), RemoveConstraintById(), and transformTableLikeClause().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5025 of file relcache.c.

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

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4760 of file relcache.c.

4761 {
4762  Relation indrel;
4763  SysScanDesc indscan;
4764  ScanKeyData skey;
4765  HeapTuple htup;
4766  List *result;
4767  List *oldlist;
4768  char replident = relation->rd_rel->relreplident;
4769  Oid pkeyIndex = InvalidOid;
4770  Oid candidateIndex = InvalidOid;
4771  bool pkdeferrable = false;
4772  MemoryContext oldcxt;
4773 
4774  /* Quick exit if we already computed the list. */
4775  if (relation->rd_indexvalid)
4776  return list_copy(relation->rd_indexlist);
4777 
4778  /*
4779  * We build the list we intend to return (in the caller's context) while
4780  * doing the scan. After successfully completing the scan, we copy that
4781  * list into the relcache entry. This avoids cache-context memory leakage
4782  * if we get some sort of error partway through.
4783  */
4784  result = NIL;
4785 
4786  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4787  ScanKeyInit(&skey,
4788  Anum_pg_index_indrelid,
4789  BTEqualStrategyNumber, F_OIDEQ,
4790  ObjectIdGetDatum(RelationGetRelid(relation)));
4791 
4792  indrel = table_open(IndexRelationId, AccessShareLock);
4793  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4794  NULL, 1, &skey);
4795 
4796  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4797  {
4799 
4800  /*
4801  * Ignore any indexes that are currently being dropped. This will
4802  * prevent them from being searched, inserted into, or considered in
4803  * HOT-safety decisions. It's unsafe to touch such an index at all
4804  * since its catalog entries could disappear at any instant.
4805  */
4806  if (!index->indislive)
4807  continue;
4808 
4809  /* add index's OID to result list */
4810  result = lappend_oid(result, index->indexrelid);
4811 
4812  /*
4813  * Non-unique or predicate indexes aren't interesting for either oid
4814  * indexes or replication identity indexes, so don't check them.
4815  * Deferred ones are not useful for replication identity either; but
4816  * we do include them if they are PKs.
4817  */
4818  if (!index->indisunique ||
4819  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4820  continue;
4821 
4822  /*
4823  * Remember primary key index, if any. We do this only if the index
4824  * is valid; but if the table is partitioned, then we do it even if
4825  * it's invalid.
4826  *
4827  * The reason for returning invalid primary keys for foreign tables is
4828  * because of pg_dump of NOT NULL constraints, and the fact that PKs
4829  * remain marked invalid until the partitions' PKs are attached to it.
4830  * If we make rd_pkindex invalid, then the attnotnull flag is reset
4831  * after the PK is created, which causes the ALTER INDEX ATTACH
4832  * PARTITION to fail with 'column ... is not marked NOT NULL'. With
4833  * this, dropconstraint_internal() will believe that the columns must
4834  * not have attnotnull reset, so the PKs-on-partitions can be attached
4835  * correctly, until finally the PK-on-parent is marked valid.
4836  *
4837  * Also, this doesn't harm anything, because rd_pkindex is not a
4838  * "real" index anyway, but a RELKIND_PARTITIONED_INDEX.
4839  */
4840  if (index->indisprimary &&
4841  (index->indisvalid ||
4842  relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4843  {
4844  pkeyIndex = index->indexrelid;
4845  pkdeferrable = !index->indimmediate;
4846  }
4847 
4848  if (!index->indimmediate)
4849  continue;
4850 
4851  if (!index->indisvalid)
4852  continue;
4853 
4854  /* remember explicitly chosen replica index */
4855  if (index->indisreplident)
4856  candidateIndex = index->indexrelid;
4857  }
4858 
4859  systable_endscan(indscan);
4860 
4861  table_close(indrel, AccessShareLock);
4862 
4863  /* Sort the result list into OID order, per API spec. */
4864  list_sort(result, list_oid_cmp);
4865 
4866  /* Now save a copy of the completed list in the relcache entry. */
4868  oldlist = relation->rd_indexlist;
4869  relation->rd_indexlist = list_copy(result);
4870  relation->rd_pkindex = pkeyIndex;
4871  relation->rd_ispkdeferrable = pkdeferrable;
4872  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4873  relation->rd_replidindex = pkeyIndex;
4874  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4875  relation->rd_replidindex = candidateIndex;
4876  else
4877  relation->rd_replidindex = InvalidOid;
4878  relation->rd_indexvalid = true;
4879  MemoryContextSwitchTo(oldcxt);
4880 
4881  /* Don't leak the old list, if there is one */
4882  list_free(oldlist);
4883 
4884  return result;
4885 }
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(), ExecRefreshMatView(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5138 of file relcache.c.

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4979 of file relcache.c.

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

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

Referenced by GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5000 of file relcache.c.

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

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

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

◆ 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  {
2087  /*
2088  * Indexes only have a limited number of possible schema changes,
2089  * and we don't want to use the full-blown procedure because it's
2090  * a headache for indexes that reload itself depends on.
2091  */
2092  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2093  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2095  else
2096  RelationClearRelation(rd, true);
2097 
2098  /*
2099  * Normally entries need to be valid here, but before the relcache
2100  * has been initialized, not enough infrastructure exists to
2101  * perform pg_class lookups. The structure of such entries doesn't
2102  * change, but we still want to update the rd_rel entry. So
2103  * rd_isvalid = false is left in place for a later lookup.
2104  */
2105  Assert(rd->rd_isvalid ||
2107  }
2108  return rd;
2109  }
2110 
2111  /*
2112  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2113  * it.
2114  */
2115  rd = RelationBuildDesc(relationId, true);
2116  if (RelationIsValid(rd))
2118  return rd;
2119 }
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1039
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2256
bool IsTransactionState(void)
Definition: xact.c:384

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

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

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

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:493
regproc RegProcedure
Definition: c.h:650
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
#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:5884
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:219
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:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733

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

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

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, 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, SearchSysCacheCopy1, smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), and table_relation_set_new_filelocator().

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

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt