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_ALL , INDEX_ATTR_BITMAP_KEY , INDEX_ATTR_BITMAP_PRIMARY_KEY , INDEX_ATTR_BITMAP_IDENTITY_KEY }
 

Functions

Relation RelationIdGetRelation (Oid relationId)
 
void RelationClose (Relation relation)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid 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 134 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_ALL 
INDEX_ATTR_BITMAP_KEY 
INDEX_ATTR_BITMAP_PRIMARY_KEY 
INDEX_ATTR_BITMAP_IDENTITY_KEY 

Definition at line 57 of file relcache.h.

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

Function Documentation

◆ AtEOSubXact_RelationCache()

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

Definition at line 3328 of file relcache.c.

3330 {
3332  RelIdCacheEnt *idhentry;
3333  int i;
3334 
3335  /*
3336  * Forget in_progress_list. This is relevant when we're aborting due to
3337  * an error during RelationBuildDesc(). We don't commit subtransactions
3338  * during RelationBuildDesc().
3339  */
3340  Assert(in_progress_list_len == 0 || !isCommit);
3342 
3343  /*
3344  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3345  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3346  * logic as in AtEOXact_RelationCache.
3347  */
3349  {
3351  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3352  {
3353  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3354  mySubid, parentSubid);
3355  }
3356  }
3357  else
3358  {
3359  for (i = 0; i < eoxact_list_len; i++)
3360  {
3361  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3362  (void *) &eoxact_list[i],
3363  HASH_FIND,
3364  NULL);
3365  if (idhentry != NULL)
3366  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3367  mySubid, parentSubid);
3368  }
3369  }
3370 
3371  /* Don't reset the list; we still need more cleanup later */
3372 }
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 void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
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:3383
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, relidcacheent::reldesc, and status().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3176 of file relcache.c.

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

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5876 of file relcache.c.

5877 {
5881 
5882  return 0; /* return value does not matter */
5883 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1348
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
#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:535
#define RelationGetNamespace(relation)
Definition: rel.h:542

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

5894 {
5895  TupleDesc reldesc = RelationGetDescr(rel);
5896  const char *colname;
5897 
5898  /* Use reldesc if it's a user attribute, else consult the catalogs */
5899  if (attnum > 0 && attnum <= reldesc->natts)
5900  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5901  else
5902  colname = get_attname(RelationGetRelid(rel), attnum, false);
5903 
5904  return errtablecolname(rel, colname);
5905 }
#define NameStr(name)
Definition: c.h:682
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:83
#define RelationGetRelid(relation)
Definition: rel.h:501
#define RelationGetDescr(relation)
Definition: rel.h:527
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5917
#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 5917 of file relcache.c.

5918 {
5919  errtable(rel);
5921 
5922  return 0; /* return value does not matter */
5923 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5876

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

3908 {
3912 
3913  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3914  EOXactListAdd(relation);
3915 }
#define InvalidSubTransactionId
Definition: c.h:594
#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:779

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

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

5619 {
5620  List *puboids;
5621  ListCell *lc;
5622  MemoryContext oldcxt;
5623  Oid schemaid;
5624  List *ancestors = NIL;
5625  Oid relid = RelationGetRelid(relation);
5626 
5627  /*
5628  * If not publishable, it publishes no actions. (pgoutput_change() will
5629  * ignore it.)
5630  */
5631  if (!is_publishable_relation(relation))
5632  {
5633  memset(pubdesc, 0, sizeof(PublicationDesc));
5634  pubdesc->rf_valid_for_update = true;
5635  pubdesc->rf_valid_for_delete = true;
5636  pubdesc->cols_valid_for_update = true;
5637  pubdesc->cols_valid_for_delete = true;
5638  return;
5639  }
5640 
5641  if (relation->rd_pubdesc)
5642  {
5643  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5644  return;
5645  }
5646 
5647  memset(pubdesc, 0, sizeof(PublicationDesc));
5648  pubdesc->rf_valid_for_update = true;
5649  pubdesc->rf_valid_for_delete = true;
5650  pubdesc->cols_valid_for_update = true;
5651  pubdesc->cols_valid_for_delete = true;
5652 
5653  /* Fetch the publication membership info. */
5654  puboids = GetRelationPublications(relid);
5655  schemaid = RelationGetNamespace(relation);
5656  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5657 
5658  if (relation->rd_rel->relispartition)
5659  {
5660  /* Add publications that the ancestors are in too. */
5661  ancestors = get_partition_ancestors(relid);
5662 
5663  foreach(lc, ancestors)
5664  {
5665  Oid ancestor = lfirst_oid(lc);
5666 
5667  puboids = list_concat_unique_oid(puboids,
5668  GetRelationPublications(ancestor));
5669  schemaid = get_rel_namespace(ancestor);
5670  puboids = list_concat_unique_oid(puboids,
5671  GetSchemaPublications(schemaid));
5672  }
5673  }
5674  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5675 
5676  foreach(lc, puboids)
5677  {
5678  Oid pubid = lfirst_oid(lc);
5679  HeapTuple tup;
5680  Form_pg_publication pubform;
5681 
5683 
5684  if (!HeapTupleIsValid(tup))
5685  elog(ERROR, "cache lookup failed for publication %u", pubid);
5686 
5687  pubform = (Form_pg_publication) GETSTRUCT(tup);
5688 
5689  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5690  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5691  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5692  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5693 
5694  /*
5695  * Check if all columns referenced in the filter expression are part
5696  * of the REPLICA IDENTITY index or not.
5697  *
5698  * If the publication is FOR ALL TABLES then it means the table has no
5699  * row filters and we can skip the validation.
5700  */
5701  if (!pubform->puballtables &&
5702  (pubform->pubupdate || pubform->pubdelete) &&
5703  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5704  pubform->pubviaroot))
5705  {
5706  if (pubform->pubupdate)
5707  pubdesc->rf_valid_for_update = false;
5708  if (pubform->pubdelete)
5709  pubdesc->rf_valid_for_delete = false;
5710  }
5711 
5712  /*
5713  * Check if all columns are part of the REPLICA IDENTITY index or not.
5714  *
5715  * If the publication is FOR ALL TABLES then it means the table has no
5716  * column list and we can skip the validation.
5717  */
5718  if (!pubform->puballtables &&
5719  (pubform->pubupdate || pubform->pubdelete) &&
5720  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5721  pubform->pubviaroot))
5722  {
5723  if (pubform->pubupdate)
5724  pubdesc->cols_valid_for_update = false;
5725  if (pubform->pubdelete)
5726  pubdesc->cols_valid_for_delete = false;
5727  }
5728 
5729  ReleaseSysCache(tup);
5730 
5731  /*
5732  * If we know everything is replicated and the row filter is invalid
5733  * for update and delete, there is no point to check for other
5734  * publications.
5735  */
5736  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5737  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5738  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5739  break;
5740 
5741  /*
5742  * If we know everything is replicated and the column list is invalid
5743  * for update and delete, there is no point to check for other
5744  * publications.
5745  */
5746  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5747  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5748  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5749  break;
5750  }
5751 
5752  if (relation->rd_pubdesc)
5753  {
5754  pfree(relation->rd_pubdesc);
5755  relation->rd_pubdesc = NULL;
5756  }
5757 
5758  /* Now save copy of the descriptor in the relcache entry. */
5760  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5761  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5762  MemoryContextSwitchTo(oldcxt);
5763 }
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1468
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1934
void * palloc(Size size)
Definition: mcxt.c:1199
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define NIL
Definition: pg_list.h:66
#define lfirst_oid(lc)
Definition: pg_list.h:172
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:600
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:52
PublicationActions pubactions
bool cols_valid_for_delete
bool cols_valid_for_update
PublicationDesc * rd_pubdesc
Definition: rel.h:164
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ PUBLICATIONOID
Definition: syscache.h:83

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6702 of file relcache.c.

6703 {
6704  LWLockRelease(RelCacheInitLock);
6705 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1802

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6677 of file relcache.c.

6678 {
6679  char localinitfname[MAXPGPATH];
6680  char sharedinitfname[MAXPGPATH];
6681 
6682  if (DatabasePath)
6683  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6685  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6687 
6688  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6689 
6690  /*
6691  * The files might not be there if no backend has been started since the
6692  * last removal. But complain about failures other than ENOENT with
6693  * ERROR. Fortunately, it's not too late to abort the transaction if we
6694  * can't get rid of the would-be-obsolete init file.
6695  */
6696  if (DatabasePath)
6697  unlink_initfile(localinitfname, ERROR);
6698  unlink_initfile(sharedinitfname, ERROR);
6699 }
char * DatabasePath
Definition: globals.c:97
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1194
@ LW_EXCLUSIVE
Definition: lwlock.h:112
#define MAXPGPATH
#define snprintf
Definition: port.h:238
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6774
#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 6717 of file relcache.c.

6718 {
6719  const char *tblspcdir = "pg_tblspc";
6720  DIR *dir;
6721  struct dirent *de;
6722  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6723 
6724  snprintf(path, sizeof(path), "global/%s",
6726  unlink_initfile(path, LOG);
6727 
6728  /* Scan everything in the default tablespace */
6730 
6731  /* Scan the tablespace link directory to find non-default tablespaces */
6732  dir = AllocateDir(tblspcdir);
6733 
6734  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6735  {
6736  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6737  {
6738  /* Scan the tablespace dir for per-database dirs */
6739  snprintf(path, sizeof(path), "%s/%s/%s",
6740  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6742  }
6743  }
6744 
6745  FreeDir(dir);
6746 }
#define LOG
Definition: elog.h:27
int FreeDir(DIR *dir)
Definition: fd.c:2761
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2724
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2643
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6750
#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 3933 of file relcache.c.

3934 {
3935  HASHCTL ctl;
3936  int allocsize;
3937 
3938  /*
3939  * make sure cache memory context exists
3940  */
3941  if (!CacheMemoryContext)
3943 
3944  /*
3945  * create hashtable that indexes the relcache
3946  */
3947  ctl.keysize = sizeof(Oid);
3948  ctl.entrysize = sizeof(RelIdCacheEnt);
3949  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3950  &ctl, HASH_ELEM | HASH_BLOBS);
3951 
3952  /*
3953  * reserve enough in_progress_list slots for many cases
3954  */
3955  allocsize = 4;
3958  allocsize * sizeof(*in_progress_list));
3959  in_progress_list_maxlen = allocsize;
3960 
3961  /*
3962  * relation mapper needs to be initialized too
3963  */
3965 }
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:994
static int in_progress_list_maxlen
Definition: relcache.c:172
#define INITRELCACHESIZE
Definition: relcache.c:3930
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 3979 of file relcache.c.

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

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2932 of file relcache.c.

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2876 of file relcache.c.

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

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

References PointerIsValid, RelationCloseSmgr(), and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2832 of file relcache.c.

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

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

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

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

Referenced by BuildDummyIndexInfo().

◆ RelationGetExclusionInfo()

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

Definition at line 5486 of file relcache.c.

5490 {
5491  int indnkeyatts;
5492  Oid *ops;
5493  Oid *funcs;
5494  uint16 *strats;
5495  Relation conrel;
5496  SysScanDesc conscan;
5497  ScanKeyData skey[1];
5498  HeapTuple htup;
5499  bool found;
5500  MemoryContext oldcxt;
5501  int i;
5502 
5503  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5504 
5505  /* Allocate result space in caller context */
5506  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5507  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5508  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5509 
5510  /* Quick exit if we have the data cached already */
5511  if (indexRelation->rd_exclstrats != NULL)
5512  {
5513  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5514  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5515  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5516  return;
5517  }
5518 
5519  /*
5520  * Search pg_constraint for the constraint associated with the index. To
5521  * make this not too painfully slow, we use the index on conrelid; that
5522  * will hold the parent relation's OID not the index's own OID.
5523  *
5524  * Note: if we wanted to rely on the constraint name matching the index's
5525  * name, we could just do a direct lookup using pg_constraint's unique
5526  * index. For the moment it doesn't seem worth requiring that.
5527  */
5528  ScanKeyInit(&skey[0],
5529  Anum_pg_constraint_conrelid,
5530  BTEqualStrategyNumber, F_OIDEQ,
5531  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5532 
5533  conrel = table_open(ConstraintRelationId, AccessShareLock);
5534  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5535  NULL, 1, skey);
5536  found = false;
5537 
5538  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5539  {
5541  Datum val;
5542  bool isnull;
5543  ArrayType *arr;
5544  int nelem;
5545 
5546  /* We want the exclusion constraint owning the index */
5547  if (conform->contype != CONSTRAINT_EXCLUSION ||
5548  conform->conindid != RelationGetRelid(indexRelation))
5549  continue;
5550 
5551  /* There should be only one */
5552  if (found)
5553  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5554  RelationGetRelationName(indexRelation));
5555  found = true;
5556 
5557  /* Extract the operator OIDS from conexclop */
5558  val = fastgetattr(htup,
5559  Anum_pg_constraint_conexclop,
5560  conrel->rd_att, &isnull);
5561  if (isnull)
5562  elog(ERROR, "null conexclop for rel %s",
5563  RelationGetRelationName(indexRelation));
5564 
5565  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5566  nelem = ARR_DIMS(arr)[0];
5567  if (ARR_NDIM(arr) != 1 ||
5568  nelem != indnkeyatts ||
5569  ARR_HASNULL(arr) ||
5570  ARR_ELEMTYPE(arr) != OIDOID)
5571  elog(ERROR, "conexclop is not a 1-D Oid array");
5572 
5573  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5574  }
5575 
5576  systable_endscan(conscan);
5577  table_close(conrel, AccessShareLock);
5578 
5579  if (!found)
5580  elog(ERROR, "exclusion constraint record missing for rel %s",
5581  RelationGetRelationName(indexRelation));
5582 
5583  /* We need the func OIDs and strategy numbers too */
5584  for (i = 0; i < indnkeyatts; i++)
5585  {
5586  funcs[i] = get_opcode(ops[i]);
5587  strats[i] = get_op_opfamily_strategy(ops[i],
5588  indexRelation->rd_opfamily[i]);
5589  /* shouldn't fail, since it was checked at index creation */
5590  if (strats[i] == InvalidStrategy)
5591  elog(ERROR, "could not find strategy for operator %u in family %u",
5592  ops[i], indexRelation->rd_opfamily[i]);
5593  }
5594 
5595  /* Save a copy of the results in the relcache entry. */
5596  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5597  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5598  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5599  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5600  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5601  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5602  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5603  MemoryContextSwitchTo(oldcxt);
5604 }
#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:441
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:745
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:520
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define InvalidStrategy
Definition: stratnum.h:24
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid * rd_exclprocs
Definition: rel.h:211
uint16 * rd_exclstrats
Definition: rel.h:212
Oid * rd_exclops
Definition: rel.h:210
Form_pg_index rd_index
Definition: rel.h:188
MemoryContext rd_indexcxt
Definition: rel.h:200
Oid * rd_opfamily
Definition: rel.h:203
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c: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 4629 of file relcache.c.

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

5413 {
5414  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5415  Relation indexDesc;
5416  int i;
5417  Oid replidindex;
5418  MemoryContext oldcxt;
5419 
5420  /* Quick exit if we already computed the result */
5421  if (relation->rd_idattr != NULL)
5422  return bms_copy(relation->rd_idattr);
5423 
5424  /* Fast path if definitely no indexes */
5425  if (!RelationGetForm(relation)->relhasindex)
5426  return NULL;
5427 
5428  /* Historic snapshot must be set. */
5430 
5431  replidindex = RelationGetReplicaIndex(relation);
5432 
5433  /* Fall out if there is no replica identity index */
5434  if (!OidIsValid(replidindex))
5435  return NULL;
5436 
5437  /* Look up the description for the replica identity index */
5438  indexDesc = RelationIdGetRelation(replidindex);
5439 
5440  if (!RelationIsValid(indexDesc))
5441  elog(ERROR, "could not open relation with OID %u",
5442  relation->rd_replidindex);
5443 
5444  /* Add referenced attributes to idindexattrs */
5445  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5446  {
5447  int attrnum = indexDesc->rd_index->indkey.values[i];
5448 
5449  /*
5450  * We don't include non-key columns into idindexattrs bitmaps. See
5451  * RelationGetIndexAttrBitmap.
5452  */
5453  if (attrnum != 0)
5454  {
5455  if (i < indexDesc->rd_index->indnkeyatts)
5456  idindexattrs = bms_add_member(idindexattrs,
5458  }
5459  }
5460 
5461  RelationClose(indexDesc);
5462 
5463  /* Don't leak the old values of these bitmaps, if any */
5464  bms_free(relation->rd_idattr);
5465  relation->rd_idattr = NULL;
5466 
5467  /* Now save copy of the bitmap in the relcache entry */
5469  relation->rd_idattr = bms_copy(idindexattrs);
5470  MemoryContextSwitchTo(oldcxt);
5471 
5472  /* We return our original working copy for caller to play with */
5473  return idindexattrs;
5474 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
#define OidIsValid(objectId)
Definition: c.h:711
#define RelationGetForm(relation)
Definition: rel.h:495
#define RelationIsValid(relation)
Definition: rel.h:474
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4947
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 5815 of file relcache.c.

5816 {
5817  MemoryContext oldcxt;
5818  bytea **opts = relation->rd_opcoptions;
5819  Oid relid = RelationGetRelid(relation);
5820  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5821  * IndexRelationGetNumberOfKeyAttributes */
5822  int i;
5823 
5824  /* Try to copy cached options. */
5825  if (opts)
5826  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5827 
5828  /* Get and parse opclass options. */
5829  opts = palloc0(sizeof(*opts) * natts);
5830 
5831  for (i = 0; i < natts; i++)
5832  {
5833  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5834  {
5835  Datum attoptions = get_attoptions(relid, i + 1);
5836 
5837  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5838 
5839  if (attoptions != (Datum) 0)
5840  pfree(DatumGetPointer(attoptions));
5841  }
5842  }
5843 
5844  /* Copy parsed options to the cache. */
5845  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5846  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5847  MemoryContextSwitchTo(oldcxt);
5848 
5849  if (copy)
5850  return opts;
5851 
5852  for (i = 0; i < natts; i++)
5853  {
5854  if (opts[i])
5855  pfree(opts[i]);
5856  }
5857 
5858  pfree(opts);
5859 
5860  return relation->rd_opcoptions;
5861 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:939
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:996
static AmcheckOptions opts
Definition: pg_amcheck.c:110
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:507
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5795
bytea ** rd_opcoptions
Definition: rel.h:214
Definition: c.h:623

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

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

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

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

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 4972 of file relcache.c.

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

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

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

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4738 of file relcache.c.

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

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

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

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

◆ RelationGetIndexRawAttOptions()

Datum* RelationGetIndexRawAttOptions ( Relation  indexrel)

Definition at line 5769 of file relcache.c.

5770 {
5771  Oid indexrelid = RelationGetRelid(indexrel);
5772  int16 natts = RelationGetNumberOfAttributes(indexrel);
5773  Datum *options = NULL;
5774  int16 attnum;
5775 
5776  for (attnum = 1; attnum <= natts; attnum++)
5777  {
5778  if (indexrel->rd_indam->amoptsprocnum == 0)
5779  continue;
5780 
5781  if (!OidIsValid(index_getprocid(indexrel, attnum,
5782  indexrel->rd_indam->amoptsprocnum)))
5783  continue;
5784 
5785  if (!options)
5786  options = palloc0(sizeof(Datum) * natts);
5787 
5788  options[attnum - 1] = get_attoptions(indexrelid, attnum);
5789  }
5790 
5791  return options;
5792 }
signed short int16
Definition: c.h:429
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769
static char ** options
uint16 amoptsprocnum
Definition: amapi.h:218
struct IndexAmRoutine * rd_indam
Definition: rel.h:202

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

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

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

Referenced by build_replindex_scan_key(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4947 of file relcache.c.

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

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4857 of file relcache.c.

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

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

6638 {
6639  if (relationId == SharedSecLabelRelationId ||
6640  relationId == TriggerRelidNameIndexId ||
6641  relationId == DatabaseNameIndexId ||
6642  relationId == SharedSecLabelObjectIndexId)
6643  {
6644  /*
6645  * If this Assert fails, we don't need the applicable special case
6646  * anymore.
6647  */
6648  Assert(!RelationSupportsSysCache(relationId));
6649  return true;
6650  }
6651  return RelationSupportsSysCache(relationId);
6652 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:1578

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 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:586
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1037
#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:513
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:5815
Definition: fmgr.h:57
uint16 amsupport
Definition: amapi.h:216
RegProcedure * rd_support
Definition: rel.h:205
Oid * rd_opcintype
Definition: rel.h:204
int16 * rd_indoption
Definition: rel.h:207
void * rd_amcache
Definition: rel.h:225
Oid rd_amhandler
Definition: rel.h:180
struct FmgrInfo * rd_supportinfo
Definition: rel.h:206
Oid * rd_indcollation
Definition: rel.h:213
Definition: c.h:651
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:658
Definition: c.h:662
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:669
@ 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 3708 of file relcache.c.

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

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