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)
 
DatumRelationGetIndexRawAttOptions (Relation indexrel)
 
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 RelationCloseSmgrByOid (Oid relationId)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
bool RelationIdIsInInitFile (Oid relationId)
 
void RelationCacheInitFilePreInvalidate (void)
 
void RelationCacheInitFilePostInvalidate (void)
 
void RelationCacheInitFileRemove (void)
 

Variables

PGDLLIMPORT bool criticalRelcachesBuilt
 
PGDLLIMPORT bool criticalSharedRelcachesBuilt
 

Macro Definition Documentation

◆ AssertPendingSyncs_RelationCache

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

Definition at line 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 57 of file relcache.h.

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

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3329 of file relcache.c.

3331 {
3332  HASH_SEQ_STATUS status;
3333  RelIdCacheEnt *idhentry;
3334  int i;
3335 
3336  /*
3337  * Forget in_progress_list. This is relevant when we're aborting due to
3338  * an error during RelationBuildDesc(). We don't commit subtransactions
3339  * during RelationBuildDesc().
3340  */
3341  Assert(in_progress_list_len == 0 || !isCommit);
3343 
3344  /*
3345  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3346  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3347  * logic as in AtEOXact_RelationCache.
3348  */
3350  {
3351  hash_seq_init(&status, RelationIdCache);
3352  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3353  {
3354  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3355  mySubid, parentSubid);
3356  }
3357  }
3358  else
3359  {
3360  for (i = 0; i < eoxact_list_len; i++)
3361  {
3362  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3363  &eoxact_list[i],
3364  HASH_FIND,
3365  NULL);
3366  if (idhentry != NULL)
3367  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3368  mySubid, parentSubid);
3369  }
3370  }
3371 
3372  /* Don't reset the list; we still need more cleanup later */
3373 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
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:3384
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 3177 of file relcache.c.

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

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

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5906 of file relcache.c.

5907 {
5911 
5912  return 0; /* return value does not matter */
5913 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1511
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3324
#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:537
#define RelationGetNamespace(relation)
Definition: rel.h:544

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5923 of file relcache.c.

5924 {
5925  TupleDesc reldesc = RelationGetDescr(rel);
5926  const char *colname;
5927 
5928  /* Use reldesc if it's a user attribute, else consult the catalogs */
5929  if (attnum > 0 && attnum <= reldesc->natts)
5930  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5931  else
5932  colname = get_attname(RelationGetRelid(rel), attnum, false);
5933 
5934  return errtablecolname(rel, colname);
5935 }
#define NameStr(name)
Definition: c.h:730
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:826
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetRelid(relation)
Definition: rel.h:503
#define RelationGetDescr(relation)
Definition: rel.h:529
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5947
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5947 of file relcache.c.

5948 {
5949  errtable(rel);
5951 
5952  return 0; /* return value does not matter */
5953 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5906

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

3909 {
3913 
3914  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3915  EOXactListAdd(relation);
3916 }
#define InvalidSubTransactionId
Definition: c.h:642
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:105
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:103
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780

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

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

References Assert(), BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog(), EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), 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 5648 of file relcache.c.

5649 {
5650  List *puboids;
5651  ListCell *lc;
5652  MemoryContext oldcxt;
5653  Oid schemaid;
5654  List *ancestors = NIL;
5655  Oid relid = RelationGetRelid(relation);
5656 
5657  /*
5658  * If not publishable, it publishes no actions. (pgoutput_change() will
5659  * ignore it.)
5660  */
5661  if (!is_publishable_relation(relation))
5662  {
5663  memset(pubdesc, 0, sizeof(PublicationDesc));
5664  pubdesc->rf_valid_for_update = true;
5665  pubdesc->rf_valid_for_delete = true;
5666  pubdesc->cols_valid_for_update = true;
5667  pubdesc->cols_valid_for_delete = true;
5668  return;
5669  }
5670 
5671  if (relation->rd_pubdesc)
5672  {
5673  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5674  return;
5675  }
5676 
5677  memset(pubdesc, 0, sizeof(PublicationDesc));
5678  pubdesc->rf_valid_for_update = true;
5679  pubdesc->rf_valid_for_delete = true;
5680  pubdesc->cols_valid_for_update = true;
5681  pubdesc->cols_valid_for_delete = true;
5682 
5683  /* Fetch the publication membership info. */
5684  puboids = GetRelationPublications(relid);
5685  schemaid = RelationGetNamespace(relation);
5686  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5687 
5688  if (relation->rd_rel->relispartition)
5689  {
5690  /* Add publications that the ancestors are in too. */
5691  ancestors = get_partition_ancestors(relid);
5692 
5693  foreach(lc, ancestors)
5694  {
5695  Oid ancestor = lfirst_oid(lc);
5696 
5697  puboids = list_concat_unique_oid(puboids,
5698  GetRelationPublications(ancestor));
5699  schemaid = get_rel_namespace(ancestor);
5700  puboids = list_concat_unique_oid(puboids,
5701  GetSchemaPublications(schemaid));
5702  }
5703  }
5704  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5705 
5706  foreach(lc, puboids)
5707  {
5708  Oid pubid = lfirst_oid(lc);
5709  HeapTuple tup;
5710  Form_pg_publication pubform;
5711 
5713 
5714  if (!HeapTupleIsValid(tup))
5715  elog(ERROR, "cache lookup failed for publication %u", pubid);
5716 
5717  pubform = (Form_pg_publication) GETSTRUCT(tup);
5718 
5719  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5720  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5721  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5722  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5723 
5724  /*
5725  * Check if all columns referenced in the filter expression are part
5726  * of the REPLICA IDENTITY index or not.
5727  *
5728  * If the publication is FOR ALL TABLES then it means the table has no
5729  * row filters and we can skip the validation.
5730  */
5731  if (!pubform->puballtables &&
5732  (pubform->pubupdate || pubform->pubdelete) &&
5733  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5734  pubform->pubviaroot))
5735  {
5736  if (pubform->pubupdate)
5737  pubdesc->rf_valid_for_update = false;
5738  if (pubform->pubdelete)
5739  pubdesc->rf_valid_for_delete = false;
5740  }
5741 
5742  /*
5743  * Check if all columns are part of the REPLICA IDENTITY index or not.
5744  *
5745  * If the publication is FOR ALL TABLES then it means the table has no
5746  * column list and we can skip the validation.
5747  */
5748  if (!pubform->puballtables &&
5749  (pubform->pubupdate || pubform->pubdelete) &&
5750  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5751  pubform->pubviaroot))
5752  {
5753  if (pubform->pubupdate)
5754  pubdesc->cols_valid_for_update = false;
5755  if (pubform->pubdelete)
5756  pubdesc->cols_valid_for_delete = false;
5757  }
5758 
5759  ReleaseSysCache(tup);
5760 
5761  /*
5762  * If we know everything is replicated and the row filter is invalid
5763  * for update and delete, there is no point to check for other
5764  * publications.
5765  */
5766  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5767  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5768  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5769  break;
5770 
5771  /*
5772  * If we know everything is replicated and the column list is invalid
5773  * for update and delete, there is no point to check for other
5774  * publications.
5775  */
5776  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5777  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5778  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5779  break;
5780  }
5781 
5782  if (relation->rd_pubdesc)
5783  {
5784  pfree(relation->rd_pubdesc);
5785  relation->rd_pubdesc = NULL;
5786  }
5787 
5788  /* Now save copy of the descriptor in the relcache entry. */
5790  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5791  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5792  MemoryContextSwitchTo(oldcxt);
5793 }
#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:1468
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1934
void * palloc(Size size)
Definition: mcxt.c:1210
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#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:166
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:866
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:818
@ PUBLICATIONOID
Definition: syscache.h:83

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6732 of file relcache.c.

6733 {
6734  LWLockRelease(RelCacheInitLock);
6735 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6707 of file relcache.c.

6708 {
6709  char localinitfname[MAXPGPATH];
6710  char sharedinitfname[MAXPGPATH];
6711 
6712  if (DatabasePath)
6713  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6715  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6717 
6718  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6719 
6720  /*
6721  * The files might not be there if no backend has been started since the
6722  * last removal. But complain about failures other than ENOENT with
6723  * ERROR. Fortunately, it's not too late to abort the transaction if we
6724  * can't get rid of the would-be-obsolete init file.
6725  */
6726  if (DatabasePath)
6727  unlink_initfile(localinitfname, ERROR);
6728  unlink_initfile(sharedinitfname, ERROR);
6729 }
char * DatabasePath
Definition: globals.c:97
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
@ LW_EXCLUSIVE
Definition: lwlock.h:115
#define MAXPGPATH
#define snprintf
Definition: port.h:238
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6804
#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 6747 of file relcache.c.

6748 {
6749  const char *tblspcdir = "pg_tblspc";
6750  DIR *dir;
6751  struct dirent *de;
6752  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6753 
6754  snprintf(path, sizeof(path), "global/%s",
6756  unlink_initfile(path, LOG);
6757 
6758  /* Scan everything in the default tablespace */
6760 
6761  /* Scan the tablespace link directory to find non-default tablespaces */
6762  dir = AllocateDir(tblspcdir);
6763 
6764  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6765  {
6766  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6767  {
6768  /* Scan the tablespace dir for per-database dirs */
6769  snprintf(path, sizeof(path), "%s/%s/%s",
6770  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6772  }
6773  }
6774 
6775  FreeDir(dir);
6776 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2762
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2725
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2644
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6780
#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 3934 of file relcache.c.

3935 {
3936  HASHCTL ctl;
3937  int allocsize;
3938 
3939  /*
3940  * make sure cache memory context exists
3941  */
3942  if (!CacheMemoryContext)
3944 
3945  /*
3946  * create hashtable that indexes the relcache
3947  */
3948  ctl.keysize = sizeof(Oid);
3949  ctl.entrysize = sizeof(RelIdCacheEnt);
3950  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3951  &ctl, HASH_ELEM | HASH_BLOBS);
3952 
3953  /*
3954  * reserve enough in_progress_list slots for many cases
3955  */
3956  allocsize = 4;
3959  allocsize * sizeof(*in_progress_list));
3960  in_progress_list_maxlen = allocsize;
3961 
3962  /*
3963  * relation mapper needs to be initialized too
3964  */
3966 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1005
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3931
struct relidcacheent RelIdCacheEnt
static InProgressEnt * in_progress_list
Definition: relcache.c:170
void RelationMapInitialize(void)
Definition: relmapper.c:649
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3980 of file relcache.c.

3981 {
3982  MemoryContext oldcxt;
3983 
3984  /*
3985  * relation mapper needs initialized too
3986  */
3988 
3989  /*
3990  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3991  * nothing.
3992  */
3994  return;
3995 
3996  /*
3997  * switch to cache memory context
3998  */
4000 
4001  /*
4002  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4003  * the cache with pre-made descriptors for the critical shared catalogs.
4004  */
4005  if (!load_relcache_init_file(true))
4006  {
4007  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4008  Natts_pg_database, Desc_pg_database);
4009  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4010  Natts_pg_authid, Desc_pg_authid);
4011  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4012  Natts_pg_auth_members, Desc_pg_auth_members);
4013  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4014  Natts_pg_shseclabel, Desc_pg_shseclabel);
4015  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4016  Natts_pg_subscription, Desc_pg_subscription);
4017 
4018 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4019  }
4020 
4021  MemoryContextSwitchTo(oldcxt);
4022 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:405
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6024
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:1866
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:669

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

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2933 of file relcache.c.

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2877 of file relcache.c.

2878 {
2879  Relation relation;
2880 
2881  RelationIdCacheLookup(relationId, relation);
2882 
2883  if (PointerIsValid(relation))
2884  {
2886  RelationFlushRelation(relation);
2887  }
2888  else
2889  {
2890  int i;
2891 
2892  for (i = 0; i < in_progress_list_len; i++)
2893  if (in_progress_list[i].reloid == relationId)
2894  in_progress_list[i].invalidated = true;
2895  }
2896 }
#define PointerIsValid(pointer)
Definition: c.h:747
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2800
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 2160 of file relcache.c.

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

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

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

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 3042 of file relcache.c.

3043 {
3044  Relation relation;
3045 
3046  RelationIdCacheLookup(relationId, relation);
3047 
3048  if (!PointerIsValid(relation))
3049  return; /* not in cache, nothing to do */
3050 
3051  RelationCloseSmgr(relation);
3052 }

References PointerIsValid, RelationCloseSmgr(), and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2833 of file relcache.c.

2834 {
2835  Relation relation;
2836 
2837  RelationIdCacheLookup(rid, relation);
2838 
2839  if (!PointerIsValid(relation))
2840  return; /* not in cache, nothing to do */
2841 
2842  if (!RelationHasReferenceCountZero(relation))
2843  elog(ERROR, "relation %u is still open", rid);
2844 
2846  if (relation->rd_createSubid != InvalidSubTransactionId ||
2848  {
2849  /*
2850  * In the event of subtransaction rollback, we must not forget
2851  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2852  * invalidates it in lieu of destroying it. (If we're in a top
2853  * transaction, we could opt to destroy the entry.)
2854  */
2856  }
2857 
2858  RelationClearRelation(relation, false);
2859 }

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

5033 {
5034  List *result;
5035  Datum exprsDatum;
5036  bool isnull;
5037  char *exprsString;
5038  List *rawExprs;
5039  ListCell *lc;
5040 
5041  /* Quick exit if there is nothing to do. */
5042  if (relation->rd_indextuple == NULL ||
5043  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5044  return NIL;
5045 
5046  /* Extract raw node tree(s) from index tuple. */
5047  exprsDatum = heap_getattr(relation->rd_indextuple,
5048  Anum_pg_index_indexprs,
5050  &isnull);
5051  Assert(!isnull);
5052  exprsString = TextDatumGetCString(exprsDatum);
5053  rawExprs = (List *) stringToNode(exprsString);
5054  pfree(exprsString);
5055 
5056  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5057  result = NIL;
5058  foreach(lc, rawExprs)
5059  {
5060  Node *rawExpr = (Node *) lfirst(lc);
5061 
5062  result = lappend(result,
5063  makeConst(exprType(rawExpr),
5064  exprTypmod(rawExpr),
5065  exprCollation(rawExpr),
5066  1,
5067  (Datum) 0,
5068  true,
5069  true));
5070  }
5071 
5072  return result;
5073 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:302
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:278
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:780
uintptr_t Datum
Definition: postgres.h:64
void * stringToNode(const char *str)
Definition: read.c:90
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4401
Definition: nodes.h:129
struct HeapTupleData * rd_indextuple
Definition: rel.h:192

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

5520 {
5521  int indnkeyatts;
5522  Oid *ops;
5523  Oid *funcs;
5524  uint16 *strats;
5525  Relation conrel;
5526  SysScanDesc conscan;
5527  ScanKeyData skey[1];
5528  HeapTuple htup;
5529  bool found;
5530  MemoryContext oldcxt;
5531  int i;
5532 
5533  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5534 
5535  /* Allocate result space in caller context */
5536  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5537  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5538  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5539 
5540  /* Quick exit if we have the data cached already */
5541  if (indexRelation->rd_exclstrats != NULL)
5542  {
5543  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5544  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5545  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5546  return;
5547  }
5548 
5549  /*
5550  * Search pg_constraint for the constraint associated with the index. To
5551  * make this not too painfully slow, we use the index on conrelid; that
5552  * will hold the parent relation's OID not the index's own OID.
5553  *
5554  * Note: if we wanted to rely on the constraint name matching the index's
5555  * name, we could just do a direct lookup using pg_constraint's unique
5556  * index. For the moment it doesn't seem worth requiring that.
5557  */
5558  ScanKeyInit(&skey[0],
5559  Anum_pg_constraint_conrelid,
5560  BTEqualStrategyNumber, F_OIDEQ,
5561  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5562 
5563  conrel = table_open(ConstraintRelationId, AccessShareLock);
5564  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5565  NULL, 1, skey);
5566  found = false;
5567 
5568  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5569  {
5571  Datum val;
5572  bool isnull;
5573  ArrayType *arr;
5574  int nelem;
5575 
5576  /* We want the exclusion constraint owning the index */
5577  if (conform->contype != CONSTRAINT_EXCLUSION ||
5578  conform->conindid != RelationGetRelid(indexRelation))
5579  continue;
5580 
5581  /* There should be only one */
5582  if (found)
5583  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5584  RelationGetRelationName(indexRelation));
5585  found = true;
5586 
5587  /* Extract the operator OIDS from conexclop */
5588  val = fastgetattr(htup,
5589  Anum_pg_constraint_conexclop,
5590  conrel->rd_att, &isnull);
5591  if (isnull)
5592  elog(ERROR, "null conexclop for rel %s",
5593  RelationGetRelationName(indexRelation));
5594 
5595  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5596  nelem = ARR_DIMS(arr)[0];
5597  if (ARR_NDIM(arr) != 1 ||
5598  nelem != indnkeyatts ||
5599  ARR_HASNULL(arr) ||
5600  ARR_ELEMTYPE(arr) != OIDOID)
5601  elog(ERROR, "conexclop is not a 1-D Oid array");
5602 
5603  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5604  }
5605 
5606  systable_endscan(conscan);
5607  table_close(conrel, AccessShareLock);
5608 
5609  if (!found)
5610  elog(ERROR, "exclusion constraint record missing for rel %s",
5611  RelationGetRelationName(indexRelation));
5612 
5613  /* We need the func OIDs and strategy numbers too */
5614  for (i = 0; i < indnkeyatts; i++)
5615  {
5616  funcs[i] = get_opcode(ops[i]);
5617  strats[i] = get_op_opfamily_strategy(ops[i],
5618  indexRelation->rd_opfamily[i]);
5619  /* shouldn't fail, since it was checked at index creation */
5620  if (strats[i] == InvalidStrategy)
5621  elog(ERROR, "could not find strategy for operator %u in family %u",
5622  ops[i], indexRelation->rd_opfamily[i]);
5623  }
5624 
5625  /* Save a copy of the results in the relcache entry. */
5626  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5627  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5628  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5629  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5630  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5631  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5632  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5633  MemoryContextSwitchTo(oldcxt);
5634 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
unsigned short uint16
Definition: c.h:489
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1267
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:82
FormData_pg_constraint * Form_pg_constraint
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:522
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:213
uint16 * rd_exclstrats
Definition: rel.h:214
Oid * rd_exclops
Definition: rel.h:212
Form_pg_index rd_index
Definition: rel.h:190
MemoryContext rd_indexcxt
Definition: rel.h:202
Oid * rd_opfamily
Definition: rel.h:205
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 4630 of file relcache.c.

4631 {
4632  List *result;
4633  Relation conrel;
4634  SysScanDesc conscan;
4635  ScanKeyData skey;
4636  HeapTuple htup;
4637  List *oldlist;
4638  MemoryContext oldcxt;
4639 
4640  /* Quick exit if we already computed the list. */
4641  if (relation->rd_fkeyvalid)
4642  return relation->rd_fkeylist;
4643 
4644  /* Fast path: non-partitioned tables without triggers can't have FKs */
4645  if (!relation->rd_rel->relhastriggers &&
4646  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4647  return NIL;
4648 
4649  /*
4650  * We build the list we intend to return (in the caller's context) while
4651  * doing the scan. After successfully completing the scan, we copy that
4652  * list into the relcache entry. This avoids cache-context memory leakage
4653  * if we get some sort of error partway through.
4654  */
4655  result = NIL;
4656 
4657  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4658  ScanKeyInit(&skey,
4659  Anum_pg_constraint_conrelid,
4660  BTEqualStrategyNumber, F_OIDEQ,
4661  ObjectIdGetDatum(RelationGetRelid(relation)));
4662 
4663  conrel = table_open(ConstraintRelationId, AccessShareLock);
4664  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4665  NULL, 1, &skey);
4666 
4667  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4668  {
4669  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4670  ForeignKeyCacheInfo *info;
4671 
4672  /* consider only foreign keys */
4673  if (constraint->contype != CONSTRAINT_FOREIGN)
4674  continue;
4675 
4676  info = makeNode(ForeignKeyCacheInfo);
4677  info->conoid = constraint->oid;
4678  info->conrelid = constraint->conrelid;
4679  info->confrelid = constraint->confrelid;
4680 
4681  DeconstructFkConstraintRow(htup, &info->nkeys,
4682  info->conkey,
4683  info->confkey,
4684  info->conpfeqop,
4685  NULL, NULL, NULL, NULL);
4686 
4687  /* Add FK's node to the result list */
4688  result = lappend(result, info);
4689  }
4690 
4691  systable_endscan(conscan);
4692  table_close(conrel, AccessShareLock);
4693 
4694  /* Now save a copy of the completed list in the relcache entry. */
4696  oldlist = relation->rd_fkeylist;
4697  relation->rd_fkeylist = copyObject(result);
4698  relation->rd_fkeyvalid = true;
4699  MemoryContextSwitchTo(oldcxt);
4700 
4701  /* Don't leak the old list, if there is one */
4702  list_free_deep(oldlist);
4703 
4704  return result;
4705 }
void list_free_deep(List *list)
Definition: list.c:1559
#define copyObject(obj)
Definition: nodes.h:244
#define makeNode(_type_)
Definition: nodes.h:176
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:121
bool rd_fkeyvalid
Definition: rel.h:122

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

5443 {
5444  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5445  Relation indexDesc;
5446  int i;
5447  Oid replidindex;
5448  MemoryContext oldcxt;
5449 
5450  /* Quick exit if we already computed the result */
5451  if (relation->rd_idattr != NULL)
5452  return bms_copy(relation->rd_idattr);
5453 
5454  /* Fast path if definitely no indexes */
5455  if (!RelationGetForm(relation)->relhasindex)
5456  return NULL;
5457 
5458  /* Historic snapshot must be set. */
5460 
5461  replidindex = RelationGetReplicaIndex(relation);
5462 
5463  /* Fall out if there is no replica identity index */
5464  if (!OidIsValid(replidindex))
5465  return NULL;
5466 
5467  /* Look up the description for the replica identity index */
5468  indexDesc = RelationIdGetRelation(replidindex);
5469 
5470  if (!RelationIsValid(indexDesc))
5471  elog(ERROR, "could not open relation with OID %u",
5472  relation->rd_replidindex);
5473 
5474  /* Add referenced attributes to idindexattrs */
5475  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5476  {
5477  int attrnum = indexDesc->rd_index->indkey.values[i];
5478 
5479  /*
5480  * We don't include non-key columns into idindexattrs bitmaps. See
5481  * RelationGetIndexAttrBitmap.
5482  */
5483  if (attrnum != 0)
5484  {
5485  if (i < indexDesc->rd_index->indnkeyatts)
5486  idindexattrs = bms_add_member(idindexattrs,
5488  }
5489  }
5490 
5491  RelationClose(indexDesc);
5492 
5493  /* Don't leak the old values of these bitmaps, if any */
5494  bms_free(relation->rd_idattr);
5495  relation->rd_idattr = NULL;
5496 
5497  /* Now save copy of the bitmap in the relcache entry */
5499  relation->rd_idattr = bms_copy(idindexattrs);
5500  MemoryContextSwitchTo(oldcxt);
5501 
5502  /* We return our original working copy for caller to play with */
5503  return idindexattrs;
5504 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define OidIsValid(objectId)
Definition: c.h:759
#define RelationGetForm(relation)
Definition: rel.h:497
#define RelationIsValid(relation)
Definition: rel.h:476
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4948
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2054
void RelationClose(Relation relation)
Definition: relcache.c:2160
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2103
Oid rd_replidindex
Definition: rel.h:153
Bitmapset * rd_idattr
Definition: rel.h:162
#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 5845 of file relcache.c.

5846 {
5847  MemoryContext oldcxt;
5848  bytea **opts = relation->rd_opcoptions;
5849  Oid relid = RelationGetRelid(relation);
5850  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5851  * IndexRelationGetNumberOfKeyAttributes */
5852  int i;
5853 
5854  /* Try to copy cached options. */
5855  if (opts)
5856  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5857 
5858  /* Get and parse opclass options. */
5859  opts = palloc0(sizeof(*opts) * natts);
5860 
5861  for (i = 0; i < natts; i++)
5862  {
5863  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5864  {
5865  Datum attoptions = get_attoptions(relid, i + 1);
5866 
5867  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5868 
5869  if (attoptions != (Datum) 0)
5870  pfree(DatumGetPointer(attoptions));
5871  }
5872  }
5873 
5874  /* Copy parsed options to the cache. */
5875  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5876  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5877  MemoryContextSwitchTo(oldcxt);
5878 
5879  if (copy)
5880  return opts;
5881 
5882  for (i = 0; i < natts; i++)
5883  {
5884  if (opts[i])
5885  pfree(opts[i]);
5886  }
5887 
5888  pfree(opts);
5889 
5890  return relation->rd_opcoptions;
5891 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:947
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:996
static AmcheckOptions opts
Definition: pg_amcheck.c:110
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:509
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5825
bytea ** rd_opcoptions
Definition: rel.h:216
Definition: c.h:671

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

5170 {
5171  Bitmapset *uindexattrs; /* columns in unique indexes */
5172  Bitmapset *pkindexattrs; /* columns in the primary index */
5173  Bitmapset *idindexattrs; /* columns in the replica identity */
5174  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5175  Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5176  List *indexoidlist;
5177  List *newindexoidlist;
5178  Oid relpkindex;
5179  Oid relreplindex;
5180  ListCell *l;
5181  MemoryContext oldcxt;
5182 
5183  /* Quick exit if we already computed the result. */
5184  if (relation->rd_attrsvalid)
5185  {
5186  switch (attrKind)
5187  {
5188  case INDEX_ATTR_BITMAP_KEY:
5189  return bms_copy(relation->rd_keyattr);
5191  return bms_copy(relation->rd_pkattr);
5193  return bms_copy(relation->rd_idattr);
5195  return bms_copy(relation->rd_hotblockingattr);
5197  return bms_copy(relation->rd_summarizedattr);
5198  default:
5199  elog(ERROR, "unknown attrKind %u", attrKind);
5200  }
5201  }
5202 
5203  /* Fast path if definitely no indexes */
5204  if (!RelationGetForm(relation)->relhasindex)
5205  return NULL;
5206 
5207  /*
5208  * Get cached list of index OIDs. If we have to start over, we do so here.
5209  */
5210 restart:
5211  indexoidlist = RelationGetIndexList(relation);
5212 
5213  /* Fall out if no indexes (but relhasindex was set) */
5214  if (indexoidlist == NIL)
5215  return NULL;
5216 
5217  /*
5218  * Copy the rd_pkindex and rd_replidindex values computed by
5219  * RelationGetIndexList before proceeding. This is needed because a
5220  * relcache flush could occur inside index_open below, resetting the
5221  * fields managed by RelationGetIndexList. We need to do the work with
5222  * stable values of these fields.
5223  */
5224  relpkindex = relation->rd_pkindex;
5225  relreplindex = relation->rd_replidindex;
5226 
5227  /*
5228  * For each index, add referenced attributes to indexattrs.
5229  *
5230  * Note: we consider all indexes returned by RelationGetIndexList, even if
5231  * they are not indisready or indisvalid. This is important because an
5232  * index for which CREATE INDEX CONCURRENTLY has just started must be
5233  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5234  * CONCURRENTLY is far enough along that we should ignore the index, it
5235  * won't be returned at all by RelationGetIndexList.
5236  */
5237  uindexattrs = NULL;
5238  pkindexattrs = NULL;
5239  idindexattrs = NULL;
5240  hotblockingattrs = NULL;
5241  summarizedattrs = NULL;
5242  foreach(l, indexoidlist)
5243  {
5244  Oid indexOid = lfirst_oid(l);
5245  Relation indexDesc;
5246  Datum datum;
5247  bool isnull;
5248  Node *indexExpressions;
5249  Node *indexPredicate;
5250  int i;
5251  bool isKey; /* candidate key */
5252  bool isPK; /* primary key */
5253  bool isIDKey; /* replica identity index */
5254  Bitmapset **attrs;
5255 
5256  indexDesc = index_open(indexOid, AccessShareLock);
5257 
5258  /*
5259  * Extract index expressions and index predicate. Note: Don't use
5260  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5261  * those might run constant expressions evaluation, which needs a
5262  * snapshot, which we might not have here. (Also, it's probably more
5263  * sound to collect the bitmaps before any transformations that might
5264  * eliminate columns, but the practical impact of this is limited.)
5265  */
5266 
5267  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5268  GetPgIndexDescriptor(), &isnull);
5269  if (!isnull)
5270  indexExpressions = stringToNode(TextDatumGetCString(datum));
5271  else
5272  indexExpressions = NULL;
5273 
5274  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5275  GetPgIndexDescriptor(), &isnull);
5276  if (!isnull)
5277  indexPredicate = stringToNode(TextDatumGetCString(datum));
5278  else
5279  indexPredicate = NULL;
5280 
5281  /* Can this index be referenced by a foreign key? */
5282  isKey = indexDesc->rd_index->indisunique &&
5283  indexExpressions == NULL &&
5284  indexPredicate == NULL;
5285 
5286  /* Is this a primary key? */
5287  isPK = (indexOid == relpkindex);
5288 
5289  /* Is this index the configured (or default) replica identity? */
5290  isIDKey = (indexOid == relreplindex);
5291 
5292  /*
5293  * If the index is summarizing, it doesn't block HOT updates, but we
5294  * may still need to update it (if the attributes were modified). So
5295  * decide which bitmap we'll update in the following loop.
5296  */
5297  if (indexDesc->rd_indam->amsummarizing)
5298  attrs = &summarizedattrs;
5299  else
5300  attrs = &hotblockingattrs;
5301 
5302  /* Collect simple attribute references */
5303  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5304  {
5305  int attrnum = indexDesc->rd_index->indkey.values[i];
5306 
5307  /*
5308  * Since we have covering indexes with non-key columns, we must
5309  * handle them accurately here. non-key columns must be added into
5310  * hotblockingattrs or summarizedattrs, since they are in index,
5311  * and update shouldn't miss them.
5312  *
5313  * Summarizing indexes do not block HOT, but do need to be updated
5314  * when the column value changes, thus require a separate
5315  * attribute bitmapset.
5316  *
5317  * Obviously, non-key columns couldn't be referenced by
5318  * foreign key or identity key. Hence we do not include them into
5319  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5320  */
5321  if (attrnum != 0)
5322  {
5323  *attrs = bms_add_member(*attrs,
5325 
5326  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5327  uindexattrs = bms_add_member(uindexattrs,
5329 
5330  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5331  pkindexattrs = bms_add_member(pkindexattrs,
5333 
5334  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5335  idindexattrs = bms_add_member(idindexattrs,
5337  }
5338  }
5339 
5340  /* Collect all attributes used in expressions, too */
5341  pull_varattnos(indexExpressions, 1, attrs);
5342 
5343  /* Collect all attributes in the index predicate, too */
5344  pull_varattnos(indexPredicate, 1, attrs);
5345 
5346  index_close(indexDesc, AccessShareLock);
5347  }
5348 
5349  /*
5350  * During one of the index_opens in the above loop, we might have received
5351  * a relcache flush event on this relcache entry, which might have been
5352  * signaling a change in the rel's index list. If so, we'd better start
5353  * over to ensure we deliver up-to-date attribute bitmaps.
5354  */
5355  newindexoidlist = RelationGetIndexList(relation);
5356  if (equal(indexoidlist, newindexoidlist) &&
5357  relpkindex == relation->rd_pkindex &&
5358  relreplindex == relation->rd_replidindex)
5359  {
5360  /* Still the same index set, so proceed */
5361  list_free(newindexoidlist);
5362  list_free(indexoidlist);
5363  }
5364  else
5365  {
5366  /* Gotta do it over ... might as well not leak memory */
5367  list_free(newindexoidlist);
5368  list_free(indexoidlist);
5369  bms_free(uindexattrs);
5370  bms_free(pkindexattrs);
5371  bms_free(idindexattrs);
5372  bms_free(hotblockingattrs);
5373  bms_free(summarizedattrs);
5374 
5375  goto restart;
5376  }
5377 
5378  /* Don't leak the old values of these bitmaps, if any */
5379  relation->rd_attrsvalid = false;
5380  bms_free(relation->rd_keyattr);
5381  relation->rd_keyattr = NULL;
5382  bms_free(relation->rd_pkattr);
5383  relation->rd_pkattr = NULL;
5384  bms_free(relation->rd_idattr);
5385  relation->rd_idattr = NULL;
5386  bms_free(relation->rd_hotblockingattr);
5387  relation->rd_hotblockingattr = NULL;
5388  bms_free(relation->rd_summarizedattr);
5389  relation->rd_summarizedattr = NULL;
5390 
5391  /*
5392  * Now save copies of the bitmaps in the relcache entry. We intentionally
5393  * set rd_attrsvalid last, because that's the one that signals validity of
5394  * the values; if we run out of memory before making that copy, we won't
5395  * leave the relcache entry looking like the other ones are valid but
5396  * empty.
5397  */
5399  relation->rd_keyattr = bms_copy(uindexattrs);
5400  relation->rd_pkattr = bms_copy(pkindexattrs);
5401  relation->rd_idattr = bms_copy(idindexattrs);
5402  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5403  relation->rd_summarizedattr = bms_copy(summarizedattrs);
5404  relation->rd_attrsvalid = true;
5405  MemoryContextSwitchTo(oldcxt);
5406 
5407  /* We return our original working copy for caller to play with */
5408  switch (attrKind)
5409  {
5410  case INDEX_ATTR_BITMAP_KEY:
5411  return uindexattrs;
5413  return pkindexattrs;
5415  return idindexattrs;
5417  return hotblockingattrs;
5419  return summarizedattrs;
5420  default:
5421  elog(ERROR, "unknown attrKind %u", attrKind);
5422  return NULL;
5423  }
5424 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4739
bool amsummarizing
Definition: amapi.h:248
Bitmapset * rd_keyattr
Definition: rel.h:160
struct IndexAmRoutine * rd_indam
Definition: rel.h:204
bool rd_attrsvalid
Definition: rel.h:159
Bitmapset * rd_hotblockingattr
Definition: rel.h:163
Oid rd_pkindex
Definition: rel.h:152
Bitmapset * rd_summarizedattr
Definition: rel.h:164
Bitmapset * rd_pkattr
Definition: rel.h:161
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 ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), pub_collist_contains_invalid_column(), and pub_rf_contains_invalid_column().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4973 of file relcache.c.

4974 {
4975  List *result;
4976  Datum exprsDatum;
4977  bool isnull;
4978  char *exprsString;
4979  MemoryContext oldcxt;
4980 
4981  /* Quick exit if we already computed the result. */
4982  if (relation->rd_indexprs)
4983  return copyObject(relation->rd_indexprs);
4984 
4985  /* Quick exit if there is nothing to do. */
4986  if (relation->rd_indextuple == NULL ||
4987  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4988  return NIL;
4989 
4990  /*
4991  * We build the tree we intend to return in the caller's context. After
4992  * successfully completing the work, we copy it into the relcache entry.
4993  * This avoids problems if we get some sort of error partway through.
4994  */
4995  exprsDatum = heap_getattr(relation->rd_indextuple,
4996  Anum_pg_index_indexprs,
4998  &isnull);
4999  Assert(!isnull);
5000  exprsString = TextDatumGetCString(exprsDatum);
5001  result = (List *) stringToNode(exprsString);
5002  pfree(exprsString);
5003 
5004  /*
5005  * Run the expressions through eval_const_expressions. This is not just an
5006  * optimization, but is necessary, because the planner will be comparing
5007  * them to similarly-processed qual clauses, and may fail to detect valid
5008  * matches without this. We must not use canonicalize_qual, however,
5009  * since these aren't qual expressions.
5010  */
5011  result = (List *) eval_const_expressions(NULL, (Node *) result);
5012 
5013  /* May as well fix opfuncids too */
5014  fix_opfuncids((Node *) result);
5015 
5016  /* Now save a copy of the completed tree in the relcache entry. */
5017  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5018  relation->rd_indexprs = copyObject(result);
5019  MemoryContextSwitchTo(oldcxt);
5020 
5021  return result;
5022 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2163
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1691
List * rd_indexprs
Definition: rel.h:210

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

4740 {
4741  Relation indrel;
4742  SysScanDesc indscan;
4743  ScanKeyData skey;
4744  HeapTuple htup;
4745  List *result;
4746  List *oldlist;
4747  char replident = relation->rd_rel->relreplident;
4748  Oid pkeyIndex = InvalidOid;
4749  Oid candidateIndex = InvalidOid;
4750  MemoryContext oldcxt;
4751 
4752  /* Quick exit if we already computed the list. */
4753  if (relation->rd_indexvalid)
4754  return list_copy(relation->rd_indexlist);
4755 
4756  /*
4757  * We build the list we intend to return (in the caller's context) while
4758  * doing the scan. After successfully completing the scan, we copy that
4759  * list into the relcache entry. This avoids cache-context memory leakage
4760  * if we get some sort of error partway through.
4761  */
4762  result = NIL;
4763 
4764  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4765  ScanKeyInit(&skey,
4766  Anum_pg_index_indrelid,
4767  BTEqualStrategyNumber, F_OIDEQ,
4768  ObjectIdGetDatum(RelationGetRelid(relation)));
4769 
4770  indrel = table_open(IndexRelationId, AccessShareLock);
4771  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4772  NULL, 1, &skey);
4773 
4774  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4775  {
4777 
4778  /*
4779  * Ignore any indexes that are currently being dropped. This will
4780  * prevent them from being searched, inserted into, or considered in
4781  * HOT-safety decisions. It's unsafe to touch such an index at all
4782  * since its catalog entries could disappear at any instant.
4783  */
4784  if (!index->indislive)
4785  continue;
4786 
4787  /* add index's OID to result list */
4788  result = lappend_oid(result, index->indexrelid);
4789 
4790  /*
4791  * Invalid, non-unique, non-immediate or predicate indexes aren't
4792  * interesting for either oid indexes or replication identity indexes,
4793  * so don't check them.
4794  */
4795  if (!index->indisvalid || !index->indisunique ||
4796  !index->indimmediate ||
4797  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4798  continue;
4799 
4800  /* remember primary key index if any */
4801  if (index->indisprimary)
4802  pkeyIndex = index->indexrelid;
4803 
4804  /* remember explicitly chosen replica index */
4805  if (index->indisreplident)
4806  candidateIndex = index->indexrelid;
4807  }
4808 
4809  systable_endscan(indscan);
4810 
4811  table_close(indrel, AccessShareLock);
4812 
4813  /* Sort the result list into OID order, per API spec. */
4814  list_sort(result, list_oid_cmp);
4815 
4816  /* Now save a copy of the completed list in the relcache entry. */
4818  oldlist = relation->rd_indexlist;
4819  relation->rd_indexlist = list_copy(result);
4820  relation->rd_pkindex = pkeyIndex;
4821  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
4822  relation->rd_replidindex = pkeyIndex;
4823  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4824  relation->rd_replidindex = candidateIndex;
4825  else
4826  relation->rd_replidindex = InvalidOid;
4827  relation->rd_indexvalid = true;
4828  MemoryContextSwitchTo(oldcxt);
4829 
4830  /* Don't leak the old list, if there is one */
4831  list_free(oldlist);
4832 
4833  return result;
4834 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1673
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
List * list_copy(const List *oldlist)
Definition: list.c:1572
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1706
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool rd_indexvalid
Definition: rel.h:63
List * rd_indexlist
Definition: rel.h:151
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_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterIndexNamespaces(), ATExecChangeOwner(), ATExecDropNotNull(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), expandTableLikeClause(), 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 5086 of file relcache.c.

5087 {
5088  List *result;
5089  Datum predDatum;
5090  bool isnull;
5091  char *predString;
5092  MemoryContext oldcxt;
5093 
5094  /* Quick exit if we already computed the result. */
5095  if (relation->rd_indpred)
5096  return copyObject(relation->rd_indpred);
5097 
5098  /* Quick exit if there is nothing to do. */
5099  if (relation->rd_indextuple == NULL ||
5100  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5101  return NIL;
5102 
5103  /*
5104  * We build the tree we intend to return in the caller's context. After
5105  * successfully completing the work, we copy it into the relcache entry.
5106  * This avoids problems if we get some sort of error partway through.
5107  */
5108  predDatum = heap_getattr(relation->rd_indextuple,
5109  Anum_pg_index_indpred,
5111  &isnull);
5112  Assert(!isnull);
5113  predString = TextDatumGetCString(predDatum);
5114  result = (List *) stringToNode(predString);
5115  pfree(predString);
5116 
5117  /*
5118  * Run the expression through const-simplification and canonicalization.
5119  * This is not just an optimization, but is necessary, because the planner
5120  * will be comparing it to similarly-processed qual clauses, and may fail
5121  * to detect valid matches without this. This must match the processing
5122  * done to qual clauses in preprocess_expression()! (We can skip the
5123  * stuff involving subqueries, however, since we don't allow any in index
5124  * predicates.)
5125  */
5126  result = (List *) eval_const_expressions(NULL, (Node *) result);
5127 
5128  result = (List *) canonicalize_qual((Expr *) result, false);
5129 
5130  /* Also convert to implicit-AND format */
5131  result = make_ands_implicit((Expr *) result);
5132 
5133  /* May as well fix opfuncids too */
5134  fix_opfuncids((Node *) result);
5135 
5136  /* Now save a copy of the completed tree in the relcache entry. */
5137  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5138  relation->rd_indpred = copyObject(result);
5139  MemoryContextSwitchTo(oldcxt);
5140 
5141  return result;
5142 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:722
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:294
List * rd_indpred
Definition: rel.h:211

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

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

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  indexrel)

Definition at line 5799 of file relcache.c.

5800 {
5801  Oid indexrelid = RelationGetRelid(indexrel);
5802  int16 natts = RelationGetNumberOfAttributes(indexrel);
5803  Datum *options = NULL;
5804  int16 attnum;
5805 
5806  for (attnum = 1; attnum <= natts; attnum++)
5807  {
5808  if (indexrel->rd_indam->amoptsprocnum == 0)
5809  continue;
5810 
5811  if (!OidIsValid(index_getprocid(indexrel, attnum,
5812  indexrel->rd_indam->amoptsprocnum)))
5813  continue;
5814 
5815  if (!options)
5816  options = palloc0(sizeof(Datum) * natts);
5817 
5818  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5819  }
5820 
5821  return options;
5822 }
signed short int16
Definition: c.h:477
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:777
static char ** options
uint16 amoptsprocnum
Definition: amapi.h:218

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

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4927 of file relcache.c.

4928 {
4929  List *ilist;
4930 
4931  if (!relation->rd_indexvalid)
4932  {
4933  /* RelationGetIndexList does the heavy lifting. */
4934  ilist = RelationGetIndexList(relation);
4935  list_free(ilist);
4936  Assert(relation->rd_indexvalid);
4937  }
4938 
4939  return relation->rd_pkindex;
4940 }

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

Referenced by GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4948 of file relcache.c.

4949 {
4950  List *ilist;
4951 
4952  if (!relation->rd_indexvalid)
4953  {
4954  /* RelationGetIndexList does the heavy lifting. */
4955  ilist = RelationGetIndexList(relation);
4956  list_free(ilist);
4957  Assert(relation->rd_indexvalid);
4958  }
4959 
4960  return relation->rd_replidindex;
4961 }

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

4859 {
4860  Relation indrel;
4861  SysScanDesc indscan;
4862  ScanKeyData skey;
4863  HeapTuple htup;
4864  List *result;
4865  List *oldlist;
4866  MemoryContext oldcxt;
4867 
4868  /* Quick exit if we already computed the list. */
4869  if (relation->rd_statvalid != 0)
4870  return list_copy(relation->rd_statlist);
4871 
4872  /*
4873  * We build the list we intend to return (in the caller's context) while
4874  * doing the scan. After successfully completing the scan, we copy that
4875  * list into the relcache entry. This avoids cache-context memory leakage
4876  * if we get some sort of error partway through.
4877  */
4878  result = NIL;
4879 
4880  /*
4881  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4882  * rel.
4883  */
4884  ScanKeyInit(&skey,
4885  Anum_pg_statistic_ext_stxrelid,
4886  BTEqualStrategyNumber, F_OIDEQ,
4887  ObjectIdGetDatum(RelationGetRelid(relation)));
4888 
4889  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4890  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4891  NULL, 1, &skey);
4892 
4893  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4894  {
4895  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4896 
4897  result = lappend_oid(result, oid);
4898  }
4899 
4900  systable_endscan(indscan);
4901 
4902  table_close(indrel, AccessShareLock);
4903 
4904  /* Sort the result list into OID order, per API spec. */
4905  list_sort(result, list_oid_cmp);
4906 
4907  /* Now save a copy of the completed list in the relcache entry. */
4909  oldlist = relation->rd_statlist;
4910  relation->rd_statlist = list_copy(result);
4911 
4912  relation->rd_statvalid = true;
4913  MemoryContextSwitchTo(oldcxt);
4914 
4915  /* Don't leak the old list, if there is one */
4916  list_free(oldlist);
4917 
4918  return result;
4919 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
bool rd_statvalid
Definition: rel.h:65
List * rd_statlist
Definition: rel.h:156

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

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

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

6668 {
6669  if (relationId == SharedSecLabelRelationId ||
6670  relationId == TriggerRelidNameIndexId ||
6671  relationId == DatabaseNameIndexId ||
6672  relationId == SharedSecLabelObjectIndexId)
6673  {
6674  /*
6675  * If this Assert fails, we don't need the applicable special case
6676  * anymore.
6677  */
6678  Assert(!RelationSupportsSysCache(relationId));
6679  return true;
6680  }
6681  return RelationSupportsSysCache(relationId);
6682 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1249

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1417 of file relcache.c.

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

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

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1801 of file relcache.c.

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

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

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

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3709 of file relcache.c.

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

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, RELOID, 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