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/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_partitioned_table.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 "partitioning/partbounds.h"
#include "partitioning/partdesc.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/partcache.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:166
static int eoxact_list_len
Definition: relcache.c:168

Definition at line 171 of file relcache.c.

Referenced by RelationBuildLocalRelation(), and RelationSetNewRelfilenode().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3576 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 166 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 104 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:134
#define WARNING
Definition: elog.h:40

Definition at line 225 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:134
#define RelationGetRelationName(relation)
Definition: rel.h:456
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:406
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374

Definition at line 191 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:134

Definition at line 213 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 93 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 385 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().

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

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

Referenced by AtEOSubXact_RelationCache().

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

◆ AtEOSubXact_RelationCache()

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

Definition at line 3076 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().

3078 {
3080  RelIdCacheEnt *idhentry;
3081  int i;
3082 
3083  /*
3084  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3085  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3086  * logic as in AtEOXact_RelationCache.
3087  */
3089  {
3090  hash_seq_init(&status, RelationIdCache);
3091  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3092  {
3093  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3094  mySubid, parentSubid);
3095  }
3096  }
3097  else
3098  {
3099  for (i = 0; i < eoxact_list_len; i++)
3100  {
3101  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3102  (void *) &eoxact_list[i],
3103  HASH_FIND,
3104  NULL);
3105  if (idhentry != NULL)
3106  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3107  mySubid, parentSubid);
3108  }
3109  }
3110 
3111  /* Don't reset the list; we still need more cleanup later */
3112 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:167
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3123
Relation reldesc
Definition: relcache.c:131
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:134
static bool eoxact_list_overflowed
Definition: relcache.c:169
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:168

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3001 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().

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

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 2938 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().

2939 {
2941  RelIdCacheEnt *idhentry;
2942  int i;
2943 
2944  /*
2945  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2946  * listed in it. Otherwise fall back on a hash_seq_search scan.
2947  *
2948  * For simplicity, eoxact_list[] entries are not deleted till end of
2949  * top-level transaction, even though we could remove them at
2950  * subtransaction end in some cases, or remove relations from the list if
2951  * they are cleared for other reasons. Therefore we should expect the
2952  * case that list entries are not found in the hashtable; if not, there's
2953  * nothing to do for them.
2954  */
2956  {
2957  hash_seq_init(&status, RelationIdCache);
2958  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2959  {
2960  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2961  }
2962  }
2963  else
2964  {
2965  for (i = 0; i < eoxact_list_len; i++)
2966  {
2967  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2968  (void *) &eoxact_list[i],
2969  HASH_FIND,
2970  NULL);
2971  if (idhentry != NULL)
2972  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2973  }
2974  }
2975 
2976  if (EOXactTupleDescArrayLen > 0)
2977  {
2978  Assert(EOXactTupleDescArray != NULL);
2979  for (i = 0; i < NextEOXactTupleDescNum; i++)
2982  EOXactTupleDescArray = NULL;
2983  }
2984 
2985  /* Now we're out of the transaction and can clear the lists */
2986  eoxact_list_len = 0;
2987  eoxact_list_overflowed = false;
2988  NextEOXactTupleDescNum = 0;
2990 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:167
static int EOXactTupleDescArrayLen
Definition: relcache.c:186
Relation reldesc
Definition: relcache.c:131
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:134
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3001
static bool eoxact_list_overflowed
Definition: relcache.c:169
static int NextEOXactTupleDescNum
Definition: relcache.c:185
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:168
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:184

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

Definition at line 4074 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().

4075 {
4076  AttrDefault *attrdef = relation->rd_att->constr->defval;
4077  int ndef = relation->rd_att->constr->num_defval;
4078  Relation adrel;
4079  SysScanDesc adscan;
4080  ScanKeyData skey;
4081  HeapTuple htup;
4082  Datum val;
4083  bool isnull;
4084  int found;
4085  int i;
4086 
4087  ScanKeyInit(&skey,
4088  Anum_pg_attrdef_adrelid,
4089  BTEqualStrategyNumber, F_OIDEQ,
4090  ObjectIdGetDatum(RelationGetRelid(relation)));
4091 
4092  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4093  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4094  NULL, 1, &skey);
4095  found = 0;
4096 
4097  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4098  {
4099  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4100  Form_pg_attribute attr = TupleDescAttr(relation->rd_att, adform->adnum - 1);
4101 
4102  for (i = 0; i < ndef; i++)
4103  {
4104  if (adform->adnum != attrdef[i].adnum)
4105  continue;
4106  if (attrdef[i].adbin != NULL)
4107  elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
4108  NameStr(attr->attname),
4109  RelationGetRelationName(relation));
4110  else
4111  found++;
4112 
4113  val = fastgetattr(htup,
4114  Anum_pg_attrdef_adbin,
4115  adrel->rd_att, &isnull);
4116  if (isnull)
4117  elog(WARNING, "null adbin for attr %s of rel %s",
4118  NameStr(attr->attname),
4119  RelationGetRelationName(relation));
4120  else
4121  {
4122  /* detoast and convert to cstring in caller's context */
4123  char *s = TextDatumGetCString(val);
4124 
4126  pfree(s);
4127  }
4128  break;
4129  }
4130 
4131  if (i >= ndef)
4132  elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
4133  adform->adnum, RelationGetRelationName(relation));
4134  }
4135 
4136  systable_endscan(adscan);
4137  table_close(adrel, AccessShareLock);
4138 }
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:456
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:84
#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:422
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 4015 of file relcache.c.

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

4016 {
4017  TupleDesc result;
4018  MemoryContext oldcxt;
4019  int i;
4020 
4022 
4023  result = CreateTemplateTupleDesc(natts);
4024  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4025  result->tdtypmod = -1;
4026 
4027  for (i = 0; i < natts; i++)
4028  {
4029  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4030  /* make sure attcacheoff is valid */
4031  TupleDescAttr(result, i)->attcacheoff = -1;
4032  }
4033 
4034  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4035  TupleDescAttr(result, 0)->attcacheoff = 0;
4036 
4037  /* Note: we don't bother to set up a TupleConstr entry */
4038 
4039  MemoryContextSwitchTo(oldcxt);
4040 
4041  return result;
4042 }
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 4215 of file relcache.c.

References ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

4216 {
4217  const ConstrCheck *ca = (const ConstrCheck *) a;
4218  const ConstrCheck *cb = (const ConstrCheck *) b;
4219 
4220  return strcmp(ca->ccname, cb->ccname);
4221 }
char * ccname
Definition: tupdesc.h:30

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4144 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().

4145 {
4146  ConstrCheck *check = relation->rd_att->constr->check;
4147  int ncheck = relation->rd_att->constr->num_check;
4148  Relation conrel;
4149  SysScanDesc conscan;
4150  ScanKeyData skey[1];
4151  HeapTuple htup;
4152  int found = 0;
4153 
4154  ScanKeyInit(&skey[0],
4155  Anum_pg_constraint_conrelid,
4156  BTEqualStrategyNumber, F_OIDEQ,
4157  ObjectIdGetDatum(RelationGetRelid(relation)));
4158 
4159  conrel = table_open(ConstraintRelationId, AccessShareLock);
4160  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4161  NULL, 1, skey);
4162 
4163  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4164  {
4166  Datum val;
4167  bool isnull;
4168  char *s;
4169 
4170  /* We want check constraints only */
4171  if (conform->contype != CONSTRAINT_CHECK)
4172  continue;
4173 
4174  if (found >= ncheck)
4175  elog(ERROR, "unexpected constraint record found for rel %s",
4176  RelationGetRelationName(relation));
4177 
4178  check[found].ccvalid = conform->convalidated;
4179  check[found].ccnoinherit = conform->connoinherit;
4181  NameStr(conform->conname));
4182 
4183  /* Grab and test conbin is actually set */
4184  val = fastgetattr(htup,
4185  Anum_pg_constraint_conbin,
4186  conrel->rd_att, &isnull);
4187  if (isnull)
4188  elog(ERROR, "null conbin for rel %s",
4189  RelationGetRelationName(relation));
4190 
4191  /* detoast and convert to cstring in caller's context */
4192  s = TextDatumGetCString(val);
4193  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4194  pfree(s);
4195 
4196  found++;
4197  }
4198 
4199  systable_endscan(conscan);
4200  table_close(conrel, AccessShareLock);
4201 
4202  if (found != ncheck)
4203  elog(ERROR, "%d constraint record(s) missing for rel %s",
4204  ncheck - found, RelationGetRelationName(relation));
4205 
4206  /* Sort the records so that CHECKs are applied in a deterministic order */
4207  if (ncheck > 1)
4208  qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
4209 }
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:4215
#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:456
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
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:488
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
char * ccbin
Definition: tupdesc.h:31
#define RelationGetRelid(relation)
Definition: rel.h:422
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 937 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().

938 {
939  int i;
940  Oid *r1,
941  *r2;
942 
943  if (policy1 != NULL)
944  {
945  if (policy2 == NULL)
946  return false;
947 
948  if (policy1->polcmd != policy2->polcmd)
949  return false;
950  if (policy1->hassublinks != policy2->hassublinks)
951  return false;
952  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
953  return false;
954  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
955  return false;
956 
957  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
958  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
959 
960  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
961  {
962  if (r1[i] != r2[i])
963  return false;
964  }
965 
966  if (!equal(policy1->qual, policy2->qual))
967  return false;
968  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
969  return false;
970  }
971  else if (policy2 != NULL)
972  return false;
973 
974  return true;
975 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3011
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 983 of file relcache.c.

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

Referenced by RelationClearRelation().

984 {
985  ListCell *lc,
986  *rc;
987 
988  if (rsdesc1 == NULL && rsdesc2 == NULL)
989  return true;
990 
991  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
992  (rsdesc1 == NULL && rsdesc2 != NULL))
993  return false;
994 
995  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
996  return false;
997 
998  /* RelationBuildRowSecurity should build policies in order */
999  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1000  {
1003 
1004  if (!equalPolicy(l, r))
1005  return false;
1006  }
1007 
1008  return true;
1009 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:937
#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 892 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().

893 {
894  int i;
895 
896  /*
897  * As of 7.3 we assume the rule ordering is repeatable, because
898  * RelationBuildRuleLock should read 'em in a consistent order. So just
899  * compare corresponding slots.
900  */
901  if (rlock1 != NULL)
902  {
903  if (rlock2 == NULL)
904  return false;
905  if (rlock1->numLocks != rlock2->numLocks)
906  return false;
907  for (i = 0; i < rlock1->numLocks; i++)
908  {
909  RewriteRule *rule1 = rlock1->rules[i];
910  RewriteRule *rule2 = rlock2->rules[i];
911 
912  if (rule1->ruleId != rule2->ruleId)
913  return false;
914  if (rule1->event != rule2->event)
915  return false;
916  if (rule1->enabled != rule2->enabled)
917  return false;
918  if (rule1->isInstead != rule2->isInstead)
919  return false;
920  if (!equal(rule1->qual, rule2->qual))
921  return false;
922  if (!equal(rule1->actions, rule2->actions))
923  return false;
924  }
925  }
926  else if (rlock2 != NULL)
927  return false;
928  return true;
929 }
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3011
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 5218 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().

5219 {
5223 
5224  return 0; /* return value does not matter */
5225 }
#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:456
int err_generic_string(int field, const char *str)
Definition: elog.c:1273
#define RelationGetNamespace(relation)
Definition: rel.h:463

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5235 of file relcache.c.

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

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

5236 {
5237  TupleDesc reldesc = RelationGetDescr(rel);
5238  const char *colname;
5239 
5240  /* Use reldesc if it's a user attribute, else consult the catalogs */
5241  if (attnum > 0 && attnum <= reldesc->natts)
5242  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5243  else
5244  colname = get_attname(RelationGetRelid(rel), attnum, false);
5245 
5246  return errtablecolname(rel, colname);
5247 }
#define RelationGetDescr(relation)
Definition: rel.h:448
#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:422
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5259

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5259 of file relcache.c.

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

Referenced by errtablecol().

5260 {
5261  errtable(rel);
5263 
5264  return 0; /* return value does not matter */
5265 }
#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:5218

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5272 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().

5273 {
5274  errtable(rel);
5276 
5277  return 0; /* return value does not matter */
5278 }
#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:5218

◆ formrdesc()

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

Definition at line 1803 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().

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

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

4046 {
4047  static TupleDesc pgclassdesc = NULL;
4048 
4049  /* Already done? */
4050  if (pgclassdesc == NULL)
4051  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4052  Desc_pg_class);
4053 
4054  return pgclassdesc;
4055 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4015
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4058 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

4059 {
4060  static TupleDesc pgindexdesc = NULL;
4061 
4062  /* Already done? */
4063  if (pgindexdesc == NULL)
4064  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4065  Desc_pg_index);
4066 
4067  return pgindexdesc;
4068 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:118
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4015

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5139 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().

5140 {
5141  List *puboids;
5142  ListCell *lc;
5143  MemoryContext oldcxt;
5144  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5145 
5146  /*
5147  * If not publishable, it publishes no actions. (pgoutput_change() will
5148  * ignore it.)
5149  */
5150  if (!is_publishable_relation(relation))
5151  return pubactions;
5152 
5153  if (relation->rd_pubactions)
5154  return memcpy(pubactions, relation->rd_pubactions,
5155  sizeof(PublicationActions));
5156 
5157  /* Fetch the publication membership info. */
5158  puboids = GetRelationPublications(RelationGetRelid(relation));
5159  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5160 
5161  foreach(lc, puboids)
5162  {
5163  Oid pubid = lfirst_oid(lc);
5164  HeapTuple tup;
5165  Form_pg_publication pubform;
5166 
5168 
5169  if (!HeapTupleIsValid(tup))
5170  elog(ERROR, "cache lookup failed for publication %u", pubid);
5171 
5172  pubform = (Form_pg_publication) GETSTRUCT(tup);
5173 
5174  pubactions->pubinsert |= pubform->pubinsert;
5175  pubactions->pubupdate |= pubform->pubupdate;
5176  pubactions->pubdelete |= pubform->pubdelete;
5177  pubactions->pubtruncate |= pubform->pubtruncate;
5178 
5179  ReleaseSysCache(tup);
5180 
5181  /*
5182  * If we know everything is replicated, there is no point to check for
5183  * other publications.
5184  */
5185  if (pubactions->pubinsert && pubactions->pubupdate &&
5186  pubactions->pubdelete && pubactions->pubtruncate)
5187  break;
5188  }
5189 
5190  if (relation->rd_pubactions)
5191  {
5192  pfree(relation->rd_pubactions);
5193  relation->rd_pubactions = NULL;
5194  }
5195 
5196  /* Now save copy of the actions in the relcache entry. */
5198  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5199  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5200  MemoryContextSwitchTo(oldcxt);
5201 
5202  return pubactions;
5203 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:119
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:422
#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 1529 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

1535 {
1536  int attIndex;
1537 
1538  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1539  {
1540  OpClassCacheEnt *opcentry;
1541 
1542  if (!OidIsValid(indclass->values[attIndex]))
1543  elog(ERROR, "bogus pg_index tuple");
1544 
1545  /* look up the info for this opclass, using a cache */
1546  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1547  maxSupportNumber);
1548 
1549  /* copy cached data into relcache entry */
1550  opFamily[attIndex] = opcentry->opcfamily;
1551  opcInType[attIndex] = opcentry->opcintype;
1552  if (maxSupportNumber > 0)
1553  memcpy(&indexSupport[attIndex * maxSupportNumber],
1554  opcentry->supportProcs,
1555  maxSupportNumber * sizeof(RegProcedure));
1556  }
1557 }
regproc RegProcedure
Definition: c.h:512
#define OidIsValid(objectId)
Definition: c.h:645
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:250
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1580
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 1337 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().

1338 {
1339  IndexAmRoutine *cached,
1340  *tmp;
1341 
1342  /*
1343  * Call the amhandler in current, short-lived memory context, just in case
1344  * it leaks anything (it probably won't, but let's be paranoid).
1345  */
1346  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1347 
1348  /* OK, now transfer the data into relation's rd_indexcxt. */
1349  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1350  sizeof(IndexAmRoutine));
1351  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1352  relation->rd_indam = cached;
1353 
1354  pfree(tmp);
1355 }
struct IndexAmRoutine * rd_indam
Definition: rel.h:157
void pfree(void *pointer)
Definition: mcxt.c:1056
Oid rd_amhandler
Definition: rel.h:135
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
MemoryContext rd_indexcxt
Definition: rel.h:155

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1730 of file relcache.c.

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

Referenced by RelationInitTableAccessMethod().

1731 {
1732  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1733 }
Oid rd_amhandler
Definition: rel.h:135
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:34
const struct TableAmRoutine * rd_tableam
Definition: rel.h:140

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 3981 of file relcache.c.

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

Referenced by RelationCacheInitializePhase3().

3982 {
3983  Relation ird;
3984 
3985  /*
3986  * We must lock the underlying catalog before locking the index to avoid
3987  * deadlock, since RelationBuildDesc might well need to read the catalog,
3988  * and if anyone else is exclusive-locking this catalog and index they'll
3989  * be doing it in that order.
3990  */
3991  LockRelationOid(heapoid, AccessShareLock);
3992  LockRelationOid(indexoid, AccessShareLock);
3993  ird = RelationBuildDesc(indexoid, true);
3994  if (ird == NULL)
3995  elog(PANIC, "could not open critical system index %u", indexoid);
3996  ird->rd_isnailed = true;
3997  ird->rd_refcnt = 1;
4000 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
bool rd_isnailed
Definition: rel.h:60
#define AccessShareLock
Definition: lockdefs.h:36
#define PANIC
Definition: elog.h:53
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1024
int rd_refcnt
Definition: rel.h:57
#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 5336 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().

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

◆ LookupOpclassInfo()

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

Definition at line 1580 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().

1582 {
1583  OpClassCacheEnt *opcentry;
1584  bool found;
1585  Relation rel;
1586  SysScanDesc scan;
1587  ScanKeyData skey[3];
1588  HeapTuple htup;
1589  bool indexOK;
1590 
1591  if (OpClassCache == NULL)
1592  {
1593  /* First time through: initialize the opclass cache */
1594  HASHCTL ctl;
1595 
1596  MemSet(&ctl, 0, sizeof(ctl));
1597  ctl.keysize = sizeof(Oid);
1598  ctl.entrysize = sizeof(OpClassCacheEnt);
1599  OpClassCache = hash_create("Operator class cache", 64,
1600  &ctl, HASH_ELEM | HASH_BLOBS);
1601 
1602  /* Also make sure CacheMemoryContext exists */
1603  if (!CacheMemoryContext)
1605  }
1606 
1607  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1608  (void *) &operatorClassOid,
1609  HASH_ENTER, &found);
1610 
1611  if (!found)
1612  {
1613  /* Need to allocate memory for new entry */
1614  opcentry->valid = false; /* until known OK */
1615  opcentry->numSupport = numSupport;
1616 
1617  if (numSupport > 0)
1618  opcentry->supportProcs = (RegProcedure *)
1620  numSupport * sizeof(RegProcedure));
1621  else
1622  opcentry->supportProcs = NULL;
1623  }
1624  else
1625  {
1626  Assert(numSupport == opcentry->numSupport);
1627  }
1628 
1629  /*
1630  * When testing for cache-flush hazards, we intentionally disable the
1631  * operator class cache and force reloading of the info on each call. This
1632  * is helpful because we want to test the case where a cache flush occurs
1633  * while we are loading the info, and it's very hard to provoke that if
1634  * this happens only once per opclass per backend.
1635  */
1636 #if defined(CLOBBER_CACHE_ALWAYS)
1637  opcentry->valid = false;
1638 #endif
1639 
1640  if (opcentry->valid)
1641  return opcentry;
1642 
1643  /*
1644  * Need to fill in new entry.
1645  *
1646  * To avoid infinite recursion during startup, force heap scans if we're
1647  * looking up info for the opclasses used by the indexes we would like to
1648  * reference here.
1649  */
1650  indexOK = criticalRelcachesBuilt ||
1651  (operatorClassOid != OID_BTREE_OPS_OID &&
1652  operatorClassOid != INT2_BTREE_OPS_OID);
1653 
1654  /*
1655  * We have to fetch the pg_opclass row to determine its opfamily and
1656  * opcintype, which are needed to look up related operators and functions.
1657  * It'd be convenient to use the syscache here, but that probably doesn't
1658  * work while bootstrapping.
1659  */
1660  ScanKeyInit(&skey[0],
1661  Anum_pg_opclass_oid,
1662  BTEqualStrategyNumber, F_OIDEQ,
1663  ObjectIdGetDatum(operatorClassOid));
1664  rel = table_open(OperatorClassRelationId, AccessShareLock);
1665  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1666  NULL, 1, skey);
1667 
1668  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1669  {
1670  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1671 
1672  opcentry->opcfamily = opclassform->opcfamily;
1673  opcentry->opcintype = opclassform->opcintype;
1674  }
1675  else
1676  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1677 
1678  systable_endscan(scan);
1680 
1681  /*
1682  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1683  * the default ones (those with lefttype = righttype = opcintype).
1684  */
1685  if (numSupport > 0)
1686  {
1687  ScanKeyInit(&skey[0],
1688  Anum_pg_amproc_amprocfamily,
1689  BTEqualStrategyNumber, F_OIDEQ,
1690  ObjectIdGetDatum(opcentry->opcfamily));
1691  ScanKeyInit(&skey[1],
1692  Anum_pg_amproc_amproclefttype,
1693  BTEqualStrategyNumber, F_OIDEQ,
1694  ObjectIdGetDatum(opcentry->opcintype));
1695  ScanKeyInit(&skey[2],
1696  Anum_pg_amproc_amprocrighttype,
1697  BTEqualStrategyNumber, F_OIDEQ,
1698  ObjectIdGetDatum(opcentry->opcintype));
1699  rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1700  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1701  NULL, 3, skey);
1702 
1703  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1704  {
1705  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1706 
1707  if (amprocform->amprocnum <= 0 ||
1708  (StrategyNumber) amprocform->amprocnum > numSupport)
1709  elog(ERROR, "invalid amproc number %d for opclass %u",
1710  amprocform->amprocnum, operatorClassOid);
1711 
1712  opcentry->supportProcs[amprocform->amprocnum - 1] =
1713  amprocform->amproc;
1714  }
1715 
1716  systable_endscan(scan);
1718  }
1719 
1720  opcentry->valid = true;
1721  return opcentry;
1722 }
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:247
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:250
static HTAB * OpClassCache
Definition: relcache.c:253
#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:140
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 1024 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, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationParseRelOptions(), ScanPgRelation(), and RelationData::trigdesc.

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

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

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

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

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

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

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6014 of file relcache.c.

References LWLockRelease().

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

6015 {
6016  LWLockRelease(RelCacheInitLock);
6017 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 5989 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().

5990 {
5991  char localinitfname[MAXPGPATH];
5992  char sharedinitfname[MAXPGPATH];
5993 
5994  if (DatabasePath)
5995  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
5997  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
5999 
6000  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6001 
6002  /*
6003  * The files might not be there if no backend has been started since the
6004  * last removal. But complain about failures other than ENOENT with
6005  * ERROR. Fortunately, it's not too late to abort the transaction if we
6006  * can't get rid of the would-be-obsolete init file.
6007  */
6008  if (DatabasePath)
6009  unlink_initfile(localinitfname, ERROR);
6010  unlink_initfile(sharedinitfname, ERROR);
6011 }
#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:6086
#define snprintf
Definition: port.h:192

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6029 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().

6030 {
6031  const char *tblspcdir = "pg_tblspc";
6032  DIR *dir;
6033  struct dirent *de;
6034  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6035 
6036  snprintf(path, sizeof(path), "global/%s",
6038  unlink_initfile(path, LOG);
6039 
6040  /* Scan everything in the default tablespace */
6042 
6043  /* Scan the tablespace link directory to find non-default tablespaces */
6044  dir = AllocateDir(tblspcdir);
6045 
6046  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6047  {
6048  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6049  {
6050  /* Scan the tablespace dir for per-database dirs */
6051  snprintf(path, sizeof(path), "%s/%s/%s",
6052  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6054  }
6055  }
6056 
6057  FreeDir(dir);
6058 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6062
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:6086
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 6062 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6063 {
6064  DIR *dir;
6065  struct dirent *de;
6066  char initfilename[MAXPGPATH * 2];
6067 
6068  /* Scan the tablespace directory to find per-database directories */
6069  dir = AllocateDir(tblspcpath);
6070 
6071  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6072  {
6073  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6074  {
6075  /* Try to remove the init file in each database */
6076  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6077  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6078  unlink_initfile(initfilename, LOG);
6079  }
6080  }
6081 
6082  FreeDir(dir);
6083 }
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:6086
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 3579 of file relcache.c.

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

Referenced by InitPostgres().

3580 {
3581  HASHCTL ctl;
3582 
3583  /*
3584  * make sure cache memory context exists
3585  */
3586  if (!CacheMemoryContext)
3588 
3589  /*
3590  * create hashtable that indexes the relcache
3591  */
3592  MemSet(&ctl, 0, sizeof(ctl));
3593  ctl.keysize = sizeof(Oid);
3594  ctl.entrysize = sizeof(RelIdCacheEnt);
3595  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3596  &ctl, HASH_ELEM | HASH_BLOBS);
3597 
3598  /*
3599  * relation mapper needs to be initialized too
3600  */
3602 }
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:134
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:3576
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3616 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().

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

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3675 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_partdesc, RelationData::rd_partkey, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), 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().

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

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2778 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().

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

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2734 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2735 {
2736  Relation relation;
2737 
2738  RelationIdCacheLookup(relationId, relation);
2739 
2740  if (PointerIsValid(relation))
2741  {
2743  RelationFlushRelation(relation);
2744  }
2745 }
static long relcacheInvalsReceived
Definition: relcache.c:154
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:213
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2666
#define PointerIsValid(pointer)
Definition: c.h:633

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2398 of file relcache.c.

References Assert, CLASS_TUPLE_SIZE, elog, equalPartitionDescs(), 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().

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