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 3989 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:454
#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:658
#define Assert(condition)
Definition: c.h:858
#define elog(elevel,...)
Definition: elog.h:224
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:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c: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 4565 of file relcache.c.

4566 {
4567  const AttrDefault *ada = (const AttrDefault *) a;
4568  const AttrDefault *adb = (const AttrDefault *) b;
4569 
4570  return pg_cmp_s16(ada->adnum, adb->adnum);
4571 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:471
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 4485 of file relcache.c.

4486 {
4487  AttrDefault *attrdef;
4488  Relation adrel;
4489  SysScanDesc adscan;
4490  ScanKeyData skey;
4491  HeapTuple htup;
4492  int found = 0;
4493 
4494  /* Allocate array with room for as many entries as expected */
4495  attrdef = (AttrDefault *)
4497  ndef * sizeof(AttrDefault));
4498 
4499  /* Search pg_attrdef for relevant entries */
4500  ScanKeyInit(&skey,
4501  Anum_pg_attrdef_adrelid,
4502  BTEqualStrategyNumber, F_OIDEQ,
4503  ObjectIdGetDatum(RelationGetRelid(relation)));
4504 
4505  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4506  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4507  NULL, 1, &skey);
4508 
4509  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4510  {
4511  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4512  Datum val;
4513  bool isnull;
4514 
4515  /* protect limited size of array */
4516  if (found >= ndef)
4517  {
4518  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4519  adform->adnum, RelationGetRelationName(relation));
4520  break;
4521  }
4522 
4523  val = fastgetattr(htup,
4524  Anum_pg_attrdef_adbin,
4525  adrel->rd_att, &isnull);
4526  if (isnull)
4527  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4528  adform->adnum, RelationGetRelationName(relation));
4529  else
4530  {
4531  /* detoast and convert to cstring in caller's context */
4532  char *s = TextDatumGetCString(val);
4533 
4534  attrdef[found].adnum = adform->adnum;
4535  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4536  pfree(s);
4537  found++;
4538  }
4539  }
4540 
4541  systable_endscan(adscan);
4542  table_close(adrel, AccessShareLock);
4543 
4544  if (found != ndef)
4545  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4546  ndef - found, RelationGetRelationName(relation));
4547 
4548  /*
4549  * Sort the AttrDefault entries by adnum, for the convenience of
4550  * equalTupleDescs(). (Usually, they already will be in order, but this
4551  * might not be so if systable_getnext isn't using an index.)
4552  */
4553  if (found > 1)
4554  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4555 
4556  /* Install array only after it's fully valid */
4557  relation->rd_att->constr->defval = attrdef;
4558  relation->rd_att->constr->num_defval = found;
4559 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#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:670
#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:453
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:4565
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 4420 of file relcache.c.

4421 {
4422  TupleDesc result;
4423  MemoryContext oldcxt;
4424  int i;
4425 
4427 
4428  result = CreateTemplateTupleDesc(natts);
4429  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4430  result->tdtypmod = -1;
4431 
4432  for (i = 0; i < natts; i++)
4433  {
4434  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4435  /* make sure attcacheoff is valid */
4436  TupleDescAttr(result, i)->attcacheoff = -1;
4437  }
4438 
4439  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4440  TupleDescAttr(result, 0)->attcacheoff = 0;
4441 
4442  /* Note: we don't bother to set up a TupleConstr entry */
4443 
4444  MemoryContextSwitchTo(oldcxt);
4445 
4446  return result;
4447 }
#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 4669 of file relcache.c.

4670 {
4671  const ConstrCheck *ca = (const ConstrCheck *) a;
4672  const ConstrCheck *cb = (const ConstrCheck *) b;
4673 
4674  return strcmp(ca->ccname, cb->ccname);
4675 }
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 4580 of file relcache.c.

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

5872 {
5873  bytea **opts = palloc(sizeof(*opts) * natts);
5874 
5875  for (int i = 0; i < natts; i++)
5876  {
5877  bytea *opt = srcopts[i];
5878 
5879  opts[i] = !opt ? NULL : (bytea *)
5880  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5881  }
5882 
5883  return opts;
5884 }
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:687

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

5953 {
5957 
5958  return 0; /* return value does not matter */
5959 }
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(), ExecPartitionCheckEmitError(), and moveSplitTableRows().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5969 of file relcache.c.

5970 {
5971  TupleDesc reldesc = RelationGetDescr(rel);
5972  const char *colname;
5973 
5974  /* Use reldesc if it's a user attribute, else consult the catalogs */
5975  if (attnum > 0 && attnum <= reldesc->natts)
5976  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5977  else
5978  colname = get_attname(RelationGetRelid(rel), attnum, false);
5979 
5980  return errtablecolname(rel, colname);
5981 }
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:5993

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

5994 {
5995  errtable(rel);
5997 
5998  return 0; /* return value does not matter */
5999 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5952

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:493
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 4450 of file relcache.c.

4451 {
4452  static TupleDesc pgclassdesc = NULL;
4453 
4454  /* Already done? */
4455  if (pgclassdesc == NULL)
4456  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4457  Desc_pg_class);
4458 
4459  return pgclassdesc;
4460 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4420
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 4463 of file relcache.c.

4464 {
4465  static TupleDesc pgindexdesc = NULL;
4466 
4467  /* Already done? */
4468  if (pgindexdesc == NULL)
4469  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4470  Desc_pg_index);
4471 
4472  return pgindexdesc;
4473 }
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:650
#define OidIsValid(objectId)
Definition: c.h:775
#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:733
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 4382 of file relcache.c.

4383 {
4384  Relation ird;
4385 
4386  /*
4387  * We must lock the underlying catalog before locking the index to avoid
4388  * deadlock, since RelationBuildDesc might well need to read the catalog,
4389  * and if anyone else is exclusive-locking this catalog and index they'll
4390  * be doing it in that order.
4391  */
4392  LockRelationOid(heapoid, AccessShareLock);
4393  LockRelationOid(indexoid, AccessShareLock);
4394  ird = RelationBuildDesc(indexoid, true);
4395  if (ird == NULL)
4396  ereport(PANIC,
4398  errmsg_internal("could not open critical system index %u", indexoid));
4399  ird->rd_isnailed = true;
4400  ird->rd_refcnt = 1;
4403 
4404  (void) RelationGetIndexAttOptions(ird, false);
4405 }
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:5891

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

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

3967 {
3971 
3972  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3973  EOXactListAdd(relation);
3974 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:789

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:3658
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3751
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
#define ProcNumberForTempRelations()
Definition: proc.h:319
#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:1856

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:203
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:264
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 5723 of file relcache.c.

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

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

Referenced by CheckCmdReplicaIdentity().

◆ 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:4485
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4580
#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 6786 of file relcache.c.

6787 {
6788  LWLockRelease(RelCacheInitLock);
6789 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6761 of file relcache.c.

6762 {
6763  char localinitfname[MAXPGPATH];
6764  char sharedinitfname[MAXPGPATH];
6765 
6766  if (DatabasePath)
6767  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6769  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6771 
6772  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6773 
6774  /*
6775  * The files might not be there if no backend has been started since the
6776  * last removal. But complain about failures other than ENOENT with
6777  * ERROR. Fortunately, it's not too late to abort the transaction if we
6778  * can't get rid of the would-be-obsolete init file.
6779  */
6780  if (DatabasePath)
6781  unlink_initfile(localinitfname, ERROR);
6782  unlink_initfile(sharedinitfname, ERROR);
6783 }
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:6858

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

6802 {
6803  const char *tblspcdir = "pg_tblspc";
6804  DIR *dir;
6805  struct dirent *de;
6806  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6807 
6808  snprintf(path, sizeof(path), "global/%s",
6810  unlink_initfile(path, LOG);
6811 
6812  /* Scan everything in the default tablespace */
6814 
6815  /* Scan the tablespace link directory to find non-default tablespaces */
6816  dir = AllocateDir(tblspcdir);
6817 
6818  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6819  {
6820  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6821  {
6822  /* Scan the tablespace dir for per-database dirs */
6823  snprintf(path, sizeof(path), "%s/%s/%s",
6824  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6826  }
6827  }
6828 
6829  FreeDir(dir);
6830 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2961
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2924
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6834
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6834 of file relcache.c.

6835 {
6836  DIR *dir;
6837  struct dirent *de;
6838  char initfilename[MAXPGPATH * 2];
6839 
6840  /* Scan the tablespace directory to find per-database directories */
6841  dir = AllocateDir(tblspcpath);
6842 
6843  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6844  {
6845  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6846  {
6847  /* Try to remove the init file in each database */
6848  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6849  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6850  unlink_initfile(initfilename, LOG);
6851  }
6852  }
6853 
6854  FreeDir(dir);
6855 }

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

3993 {
3994  HASHCTL ctl;
3995  int allocsize;
3996 
3997  /*
3998  * make sure cache memory context exists
3999  */
4000  if (!CacheMemoryContext)
4002 
4003  /*
4004  * create hashtable that indexes the relcache
4005  */
4006  ctl.keysize = sizeof(Oid);
4007  ctl.entrysize = sizeof(RelIdCacheEnt);
4008  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4009  &ctl, HASH_ELEM | HASH_BLOBS);
4010 
4011  /*
4012  * reserve enough in_progress_list slots for many cases
4013  */
4014  allocsize = 4;
4017  allocsize * sizeof(*in_progress_list));
4018  in_progress_list_maxlen = allocsize;
4019 
4020  /*
4021  * relation mapper needs to be initialized too
4022  */
4024 }
#define INITRELCACHESIZE
Definition: relcache.c:3989
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 4038 of file relcache.c.

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

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

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:353

References Assert, hash_seq_init(), hash_seq_search(), i, in_progress_list, in_progress_list_len, InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationClearRelation(), 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:763
#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:656
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:385

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:2140

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

5098 {
5099  List *result;
5100  Datum exprsDatum;
5101  bool isnull;
5102  char *exprsString;
5103  List *rawExprs;
5104  ListCell *lc;
5105 
5106  /* Quick exit if there is nothing to do. */
5107  if (relation->rd_indextuple == NULL ||
5108  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5109  return NIL;
5110 
5111  /* Extract raw node tree(s) from index tuple. */
5112  exprsDatum = heap_getattr(relation->rd_indextuple,
5113  Anum_pg_index_indexprs,
5115  &isnull);
5116  Assert(!isnull);
5117  exprsString = TextDatumGetCString(exprsDatum);
5118  rawExprs = (List *) stringToNode(exprsString);
5119  pfree(exprsString);
5120 
5121  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5122  result = NIL;
5123  foreach(lc, rawExprs)
5124  {
5125  Node *rawExpr = (Node *) lfirst(lc);
5126 
5127  result = lappend(result,
5128  makeConst(exprType(rawExpr),
5129  exprTypmod(rawExpr),
5130  exprCollation(rawExpr),
5131  1,
5132  (Datum) 0,
5133  true,
5134  true));
5135  }
5136 
5137  return result;
5138 }
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:4463

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

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

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

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

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

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

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

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

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

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5038 of file relcache.c.

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

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4801 of file relcache.c.

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

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4992 of file relcache.c.

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

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

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

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

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

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

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:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
Definition: c.h:726

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:659
Oid MyDatabaseTableSpace
Definition: globals.c:94
Oid MyDatabaseId
Definition: globals.c:92
#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:144
static char ** options
static TupleDesc GetPgClassDescriptor(void)
Definition: relcache.c:4450
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
Definition: reloptions.c:1379
amoptions_function amoptions
Definition: amapi.h:275

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

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

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

◆ 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:494

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

6876 {
6878 
6879  return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6880 }
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 6883 of file relcache.c.

6884 {
6886 
6887  /*
6888  * This reference has already been removed from the resource owner, so
6889  * just decrement reference count without calling
6890  * ResourceOwnerForgetRelationRef.
6891  */
6892  Assert(rel->rd_refcnt > 0);
6893  rel->rd_refcnt -= 1;
6894 
6896 }

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

6859 {
6860  if (unlink(initfilename) < 0)
6861  {
6862  /* It might not be there, but log any error other than ENOENT */
6863  if (errno != ENOENT)
6864  ereport(elevel,
6866  errmsg("could not remove cache file \"%s\": %m",
6867  initfilename)));
6868  }
6869 }
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 6698 of file relcache.c.

6699 {
6700  if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6701  ereport(FATAL,
6703  errmsg_internal("could not write init file: %m"));
6704  if (len > 0 && fwrite(data, 1, len, fp) != len)
6705  ereport(FATAL,
6707  errmsg_internal("could not write init file: %m"));
6708 }
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 6486 of file relcache.c.

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