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/nbtree.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 "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.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/trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.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/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_private.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  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 opclasscacheent OpClassCacheEnt
 

Functions

static void RelationDestroyRelation (Relation relation, bool remember_tupdesc)
 
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)
 
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)
 
void RelationIncrementReferenceCount (Relation rel)
 
void RelationDecrementReferenceCount (Relation rel)
 
void RelationClose (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (void)
 
void RelationCloseSmgrByOid (Oid relationId)
 
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, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence)
 
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)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
struct PublicationActionsGetRelationPublicationActions (Relation relation)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
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 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
 

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:161
static int eoxact_list_len
Definition: relcache.c:163

Definition at line 166 of file relcache.c.

Referenced by RelationBuildLocalRelation(), and RelationSetNewRelfilenode().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3579 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 161 of file relcache.c.

◆ NUM_CRITICAL_LOCAL_INDEXES

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

Referenced by load_relcache_init_file().

◆ NUM_CRITICAL_LOCAL_RELS

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

Referenced by load_relcache_init_file().

◆ NUM_CRITICAL_SHARED_INDEXES

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

Referenced by load_relcache_init_file().

◆ NUM_CRITICAL_SHARED_RELS

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

Referenced by load_relcache_init_file().

◆ RECOVER_RELATION_BUILD_MEMORY

#define RECOVER_RELATION_BUILD_MEMORY   0

Definition at line 99 of file relcache.c.

◆ RelationCacheDelete

#define RelationCacheDelete (   RELATION)
Value:
do { \
RelIdCacheEnt *hentry; \
(void *) &((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:906
static HTAB * RelationIdCache
Definition: relcache.c:129
#define WARNING
Definition: elog.h:40

Definition at line 220 of file relcache.c.

Referenced by RelationClearRelation().

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
(void *) &((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)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:129
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:412
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372

Definition at line 186 of file relcache.c.

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

◆ RelationIdCacheLookup

#define RelationIdCacheLookup (   ID,
  RELATION 
)
Value:
do { \
RelIdCacheEnt *hentry; \
(void *) &(ID), \
HASH_FIND, NULL); \
if (hentry) \
RELATION = hentry->reldesc; \
else \
RELATION = NULL; \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:129

Definition at line 208 of file relcache.c.

Referenced by RelationCacheInvalidateEntry(), RelationCloseSmgrByOid(), RelationForgetRelation(), and RelationIdGetRelation().

◆ RELCACHE_INIT_FILEMAGIC

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

Definition at line 88 of file relcache.c.

Referenced by load_relcache_init_file(), and write_relcache_init_file().

◆ SWAPFIELD

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

Referenced by RelationClearRelation().

Typedef Documentation

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 380 of file relcache.c.

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

Referenced by RelationBuildDesc().

381 {
382  Relation relation;
383  MemoryContext oldcxt;
384  Form_pg_class relationForm;
385 
386  /* Relcache entries must live in CacheMemoryContext */
388 
389  /*
390  * allocate and zero space for new relation descriptor
391  */
392  relation = (Relation) palloc0(sizeof(RelationData));
393 
394  /* make sure relation is marked as having no open file yet */
395  relation->rd_smgr = NULL;
396 
397  /*
398  * Copy the relation tuple form
399  *
400  * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. The
401  * variable-length fields (relacl, reloptions) are NOT stored in the
402  * relcache --- there'd be little point in it, since we don't copy the
403  * tuple's nulls bitmap and hence wouldn't know if the values are valid.
404  * Bottom line is that relacl *cannot* be retrieved from the relcache. Get
405  * it from the syscache if you need it. The same goes for the original
406  * form of reloptions (however, we do store the parsed form of reloptions
407  * in rd_options).
408  */
409  relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
410 
411  memcpy(relationForm, relp, CLASS_TUPLE_SIZE);
412 
413  /* initialize relation tuple form */
414  relation->rd_rel = relationForm;
415 
416  /* and allocate attribute tuple form storage */
417  relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
418  /* which we mark as a reference-counted tupdesc */
419  relation->rd_att->tdrefcount = 1;
420 
421  MemoryContextSwitchTo(oldcxt);
422 
423  return relation;
424 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Form_pg_class rd_rel
Definition: rel.h:84
struct RelationData * Relation
Definition: relcache.h:26
void * palloc0(Size size)
Definition: mcxt.c:980
TupleDesc rd_att
Definition: rel.h:85
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
void * palloc(Size size)
Definition: mcxt.c:949
int tdrefcount
Definition: tupdesc.h:84
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ AtEOSubXact_cleanup()

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

Definition at line 3126 of file relcache.c.

References elog, InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationGetRelationName, RelationHasReferenceCountZero, and WARNING.

Referenced by AtEOSubXact_RelationCache().

3128 {
3129  /*
3130  * Is it a relation created in the current subtransaction?
3131  *
3132  * During subcommit, mark it as belonging to the parent, instead. During
3133  * subabort, simply delete the relcache entry.
3134  */
3135  if (relation->rd_createSubid == mySubid)
3136  {
3137  if (isCommit)
3138  relation->rd_createSubid = parentSubid;
3139  else if (RelationHasReferenceCountZero(relation))
3140  {
3141  RelationClearRelation(relation, false);
3142  return;
3143  }
3144  else
3145  {
3146  /*
3147  * Hmm, somewhere there's a (leaked?) reference to the relation.
3148  * We daren't remove the entry for fear of dereferencing a
3149  * dangling pointer later. Bleat, and transfer it to the parent
3150  * subtransaction so we can try again later. This must be just a
3151  * WARNING to avoid error-during-error-recovery loops.
3152  */
3153  relation->rd_createSubid = parentSubid;
3154  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3155  RelationGetRelationName(relation));
3156  }
3157  }
3158 
3159  /*
3160  * Likewise, update or drop any new-relfilenode-in-subtransaction hint.
3161  */
3162  if (relation->rd_newRelfilenodeSubid == mySubid)
3163  {
3164  if (isCommit)
3165  relation->rd_newRelfilenodeSubid = parentSubid;
3166  else
3168  }
3169 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2394
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidSubTransactionId
Definition: c.h:520
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:412
#define elog(elevel,...)
Definition: elog.h:228

◆ AtEOSubXact_RelationCache()

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

Definition at line 3079 of file relcache.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

3081 {
3083  RelIdCacheEnt *idhentry;
3084  int i;
3085 
3086  /*
3087  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3088  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3089  * logic as in AtEOXact_RelationCache.
3090  */
3092  {
3093  hash_seq_init(&status, RelationIdCache);
3094  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3095  {
3096  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3097  mySubid, parentSubid);
3098  }
3099  }
3100  else
3101  {
3102  for (i = 0; i < eoxact_list_len; i++)
3103  {
3104  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3105  (void *) &eoxact_list[i],
3106  HASH_FIND,
3107  NULL);
3108  if (idhentry != NULL)
3109  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3110  mySubid, parentSubid);
3111  }
3112  }
3113 
3114  /* Don't reset the list; we still need more cleanup later */
3115 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:162
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3126
Relation reldesc
Definition: relcache.c:126
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:129
static bool eoxact_list_overflowed
Definition: relcache.c:164
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
static int eoxact_list_len
Definition: relcache.c:163

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3004 of file relcache.c.

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

Referenced by AtEOXact_RelationCache().

3005 {
3006  /*
3007  * The relcache entry's ref count should be back to its normal
3008  * not-in-a-transaction state: 0 unless it's nailed in cache.
3009  *
3010  * In bootstrap mode, this is NOT true, so don't check it --- the
3011  * bootstrap code expects relations to stay open across start/commit
3012  * transaction calls. (That seems bogus, but it's not worth fixing.)
3013  *
3014  * Note: ideally this check would be applied to every relcache entry, not
3015  * just those that have eoxact work to do. But it's not worth forcing a
3016  * scan of the whole relcache just for this. (Moreover, doing so would
3017  * mean that assert-enabled testing never tests the hash_search code path
3018  * above, which seems a bad idea.)
3019  */
3020 #ifdef USE_ASSERT_CHECKING
3022  {
3023  int expected_refcnt;
3024 
3025  expected_refcnt = relation->rd_isnailed ? 1 : 0;
3026  Assert(relation->rd_refcnt == expected_refcnt);
3027  }
3028 #endif
3029 
3030  /*
3031  * Is it a relation created in the current transaction?
3032  *
3033  * During commit, reset the flag to zero, since we are now out of the
3034  * creating transaction. During abort, simply delete the relcache entry
3035  * --- it isn't interesting any longer. (NOTE: if we have forgotten the
3036  * new-ness of a new relation due to a forced cache flush, the entry will
3037  * get deleted anyway by shared-cache-inval processing of the aborted
3038  * pg_class insertion.)
3039  */
3040  if (relation->rd_createSubid != InvalidSubTransactionId)
3041  {
3042  if (isCommit)
3044  else if (RelationHasReferenceCountZero(relation))
3045  {
3046  RelationClearRelation(relation, false);
3047  return;
3048  }
3049  else
3050  {
3051  /*
3052  * Hmm, somewhere there's a (leaked?) reference to the relation.
3053  * We daren't remove the entry for fear of dereferencing a
3054  * dangling pointer later. Bleat, and mark it as not belonging to
3055  * the current transaction. Hopefully it'll get cleaned up
3056  * eventually. This must be just a WARNING to avoid
3057  * error-during-error-recovery loops.
3058  */
3060  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3061  RelationGetRelationName(relation));
3062  }
3063  }
3064 
3065  /*
3066  * Likewise, reset the hint about the relfilenode being new.
3067  */
3069 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2394
bool rd_isnailed
Definition: rel.h:61
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:80
#define Assert(condition)
Definition: c.h:739
#define InvalidSubTransactionId
Definition: c.h:520
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:412
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:228

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 2941 of file relcache.c.

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

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

2942 {
2944  RelIdCacheEnt *idhentry;
2945  int i;
2946 
2947  /*
2948  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2949  * listed in it. Otherwise fall back on a hash_seq_search scan.
2950  *
2951  * For simplicity, eoxact_list[] entries are not deleted till end of
2952  * top-level transaction, even though we could remove them at
2953  * subtransaction end in some cases, or remove relations from the list if
2954  * they are cleared for other reasons. Therefore we should expect the
2955  * case that list entries are not found in the hashtable; if not, there's
2956  * nothing to do for them.
2957  */
2959  {
2960  hash_seq_init(&status, RelationIdCache);
2961  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2962  {
2963  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2964  }
2965  }
2966  else
2967  {
2968  for (i = 0; i < eoxact_list_len; i++)
2969  {
2970  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2971  (void *) &eoxact_list[i],
2972  HASH_FIND,
2973  NULL);
2974  if (idhentry != NULL)
2975  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2976  }
2977  }
2978 
2979  if (EOXactTupleDescArrayLen > 0)
2980  {
2981  Assert(EOXactTupleDescArray != NULL);
2982  for (i = 0; i < NextEOXactTupleDescNum; i++)
2985  EOXactTupleDescArray = NULL;
2986  }
2987 
2988  /* Now we're out of the transaction and can clear the lists */
2989  eoxact_list_len = 0;
2990  eoxact_list_overflowed = false;
2991  NextEOXactTupleDescNum = 0;
2993 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:162
static int EOXactTupleDescArrayLen
Definition: relcache.c:181
Relation reldesc
Definition: relcache.c:126
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:129
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3004
static bool eoxact_list_overflowed
Definition: relcache.c:164
static int NextEOXactTupleDescNum
Definition: relcache.c:180
void pfree(void *pointer)
Definition: mcxt.c:1056
#define Assert(condition)
Definition: c.h:739
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:313
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
static int eoxact_list_len
Definition: relcache.c:163
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:179

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

Definition at line 4057 of file relcache.c.

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

Referenced by RelationBuildTupleDesc().

4058 {
4059  AttrDefault *attrdef = relation->rd_att->constr->defval;
4060  int ndef = relation->rd_att->constr->num_defval;
4061  Relation adrel;
4062  SysScanDesc adscan;
4063  ScanKeyData skey;
4064  HeapTuple htup;
4065  Datum val;
4066  bool isnull;
4067  int found;
4068  int i;
4069 
4070  ScanKeyInit(&skey,
4071  Anum_pg_attrdef_adrelid,
4072  BTEqualStrategyNumber, F_OIDEQ,
4073  ObjectIdGetDatum(RelationGetRelid(relation)));
4074 
4075  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4076  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4077  NULL, 1, &skey);
4078  found = 0;
4079 
4080  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4081  {
4082  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4083  Form_pg_attribute attr = TupleDescAttr(relation->rd_att, adform->adnum - 1);
4084 
4085  for (i = 0; i < ndef; i++)
4086  {
4087  if (adform->adnum != attrdef[i].adnum)
4088  continue;
4089  if (attrdef[i].adbin != NULL)
4090  elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
4091  NameStr(attr->attname),
4092  RelationGetRelationName(relation));
4093  else
4094  found++;
4095 
4096  val = fastgetattr(htup,
4097  Anum_pg_attrdef_adbin,
4098  adrel->rd_att, &isnull);
4099  if (isnull)
4100  elog(WARNING, "null adbin for attr %s of rel %s",
4101  NameStr(attr->attname),
4102  RelationGetRelationName(relation));
4103  else
4104  {
4105  /* detoast and convert to cstring in caller's context */
4106  char *s = TextDatumGetCString(val);
4107 
4109  pfree(s);
4110  }
4111  break;
4112  }
4113 
4114  if (i >= ndef)
4115  elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
4116  adform->adnum, RelationGetRelationName(relation));
4117  }
4118 
4119  systable_endscan(adscan);
4120  table_close(adrel, AccessShareLock);
4121 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
AttrDefault * defval
Definition: tupdesc.h:39
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define AttrDefaultIndexId
Definition: indexing.h:89
TupleConstr * constr
Definition: tupdesc.h:85
#define RelationGetRelationName(relation)
Definition: rel.h:462
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:47
#define WARNING
Definition: elog.h:40
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
uint16 num_defval
Definition: tupdesc.h:42
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25
#define NameStr(name)
Definition: c.h:616
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:428
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ BuildHardcodedDescriptor()

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

Definition at line 3998 of file relcache.c.

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

3999 {
4000  TupleDesc result;
4001  MemoryContext oldcxt;
4002  int i;
4003 
4005 
4006  result = CreateTemplateTupleDesc(natts);
4007  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4008  result->tdtypmod = -1;
4009 
4010  for (i = 0; i < natts; i++)
4011  {
4012  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4013  /* make sure attcacheoff is valid */
4014  TupleDescAttr(result, i)->attcacheoff = -1;
4015  }
4016 
4017  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4018  TupleDescAttr(result, 0)->attcacheoff = 0;
4019 
4020  /* Note: we don't bother to set up a TupleConstr entry */
4021 
4022  MemoryContextSwitchTo(oldcxt);
4023 
4024  return result;
4025 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int32 tdtypmod
Definition: tupdesc.h:83
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:192
Oid tdtypeid
Definition: tupdesc.h:82
int i
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ CheckConstraintCmp()

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

Definition at line 4198 of file relcache.c.

References ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

4199 {
4200  const ConstrCheck *ca = (const ConstrCheck *) a;
4201  const ConstrCheck *cb = (const ConstrCheck *) b;
4202 
4203  return strcmp(ca->ccname, cb->ccname);
4204 }
char * ccname
Definition: tupdesc.h:30

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4127 of file relcache.c.

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

Referenced by RelationBuildTupleDesc().

4128 {
4129  ConstrCheck *check = relation->rd_att->constr->check;
4130  int ncheck = relation->rd_att->constr->num_check;
4131  Relation conrel;
4132  SysScanDesc conscan;
4133  ScanKeyData skey[1];
4134  HeapTuple htup;
4135  int found = 0;
4136 
4137  ScanKeyInit(&skey[0],
4138  Anum_pg_constraint_conrelid,
4139  BTEqualStrategyNumber, F_OIDEQ,
4140  ObjectIdGetDatum(RelationGetRelid(relation)));
4141 
4142  conrel = table_open(ConstraintRelationId, AccessShareLock);
4143  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4144  NULL, 1, skey);
4145 
4146  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4147  {
4149  Datum val;
4150  bool isnull;
4151  char *s;
4152 
4153  /* We want check constraints only */
4154  if (conform->contype != CONSTRAINT_CHECK)
4155  continue;
4156 
4157  if (found >= ncheck)
4158  elog(ERROR, "unexpected constraint record found for rel %s",
4159  RelationGetRelationName(relation));
4160 
4161  check[found].ccvalid = conform->convalidated;
4162  check[found].ccnoinherit = conform->connoinherit;
4164  NameStr(conform->conname));
4165 
4166  /* Grab and test conbin is actually set */
4167  val = fastgetattr(htup,
4168  Anum_pg_constraint_conbin,
4169  conrel->rd_att, &isnull);
4170  if (isnull)
4171  elog(ERROR, "null conbin for rel %s",
4172  RelationGetRelationName(relation));
4173 
4174  /* detoast and convert to cstring in caller's context */
4175  s = TextDatumGetCString(val);
4176  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4177  pfree(s);
4178 
4179  found++;
4180  }
4181 
4182  systable_endscan(conscan);
4183  table_close(conrel, AccessShareLock);
4184 
4185  if (found != ncheck)
4186  elog(ERROR, "%d constraint record(s) missing for rel %s",
4187  ncheck - found, RelationGetRelationName(relation));
4188 
4189  /* Sort the records so that CHECKs are applied in a deterministic order */
4190  if (ncheck > 1)
4191  qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
4192 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4198
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
TupleConstr * constr
Definition: tupdesc.h:85
char * ccname
Definition: tupdesc.h:30
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
uint16 num_check
Definition: tupdesc.h:43
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ConstraintRelidTypidNameIndexId
Definition: indexing.h:128
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
ConstrCheck * check
Definition: tupdesc.h:40
bool ccvalid
Definition: tupdesc.h:32
#define qsort(a, b, c, d)
Definition: port.h:491
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
char * ccbin
Definition: tupdesc.h:31
#define RelationGetRelid(relation)
Definition: rel.h:428
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ccnoinherit
Definition: tupdesc.h:33
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 932 of file relcache.c.

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().

933 {
934  int i;
935  Oid *r1,
936  *r2;
937 
938  if (policy1 != NULL)
939  {
940  if (policy2 == NULL)
941  return false;
942 
943  if (policy1->polcmd != policy2->polcmd)
944  return false;
945  if (policy1->hassublinks != policy2->hassublinks)
946  return false;
947  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
948  return false;
949  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
950  return false;
951 
952  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
953  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
954 
955  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
956  {
957  if (r1[i] != r2[i])
958  return false;
959  }
960 
961  if (!equal(policy1->qual, policy2->qual))
962  return false;
963  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
964  return false;
965  }
966  else if (policy2 != NULL)
967  return false;
968 
969  return true;
970 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
unsigned int Oid
Definition: postgres_ext.h:31
#define ARR_DIMS(a)
Definition: array.h:282
#define ARR_DATA_PTR(a)
Definition: array.h:310
Expr * with_check_qual
Definition: rowsecurity.h:27
ArrayType * roles
Definition: rowsecurity.h:24
int i

◆ equalRSDesc()

static bool equalRSDesc ( RowSecurityDesc rsdesc1,
RowSecurityDesc rsdesc2 
)
static

Definition at line 978 of file relcache.c.

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

Referenced by RelationClearRelation().

979 {
980  ListCell *lc,
981  *rc;
982 
983  if (rsdesc1 == NULL && rsdesc2 == NULL)
984  return true;
985 
986  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
987  (rsdesc1 == NULL && rsdesc2 != NULL))
988  return false;
989 
990  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
991  return false;
992 
993  /* RelationBuildRowSecurity should build policies in order */
994  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
995  {
998 
999  if (!equalPolicy(l, r))
1000  return false;
1001  }
1002 
1003  return true;
1004 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:932
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 887 of file relcache.c.

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

Referenced by RelationClearRelation().

888 {
889  int i;
890 
891  /*
892  * As of 7.3 we assume the rule ordering is repeatable, because
893  * RelationBuildRuleLock should read 'em in a consistent order. So just
894  * compare corresponding slots.
895  */
896  if (rlock1 != NULL)
897  {
898  if (rlock2 == NULL)
899  return false;
900  if (rlock1->numLocks != rlock2->numLocks)
901  return false;
902  for (i = 0; i < rlock1->numLocks; i++)
903  {
904  RewriteRule *rule1 = rlock1->rules[i];
905  RewriteRule *rule2 = rlock2->rules[i];
906 
907  if (rule1->ruleId != rule2->ruleId)
908  return false;
909  if (rule1->event != rule2->event)
910  return false;
911  if (rule1->enabled != rule2->enabled)
912  return false;
913  if (rule1->isInstead != rule2->isInstead)
914  return false;
915  if (!equal(rule1->qual, rule2->qual))
916  return false;
917  if (!equal(rule1->actions, rule2->actions))
918  return false;
919  }
920  }
921  else if (rlock2 != NULL)
922  return false;
923  return true;
924 }
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
bool isInstead
Definition: prs2lock.h:31
CmdType event
Definition: prs2lock.h:27
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
int i
Oid ruleId
Definition: prs2lock.h:26
char enabled
Definition: prs2lock.h:30

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5201 of file relcache.c.

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

Referenced by ATPrepChangePersistence(), BuildRelationExtStatistics(), errtablecolname(), and errtableconstraint().

5202 {
5206 
5207  return 0; /* return value does not matter */
5208 }
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define RelationGetRelationName(relation)
Definition: rel.h:462
int err_generic_string(int field, const char *str)
Definition: elog.c:1273
#define RelationGetNamespace(relation)
Definition: rel.h:469

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5218 of file relcache.c.

References attname, errtablecolname(), get_attname(), NameStr, RelationGetDescr, RelationGetRelid, relidcacheent::reldesc, and TupleDescAttr.

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

5219 {
5220  TupleDesc reldesc = RelationGetDescr(rel);
5221  const char *colname;
5222 
5223  /* Use reldesc if it's a user attribute, else consult the catalogs */
5224  if (attnum > 0 && attnum <= reldesc->natts)
5225  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5226  else
5227  colname = get_attname(RelationGetRelid(rel), attnum, false);
5228 
5229  return errtablecolname(rel, colname);
5230 }
#define RelationGetDescr(relation)
Definition: rel.h:454
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
NameData attname
Definition: pg_attribute.h:40
int16 attnum
Definition: pg_attribute.h:79
#define NameStr(name)
Definition: c.h:616
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:428
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5242

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5242 of file relcache.c.

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

Referenced by errtablecol().

5243 {
5244  errtable(rel);
5246 
5247  return 0; /* return value does not matter */
5248 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1273
int errtable(Relation rel)
Definition: relcache.c:5201

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5255 of file relcache.c.

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

Referenced by _bt_check_third_page(), _bt_check_unique(), ATPrepChangePersistence(), ATRewriteTable(), check_exclusion_or_unique_constraint(), comparetup_index_btree(), ExecCheckIndexConstraints(), ExecConstraints(), RI_FKey_check(), RI_Initial_Check(), ri_ReportViolation(), and validateCheckConstraint().

5256 {
5257  errtable(rel);
5259 
5260  return 0; /* return value does not matter */
5261 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1273
int errtable(Relation rel)
Definition: relcache.c:5201

◆ formrdesc()

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

Definition at line 1789 of file relcache.c.

References ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateTemplateTupleDesc(), GetHeapamTableAmRoutine(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, 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().

1792 {
1793  Relation relation;
1794  int i;
1795  bool has_not_null;
1796 
1797  /*
1798  * allocate new relation desc, clear all fields of reldesc
1799  */
1800  relation = (Relation) palloc0(sizeof(RelationData));
1801 
1802  /* make sure relation is marked as having no open file yet */
1803  relation->rd_smgr = NULL;
1804 
1805  /*
1806  * initialize reference count: 1 because it is nailed in cache
1807  */
1808  relation->rd_refcnt = 1;
1809 
1810  /*
1811  * all entries built with this routine are nailed-in-cache; none are for
1812  * new or temp relations.
1813  */
1814  relation->rd_isnailed = true;
1817  relation->rd_backend = InvalidBackendId;
1818  relation->rd_islocaltemp = false;
1819 
1820  /*
1821  * initialize relation tuple form
1822  *
1823  * The data we insert here is pretty incomplete/bogus, but it'll serve to
1824  * get us launched. RelationCacheInitializePhase3() will read the real
1825  * data from pg_class and replace what we've done here. Note in
1826  * particular that relowner is left as zero; this cues
1827  * RelationCacheInitializePhase3 that the real data isn't there yet.
1828  */
1830 
1831  namestrcpy(&relation->rd_rel->relname, relationName);
1832  relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1833  relation->rd_rel->reltype = relationReltype;
1834 
1835  /*
1836  * It's important to distinguish between shared and non-shared relations,
1837  * even at bootstrap time, to make sure we know where they are stored.
1838  */
1839  relation->rd_rel->relisshared = isshared;
1840  if (isshared)
1841  relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1842 
1843  /* formrdesc is used only for permanent relations */
1844  relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1845 
1846  /* ... and they're always populated, too */
1847  relation->rd_rel->relispopulated = true;
1848 
1849  relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1850  relation->rd_rel->relpages = 0;
1851  relation->rd_rel->reltuples = 0;
1852  relation->rd_rel->relallvisible = 0;
1853  relation->rd_rel->relkind = RELKIND_RELATION;
1854  relation->rd_rel->relnatts = (int16) natts;
1855  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
1856 
1857  /*
1858  * initialize attribute tuple form
1859  *
1860  * Unlike the case with the relation tuple, this data had better be right
1861  * because it will never be replaced. The data comes from
1862  * src/include/catalog/ headers via genbki.pl.
1863  */
1864  relation->rd_att = CreateTemplateTupleDesc(natts);
1865  relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1866 
1867  relation->rd_att->tdtypeid = relationReltype;
1868  relation->rd_att->tdtypmod = -1; /* unnecessary, but... */
1869 
1870  /*
1871  * initialize tuple desc info
1872  */
1873  has_not_null = false;
1874  for (i = 0; i < natts; i++)
1875  {
1876  memcpy(TupleDescAttr(relation->rd_att, i),
1877  &attrs[i],
1879  has_not_null |= attrs[i].attnotnull;
1880  /* make sure attcacheoff is valid */
1881  TupleDescAttr(relation->rd_att, i)->attcacheoff = -1;
1882  }
1883 
1884  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
1885  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
1886 
1887  /* mark not-null status */
1888  if (has_not_null)
1889  {
1890  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1891 
1892  constr->has_not_null = true;
1893  relation->rd_att->constr = constr;
1894  }
1895 
1896  /*
1897  * initialize relation id from info in att array (my, this is ugly)
1898  */
1899  RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
1900 
1901  /*
1902  * All relations made with formrdesc are mapped. This is necessarily so
1903  * because there is no other way to know what filenode they currently
1904  * have. In bootstrap mode, add them to the initial relation mapper data,
1905  * specifying that the initial filenode is the same as the OID.
1906  */
1907  relation->rd_rel->relfilenode = InvalidOid;
1910  RelationGetRelid(relation),
1911  isshared, true);
1912 
1913  /*
1914  * initialize the relation lock manager information
1915  */
1916  RelationInitLockInfo(relation); /* see lmgr.c */
1917 
1918  /*
1919  * initialize physical addressing information for the relation
1920  */
1921  RelationInitPhysicalAddr(relation);
1922 
1923  /*
1924  * initialize the table am handler
1925  */
1926  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
1927  relation->rd_tableam = GetHeapamTableAmRoutine();
1928 
1929  /*
1930  * initialize the rel-has-index flag, using hardwired knowledge
1931  */
1933  {
1934  /* In bootstrap mode, we have no indexes */
1935  relation->rd_rel->relhasindex = false;
1936  }
1937  else
1938  {
1939  /* Otherwise, all the rels formrdesc is used for have indexes */
1940  relation->rd_rel->relhasindex = true;
1941  }
1942 
1943  /*
1944  * add new reldesc to relcache
1945  */
1946  RelationCacheInsert(relation, false);
1947 
1948  /* It's fully valid */
1949  relation->rd_isvalid = true;
1950 }
signed short int16
Definition: c.h:346
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Form_pg_class rd_rel
Definition: rel.h:84
int namestrcpy(Name name, const char *str)
Definition: name.c:250
struct RelationData * Relation
Definition: relcache.h:26
int32 tdtypmod
Definition: tupdesc.h:83
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
TupleConstr * constr
Definition: tupdesc.h:85
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:192
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:980
const struct TableAmRoutine * rd_tableam
Definition: rel.h:146
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:186
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
BackendId rd_backend
Definition: rel.h:59
#define InvalidSubTransactionId
Definition: c.h:520
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
Oid tdtypeid
Definition: tupdesc.h:82
int rd_refcnt
Definition: rel.h:58
int i
int tdrefcount
Definition: tupdesc.h:84
bool has_not_null
Definition: tupdesc.h:44
#define RelationGetRelid(relation)
Definition: rel.h:428
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261
const TableAmRoutine * GetHeapamTableAmRoutine(void)

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4028 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

4029 {
4030  static TupleDesc pgclassdesc = NULL;
4031 
4032  /* Already done? */
4033  if (pgclassdesc == NULL)
4034  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4035  Desc_pg_class);
4036 
4037  return pgclassdesc;
4038 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:3998
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:106

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4041 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

4042 {
4043  static TupleDesc pgindexdesc = NULL;
4044 
4045  /* Already done? */
4046  if (pgindexdesc == NULL)
4047  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4048  Desc_pg_index);
4049 
4050  return pgindexdesc;
4051 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:113
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:3998

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5122 of file relcache.c.

References CacheMemoryContext, elog, ERROR, GetAllTablesPublications(), GetRelationPublications(), GETSTRUCT, HeapTupleIsValid, is_publishable_relation(), lfirst_oid, list_concat_unique_oid(), MemoryContextSwitchTo(), ObjectIdGetDatum, palloc(), palloc0(), pfree(), PublicationActions::pubdelete, PublicationActions::pubinsert, PUBLICATIONOID, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubactions, RelationGetRelid, ReleaseSysCache(), and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

5123 {
5124  List *puboids;
5125  ListCell *lc;
5126  MemoryContext oldcxt;
5127  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5128 
5129  /*
5130  * If not publishable, it publishes no actions. (pgoutput_change() will
5131  * ignore it.)
5132  */
5133  if (!is_publishable_relation(relation))
5134  return pubactions;
5135 
5136  if (relation->rd_pubactions)
5137  return memcpy(pubactions, relation->rd_pubactions,
5138  sizeof(PublicationActions));
5139 
5140  /* Fetch the publication membership info. */
5141  puboids = GetRelationPublications(RelationGetRelid(relation));
5142  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5143 
5144  foreach(lc, puboids)
5145  {
5146  Oid pubid = lfirst_oid(lc);
5147  HeapTuple tup;
5148  Form_pg_publication pubform;
5149 
5151 
5152  if (!HeapTupleIsValid(tup))
5153  elog(ERROR, "cache lookup failed for publication %u", pubid);
5154 
5155  pubform = (Form_pg_publication) GETSTRUCT(tup);
5156 
5157  pubactions->pubinsert |= pubform->pubinsert;
5158  pubactions->pubupdate |= pubform->pubupdate;
5159  pubactions->pubdelete |= pubform->pubdelete;
5160  pubactions->pubtruncate |= pubform->pubtruncate;
5161 
5162  ReleaseSysCache(tup);
5163 
5164  /*
5165  * If we know everything is replicated, there is no point to check for
5166  * other publications.
5167  */
5168  if (pubactions->pubinsert && pubactions->pubupdate &&
5169  pubactions->pubdelete && pubactions->pubtruncate)
5170  break;
5171  }
5172 
5173  if (relation->rd_pubactions)
5174  {
5175  pfree(relation->rd_pubactions);
5176  relation->rd_pubactions = NULL;
5177  }
5178 
5179  /* Now save copy of the actions in the relcache entry. */
5181  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5182  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5183  MemoryContextSwitchTo(oldcxt);
5184 
5185  return pubactions;
5186 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1302
bool is_publishable_relation(Relation rel)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void * palloc0(Size size)
Definition: mcxt.c:980
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:428
#define lfirst_oid(lc)
Definition: pg_list.h:192
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ IndexSupportInitialize()

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

Definition at line 1515 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

1521 {
1522  int attIndex;
1523 
1524  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1525  {
1526  OpClassCacheEnt *opcentry;
1527 
1528  if (!OidIsValid(indclass->values[attIndex]))
1529  elog(ERROR, "bogus pg_index tuple");
1530 
1531  /* look up the info for this opclass, using a cache */
1532  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1533  maxSupportNumber);
1534 
1535  /* copy cached data into relcache entry */
1536  opFamily[attIndex] = opcentry->opcfamily;
1537  opcInType[attIndex] = opcentry->opcintype;
1538  if (maxSupportNumber > 0)
1539  memcpy(&indexSupport[attIndex * maxSupportNumber],
1540  opcentry->supportProcs,
1541  maxSupportNumber * sizeof(RegProcedure));
1542  }
1543 }
regproc RegProcedure
Definition: c.h:512
#define OidIsValid(objectId)
Definition: c.h:645
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:245
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1566
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:603
#define elog(elevel,...)
Definition: elog.h:228

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1323 of file relcache.c.

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

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

1324 {
1325  IndexAmRoutine *cached,
1326  *tmp;
1327 
1328  /*
1329  * Call the amhandler in current, short-lived memory context, just in case
1330  * it leaks anything (it probably won't, but let's be paranoid).
1331  */
1332  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1333 
1334  /* OK, now transfer the data into relation's rd_indexcxt. */
1335  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1336  sizeof(IndexAmRoutine));
1337  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1338  relation->rd_indam = cached;
1339 
1340  pfree(tmp);
1341 }
struct IndexAmRoutine * rd_indam
Definition: rel.h:163
void pfree(void *pointer)
Definition: mcxt.c:1056
Oid rd_amhandler
Definition: rel.h:141
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
MemoryContext rd_indexcxt
Definition: rel.h:161

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1716 of file relcache.c.

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

Referenced by RelationInitTableAccessMethod().

1717 {
1718  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1719 }
Oid rd_amhandler
Definition: rel.h:141
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:34
const struct TableAmRoutine * rd_tableam
Definition: rel.h:146

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 3964 of file relcache.c.

References AccessShareLock, elog, LockRelationOid(), PANIC, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationBuildDesc(), and UnlockRelationOid().

Referenced by RelationCacheInitializePhase3().

3965 {
3966  Relation ird;
3967 
3968  /*
3969  * We must lock the underlying catalog before locking the index to avoid
3970  * deadlock, since RelationBuildDesc might well need to read the catalog,
3971  * and if anyone else is exclusive-locking this catalog and index they'll
3972  * be doing it in that order.
3973  */
3974  LockRelationOid(heapoid, AccessShareLock);
3975  LockRelationOid(indexoid, AccessShareLock);
3976  ird = RelationBuildDesc(indexoid, true);
3977  if (ird == NULL)
3978  elog(PANIC, "could not open critical system index %u", indexoid);
3979  ird->rd_isnailed = true;
3980  ird->rd_refcnt = 1;
3983 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
bool rd_isnailed
Definition: rel.h:61
#define AccessShareLock
Definition: lockdefs.h:36
#define PANIC
Definition: elog.h:53
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1019
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:228
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 5319 of file relcache.c.

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, MAXPGPATH, MemoryContextAlloc(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemSet, 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_createSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexattr, 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_newRelfilenodeSubid, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_pubactions, 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().

5320 {
5321  FILE *fp;
5322  char initfilename[MAXPGPATH];
5323  Relation *rels;
5324  int relno,
5325  num_rels,
5326  max_rels,
5327  nailed_rels,
5328  nailed_indexes,
5329  magic;
5330  int i;
5331 
5332  if (shared)
5333  snprintf(initfilename, sizeof(initfilename), "global/%s",
5335  else
5336  snprintf(initfilename, sizeof(initfilename), "%s/%s",
5338 
5339  fp = AllocateFile(initfilename, PG_BINARY_R);
5340  if (fp == NULL)
5341  return false;
5342 
5343  /*
5344  * Read the index relcache entries from the file. Note we will not enter
5345  * any of them into the cache if the read fails partway through; this
5346  * helps to guard against broken init files.
5347  */
5348  max_rels = 100;
5349  rels = (Relation *) palloc(max_rels * sizeof(Relation));
5350  num_rels = 0;
5351  nailed_rels = nailed_indexes = 0;
5352 
5353  /* check for correct magic number (compatible version) */
5354  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
5355  goto read_failed;
5356  if (magic != RELCACHE_INIT_FILEMAGIC)
5357  goto read_failed;
5358 
5359  for (relno = 0;; relno++)
5360  {
5361  Size len;
5362  size_t nread;
5363  Relation rel;
5364  Form_pg_class relform;
5365  bool has_not_null;
5366 
5367  /* first read the relation descriptor length */
5368  nread = fread(&len, 1, sizeof(len), fp);
5369  if (nread != sizeof(len))
5370  {
5371  if (nread == 0)
5372  break; /* end of file */
5373  goto read_failed;
5374  }
5375 
5376  /* safety check for incompatible relcache layout */
5377  if (len != sizeof(RelationData))
5378  goto read_failed;
5379 
5380  /* allocate another relcache header */
5381  if (num_rels >= max_rels)
5382  {
5383  max_rels *= 2;
5384  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
5385  }
5386 
5387  rel = rels[num_rels++] = (Relation) palloc(len);
5388 
5389  /* then, read the Relation structure */
5390  if (fread(rel, 1, len, fp) != len)
5391  goto read_failed;
5392 
5393  /* next read the relation tuple form */
5394  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5395  goto read_failed;
5396 
5397  relform = (Form_pg_class) palloc(len);
5398  if (fread(relform, 1, len, fp) != len)
5399  goto read_failed;
5400 
5401  rel->rd_rel = relform;
5402 
5403  /* initialize attribute tuple forms */
5404  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
5405  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
5406 
5407  rel->rd_att->tdtypeid = relform->reltype;
5408  rel->rd_att->tdtypmod = -1; /* unnecessary, but... */
5409 
5410  /* next read all the attribute tuple form data entries */
5411  has_not_null = false;
5412  for (i = 0; i < relform->relnatts; i++)
5413  {
5414  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
5415 
5416  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5417  goto read_failed;
5418  if (len != ATTRIBUTE_FIXED_PART_SIZE)
5419  goto read_failed;
5420  if (fread(attr, 1, len, fp) != len)
5421  goto read_failed;
5422 
5423  has_not_null |= attr->attnotnull;
5424  }
5425 
5426  /* next read the access method specific field */
5427  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5428  goto read_failed;
5429  if (len > 0)
5430  {
5431  rel->rd_options = palloc(len);
5432  if (fread(rel->rd_options, 1, len, fp) != len)
5433  goto read_failed;
5434  if (len != VARSIZE(rel->rd_options))
5435  goto read_failed; /* sanity check */
5436  }
5437  else
5438  {
5439  rel->rd_options = NULL;
5440  }
5441 
5442  /* mark not-null status */
5443  if (has_not_null)
5444  {
5445  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
5446 
5447  constr->has_not_null = true;
5448  rel->rd_att->constr = constr;
5449  }
5450 
5451  /*
5452  * If it's an index, there's more to do. Note we explicitly ignore
5453  * partitioned indexes here.
5454  */
5455  if (rel->rd_rel->relkind == RELKIND_INDEX)
5456  {
5457  MemoryContext indexcxt;
5458  Oid *opfamily;
5459  Oid *opcintype;
5460  RegProcedure *support;
5461  int nsupport;
5462  int16 *indoption;
5463  Oid *indcollation;
5464 
5465  /* Count nailed indexes to ensure we have 'em all */
5466  if (rel->rd_isnailed)
5467  nailed_indexes++;
5468 
5469  /* next, read the pg_index tuple */
5470  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5471  goto read_failed;
5472 
5473  rel->rd_indextuple = (HeapTuple) palloc(len);
5474  if (fread(rel->rd_indextuple, 1, len, fp) != len)
5475  goto read_failed;
5476 
5477  /* Fix up internal pointers in the tuple -- see heap_copytuple */
5478  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
5480 
5481  /*
5482  * prepare index info context --- parameters should match
5483  * RelationInitIndexAccessInfo
5484  */
5486  "index info",
5488  rel->rd_indexcxt = indexcxt;
5491 
5492  /*
5493  * Now we can fetch the index AM's API struct. (We can't store
5494  * that in the init file, since it contains function pointers that
5495  * might vary across server executions. Fortunately, it should be
5496  * safe to call the amhandler even while bootstrapping indexes.)
5497  */
5498  InitIndexAmRoutine(rel);
5499 
5500  /* next, read the vector of opfamily OIDs */
5501  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5502  goto read_failed;
5503 
5504  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
5505  if (fread(opfamily, 1, len, fp) != len)
5506  goto read_failed;
5507 
5508  rel->rd_opfamily = opfamily;
5509 
5510  /* next, read the vector of opcintype OIDs */
5511  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5512  goto read_failed;
5513 
5514  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
5515  if (fread(opcintype, 1, len, fp) != len)
5516  goto read_failed;
5517 
5518  rel->rd_opcintype = opcintype;
5519 
5520  /* next, read the vector of support procedure OIDs */
5521  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5522  goto read_failed;
5523  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
5524  if (fread(support, 1, len, fp) != len)
5525  goto read_failed;
5526 
5527  rel->rd_support = support;
5528 
5529  /* next, read the vector of collation OIDs */
5530  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5531  goto read_failed;
5532 
5533  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
5534  if (fread(indcollation, 1, len, fp) != len)
5535  goto read_failed;
5536 
5537  rel->rd_indcollation = indcollation;
5538 
5539  /* finally, read the vector of indoption values */
5540  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5541  goto read_failed;
5542 
5543  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
5544  if (fread(indoption, 1, len, fp) != len)
5545  goto read_failed;
5546 
5547  rel->rd_indoption = indoption;
5548 
5549  /* set up zeroed fmgr-info vector */
5550  nsupport = relform->relnatts * rel->rd_indam->amsupport;
5551  rel->rd_supportinfo = (FmgrInfo *)
5552  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
5553  }
5554  else
5555  {
5556  /* Count nailed rels to ensure we have 'em all */
5557  if (rel->rd_isnailed)
5558  nailed_rels++;
5559 
5560  /* Load table AM data */
5561  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5562  rel->rd_rel->relkind == RELKIND_SEQUENCE ||
5563  rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
5564  rel->rd_rel->relkind == RELKIND_MATVIEW)
5566 
5567  Assert(rel->rd_index == NULL);
5568  Assert(rel->rd_indextuple == NULL);
5569  Assert(rel->rd_indexcxt == NULL);
5570  Assert(rel->rd_indam == NULL);
5571  Assert(rel->rd_opfamily == NULL);
5572  Assert(rel->rd_opcintype == NULL);
5573  Assert(rel->rd_support == NULL);
5574  Assert(rel->rd_supportinfo == NULL);
5575  Assert(rel->rd_indoption == NULL);
5576  Assert(rel->rd_indcollation == NULL);
5577  }
5578 
5579  /*
5580  * Rules and triggers are not saved (mainly because the internal
5581  * format is complex and subject to change). They must be rebuilt if
5582  * needed by RelationCacheInitializePhase3. This is not expected to
5583  * be a big performance hit since few system catalogs have such. Ditto
5584  * for RLS policy data, partition info, index expressions, predicates,
5585  * exclusion info, and FDW info.
5586  */
5587  rel->rd_rules = NULL;
5588  rel->rd_rulescxt = NULL;
5589  rel->trigdesc = NULL;
5590  rel->rd_rsdesc = NULL;
5591  rel->rd_partkey = NULL;
5592  rel->rd_partkeycxt = NULL;
5593  rel->rd_partdesc = NULL;
5594  rel->rd_pdcxt = NULL;
5595  rel->rd_partcheck = NIL;
5596  rel->rd_partcheckvalid = false;
5597  rel->rd_partcheckcxt = NULL;
5598  rel->rd_indexprs = NIL;
5599  rel->rd_indpred = NIL;
5600  rel->rd_exclops = NULL;
5601  rel->rd_exclprocs = NULL;
5602  rel->rd_exclstrats = NULL;
5603  rel->rd_fdwroutine = NULL;
5604 
5605  /*
5606  * Reset transient-state fields in the relcache entry
5607  */
5608  rel->rd_smgr = NULL;
5609  if (rel->rd_isnailed)
5610  rel->rd_refcnt = 1;
5611  else
5612  rel->rd_refcnt = 0;
5613  rel->rd_indexvalid = false;
5614  rel->rd_indexlist = NIL;
5615  rel->rd_pkindex = InvalidOid;
5616  rel->rd_replidindex = InvalidOid;
5617  rel->rd_indexattr = NULL;
5618  rel->rd_keyattr = NULL;
5619  rel->rd_pkattr = NULL;
5620  rel->rd_idattr = NULL;
5621  rel->rd_pubactions = NULL;
5622  rel->rd_statvalid = false;
5623  rel->rd_statlist = NIL;
5624  rel->rd_fkeyvalid = false;
5625  rel->rd_fkeylist = NIL;
5628  rel->rd_amcache = NULL;
5629  MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
5630 
5631  /*
5632  * Recompute lock and physical addressing info. This is needed in
5633  * case the pg_internal.init file was copied from some other database
5634  * by CREATE DATABASE.
5635  */
5636  RelationInitLockInfo(rel);
5638  }
5639 
5640  /*
5641  * We reached the end of the init file without apparent problem. Did we
5642  * get the right number of nailed items? This is a useful crosscheck in
5643  * case the set of critical rels or indexes changes. However, that should
5644  * not happen in a normally-running system, so let's bleat if it does.
5645  *
5646  * For the shared init file, we're called before client authentication is
5647  * done, which means that elog(WARNING) will go only to the postmaster
5648  * log, where it's easily missed. To ensure that developers notice bad
5649  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
5650  * an Assert(false) there.
5651  */
5652  if (shared)
5653  {
5654  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
5655  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
5656  {
5657  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
5658  nailed_rels, nailed_indexes,
5660  /* Make sure we get developers' attention about this */
5661  Assert(false);
5662  /* In production builds, recover by bootstrapping the relcache */
5663  goto read_failed;
5664  }
5665  }
5666  else
5667  {
5668  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
5669  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
5670  {
5671  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
5672  nailed_rels, nailed_indexes,
5674  /* We don't need an Assert() in this case */
5675  goto read_failed;
5676  }
5677  }
5678 
5679  /*
5680  * OK, all appears well.
5681  *
5682  * Now insert all the new relcache entries into the cache.
5683  */
5684  for (relno = 0; relno < num_rels; relno++)
5685  {
5686  RelationCacheInsert(rels[relno], false);
5687  }
5688 
5689  pfree(rels);
5690  FreeFile(fp);
5691 
5692  if (shared)
5694  else
5695  criticalRelcachesBuilt = true;
5696  return true;
5697 
5698  /*
5699  * init file is broken, so do it the hard way. We don't bother trying to
5700  * free the clutter we just allocated; it's not in the relcache so it
5701  * won't hurt.
5702  */
5703 read_failed:
5704  pfree(rels);
5705  FreeFile(fp);
5706 
5707  return false;
5708 }
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:196
signed short int16
Definition: c.h:346
#define NIL
Definition: pg_list.h:65
struct IndexAmRoutine * rd_indam
Definition: rel.h:163
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:173
#define AllocSetContextCreate
Definition: memutils.h:170
HeapTupleData * HeapTuple
Definition: htup.h:71
int16 * rd_indoption
Definition: rel.h:168
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:125
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
struct FmgrInfo * rd_supportinfo
Definition: rel.h:167
Bitmapset * rd_keyattr
Definition: rel.h:121
#define VARSIZE(PTR)
Definition: postgres.h:303
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1725
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Oid rd_replidindex
Definition: rel.h:114
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
bool rd_isnailed
Definition: rel.h:61
regproc RegProcedure
Definition: c.h:512
uint16 * rd_exclstrats
Definition: rel.h:173
#define NUM_CRITICAL_LOCAL_INDEXES
List * rd_indexprs
Definition: rel.h:169
List * rd_fkeylist
Definition: rel.h:95
bool rd_partcheckvalid
Definition: rel.h:108
#define MemSet(start, val, len)
Definition: c.h:962
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
MemoryContext rd_rulescxt
Definition: rel.h:89
bool criticalSharedRelcachesBuilt
Definition: relcache.c:141
Oid * rd_exclprocs
Definition: rel.h:172
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define NUM_CRITICAL_SHARED_INDEXES
#define PG_BINARY_R
Definition: c.h:1223
#define NUM_CRITICAL_SHARED_RELS
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1323
struct HeapTupleData * rd_indextuple
Definition: rel.h:151
HeapTupleHeader t_data
Definition: htup.h:68
struct RelationData * Relation
Definition: relcache.h:26
Form_pg_index rd_index
Definition: rel.h:149
PartitionKey rd_partkey
Definition: rel.h:99
void pfree(void *pointer)
Definition: mcxt.c:1056
#define NUM_CRITICAL_LOCAL_RELS
Oid * rd_indcollation
Definition: rel.h:174
int32 tdtypmod
Definition: tupdesc.h:83
Oid rd_pkindex
Definition: rel.h:113
#define MAXPGPATH
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:97
TupleConstr * constr
Definition: tupdesc.h:85
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2242
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:88
#define RelationGetRelationName(relation)
Definition: rel.h:462
List * rd_indpred
Definition: rel.h:170
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Oid * rd_opfamily
Definition: rel.h:164
Oid * rd_exclops
Definition: rel.h:171
PartitionDesc rd_partdesc
Definition: rel.h:103
List * rd_indexlist
Definition: rel.h:112
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:192
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
RegProcedure * rd_support
Definition: rel.h:166
#define WARNING
Definition: elog.h:40
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
SubTransactionId rd_createSubid
Definition: rel.h:80
bool rd_indexvalid
Definition: rel.h:63
void * palloc0(Size size)
Definition: mcxt.c:980
TupleDesc rd_att
Definition: rel.h:85
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define InvalidOid
Definition: postgres_ext.h:36
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
Bitmapset * rd_idattr
Definition: rel.h:123
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:186
char * DatabasePath
Definition: globals.c:93
MemoryContext rd_pdcxt
Definition: rel.h:104
#define Assert(condition)
Definition: c.h:739
MemoryContext rd_partkeycxt
Definition: rel.h:100
RuleLock * rd_rules
Definition: rel.h:88
size_t Size
Definition: c.h:467
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:210
#define InvalidSubTransactionId
Definition: c.h:520
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
int FreeFile(FILE *file)
Definition: fd.c:2441
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
Bitmapset * rd_pkattr
Definition: rel.h:122
Oid tdtypeid
Definition: tupdesc.h:82
bool rd_statvalid
Definition: rel.h:65
void * palloc(Size size)
Definition: mcxt.c:949
int rd_refcnt
Definition: rel.h:58
#define HEAPTUPLESIZE
Definition: htup.h:73
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:228
MemoryContext rd_indexcxt
Definition: rel.h:161
int i
int tdrefcount
Definition: tupdesc.h:84
MemoryContext rd_partcheckcxt
Definition: rel.h:109
bool criticalRelcachesBuilt
Definition: relcache.c:135
void * rd_amcache
Definition: rel.h:185
Oid * rd_opcintype
Definition: rel.h:165
bool has_not_null
Definition: tupdesc.h:44
List * rd_statlist
Definition: rel.h:117
#define snprintf
Definition: port.h:192
bool rd_fkeyvalid
Definition: rel.h:96
List * rd_partcheck
Definition: rel.h:107
Bitmapset * rd_indexattr
Definition: rel.h:120
bytea * rd_options
Definition: rel.h:132
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ LookupOpclassInfo()

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

Definition at line 1566 of file relcache.c.

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

Referenced by IndexSupportInitialize().

1568 {
1569  OpClassCacheEnt *opcentry;
1570  bool found;
1571  Relation rel;
1572  SysScanDesc scan;
1573  ScanKeyData skey[3];
1574  HeapTuple htup;
1575  bool indexOK;
1576 
1577  if (OpClassCache == NULL)
1578  {
1579  /* First time through: initialize the opclass cache */
1580  HASHCTL ctl;
1581 
1582  MemSet(&ctl, 0, sizeof(ctl));
1583  ctl.keysize = sizeof(Oid);
1584  ctl.entrysize = sizeof(OpClassCacheEnt);
1585  OpClassCache = hash_create("Operator class cache", 64,
1586  &ctl, HASH_ELEM | HASH_BLOBS);
1587 
1588  /* Also make sure CacheMemoryContext exists */
1589  if (!CacheMemoryContext)
1591  }
1592 
1593  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1594  (void *) &operatorClassOid,
1595  HASH_ENTER, &found);
1596 
1597  if (!found)
1598  {
1599  /* Need to allocate memory for new entry */
1600  opcentry->valid = false; /* until known OK */
1601  opcentry->numSupport = numSupport;
1602 
1603  if (numSupport > 0)
1604  opcentry->supportProcs = (RegProcedure *)
1606  numSupport * sizeof(RegProcedure));
1607  else
1608  opcentry->supportProcs = NULL;
1609  }
1610  else
1611  {
1612  Assert(numSupport == opcentry->numSupport);
1613  }
1614 
1615  /*
1616  * When testing for cache-flush hazards, we intentionally disable the
1617  * operator class cache and force reloading of the info on each call. This
1618  * is helpful because we want to test the case where a cache flush occurs
1619  * while we are loading the info, and it's very hard to provoke that if
1620  * this happens only once per opclass per backend.
1621  */
1622 #if defined(CLOBBER_CACHE_ALWAYS)
1623  opcentry->valid = false;
1624 #endif
1625 
1626  if (opcentry->valid)
1627  return opcentry;
1628 
1629  /*
1630  * Need to fill in new entry.
1631  *
1632  * To avoid infinite recursion during startup, force heap scans if we're
1633  * looking up info for the opclasses used by the indexes we would like to
1634  * reference here.
1635  */
1636  indexOK = criticalRelcachesBuilt ||
1637  (operatorClassOid != OID_BTREE_OPS_OID &&
1638  operatorClassOid != INT2_BTREE_OPS_OID);
1639 
1640  /*
1641  * We have to fetch the pg_opclass row to determine its opfamily and
1642  * opcintype, which are needed to look up related operators and functions.
1643  * It'd be convenient to use the syscache here, but that probably doesn't
1644  * work while bootstrapping.
1645  */
1646  ScanKeyInit(&skey[0],
1647  Anum_pg_opclass_oid,
1648  BTEqualStrategyNumber, F_OIDEQ,
1649  ObjectIdGetDatum(operatorClassOid));
1650  rel = table_open(OperatorClassRelationId, AccessShareLock);
1651  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1652  NULL, 1, skey);
1653 
1654  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1655  {
1656  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1657 
1658  opcentry->opcfamily = opclassform->opcfamily;
1659  opcentry->opcintype = opclassform->opcintype;
1660  }
1661  else
1662  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1663 
1664  systable_endscan(scan);
1666 
1667  /*
1668  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1669  * the default ones (those with lefttype = righttype = opcintype).
1670  */
1671  if (numSupport > 0)
1672  {
1673  ScanKeyInit(&skey[0],
1674  Anum_pg_amproc_amprocfamily,
1675  BTEqualStrategyNumber, F_OIDEQ,
1676  ObjectIdGetDatum(opcentry->opcfamily));
1677  ScanKeyInit(&skey[1],
1678  Anum_pg_amproc_amproclefttype,
1679  BTEqualStrategyNumber, F_OIDEQ,
1680  ObjectIdGetDatum(opcentry->opcintype));
1681  ScanKeyInit(&skey[2],
1682  Anum_pg_amproc_amprocrighttype,
1683  BTEqualStrategyNumber, F_OIDEQ,
1684  ObjectIdGetDatum(opcentry->opcintype));
1685  rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1686  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1687  NULL, 3, skey);
1688 
1689  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1690  {
1691  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1692 
1693  if (amprocform->amprocnum <= 0 ||
1694  (StrategyNumber) amprocform->amprocnum > numSupport)
1695  elog(ERROR, "invalid amproc number %d for opclass %u",
1696  amprocform->amprocnum, operatorClassOid);
1697 
1698  opcentry->supportProcs[amprocform->amprocnum - 1] =
1699  amprocform->amproc;
1700  }
1701 
1702  systable_endscan(scan);
1704  }
1705 
1706  opcentry->valid = true;
1707  return opcentry;
1708 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
struct opclasscacheent OpClassCacheEnt
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define HASH_ELEM
Definition: hsearch.h:87
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
regproc RegProcedure
Definition: c.h:512
#define AccessShareLock
Definition: lockdefs.h:36
Size entrysize
Definition: hsearch.h:73
uint16 StrategyNumber
Definition: stratnum.h:22
#define MemSet(start, val, len)
Definition: c.h:962
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
StrategyNumber numSupport
Definition: relcache.c:242
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:245
static HTAB * OpClassCache
Definition: relcache.c:248
#define HASH_BLOBS
Definition: hsearch.h:88
#define AccessMethodProcedureIndexId
Definition: indexing.h:84
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define OpclassOidIndexId
Definition: indexing.h:197
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define elog(elevel,...)
Definition: elog.h:228
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool criticalRelcachesBuilt
Definition: relcache.c:135
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1019 of file relcache.c.

References AllocateRelationDesc(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, BackendIdForTempRelations, CurrentMemoryContext, elog, ERROR, GETSTRUCT, GetTempNamespaceBackendId(), heap_freetuple(), HeapTupleIsValid, InvalidBackendId, InvalidOid, InvalidSubTransactionId, isTempOrTempToastNamespace(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationParseRelOptions(), ScanPgRelation(), and RelationData::trigdesc.

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

1020 {
1021  Relation relation;
1022  Oid relid;
1023  HeapTuple pg_class_tuple;
1024  Form_pg_class relp;
1025 
1026  /*
1027  * This function and its subroutines can allocate a good deal of transient
1028  * data in CurrentMemoryContext. Traditionally we've just leaked that
1029  * data, reasoning that the caller's context is at worst of transaction
1030  * scope, and relcache loads shouldn't happen so often that it's essential
1031  * to recover transient data before end of statement/transaction. However
1032  * that's definitely not true in clobber-cache test builds, and perhaps
1033  * it's not true in other cases. If RECOVER_RELATION_BUILD_MEMORY is not
1034  * zero, arrange to allocate the junk in a temporary context that we'll
1035  * free before returning. Make it a child of caller's context so that it
1036  * will get cleaned up appropriately if we error out partway through.
1037  */
1038 #if RECOVER_RELATION_BUILD_MEMORY
1039  MemoryContext tmpcxt;
1040  MemoryContext oldcxt;
1041 
1043  "RelationBuildDesc workspace",
1045  oldcxt = MemoryContextSwitchTo(tmpcxt);
1046 #endif
1047 
1048  /*
1049  * find the tuple in pg_class corresponding to the given relation id
1050  */
1051  pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1052 
1053  /*
1054  * if no such tuple exists, return NULL
1055  */
1056  if (!HeapTupleIsValid(pg_class_tuple))
1057  {
1058 #if RECOVER_RELATION_BUILD_MEMORY
1059  /* Return to caller's context, and blow away the temporary context */
1060  MemoryContextSwitchTo(oldcxt);
1061  MemoryContextDelete(tmpcxt);
1062 #endif
1063  return NULL;
1064  }
1065 
1066  /*
1067  * get information from the pg_class_tuple
1068  */
1069  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1070  relid = relp->oid;
1071  Assert(relid == targetRelId);
1072 
1073  /*
1074  * allocate storage for the relation descriptor, and copy pg_class_tuple
1075  * to relation->rd_rel.
1076  */
1077  relation = AllocateRelationDesc(relp);
1078 
1079  /*
1080  * initialize the relation's relation id (relation->rd_id)
1081  */
1082  RelationGetRelid(relation) = relid;
1083 
1084  /*
1085  * normal relations are not nailed into the cache; nor can a pre-existing
1086  * relation be new. It could be temp though. (Actually, it could be new
1087  * too, but it's okay to forget that fact if forced to flush the entry.)
1088  */
1089  relation->rd_refcnt = 0;
1090  relation->rd_isnailed = false;
1093  switch (relation->rd_rel->relpersistence)
1094  {
1095  case RELPERSISTENCE_UNLOGGED:
1096  case RELPERSISTENCE_PERMANENT:
1097  relation->rd_backend = InvalidBackendId;
1098  relation->rd_islocaltemp = false;
1099  break;
1100  case RELPERSISTENCE_TEMP:
1101  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1102  {
1103  relation->rd_backend = BackendIdForTempRelations();
1104  relation->rd_islocaltemp = true;
1105  }
1106  else
1107  {
1108  /*
1109  * If it's a temp table, but not one of ours, we have to use
1110  * the slow, grotty method to figure out the owning backend.
1111  *
1112  * Note: it's possible that rd_backend gets set to MyBackendId
1113  * here, in case we are looking at a pg_class entry left over
1114  * from a crashed backend that coincidentally had the same
1115  * BackendId we're using. We should *not* consider such a
1116  * table to be "ours"; this is why we need the separate
1117  * rd_islocaltemp flag. The pg_class entry will get flushed
1118  * if/when we clean out the corresponding temp table namespace
1119  * in preparation for using it.
1120  */
1121  relation->rd_backend =
1122  GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
1123  Assert(relation->rd_backend != InvalidBackendId);
1124  relation->rd_islocaltemp = false;
1125  }
1126  break;
1127  default:
1128  elog(ERROR, "invalid relpersistence: %c",
1129  relation->rd_rel->relpersistence);
1130  break;
1131  }
1132 
1133  /*
1134  * initialize the tuple descriptor (relation->rd_att).
1135  */
1136  RelationBuildTupleDesc(relation);
1137 
1138  /*
1139  * Fetch rules and triggers that affect this relation
1140  */
1141  if (relation->rd_rel->relhasrules)
1142  RelationBuildRuleLock(relation);
1143  else
1144  {
1145  relation->rd_rules = NULL;
1146  relation->rd_rulescxt = NULL;
1147  }
1148 
1149  if (relation->rd_rel->relhastriggers)
1150  RelationBuildTriggers(relation);
1151  else
1152  relation->trigdesc = NULL;
1153 
1154  if (relation->rd_rel->relrowsecurity)
1155  RelationBuildRowSecurity(relation);
1156  else
1157  relation->rd_rsdesc = NULL;
1158 
1159  /* foreign key data is not loaded till asked for */
1160  relation->rd_fkeylist = NIL;
1161  relation->rd_fkeyvalid = false;
1162 
1163  /* partitioning data is not loaded till asked for */
1164  relation->rd_partkey = NULL;
1165  relation->rd_partkeycxt = NULL;
1166  relation->rd_partdesc = NULL;
1167  relation->rd_pdcxt = NULL;
1168  relation->rd_partcheck = NIL;
1169  relation->rd_partcheckvalid = false;
1170  relation->rd_partcheckcxt = NULL;
1171 
1172  /*
1173  * initialize access method information
1174  */
1175  switch (relation->rd_rel->relkind)
1176  {
1177  case RELKIND_INDEX:
1178  case RELKIND_PARTITIONED_INDEX:
1179  Assert(relation->rd_rel->relam != InvalidOid);
1180  RelationInitIndexAccessInfo(relation);
1181  break;
1182  case RELKIND_RELATION:
1183  case RELKIND_TOASTVALUE:
1184  case RELKIND_MATVIEW:
1185  Assert(relation->rd_rel->relam != InvalidOid);
1187  break;
1188  case RELKIND_SEQUENCE:
1189  Assert(relation->rd_rel->relam == InvalidOid);
1191  break;
1192  case RELKIND_VIEW:
1193  case RELKIND_COMPOSITE_TYPE:
1194  case RELKIND_FOREIGN_TABLE:
1195  case RELKIND_PARTITIONED_TABLE:
1196  Assert(relation->rd_rel->relam == InvalidOid);
1197  break;
1198  }
1199 
1200  /* extract reloptions if any */
1201  RelationParseRelOptions(relation, pg_class_tuple);
1202 
1203  /*
1204  * initialize the relation lock manager information
1205  */
1206  RelationInitLockInfo(relation); /* see lmgr.c */
1207 
1208  /*
1209  * initialize physical addressing information for the relation
1210  */
1211  RelationInitPhysicalAddr(relation);
1212 
1213  /* make sure relation is marked as having no open file yet */
1214  relation->rd_smgr = NULL;
1215 
1216  /*
1217  * now we can free the memory allocated for pg_class_tuple
1218  */
1219  heap_freetuple(pg_class_tuple);
1220 
1221  /*
1222  * Insert newly created relation into relcache hash table, if requested.
1223  *
1224  * There is one scenario in which we might find a hashtable entry already
1225  * present, even though our caller failed to find it: if the relation is a
1226  * system catalog or index that's used during relcache load, we might have
1227  * recursively created the same relcache entry during the preceding steps.
1228  * So allow RelationCacheInsert to delete any already-present relcache
1229  * entry for the same OID. The already-present entry should have refcount
1230  * zero (else somebody forgot to close it); in the event that it doesn't,
1231  * we'll elog a WARNING and leak the already-present entry.
1232  */
1233  if (insertIt)
1234  RelationCacheInsert(relation, true);
1235 
1236  /* It's fully valid */
1237  relation->rd_isvalid = true;
1238 
1239 #if RECOVER_RELATION_BUILD_MEMORY
1240  /* Return to caller's context, and blow away the temporary context */
1241  MemoryContextSwitchTo(oldcxt);
1242  MemoryContextDelete(tmpcxt);
1243 #endif
1244 
1245  return relation;
1246 }
#define NIL
Definition: pg_list.h:65
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:192
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3173
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1725
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * rd_fkeylist
Definition: rel.h:95
bool rd_partcheckvalid
Definition: rel.h:108
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3266
MemoryContext rd_rulescxt
Definition: rel.h:89
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:380
PartitionKey rd_partkey
Definition: rel.h:99
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
#define BackendIdForTempRelations()
Definition: backendid.h:34
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:435
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:492
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
PartitionDesc rd_partdesc
Definition: rel.h:103
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:186
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
MemoryContext rd_pdcxt
Definition: rel.h:104
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:739
MemoryContext rd_partkeycxt
Definition: rel.h:100
RuleLock * rd_rules
Definition: rel.h:88
#define InvalidSubTransactionId
Definition: c.h:520
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1347
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1922
int rd_refcnt
Definition: rel.h:58
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:310
#define elog(elevel,...)
Definition: elog.h:228
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:726
MemoryContext rd_partcheckcxt
Definition: rel.h:109
bool rd_fkeyvalid
Definition: rel.h:96
#define RelationGetRelid(relation)
Definition: rel.h:428
List * rd_partcheck
Definition: rel.h:107

◆ RelationBuildLocalRelation()

Relation RelationBuildLocalRelation ( const char *  relname,
Oid  relnamespace,
TupleDesc  tupDesc,
Oid  relid,
Oid  accessmtd,
Oid  relfilenode,
Oid  reltablespace,
bool  shared_relation,
bool  mapped_relation,
char  relpersistence,
char  relkind 
)

Definition at line 3178 of file relcache.c.

References Assert, AssertArg, BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationMapUpdateMap(), relfilenode, relkind, relpersistence, TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

3189 {
3190  Relation rel;
3191  MemoryContext oldcxt;
3192  int natts = tupDesc->natts;
3193  int i;
3194  bool has_not_null;
3195  bool nailit;
3196 
3197  AssertArg(natts >= 0);
3198 
3199  /*
3200  * check for creation of a rel that must be nailed in cache.
3201  *
3202  * XXX this list had better match the relations specially handled in
3203  * RelationCacheInitializePhase2/3.
3204  */
3205  switch (relid)
3206  {
3207  case DatabaseRelationId:
3208  case AuthIdRelationId:
3209  case AuthMemRelationId:
3210  case RelationRelationId:
3211  case AttributeRelationId:
3212  case ProcedureRelationId:
3213  case TypeRelationId:
3214  nailit = true;
3215  break;
3216  default:
3217  nailit = false;
3218  break;
3219  }
3220 
3221  /*
3222  * check that hardwired list of shared rels matches what's in the
3223  * bootstrap .bki file. If you get a failure here during initdb, you
3224  * probably need to fix IsSharedRelation() to match whatever you've done
3225  * to the set of shared relations.
3226  */
3227  if (shared_relation != IsSharedRelation(relid))
3228  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3229  relname, relid);
3230 
3231  /* Shared relations had better be mapped, too */
3232  Assert(mapped_relation || !shared_relation);
3233 
3234  /*
3235  * switch to the cache context to create the relcache entry.
3236  */
3237  if (!CacheMemoryContext)
3239 
3241 
3242  /*
3243  * allocate a new relation descriptor and fill in basic state fields.
3244  */
3245  rel = (Relation) palloc0(sizeof(RelationData));
3246 
3247  /* make sure relation is marked as having no open file yet */
3248  rel->rd_smgr = NULL;
3249 
3250  /* mark it nailed if appropriate */
3251  rel->rd_isnailed = nailit;
3252 
3253  rel->rd_refcnt = nailit ? 1 : 0;
3254 
3255  /* it's being created in this transaction */
3258 
3259  /*
3260  * create a new tuple descriptor from the one passed in. We do this
3261  * partly to copy it into the cache context, and partly because the new
3262  * relation can't have any defaults or constraints yet; they have to be
3263  * added in later steps, because they require additions to multiple system
3264  * catalogs. We can copy attnotnull constraints here, however.
3265  */
3266  rel->rd_att = CreateTupleDescCopy(tupDesc);
3267  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3268  has_not_null = false;
3269  for (i = 0; i < natts; i++)
3270  {
3271  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3272  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3273 
3274  datt->attidentity = satt->attidentity;
3275  datt->attgenerated = satt->attgenerated;
3276  datt->attnotnull = satt->attnotnull;
3277  has_not_null |= satt->attnotnull;
3278  }
3279 
3280  if (has_not_null)
3281  {
3282  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3283 
3284  constr->has_not_null = true;
3285  rel->rd_att->constr = constr;
3286  }
3287 
3288  /*
3289  * initialize relation tuple form (caller may add/override data later)
3290  */
3292 
3293  namestrcpy(&rel->rd_rel->relname, relname);
3294  rel->rd_rel->relnamespace = relnamespace;
3295 
3296  rel->rd_rel->relkind = relkind;
3297  rel->rd_rel->relnatts = natts;
3298  rel->rd_rel->reltype = InvalidOid;
3299  /* needed when bootstrapping: */
3300  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3301 
3302  /* set up persistence and relcache fields dependent on it */
3303  rel->rd_rel->relpersistence = relpersistence;
3304  switch (relpersistence)
3305  {
3306  case RELPERSISTENCE_UNLOGGED:
3307  case RELPERSISTENCE_PERMANENT:
3309  rel->rd_islocaltemp = false;
3310  break;
3311  case RELPERSISTENCE_TEMP:
3312  Assert(isTempOrTempToastNamespace(relnamespace));
3314  rel->rd_islocaltemp = true;
3315  break;
3316  default:
3317  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3318  break;
3319  }
3320 
3321  /* if it's a materialized view, it's not populated initially */
3322  if (relkind == RELKIND_MATVIEW)
3323  rel->rd_rel->relispopulated = false;
3324  else
3325  rel->rd_rel->relispopulated = true;
3326 
3327  /* set replica identity -- system catalogs and non-tables don't have one */
3328  if (!IsCatalogNamespace(relnamespace) &&
3329  (relkind == RELKIND_RELATION ||
3330  relkind == RELKIND_MATVIEW ||
3331  relkind == RELKIND_PARTITIONED_TABLE))
3332  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3333  else
3334  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3335 
3336  /*
3337  * Insert relation physical and logical identifiers (OIDs) into the right
3338  * places. For a mapped relation, we set relfilenode to zero and rely on
3339  * RelationInitPhysicalAddr to consult the map.
3340  */
3341  rel->rd_rel->relisshared = shared_relation;
3342 
3343  RelationGetRelid(rel) = relid;
3344 
3345  for (i = 0; i < natts; i++)
3346  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3347 
3348  rel->rd_rel->reltablespace = reltablespace;
3349 
3350  if (mapped_relation)
3351  {
3352  rel->rd_rel->relfilenode = InvalidOid;
3353  /* Add it to the active mapping information */
3354  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3355  }
3356  else
3357  rel->rd_rel->relfilenode = relfilenode;
3358 
3359  RelationInitLockInfo(rel); /* see lmgr.c */
3360 
3362 
3363  rel->rd_rel->relam = accessmtd;
3364 
3365  if (relkind == RELKIND_RELATION ||
3366  relkind == RELKIND_SEQUENCE ||
3367  relkind == RELKIND_TOASTVALUE ||
3368  relkind == RELKIND_MATVIEW)
3370 
3371  /*
3372  * Okay to insert into the relcache hash table.
3373  *
3374  * Ordinarily, there should certainly not be an existing hash entry for
3375  * the same OID; but during bootstrap, when we create a "real" relcache
3376  * entry for one of the bootstrap relations, we'll be overwriting the
3377  * phony one created with formrdesc. So allow that to happen for nailed
3378  * rels.
3379  */
3380  RelationCacheInsert(rel, nailit);
3381 
3382  /*
3383  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3384  * can't do this before storing relid in it.
3385  */
3386  EOXactListAdd(rel);
3387 
3388  /*
3389  * done building relcache entry.
3390  */
3391  MemoryContextSwitchTo(oldcxt);
3392 
3393  /* It's fully valid */
3394  rel->rd_isvalid = true;
3395 
3396  /*
3397  * Caller expects us to pin the returned entry.
3398  */
3400 
3401  return rel;
3402 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define EOXactListAdd(rel)
Definition: relcache.c:166
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3173
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1725
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Form_pg_class rd_rel
Definition: rel.h:84
NameData relname
Definition: pg_class.h:35
int namestrcpy(Name name, const char *str)
Definition: name.c:250
char relkind
Definition: pg_class.h:81
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:78
Oid relfilenode
Definition: pg_class.h:54
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
#define BackendIdForTempRelations()
Definition: backendid.h:34
TupleConstr * constr
Definition: tupdesc.h:85
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define AssertArg(condition)
Definition: c.h:741
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:980
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2041
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:239
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:186
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:739
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:707
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define InvalidSubTransactionId
Definition: c.h:520
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:178
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:228
int i
int tdrefcount
Definition: tupdesc.h:84
bool has_not_null
Definition: tupdesc.h:44
#define RelationGetRelid(relation)
Definition: rel.h:428
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:261
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 726 of file relcache.c.

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

727 {
728  MemoryContext rulescxt;
729  MemoryContext oldcxt;
730  HeapTuple rewrite_tuple;
731  Relation rewrite_desc;
732  TupleDesc rewrite_tupdesc;
733  SysScanDesc rewrite_scan;
735  RuleLock *rulelock;
736  int numlocks;
737  RewriteRule **rules;
738  int maxlocks;
739 
740  /*
741  * Make the private context. Assume it'll not contain much data.
742  */
744  "relation rules",
746  relation->rd_rulescxt = rulescxt;
748  RelationGetRelationName(relation));
749 
750  /*
751  * allocate an array to hold the rewrite rules (the array is extended if
752  * necessary)
753  */
754  maxlocks = 4;
755  rules = (RewriteRule **)
756  MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
757  numlocks = 0;
758 
759  /*
760  * form a scan key
761  */
762  ScanKeyInit(&key,
763  Anum_pg_rewrite_ev_class,
764  BTEqualStrategyNumber, F_OIDEQ,
766 
767  /*
768  * open pg_rewrite and begin a scan
769  *
770  * Note: since we scan the rules using RewriteRelRulenameIndexId, we will
771  * be reading the rules in name order, except possibly during
772  * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
773  * ensures that rules will be fired in name order.
774  */
775  rewrite_desc = table_open(RewriteRelationId, AccessShareLock);
776  rewrite_tupdesc = RelationGetDescr(rewrite_desc);
777  rewrite_scan = systable_beginscan(rewrite_desc,
779  true, NULL,
780  1, &key);
781 
782  while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
783  {
784  Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
785  bool isnull;
786  Datum rule_datum;
787  char *rule_str;
788  RewriteRule *rule;
789 
790  rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
791  sizeof(RewriteRule));
792 
793  rule->ruleId = rewrite_form->oid;
794 
795  rule->event = rewrite_form->ev_type - '0';
796  rule->enabled = rewrite_form->ev_enabled;
797  rule->isInstead = rewrite_form->is_instead;
798 
799  /*
800  * Must use heap_getattr to fetch ev_action and ev_qual. Also, the
801  * rule strings are often large enough to be toasted. To avoid
802  * leaking memory in the caller's context, do the detoasting here so
803  * we can free the detoasted version.
804  */
805  rule_datum = heap_getattr(rewrite_tuple,
806  Anum_pg_rewrite_ev_action,
807  rewrite_tupdesc,
808  &isnull);
809  Assert(!isnull);
810  rule_str = TextDatumGetCString(rule_datum);
811  oldcxt = MemoryContextSwitchTo(rulescxt);
812  rule->actions = (List *) stringToNode(rule_str);
813  MemoryContextSwitchTo(oldcxt);
814  pfree(rule_str);
815 
816  rule_datum = heap_getattr(rewrite_tuple,
817  Anum_pg_rewrite_ev_qual,
818  rewrite_tupdesc,
819  &isnull);
820  Assert(!isnull);
821  rule_str = TextDatumGetCString(rule_datum);
822  oldcxt = MemoryContextSwitchTo(rulescxt);
823  rule->qual = (Node *) stringToNode(rule_str);
824  MemoryContextSwitchTo(oldcxt);
825  pfree(rule_str);
826 
827  /*
828  * We want the rule's table references to be checked as though by the
829  * table owner, not the user referencing the rule. Therefore, scan
830  * through the rule's actions and set the checkAsUser field on all
831  * rtable entries. We have to look at the qual as well, in case it
832  * contains sublinks.
833  *
834  * The reason for doing this when the rule is loaded, rather than when
835  * it is stored, is that otherwise ALTER TABLE OWNER would have to
836  * grovel through stored rules to update checkAsUser fields. Scanning
837  * the rule tree during load is relatively cheap (compared to
838  * constructing it in the first place), so we do it here.
839  */
840  setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner);
841  setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner);
842 
843  if (numlocks >= maxlocks)
844  {
845  maxlocks *= 2;
846  rules = (RewriteRule **)
847  repalloc(rules, sizeof(RewriteRule *) * maxlocks);
848  }
849  rules[numlocks++] = rule;
850  }
851 
852  /*
853  * end the scan and close the attribute relation
854  */
855  systable_endscan(rewrite_scan);
856  table_close(rewrite_desc, AccessShareLock);
857 
858  /*
859  * there might not be any rules (if relhasrules is out-of-date)
860  */
861  if (numlocks == 0)
862  {
863  relation->rd_rules = NULL;
864  relation->rd_rulescxt = NULL;
865  MemoryContextDelete(rulescxt);
866  return;
867  }
868 
869  /*
870  * form a RuleLock and insert into relation
871  */
872  rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
873  rulelock->numLocks = numlocks;
874  rulelock->rules = rules;
875 
876  relation->rd_rules = rulelock;
877 }
Node * qual
Definition: prs2lock.h:28
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int numLocks
Definition: prs2lock.h:42
void setRuleCheckAsUser(Node *node, Oid userid)
#define RelationGetDescr(relation)
Definition: rel.h:454
#define RewriteRelRulenameIndexId
Definition: indexing.h:220
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:525
void * stringToNode(const char *str)
Definition: read.c:89
MemoryContext rd_rulescxt
Definition: rel.h:89
Form_pg_class rd_rel
Definition: rel.h:84
bool isInstead
Definition: prs2lock.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
Definition: localtime.c:79
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:97
CmdType event
Definition: prs2lock.h:27
static struct rule * rules
Definition: zic.c:278
#define RelationGetRelationName(relation)
Definition: rel.h:462
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:88
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
FormData_pg_rewrite * Form_pg_rewrite
Definition: pg_rewrite.h:52
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:428
Oid ruleId
Definition: prs2lock.h:26
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
char enabled
Definition: prs2lock.h:30

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 492 of file relcache.c.

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

Referenced by RelationBuildDesc().

493 {
494  HeapTuple pg_attribute_tuple;
495  Relation pg_attribute_desc;
496  SysScanDesc pg_attribute_scan;
497  ScanKeyData skey[2];
498  int need;
499  TupleConstr *constr;
500  AttrDefault *attrdef = NULL;
501  AttrMissing *attrmiss = NULL;
502  int ndef = 0;
503 
504  /* copy some fields from pg_class row to rd_att */
505  relation->rd_att->tdtypeid = relation->rd_rel->reltype;
506  relation->rd_att->tdtypmod = -1; /* unnecessary, but... */
507 
509  sizeof(TupleConstr));
510  constr->has_not_null = false;
511  constr->has_generated_stored = false;
512 
513  /*
514  * Form a scan key that selects only user attributes (attnum > 0).
515  * (Eliminating system attribute rows at the index level is lots faster
516  * than fetching them.)
517  */
518  ScanKeyInit(&skey[0],
519  Anum_pg_attribute_attrelid,
520  BTEqualStrategyNumber, F_OIDEQ,
522  ScanKeyInit(&skey[1],
523  Anum_pg_attribute_attnum,
524  BTGreaterStrategyNumber, F_INT2GT,
525  Int16GetDatum(0));
526 
527  /*
528  * Open pg_attribute and begin a scan. Force heap scan if we haven't yet
529  * built the critical relcache entries (this includes initdb and startup
530  * without a pg_internal.init file).
531  */
532  pg_attribute_desc = table_open(AttributeRelationId, AccessShareLock);
533  pg_attribute_scan = systable_beginscan(pg_attribute_desc,
536  NULL,
537  2, skey);
538 
539  /*
540  * add attribute data to relation->rd_att
541  */
542  need = RelationGetNumberOfAttributes(relation);
543 
544  while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
545  {
546  Form_pg_attribute attp;
547  int attnum;
548 
549  attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
550 
551  attnum = attp->attnum;
552  if (attnum <= 0 || attnum > RelationGetNumberOfAttributes(relation))
553  elog(ERROR, "invalid attribute number %d for %s",
554  attp->attnum, RelationGetRelationName(relation));
555 
556 
557  memcpy(TupleDescAttr(relation->rd_att, attnum - 1),
558  attp,
560 
561  /* Update constraint/default info */
562  if (attp->attnotnull)
563  constr->has_not_null = true;
564  if (attp->attgenerated == ATTRIBUTE_GENERATED_STORED)
565  constr->has_generated_stored = true;
566 
567  /* If the column has a default, fill it into the attrdef array */
568  if (attp->atthasdef)
569  {
570  if (attrdef == NULL)
571  attrdef = (AttrDefault *)
574  sizeof(AttrDefault));
575  attrdef[ndef].adnum = attnum;
576  attrdef[ndef].adbin = NULL;
577 
578  ndef++;
579  }
580 
581  /* Likewise for a missing value */
582  if (attp->atthasmissing)
583  {
584  Datum missingval;
585  bool missingNull;
586 
587  /* Do we have a missing value? */
588  missingval = heap_getattr(pg_attribute_tuple,
589  Anum_pg_attribute_attmissingval,
590  pg_attribute_desc->rd_att,
591  &missingNull);
592  if (!missingNull)
593  {
594  /* Yes, fetch from the array */
595  MemoryContext oldcxt;
596  bool is_null;
597  int one = 1;
598  Datum missval;
599 
600  if (attrmiss == NULL)
601  attrmiss = (AttrMissing *)
603  relation->rd_rel->relnatts *
604  sizeof(AttrMissing));
605 
606  missval = array_get_element(missingval,
607  1,
608  &one,
609  -1,
610  attp->attlen,
611  attp->attbyval,
612  attp->attalign,
613  &is_null);
614  Assert(!is_null);
615  if (attp->attbyval)
616  {
617  /* for copy by val just copy the datum direct */
618  attrmiss[attnum - 1].am_value = missval;
619  }
620  else
621  {
622  /* otherwise copy in the correct context */
624  attrmiss[attnum - 1].am_value = datumCopy(missval,
625  attp->attbyval,
626  attp->attlen);
627  MemoryContextSwitchTo(oldcxt);
628  }
629  attrmiss[attnum - 1].am_present = true;
630  }
631  }
632  need--;
633  if (need == 0)
634  break;
635  }
636 
637  /*
638  * end the scan and close the attribute relation
639  */
640  systable_endscan(pg_attribute_scan);
641  table_close(pg_attribute_desc, AccessShareLock);
642 
643  if (need != 0)
644  elog(ERROR, "catalog is missing %d attribute(s) for relid %u",
645  need, RelationGetRelid(relation));
646 
647  /*
648  * The attcacheoff values we read from pg_attribute should all be -1
649  * ("unknown"). Verify this if assert checking is on. They will be
650  * computed when and if needed during tuple access.
651  */
652 #ifdef USE_ASSERT_CHECKING
653  {
654  int i;
655 
656  for (i = 0; i < RelationGetNumberOfAttributes(relation); i++)
657  Assert(TupleDescAttr(relation->rd_att, i)->attcacheoff == -1);
658  }
659 #endif
660 
661  /*
662  * However, we can easily set the attcacheoff value for the first
663  * attribute: it must be zero. This eliminates the need for special cases
664  * for attnum=1 that used to exist in fastgetattr() and index_getattr().
665  */
666  if (RelationGetNumberOfAttributes(relation) > 0)
667  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
668 
669  /*
670  * Set up constraint/default info
671  */
672  if (constr->has_not_null || ndef > 0 ||
673  attrmiss || relation->rd_rel->relchecks)
674  {
675  relation->rd_att->constr = constr;
676 
677  if (ndef > 0) /* DEFAULTs */
678  {
679  if (ndef < RelationGetNumberOfAttributes(relation))
680  constr->defval = (AttrDefault *)
681  repalloc(attrdef, ndef * sizeof(AttrDefault));
682  else
683  constr->defval = attrdef;
684  constr->num_defval = ndef;
685  AttrDefaultFetch(relation);
686  }
687  else
688  constr->num_defval = 0;
689 
690  constr->missing = attrmiss;
691 
692  if (relation->rd_rel->relchecks > 0) /* CHECKs */
693  {
694  constr->num_check = relation->rd_rel->relchecks;
695  constr->check = (ConstrCheck *)
697  constr->num_check * sizeof(ConstrCheck));
698  CheckConstraintFetch(relation);
699  }
700  else
701  constr->num_check = 0;
702  }
703  else
704  {
705  pfree(constr);
706  relation->rd_att->constr = NULL;
707  }
708 }
#define AttributeRelidNumIndexId
Definition: indexing.h:96
static void AttrDefaultFetch(Relation relation)
Definition: relcache.c:4057
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:434
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:451
#define AccessShareLock
Definition: lockdefs.h:36
Form_pg_class rd_rel
Definition: rel.h:84
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
AttrDefault * defval
Definition: tupdesc.h:39
struct AttrDefault AttrDefault
bool has_generated_stored
Definition: tupdesc.h:45
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
TupleConstr * constr
Definition: tupdesc.h:85
#define RelationGetRelationName(relation)
Definition: rel.h:462
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:192
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
uint16 num_check
Definition: tupdesc.h:43
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
int16 attnum
Definition: pg_attribute.h:79
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1819
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4127
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
struct AttrMissing * missing
Definition: tupdesc.h:41
uint16 num_defval
Definition: tupdesc.h:42
Oid tdtypeid
Definition: tupdesc.h:82
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:228
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
ConstrCheck * check
Definition: tupdesc.h:40
bool criticalRelcachesBuilt
Definition: relcache.c:135
bool has_not_null
Definition: tupdesc.h:44
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:428
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 5997 of file relcache.c.

References LWLockRelease().

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

5998 {
5999  LWLockRelease(RelCacheInitLock);
6000 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 5972 of file relcache.c.

References DatabasePath, ERROR, LW_EXCLUSIVE, LWLockAcquire(), MAXPGPATH, RELCACHE_INIT_FILENAME, snprintf, and unlink_initfile().

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

5973 {
5974  char localinitfname[MAXPGPATH];
5975  char sharedinitfname[MAXPGPATH];
5976 
5977  if (DatabasePath)
5978  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
5980  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
5982 
5983  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
5984 
5985  /*
5986  * The files might not be there if no backend has been started since the
5987  * last removal. But complain about failures other than ENOENT with
5988  * ERROR. Fortunately, it's not too late to abort the transaction if we
5989  * can't get rid of the would-be-obsolete init file.
5990  */
5991  if (DatabasePath)
5992  unlink_initfile(localinitfname, ERROR);
5993  unlink_initfile(sharedinitfname, ERROR);
5994 }
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char * DatabasePath
Definition: globals.c:93
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6069
#define snprintf
Definition: port.h:192

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6012 of file relcache.c.

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

Referenced by StartupXLOG().

6013 {
6014  const char *tblspcdir = "pg_tblspc";
6015  DIR *dir;
6016  struct dirent *de;
6017  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6018 
6019  snprintf(path, sizeof(path), "global/%s",
6021  unlink_initfile(path, LOG);
6022 
6023  /* Scan everything in the default tablespace */
6025 
6026  /* Scan the tablespace link directory to find non-default tablespaces */
6027  dir = AllocateDir(tblspcdir);
6028 
6029  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6030  {
6031  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6032  {
6033  /* Scan the tablespace dir for per-database dirs */
6034  snprintf(path, sizeof(path), "%s/%s/%s",
6035  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6037  }
6038  }
6039 
6040  FreeDir(dir);
6041 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6045
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2584
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2503
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6069
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2621

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6045 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6046 {
6047  DIR *dir;
6048  struct dirent *de;
6049  char initfilename[MAXPGPATH * 2];
6050 
6051  /* Scan the tablespace directory to find per-database directories */
6052  dir = AllocateDir(tblspcpath);
6053 
6054  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6055  {
6056  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6057  {
6058  /* Try to remove the init file in each database */
6059  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6060  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6061  unlink_initfile(initfilename, LOG);
6062  }
6063  }
6064 
6065  FreeDir(dir);
6066 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2584
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2503
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6069
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2621

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3582 of file relcache.c.

References CacheMemoryContext, CreateCacheMemoryContext(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, INITRELCACHESIZE, HASHCTL::keysize, MemSet, and RelationMapInitialize().

Referenced by InitPostgres().

3583 {
3584  HASHCTL ctl;
3585 
3586  /*
3587  * make sure cache memory context exists
3588  */
3589  if (!CacheMemoryContext)
3591 
3592  /*
3593  * create hashtable that indexes the relcache
3594  */
3595  MemSet(&ctl, 0, sizeof(ctl));
3596  ctl.keysize = sizeof(Oid);
3597  ctl.entrysize = sizeof(RelIdCacheEnt);
3598  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3599  &ctl, HASH_ELEM | HASH_BLOBS);
3600 
3601  /*
3602  * relation mapper needs to be initialized too
3603  */
3605 }
void RelationMapInitialize(void)
Definition: relmapper.c:584
#define HASH_ELEM
Definition: hsearch.h:87
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:962
static HTAB * RelationIdCache
Definition: relcache.c:129
unsigned int Oid
Definition: postgres_ext.h:31
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define INITRELCACHESIZE
Definition: relcache.c:3579
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3619 of file relcache.c.

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().

3620 {
3621  MemoryContext oldcxt;
3622 
3623  /*
3624  * relation mapper needs initialized too
3625  */
3627 
3628  /*
3629  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3630  * nothing.
3631  */
3633  return;
3634 
3635  /*
3636  * switch to cache memory context
3637  */
3639 
3640  /*
3641  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3642  * the cache with pre-made descriptors for the critical shared catalogs.
3643  */
3644  if (!load_relcache_init_file(true))
3645  {
3646  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3647  Natts_pg_database, Desc_pg_database);
3648  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3649  Natts_pg_authid, Desc_pg_authid);
3650  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3651  Natts_pg_auth_members, Desc_pg_auth_members);
3652  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3653  Natts_pg_shseclabel, Desc_pg_shseclabel);
3654  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3655  Natts_pg_subscription, Desc_pg_subscription);
3656 
3657 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3658  }
3659 
3660  MemoryContextSwitchTo(oldcxt);
3661 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:112
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5319
void RelationMapInitializePhase2(void)
Definition: relmapper.c:604
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:111
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:115
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:110
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:114
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1789
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3678 of file relcache.c.

References AccessMethodProcedureIndexId, Assert, AttributeRelidNumIndexId, AuthIdOidIndexId, AuthIdRolnameIndexId, AuthMemMemRoleIndexId, CacheMemoryContext, CLASS_TUPLE_SIZE, ClassOidIndexId, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabaseNameIndexId, DatabaseOidIndexId, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ERROR, FATAL, formrdesc(), GETSTRUCT, hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, IndexRelidIndexId, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum, OpclassOidIndexId, 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, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, RewriteRelRulenameIndexId, SearchSysCache1(), SharedSecLabelObjectIndexId, status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, TriggerRelidNameIndexId, and write_relcache_init_file().

Referenced by InitPostgres().

3679 {
3681  RelIdCacheEnt *idhentry;
3682  MemoryContext oldcxt;
3683  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3684 
3685  /*
3686  * relation mapper needs initialized too
3687  */
3689 
3690  /*
3691  * switch to cache memory context
3692  */
3694 
3695  /*
3696  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3697  * the cache with pre-made descriptors for the critical "nailed-in" system
3698  * catalogs.
3699  */
3700  if (IsBootstrapProcessingMode() ||
3701  !load_relcache_init_file(false))
3702  {
3703  needNewCacheFile = true;
3704 
3705  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3706  Natts_pg_class, Desc_pg_class);
3707  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3708  Natts_pg_attribute, Desc_pg_attribute);
3709  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3710  Natts_pg_proc, Desc_pg_proc);
3711  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3712  Natts_pg_type, Desc_pg_type);
3713 
3714 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3715  }
3716 
3717  MemoryContextSwitchTo(oldcxt);
3718 
3719  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3721  return;
3722 
3723  /*
3724  * If we didn't get the critical system indexes loaded into relcache, do
3725  * so now. These are critical because the catcache and/or opclass cache
3726  * depend on them for fetches done during relcache load. Thus, we have an
3727  * infinite-recursion problem. We can break the recursion by doing
3728  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3729  * performance, we only want to do that until we have the critical indexes
3730  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3731  * decide whether to do heapscan or indexscan at the key spots, and we set
3732  * it true after we've loaded the critical indexes.
3733  *
3734  * The critical indexes are marked as "nailed in cache", partly to make it
3735  * easy for load_relcache_init_file to count them, but mainly because we
3736  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3737  * true. (NOTE: perhaps it would be possible to reload them by
3738  * temporarily setting criticalRelcachesBuilt to false again. For now,
3739  * though, we just nail 'em in.)
3740  *
3741  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3742  * in the same way as the others, because the critical catalogs don't
3743  * (currently) have any rules or triggers, and so these indexes can be
3744  * rebuilt without inducing recursion. However they are used during
3745  * relcache load when a rel does have rules or triggers, so we choose to
3746  * nail them for performance reasons.
3747  */
3749  {
3751  RelationRelationId);
3753  AttributeRelationId);
3755  IndexRelationId);
3757  OperatorClassRelationId);
3759  AccessMethodProcedureRelationId);
3761  RewriteRelationId);
3763  TriggerRelationId);
3764 
3765 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3766 
3767  criticalRelcachesBuilt = true;
3768  }
3769 
3770  /*
3771  * Process critical shared indexes too.
3772  *
3773  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3774  * initial lookup of MyDatabaseId, without which we'll never find any
3775  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3776  * database OID, so it instead depends on DatabaseOidIndexId. We also
3777  * need to nail up some indexes on pg_authid and pg_auth_members for use
3778  * during client authentication. SharedSecLabelObjectIndexId isn't
3779  * critical for the core system, but authentication hooks might be
3780  * interested in it.
3781  */
3783  {
3785  DatabaseRelationId);
3787  DatabaseRelationId);
3789  AuthIdRelationId);
3791  AuthIdRelationId);
3793  AuthMemRelationId);
3795  SharedSecLabelRelationId);
3796 
3797 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3798 
3800  }
3801 
3802  /*
3803  * Now, scan all the relcache entries and update anything that might be
3804  * wrong in the results from formrdesc or the relcache cache file. If we
3805  * faked up relcache entries using formrdesc, then read the real pg_class
3806  * rows and replace the fake entries with them. Also, if any of the
3807  * relcache entries have rules, triggers, or security policies, load that
3808  * info the hard way since it isn't recorded in the cache file.
3809  *
3810  * Whenever we access the catalogs to read data, there is a possibility of
3811  * a shared-inval cache flush causing relcache entries to be removed.
3812  * Since hash_seq_search only guarantees to still work after the *current*
3813  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3814  * We handle this by restarting the scan from scratch after each access.
3815  * This is theoretically O(N^2), but the number of entries that actually
3816  * need to be fixed is small enough that it doesn't matter.
3817  */
3818  hash_seq_init(&status, RelationIdCache);
3819 
3820  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3821  {
3822  Relation relation = idhentry->reldesc;
3823  bool restart = false;
3824 
3825  /*
3826  * Make sure *this* entry doesn't get flushed while we work with it.
3827  */
3829 
3830  /*
3831  * If it's a faked-up entry, read the real pg_class tuple.
3832  */
3833  if (relation->rd_rel->relowner == InvalidOid)
3834  {
3835  HeapTuple htup;
3836  Form_pg_class relp;
3837 
3838  htup = SearchSysCache1(RELOID,
3839  ObjectIdGetDatum(RelationGetRelid(relation)));
3840  if (!HeapTupleIsValid(htup))
3841  elog(FATAL, "cache lookup failed for relation %u",
3842  RelationGetRelid(relation));
3843  relp = (Form_pg_class) GETSTRUCT(htup);
3844 
3845  /*
3846  * Copy tuple to relation->rd_rel. (See notes in
3847  * AllocateRelationDesc())
3848  */
3849  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
3850 
3851  /* Update rd_options while we have the tuple */
3852  if (relation->rd_options)
3853  pfree(relation->rd_options);
3854  RelationParseRelOptions(relation, htup);
3855 
3856  /*
3857  * Check the values in rd_att were set up correctly. (We cannot
3858  * just copy them over now: formrdesc must have set up the rd_att
3859  * data correctly to start with, because it may already have been
3860  * copied into one or more catcache entries.)
3861  */
3862  Assert(relation->rd_att->tdtypeid == relp->reltype);
3863  Assert(relation->rd_att->tdtypmod == -1);
3864 
3865  ReleaseSysCache(htup);
3866 
3867  /* relowner had better be OK now, else we'll loop forever */
3868  if (relation->rd_rel->relowner == InvalidOid)
3869  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
3870  RelationGetRelationName(relation));
3871 
3872  restart = true;
3873  }
3874 
3875  /*
3876  * Fix data that isn't saved in relcache cache file.
3877  *
3878  * relhasrules or relhastriggers could possibly be wrong or out of
3879  * date. If we don't actually find any rules or triggers, clear the
3880  * local copy of the flag so that we don't get into an infinite loop
3881  * here. We don't make any attempt to fix the pg_class entry, though.
3882  */
3883  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
3884  {
3885  RelationBuildRuleLock(relation);
3886  if (relation->rd_rules == NULL)
3887  relation->rd_rel->relhasrules = false;
3888  restart = true;
3889  }
3890  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
3891  {
3892  RelationBuildTriggers(relation);
3893  if (relation->trigdesc == NULL)
3894  relation->rd_rel->relhastriggers = false;
3895  restart = true;
3896  }
3897 
3898  /*
3899  * Re-load the row security policies if the relation has them, since
3900  * they are not preserved in the cache. Note that we can never NOT
3901  * have a policy while relrowsecurity is true,
3902  * RelationBuildRowSecurity will create a single default-deny policy
3903  * if there is no policy defined in pg_policy.
3904  */
3905  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
3906  {
3907  RelationBuildRowSecurity(relation);
3908 
3909  Assert(relation->rd_rsdesc != NULL);
3910  restart = true;
3911  }
3912 
3913  /* Reload tableam data if needed */
3914  if (relation->rd_tableam == NULL &&
3915  (relation->rd_rel->relkind == RELKIND_RELATION ||
3916  relation->rd_rel->relkind == RELKIND_SEQUENCE ||
3917  relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
3918  relation->rd_rel->relkind == RELKIND_MATVIEW))
3919  {
3921  Assert(relation->rd_tableam != NULL);
3922 
3923  restart = true;
3924  }
3925 
3926  /* Release hold on the relation */
3928 
3929  /* Now, restart the hashtable scan if needed */
3930  if (restart)
3931  {
3932  hash_seq_term(&status);
3933  hash_seq_init(&status, RelationIdCache);
3934  }
3935  }
3936 
3937  /*
3938  * Lastly, write out new relcache cache files if needed. We don't bother
3939  * to distinguish cases where only one of the two needs an update.
3940  */
3941  if (needNewCacheFile)
3942  {
3943  /*
3944  * Force all the catcaches to finish initializing and thereby open the
3945  * catalogs and indexes they use. This will preload the relcache with
3946  * entries for all the most important system catalogs and indexes, so
3947  * that the init files will be most useful for future backends.
3948  */
3950 
3951  /* now write the files */
3953  write_relcache_init_file(false);
3954  }
3955 }
#define AttributeRelidNumIndexId
Definition: indexing.h:96
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5319
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define IndexRelidIndexId
Definition: indexing.h:168
#define RewriteRelRulenameIndexId
Definition: indexing.h:220
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:192
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1725
Relation reldesc
Definition: relcache.c:126
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:141
#define AuthIdOidIndexId
Definition: indexing.h:101
static HTAB * RelationIdCache
Definition: relcache.c:129
Form_pg_class rd_rel
Definition: rel.h:84
#define TriggerRelidNameIndexId
Definition: indexing.h:256
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2054
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
#define FATAL
Definition: elog.h:52
static void write_relcache_init_file(bool shared)
Definition: relcache.c:5715
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:435
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:3964
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:108
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define DatabaseOidIndexId
Definition: indexing.h:146
#define ClassOidIndexId
Definition: indexing.h:114
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
#define AccessMethodProcedureIndexId
Definition: indexing.h:84
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2041
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
const struct TableAmRoutine * rd_tableam
Definition: rel.h:146
TupleDesc rd_att
Definition: rel.h:85
#define OpclassOidIndexId
Definition: indexing.h:197
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739
#define AuthMemMemRoleIndexId
Definition: indexing.h:106
RuleLock * rd_rules
Definition: rel.h:88
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
#define DatabaseNameIndexId
Definition: indexing.h:144
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define SharedSecLabelObjectIndexId
Definition: indexing.h:323
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
Oid tdtypeid
Definition: tupdesc.h:82
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1922
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1789
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:106
#define elog(elevel,...)
Definition: elog.h:228
void RelationMapInitializePhase3(void)
Definition: relmapper.c:625
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:726
bool criticalRelcachesBuilt
Definition: relcache.c:135
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
#define AuthIdRolnameIndexId
Definition: indexing.h:99
void InitCatalogCachePhase2(void)
Definition: syscache.c:1075
#define RelationGetRelid(relation)
Definition: rel.h:428
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:109
bytea * rd_options
Definition: rel.h:132
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:107
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2781 of file relcache.c.

References Assert, ClassOidIndexId, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_isnailed, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCaches(), and LocalExecuteInvalidationMessage().

2782 {
2784  RelIdCacheEnt *idhentry;
2785  Relation relation;
2786  List *rebuildFirstList = NIL;
2787  List *rebuildList = NIL;
2788  ListCell *l;
2789 
2790  /*
2791  * Reload relation mapping data before starting to reconstruct cache.
2792  */
2794 
2795  /* Phase 1 */
2796  hash_seq_init(&status, RelationIdCache);
2797 
2798  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2799  {
2800  relation = idhentry->reldesc;
2801 
2802  /* Must close all smgr references to avoid leaving dangling ptrs */
2803  RelationCloseSmgr(relation);
2804 
2805  /*
2806  * Ignore new relations; no other backend will manipulate them before
2807  * we commit. Likewise, before replacing a relation's relfilenode, we
2808  * shall have acquired AccessExclusiveLock and drained any applicable
2809  * pending invalidations.
2810  */
2811  if (relation->rd_createSubid != InvalidSubTransactionId ||
2813  continue;
2814 
2816 
2817  if (RelationHasReferenceCountZero(relation))
2818  {
2819  /* Delete this entry immediately */
2820  Assert(!relation->rd_isnailed);
2821  RelationClearRelation(relation, false);
2822  }
2823  else
2824  {
2825  /*
2826  * If it's a mapped relation, immediately update its rd_node in
2827  * case its relfilenode changed. We must do this during phase 1
2828  * in case the relation is consulted during rebuild of other
2829  * relcache entries in phase 2. It's safe since consulting the
2830  * map doesn't involve any access to relcache entries.
2831  */
2832  if (RelationIsMapped(relation))
2833  RelationInitPhysicalAddr(relation);
2834 
2835  /*
2836  * Add this entry to list of stuff to rebuild in second pass.
2837  * pg_class goes to the front of rebuildFirstList while
2838  * pg_class_oid_index goes to the back of rebuildFirstList, so
2839  * they are done first and second respectively. Other nailed
2840  * relations go to the front of rebuildList, so they'll be done
2841  * next in no particular order; and everything else goes to the
2842  * back of rebuildList.
2843  */
2844  if (RelationGetRelid(relation) == RelationRelationId)
2845  rebuildFirstList = lcons(relation, rebuildFirstList);
2846  else if (RelationGetRelid(relation) == ClassOidIndexId)
2847  rebuildFirstList = lappend(rebuildFirstList, relation);
2848  else if (relation->rd_isnailed)
2849  rebuildList = lcons(relation, rebuildList);
2850  else
2851  rebuildList = lappend(rebuildList, relation);
2852  }
2853  }
2854 
2855  /*
2856  * Now zap any remaining smgr cache entries. This must happen before we
2857  * start to rebuild entries, since that may involve catalog fetches which
2858  * will re-open catalog files.
2859  */
2860  smgrcloseall();
2861 
2862  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2863  foreach(l, rebuildFirstList)
2864  {
2865  relation = (Relation) lfirst(l);
2866  RelationClearRelation(relation, true);
2867  }
2868  list_free(rebuildFirstList);
2869  foreach(l, rebuildList)
2870  {
2871  relation = (Relation) lfirst(l);
2872  RelationClearRelation(relation, true);
2873  }
2874  list_free(rebuildList);
2875 }
#define NIL
Definition: pg_list.h:65
static long relcacheInvalsReceived
Definition: relcache.c:149
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2394
bool rd_isnailed
Definition: rel.h:61
Relation reldesc
Definition: relcache.c:126
#define RelationCloseSmgr(relation)
Definition: rel.h:497
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
static HTAB * RelationIdCache
Definition: relcache.c:129
void smgrcloseall(void)
Definition: smgr.c:286
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
#define ClassOidIndexId
Definition: indexing.h:114
List * lappend(List *list, void *datum)
Definition: list.c:322
#define RelationIsMapped(relation)
Definition: rel.h:477
SubTransactionId rd_createSubid
Definition: rel.h:80
List * lcons(void *datum, List *list)
Definition: list.c:454
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:520
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:412
void list_free(List *list)
Definition: list.c:1377
void RelationMapInvalidateAll(void)
Definition: relmapper.c:425
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:428

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2737 of file relcache.c.

References PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.

Referenced by LocalExecuteInvalidationMessage().

2738 {
2739  Relation relation;
2740 
2741  RelationIdCacheLookup(relationId, relation);
2742 
2743  if (PointerIsValid(relation))
2744  {
2746  RelationFlushRelation(relation);
2747  }
2748 }
static long relcacheInvalsReceived
Definition: relcache.c:149
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:208
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2669
#define PointerIsValid(pointer)
Definition: c.h:633

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2394 of file relcache.c.

References Assert, CLASS_TUPLE_SIZE, elog, equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), IsTransactionState(), MemoryContextSetParent(), pfree(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_pdcxt, 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(), RelationClose(), RelationFlushRelation(), RelationForgetRelation(), and RelationIdGetRelation().

2395 {
2396  /*
2397  * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of
2398  * course it would be an equally bad idea to blow away one with nonzero
2399  * refcnt, since that would leave someone somewhere with a dangling
2400  * pointer. All callers are expected to have verified that this holds.
2401  */
2402  Assert(rebuild ?
2403  !RelationHasReferenceCountZero(relation) :
2404  RelationHasReferenceCountZero(relation));
2405 
2406  /*
2407  * Make sure smgr and lower levels close the relation's files, if they
2408  * weren't closed already. If the relation is not getting deleted, the
2409  * next smgr access should reopen the files automatically. This ensures
2410  * that the low-level file access state is updated after, say, a vacuum
2411  * truncation.
2412  */
2413  RelationCloseSmgr(relation);
2414 
2415  /* Free AM cached data, if any */
2416  if (relation->rd_amcache)
2417  pfree(relation->rd_amcache);
2418  relation->rd_amcache = NULL;
2419 
2420  /*
2421  * Treat nailed-in system relations separately, they always need to be
2422  * accessible, so we can't blow them away.
2423  */
2424  if (relation->rd_isnailed)
2425  {
2426  RelationReloadNailed(relation);
2427  return;
2428  }
2429 
2430  /*
2431  * Even non-system indexes should not be blown away if they are open and
2432  * have valid index support information. This avoids problems with active
2433  * use of the index support information. As with nailed indexes, we
2434  * re-read the pg_class row to handle possible physical relocation of the
2435  * index, and we check for pg_index updates too.
2436  */
2437  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2438  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2439  relation->rd_refcnt > 0 &&
2440  relation->rd_indexcxt != NULL)
2441  {
2442  relation->rd_isvalid = false; /* needs to be revalidated */
2443  if (IsTransactionState())
2444  RelationReloadIndexInfo(relation);
2445  return;
2446  }
2447 
2448  /* Mark it invalid until we've finished rebuild */
2449  relation->rd_isvalid = false;
2450 
2451  /*
2452  * If we're really done with the relcache entry, blow it away. But if
2453  * someone is still using it, reconstruct the whole deal without moving
2454  * the physical RelationData record (so that the someone's pointer is
2455  * still valid).
2456  */
2457  if (!rebuild)
2458  {
2459  /* Remove it from the hash table */
2460  RelationCacheDelete(relation);
2461 
2462  /* And release storage */
2463  RelationDestroyRelation(relation, false);
2464  }
2465  else if (!IsTransactionState())
2466  {
2467  /*
2468  * If we're not inside a valid transaction, we can't do any catalog
2469  * access so it's not possible to rebuild yet. Just exit, leaving
2470  * rd_isvalid = false so that the rebuild will occur when the entry is
2471  * next opened.
2472  *
2473  * Note: it's possible that we come here during subtransaction abort,
2474  * and the reason for wanting to rebuild is that the rel is open in
2475  * the outer transaction. In that case it might seem unsafe to not
2476  * rebuild immediately, since whatever code has the rel already open
2477  * will keep on using the relcache entry as-is. However, in such a
2478  * case the outer transaction should be holding a lock that's
2479  * sufficient to prevent any significant change in the rel's schema,
2480  * so the existing entry contents should be good enough for its
2481  * purposes; at worst we might be behind on statistics updates or the
2482  * like. (See also CheckTableNotInUse() and its callers.) These same
2483  * remarks also apply to the cases above where we exit without having
2484  * done RelationReloadIndexInfo() yet.
2485  */
2486  return;
2487  }
2488  else
2489  {
2490  /*
2491  * Our strategy for rebuilding an open relcache entry is to build a
2492  * new entry from scratch, swap its contents with the old entry, and
2493  * finally delete the new entry (along with any infrastructure swapped
2494  * over from the old entry). This is to avoid trouble in case an
2495  * error causes us to lose control partway through. The old entry
2496  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2497  * on next access. Meanwhile it's not any less valid than it was
2498  * before, so any code that might expect to continue accessing it
2499  * isn't hurt by the rebuild failure. (Consider for example a
2500  * subtransaction that ALTERs a table and then gets canceled partway
2501  * through the cache entry rebuild. The outer transaction should
2502  * still see the not-modified cache entry as valid.) The worst
2503  * consequence of an error is leaking the necessarily-unreferenced new
2504  * entry, and this shouldn't happen often enough for that to be a big
2505  * problem.
2506  *
2507  * When rebuilding an open relcache entry, we must preserve ref count,
2508  * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state. Also
2509  * attempt to preserve the pg_class entry (rd_rel), tupledesc,
2510  * rewrite-rule, partition key, and partition descriptor substructures
2511  * in place, because various places assume that these structures won't
2512  * move while they are working with an open relcache entry. (Note:
2513  * the refcount mechanism for tupledescs might someday allow us to
2514  * remove this hack for the tupledesc.)
2515  *
2516  * Note that this process does not touch CurrentResourceOwner; which
2517  * is good because whatever ref counts the entry may have do not
2518  * necessarily belong to that resource owner.
2519  */
2520  Relation newrel;
2521  Oid save_relid = RelationGetRelid(relation);
2522  bool keep_tupdesc;
2523  bool keep_rules;
2524  bool keep_policies;
2525  bool keep_partkey;
2526 
2527  /* Build temporary entry, but don't link it into hashtable */
2528  newrel = RelationBuildDesc(save_relid, false);
2529  if (newrel == NULL)
2530  {
2531  /*
2532  * We can validly get here, if we're using a historic snapshot in
2533  * which a relation, accessed from outside logical decoding, is
2534  * still invisible. In that case it's fine to just mark the
2535  * relation as invalid and return - it'll fully get reloaded by
2536  * the cache reset at the end of logical decoding (or at the next
2537  * access). During normal processing we don't want to ignore this
2538  * case as it shouldn't happen there, as explained below.
2539  */
2540  if (HistoricSnapshotActive())
2541  return;
2542 
2543  /*
2544  * This shouldn't happen as dropping a relation is intended to be
2545  * impossible if still referenced (cf. CheckTableNotInUse()). But
2546  * if we get here anyway, we can't just delete the relcache entry,
2547  * as it possibly could get accessed later (as e.g. the error
2548  * might get trapped and handled via a subtransaction rollback).
2549  */
2550  elog(ERROR, "relation %u deleted while still in use", save_relid);
2551  }
2552 
2553  keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2554  keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2555  keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2556  /* partkey is immutable once set up, so we can always keep it */
2557  keep_partkey = (relation->rd_partkey != NULL);
2558 
2559  /*
2560  * Perform swapping of the relcache entry contents. Within this
2561  * process the old entry is momentarily invalid, so there *must* be no
2562  * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2563  * all-in-line code for safety.
2564  *
2565  * Since the vast majority of fields should be swapped, our method is
2566  * to swap the whole structures and then re-swap those few fields we
2567  * didn't want swapped.
2568  */
2569 #define SWAPFIELD(fldtype, fldname) \
2570  do { \
2571  fldtype _tmp = newrel->fldname; \
2572  newrel->fldname = relation->fldname; \
2573  relation->fldname = _tmp; \
2574  } while (0)
2575 
2576  /* swap all Relation struct fields */
2577  {
2578  RelationData tmpstruct;
2579 
2580  memcpy(&tmpstruct, newrel, sizeof(RelationData));
2581  memcpy(newrel, relation, sizeof(RelationData));
2582  memcpy(relation, &tmpstruct, sizeof(RelationData));
2583  }
2584 
2585  /* rd_smgr must not be swapped, due to back-links from smgr level */
2586  SWAPFIELD(SMgrRelation, rd_smgr);
2587  /* rd_refcnt must be preserved */
2588  SWAPFIELD(int, rd_refcnt);
2589  /* isnailed shouldn't change */
2590  Assert(newrel->rd_isnailed == relation->rd_isnailed);
2591  /* creation sub-XIDs must be preserved */
2592  SWAPFIELD(SubTransactionId, rd_createSubid);
2593  SWAPFIELD(SubTransactionId, rd_newRelfilenodeSubid);
2594  /* un-swap rd_rel pointers, swap contents instead */
2595  SWAPFIELD(Form_pg_class, rd_rel);
2596  /* ... but actually, we don't have to update newrel->rd_rel */
2597  memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2598  /* preserve old tupledesc, rules, policies if no logical change */
2599  if (keep_tupdesc)
2600  SWAPFIELD(TupleDesc, rd_att);
2601  if (keep_rules)
2602  {
2603  SWAPFIELD(RuleLock *, rd_rules);
2604  SWAPFIELD(MemoryContext, rd_rulescxt);
2605  }
2606  if (keep_policies)
2607  SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2608  /* toast OID override must be preserved */
2609  SWAPFIELD(Oid, rd_toastoid);
2610  /* pgstat_info must be preserved */
2611  SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2612  /* preserve old partition key if we have one */
2613  if (keep_partkey)
2614  {
2615  SWAPFIELD(PartitionKey, rd_partkey);
2616  SWAPFIELD(MemoryContext, rd_partkeycxt);
2617  }
2618  if (newrel->rd_pdcxt != NULL)
2619  {
2620  /*
2621  * We are rebuilding a partitioned relation with a non-zero
2622  * reference count, so we must keep the old partition descriptor
2623  * around, in case there's a PartitionDirectory with a pointer to
2624  * it. This means we can't free the old rd_pdcxt yet. (This is
2625  * necessary because RelationGetPartitionDesc hands out direct
2626  * pointers to the relcache's data structure, unlike our usual
2627  * practice which is to hand out copies. We'd have the same
2628  * problem with rd_partkey, except that we always preserve that
2629  * once created.)
2630  *
2631  * To ensure that it's not leaked completely, re-attach it to the
2632  * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2633  * in the unlikely event that there is one already. (Compare hack
2634  * in RelationBuildPartitionDesc.) RelationClose will clean up
2635  * any such contexts once the reference count reaches zero.
2636  *
2637  * In the case where the reference count is zero, this code is not
2638  * reached, which should be OK because in that case there should
2639  * be no PartitionDirectory with a pointer to the old entry.
2640  *
2641  * Note that newrel and relation have already been swapped, so the
2642  * "old" partition descriptor is actually the one hanging off of
2643  * newrel.
2644  */
2645  relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2646  if (relation->rd_pdcxt != NULL) /* probably never happens */
2647  MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2648  else
2649  relation->rd_pdcxt = newrel->rd_pdcxt;
2650  /* drop newrel's pointers so we don't destroy it below */
2651  newrel->rd_partdesc = NULL;
2652  newrel->rd_pdcxt = NULL;
2653  }
2654 
2655 #undef SWAPFIELD
2656 
2657  /* And now we can throw away the temporary entry */
2658  RelationDestroyRelation(newrel, !keep_tupdesc);
2659  }
2660 }
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
bool rd_isnailed
Definition: rel.h:61
bool rd_isvalid
Definition: rel.h:62
#define RelationCloseSmgr(relation)
Definition: rel.h:497
uint32 SubTransactionId
Definition: c.h:518
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
PartitionKey rd_partkey
Definition: rel.h:99
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
#define RelationCacheDelete(RELATION)
Definition: relcache.c:220
PartitionDesc rd_partdesc
Definition: rel.h:103
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
Definition: relcache.c:887
#define SWAPFIELD(fldtype, fldname)
static void RelationReloadNailed(Relation relation)
Definition: relcache.c:2236
static void RelationDestroyRelation(Relation relation, bool remember_tupdesc)
Definition: relcache.c:2308
TupleDesc rd_att
Definition: rel.h:85
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:142
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2125
MemoryContext rd_pdcxt
Definition: rel.h:104
#define Assert(condition)
Definition: c.h:739
RuleLock * rd_rules
Definition: rel.h:88
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1019
bool IsTransactionState(void)
Definition: xact.c:355
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:412
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:228
MemoryContext rd_indexcxt
Definition: rel.h:161
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:411
void * rd_amcache
Definition: rel.h:185
#define RelationGetRelid(relation)
Definition: rel.h:428
static bool equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
Definition: relcache.c:978

◆ RelationClose()