PostgreSQL Source Code  git master
relcache.c File Reference
#include "postgres.h"
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/parallel.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/tupdesc_details.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "commands/policy.h"
#include "commands/publicationcmds.h"
#include "commands/trigger.h"
#include "common/int.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rowsecurity.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relmapper.h"
#include "utils/resowner.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for relcache.c:

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

#define RELCACHE_INIT_FILEMAGIC   0x573266 /* version ID value */
 
#define RECOVER_RELATION_BUILD_MEMORY   0
 
#define MAX_EOXACT_LIST   32
 
#define EOXactListAdd(rel)
 
#define RelationCacheInsert(RELATION, replace_allowed)
 
#define RelationIdCacheLookup(ID, RELATION)
 
#define RelationCacheDelete(RELATION)
 
#define SWAPFIELD(fldtype, fldname)
 
#define INITRELCACHESIZE   400
 
#define NUM_CRITICAL_SHARED_RELS   5 /* fix if you change list above */
 
#define NUM_CRITICAL_LOCAL_RELS   4 /* fix if you change list above */
 
#define NUM_CRITICAL_LOCAL_INDEXES   7 /* fix if you change list above */
 
#define NUM_CRITICAL_SHARED_INDEXES   6 /* fix if you change list above */
 

Typedefs

typedef struct relidcacheent RelIdCacheEnt
 
typedef struct inprogressent InProgressEnt
 
typedef struct opclasscacheent OpClassCacheEnt
 

Functions

static void RelationCloseCleanup (Relation relation)
 
static void RelationDestroyRelation (Relation relation, bool remember_tupdesc)
 
static void RelationInvalidateRelation (Relation relation)
 
static void RelationClearRelation (Relation relation, bool rebuild)
 
static void RelationReloadIndexInfo (Relation relation)
 
static void RelationReloadNailed (Relation relation)
 
static void RelationFlushRelation (Relation relation)
 
static void RememberToFreeTupleDescAtEOX (TupleDesc td)
 
static void AtEOXact_cleanup (Relation relation, bool isCommit)
 
static void AtEOSubXact_cleanup (Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
static bool load_relcache_init_file (bool shared)
 
static void write_relcache_init_file (bool shared)
 
static void write_item (const void *data, Size len, FILE *fp)
 
static void formrdesc (const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
 
static HeapTuple ScanPgRelation (Oid targetRelId, bool indexOK, bool force_non_historic)
 
static Relation AllocateRelationDesc (Form_pg_class relp)
 
static void RelationParseRelOptions (Relation relation, HeapTuple tuple)
 
static void RelationBuildTupleDesc (Relation relation)
 
static Relation RelationBuildDesc (Oid targetRelId, bool insertIt)
 
static void RelationInitPhysicalAddr (Relation relation)
 
static void load_critical_index (Oid indexoid, Oid heapoid)
 
static TupleDesc GetPgClassDescriptor (void)
 
static TupleDesc GetPgIndexDescriptor (void)
 
static void AttrDefaultFetch (Relation relation, int ndef)
 
static int AttrDefaultCmp (const void *a, const void *b)
 
static void CheckConstraintFetch (Relation relation)
 
static int CheckConstraintCmp (const void *a, const void *b)
 
static void InitIndexAmRoutine (Relation relation)
 
static void IndexSupportInitialize (oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
 
static OpClassCacheEntLookupOpclassInfo (Oid operatorClassOid, StrategyNumber numSupport)
 
static void RelationCacheInitFileRemoveInDir (const char *tblspcpath)
 
static void unlink_initfile (const char *initfilename, int elevel)
 
static void RelationBuildRuleLock (Relation relation)
 
static bool equalRuleLocks (RuleLock *rlock1, RuleLock *rlock2)
 
static bool equalPolicy (RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
 
static bool equalRSDesc (RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
 
void RelationInitIndexAccessInfo (Relation relation)
 
static void InitTableAmRoutine (Relation relation)
 
void RelationInitTableAccessMethod (Relation relation)
 
Relation RelationIdGetRelation (Oid relationId)
 
static void ResOwnerReleaseRelation (Datum res)
 
static char * ResOwnerPrintRelCache (Datum res)
 
static void ResourceOwnerRememberRelationRef (ResourceOwner owner, Relation rel)
 
static void ResourceOwnerForgetRelationRef (ResourceOwner owner, Relation rel)
 
void RelationIncrementReferenceCount (Relation rel)
 
void RelationDecrementReferenceCount (Relation rel)
 
void RelationClose (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (bool debug_discard)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
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 RelationCacheInitialize (void)
 
void RelationCacheInitializePhase2 (void)
 
void RelationCacheInitializePhase3 (void)
 
static TupleDesc BuildHardcodedDescriptor (int natts, const FormData_pg_attribute *attrs)
 
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)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
BitmapsetRelationGetIdentityKeyBitmap (Relation relation)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
void RelationBuildPublicationDesc (Relation relation, PublicationDesc *pubdesc)
 
static bytea ** CopyIndexAttOptions (bytea **srcopts, int natts)
 
bytea ** RelationGetIndexAttOptions (Relation relation, bool copy)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
bool RelationIdIsInInitFile (Oid relationId)
 
void RelationCacheInitFilePreInvalidate (void)
 
void RelationCacheInitFilePostInvalidate (void)
 
void RelationCacheInitFileRemove (void)
 

Variables

static const FormData_pg_attribute Desc_pg_class [Natts_pg_class] = {Schema_pg_class}
 
static const FormData_pg_attribute Desc_pg_attribute [Natts_pg_attribute] = {Schema_pg_attribute}
 
static const FormData_pg_attribute Desc_pg_proc [Natts_pg_proc] = {Schema_pg_proc}
 
static const FormData_pg_attribute Desc_pg_type [Natts_pg_type] = {Schema_pg_type}
 
static const FormData_pg_attribute Desc_pg_database [Natts_pg_database] = {Schema_pg_database}
 
static const FormData_pg_attribute Desc_pg_authid [Natts_pg_authid] = {Schema_pg_authid}
 
static const FormData_pg_attribute Desc_pg_auth_members [Natts_pg_auth_members] = {Schema_pg_auth_members}
 
static const FormData_pg_attribute Desc_pg_index [Natts_pg_index] = {Schema_pg_index}
 
static const FormData_pg_attribute Desc_pg_shseclabel [Natts_pg_shseclabel] = {Schema_pg_shseclabel}
 
static const FormData_pg_attribute Desc_pg_subscription [Natts_pg_subscription] = {Schema_pg_subscription}
 
static HTABRelationIdCache
 
bool criticalRelcachesBuilt = false
 
bool criticalSharedRelcachesBuilt = false
 
static long relcacheInvalsReceived = 0L
 
static InProgressEntin_progress_list
 
static int in_progress_list_len
 
static int in_progress_list_maxlen
 
static Oid eoxact_list [MAX_EOXACT_LIST]
 
static int eoxact_list_len = 0
 
static bool eoxact_list_overflowed = false
 
static TupleDescEOXactTupleDescArray
 
static int NextEOXactTupleDescNum = 0
 
static int EOXactTupleDescArrayLen = 0
 
static HTABOpClassCache = NULL
 
static const ResourceOwnerDesc relref_resowner_desc
 

Macro Definition Documentation

◆ EOXactListAdd

#define EOXactListAdd (   rel)
Value:
do { \
eoxact_list[eoxact_list_len++] = (rel)->rd_id; \
else \
eoxact_list_overflowed = true; \
} while (0)
#define MAX_EOXACT_LIST
Definition: relcache.c:184
static int eoxact_list_len
Definition: relcache.c:186

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3992 of file relcache.c.

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 184 of file relcache.c.

◆ NUM_CRITICAL_LOCAL_INDEXES

#define NUM_CRITICAL_LOCAL_INDEXES   7 /* fix if you change list above */

◆ NUM_CRITICAL_LOCAL_RELS

#define NUM_CRITICAL_LOCAL_RELS   4 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_INDEXES

#define NUM_CRITICAL_SHARED_INDEXES   6 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_RELS

#define NUM_CRITICAL_SHARED_RELS   5 /* fix if you change list above */

◆ RECOVER_RELATION_BUILD_MEMORY

#define RECOVER_RELATION_BUILD_MEMORY   0

Definition at line 102 of file relcache.c.

◆ RelationCacheDelete

#define RelationCacheDelete (   RELATION)
Value:
do { \
RelIdCacheEnt *hentry; \
&((RELATION)->rd_id), \
HASH_REMOVE, NULL); \
if (hentry == NULL) \
elog(WARNING, "failed to delete relcache entry for OID %u", \
(RELATION)->rd_id); \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
#define WARNING
Definition: elog.h:36
static HTAB * RelationIdCache
Definition: relcache.c:134

Definition at line 243 of file relcache.c.

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
&((RELATION)->rd_id), \
HASH_ENTER, &found); \
if (found) \
{ \
/* see comments in RelationBuildDesc and RelationBuildLocalRelation */ \
Relation _old_rel = hentry->reldesc; \
Assert(replace_allowed); \
hentry->reldesc = (RELATION); \
RelationDestroyRelation(_old_rel, false); \
elog(WARNING, "leaking still-referenced relcache entry for \"%s\"", \
} \
else \
hentry->reldesc = (RELATION); \
} while(0)
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:489
#define RelationGetRelationName(relation)
Definition: rel.h:539

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

#define RelationIdCacheLookup (   ID,
  RELATION 
)
Value:
do { \
RelIdCacheEnt *hentry; \
&(ID), \
HASH_FIND, NULL); \
if (hentry) \
RELATION = hentry->reldesc; \
else \
RELATION = NULL; \
} while(0)

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

#define RELCACHE_INIT_FILEMAGIC   0x573266 /* version ID value */

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

#define SWAPFIELD (   fldtype,
  fldname 
)
Value:
do { \
fldtype _tmp = newrel->fldname; \
newrel->fldname = relation->fldname; \
relation->fldname = _tmp; \
} while (0)

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 409 of file relcache.c.

410 {
411  Relation relation;
412  MemoryContext oldcxt;
413  Form_pg_class relationForm;
414 
415  /* Relcache entries must live in CacheMemoryContext */
417 
418  /*
419  * allocate and zero space for new relation descriptor
420  */
421  relation = (Relation) palloc0(sizeof(RelationData));
422 
423  /* make sure relation is marked as having no open file yet */
424  relation->rd_smgr = NULL;
425 
426  /*
427  * Copy the relation tuple form
428  *
429  * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. The
430  * variable-length fields (relacl, reloptions) are NOT stored in the
431  * relcache --- there'd be little point in it, since we don't copy the
432  * tuple's nulls bitmap and hence wouldn't know if the values are valid.
433  * Bottom line is that relacl *cannot* be retrieved from the relcache. Get
434  * it from the syscache if you need it. The same goes for the original
435  * form of reloptions (however, we do store the parsed form of reloptions
436  * in rd_options).
437  */
438  relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
439 
440  memcpy(relationForm, relp, CLASS_TUPLE_SIZE);
441 
442  /* initialize relation tuple form */
443  relation->rd_rel = relationForm;
444 
445  /* and allocate attribute tuple form storage */
446  relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
447  /* which we mark as a reference-counted tupdesc */
448  relation->rd_att->tdrefcount = 1;
449 
450  MemoryContextSwitchTo(oldcxt);
451 
452  return relation;
453 }
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void * palloc(Size size)
Definition: mcxt.c:1317
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
MemoryContextSwitchTo(old_ctx)
struct RelationData * Relation
Definition: relcache.h:27
TupleDesc rd_att
Definition: rel.h:112
SMgrRelation rd_smgr
Definition: rel.h:58
Form_pg_class rd_rel
Definition: rel.h:111
int tdrefcount
Definition: tupdesc.h:84
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67

References CacheMemoryContext, CLASS_TUPLE_SIZE, CreateTemplateTupleDesc(), MemoryContextSwitchTo(), palloc(), palloc0(), RelationData::rd_att, RelationData::rd_rel, RelationData::rd_smgr, and TupleDescData::tdrefcount.

Referenced by RelationBuildDesc().

◆ AtEOSubXact_cleanup()

static void AtEOSubXact_cleanup ( Relation  relation,
bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)
static

Definition at line 3442 of file relcache.c.

3444 {
3445  /*
3446  * Is it a relation created in the current subtransaction?
3447  *
3448  * During subcommit, mark it as belonging to the parent, instead, as long
3449  * as it has not been dropped. Otherwise simply delete the relcache entry.
3450  * --- it isn't interesting any longer.
3451  */
3452  if (relation->rd_createSubid == mySubid)
3453  {
3454  /*
3455  * Valid rd_droppedSubid means the corresponding relation is dropped
3456  * but the relcache entry is preserved for at-commit pending sync. We
3457  * need to drop it explicitly here not to make the entry orphan.
3458  */
3459  Assert(relation->rd_droppedSubid == mySubid ||
3461  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3462  relation->rd_createSubid = parentSubid;
3463  else if (RelationHasReferenceCountZero(relation))
3464  {
3465  /* allow the entry to be removed */
3470  RelationClearRelation(relation, false);
3471  return;
3472  }
3473  else
3474  {
3475  /*
3476  * Hmm, somewhere there's a (leaked?) reference to the relation.
3477  * We daren't remove the entry for fear of dereferencing a
3478  * dangling pointer later. Bleat, and transfer it to the parent
3479  * subtransaction so we can try again later. This must be just a
3480  * WARNING to avoid error-during-error-recovery loops.
3481  */
3482  relation->rd_createSubid = parentSubid;
3483  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3484  RelationGetRelationName(relation));
3485  }
3486  }
3487 
3488  /*
3489  * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3490  * or drop record.
3491  */
3492  if (relation->rd_newRelfilelocatorSubid == mySubid)
3493  {
3494  if (isCommit)
3495  relation->rd_newRelfilelocatorSubid = parentSubid;
3496  else
3498  }
3499 
3500  if (relation->rd_firstRelfilelocatorSubid == mySubid)
3501  {
3502  if (isCommit)
3503  relation->rd_firstRelfilelocatorSubid = parentSubid;
3504  else
3506  }
3507 
3508  if (relation->rd_droppedSubid == mySubid)
3509  {
3510  if (isCommit)
3511  relation->rd_droppedSubid = parentSubid;
3512  else
3514  }
3515 }
#define InvalidSubTransactionId
Definition: c.h:649
#define Assert(condition)
Definition: c.h:849
#define elog(elevel,...)
Definition: elog.h:225
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2559
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_droppedSubid
Definition: rel.h:109

References Assert, elog, InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_newRelfilelocatorSubid, RelationClearRelation(), RelationGetRelationName, RelationHasReferenceCountZero, and WARNING.

Referenced by AtEOSubXact_RelationCache().

◆ AtEOSubXact_RelationCache()

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

Definition at line 3387 of file relcache.c.

3389 {
3390  HASH_SEQ_STATUS status;
3391  RelIdCacheEnt *idhentry;
3392  int i;
3393 
3394  /*
3395  * Forget in_progress_list. This is relevant when we're aborting due to
3396  * an error during RelationBuildDesc(). We don't commit subtransactions
3397  * during RelationBuildDesc().
3398  */
3399  Assert(in_progress_list_len == 0 || !isCommit);
3401 
3402  /*
3403  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3404  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3405  * logic as in AtEOXact_RelationCache.
3406  */
3408  {
3409  hash_seq_init(&status, RelationIdCache);
3410  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3411  {
3412  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3413  mySubid, parentSubid);
3414  }
3415  }
3416  else
3417  {
3418  for (i = 0; i < eoxact_list_len; i++)
3419  {
3420  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3421  &eoxact_list[i],
3422  HASH_FIND,
3423  NULL);
3424  if (idhentry != NULL)
3425  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3426  mySubid, parentSubid);
3427  }
3428  }
3429 
3430  /* Don't reset the list; we still need more cleanup later */
3431 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3442
static bool eoxact_list_overflowed
Definition: relcache.c:187
Relation reldesc
Definition: relcache.c:131

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3305 of file relcache.c.

3306 {
3307  bool clear_relcache = false;
3308 
3309  /*
3310  * The relcache entry's ref count should be back to its normal
3311  * not-in-a-transaction state: 0 unless it's nailed in cache.
3312  *
3313  * In bootstrap mode, this is NOT true, so don't check it --- the
3314  * bootstrap code expects relations to stay open across start/commit
3315  * transaction calls. (That seems bogus, but it's not worth fixing.)
3316  *
3317  * Note: ideally this check would be applied to every relcache entry, not
3318  * just those that have eoxact work to do. But it's not worth forcing a
3319  * scan of the whole relcache just for this. (Moreover, doing so would
3320  * mean that assert-enabled testing never tests the hash_search code path
3321  * above, which seems a bad idea.)
3322  */
3323 #ifdef USE_ASSERT_CHECKING
3325  {
3326  int expected_refcnt;
3327 
3328  expected_refcnt = relation->rd_isnailed ? 1 : 0;
3329  Assert(relation->rd_refcnt == expected_refcnt);
3330  }
3331 #endif
3332 
3333  /*
3334  * Is the relation live after this transaction ends?
3335  *
3336  * During commit, clear the relcache entry if it is preserved after
3337  * relation drop, in order not to orphan the entry. During rollback,
3338  * clear the relcache entry if the relation is created in the current
3339  * transaction since it isn't interesting any longer once we are out of
3340  * the transaction.
3341  */
3342  clear_relcache =
3343  (isCommit ?
3346 
3347  /*
3348  * Since we are now out of the transaction, reset the subids to zero. That
3349  * also lets RelationClearRelation() drop the relcache entry.
3350  */
3355 
3356  if (clear_relcache)
3357  {
3358  if (RelationHasReferenceCountZero(relation))
3359  {
3360  RelationClearRelation(relation, false);
3361  return;
3362  }
3363  else
3364  {
3365  /*
3366  * Hmm, somewhere there's a (leaked?) reference to the relation.
3367  * We daren't remove the entry for fear of dereferencing a
3368  * dangling pointer later. Bleat, and mark it as not belonging to
3369  * the current transaction. Hopefully it'll get cleaned up
3370  * eventually. This must be just a WARNING to avoid
3371  * error-during-error-recovery loops.
3372  */
3373  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3374  RelationGetRelationName(relation));
3375  }
3376  }
3377 }
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62

References Assert, elog, InvalidSubTransactionId, IsBootstrapProcessingMode, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationClearRelation(), RelationGetRelationName, RelationHasReferenceCountZero, and WARNING.

Referenced by AtEOXact_RelationCache().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3235 of file relcache.c.

3236 {
3237  HASH_SEQ_STATUS status;
3238  RelIdCacheEnt *idhentry;
3239  int i;
3240 
3241  /*
3242  * Forget in_progress_list. This is relevant when we're aborting due to
3243  * an error during RelationBuildDesc().
3244  */
3245  Assert(in_progress_list_len == 0 || !isCommit);
3247 
3248  /*
3249  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3250  * listed in it. Otherwise fall back on a hash_seq_search scan.
3251  *
3252  * For simplicity, eoxact_list[] entries are not deleted till end of
3253  * top-level transaction, even though we could remove them at
3254  * subtransaction end in some cases, or remove relations from the list if
3255  * they are cleared for other reasons. Therefore we should expect the
3256  * case that list entries are not found in the hashtable; if not, there's
3257  * nothing to do for them.
3258  */
3260  {
3261  hash_seq_init(&status, RelationIdCache);
3262  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3263  {
3264  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3265  }
3266  }
3267  else
3268  {
3269  for (i = 0; i < eoxact_list_len; i++)
3270  {
3271  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3272  &eoxact_list[i],
3273  HASH_FIND,
3274  NULL);
3275  if (idhentry != NULL)
3276  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3277  }
3278  }
3279 
3280  if (EOXactTupleDescArrayLen > 0)
3281  {
3282  Assert(EOXactTupleDescArray != NULL);
3283  for (i = 0; i < NextEOXactTupleDescNum; i++)
3286  EOXactTupleDescArray = NULL;
3287  }
3288 
3289  /* Now we're out of the transaction and can clear the lists */
3290  eoxact_list_len = 0;
3291  eoxact_list_overflowed = false;
3294 }
void pfree(void *pointer)
Definition: mcxt.c:1521
static int NextEOXactTupleDescNum
Definition: relcache.c:203
static int EOXactTupleDescArrayLen
Definition: relcache.c:204
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3305
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331

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

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

◆ AttrDefaultCmp()

static int AttrDefaultCmp ( const void *  a,
const void *  b 
)
static

Definition at line 4568 of file relcache.c.

4569 {
4570  const AttrDefault *ada = (const AttrDefault *) a;
4571  const AttrDefault *adb = (const AttrDefault *) b;
4572 
4573  return pg_cmp_s16(ada->adnum, adb->adnum);
4574 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:586
int b
Definition: isn.c:70
int a
Definition: isn.c:69
AttrNumber adnum
Definition: tupdesc.h:24

References a, AttrDefault::adnum, b, and pg_cmp_s16().

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4488 of file relcache.c.

4489 {
4490  AttrDefault *attrdef;
4491  Relation adrel;
4492  SysScanDesc adscan;
4493  ScanKeyData skey;
4494  HeapTuple htup;
4495  int found = 0;
4496 
4497  /* Allocate array with room for as many entries as expected */
4498  attrdef = (AttrDefault *)
4500  ndef * sizeof(AttrDefault));
4501 
4502  /* Search pg_attrdef for relevant entries */
4503  ScanKeyInit(&skey,
4504  Anum_pg_attrdef_adrelid,
4505  BTEqualStrategyNumber, F_OIDEQ,
4506  ObjectIdGetDatum(RelationGetRelid(relation)));
4507 
4508  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4509  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4510  NULL, 1, &skey);
4511 
4512  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4513  {
4514  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4515  Datum val;
4516  bool isnull;
4517 
4518  /* protect limited size of array */
4519  if (found >= ndef)
4520  {
4521  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4522  adform->adnum, RelationGetRelationName(relation));
4523  break;
4524  }
4525 
4526  val = fastgetattr(htup,
4527  Anum_pg_attrdef_adbin,
4528  adrel->rd_att, &isnull);
4529  if (isnull)
4530  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4531  adform->adnum, RelationGetRelationName(relation));
4532  else
4533  {
4534  /* detoast and convert to cstring in caller's context */
4535  char *s = TextDatumGetCString(val);
4536 
4537  attrdef[found].adnum = adform->adnum;
4538  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4539  pfree(s);
4540  found++;
4541  }
4542  }
4543 
4544  systable_endscan(adscan);
4545  table_close(adrel, AccessShareLock);
4546 
4547  if (found != ndef)
4548  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4549  ndef - found, RelationGetRelationName(relation));
4550 
4551  /*
4552  * Sort the AttrDefault entries by adnum, for the convenience of
4553  * equalTupleDescs(). (Usually, they already will be in order, but this
4554  * might not be so if systable_getnext isn't using an index.)
4555  */
4556  if (found > 1)
4557  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4558 
4559  /* Install array only after it's fully valid */
4560  relation->rd_att->constr->defval = attrdef;
4561  relation->rd_att->constr->num_defval = found;
4562 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:447
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetRelid(relation)
Definition: rel.h:505
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4568
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char * adbin
Definition: tupdesc.h:25
AttrDefault * defval
Definition: tupdesc.h:39
uint16 num_defval
Definition: tupdesc.h:42
TupleConstr * constr
Definition: tupdesc.h:85
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, AttrDefault::adbin, AttrDefault::adnum, AttrDefaultCmp(), BTEqualStrategyNumber, CacheMemoryContext, TupleDescData::constr, TupleConstr::defval, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), TupleConstr::num_defval, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ BuildHardcodedDescriptor()

static TupleDesc BuildHardcodedDescriptor ( int  natts,
const FormData_pg_attribute attrs 
)
static

Definition at line 4423 of file relcache.c.

4424 {
4425  TupleDesc result;
4426  MemoryContext oldcxt;
4427  int i;
4428 
4430 
4431  result = CreateTemplateTupleDesc(natts);
4432  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4433  result->tdtypmod = -1;
4434 
4435  for (i = 0; i < natts; i++)
4436  {
4437  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4438  /* make sure attcacheoff is valid */
4439  TupleDescAttr(result, i)->attcacheoff = -1;
4440  }
4441 
4442  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4443  TupleDescAttr(result, 0)->attcacheoff = 0;
4444 
4445  /* Note: we don't bother to set up a TupleConstr entry */
4446 
4447  MemoryContextSwitchTo(oldcxt);
4448 
4449  return result;
4450 }
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:201
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References ATTRIBUTE_FIXED_PART_SIZE, CacheMemoryContext, CreateTemplateTupleDesc(), i, MemoryContextSwitchTo(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

◆ CheckConstraintCmp()

static int CheckConstraintCmp ( const void *  a,
const void *  b 
)
static

Definition at line 4672 of file relcache.c.

4673 {
4674  const ConstrCheck *ca = (const ConstrCheck *) a;
4675  const ConstrCheck *cb = (const ConstrCheck *) b;
4676 
4677  return strcmp(ca->ccname, cb->ccname);
4678 }
char * ccname
Definition: tupdesc.h:30

References a, b, and ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4583 of file relcache.c.

4584 {
4585  ConstrCheck *check;
4586  int ncheck = relation->rd_rel->relchecks;
4587  Relation conrel;
4588  SysScanDesc conscan;
4589  ScanKeyData skey[1];
4590  HeapTuple htup;
4591  int found = 0;
4592 
4593  /* Allocate array with room for as many entries as expected */
4594  check = (ConstrCheck *)
4596  ncheck * sizeof(ConstrCheck));
4597 
4598  /* Search pg_constraint for relevant entries */
4599  ScanKeyInit(&skey[0],
4600  Anum_pg_constraint_conrelid,
4601  BTEqualStrategyNumber, F_OIDEQ,
4602  ObjectIdGetDatum(RelationGetRelid(relation)));
4603 
4604  conrel = table_open(ConstraintRelationId, AccessShareLock);
4605  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4606  NULL, 1, skey);
4607 
4608  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4609  {
4611  Datum val;
4612  bool isnull;
4613 
4614  /* We want check constraints only */
4615  if (conform->contype != CONSTRAINT_CHECK)
4616  continue;
4617 
4618  /* protect limited size of array */
4619  if (found >= ncheck)
4620  {
4621  elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4622  RelationGetRelationName(relation));
4623  break;
4624  }
4625 
4626  check[found].ccvalid = conform->convalidated;
4627  check[found].ccnoinherit = conform->connoinherit;
4629  NameStr(conform->conname));
4630 
4631  /* Grab and test conbin is actually set */
4632  val = fastgetattr(htup,
4633  Anum_pg_constraint_conbin,
4634  conrel->rd_att, &isnull);
4635  if (isnull)
4636  elog(WARNING, "null conbin for relation \"%s\"",
4637  RelationGetRelationName(relation));
4638  else
4639  {
4640  /* detoast and convert to cstring in caller's context */
4641  char *s = TextDatumGetCString(val);
4642 
4643  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4644  pfree(s);
4645  found++;
4646  }
4647  }
4648 
4649  systable_endscan(conscan);
4650  table_close(conrel, AccessShareLock);
4651 
4652  if (found != ncheck)
4653  elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4654  ncheck - found, RelationGetRelationName(relation));
4655 
4656  /*
4657  * Sort the records by name. This ensures that CHECKs are applied in a
4658  * deterministic order, and it also makes equalTupleDescs() faster.
4659  */
4660  if (found > 1)
4661  qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4662 
4663  /* Install array only after it's fully valid */
4664  relation->rd_att->constr->check = check;
4665  relation->rd_att->constr->num_check = found;
4666 }
#define NameStr(name)
Definition: c.h:737
FormData_pg_constraint * Form_pg_constraint
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4672
bool ccnoinherit
Definition: tupdesc.h:33
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_check
Definition: tupdesc.h:43

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ConstrCheck::ccbin, ConstrCheck::ccname, ConstrCheck::ccnoinherit, ConstrCheck::ccvalid, TupleConstr::check, CheckConstraintCmp(), TupleDescData::constr, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), NameStr, TupleConstr::num_check, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ CopyIndexAttOptions()

static bytea** CopyIndexAttOptions ( bytea **  srcopts,
int  natts 
)
static

Definition at line 5880 of file relcache.c.

5881 {
5882  bytea **opts = palloc(sizeof(*opts) * natts);
5883 
5884  for (int i = 0; i < natts; i++)
5885  {
5886  bytea *opt = srcopts[i];
5887 
5888  opts[i] = !opt ? NULL : (bytea *)
5889  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5890  }
5891 
5892  return opts;
5893 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
static AmcheckOptions opts
Definition: pg_amcheck.c:111
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
Definition: c.h:678

References datumCopy(), DatumGetPointer(), i, opts, palloc(), and PointerGetDatum().

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 951 of file relcache.c.

952 {
953  int i;
954  Oid *r1,
955  *r2;
956 
957  if (policy1 != NULL)
958  {
959  if (policy2 == NULL)
960  return false;
961 
962  if (policy1->polcmd != policy2->polcmd)
963  return false;
964  if (policy1->hassublinks != policy2->hassublinks)
965  return false;
966  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
967  return false;
968  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
969  return false;
970 
971  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
972  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
973 
974  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
975  {
976  if (r1[i] != r2[i])
977  return false;
978  }
979 
980  if (!equal(policy1->qual, policy2->qual))
981  return false;
982  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
983  return false;
984  }
985  else if (policy2 != NULL)
986  return false;
987 
988  return true;
989 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_DIMS(a)
Definition: array.h:294
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
unsigned int Oid
Definition: postgres_ext.h:31
ArrayType * roles
Definition: rowsecurity.h:24
Expr * with_check_qual
Definition: rowsecurity.h:27

References ARR_DATA_PTR, ARR_DIMS, equal(), RowSecurityPolicy::hassublinks, i, RowSecurityPolicy::polcmd, RowSecurityPolicy::policy_name, RowSecurityPolicy::qual, RowSecurityPolicy::roles, and RowSecurityPolicy::with_check_qual.

Referenced by equalRSDesc().

◆ equalRSDesc()

static bool equalRSDesc ( RowSecurityDesc rsdesc1,
RowSecurityDesc rsdesc2 
)
static

Definition at line 997 of file relcache.c.

998 {
999  ListCell *lc,
1000  *rc;
1001 
1002  if (rsdesc1 == NULL && rsdesc2 == NULL)
1003  return true;
1004 
1005  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1006  (rsdesc1 == NULL && rsdesc2 != NULL))
1007  return false;
1008 
1009  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1010  return false;
1011 
1012  /* RelationBuildRowSecurity should build policies in order */
1013  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1014  {
1017 
1018  if (!equalPolicy(l, r))
1019  return false;
1020  }
1021 
1022  return true;
1023 }
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:951

References equalPolicy(), forboth, lfirst, list_length(), and RowSecurityDesc::policies.

Referenced by RelationClearRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 906 of file relcache.c.

907 {
908  int i;
909 
910  /*
911  * As of 7.3 we assume the rule ordering is repeatable, because
912  * RelationBuildRuleLock should read 'em in a consistent order. So just
913  * compare corresponding slots.
914  */
915  if (rlock1 != NULL)
916  {
917  if (rlock2 == NULL)
918  return false;
919  if (rlock1->numLocks != rlock2->numLocks)
920  return false;
921  for (i = 0; i < rlock1->numLocks; i++)
922  {
923  RewriteRule *rule1 = rlock1->rules[i];
924  RewriteRule *rule2 = rlock2->rules[i];
925 
926  if (rule1->ruleId != rule2->ruleId)
927  return false;
928  if (rule1->event != rule2->event)
929  return false;
930  if (rule1->enabled != rule2->enabled)
931  return false;
932  if (rule1->isInstead != rule2->isInstead)
933  return false;
934  if (!equal(rule1->qual, rule2->qual))
935  return false;
936  if (!equal(rule1->actions, rule2->actions))
937  return false;
938  }
939  }
940  else if (rlock2 != NULL)
941  return false;
942  return true;
943 }
Oid ruleId
Definition: prs2lock.h:26
CmdType event
Definition: prs2lock.h:27
List * actions
Definition: prs2lock.h:29
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28
char enabled
Definition: prs2lock.h:30
RewriteRule ** rules
Definition: prs2lock.h:43
int numLocks
Definition: prs2lock.h:42

References RewriteRule::actions, RewriteRule::enabled, equal(), RewriteRule::event, i, RewriteRule::isInstead, RuleLock::numLocks, RewriteRule::qual, RewriteRule::ruleId, and RuleLock::rules.

Referenced by RelationClearRelation().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5961 of file relcache.c.

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

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5978 of file relcache.c.

5979 {
5980  TupleDesc reldesc = RelationGetDescr(rel);
5981  const char *colname;
5982 
5983  /* Use reldesc if it's a user attribute, else consult the catalogs */
5984  if (attnum > 0 && attnum <= reldesc->natts)
5985  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5986  else
5987  colname = get_attname(RelationGetRelid(rel), attnum, false);
5988 
5989  return errtablecolname(rel, colname);
5990 }
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetDescr(relation)
Definition: rel.h:531
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:6002

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 6002 of file relcache.c.

6003 {
6004  errtable(rel);
6006 
6007  return 0; /* return value does not matter */
6008 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5961

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ formrdesc()

static void formrdesc ( const char *  relationName,
Oid  relationReltype,
bool  isshared,
int  natts,
const FormData_pg_attribute attrs 
)
static

Definition at line 1873 of file relcache.c.

1876 {
1877  Relation relation;
1878  int i;
1879  bool has_not_null;
1880 
1881  /*
1882  * allocate new relation desc, clear all fields of reldesc
1883  */
1884  relation = (Relation) palloc0(sizeof(RelationData));
1885 
1886  /* make sure relation is marked as having no open file yet */
1887  relation->rd_smgr = NULL;
1888 
1889  /*
1890  * initialize reference count: 1 because it is nailed in cache
1891  */
1892  relation->rd_refcnt = 1;
1893 
1894  /*
1895  * all entries built with this routine are nailed-in-cache; none are for
1896  * new or temp relations.
1897  */
1898  relation->rd_isnailed = true;
1903  relation->rd_backend = INVALID_PROC_NUMBER;
1904  relation->rd_islocaltemp = false;
1905 
1906  /*
1907  * initialize relation tuple form
1908  *
1909  * The data we insert here is pretty incomplete/bogus, but it'll serve to
1910  * get us launched. RelationCacheInitializePhase3() will read the real
1911  * data from pg_class and replace what we've done here. Note in
1912  * particular that relowner is left as zero; this cues
1913  * RelationCacheInitializePhase3 that the real data isn't there yet.
1914  */
1916 
1917  namestrcpy(&relation->rd_rel->relname, relationName);
1918  relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1919  relation->rd_rel->reltype = relationReltype;
1920 
1921  /*
1922  * It's important to distinguish between shared and non-shared relations,
1923  * even at bootstrap time, to make sure we know where they are stored.
1924  */
1925  relation->rd_rel->relisshared = isshared;
1926  if (isshared)
1927  relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1928 
1929  /* formrdesc is used only for permanent relations */
1930  relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1931 
1932  /* ... and they're always populated, too */
1933  relation->rd_rel->relispopulated = true;
1934 
1935  relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1936  relation->rd_rel->relpages = 0;
1937  relation->rd_rel->reltuples = -1;
1938  relation->rd_rel->relallvisible = 0;
1939  relation->rd_rel->relkind = RELKIND_RELATION;
1940  relation->rd_rel->relnatts = (int16) natts;
1941  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
1942 
1943  /*
1944  * initialize attribute tuple form
1945  *
1946  * Unlike the case with the relation tuple, this data had better be right
1947  * because it will never be replaced. The data comes from
1948  * src/include/catalog/ headers via genbki.pl.
1949  */
1950  relation->rd_att = CreateTemplateTupleDesc(natts);
1951  relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1952 
1953  relation->rd_att->tdtypeid = relationReltype;
1954  relation->rd_att->tdtypmod = -1; /* just to be sure */
1955 
1956  /*
1957  * initialize tuple desc info
1958  */
1959  has_not_null = false;
1960  for (i = 0; i < natts; i++)
1961  {
1962  memcpy(TupleDescAttr(relation->rd_att, i),
1963  &attrs[i],
1965  has_not_null |= attrs[i].attnotnull;
1966  /* make sure attcacheoff is valid */
1967  TupleDescAttr(relation->rd_att, i)->attcacheoff = -1;
1968  }
1969 
1970  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
1971  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
1972 
1973  /* mark not-null status */
1974  if (has_not_null)
1975  {
1976  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1977 
1978  constr->has_not_null = true;
1979  relation->rd_att->constr = constr;
1980  }
1981 
1982  /*
1983  * initialize relation id from info in att array (my, this is ugly)
1984  */
1985  RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
1986 
1987  /*
1988  * All relations made with formrdesc are mapped. This is necessarily so
1989  * because there is no other way to know what filenumber they currently
1990  * have. In bootstrap mode, add them to the initial relation mapper data,
1991  * specifying that the initial filenumber is the same as the OID.
1992  */
1993  relation->rd_rel->relfilenode = InvalidRelFileNumber;
1996  RelationGetRelid(relation),
1997  isshared, true);
1998 
1999  /*
2000  * initialize the relation lock manager information
2001  */
2002  RelationInitLockInfo(relation); /* see lmgr.c */
2003 
2004  /*
2005  * initialize physical addressing information for the relation
2006  */
2007  RelationInitPhysicalAddr(relation);
2008 
2009  /*
2010  * initialize the table am handler
2011  */
2012  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
2013  relation->rd_tableam = GetHeapamTableAmRoutine();
2014 
2015  /*
2016  * initialize the rel-has-index flag, using hardwired knowledge
2017  */
2019  {
2020  /* In bootstrap mode, we have no indexes */
2021  relation->rd_rel->relhasindex = false;
2022  }
2023  else
2024  {
2025  /* Otherwise, all the rels formrdesc is used for have indexes */
2026  relation->rd_rel->relhasindex = true;
2027  }
2028 
2029  /*
2030  * add new reldesc to relcache
2031  */
2032  RelationCacheInsert(relation, false);
2033 
2034  /* It's fully valid */
2035  relation->rd_isvalid = true;
2036 }
signed short int16
Definition: c.h:495
const TableAmRoutine * GetHeapamTableAmRoutine(void)
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:209
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1318
void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared, bool immediate)
Definition: relmapper.c:325
#define InvalidRelFileNumber
Definition: relpath.h:26
ProcNumber rd_backend
Definition: rel.h:60
const struct TableAmRoutine * rd_tableam
Definition: rel.h:189
bool rd_isvalid
Definition: rel.h:63
bool rd_islocaltemp
Definition: rel.h:61
bool has_not_null
Definition: tupdesc.h:44

References ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateTemplateTupleDesc(), GetHeapamTableAmRoutine(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidRelFileNumber, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), 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, RelationData::rd_tableam, RelationCacheInsert, RelationGetRelid, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4453 of file relcache.c.

4454 {
4455  static TupleDesc pgclassdesc = NULL;
4456 
4457  /* Already done? */
4458  if (pgclassdesc == NULL)
4459  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4460  Desc_pg_class);
4461 
4462  return pgclassdesc;
4463 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4423
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4466 of file relcache.c.

4467 {
4468  static TupleDesc pgindexdesc = NULL;
4469 
4470  /* Already done? */
4471  if (pgindexdesc == NULL)
4472  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4473  Desc_pg_index);
4474 
4475  return pgindexdesc;
4476 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:118

References BuildHardcodedDescriptor(), and Desc_pg_index.

Referenced by RelationGetDummyIndexExpressions(), RelationGetIndexAttrBitmap(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), and RelationInitIndexAccessInfo().

◆ IndexSupportInitialize()

static void IndexSupportInitialize ( oidvector indclass,
RegProcedure indexSupport,
Oid opFamily,
Oid opcInType,
StrategyNumber  maxSupportNumber,
AttrNumber  maxAttributeNumber 
)
static

Definition at line 1595 of file relcache.c.

1601 {
1602  int attIndex;
1603 
1604  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1605  {
1606  OpClassCacheEnt *opcentry;
1607 
1608  if (!OidIsValid(indclass->values[attIndex]))
1609  elog(ERROR, "bogus pg_index tuple");
1610 
1611  /* look up the info for this opclass, using a cache */
1612  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1613  maxSupportNumber);
1614 
1615  /* copy cached data into relcache entry */
1616  opFamily[attIndex] = opcentry->opcfamily;
1617  opcInType[attIndex] = opcentry->opcintype;
1618  if (maxSupportNumber > 0)
1619  memcpy(&indexSupport[attIndex * maxSupportNumber],
1620  opcentry->supportProcs,
1621  maxSupportNumber * sizeof(RegProcedure));
1622  }
1623 }
regproc RegProcedure
Definition: c.h:641
#define OidIsValid(objectId)
Definition: c.h:766
#define ERROR
Definition: elog.h:39
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1646
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:724
RegProcedure * supportProcs
Definition: relcache.c:268

References elog, ERROR, LookupOpclassInfo(), OidIsValid, opclasscacheent::opcfamily, opclasscacheent::opcintype, opclasscacheent::supportProcs, and oidvector::values.

Referenced by RelationInitIndexAccessInfo().

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1400 of file relcache.c.

1401 {
1402  IndexAmRoutine *cached,
1403  *tmp;
1404 
1405  /*
1406  * Call the amhandler in current, short-lived memory context, just in case
1407  * it leaks anything (it probably won't, but let's be paranoid).
1408  */
1409  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1410 
1411  /* OK, now transfer the data into relation's rd_indexcxt. */
1412  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1413  sizeof(IndexAmRoutine));
1414  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1415  relation->rd_indam = cached;
1416 
1417  pfree(tmp);
1418 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
Oid rd_amhandler
Definition: rel.h:184
MemoryContext rd_indexcxt
Definition: rel.h:204

References GetIndexAmRoutine(), MemoryContextAlloc(), pfree(), RelationData::rd_amhandler, RelationData::rd_indam, and RelationData::rd_indexcxt.

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1799 of file relcache.c.

1800 {
1801  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1802 }
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:28

References GetTableAmRoutine(), RelationData::rd_amhandler, and RelationData::rd_tableam.

Referenced by RelationInitTableAccessMethod().

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 4385 of file relcache.c.

4386 {
4387  Relation ird;
4388 
4389  /*
4390  * We must lock the underlying catalog before locking the index to avoid
4391  * deadlock, since RelationBuildDesc might well need to read the catalog,
4392  * and if anyone else is exclusive-locking this catalog and index they'll
4393  * be doing it in that order.
4394  */
4395  LockRelationOid(heapoid, AccessShareLock);
4396  LockRelationOid(indexoid, AccessShareLock);
4397  ird = RelationBuildDesc(indexoid, true);
4398  if (ird == NULL)
4399  ereport(PANIC,
4401  errmsg_internal("could not open critical system index %u", indexoid));
4402  ird->rd_isnailed = true;
4403  ird->rd_refcnt = 1;
4406 
4407  (void) RelationGetIndexAttOptions(ird, false);
4408 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode(int sqlerrcode)
Definition: elog.c:853
#define PANIC
Definition: elog.h:42
#define ereport(elevel,...)
Definition: elog.h:149
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1038
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5900

References AccessShareLock, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), LockRelationOid(), PANIC, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationBuildDesc(), RelationGetIndexAttOptions(), and UnlockRelationOid().

Referenced by RelationCacheInitializePhase3().

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 6079 of file relcache.c.

6080 {
6081  FILE *fp;
6082  char initfilename[MAXPGPATH];
6083  Relation *rels;
6084  int relno,
6085  num_rels,
6086  max_rels,
6087  nailed_rels,
6088  nailed_indexes,
6089  magic;
6090  int i;
6091 
6092  if (shared)
6093  snprintf(initfilename, sizeof(initfilename), "global/%s",
6095  else
6096  snprintf(initfilename, sizeof(initfilename), "%s/%s",
6098 
6099  fp = AllocateFile(initfilename, PG_BINARY_R);
6100  if (fp == NULL)
6101  return false;
6102 
6103  /*
6104  * Read the index relcache entries from the file. Note we will not enter
6105  * any of them into the cache if the read fails partway through; this
6106  * helps to guard against broken init files.
6107  */
6108  max_rels = 100;
6109  rels = (Relation *) palloc(max_rels * sizeof(Relation));
6110  num_rels = 0;
6111  nailed_rels = nailed_indexes = 0;
6112 
6113  /* check for correct magic number (compatible version) */
6114  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6115  goto read_failed;
6116  if (magic != RELCACHE_INIT_FILEMAGIC)
6117  goto read_failed;
6118 
6119  for (relno = 0;; relno++)
6120  {
6121  Size len;
6122  size_t nread;
6123  Relation rel;
6124  Form_pg_class relform;
6125  bool has_not_null;
6126 
6127  /* first read the relation descriptor length */
6128  nread = fread(&len, 1, sizeof(len), fp);
6129  if (nread != sizeof(len))
6130  {
6131  if (nread == 0)
6132  break; /* end of file */
6133  goto read_failed;
6134  }
6135 
6136  /* safety check for incompatible relcache layout */
6137  if (len != sizeof(RelationData))
6138  goto read_failed;
6139 
6140  /* allocate another relcache header */
6141  if (num_rels >= max_rels)
6142  {
6143  max_rels *= 2;
6144  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
6145  }
6146 
6147  rel = rels[num_rels++] = (Relation) palloc(len);
6148 
6149  /* then, read the Relation structure */
6150  if (fread(rel, 1, len, fp) != len)
6151  goto read_failed;
6152 
6153  /* next read the relation tuple form */
6154  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6155  goto read_failed;
6156 
6157  relform = (Form_pg_class) palloc(len);
6158  if (fread(relform, 1, len, fp) != len)
6159  goto read_failed;
6160 
6161  rel->rd_rel = relform;
6162 
6163  /* initialize attribute tuple forms */
6164  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
6165  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
6166 
6167  rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
6168  rel->rd_att->tdtypmod = -1; /* just to be sure */
6169 
6170  /* next read all the attribute tuple form data entries */
6171  has_not_null = false;
6172  for (i = 0; i < relform->relnatts; i++)
6173  {
6174  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
6175 
6176  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6177  goto read_failed;
6179  goto read_failed;
6180  if (fread(attr, 1, len, fp) != len)
6181  goto read_failed;
6182 
6183  has_not_null |= attr->attnotnull;
6184  }
6185 
6186  /* next read the access method specific field */
6187  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6188  goto read_failed;
6189  if (len > 0)
6190  {
6191  rel->rd_options = palloc(len);
6192  if (fread(rel->rd_options, 1, len, fp) != len)
6193  goto read_failed;
6194  if (len != VARSIZE(rel->rd_options))
6195  goto read_failed; /* sanity check */
6196  }
6197  else
6198  {
6199  rel->rd_options = NULL;
6200  }
6201 
6202  /* mark not-null status */
6203  if (has_not_null)
6204  {
6205  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
6206 
6207  constr->has_not_null = true;
6208  rel->rd_att->constr = constr;
6209  }
6210 
6211  /*
6212  * If it's an index, there's more to do. Note we explicitly ignore
6213  * partitioned indexes here.
6214  */
6215  if (rel->rd_rel->relkind == RELKIND_INDEX)
6216  {
6217  MemoryContext indexcxt;
6218  Oid *opfamily;
6219  Oid *opcintype;
6220  RegProcedure *support;
6221  int nsupport;
6222  int16 *indoption;
6223  Oid *indcollation;
6224 
6225  /* Count nailed indexes to ensure we have 'em all */
6226  if (rel->rd_isnailed)
6227  nailed_indexes++;
6228 
6229  /* read the pg_index tuple */
6230  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6231  goto read_failed;
6232 
6233  rel->rd_indextuple = (HeapTuple) palloc(len);
6234  if (fread(rel->rd_indextuple, 1, len, fp) != len)
6235  goto read_failed;
6236 
6237  /* Fix up internal pointers in the tuple -- see heap_copytuple */
6238  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
6240 
6241  /*
6242  * prepare index info context --- parameters should match
6243  * RelationInitIndexAccessInfo
6244  */
6246  "index info",
6248  rel->rd_indexcxt = indexcxt;
6251 
6252  /*
6253  * Now we can fetch the index AM's API struct. (We can't store
6254  * that in the init file, since it contains function pointers that
6255  * might vary across server executions. Fortunately, it should be
6256  * safe to call the amhandler even while bootstrapping indexes.)
6257  */
6258  InitIndexAmRoutine(rel);
6259 
6260  /* read the vector of opfamily OIDs */
6261  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6262  goto read_failed;
6263 
6264  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
6265  if (fread(opfamily, 1, len, fp) != len)
6266  goto read_failed;
6267 
6268  rel->rd_opfamily = opfamily;
6269 
6270  /* read the vector of opcintype OIDs */
6271  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6272  goto read_failed;
6273 
6274  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
6275  if (fread(opcintype, 1, len, fp) != len)
6276  goto read_failed;
6277 
6278  rel->rd_opcintype = opcintype;
6279 
6280  /* read the vector of support procedure OIDs */
6281  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6282  goto read_failed;
6283  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
6284  if (fread(support, 1, len, fp) != len)
6285  goto read_failed;
6286 
6287  rel->rd_support = support;
6288 
6289  /* read the vector of collation OIDs */
6290  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6291  goto read_failed;
6292 
6293  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
6294  if (fread(indcollation, 1, len, fp) != len)
6295  goto read_failed;
6296 
6297  rel->rd_indcollation = indcollation;
6298 
6299  /* read the vector of indoption values */
6300  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6301  goto read_failed;
6302 
6303  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
6304  if (fread(indoption, 1, len, fp) != len)
6305  goto read_failed;
6306 
6307  rel->rd_indoption = indoption;
6308 
6309  /* read the vector of opcoptions values */
6310  rel->rd_opcoptions = (bytea **)
6311  MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
6312 
6313  for (i = 0; i < relform->relnatts; i++)
6314  {
6315  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6316  goto read_failed;
6317 
6318  if (len > 0)
6319  {
6320  rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
6321  if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
6322  goto read_failed;
6323  }
6324  }
6325 
6326  /* set up zeroed fmgr-info vector */
6327  nsupport = relform->relnatts * rel->rd_indam->amsupport;
6328  rel->rd_supportinfo = (FmgrInfo *)
6329  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
6330  }
6331  else
6332  {
6333  /* Count nailed rels to ensure we have 'em all */
6334  if (rel->rd_isnailed)
6335  nailed_rels++;
6336 
6337  /* Load table AM data */
6338  if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
6340 
6341  Assert(rel->rd_index == NULL);
6342  Assert(rel->rd_indextuple == NULL);
6343  Assert(rel->rd_indexcxt == NULL);
6344  Assert(rel->rd_indam == NULL);
6345  Assert(rel->rd_opfamily == NULL);
6346  Assert(rel->rd_opcintype == NULL);
6347  Assert(rel->rd_support == NULL);
6348  Assert(rel->rd_supportinfo == NULL);
6349  Assert(rel->rd_indoption == NULL);
6350  Assert(rel->rd_indcollation == NULL);
6351  Assert(rel->rd_opcoptions == NULL);
6352  }
6353 
6354  /*
6355  * Rules and triggers are not saved (mainly because the internal
6356  * format is complex and subject to change). They must be rebuilt if
6357  * needed by RelationCacheInitializePhase3. This is not expected to
6358  * be a big performance hit since few system catalogs have such. Ditto
6359  * for RLS policy data, partition info, index expressions, predicates,
6360  * exclusion info, and FDW info.
6361  */
6362  rel->rd_rules = NULL;
6363  rel->rd_rulescxt = NULL;
6364  rel->trigdesc = NULL;
6365  rel->rd_rsdesc = NULL;
6366  rel->rd_partkey = NULL;
6367  rel->rd_partkeycxt = NULL;
6368  rel->rd_partdesc = NULL;
6369  rel->rd_partdesc_nodetached = NULL;
6371  rel->rd_pdcxt = NULL;
6372  rel->rd_pddcxt = NULL;
6373  rel->rd_partcheck = NIL;
6374  rel->rd_partcheckvalid = false;
6375  rel->rd_partcheckcxt = NULL;
6376  rel->rd_indexprs = NIL;
6377  rel->rd_indpred = NIL;
6378  rel->rd_exclops = NULL;
6379  rel->rd_exclprocs = NULL;
6380  rel->rd_exclstrats = NULL;
6381  rel->rd_fdwroutine = NULL;
6382 
6383  /*
6384  * Reset transient-state fields in the relcache entry
6385  */
6386  rel->rd_smgr = NULL;
6387  if (rel->rd_isnailed)
6388  rel->rd_refcnt = 1;
6389  else
6390  rel->rd_refcnt = 0;
6391  rel->rd_indexvalid = false;
6392  rel->rd_indexlist = NIL;
6393  rel->rd_pkindex = InvalidOid;
6394  rel->rd_replidindex = InvalidOid;
6395  rel->rd_attrsvalid = false;
6396  rel->rd_keyattr = NULL;
6397  rel->rd_pkattr = NULL;
6398  rel->rd_idattr = NULL;
6399  rel->rd_pubdesc = NULL;
6400  rel->rd_statvalid = false;
6401  rel->rd_statlist = NIL;
6402  rel->rd_fkeyvalid = false;
6403  rel->rd_fkeylist = NIL;
6408  rel->rd_amcache = NULL;
6409  rel->pgstat_info = NULL;
6410 
6411  /*
6412  * Recompute lock and physical addressing info. This is needed in
6413  * case the pg_internal.init file was copied from some other database
6414  * by CREATE DATABASE.
6415  */
6416  RelationInitLockInfo(rel);
6418  }
6419 
6420  /*
6421  * We reached the end of the init file without apparent problem. Did we
6422  * get the right number of nailed items? This is a useful crosscheck in
6423  * case the set of critical rels or indexes changes. However, that should
6424  * not happen in a normally-running system, so let's bleat if it does.
6425  *
6426  * For the shared init file, we're called before client authentication is
6427  * done, which means that elog(WARNING) will go only to the postmaster
6428  * log, where it's easily missed. To ensure that developers notice bad
6429  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
6430  * an Assert(false) there.
6431  */
6432  if (shared)
6433  {
6434  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
6435  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
6436  {
6437  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
6438  nailed_rels, nailed_indexes,
6440  /* Make sure we get developers' attention about this */
6441  Assert(false);
6442  /* In production builds, recover by bootstrapping the relcache */
6443  goto read_failed;
6444  }
6445  }
6446  else
6447  {
6448  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
6449  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
6450  {
6451  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
6452  nailed_rels, nailed_indexes,
6454  /* We don't need an Assert() in this case */
6455  goto read_failed;
6456  }
6457  }
6458 
6459  /*
6460  * OK, all appears well.
6461  *
6462  * Now insert all the new relcache entries into the cache.
6463  */
6464  for (relno = 0; relno < num_rels; relno++)
6465  {
6466  RelationCacheInsert(rels[relno], false);
6467  }
6468 
6469  pfree(rels);
6470  FreeFile(fp);
6471 
6472  if (shared)
6474  else
6475  criticalRelcachesBuilt = true;
6476  return true;
6477 
6478  /*
6479  * init file is broken, so do it the hard way. We don't bother trying to
6480  * free the clutter we just allocated; it's not in the relcache so it
6481  * won't hurt.
6482  */
6483 read_failed:
6484  pfree(rels);
6485  FreeFile(fp);
6486 
6487  return false;
6488 }
#define PG_BINARY_R
Definition: c.h:1266
size_t Size
Definition: c.h:596
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2606
int FreeFile(FILE *file)
Definition: fd.c:2804
char * DatabasePath
Definition: globals.c:103
#define HEAPTUPLESIZE
Definition: htup.h:73
HeapTupleData * HeapTuple
Definition: htup.h:71
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define MAXPGPATH
const void size_t len
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define NIL
Definition: pg_list.h:68
#define snprintf
Definition: port.h:238
#define InvalidOid
Definition: postgres_ext.h:36
#define NUM_CRITICAL_LOCAL_RELS
#define NUM_CRITICAL_SHARED_INDEXES
bool criticalRelcachesBuilt
Definition: relcache.c:140
bool criticalSharedRelcachesBuilt
Definition: relcache.c:146
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1400
#define NUM_CRITICAL_SHARED_RELS
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1808
#define NUM_CRITICAL_LOCAL_INDEXES
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:93
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
Definition: fmgr.h:57
HeapTupleHeader t_data
Definition: htup.h:68
uint16 amsupport
Definition: amapi.h:227
List * rd_partcheck
Definition: rel.h:147
Bitmapset * rd_keyattr
Definition: rel.h:162
bool rd_partcheckvalid
Definition: rel.h:148
MemoryContext rd_pdcxt
Definition: rel.h:131
MemoryContext rd_partkeycxt
Definition: rel.h:127
TransactionId rd_partdesc_nodetached_xmin
Definition: rel.h:144
bool rd_indexvalid
Definition: rel.h:64
List * rd_indpred
Definition: rel.h:213
List * rd_fkeylist
Definition: rel.h:122
Oid * rd_exclprocs
Definition: rel.h:215
uint16 * rd_exclstrats
Definition: rel.h:216
List * rd_indexlist
Definition: rel.h:152
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:119
PartitionDesc rd_partdesc
Definition: rel.h:130
Oid rd_replidindex
Definition: rel.h:155
RegProcedure * rd_support
Definition: rel.h:209
PartitionDesc rd_partdesc_nodetached
Definition: rel.h:134
bytea ** rd_opcoptions
Definition: rel.h:218
PublicationDesc * rd_pubdesc
Definition: rel.h:168
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:240
TriggerDesc * trigdesc
Definition: rel.h:117
Bitmapset * rd_idattr
Definition: rel.h:164
List * rd_indexprs
Definition: rel.h:212
bool rd_attrsvalid
Definition: rel.h:161
Oid * rd_exclops
Definition: rel.h:214
Oid * rd_opcintype
Definition: rel.h:208
struct HeapTupleData * rd_indextuple
Definition: rel.h:194
MemoryContext rd_partcheckcxt
Definition: rel.h:149
int16 * rd_indoption
Definition: rel.h:211
Form_pg_index rd_index
Definition: rel.h:192
void * rd_amcache
Definition: rel.h:229
Oid rd_pkindex
Definition: rel.h:153
bool rd_fkeyvalid
Definition: rel.h:123
bool rd_statvalid
Definition: rel.h:66
List * rd_statlist
Definition: rel.h:158
MemoryContext rd_pddcxt
Definition: rel.h:135
RuleLock * rd_rules
Definition: rel.h:115
struct FmgrInfo * rd_supportinfo
Definition: rel.h:210
Oid * rd_opfamily
Definition: rel.h:207
MemoryContext rd_rulescxt
Definition: rel.h:116
Bitmapset * rd_pkattr
Definition: rel.h:163
PartitionKey rd_partkey
Definition: rel.h:126
bytea * rd_options
Definition: rel.h:175
Oid * rd_indcollation
Definition: rel.h:217
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:255
#define InvalidTransactionId
Definition: transam.h:31
#define VARSIZE(PTR)
Definition: varatt.h:279

References AllocateFile(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert, ATTRIBUTE_FIXED_PART_SIZE, CacheMemoryContext, TupleDescData::constr, CreateTemplateTupleDesc(), criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabasePath, elog, FreeFile(), GETSTRUCT, TupleConstr::has_not_null, HEAPTUPLESIZE, i, InitIndexAmRoutine(), InvalidOid, InvalidSubTransactionId, InvalidTransactionId, len, MAXPGPATH, MemoryContextAlloc(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, NIL, NUM_CRITICAL_LOCAL_INDEXES, NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_SHARED_INDEXES, NUM_CRITICAL_SHARED_RELS, palloc(), palloc0(), pfree(), PG_BINARY_R, RelationData::pgstat_info, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_attrsvalid, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexlist, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indexvalid, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_isnailed, RelationData::rd_keyattr, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_opcintype, RelationData::rd_opcoptions, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_pubdesc, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_replidindex, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationData::rd_statlist, RelationData::rd_statvalid, RelationData::rd_support, RelationData::rd_supportinfo, RelationCacheInsert, RelationGetRelationName, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, repalloc(), snprintf, HeapTupleData::t_data, TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, TupleDescAttr, VARSIZE, and WARNING.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ LookupOpclassInfo()

static OpClassCacheEnt * LookupOpclassInfo ( Oid  operatorClassOid,
StrategyNumber  numSupport 
)
static

Definition at line 1646 of file relcache.c.

1648 {
1649  OpClassCacheEnt *opcentry;
1650  bool found;
1651  Relation rel;
1652  SysScanDesc scan;
1653  ScanKeyData skey[3];
1654  HeapTuple htup;
1655  bool indexOK;
1656 
1657  if (OpClassCache == NULL)
1658  {
1659  /* First time through: initialize the opclass cache */
1660  HASHCTL ctl;
1661 
1662  /* Also make sure CacheMemoryContext exists */
1663  if (!CacheMemoryContext)
1665 
1666  ctl.keysize = sizeof(Oid);
1667  ctl.entrysize = sizeof(OpClassCacheEnt);
1668  OpClassCache = hash_create("Operator class cache", 64,
1669  &ctl, HASH_ELEM | HASH_BLOBS);
1670  }
1671 
1672  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1673  &operatorClassOid,
1674  HASH_ENTER, &found);
1675 
1676  if (!found)
1677  {
1678  /* Initialize new entry */
1679  opcentry->valid = false; /* until known OK */
1680  opcentry->numSupport = numSupport;
1681  opcentry->supportProcs = NULL; /* filled below */
1682  }
1683  else
1684  {
1685  Assert(numSupport == opcentry->numSupport);
1686  }
1687 
1688  /*
1689  * When aggressively testing cache-flush hazards, we disable the operator
1690  * class cache and force reloading of the info on each call. This models
1691  * no real-world behavior, since the cache entries are never invalidated
1692  * otherwise. However it can be helpful for detecting bugs in the cache
1693  * loading logic itself, such as reliance on a non-nailed index. Given
1694  * the limited use-case and the fact that this adds a great deal of
1695  * expense, we enable it only for high values of debug_discard_caches.
1696  */
1697 #ifdef DISCARD_CACHES_ENABLED
1698  if (debug_discard_caches > 2)
1699  opcentry->valid = false;
1700 #endif
1701 
1702  if (opcentry->valid)
1703  return opcentry;
1704 
1705  /*
1706  * Need to fill in new entry. First allocate space, unless we already did
1707  * so in some previous attempt.
1708  */
1709  if (opcentry->supportProcs == NULL && numSupport > 0)
1710  opcentry->supportProcs = (RegProcedure *)
1712  numSupport * sizeof(RegProcedure));
1713 
1714  /*
1715  * To avoid infinite recursion during startup, force heap scans if we're
1716  * looking up info for the opclasses used by the indexes we would like to
1717  * reference here.
1718  */
1719  indexOK = criticalRelcachesBuilt ||
1720  (operatorClassOid != OID_BTREE_OPS_OID &&
1721  operatorClassOid != INT2_BTREE_OPS_OID);
1722 
1723  /*
1724  * We have to fetch the pg_opclass row to determine its opfamily and
1725  * opcintype, which are needed to look up related operators and functions.
1726  * It'd be convenient to use the syscache here, but that probably doesn't
1727  * work while bootstrapping.
1728  */
1729  ScanKeyInit(&skey[0],
1730  Anum_pg_opclass_oid,
1731  BTEqualStrategyNumber, F_OIDEQ,
1732  ObjectIdGetDatum(operatorClassOid));
1733  rel = table_open(OperatorClassRelationId, AccessShareLock);
1734  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1735  NULL, 1, skey);
1736 
1737  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1738  {
1739  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1740 
1741  opcentry->opcfamily = opclassform->opcfamily;
1742  opcentry->opcintype = opclassform->opcintype;
1743  }
1744  else
1745  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1746 
1747  systable_endscan(scan);
1749 
1750  /*
1751  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1752  * the default ones (those with lefttype = righttype = opcintype).
1753  */
1754  if (numSupport > 0)
1755  {
1756  ScanKeyInit(&skey[0],
1757  Anum_pg_amproc_amprocfamily,
1758  BTEqualStrategyNumber, F_OIDEQ,
1759  ObjectIdGetDatum(opcentry->opcfamily));
1760  ScanKeyInit(&skey[1],
1761  Anum_pg_amproc_amproclefttype,
1762  BTEqualStrategyNumber, F_OIDEQ,
1763  ObjectIdGetDatum(opcentry->opcintype));
1764  ScanKeyInit(&skey[2],
1765  Anum_pg_amproc_amprocrighttype,
1766  BTEqualStrategyNumber, F_OIDEQ,
1767  ObjectIdGetDatum(opcentry->opcintype));
1768  rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1769  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1770  NULL, 3, skey);
1771 
1772  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1773  {
1774  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1775 
1776  if (amprocform->amprocnum <= 0 ||
1777  (StrategyNumber) amprocform->amprocnum > numSupport)
1778  elog(ERROR, "invalid amproc number %d for opclass %u",
1779  amprocform->amprocnum, operatorClassOid);
1780 
1781  opcentry->supportProcs[amprocform->amprocnum - 1] =
1782  amprocform->amproc;
1783  }
1784 
1785  systable_endscan(scan);
1787  }
1788 
1789  opcentry->valid = true;
1790  return opcentry;
1791 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:680
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int debug_discard_caches
Definition: inval.c:240
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
tree ctl
Definition: radixtree.h:1853
static HTAB * OpClassCache
Definition: relcache.c:271
struct opclasscacheent OpClassCacheEnt
uint16 StrategyNumber
Definition: stratnum.h:22
StrategyNumber numSupport
Definition: relcache.c:265

References AccessShareLock, Assert, BTEqualStrategyNumber, CacheMemoryContext, CreateCacheMemoryContext(), criticalRelcachesBuilt, ctl, debug_discard_caches, elog, ERROR, GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HeapTupleIsValid, MemoryContextAllocZero(), opclasscacheent::numSupport, ObjectIdGetDatum(), opclasscacheent::opcfamily, opclasscacheent::opcintype, OpClassCache, ScanKeyInit(), opclasscacheent::supportProcs, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and opclasscacheent::valid.

Referenced by IndexSupportInitialize().

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3969 of file relcache.c.

3970 {
3974 
3975  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3976  EOXactListAdd(relation);
3977 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790

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

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1038 of file relcache.c.

1039 {
1040  int in_progress_offset;
1041  Relation relation;
1042  Oid relid;
1043  HeapTuple pg_class_tuple;
1044  Form_pg_class relp;
1045 
1046  /*
1047  * This function and its subroutines can allocate a good deal of transient
1048  * data in CurrentMemoryContext. Traditionally we've just leaked that
1049  * data, reasoning that the caller's context is at worst of transaction
1050  * scope, and relcache loads shouldn't happen so often that it's essential
1051  * to recover transient data before end of statement/transaction. However
1052  * that's definitely not true when debug_discard_caches is active, and
1053  * perhaps it's not true in other cases.
1054  *
1055  * When debug_discard_caches is active or when forced to by
1056  * RECOVER_RELATION_BUILD_MEMORY=1, arrange to allocate the junk in a
1057  * temporary context that we'll free before returning. Make it a child of
1058  * caller's context so that it will get cleaned up appropriately if we
1059  * error out partway through.
1060  */
1061 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1062  MemoryContext tmpcxt = NULL;
1063  MemoryContext oldcxt = NULL;
1064 
1066  {
1068  "RelationBuildDesc workspace",
1070  oldcxt = MemoryContextSwitchTo(tmpcxt);
1071  }
1072 #endif
1073 
1074  /* Register to catch invalidation messages */
1076  {
1077  int allocsize;
1078 
1079  allocsize = in_progress_list_maxlen * 2;
1081  allocsize * sizeof(*in_progress_list));
1082  in_progress_list_maxlen = allocsize;
1083  }
1084  in_progress_offset = in_progress_list_len++;
1085  in_progress_list[in_progress_offset].reloid = targetRelId;
1086 retry:
1087  in_progress_list[in_progress_offset].invalidated = false;
1088 
1089  /*
1090  * find the tuple in pg_class corresponding to the given relation id
1091  */
1092  pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1093 
1094  /*
1095  * if no such tuple exists, return NULL
1096  */
1097  if (!HeapTupleIsValid(pg_class_tuple))
1098  {
1099 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1100  if (tmpcxt)
1101  {
1102  /* Return to caller's context, and blow away the temporary context */
1103  MemoryContextSwitchTo(oldcxt);
1104  MemoryContextDelete(tmpcxt);
1105  }
1106 #endif
1107  Assert(in_progress_offset + 1 == in_progress_list_len);
1109  return NULL;
1110  }
1111 
1112  /*
1113  * get information from the pg_class_tuple
1114  */
1115  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1116  relid = relp->oid;
1117  Assert(relid == targetRelId);
1118 
1119  /*
1120  * allocate storage for the relation descriptor, and copy pg_class_tuple
1121  * to relation->rd_rel.
1122  */
1123  relation = AllocateRelationDesc(relp);
1124 
1125  /*
1126  * initialize the relation's relation id (relation->rd_id)
1127  */
1128  RelationGetRelid(relation) = relid;
1129 
1130  /*
1131  * Normal relations are not nailed into the cache. Since we don't flush
1132  * new relations, it won't be new. It could be temp though.
1133  */
1134  relation->rd_refcnt = 0;
1135  relation->rd_isnailed = false;
1140  switch (relation->rd_rel->relpersistence)
1141  {
1142  case RELPERSISTENCE_UNLOGGED:
1143  case RELPERSISTENCE_PERMANENT:
1144  relation->rd_backend = INVALID_PROC_NUMBER;
1145  relation->rd_islocaltemp = false;
1146  break;
1147  case RELPERSISTENCE_TEMP:
1148  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1149  {
1150  relation->rd_backend = ProcNumberForTempRelations();
1151  relation->rd_islocaltemp = true;
1152  }
1153  else
1154  {
1155  /*
1156  * If it's a temp table, but not one of ours, we have to use
1157  * the slow, grotty method to figure out the owning backend.
1158  *
1159  * Note: it's possible that rd_backend gets set to
1160  * MyProcNumber here, in case we are looking at a pg_class
1161  * entry left over from a crashed backend that coincidentally
1162  * had the same ProcNumber we're using. We should *not*
1163  * consider such a table to be "ours"; this is why we need the
1164  * separate rd_islocaltemp flag. The pg_class entry will get
1165  * flushed if/when we clean out the corresponding temp table
1166  * namespace in preparation for using it.
1167  */
1168  relation->rd_backend =
1169  GetTempNamespaceProcNumber(relation->rd_rel->relnamespace);
1170  Assert(relation->rd_backend != INVALID_PROC_NUMBER);
1171  relation->rd_islocaltemp = false;
1172  }
1173  break;
1174  default:
1175  elog(ERROR, "invalid relpersistence: %c",
1176  relation->rd_rel->relpersistence);
1177  break;
1178  }
1179 
1180  /*
1181  * initialize the tuple descriptor (relation->rd_att).
1182  */
1183  RelationBuildTupleDesc(relation);
1184 
1185  /* foreign key data is not loaded till asked for */
1186  relation->rd_fkeylist = NIL;
1187  relation->rd_fkeyvalid = false;
1188 
1189  /* partitioning data is not loaded till asked for */
1190  relation->rd_partkey = NULL;
1191  relation->rd_partkeycxt = NULL;
1192  relation->rd_partdesc = NULL;
1193  relation->rd_partdesc_nodetached = NULL;
1195  relation->rd_pdcxt = NULL;
1196  relation->rd_pddcxt = NULL;
1197  relation->rd_partcheck = NIL;
1198  relation->rd_partcheckvalid = false;
1199  relation->rd_partcheckcxt = NULL;
1200 
1201  /*
1202  * initialize access method information
1203  */
1204  if (relation->rd_rel->relkind == RELKIND_INDEX ||
1205  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
1206  RelationInitIndexAccessInfo(relation);
1207  else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) ||
1208  relation->rd_rel->relkind == RELKIND_SEQUENCE)
1210  else if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1211  {
1212  /*
1213  * Do nothing: access methods are a setting that partitions can
1214  * inherit.
1215  */
1216  }
1217  else
1218  Assert(relation->rd_rel->relam == InvalidOid);
1219 
1220  /* extract reloptions if any */
1221  RelationParseRelOptions(relation, pg_class_tuple);
1222 
1223  /*
1224  * Fetch rules and triggers that affect this relation.
1225  *
1226  * Note that RelationBuildRuleLock() relies on this being done after
1227  * extracting the relation's reloptions.
1228  */
1229  if (relation->rd_rel->relhasrules)
1230  RelationBuildRuleLock(relation);
1231  else
1232  {
1233  relation->rd_rules = NULL;
1234  relation->rd_rulescxt = NULL;
1235  }
1236 
1237  if (relation->rd_rel->relhastriggers)
1238  RelationBuildTriggers(relation);
1239  else
1240  relation->trigdesc = NULL;
1241 
1242  if (relation->rd_rel->relrowsecurity)
1243  RelationBuildRowSecurity(relation);
1244  else
1245  relation->rd_rsdesc = NULL;
1246 
1247  /*
1248  * initialize the relation lock manager information
1249  */
1250  RelationInitLockInfo(relation); /* see lmgr.c */
1251 
1252  /*
1253  * initialize physical addressing information for the relation
1254  */
1255  RelationInitPhysicalAddr(relation);
1256 
1257  /* make sure relation is marked as having no open file yet */
1258  relation->rd_smgr = NULL;
1259 
1260  /*
1261  * now we can free the memory allocated for pg_class_tuple
1262  */
1263  heap_freetuple(pg_class_tuple);
1264 
1265  /*
1266  * If an invalidation arrived mid-build, start over. Between here and the
1267  * end of this function, don't add code that does or reasonably could read
1268  * system catalogs. That range must be free from invalidation processing
1269  * for the !insertIt case. For the insertIt case, RelationCacheInsert()
1270  * will enroll this relation in ordinary relcache invalidation processing,
1271  */
1272  if (in_progress_list[in_progress_offset].invalidated)
1273  {
1274  RelationDestroyRelation(relation, false);
1275  goto retry;
1276  }
1277  Assert(in_progress_offset + 1 == in_progress_list_len);
1279 
1280  /*
1281  * Insert newly created relation into relcache hash table, if requested.
1282  *
1283  * There is one scenario in which we might find a hashtable entry already
1284  * present, even though our caller failed to find it: if the relation is a
1285  * system catalog or index that's used during relcache load, we might have
1286  * recursively created the same relcache entry during the preceding steps.
1287  * So allow RelationCacheInsert to delete any already-present relcache
1288  * entry for the same OID. The already-present entry should have refcount
1289  * zero (else somebody forgot to close it); in the event that it doesn't,
1290  * we'll elog a WARNING and leak the already-present entry.
1291  */
1292  if (insertIt)
1293  RelationCacheInsert(relation, true);
1294 
1295  /* It's fully valid */
1296  relation->rd_isvalid = true;
1297 
1298 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1299  if (tmpcxt)
1300  {
1301  /* Return to caller's context, and blow away the temporary context */
1302  MemoryContextSwitchTo(oldcxt);
1303  MemoryContextDelete(tmpcxt);
1304  }
1305 #endif
1306 
1307  return relation;
1308 }
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3766
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
#define ProcNumberForTempRelations()
Definition: proc.h:324
#define RECOVER_RELATION_BUILD_MEMORY
Definition: relcache.c:102
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:464
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:409
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1424
static int in_progress_list_maxlen
Definition: relcache.c:172
static void RelationDestroyRelation(Relation relation, bool remember_tupdesc)
Definition: relcache.c:2441
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:731
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:339
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:521
static InProgressEnt * in_progress_list
Definition: relcache.c:170
bool invalidated
Definition: relcache.c:167
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1857

References AllocateRelationDesc(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentMemoryContext, debug_discard_caches, elog, ERROR, GETSTRUCT, GetTempNamespaceProcNumber(), heap_freetuple(), HeapTupleIsValid, in_progress_list, in_progress_list_len, in_progress_list_maxlen, INVALID_PROC_NUMBER, inprogressent::invalidated, InvalidOid, InvalidSubTransactionId, InvalidTransactionId, isTempOrTempToastNamespace(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, ProcNumberForTempRelations, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RECOVER_RELATION_BUILD_MEMORY, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationDestroyRelation(), RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationParseRelOptions(), inprogressent::reloid, repalloc(), ScanPgRelation(), and RelationData::trigdesc.

Referenced by load_critical_index(), RelationClearRelation(), and RelationIdGetRelation().

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

3535 {
3536  Relation rel;
3537  MemoryContext oldcxt;
3538  int natts = tupDesc->natts;
3539  int i;
3540  bool has_not_null;
3541  bool nailit;
3542 
3543  Assert(natts >= 0);
3544 
3545  /*
3546  * check for creation of a rel that must be nailed in cache.
3547  *
3548  * XXX this list had better match the relations specially handled in
3549  * RelationCacheInitializePhase2/3.
3550  */
3551  switch (relid)
3552  {
3553  case DatabaseRelationId:
3554  case AuthIdRelationId:
3555  case AuthMemRelationId:
3556  case RelationRelationId:
3557  case AttributeRelationId:
3558  case ProcedureRelationId:
3559  case TypeRelationId:
3560  nailit = true;
3561  break;
3562  default:
3563  nailit = false;
3564  break;
3565  }
3566 
3567  /*
3568  * check that hardwired list of shared rels matches what's in the
3569  * bootstrap .bki file. If you get a failure here during initdb, you
3570  * probably need to fix IsSharedRelation() to match whatever you've done
3571  * to the set of shared relations.
3572  */
3573  if (shared_relation != IsSharedRelation(relid))
3574  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3575  relname, relid);
3576 
3577  /* Shared relations had better be mapped, too */
3578  Assert(mapped_relation || !shared_relation);
3579 
3580  /*
3581  * switch to the cache context to create the relcache entry.
3582  */
3583  if (!CacheMemoryContext)
3585 
3587 
3588  /*
3589  * allocate a new relation descriptor and fill in basic state fields.
3590  */
3591  rel = (Relation) palloc0(sizeof(RelationData));
3592 
3593  /* make sure relation is marked as having no open file yet */
3594  rel->rd_smgr = NULL;
3595 
3596  /* mark it nailed if appropriate */
3597  rel->rd_isnailed = nailit;
3598 
3599  rel->rd_refcnt = nailit ? 1 : 0;
3600 
3601  /* it's being created in this transaction */
3606 
3607  /*
3608  * create a new tuple descriptor from the one passed in. We do this
3609  * partly to copy it into the cache context, and partly because the new
3610  * relation can't have any defaults or constraints yet; they have to be
3611  * added in later steps, because they require additions to multiple system
3612  * catalogs. We can copy attnotnull constraints here, however.
3613  */
3614  rel->rd_att = CreateTupleDescCopy(tupDesc);
3615  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3616  has_not_null = false;
3617  for (i = 0; i < natts; i++)
3618  {
3619  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3620  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3621 
3622  datt->attidentity = satt->attidentity;
3623  datt->attgenerated = satt->attgenerated;
3624  datt->attnotnull = satt->attnotnull;
3625  has_not_null |= satt->attnotnull;
3626  }
3627 
3628  if (has_not_null)
3629  {
3630  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3631 
3632  constr->has_not_null = true;
3633  rel->rd_att->constr = constr;
3634  }
3635 
3636  /*
3637  * initialize relation tuple form (caller may add/override data later)
3638  */
3640 
3641  namestrcpy(&rel->rd_rel->relname, relname);
3642  rel->rd_rel->relnamespace = relnamespace;
3643 
3644  rel->rd_rel->relkind = relkind;
3645  rel->rd_rel->relnatts = natts;
3646  rel->rd_rel->reltype = InvalidOid;
3647  /* needed when bootstrapping: */
3648  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3649 
3650  /* set up persistence and relcache fields dependent on it */
3651  rel->rd_rel->relpersistence = relpersistence;
3652  switch (relpersistence)
3653  {
3654  case RELPERSISTENCE_UNLOGGED:
3655  case RELPERSISTENCE_PERMANENT:
3657  rel->rd_islocaltemp = false;
3658  break;
3659  case RELPERSISTENCE_TEMP:
3660  Assert(isTempOrTempToastNamespace(relnamespace));
3662  rel->rd_islocaltemp = true;
3663  break;
3664  default:
3665  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3666  break;
3667  }
3668 
3669  /* if it's a materialized view, it's not populated initially */
3670  if (relkind == RELKIND_MATVIEW)
3671  rel->rd_rel->relispopulated = false;
3672  else
3673  rel->rd_rel->relispopulated = true;
3674 
3675  /* set replica identity -- system catalogs and non-tables don't have one */
3676  if (!IsCatalogNamespace(relnamespace) &&
3677  (relkind == RELKIND_RELATION ||
3678  relkind == RELKIND_MATVIEW ||
3679  relkind == RELKIND_PARTITIONED_TABLE))
3680  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3681  else
3682  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3683 
3684  /*
3685  * Insert relation physical and logical identifiers (OIDs) into the right
3686  * places. For a mapped relation, we set relfilenumber to zero and rely
3687  * on RelationInitPhysicalAddr to consult the map.
3688  */
3689  rel->rd_rel->relisshared = shared_relation;
3690 
3691  RelationGetRelid(rel) = relid;
3692 
3693  for (i = 0; i < natts; i++)
3694  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3695 
3696  rel->rd_rel->reltablespace = reltablespace;
3697 
3698  if (mapped_relation)
3699  {
3700  rel->rd_rel->relfilenode = InvalidRelFileNumber;
3701  /* Add it to the active mapping information */
3702  RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3703  }
3704  else
3705  rel->rd_rel->relfilenode = relfilenumber;
3706 
3707  RelationInitLockInfo(rel); /* see lmgr.c */
3708 
3710 
3711  rel->rd_rel->relam = accessmtd;
3712 
3713  /*
3714  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3715  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3716  * require a long-lived current context.
3717  */
3718  MemoryContextSwitchTo(oldcxt);
3719 
3720  if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3722 
3723  /*
3724  * Okay to insert into the relcache hash table.
3725  *
3726  * Ordinarily, there should certainly not be an existing hash entry for
3727  * the same OID; but during bootstrap, when we create a "real" relcache
3728  * entry for one of the bootstrap relations, we'll be overwriting the
3729  * phony one created with formrdesc. So allow that to happen for nailed
3730  * rels.
3731  */
3732  RelationCacheInsert(rel, nailit);
3733 
3734  /*
3735  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3736  * can't do this before storing relid in it.
3737  */
3738  EOXactListAdd(rel);
3739 
3740  /* It's fully valid */
3741  rel->rd_isvalid = true;
3742 
3743  /*
3744  * Caller expects us to pin the returned entry.
3745  */
3747 
3748  return rel;
3749 }
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:273
NameData relname
Definition: pg_class.h:38
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2159
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133

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

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5732 of file relcache.c.

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

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 731 of file relcache.c.

732 {
733  MemoryContext rulescxt;
734  MemoryContext oldcxt;
735  HeapTuple rewrite_tuple;
736  Relation rewrite_desc;
737  TupleDesc rewrite_tupdesc;
738  SysScanDesc rewrite_scan;
740  RuleLock *rulelock;
741  int numlocks;
742  RewriteRule **rules;
743  int maxlocks;
744 
745  /*
746  * Make the private context. Assume it'll not contain much data.
747  */
749  "relation rules",
751  relation->rd_rulescxt = rulescxt;
753  RelationGetRelationName(relation));
754 
755  /*
756  * allocate an array to hold the rewrite rules (the array is extended if
757  * necessary)
758  */
759  maxlocks = 4;
760  rules = (RewriteRule **)
761  MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
762  numlocks = 0;
763 
764  /*
765  * form a scan key
766  */
767  ScanKeyInit(&key,
768  Anum_pg_rewrite_ev_class,
769  BTEqualStrategyNumber, F_OIDEQ,
771 
772  /*
773  * open pg_rewrite and begin a scan
774  *
775  * Note: since we scan the rules using RewriteRelRulenameIndexId, we will
776  * be reading the rules in name order, except possibly during
777  * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
778  * ensures that rules will be fired in name order.
779  */
780  rewrite_desc = table_open(RewriteRelationId, AccessShareLock);
781  rewrite_tupdesc = RelationGetDescr(rewrite_desc);
782  rewrite_scan = systable_beginscan(rewrite_desc,
783  RewriteRelRulenameIndexId,
784  true, NULL,
785  1, &key);
786 
787  while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
788  {
789  Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
790  bool isnull;
791  Datum rule_datum;
792  char *rule_str;
793  RewriteRule *rule;
794  Oid check_as_user;
795 
796  rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
797  sizeof(RewriteRule));
798 
799  rule->ruleId = rewrite_form->oid;
800 
801  rule->event = rewrite_form->ev_type - '0';
802  rule->enabled = rewrite_form->ev_enabled;
803  rule->isInstead = rewrite_form->is_instead;
804 
805  /*
806  * Must use heap_getattr to fetch ev_action and ev_qual. Also, the
807  * rule strings are often large enough to be toasted. To avoid
808  * leaking memory in the caller's context, do the detoasting here so
809  * we can free the detoasted version.
810  */
811  rule_datum = heap_getattr(rewrite_tuple,
812  Anum_pg_rewrite_ev_action,
813  rewrite_tupdesc,
814  &isnull);
815  Assert(!isnull);
816  rule_str = TextDatumGetCString(rule_datum);
817  oldcxt = MemoryContextSwitchTo(rulescxt);
818  rule->actions = (List *) stringToNode(rule_str);
819  MemoryContextSwitchTo(oldcxt);
820  pfree(rule_str);
821 
822  rule_datum = heap_getattr(rewrite_tuple,
823  Anum_pg_rewrite_ev_qual,
824  rewrite_tupdesc,
825  &isnull);
826  Assert(!isnull);
827  rule_str = TextDatumGetCString(rule_datum);
828  oldcxt = MemoryContextSwitchTo(rulescxt);
829  rule->qual = (Node *) stringToNode(rule_str);
830  MemoryContextSwitchTo(oldcxt);
831  pfree(rule_str);
832 
833  /*
834  * If this is a SELECT rule defining a view, and the view has
835  * "security_invoker" set, we must perform all permissions checks on
836  * relations referred to by the rule as the invoking user.
837  *
838  * In all other cases (including non-SELECT rules on security invoker
839  * views), perform the permissions checks as the relation owner.
840  */
841  if (rule->event == CMD_SELECT &&
842  relation->rd_rel->relkind == RELKIND_VIEW &&
843  RelationHasSecurityInvoker(relation))
844  check_as_user = InvalidOid;
845  else
846  check_as_user = relation->rd_rel->relowner;
847 
848  /*
849  * Scan through the rule's actions and set the checkAsUser field on
850  * all RTEPermissionInfos. We have to look at the qual as well, in
851  * case it contains sublinks.
852  *
853  * The reason for doing this when the rule is loaded, rather than when
854  * it is stored, is that otherwise ALTER TABLE OWNER would have to
855  * grovel through stored rules to update checkAsUser fields. Scanning
856  * the rule tree during load is relatively cheap (compared to
857  * constructing it in the first place), so we do it here.
858  */
859  setRuleCheckAsUser((Node *) rule->actions, check_as_user);
860  setRuleCheckAsUser(rule->qual, check_as_user);
861 
862  if (numlocks >= maxlocks)
863  {
864  maxlocks *= 2;
865  rules = (RewriteRule **)
866  repalloc(rules, sizeof(RewriteRule *) * maxlocks);
867  }
868  rules[numlocks++] = rule;
869  }
870 
871  /*
872  * end the scan and close the attribute relation
873  */
874  systable_endscan(rewrite_scan);
875  table_close(rewrite_desc, AccessShareLock);
876 
877  /*
878  * there might not be any rules (if relhasrules is out-of-date)
879  */
880  if (numlocks == 0)
881  {
882  relation->rd_rules = NULL;
883  relation->rd_rulescxt = NULL;
884  MemoryContextDelete(rulescxt);
885  return;
886  }
887 
888  /*
889  * form a RuleLock and insert into relation
890  */
891  rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
892  rulelock->numLocks = numlocks;
893  rulelock->rules = rules;
894 
895  relation->rd_rules = rulelock;
896 }
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
@ CMD_SELECT
Definition: nodes.h:265
FormData_pg_rewrite * Form_pg_rewrite
Definition: pg_rewrite.h:52
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationHasSecurityInvoker(relation)
Definition: rel.h:436
void setRuleCheckAsUser(Node *node, Oid userid)
Definition: nodes.h:129
Definition: localtime.c:73
static struct rule * rules
Definition: zic.c:283

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, BTEqualStrategyNumber, CacheMemoryContext, CMD_SELECT, GETSTRUCT, heap_getattr(), HeapTupleIsValid, InvalidOid, sort-test::key, MemoryContextAlloc(), MemoryContextCopyAndSetIdentifier, MemoryContextDelete(), MemoryContextSwitchTo(), RuleLock::numLocks, ObjectIdGetDatum(), pfree(), RelationData::rd_rel, RelationData::rd_rules, RelationData::rd_rulescxt, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationHasSecurityInvoker, repalloc(), RuleLock::rules, rules, ScanKeyInit(), setRuleCheckAsUser(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 521 of file relcache.c.

522 {
523  HeapTuple pg_attribute_tuple;
524  Relation pg_attribute_desc;
525  SysScanDesc pg_attribute_scan;
526  ScanKeyData skey[2];
527  int need;
528  TupleConstr *constr;
529  AttrMissing *attrmiss = NULL;
530  int ndef = 0;
531 
532  /* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */
533  relation->rd_att->tdtypeid =
534  relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
535  relation->rd_att->tdtypmod = -1; /* just to be sure */
536 
538  sizeof(TupleConstr));
539 
540  /*
541  * Form a scan key that selects only user attributes (attnum > 0).
542  * (Eliminating system attribute rows at the index level is lots faster
543  * than fetching them.)
544  */
545  ScanKeyInit(&skey[0],
546  Anum_pg_attribute_attrelid,
547  BTEqualStrategyNumber, F_OIDEQ,
549  ScanKeyInit(&skey[1],
550  Anum_pg_attribute_attnum,
551  BTGreaterStrategyNumber, F_INT2GT,
552  Int16GetDatum(0));
553 
554  /*
555  * Open pg_attribute and begin a scan. Force heap scan if we haven't yet
556  * built the critical relcache entries (this includes initdb and startup
557  * without a pg_internal.init file).
558  */
559  pg_attribute_desc = table_open(AttributeRelationId, AccessShareLock);
560  pg_attribute_scan = systable_beginscan(pg_attribute_desc,
561  AttributeRelidNumIndexId,
563  NULL,
564  2, skey);
565 
566  /*
567  * add attribute data to relation->rd_att
568  */
569  need = RelationGetNumberOfAttributes(relation);
570 
571  while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
572  {
573  Form_pg_attribute attp;
574  int attnum;
575 
576  attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
577 
578  attnum = attp->attnum;
579  if (attnum <= 0 || attnum > RelationGetNumberOfAttributes(relation))
580  elog(ERROR, "invalid attribute number %d for relation \"%s\"",
581  attp->attnum, RelationGetRelationName(relation));
582 
583  memcpy(TupleDescAttr(relation->rd_att, attnum - 1),
584  attp,
586 
587  /* Update constraint/default info */
588  if (attp->attnotnull)
589  constr->has_not_null = true;
590  if (attp->attgenerated == ATTRIBUTE_GENERATED_STORED)
591  constr->has_generated_stored = true;
592  if (attp->atthasdef)
593  ndef++;
594 
595  /* If the column has a "missing" value, put it in the attrmiss array */
596  if (attp->atthasmissing)
597  {
598  Datum missingval;
599  bool missingNull;
600 
601  /* Do we have a missing value? */
602  missingval = heap_getattr(pg_attribute_tuple,
603  Anum_pg_attribute_attmissingval,
604  pg_attribute_desc->rd_att,
605  &missingNull);
606  if (!missingNull)
607  {
608  /* Yes, fetch from the array */
609  MemoryContext oldcxt;
610  bool is_null;
611  int one = 1;
612  Datum missval;
613 
614  if (attrmiss == NULL)
615  attrmiss = (AttrMissing *)
617  relation->rd_rel->relnatts *
618  sizeof(AttrMissing));
619 
620  missval = array_get_element(missingval,
621  1,
622  &one,
623  -1,
624  attp->attlen,
625  attp->attbyval,
626  attp->attalign,
627  &is_null);
628  Assert(!is_null);
629  if (attp->attbyval)
630  {
631  /* for copy by val just copy the datum direct */
632  attrmiss[attnum - 1].am_value = missval;
633  }
634  else
635  {
636  /* otherwise copy in the correct context */
638  attrmiss[attnum - 1].am_value = datumCopy(missval,
639  attp->attbyval,
640  attp->attlen);
641  MemoryContextSwitchTo(oldcxt);
642  }
643  attrmiss[attnum - 1].am_present = true;
644  }
645  }
646  need--;
647  if (need == 0)
648  break;
649  }
650 
651  /*
652  * end the scan and close the attribute relation
653  */
654  systable_endscan(pg_attribute_scan);
655  table_close(pg_attribute_desc, AccessShareLock);
656 
657  if (need != 0)
658  elog(ERROR, "pg_attribute catalog is missing %d attribute(s) for relation OID %u",
659  need, RelationGetRelid(relation));
660 
661  /*
662  * The attcacheoff values we read from pg_attribute should all be -1
663  * ("unknown"). Verify this if assert checking is on. They will be
664  * computed when and if needed during tuple access.
665  */
666 #ifdef USE_ASSERT_CHECKING
667  {
668  int i;
669 
670  for (i = 0; i < RelationGetNumberOfAttributes(relation); i++)
671  Assert(TupleDescAttr(relation->rd_att, i)->attcacheoff == -1);
672  }
673 #endif
674 
675  /*
676  * However, we can easily set the attcacheoff value for the first
677  * attribute: it must be zero. This eliminates the need for special cases
678  * for attnum=1 that used to exist in fastgetattr() and index_getattr().
679  */
680  if (RelationGetNumberOfAttributes(relation) > 0)
681  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
682 
683  /*
684  * Set up constraint/default info
685  */
686  if (constr->has_not_null ||
687  constr->has_generated_stored ||
688  ndef > 0 ||
689  attrmiss ||
690  relation->rd_rel->relchecks > 0)
691  {
692  relation->rd_att->constr = constr;
693 
694  if (ndef > 0) /* DEFAULTs */
695  AttrDefaultFetch(relation, ndef);
696  else
697  constr->num_defval = 0;
698 
699  constr->missing = attrmiss;
700 
701  if (relation->rd_rel->relchecks > 0) /* CHECKs */
702  CheckConstraintFetch(relation);
703  else
704  constr->num_check = 0;
705  }
706  else
707  {
708  pfree(constr);
709  relation->rd_att->constr = NULL;
710  }
711 }
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
static void AttrDefaultFetch(Relation relation, int ndef)
Definition: relcache.c:4488
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4583
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
bool has_generated_stored
Definition: tupdesc.h:45
struct AttrMissing * missing
Definition: tupdesc.h:41

References AccessShareLock, AttrMissing::am_present, AttrMissing::am_value, array_get_element(), Assert, attnum, AttrDefaultFetch(), ATTRIBUTE_FIXED_PART_SIZE, BTEqualStrategyNumber, BTGreaterStrategyNumber, CacheMemoryContext, CheckConstraintFetch(), TupleDescData::constr, criticalRelcachesBuilt, datumCopy(), elog, ERROR, GETSTRUCT, TupleConstr::has_generated_stored, TupleConstr::has_not_null, heap_getattr(), HeapTupleIsValid, i, Int16GetDatum(), MemoryContextAllocZero(), MemoryContextSwitchTo(), TupleConstr::missing, TupleConstr::num_check, TupleConstr::num_defval, ObjectIdGetDatum(), pfree(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by RelationBuildDesc().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6795 of file relcache.c.

6796 {
6797  LWLockRelease(RelCacheInitLock);
6798 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6770 of file relcache.c.

6771 {
6772  char localinitfname[MAXPGPATH];
6773  char sharedinitfname[MAXPGPATH];
6774 
6775  if (DatabasePath)
6776  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6778  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6780 
6781  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6782 
6783  /*
6784  * The files might not be there if no backend has been started since the
6785  * last removal. But complain about failures other than ENOENT with
6786  * ERROR. Fortunately, it's not too late to abort the transaction if we
6787  * can't get rid of the would-be-obsolete init file.
6788  */
6789  if (DatabasePath)
6790  unlink_initfile(localinitfname, ERROR);
6791  unlink_initfile(sharedinitfname, ERROR);
6792 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6867

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

6811 {
6812  const char *tblspcdir = PG_TBLSPC_DIR;
6813  DIR *dir;
6814  struct dirent *de;
6815  char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6816 
6817  snprintf(path, sizeof(path), "global/%s",
6819  unlink_initfile(path, LOG);
6820 
6821  /* Scan everything in the default tablespace */
6823 
6824  /* Scan the tablespace link directory to find non-default tablespaces */
6825  dir = AllocateDir(tblspcdir);
6826 
6827  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6828  {
6829  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6830  {
6831  /* Scan the tablespace dir for per-database dirs */
6832  snprintf(path, sizeof(path), "%s/%s/%s",
6833  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6835  }
6836  }
6837 
6838  FreeDir(dir);
6839 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2984
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2947
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2866
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6843
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6843 of file relcache.c.

6844 {
6845  DIR *dir;
6846  struct dirent *de;
6847  char initfilename[MAXPGPATH * 2];
6848 
6849  /* Scan the tablespace directory to find per-database directories */
6850  dir = AllocateDir(tblspcpath);
6851 
6852  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6853  {
6854  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6855  {
6856  /* Try to remove the init file in each database */
6857  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6858  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6859  unlink_initfile(initfilename, LOG);
6860  }
6861  }
6862 
6863  FreeDir(dir);
6864 }

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

Referenced by RelationCacheInitFileRemove().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3995 of file relcache.c.

3996 {
3997  HASHCTL ctl;
3998  int allocsize;
3999 
4000  /*
4001  * make sure cache memory context exists
4002  */
4003  if (!CacheMemoryContext)
4005 
4006  /*
4007  * create hashtable that indexes the relcache
4008  */
4009  ctl.keysize = sizeof(Oid);
4010  ctl.entrysize = sizeof(RelIdCacheEnt);
4011  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4012  &ctl, HASH_ELEM | HASH_BLOBS);
4013 
4014  /*
4015  * reserve enough in_progress_list slots for many cases
4016  */
4017  allocsize = 4;
4020  allocsize * sizeof(*in_progress_list));
4021  in_progress_list_maxlen = allocsize;
4022 
4023  /*
4024  * relation mapper needs to be initialized too
4025  */
4027 }
#define INITRELCACHESIZE
Definition: relcache.c:3992
struct relidcacheent RelIdCacheEnt
void RelationMapInitialize(void)
Definition: relmapper.c:651

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 4041 of file relcache.c.

4042 {
4043  MemoryContext oldcxt;
4044 
4045  /*
4046  * relation mapper needs initialized too
4047  */
4049 
4050  /*
4051  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4052  * nothing.
4053  */
4055  return;
4056 
4057  /*
4058  * switch to cache memory context
4059  */
4061 
4062  /*
4063  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4064  * the cache with pre-made descriptors for the critical shared catalogs.
4065  */
4066  if (!load_relcache_init_file(true))
4067  {
4068  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4069  Natts_pg_database, Desc_pg_database);
4070  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4071  Natts_pg_authid, Desc_pg_authid);
4072  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4073  Natts_pg_auth_members, Desc_pg_auth_members);
4074  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4075  Natts_pg_shseclabel, Desc_pg_shseclabel);
4076  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4077  Natts_pg_subscription, Desc_pg_subscription);
4078 
4079 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4080  }
4081 
4082  MemoryContextSwitchTo(oldcxt);
4083 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6079
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:1873
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:120
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:117
void RelationMapInitializePhase2(void)
Definition: relmapper.c:671

References CacheMemoryContext, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, Desc_pg_shseclabel, Desc_pg_subscription, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), and RelationMapInitializePhase2().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 4100 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 3011 of file relcache.c.

3012 {
3013  HASH_SEQ_STATUS status;
3014  RelIdCacheEnt *idhentry;
3015  Relation relation;
3016  List *rebuildFirstList = NIL;
3017  List *rebuildList = NIL;
3018  ListCell *l;
3019  int i;
3020 
3021  /*
3022  * Reload relation mapping data before starting to reconstruct cache.
3023  */
3025 
3026  /* Phase 1 */
3027  hash_seq_init(&status, RelationIdCache);
3028 
3029  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3030  {
3031  relation = idhentry->reldesc;
3032 
3033  /*
3034  * Ignore new relations; no other backend will manipulate them before
3035  * we commit. Likewise, before replacing a relation's relfilelocator,
3036  * we shall have acquired AccessExclusiveLock and drained any
3037  * applicable pending invalidations.
3038  */
3039  if (relation->rd_createSubid != InvalidSubTransactionId ||
3041  continue;
3042 
3044 
3045  if (RelationHasReferenceCountZero(relation))
3046  {
3047  /* Delete this entry immediately */
3048  Assert(!relation->rd_isnailed);
3049  RelationClearRelation(relation, false);
3050  }
3051  else
3052  {
3053  /*
3054  * If it's a mapped relation, immediately update its rd_locator in
3055  * case its relfilenumber changed. We must do this during phase 1
3056  * in case the relation is consulted during rebuild of other
3057  * relcache entries in phase 2. It's safe since consulting the
3058  * map doesn't involve any access to relcache entries.
3059  */
3060  if (RelationIsMapped(relation))
3061  {
3062  RelationCloseSmgr(relation);
3063  RelationInitPhysicalAddr(relation);
3064  }
3065 
3066  /*
3067  * Add this entry to list of stuff to rebuild in second pass.
3068  * pg_class goes to the front of rebuildFirstList while
3069  * pg_class_oid_index goes to the back of rebuildFirstList, so
3070  * they are done first and second respectively. Other nailed
3071  * relations go to the front of rebuildList, so they'll be done
3072  * next in no particular order; and everything else goes to the
3073  * back of rebuildList.
3074  */
3075  if (RelationGetRelid(relation) == RelationRelationId)
3076  rebuildFirstList = lcons(relation, rebuildFirstList);
3077  else if (RelationGetRelid(relation) == ClassOidIndexId)
3078  rebuildFirstList = lappend(rebuildFirstList, relation);
3079  else if (relation->rd_isnailed)
3080  rebuildList = lcons(relation, rebuildList);
3081  else
3082  rebuildList = lappend(rebuildList, relation);
3083  }
3084  }
3085 
3086  /*
3087  * We cannot destroy the SMgrRelations as there might still be references
3088  * to them, but close the underlying file descriptors.
3089  */
3090  smgrreleaseall();
3091 
3092  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3093  foreach(l, rebuildFirstList)
3094  {
3095  relation = (Relation) lfirst(l);
3096  RelationClearRelation(relation, true);
3097  }
3098  list_free(rebuildFirstList);
3099  foreach(l, rebuildList)
3100  {
3101  relation = (Relation) lfirst(l);
3102  RelationClearRelation(relation, true);
3103  }
3104  list_free(rebuildList);
3105 
3106  if (!debug_discard)
3107  /* Any RelationBuildDesc() on the stack must start over. */
3108  for (i = 0; i < in_progress_list_len; i++)
3109  in_progress_list[i].invalidated = true;
3110 }
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
List * lcons(void *datum, List *list)
Definition: list.c:495
#define RelationIsMapped(relation)
Definition: rel.h:554
static void RelationCloseSmgr(Relation relation)
Definition: rel.h:582
static long relcacheInvalsReceived
Definition: relcache.c:154
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:356

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2955 of file relcache.c.

2956 {
2957  Relation relation;
2958 
2959  RelationIdCacheLookup(relationId, relation);
2960 
2961  if (PointerIsValid(relation))
2962  {
2964  RelationFlushRelation(relation);
2965  }
2966  else
2967  {
2968  int i;
2969 
2970  for (i = 0; i < in_progress_list_len; i++)
2971  if (in_progress_list[i].reloid == relationId)
2972  in_progress_list[i].invalidated = true;
2973  }
2974 }
#define PointerIsValid(pointer)
Definition: c.h:754
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2864

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

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2559 of file relcache.c.

2560 {
2561  /*
2562  * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of
2563  * course it would be an equally bad idea to blow away one with nonzero
2564  * refcnt, since that would leave someone somewhere with a dangling
2565  * pointer. All callers are expected to have verified that this holds.
2566  */
2567  Assert(rebuild ?
2568  !RelationHasReferenceCountZero(relation) :
2569  RelationHasReferenceCountZero(relation));
2570 
2571  /*
2572  * Make sure smgr and lower levels close the relation's files, if they
2573  * weren't closed already. If the relation is not getting deleted, the
2574  * next smgr access should reopen the files automatically. This ensures
2575  * that the low-level file access state is updated after, say, a vacuum
2576  * truncation.
2577  */
2578  RelationCloseSmgr(relation);
2579 
2580  /* Free AM cached data, if any */
2581  if (relation->rd_amcache)
2582  pfree(relation->rd_amcache);
2583  relation->rd_amcache = NULL;
2584 
2585  /*
2586  * Treat nailed-in system relations separately, they always need to be
2587  * accessible, so we can't blow them away.
2588  */
2589  if (relation->rd_isnailed)
2590  {
2591  RelationReloadNailed(relation);
2592  return;
2593  }
2594 
2595  /* Mark it invalid until we've finished rebuild */
2596  relation->rd_isvalid = false;
2597 
2598  /* See RelationForgetRelation(). */
2599  if (relation->rd_droppedSubid != InvalidSubTransactionId)
2600  return;
2601 
2602  /*
2603  * Even non-system indexes should not be blown away if they are open and
2604  * have valid index support information. This avoids problems with active
2605  * use of the index support information. As with nailed indexes, we
2606  * re-read the pg_class row to handle possible physical relocation of the
2607  * index, and we check for pg_index updates too.
2608  */
2609  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2610  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2611  relation->rd_refcnt > 0 &&
2612  relation->rd_indexcxt != NULL)
2613  {
2614  if (IsTransactionState())
2615  RelationReloadIndexInfo(relation);
2616  return;
2617  }
2618 
2619  /*
2620  * If we're really done with the relcache entry, blow it away. But if
2621  * someone is still using it, reconstruct the whole deal without moving
2622  * the physical RelationData record (so that the someone's pointer is
2623  * still valid).
2624  */
2625  if (!rebuild)
2626  {
2627  /* Remove it from the hash table */
2628  RelationCacheDelete(relation);
2629 
2630  /* And release storage */
2631  RelationDestroyRelation(relation, false);
2632  }
2633  else if (!IsTransactionState())
2634  {
2635  /*
2636  * If we're not inside a valid transaction, we can't do any catalog
2637  * access so it's not possible to rebuild yet. Just exit, leaving
2638  * rd_isvalid = false so that the rebuild will occur when the entry is
2639  * next opened.
2640  *
2641  * Note: it's possible that we come here during subtransaction abort,
2642  * and the reason for wanting to rebuild is that the rel is open in
2643  * the outer transaction. In that case it might seem unsafe to not
2644  * rebuild immediately, since whatever code has the rel already open
2645  * will keep on using the relcache entry as-is. However, in such a
2646  * case the outer transaction should be holding a lock that's
2647  * sufficient to prevent any significant change in the rel's schema,
2648  * so the existing entry contents should be good enough for its
2649  * purposes; at worst we might be behind on statistics updates or the
2650  * like. (See also CheckTableNotInUse() and its callers.) These same
2651  * remarks also apply to the cases above where we exit without having
2652  * done RelationReloadIndexInfo() yet.
2653  */
2654  return;
2655  }
2656  else
2657  {
2658  /*
2659  * Our strategy for rebuilding an open relcache entry is to build a
2660  * new entry from scratch, swap its contents with the old entry, and
2661  * finally delete the new entry (along with any infrastructure swapped
2662  * over from the old entry). This is to avoid trouble in case an
2663  * error causes us to lose control partway through. The old entry
2664  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2665  * on next access. Meanwhile it's not any less valid than it was
2666  * before, so any code that might expect to continue accessing it
2667  * isn't hurt by the rebuild failure. (Consider for example a
2668  * subtransaction that ALTERs a table and then gets canceled partway
2669  * through the cache entry rebuild. The outer transaction should
2670  * still see the not-modified cache entry as valid.) The worst
2671  * consequence of an error is leaking the necessarily-unreferenced new
2672  * entry, and this shouldn't happen often enough for that to be a big
2673  * problem.
2674  *
2675  * When rebuilding an open relcache entry, we must preserve ref count,
2676  * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2677  * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2678  * and partition descriptor substructures in place, because various
2679  * places assume that these structures won't move while they are
2680  * working with an open relcache entry. (Note: the refcount
2681  * mechanism for tupledescs might someday allow us to remove this hack
2682  * for the tupledesc.)
2683  *
2684  * Note that this process does not touch CurrentResourceOwner; which
2685  * is good because whatever ref counts the entry may have do not
2686  * necessarily belong to that resource owner.
2687  */
2688  Relation newrel;
2689  Oid save_relid = RelationGetRelid(relation);
2690  bool keep_tupdesc;
2691  bool keep_rules;
2692  bool keep_policies;
2693  bool keep_partkey;
2694 
2695  /* Build temporary entry, but don't link it into hashtable */
2696  newrel = RelationBuildDesc(save_relid, false);
2697 
2698  /*
2699  * Between here and the end of the swap, don't add code that does or
2700  * reasonably could read system catalogs. That range must be free
2701  * from invalidation processing. See RelationBuildDesc() manipulation
2702  * of in_progress_list.
2703  */
2704 
2705  if (newrel == NULL)
2706  {
2707  /*
2708  * We can validly get here, if we're using a historic snapshot in
2709  * which a relation, accessed from outside logical decoding, is
2710  * still invisible. In that case it's fine to just mark the
2711  * relation as invalid and return - it'll fully get reloaded by
2712  * the cache reset at the end of logical decoding (or at the next
2713  * access). During normal processing we don't want to ignore this
2714  * case as it shouldn't happen there, as explained below.
2715  */
2716  if (HistoricSnapshotActive())
2717  return;
2718 
2719  /*
2720  * This shouldn't happen as dropping a relation is intended to be
2721  * impossible if still referenced (cf. CheckTableNotInUse()). But
2722  * if we get here anyway, we can't just delete the relcache entry,
2723  * as it possibly could get accessed later (as e.g. the error
2724  * might get trapped and handled via a subtransaction rollback).
2725  */
2726  elog(ERROR, "relation %u deleted while still in use", save_relid);
2727  }
2728 
2729  /*
2730  * If we were to, again, have cases of the relkind of a relcache entry
2731  * changing, we would need to ensure that pgstats does not get
2732  * confused.
2733  */
2734  Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind);
2735 
2736  keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2737  keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2738  keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2739  /* partkey is immutable once set up, so we can always keep it */
2740  keep_partkey = (relation->rd_partkey != NULL);
2741 
2742  /*
2743  * Perform swapping of the relcache entry contents. Within this
2744  * process the old entry is momentarily invalid, so there *must* be no
2745  * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2746  * all-in-line code for safety.
2747  *
2748  * Since the vast majority of fields should be swapped, our method is
2749  * to swap the whole structures and then re-swap those few fields we
2750  * didn't want swapped.
2751  */
2752 #define SWAPFIELD(fldtype, fldname) \
2753  do { \
2754  fldtype _tmp = newrel->fldname; \
2755  newrel->fldname = relation->fldname; \
2756  relation->fldname = _tmp; \
2757  } while (0)
2758 
2759  /* swap all Relation struct fields */
2760  {
2761  RelationData tmpstruct;
2762 
2763  memcpy(&tmpstruct, newrel, sizeof(RelationData));
2764  memcpy(newrel, relation, sizeof(RelationData));
2765  memcpy(relation, &tmpstruct, sizeof(RelationData));
2766  }
2767 
2768  /* rd_smgr must not be swapped, due to back-links from smgr level */
2769  SWAPFIELD(SMgrRelation, rd_smgr);
2770  /* rd_refcnt must be preserved */
2771  SWAPFIELD(int, rd_refcnt);
2772  /* isnailed shouldn't change */
2773  Assert(newrel->rd_isnailed == relation->rd_isnailed);
2774  /* creation sub-XIDs must be preserved */
2775  SWAPFIELD(SubTransactionId, rd_createSubid);
2776  SWAPFIELD(SubTransactionId, rd_newRelfilelocatorSubid);
2777  SWAPFIELD(SubTransactionId, rd_firstRelfilelocatorSubid);
2778  SWAPFIELD(SubTransactionId, rd_droppedSubid);
2779  /* un-swap rd_rel pointers, swap contents instead */
2780  SWAPFIELD(Form_pg_class, rd_rel);
2781  /* ... but actually, we don't have to update newrel->rd_rel */
2782  memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2783  /* preserve old tupledesc, rules, policies if no logical change */
2784  if (keep_tupdesc)
2785  SWAPFIELD(TupleDesc, rd_att);
2786  if (keep_rules)
2787  {
2788  SWAPFIELD(RuleLock *, rd_rules);
2789  SWAPFIELD(MemoryContext, rd_rulescxt);
2790  }
2791  if (keep_policies)
2792  SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2793  /* toast OID override must be preserved */
2794  SWAPFIELD(Oid, rd_toastoid);
2795  /* pgstat_info / enabled must be preserved */
2796  SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2797  SWAPFIELD(bool, pgstat_enabled);
2798  /* preserve old partition key if we have one */
2799  if (keep_partkey)
2800  {
2801  SWAPFIELD(PartitionKey, rd_partkey);
2802  SWAPFIELD(MemoryContext, rd_partkeycxt);
2803  }
2804  if (newrel->rd_pdcxt != NULL || newrel->rd_pddcxt != NULL)
2805  {
2806  /*
2807  * We are rebuilding a partitioned relation with a non-zero
2808  * reference count, so we must keep the old partition descriptor
2809  * around, in case there's a PartitionDirectory with a pointer to
2810  * it. This means we can't free the old rd_pdcxt yet. (This is
2811  * necessary because RelationGetPartitionDesc hands out direct
2812  * pointers to the relcache's data structure, unlike our usual
2813  * practice which is to hand out copies. We'd have the same
2814  * problem with rd_partkey, except that we always preserve that
2815  * once created.)
2816  *
2817  * To ensure that it's not leaked completely, re-attach it to the
2818  * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2819  * in the unlikely event that there is one already. (Compare hack
2820  * in RelationBuildPartitionDesc.) RelationClose will clean up
2821  * any such contexts once the reference count reaches zero.
2822  *
2823  * In the case where the reference count is zero, this code is not
2824  * reached, which should be OK because in that case there should
2825  * be no PartitionDirectory with a pointer to the old entry.
2826  *
2827  * Note that newrel and relation have already been swapped, so the
2828  * "old" partition descriptor is actually the one hanging off of
2829  * newrel.
2830  */
2831  relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2832  relation->rd_partdesc_nodetached = NULL;
2834  if (relation->rd_pdcxt != NULL) /* probably never happens */
2835  MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2836  else
2837  relation->rd_pdcxt = newrel->rd_pdcxt;
2838  if (relation->rd_pddcxt != NULL)
2839  MemoryContextSetParent(newrel->rd_pddcxt, relation->rd_pddcxt);
2840  else
2841  relation->rd_pddcxt = newrel->rd_pddcxt;
2842  /* drop newrel's pointers so we don't destroy it below */
2843  newrel->rd_partdesc = NULL;
2844  newrel->rd_partdesc_nodetached = NULL;
2846  newrel->rd_pdcxt = NULL;
2847  newrel->rd_pddcxt = NULL;
2848  }
2849 
2850 #undef SWAPFIELD
2851 
2852  /* And now we can throw away the temporary entry */
2853  RelationDestroyRelation(newrel, !keep_tupdesc);
2854  }
2855 }
uint32 SubTransactionId
Definition: c.h:647
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
Definition: relcache.c:906
static void RelationReloadNailed(Relation relation)
Definition: relcache.c:2369
#define RelationCacheDelete(RELATION)
Definition: relcache.c:243
static bool equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
Definition: relcache.c:997
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2255
#define SWAPFIELD(fldtype, fldname)
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:419
bool IsTransactionState(void)
Definition: xact.c:386

References Assert, CLASS_TUPLE_SIZE, elog, equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), InvalidSubTransactionId, InvalidTransactionId, IsTransactionState(), MemoryContextSetParent(), pfree(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_droppedSubid, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationBuildDesc(), RelationCacheDelete, RelationCloseSmgr(), RelationDestroyRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationReloadIndexInfo(), RelationReloadNailed(), and SWAPFIELD.

Referenced by AtEOSubXact_cleanup(), AtEOXact_cleanup(), RelationCacheInvalidate(), RelationCloseCleanup(), RelationFlushRelation(), RelationForgetRelation(), and RelationIdGetRelation().

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2192 of file relcache.c.

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

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

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

◆ RelationCloseCleanup()

static void RelationCloseCleanup ( Relation  relation)
static

Definition at line 2201 of file relcache.c.

2202 {
2203  /*
2204  * If the relation is no longer open in this session, we can clean up any
2205  * stale partition descriptors it has. This is unlikely, so check to see
2206  * if there are child contexts before expending a call to mcxt.c.
2207  */
2208  if (RelationHasReferenceCountZero(relation))
2209  {
2210  if (relation->rd_pdcxt != NULL &&
2211  relation->rd_pdcxt->firstchild != NULL)
2213 
2214  if (relation->rd_pddcxt != NULL &&
2215  relation->rd_pddcxt->firstchild != NULL)
2217  }
2218 
2219 #ifdef RELCACHE_FORCE_RELEASE
2220  if (RelationHasReferenceCountZero(relation) &&
2221  relation->rd_createSubid == InvalidSubTransactionId &&
2223  RelationClearRelation(relation, false);
2224 #endif
2225 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:539
MemoryContext firstchild
Definition: memnodes.h:128

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

Referenced by RelationClose(), and ResOwnerReleaseRelation().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2172 of file relcache.c.

2173 {
2174  Assert(rel->rd_refcnt > 0);
2175  rel->rd_refcnt -= 1;
2178 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2145
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References Assert, CurrentResourceOwner, IsBootstrapProcessingMode, RelationData::rd_refcnt, and ResourceOwnerForgetRelationRef().

Referenced by DestroyPartitionDirectory(), heap_endscan(), index_endscan(), RelationCacheInitializePhase3(), RelationClose(), and RelationFlushRelation().

◆ RelationDestroyRelation()

static void RelationDestroyRelation ( Relation  relation,
bool  remember_tupdesc 
)
static

Definition at line 2441 of file relcache.c.

2442 {
2444 
2445  /*
2446  * Make sure smgr and lower levels close the relation's files, if they
2447  * weren't closed already. (This was probably done by caller, but let's
2448  * just be real sure.)
2449  */
2450  RelationCloseSmgr(relation);
2451 
2452  /* break mutual link with stats entry */
2453  pgstat_unlink_relation(relation);
2454 
2455  /*
2456  * Free all the subsidiary data structures of the relcache entry, then the
2457  * entry itself.
2458  */
2459  if (relation->rd_rel)
2460  pfree(relation->rd_rel);
2461  /* can't use DecrTupleDescRefCount here */
2462  Assert(relation->rd_att->tdrefcount > 0);
2463  if (--relation->rd_att->tdrefcount == 0)
2464  {
2465  /*
2466  * If we Rebuilt a relcache entry during a transaction then its
2467  * possible we did that because the TupDesc changed as the result of
2468  * an ALTER TABLE that ran at less than AccessExclusiveLock. It's
2469  * possible someone copied that TupDesc, in which case the copy would
2470  * point to free'd memory. So if we rebuild an entry we keep the
2471  * TupDesc around until end of transaction, to be safe.
2472  */
2473  if (remember_tupdesc)
2475  else
2476  FreeTupleDesc(relation->rd_att);
2477  }
2478  FreeTriggerDesc(relation->trigdesc);
2479  list_free_deep(relation->rd_fkeylist);
2480  list_free(relation->rd_indexlist);
2481  list_free(relation->rd_statlist);
2482  bms_free(relation->rd_keyattr);
2483  bms_free(relation->rd_pkattr);
2484  bms_free(relation->rd_idattr);
2485  bms_free(relation->rd_hotblockingattr);
2486  bms_free(relation->rd_summarizedattr);
2487  if (relation->rd_pubdesc)
2488  pfree(relation->rd_pubdesc);
2489  if (relation->rd_options)
2490  pfree(relation->rd_options);
2491  if (relation->rd_indextuple)
2492  pfree(relation->rd_indextuple);
2493  if (relation->rd_amcache)
2494  pfree(relation->rd_amcache);
2495  if (relation->rd_fdwroutine)
2496  pfree(relation->rd_fdwroutine);
2497  if (relation->rd_indexcxt)
2498  MemoryContextDelete(relation->rd_indexcxt);
2499  if (relation->rd_rulescxt)
2500  MemoryContextDelete(relation->rd_rulescxt);
2501  if (relation->rd_rsdesc)
2502  MemoryContextDelete(relation->rd_rsdesc->rscxt);
2503  if (relation->rd_partkeycxt)
2505  if (relation->rd_pdcxt)
2506  MemoryContextDelete(relation->rd_pdcxt);
2507  if (relation->rd_pddcxt)
2508  MemoryContextDelete(relation->rd_pddcxt);
2509  if (relation->rd_partcheckcxt)
2511  pfree(relation);
2512 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
void list_free_deep(List *list)
Definition: list.c:1560
void pgstat_unlink_relation(Relation rel)
static void RememberToFreeTupleDescAtEOX(TupleDesc td)
Definition: relcache.c:3113
Bitmapset * rd_hotblockingattr
Definition: rel.h:165
Bitmapset * rd_summarizedattr
Definition: rel.h:166
MemoryContext rscxt
Definition: rowsecurity.h:33
void FreeTriggerDesc(TriggerDesc *trigdesc)
Definition: trigger.c:2141

References Assert, bms_free(), FreeTriggerDesc(), FreeTupleDesc(), list_free(), list_free_deep(), MemoryContextDelete(), pfree(), pgstat_unlink_relation(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_fdwroutine, RelationData::rd_fkeylist, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indexcxt, RelationData::rd_indexlist, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_options, RelationData::rd_partcheckcxt, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_pkattr, RelationData::rd_pubdesc, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rulescxt, RelationData::rd_statlist, RelationData::rd_summarizedattr, RelationCloseSmgr(), RelationHasReferenceCountZero, RememberToFreeTupleDescAtEOX(), RowSecurityDesc::rscxt, TupleDescData::tdrefcount, and RelationData::trigdesc.

Referenced by RelationBuildDesc(), and RelationClearRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2864 of file relcache.c.

2865 {
2866  if (relation->rd_createSubid != InvalidSubTransactionId ||
2868  {
2869  /*
2870  * New relcache entries are always rebuilt, not flushed; else we'd
2871  * forget the "new" status of the relation. Ditto for the
2872  * new-relfilenumber status.
2873  */
2875  {
2876  /*
2877  * The rel could have zero refcnt here, so temporarily increment
2878  * the refcnt to ensure it's safe to rebuild it. We can assume
2879  * that the current transaction has some lock on the rel already.
2880  */
2882  RelationClearRelation(relation, true);
2884  }
2885  else
2886  {
2887  /*
2888  * During abort processing, the current resource owner is not
2889  * valid and we cannot hold a refcnt. Without a valid
2890  * transaction, RelationClearRelation() would just mark the rel as
2891  * invalid anyway, so we can do the same directly.
2892  */
2893  RelationInvalidateRelation(relation);
2894  }
2895  }
2896  else
2897  {
2898  /*
2899  * Pre-existing rels can be dropped from the relcache if not open.
2900  */
2901  bool rebuild = !RelationHasReferenceCountZero(relation);
2902 
2903  RelationClearRelation(relation, rebuild);
2904  }
2905 }
static void RelationInvalidateRelation(Relation relation)
Definition: relcache.c:2520

References InvalidSubTransactionId, IsTransactionState(), RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationClearRelation(), RelationDecrementReferenceCount(), RelationHasReferenceCountZero, RelationIncrementReferenceCount(), and RelationInvalidateRelation().

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2911 of file relcache.c.

2912 {
2913  Relation relation;
2914 
2915  RelationIdCacheLookup(rid, relation);
2916 
2917  if (!PointerIsValid(relation))
2918  return; /* not in cache, nothing to do */
2919 
2920  if (!RelationHasReferenceCountZero(relation))
2921  elog(ERROR, "relation %u is still open", rid);
2922 
2924  if (relation->rd_createSubid != InvalidSubTransactionId ||
2926  {
2927  /*
2928  * In the event of subtransaction rollback, we must not forget
2929  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2930  * invalidates it in lieu of destroying it. (If we're in a top
2931  * transaction, we could opt to destroy the entry.)
2932  */
2934  }
2935 
2936  RelationClearRelation(relation, false);
2937 }

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

5101 {
5102  List *result;
5103  Datum exprsDatum;
5104  bool isnull;
5105  char *exprsString;
5106  List *rawExprs;
5107  ListCell *lc;
5108 
5109  /* Quick exit if there is nothing to do. */
5110  if (relation->rd_indextuple == NULL ||
5111  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5112  return NIL;
5113 
5114  /* Extract raw node tree(s) from index tuple. */
5115  exprsDatum = heap_getattr(relation->rd_indextuple,
5116  Anum_pg_index_indexprs,
5118  &isnull);
5119  Assert(!isnull);
5120  exprsString = TextDatumGetCString(exprsDatum);
5121  rawExprs = (List *) stringToNode(exprsString);
5122  pfree(exprsString);
5123 
5124  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5125  result = NIL;
5126  foreach(lc, rawExprs)
5127  {
5128  Node *rawExpr = (Node *) lfirst(lc);
5129 
5130  result = lappend(result,
5131  makeConst(exprType(rawExpr),
5132  exprTypmod(rawExpr),
5133  exprCollation(rawExpr),
5134  1,
5135  (Datum) 0,
5136  true,
5137  true));
5138  }
5139 
5140  return result;
5141 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4466

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

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

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

4696 {
4697  List *result;
4698  Relation conrel;
4699  SysScanDesc conscan;
4700  ScanKeyData skey;
4701  HeapTuple htup;
4702  List *oldlist;
4703  MemoryContext oldcxt;
4704 
4705  /* Quick exit if we already computed the list. */
4706  if (relation->rd_fkeyvalid)
4707  return relation->rd_fkeylist;
4708 
4709  /* Fast path: non-partitioned tables without triggers can't have FKs */
4710  if (!relation->rd_rel->relhastriggers &&
4711  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4712  return NIL;
4713 
4714  /*
4715  * We build the list we intend to return (in the caller's context) while
4716  * doing the scan. After successfully completing the scan, we copy that
4717  * list into the relcache entry. This avoids cache-context memory leakage
4718  * if we get some sort of error partway through.
4719  */
4720  result = NIL;
4721 
4722  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4723  ScanKeyInit(&skey,
4724  Anum_pg_constraint_conrelid,
4725  BTEqualStrategyNumber, F_OIDEQ,
4726  ObjectIdGetDatum(RelationGetRelid(relation)));
4727 
4728  conrel = table_open(ConstraintRelationId, AccessShareLock);
4729  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4730  NULL, 1, &skey);
4731 
4732  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4733  {
4734  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4735  ForeignKeyCacheInfo *info;
4736 
4737  /* consider only foreign keys */
4738  if (constraint->contype != CONSTRAINT_FOREIGN)
4739  continue;
4740 
4741  info = makeNode(ForeignKeyCacheInfo);
4742  info->conoid = constraint->oid;
4743  info->conrelid = constraint->conrelid;
4744  info->confrelid = constraint->confrelid;
4745 
4746  DeconstructFkConstraintRow(htup, &info->nkeys,
4747  info->conkey,
4748  info->confkey,
4749  info->conpfeqop,
4750  NULL, NULL, NULL, NULL);
4751 
4752  /* Add FK's node to the result list */
4753  result = lappend(result, info);
4754  }
4755 
4756  systable_endscan(conscan);
4757  table_close(conrel, AccessShareLock);
4758 
4759  /* Now save a copy of the completed list in the relcache entry. */
4761  oldlist = relation->rd_fkeylist;
4762  relation->rd_fkeylist = copyObject(result);
4763  relation->rd_fkeyvalid = true;
4764  MemoryContextSwitchTo(oldcxt);
4765 
4766  /* Don't leak the old list, if there is one */
4767  list_free_deep(oldlist);
4768 
4769  return result;
4770 }
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)

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

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

5901 {
5902  MemoryContext oldcxt;
5903  bytea **opts = relation->rd_opcoptions;
5904  Oid relid = RelationGetRelid(relation);
5905  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5906  * IndexRelationGetNumberOfKeyAttributes */
5907  int i;
5908 
5909  /* Try to copy cached options. */
5910  if (opts)
5911  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5912 
5913  /* Get and parse opclass options. */
5914  opts = palloc0(sizeof(*opts) * natts);
5915 
5916  for (i = 0; i < natts; i++)
5917  {
5918  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5919  {
5920  Datum attoptions = get_attoptions(relid, i + 1);
5921 
5922  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5923 
5924  if (attoptions != (Datum) 0)
5925  pfree(DatumGetPointer(attoptions));
5926  }
5927  }
5928 
5929  /* Copy parsed options to the cache. */
5930  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5931  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5932  MemoryContextSwitchTo(oldcxt);
5933 
5934  if (copy)
5935  return opts;
5936 
5937  for (i = 0; i < natts; i++)
5938  {
5939  if (opts[i])
5940  pfree(opts[i]);
5941  }
5942 
5943  pfree(opts);
5944 
5945  return relation->rd_opcoptions;
5946 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:998
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5880

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

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

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

Referenced by 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 5041 of file relcache.c.

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

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

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

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4804 of file relcache.c.

4805 {
4806  Relation indrel;
4807  SysScanDesc indscan;
4808  ScanKeyData skey;
4809  HeapTuple htup;
4810  List *result;
4811  List *oldlist;
4812  char replident = relation->rd_rel->relreplident;
4813  Oid pkeyIndex = InvalidOid;
4814  Oid candidateIndex = InvalidOid;
4815  bool pkdeferrable = false;
4816  MemoryContext oldcxt;
4817 
4818  /* Quick exit if we already computed the list. */
4819  if (relation->rd_indexvalid)
4820  return list_copy(relation->rd_indexlist);
4821 
4822  /*
4823  * We build the list we intend to return (in the caller's context) while
4824  * doing the scan. After successfully completing the scan, we copy that
4825  * list into the relcache entry. This avoids cache-context memory leakage
4826  * if we get some sort of error partway through.
4827  */
4828  result = NIL;
4829 
4830  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4831  ScanKeyInit(&skey,
4832  Anum_pg_index_indrelid,
4833  BTEqualStrategyNumber, F_OIDEQ,
4834  ObjectIdGetDatum(RelationGetRelid(relation)));
4835 
4836  indrel = table_open(IndexRelationId, AccessShareLock);
4837  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4838  NULL, 1, &skey);
4839 
4840  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4841  {
4843 
4844  /*
4845  * Ignore any indexes that are currently being dropped. This will
4846  * prevent them from being searched, inserted into, or considered in
4847  * HOT-safety decisions. It's unsafe to touch such an index at all
4848  * since its catalog entries could disappear at any instant.
4849  */
4850  if (!index->indislive)
4851  continue;
4852 
4853  /* add index's OID to result list */
4854  result = lappend_oid(result, index->indexrelid);
4855 
4856  /*
4857  * Invalid, non-unique, non-immediate or predicate indexes aren't
4858  * interesting for either oid indexes or replication identity indexes,
4859  * so don't check them.
4860  */
4861  if (!index->indisvalid || !index->indisunique ||
4862  !index->indimmediate ||
4863  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4864  continue;
4865 
4866  /* remember primary key index if any */
4867  if (index->indisprimary)
4868  pkeyIndex = index->indexrelid;
4869 
4870  /* remember explicitly chosen replica index */
4871  if (index->indisreplident)
4872  candidateIndex = index->indexrelid;
4873  }
4874 
4875  systable_endscan(indscan);
4876 
4877  table_close(indrel, AccessShareLock);
4878 
4879  /* Sort the result list into OID order, per API spec. */
4880  list_sort(result, list_oid_cmp);
4881 
4882  /* Now save a copy of the completed list in the relcache entry. */
4884  oldlist = relation->rd_indexlist;
4885  relation->rd_indexlist = list_copy(result);
4886  relation->rd_pkindex = pkeyIndex;
4887  relation->rd_ispkdeferrable = pkdeferrable;
4888  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4889  relation->rd_replidindex = pkeyIndex;
4890  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4891  relation->rd_replidindex = candidateIndex;
4892  else
4893  relation->rd_replidindex = InvalidOid;
4894  relation->rd_indexvalid = true;
4895  MemoryContextSwitchTo(oldcxt);
4896 
4897  /* Don't leak the old list, if there is one */
4898  list_free(oldlist);
4899 
4900  return result;
4901 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
bool rd_ispkdeferrable
Definition: rel.h:154
Definition: type.h:95

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

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

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5154 of file relcache.c.

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

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

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4995 of file relcache.c.

4996 {
4997  List *ilist;
4998 
4999  if (!relation->rd_indexvalid)
5000  {
5001  /* RelationGetIndexList does the heavy lifting. */
5002  ilist = RelationGetIndexList(relation);
5003  list_free(ilist);
5004  Assert(relation->rd_indexvalid);
5005  }
5006 
5007  return relation->rd_ispkdeferrable ? InvalidOid : relation->rd_pkindex;
5008 }

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

Referenced by GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5016 of file relcache.c.

5017 {
5018  List *ilist;
5019 
5020  if (!relation->rd_indexvalid)
5021  {
5022  /* RelationGetIndexList does the heavy lifting. */
5023  ilist = RelationGetIndexList(relation);
5024  list_free(ilist);
5025  Assert(relation->rd_indexvalid);
5026  }
5027 
5028  return relation->rd_replidindex;
5029 }

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

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

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4925 of file relcache.c.

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

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

Referenced by expandTableLikeClause(), and get_relation_statistics().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2061 of file relcache.c.

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

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

6731 {
6732  if (relationId == SharedSecLabelRelationId ||
6733  relationId == TriggerRelidNameIndexId ||
6734  relationId == DatabaseNameIndexId ||
6735  relationId == SharedSecLabelObjectIndexId)
6736  {
6737  /*
6738  * If this Assert fails, we don't need the applicable special case
6739  * anymore.
6740  */
6741  Assert(!RelationSupportsSysCache(relationId));
6742  return true;
6743  }
6744  return RelationSupportsSysCache(relationId);
6745 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:766

References Assert, and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationIncrementReferenceCount()

void RelationIncrementReferenceCount ( Relation  rel)

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1424 of file relcache.c.

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

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

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitPhysicalAddr()

static void RelationInitPhysicalAddr ( Relation  relation)
static

Definition at line 1318 of file relcache.c.

1319 {
1320  RelFileNumber oldnumber = relation->rd_locator.relNumber;
1321 
1322  /* these relations kinds never have storage */
1323  if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
1324  return;
1325 
1326  if (relation->rd_rel->reltablespace)
1327  relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
1328  else
1330  if (relation->rd_locator.spcOid == GLOBALTABLESPACE_OID)
1331  relation->rd_locator.dbOid = InvalidOid;
1332  else
1333  relation->rd_locator.dbOid = MyDatabaseId;
1334 
1335  if (relation->rd_rel->relfilenode)
1336  {
1337  /*
1338  * Even if we are using a decoding snapshot that doesn't represent the
1339  * current state of the catalog we need to make sure the filenode
1340  * points to the current file since the older file will be gone (or
1341  * truncated). The new file will still contain older rows so lookups
1342  * in them will work correctly. This wouldn't work correctly if
1343  * rewrites were allowed to change the schema in an incompatible way,
1344  * but those are prevented both on catalog tables and on user tables
1345  * declared as additional catalog tables.
1346  */
1349  && IsTransactionState())
1350  {
1351  HeapTuple phys_tuple;
1352  Form_pg_class physrel;
1353 
1354  phys_tuple = ScanPgRelation(RelationGetRelid(relation),
1355  RelationGetRelid(relation) != ClassOidIndexId,
1356  true);
1357  if (!HeapTupleIsValid(phys_tuple))
1358  elog(ERROR, "could not find pg_class entry for %u",
1359  RelationGetRelid(relation));
1360  physrel = (Form_pg_class) GETSTRUCT(phys_tuple);
1361 
1362  relation->rd_rel->reltablespace = physrel->reltablespace;
1363  relation->rd_rel->relfilenode = physrel->relfilenode;
1364  heap_freetuple(phys_tuple);
1365  }
1366 
1367  relation->rd_locator.relNumber = relation->rd_rel->relfilenode;
1368  }
1369  else
1370  {
1371  /* Consult the relation mapper */
1372  relation->rd_locator.relNumber =
1374  relation->rd_rel->relisshared);
1375  if (!RelFileNumberIsValid(relation->rd_locator.relNumber))
1376  elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1377  RelationGetRelationName(relation), relation->rd_id);
1378  }
1379 
1380  /*
1381  * For RelationNeedsWAL() to answer correctly on parallel workers, restore
1382  * rd_firstRelfilelocatorSubid. No subtransactions start or end while in
1383  * parallel mode, so the specific SubTransactionId does not matter.
1384  */
1385  if (IsParallelWorker() && oldnumber != relation->rd_locator.relNumber)
1386  {
1387  if (RelFileLocatorSkippingWAL(relation->rd_locator))
1389  else
1391  }
1392 }
#define TopSubTransactionId
Definition: c.h:650
Oid MyDatabaseTableSpace
Definition: globals.c:95
Oid MyDatabaseId
Definition: globals.c:93
#define IsParallelWorker()
Definition: parallel.h:60
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool RelFileLocatorSkippingWAL(RelFileLocator rlocator)
Definition: storage.c:532
RelFileNumber relNumber
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

References RelFileLocator::dbOid, elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, HistoricSnapshotActive(), InvalidOid, InvalidSubTransactionId, IsParallelWorker, IsTransactionState(), MyDatabaseId, MyDatabaseTableSpace, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_id, RelationData::rd_locator, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationMapOidToFilenumber(), RelFileLocatorSkippingWAL(), RelFileNumberIsValid, RelFileLocator::relNumber, ScanPgRelation(), RelFileLocator::spcOid, and TopSubTransactionId.

Referenced by formrdesc(), load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), RelationCacheInvalidate(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1808 of file relcache.c.

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

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

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

◆ RelationInvalidateRelation()

static void RelationInvalidateRelation ( Relation  relation)
static

Definition at line 2520 of file relcache.c.

2521 {
2522  /*
2523  * Make sure smgr and lower levels close the relation's files, if they
2524  * weren't closed already. If the relation is not getting deleted, the
2525  * next smgr access should reopen the files automatically. This ensures
2526  * that the low-level file access state is updated after, say, a vacuum
2527  * truncation.
2528  */
2529  RelationCloseSmgr(relation);
2530 
2531  /* Free AM cached data, if any */
2532  if (relation->rd_amcache)
2533  pfree(relation->rd_amcache);
2534  relation->rd_amcache = NULL;
2535 
2536  relation->rd_isvalid = false;
2537 }

References pfree(), RelationData::rd_amcache, RelationData::rd_isvalid, and RelationCloseSmgr().

Referenced by RelationFlushRelation().

◆ RelationParseRelOptions()

static void RelationParseRelOptions ( Relation  relation,
HeapTuple  tuple 
)
static

Definition at line 464 of file relcache.c.

465 {
466  bytea *options;
467  amoptions_function amoptsfn;
468 
469  relation->rd_options = NULL;
470 
471  /*
472  * Look up any AM-specific parse function; fall out if relkind should not
473  * have options.
474  */
475  switch (relation->rd_rel->relkind)
476  {
477  case RELKIND_RELATION:
478  case RELKIND_TOASTVALUE:
479  case RELKIND_VIEW:
480  case RELKIND_MATVIEW:
481  case RELKIND_PARTITIONED_TABLE:
482  amoptsfn = NULL;
483  break;
484  case RELKIND_INDEX:
485  case RELKIND_PARTITIONED_INDEX:
486  amoptsfn = relation->rd_indam->amoptions;
487  break;
488  default:
489  return;
490  }
491 
492  /*
493  * Fetch reloptions from tuple; have to use a hardwired descriptor because
494  * we might not have any other for pg_class yet (consider executing this
495  * code for pg_class itself)
496  */
497  options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
498 
499  /*
500  * Copy parsed data into CacheMemoryContext. To guard against the
501  * possibility of leaks in the reloptions code, we want to do the actual
502  * parsing in the caller's memory context and copy the results into
503  * CacheMemoryContext after the fact.
504  */
505  if (options)
506  {
508  VARSIZE(options));
509  memcpy(relation->rd_options, options, VARSIZE(options));
510  pfree(options);
511  }
512 }
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:151
static char ** options
static TupleDesc GetPgClassDescriptor(void)
Definition: relcache.c:4453
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
Definition: reloptions.c:1379
amoptions_function amoptions
Definition: amapi.h:283

References IndexAmRoutine::amoptions, CacheMemoryContext, extractRelOptions(), GetPgClassDescriptor(), MemoryContextAlloc(), options, pfree(), RelationData::rd_indam, RelationData::rd_options, RelationData::rd_rel, and VARSIZE.

Referenced by RelationBuildDesc(), RelationCacheInitializePhase3(), and RelationReloadIndexInfo().

◆ RelationReloadIndexInfo()

static void RelationReloadIndexInfo ( Relation  relation)
static

Definition at line 2255 of file relcache.c.

2256 {
2257  bool indexOK;
2258  HeapTuple pg_class_tuple;
2259  Form_pg_class relp;
2260 
2261  /* Should be called only for invalidated, live indexes */
2262  Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
2263  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2264  !relation->rd_isvalid &&
2266 
2267  /* Ensure it's closed at smgr level */
2268  RelationCloseSmgr(relation);
2269 
2270  /* Must free any AM cached data upon relcache flush */
2271  if (relation->rd_amcache)
2272  pfree(relation->rd_amcache);
2273  relation->rd_amcache = NULL;
2274 
2275  /*
2276  * If it's a shared index, we might be called before backend startup has
2277  * finished selecting a database, in which case we have no way to read
2278  * pg_class yet. However, a shared index can never have any significant
2279  * schema updates, so it's okay to ignore the invalidation signal. Just
2280  * mark it valid and return without doing anything more.
2281  */
2282  if (relation->rd_rel->relisshared && !criticalRelcachesBuilt)
2283  {
2284  relation->rd_isvalid = true;
2285  return;
2286  }
2287 
2288  /*
2289  * Read the pg_class row
2290  *
2291  * Don't try to use an indexscan of pg_class_oid_index to reload the info
2292  * for pg_class_oid_index ...
2293  */
2294  indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
2295  pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK, false);
2296  if (!HeapTupleIsValid(pg_class_tuple))
2297  elog(ERROR, "could not find pg_class tuple for index %u",
2298  RelationGetRelid(relation));
2299  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2300  memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2301  /* Reload reloptions in case they changed */
2302  if (relation->rd_options)
2303  pfree(relation->rd_options);
2304  RelationParseRelOptions(relation, pg_class_tuple);
2305  /* done with pg_class tuple */
2306  heap_freetuple(pg_class_tuple);
2307  /* We must recalculate physical address in case it changed */
2308  RelationInitPhysicalAddr(relation);
2309 
2310  /*
2311  * For a non-system index, there are fields of the pg_index row that are
2312  * allowed to change, so re-read that row and update the relcache entry.
2313  * Most of the info derived from pg_index (such as support function lookup
2314  * info) cannot change, and indeed the whole point of this routine is to
2315  * update the relcache entry without clobbering that data; so wholesale
2316  * replacement is not appropriate.
2317  */
2318  if (!IsSystemRelation(relation))
2319  {
2320  HeapTuple tuple;
2322 
2323  tuple = SearchSysCache1(INDEXRELID,
2324  ObjectIdGetDatum(RelationGetRelid(relation)));
2325  if (!HeapTupleIsValid(tuple))
2326  elog(ERROR, "cache lookup failed for index %u",
2327  RelationGetRelid(relation));
2328  index = (Form_pg_index) GETSTRUCT(tuple);
2329 
2330  /*
2331  * Basically, let's just copy all the bool fields. There are one or
2332  * two of these that can't actually change in the current code, but
2333  * it's not worth it to track exactly which ones they are. None of
2334  * the array fields are allowed to change, though.
2335  */
2336  relation->rd_index->indisunique = index->indisunique;
2337  relation->rd_index->indnullsnotdistinct = index->indnullsnotdistinct;
2338  relation->rd_index->indisprimary = index->indisprimary;
2339  relation->rd_index->indisexclusion = index->indisexclusion;
2340  relation->rd_index->indimmediate = index->indimmediate;
2341  relation->rd_index->indisclustered = index->indisclustered;
2342  relation->rd_index->indisvalid = index->indisvalid;
2343  relation->rd_index->indcheckxmin = index->indcheckxmin;
2344  relation->rd_index->indisready = index->indisready;
2345  relation->rd_index->indislive = index->indislive;
2346  relation->rd_index->indisreplident = index->indisreplident;
2347 
2348  /* Copy xmin too, as that is needed to make sense of indcheckxmin */
2350  HeapTupleHeaderGetXmin(tuple->t_data));
2351 
2352  ReleaseSysCache(tuple);
2353  }
2354 
2355  /* Okay, now it's valid again */
2356  relation->rd_isvalid = true;
2357 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:315
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309

References Assert, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleHeaderGetXmin, HeapTupleHeaderSetXmin, HeapTupleIsValid, InvalidSubTransactionId, IsSystemRelation(), ObjectIdGetDatum(), pfree(), RelationData::rd_amcache, RelationData::rd_droppedSubid, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_isvalid, RelationData::rd_options, RelationData::rd_rel, RelationCloseSmgr(), RelationGetRelid, RelationInitPhysicalAddr(), RelationParseRelOptions(), ReleaseSysCache(), ScanPgRelation(), SearchSysCache1(), and HeapTupleData::t_data.

Referenced by RelationClearRelation(), RelationIdGetRelation(), and RelationReloadNailed().

◆ RelationReloadNailed()

static void RelationReloadNailed ( Relation  relation)
static

Definition at line 2369 of file relcache.c.

2370 {
2371  Assert(relation->rd_isnailed);
2372 
2373  /*
2374  * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2375  * mapping changed.
2376  */
2377  RelationInitPhysicalAddr(relation);
2378 
2379  /* flag as needing to be revalidated */
2380  relation->rd_isvalid = false;
2381 
2382  /*
2383  * Can only reread catalog contents if in a transaction. If the relation
2384  * is currently open (not counting the nailed refcount), do so
2385  * immediately. Otherwise we've already marked the entry as possibly
2386  * invalid, and it'll be fixed when next opened.
2387  */
2388  if (!IsTransactionState() || relation->rd_refcnt <= 1)
2389  return;
2390 
2391  if (relation->rd_rel->relkind == RELKIND_INDEX)
2392  {
2393  /*
2394  * If it's a nailed-but-not-mapped index, then we need to re-read the
2395  * pg_class row to see if its relfilenumber changed.
2396  */
2397  RelationReloadIndexInfo(relation);
2398  }
2399  else
2400  {
2401  /*
2402  * Reload a non-index entry. We can't easily do so if relcaches
2403  * aren't yet built, but that's fine because at that stage the
2404  * attributes that need to be current (like relfrozenxid) aren't yet
2405  * accessed. To ensure the entry will later be revalidated, we leave
2406  * it in invalid state, but allow use (cf. RelationIdGetRelation()).
2407  */
2409  {
2410  HeapTuple pg_class_tuple;
2411  Form_pg_class relp;
2412 
2413  /*
2414  * NB: Mark the entry as valid before starting to scan, to avoid
2415  * self-recursion when re-building pg_class.
2416  */
2417  relation->rd_isvalid = true;
2418 
2419  pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
2420  true, false);
2421  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2422  memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2423  heap_freetuple(pg_class_tuple);
2424 
2425  /*
2426  * Again mark as valid, to protect against concurrently arriving
2427  * invalidations.
2428  */
2429  relation->rd_isvalid = true;
2430  }
2431  }
2432 }

References Assert, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, GETSTRUCT, heap_freetuple(), IsTransactionState(), RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_refcnt, RelationData::rd_rel, RelationGetRelid, RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and ScanPgRelation().

Referenced by RelationClearRelation().

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3767 of file relcache.c.

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

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

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

◆ RememberToFreeTupleDescAtEOX()

static void RememberToFreeTupleDescAtEOX ( TupleDesc  td)
static

Definition at line 3113 of file relcache.c.

3114 {
3115  if (EOXactTupleDescArray == NULL)
3116  {
3117  MemoryContext oldcxt;
3118 
3120 
3121  EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3124  MemoryContextSwitchTo(oldcxt);
3125  }
3127  {
3128  int32 newlen = EOXactTupleDescArrayLen * 2;
3129 
3131 
3133  newlen * sizeof(TupleDesc));
3134  EOXactTupleDescArrayLen = newlen;
3135  }
3136 
3138 }
signed int int32
Definition: c.h:496

References Assert, CacheMemoryContext, EOXactTupleDescArray, EOXactTupleDescArrayLen, MemoryContextSwitchTo(), NextEOXactTupleDescNum, palloc(), and repalloc().

Referenced by RelationDestroyRelation().

◆ ResourceOwnerForgetRelationRef()

static void ResourceOwnerForgetRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2145 of file relcache.c.

2146 {
2148 }
static const ResourceOwnerDesc relref_resowner_desc
Definition: relcache.c:2129
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerForget().

Referenced by RelationDecrementReferenceCount().

◆ ResourceOwnerRememberRelationRef()

static void ResourceOwnerRememberRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2140 of file relcache.c.

2141 {
2143 }
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerRemember().

Referenced by RelationIncrementReferenceCount().

◆ ResOwnerPrintRelCache()

static char * ResOwnerPrintRelCache ( Datum  res)
static

Definition at line 6884 of file relcache.c.

6885 {
6887 
6888  return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6889 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

References DatumGetPointer(), psprintf(), RelationGetRelationName, and res.

◆ ResOwnerReleaseRelation()

static void ResOwnerReleaseRelation ( Datum  res)
static

Definition at line 6892 of file relcache.c.

6893 {
6895 
6896  /*
6897  * This reference has already been removed from the resource owner, so
6898  * just decrement reference count without calling
6899  * ResourceOwnerForgetRelationRef.
6900  */
6901  Assert(rel->rd_refcnt > 0);
6902  rel->rd_refcnt -= 1;
6903 
6905 }

References Assert, DatumGetPointer(), RelationData::rd_refcnt, RelationCloseCleanup(), and res.

◆ ScanPgRelation()

static HeapTuple ScanPgRelation ( Oid  targetRelId,
bool  indexOK,
bool  force_non_historic 
)
static

Definition at line 339 of file relcache.c.

340 {
341  HeapTuple pg_class_tuple;
342  Relation pg_class_desc;
343  SysScanDesc pg_class_scan;
344  ScanKeyData key[1];
345  Snapshot snapshot = NULL;
346 
347  /*
348  * If something goes wrong during backend startup, we might find ourselves
349  * trying to read pg_class before we've selected a database. That ain't
350  * gonna work, so bail out with a useful error message. If this happens,
351  * it probably means a relcache entry that needs to be nailed isn't.
352  */
353  if (!OidIsValid(MyDatabaseId))
354  elog(FATAL, "cannot read pg_class without having selected a database");
355 
356  /*
357  * form a scan key
358  */
359  ScanKeyInit(&key[0],
360  Anum_pg_class_oid,
361  BTEqualStrategyNumber, F_OIDEQ,
362  ObjectIdGetDatum(targetRelId));
363 
364  /*
365  * Open pg_class and fetch a tuple. Force heap scan if we haven't yet
366  * built the critical relcache entries (this includes initdb and startup
367  * without a pg_internal.init file). The caller can also force a heap
368  * scan by setting indexOK == false.
369  */
370  pg_class_desc = table_open(RelationRelationId, AccessShareLock);
371 
372  /*
373  * The caller might need a tuple that's newer than the one the historic
374  * snapshot; currently the only case requiring to do so is looking up the
375  * relfilenumber of non mapped system relations during decoding. That
376  * snapshot can't change in the midst of a relcache build, so there's no
377  * need to register the snapshot.
378  */
379  if (force_non_historic)
380  snapshot = GetNonHistoricCatalogSnapshot(RelationRelationId);
381 
382  pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
383  indexOK && criticalRelcachesBuilt,
384  snapshot,
385  1, key);
386 
387  pg_class_tuple = systable_getnext(pg_class_scan);
388 
389  /*
390  * Must copy tuple before releasing buffer.
391  */
392  if (HeapTupleIsValid(pg_class_tuple))
393  pg_class_tuple = heap_copytuple(pg_class_tuple);
394 
395  /* all done */
396  systable_endscan(pg_class_scan);
397  table_close(pg_class_desc, AccessShareLock);
398 
399  return pg_class_tuple;
400 }
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:374

References AccessShareLock, BTEqualStrategyNumber, criticalRelcachesBuilt, elog, FATAL, GetNonHistoricCatalogSnapshot(), heap_copytuple(), HeapTupleIsValid, sort-test::key, MyDatabaseId, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by RelationBuildDesc(), RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ unlink_initfile()

static void unlink_initfile ( const char *  initfilename,
int  elevel 
)
static

Definition at line 6867 of file relcache.c.

6868 {
6869  if (unlink(initfilename) < 0)
6870  {
6871  /* It might not be there, but log any error other than ENOENT */
6872  if (errno != ENOENT)
6873  ereport(elevel,
6875  errmsg("could not remove cache file \"%s\": %m",
6876  initfilename)));
6877  }
6878 }
int errcode_for_file_access(void)
Definition: elog.c:876

References ereport, errcode_for_file_access(), and errmsg().

Referenced by RelationCacheInitFilePreInvalidate(), RelationCacheInitFileRemove(), and RelationCacheInitFileRemoveInDir().

◆ write_item()

static void write_item ( const void *  data,
Size  len,
FILE *  fp 
)
static

Definition at line 6707 of file relcache.c.

6708 {
6709  if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6710  ereport(FATAL,
6712  errmsg_internal("could not write init file: %m"));
6713  if (len > 0 && fwrite(data, 1, len, fp) != len)
6714  ereport(FATAL,
6716  errmsg_internal("could not write init file: %m"));
6717 }
const void * data

References data, ereport, errcode_for_file_access(), errmsg_internal(), FATAL, and len.

Referenced by write_relcache_init_file().

◆ write_relcache_init_file()

static void write_relcache_init_file ( bool  shared)
static

Definition at line 6495 of file relcache.c.

6496 {
6497  FILE *fp;
6498  char tempfilename[MAXPGPATH];
6499  char finalfilename[MAXPGPATH];
6500  int magic;
6501  HASH_SEQ_STATUS status;
6502  RelIdCacheEnt *idhentry;
6503  int i;
6504 
6505  /*
6506  * If we have already received any relcache inval events, there's no
6507  * chance of succeeding so we may as well skip the whole thing.
6508  */
6509  if (relcacheInvalsReceived != 0L)
6510  return;
6511 
6512  /*
6513  * We must write a temporary file and rename it into place. Otherwise,
6514  * another backend starting at about the same time might crash trying to
6515  * read the partially-complete file.
6516  */
6517  if (shared)
6518  {
6519  snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d",
6521  snprintf(finalfilename, sizeof(finalfilename), "global/%s",
6523  }
6524  else
6525  {
6526  snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
6528  snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
6530  }
6531 
6532  unlink(tempfilename); /* in case it exists w/wrong permissions */
6533 
6534  fp = AllocateFile(tempfilename, PG_BINARY_W);
6535  if (fp == NULL)
6536  {
6537  /*
6538  * We used to consider this a fatal error, but we might as well
6539  * continue with backend startup ...
6540  */
6541  ereport(WARNING,
6543  errmsg("could not create relation-cache initialization file \"%s\": %m",
6544  tempfilename),
6545  errdetail("Continuing anyway, but there's something wrong.")));
6546  return;
6547  }
6548 
6549  /*
6550  * Write a magic number to serve as a file version identifier. We can
6551  * change the magic number whenever the relcache layout changes.
6552  */
6553  magic = RELCACHE_INIT_FILEMAGIC;
6554  if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6555  ereport(FATAL,
6557  errmsg_internal("could not write init file: %m"));
6558 
6559  /*
6560  * Write all the appropriate reldescs (in no particular order).
6561  */
6562  hash_seq_init(&status, RelationIdCache);
6563 
6564  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
6565  {
6566  Relation rel = idhentry->reldesc;
6567  Form_pg_class relform = rel->rd_rel;
6568 
6569  /* ignore if not correct group */
6570  if (relform->relisshared != shared)
6571  continue;
6572 
6573  /*
6574  * Ignore if not supposed to be in init file. We can allow any shared
6575  * relation that's been loaded so far to be in the shared init file,
6576  * but unshared relations must be ones that should be in the local
6577  * file per RelationIdIsInInitFile. (Note: if you want to change the
6578  * criterion for rels to be kept in the init file, see also inval.c.
6579  * The reason for filtering here is to be sure that we don't put
6580  * anything into the local init file for which a relcache inval would
6581  * not cause invalidation of that init file.)
6582  */
6583  if (!shared && !RelationIdIsInInitFile(RelationGetRelid(rel)))
6584  {
6585  /* Nailed rels had better get stored. */
6586  Assert(!rel->rd_isnailed);
6587  continue;
6588  }
6589 
6590  /* first write the relcache entry proper */
6591  write_item(rel, sizeof(RelationData), fp);
6592 
6593  /* next write the relation tuple form */
6594  write_item(relform, CLASS_TUPLE_SIZE, fp);
6595 
6596  /* next, do all the attribute tuple form data entries */
6597  for (i = 0; i < relform->relnatts; i++)
6598  {
6601  }
6602 
6603  /* next, do the access method specific field */
6604  write_item(rel->rd_options,
6605  (rel->rd_options ? VARSIZE(rel->rd_options) : 0),
6606  fp);
6607 
6608  /*
6609  * If it's an index, there's more to do. Note we explicitly ignore
6610  * partitioned indexes here.
6611  */
6612  if (rel->rd_rel->relkind == RELKIND_INDEX)
6613  {
6614  /* write the pg_index tuple */
6615  /* we assume this was created by heap_copytuple! */
6618  fp);
6619 
6620  /* write the vector of opfamily OIDs */
6621  write_item(rel->rd_opfamily,
6622  relform->relnatts * sizeof(Oid),
6623  fp);
6624 
6625  /* write the vector of opcintype OIDs */
6626  write_item(rel->rd_opcintype,
6627  relform->relnatts * sizeof(Oid),
6628  fp);
6629 
6630  /* write the vector of support procedure OIDs */
6631  write_item(rel->rd_support,
6632  relform->relnatts * (rel->rd_indam->amsupport * sizeof(RegProcedure)),
6633  fp);
6634 
6635  /* write the vector of collation OIDs */
6637  relform->relnatts * sizeof(Oid),
6638  fp);
6639 
6640  /* write the vector of indoption values */
6641  write_item(rel->rd_indoption,
6642  relform->relnatts * sizeof(int16),
6643  fp);
6644 
6645  Assert(rel->rd_opcoptions);
6646 
6647  /* write the vector of opcoptions values */
6648  for (i = 0; i < relform->relnatts; i++)
6649  {
6650  bytea *opt = rel->rd_opcoptions[i];
6651 
6652  write_item(opt, opt ? VARSIZE(opt) : 0, fp);
6653  }
6654  }
6655  }
6656 
6657  if (FreeFile(fp))
6658  ereport(FATAL,
6660  errmsg_internal("could not write init file: %m"));
6661 
6662  /*
6663  * Now we have to check whether the data we've so painstakingly
6664  * accumulated is already obsolete due to someone else's just-committed
6665  * catalog changes. If so, we just delete the temp file and leave it to
6666  * the next backend to try again. (Our own relcache entries will be
6667  * updated by SI message processing, but we can't be sure whether what we
6668  * wrote out was up-to-date.)
6669  *
6670  * This mustn't run concurrently with the code that unlinks an init file
6671  * and sends SI messages, so grab a serialization lock for the duration.
6672  */
6673  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6674 
6675  /* Make sure we have seen all incoming SI messages */
6677 
6678  /*
6679  * If we have received any SI relcache invals since backend start, assume
6680  * we may have written out-of-date data.
6681  */
6682  if (relcacheInvalsReceived == 0L)
6683  {
6684  /*
6685  * OK, rename the temp file to its final name, deleting any
6686  * previously-existing init file.
6687  *
6688  * Note: a failure here is possible under Cygwin, if some other
6689  * backend is holding open an unlinked-but-not-yet-gone init file. So
6690  * treat this as a noncritical failure; just remove the useless temp
6691  * file on failure.
6692  */
6693  if (rename(tempfilename, finalfilename) < 0)
6694  unlink(tempfilename);
6695  }
6696  else
6697  {
6698  /* Delete the already-obsolete temp file */
6699  unlink(tempfilename);
6700  }
6701 
6702  LWLockRelease(RelCacheInitLock);
6703 }
#define PG_BINARY_W
Definition: c.h:1267
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int MyProcPid
Definition: globals.c:46
void AcceptInvalidationMessages(void)
Definition: inval.c:806
static void write_item(const void *data, Size len, FILE *fp)
Definition: relcache.c:6707
bool RelationIdIsInInitFile(Oid relationId)
Definition: relcache.c:6730
uint32 t_len
Definition: htup.h:64

References AcceptInvalidationMessages(), AllocateFile(), IndexAmRoutine::amsupport, Assert, ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, DatabasePath, ereport, errcode_for_file_access(), errdetail(), errmsg(), errmsg_internal(), FATAL, FreeFile(), hash_seq_init(), hash_seq_search(), HEAPTUPLESIZE, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, MyProcPid, PG_BINARY_W, RelationData::rd_att, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_isnailed, RelationData::rd_opcintype, RelationData::rd_opcoptions, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_support, RelationGetRelid, RelationIdCache, RelationIdIsInInitFile(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, relcacheInvalsReceived, relidcacheent::reldesc, snprintf, HeapTupleData::t_len, TupleDescAttr, VARSIZE, WARNING, and write_item().

Referenced by RelationCacheInitializePhase3().

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

◆ Desc_pg_attribute

const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}
static

Definition at line 112 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_auth_members

const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members}
static

Definition at line 117 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_authid

const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid}
static

Definition at line 116 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_class

const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}
static

Definition at line 111 of file relcache.c.

Referenced by GetPgClassDescriptor(), and RelationCacheInitializePhase3().

◆ Desc_pg_database

const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database}
static

Definition at line 115 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_index

const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}
static

Definition at line 118 of file relcache.c.

Referenced by GetPgIndexDescriptor().

◆ Desc_pg_proc

const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}
static

Definition at line 113 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_shseclabel

const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel] = {Schema_pg_shseclabel}
static

Definition at line 119 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_subscription

const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription] = {Schema_pg_subscription}
static

Definition at line 120 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_type

const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}
static

Definition at line 114 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ eoxact_list

Oid eoxact_list[MAX_EOXACT_LIST]
static

Definition at line 185 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_len

int eoxact_list_len = 0
static

Definition at line 186 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_overflowed

bool eoxact_list_overflowed = false
static

Definition at line 187 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ EOXactTupleDescArray

TupleDesc* EOXactTupleDescArray
static

Definition at line 202 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ EOXactTupleDescArrayLen

int EOXactTupleDescArrayLen = 0
static

Definition at line 204 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ in_progress_list

◆ in_progress_list_len

◆ in_progress_list_maxlen

int in_progress_list_maxlen
static

Definition at line 172 of file relcache.c.

Referenced by RelationBuildDesc(), and RelationCacheInitialize().

◆ NextEOXactTupleDescNum

int NextEOXactTupleDescNum = 0
static

Definition at line 203 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ OpClassCache

HTAB* OpClassCache = NULL
static

Definition at line 271 of file relcache.c.

Referenced by LookupOpclassInfo().

◆ RelationIdCache

◆ relcacheInvalsReceived

long relcacheInvalsReceived = 0L
static

◆ relref_resowner_desc

const ResourceOwnerDesc relref_resowner_desc
static
Initial value:
=
{
.name = "relcache reference",
.release_priority = RELEASE_PRIO_RELCACHE_REFS,
.ReleaseResource = ResOwnerReleaseRelation,
.DebugPrint = ResOwnerPrintRelCache
}
static void ResOwnerReleaseRelation(Datum res)
Definition: relcache.c:6892
static char * ResOwnerPrintRelCache(Datum res)
Definition: relcache.c:6884
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
#define RELEASE_PRIO_RELCACHE_REFS
Definition: resowner.h:64

Definition at line 2129 of file relcache.c.

Referenced by ResourceOwnerForgetRelationRef(), and ResourceOwnerRememberRelationRef().