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_authid.h"
#include "catalog/pg_auth_members.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)
 
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:167
static int eoxact_list_len
Definition: relcache.c:169

Definition at line 172 of file relcache.c.

Referenced by RelationBuildLocalRelation(), and RelationSetNewRelfilenode().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3577 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 167 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 105 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:135
#define WARNING
Definition: elog.h:40

Definition at line 226 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:135
#define RelationGetRelationName(relation)
Definition: rel.h:453
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:403
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374

Definition at line 192 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:135

Definition at line 214 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 94 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 386 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().

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

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

Referenced by AtEOSubXact_RelationCache().

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

◆ AtEOSubXact_RelationCache()

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

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

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

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

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

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

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

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

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

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

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

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

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

References ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

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

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

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

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

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

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

Referenced by RelationClearRelation().

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

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

5169 {
5173 
5174  return 0; /* return value does not matter */
5175 }
#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:453
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
#define RelationGetNamespace(relation)
Definition: rel.h:460

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5185 of file relcache.c.

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

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

5186 {
5187  TupleDesc reldesc = RelationGetDescr(rel);
5188  const char *colname;
5189 
5190  /* Use reldesc if it's a user attribute, else consult the catalogs */
5191  if (attnum > 0 && attnum <= reldesc->natts)
5192  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5193  else
5194  colname = get_attname(RelationGetRelid(rel), attnum, false);
5195 
5196  return errtablecolname(rel, colname);
5197 }
#define RelationGetDescr(relation)
Definition: rel.h:445
#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:609
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:419
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5209

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5209 of file relcache.c.

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

Referenced by errtablecol().

5210 {
5211  errtable(rel);
5213 
5214  return 0; /* return value does not matter */
5215 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
int errtable(Relation rel)
Definition: relcache.c:5168

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

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

5223 {
5224  errtable(rel);
5226 
5227  return 0; /* return value does not matter */
5228 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1178
int errtable(Relation rel)
Definition: relcache.c:5168

◆ formrdesc()

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

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

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

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

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

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4059 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

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

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

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

5090 {
5091  List *puboids;
5092  ListCell *lc;
5093  MemoryContext oldcxt;
5094  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5095 
5096  /*
5097  * If not publishable, it publishes no actions. (pgoutput_change() will
5098  * ignore it.)
5099  */
5100  if (!is_publishable_relation(relation))
5101  return pubactions;
5102 
5103  if (relation->rd_pubactions)
5104  return memcpy(pubactions, relation->rd_pubactions,
5105  sizeof(PublicationActions));
5106 
5107  /* Fetch the publication membership info. */
5108  puboids = GetRelationPublications(RelationGetRelid(relation));
5109  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5110 
5111  foreach(lc, puboids)
5112  {
5113  Oid pubid = lfirst_oid(lc);
5114  HeapTuple tup;
5115  Form_pg_publication pubform;
5116 
5118 
5119  if (!HeapTupleIsValid(tup))
5120  elog(ERROR, "cache lookup failed for publication %u", pubid);
5121 
5122  pubform = (Form_pg_publication) GETSTRUCT(tup);
5123 
5124  pubactions->pubinsert |= pubform->pubinsert;
5125  pubactions->pubupdate |= pubform->pubupdate;
5126  pubactions->pubdelete |= pubform->pubdelete;
5127  pubactions->pubtruncate |= pubform->pubtruncate;
5128 
5129  ReleaseSysCache(tup);
5130 
5131  /*
5132  * If we know everything is replicated, there is no point to check for
5133  * other publications.
5134  */
5135  if (pubactions->pubinsert && pubactions->pubupdate &&
5136  pubactions->pubdelete && pubactions->pubtruncate)
5137  break;
5138  }
5139 
5140  if (relation->rd_pubactions)
5141  {
5142  pfree(relation->rd_pubactions);
5143  relation->rd_pubactions = NULL;
5144  }
5145 
5146  /* Now save copy of the actions in the relcache entry. */
5148  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5149  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5150  MemoryContextSwitchTo(oldcxt);
5151 
5152  return pubactions;
5153 }
#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:1124
void * palloc0(Size size)
Definition: mcxt.c:980
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:226
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:419
#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 1530 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

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

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

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

1339 {
1340  IndexAmRoutine *cached,
1341  *tmp;
1342 
1343  /*
1344  * Call the amhandler in current, short-lived memory context, just in case
1345  * it leaks anything (it probably won't, but let's be paranoid).
1346  */
1347  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1348 
1349  /* OK, now transfer the data into relation's rd_indexcxt. */
1350  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1351  sizeof(IndexAmRoutine));
1352  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1353  relation->rd_indam = cached;
1354 
1355  pfree(tmp);
1356 }
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 1731 of file relcache.c.

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

Referenced by RelationInitTableAccessMethod().

1732 {
1733  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1734 }
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 3982 of file relcache.c.

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

Referenced by RelationCacheInitializePhase3().

3983 {
3984  Relation ird;
3985 
3986  /*
3987  * We must lock the underlying catalog before locking the index to avoid
3988  * deadlock, since RelationBuildDesc might well need to read the catalog,
3989  * and if anyone else is exclusive-locking this catalog and index they'll
3990  * be doing it in that order.
3991  */
3992  LockRelationOid(heapoid, AccessShareLock);
3993  LockRelationOid(indexoid, AccessShareLock);
3994  ird = RelationBuildDesc(indexoid, true);
3995  if (ird == NULL)
3996  elog(PANIC, "could not open critical system index %u", indexoid);
3997  ird->rd_isnailed = true;
3998  ird->rd_refcnt = 1;
4001 }
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:1025
int rd_refcnt
Definition: rel.h:57
#define elog(elevel,...)
Definition: elog.h:226
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 5286 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().

5287 {
5288  FILE *fp;
5289  char initfilename[MAXPGPATH];
5290  Relation *rels;
5291  int relno,
5292  num_rels,
5293  max_rels,
5294  nailed_rels,
5295  nailed_indexes,
5296  magic;
5297  int i;
5298 
5299  if (shared)
5300  snprintf(initfilename, sizeof(initfilename), "global/%s",
5302  else
5303  snprintf(initfilename, sizeof(initfilename), "%s/%s",
5305 
5306  fp = AllocateFile(initfilename, PG_BINARY_R);
5307  if (fp == NULL)
5308  return false;
5309 
5310  /*
5311  * Read the index relcache entries from the file. Note we will not enter
5312  * any of them into the cache if the read fails partway through; this
5313  * helps to guard against broken init files.
5314  */
5315  max_rels = 100;
5316  rels = (Relation *) palloc(max_rels * sizeof(Relation));
5317  num_rels = 0;
5318  nailed_rels = nailed_indexes = 0;
5319 
5320  /* check for correct magic number (compatible version) */
5321  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
5322  goto read_failed;
5323  if (magic != RELCACHE_INIT_FILEMAGIC)
5324  goto read_failed;
5325 
5326  for (relno = 0;; relno++)
5327  {
5328  Size len;
5329  size_t nread;
5330  Relation rel;
5331  Form_pg_class relform;
5332  bool has_not_null;
5333 
5334  /* first read the relation descriptor length */
5335  nread = fread(&len, 1, sizeof(len), fp);
5336  if (nread != sizeof(len))
5337  {
5338  if (nread == 0)
5339  break; /* end of file */
5340  goto read_failed;
5341  }
5342 
5343  /* safety check for incompatible relcache layout */
5344  if (len != sizeof(RelationData))
5345  goto read_failed;
5346 
5347  /* allocate another relcache header */
5348  if (num_rels >= max_rels)
5349  {
5350  max_rels *= 2;
5351  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
5352  }
5353 
5354  rel = rels[num_rels++] = (Relation) palloc(len);
5355 
5356  /* then, read the Relation structure */
5357  if (fread(rel, 1, len, fp) != len)
5358  goto read_failed;
5359 
5360  /* next read the relation tuple form */
5361  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5362  goto read_failed;
5363 
5364  relform = (Form_pg_class) palloc(len);
5365  if (fread(relform, 1, len, fp) != len)
5366  goto read_failed;
5367 
5368  rel->rd_rel = relform;
5369 
5370  /* initialize attribute tuple forms */
5371  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
5372  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
5373 
5374  rel->rd_att->tdtypeid = relform->reltype;
5375  rel->rd_att->tdtypmod = -1; /* unnecessary, but... */
5376 
5377  /* next read all the attribute tuple form data entries */
5378  has_not_null = false;
5379  for (i = 0; i < relform->relnatts; i++)
5380  {
5381  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
5382 
5383  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5384  goto read_failed;
5385  if (len != ATTRIBUTE_FIXED_PART_SIZE)
5386  goto read_failed;
5387  if (fread(attr, 1, len, fp) != len)
5388  goto read_failed;
5389 
5390  has_not_null |= attr->attnotnull;
5391  }
5392 
5393  /* next read the access method specific field */
5394  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5395  goto read_failed;
5396  if (len > 0)
5397  {
5398  rel->rd_options = palloc(len);
5399  if (fread(rel->rd_options, 1, len, fp) != len)
5400  goto read_failed;
5401  if (len != VARSIZE(rel->rd_options))
5402  goto read_failed; /* sanity check */
5403  }
5404  else
5405  {
5406  rel->rd_options = NULL;
5407  }
5408 
5409  /* mark not-null status */
5410  if (has_not_null)
5411  {
5412  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
5413 
5414  constr->has_not_null = true;
5415  rel->rd_att->constr = constr;
5416  }
5417 
5418  /*
5419  * If it's an index, there's more to do. Note we explicitly ignore
5420  * partitioned indexes here.
5421  */
5422  if (rel->rd_rel->relkind == RELKIND_INDEX)
5423  {
5424  MemoryContext indexcxt;
5425  Oid *opfamily;
5426  Oid *opcintype;
5427  RegProcedure *support;
5428  int nsupport;
5429  int16 *indoption;
5430  Oid *indcollation;
5431 
5432  /* Count nailed indexes to ensure we have 'em all */
5433  if (rel->rd_isnailed)
5434  nailed_indexes++;
5435 
5436  /* next, read the pg_index tuple */
5437  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5438  goto read_failed;
5439 
5440  rel->rd_indextuple = (HeapTuple) palloc(len);
5441  if (fread(rel->rd_indextuple, 1, len, fp) != len)
5442  goto read_failed;
5443 
5444  /* Fix up internal pointers in the tuple -- see heap_copytuple */
5445  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
5447 
5448  /*
5449  * prepare index info context --- parameters should match
5450  * RelationInitIndexAccessInfo
5451  */
5453  "index info",
5455  rel->rd_indexcxt = indexcxt;
5458 
5459  /*
5460  * Now we can fetch the index AM's API struct. (We can't store
5461  * that in the init file, since it contains function pointers that
5462  * might vary across server executions. Fortunately, it should be
5463  * safe to call the amhandler even while bootstrapping indexes.)
5464  */
5465  InitIndexAmRoutine(rel);
5466 
5467  /* next, read the vector of opfamily OIDs */
5468  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5469  goto read_failed;
5470 
5471  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
5472  if (fread(opfamily, 1, len, fp) != len)
5473  goto read_failed;
5474 
5475  rel->rd_opfamily = opfamily;
5476 
5477  /* next, read the vector of opcintype OIDs */
5478  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5479  goto read_failed;
5480 
5481  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
5482  if (fread(opcintype, 1, len, fp) != len)
5483  goto read_failed;
5484 
5485  rel->rd_opcintype = opcintype;
5486 
5487  /* next, read the vector of support procedure OIDs */
5488  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5489  goto read_failed;
5490  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
5491  if (fread(support, 1, len, fp) != len)
5492  goto read_failed;
5493 
5494  rel->rd_support = support;
5495 
5496  /* next, read the vector of collation OIDs */
5497  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5498  goto read_failed;
5499 
5500  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
5501  if (fread(indcollation, 1, len, fp) != len)
5502  goto read_failed;
5503 
5504  rel->rd_indcollation = indcollation;
5505 
5506  /* finally, read the vector of indoption values */
5507  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5508  goto read_failed;
5509 
5510  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
5511  if (fread(indoption, 1, len, fp) != len)
5512  goto read_failed;
5513 
5514  rel->rd_indoption = indoption;
5515 
5516  /* set up zeroed fmgr-info vector */
5517  nsupport = relform->relnatts * rel->rd_indam->amsupport;
5518  rel->rd_supportinfo = (FmgrInfo *)
5519  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
5520  }
5521  else
5522  {
5523  /* Count nailed rels to ensure we have 'em all */
5524  if (rel->rd_isnailed)
5525  nailed_rels++;
5526 
5527  /* Load table AM data */
5528  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5529  rel->rd_rel->relkind == RELKIND_SEQUENCE ||
5530  rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
5531  rel->rd_rel->relkind == RELKIND_MATVIEW)
5533 
5534  Assert(rel->rd_index == NULL);
5535  Assert(rel->rd_indextuple == NULL);
5536  Assert(rel->rd_indexcxt == NULL);
5537  Assert(rel->rd_indam == NULL);
5538  Assert(rel->rd_opfamily == NULL);
5539  Assert(rel->rd_opcintype == NULL);
5540  Assert(rel->rd_support == NULL);
5541  Assert(rel->rd_supportinfo == NULL);
5542  Assert(rel->rd_indoption == NULL);
5543  Assert(rel->rd_indcollation == NULL);
5544  }
5545 
5546  /*
5547  * Rules and triggers are not saved (mainly because the internal
5548  * format is complex and subject to change). They must be rebuilt if
5549  * needed by RelationCacheInitializePhase3. This is not expected to
5550  * be a big performance hit since few system catalogs have such. Ditto
5551  * for RLS policy data, partition info, index expressions, predicates,
5552  * exclusion info, and FDW info.
5553  */
5554  rel->rd_rules = NULL;
5555  rel->rd_rulescxt = NULL;
5556  rel->trigdesc = NULL;
5557  rel->rd_rsdesc = NULL;
5558  rel->rd_partkey = NULL;
5559  rel->rd_partkeycxt = NULL;
5560  rel->rd_partdesc = NULL;
5561  rel->rd_pdcxt = NULL;
5562  rel->rd_partcheck = NIL;
5563  rel->rd_partcheckvalid = false;
5564  rel->rd_partcheckcxt = NULL;
5565  rel->rd_indexprs = NIL;
5566  rel->rd_indpred = NIL;
5567  rel->rd_exclops = NULL;
5568  rel->rd_exclprocs = NULL;
5569  rel->rd_exclstrats = NULL;
5570  rel->rd_fdwroutine = NULL;
5571 
5572  /*
5573  * Reset transient-state fields in the relcache entry
5574  */
5575  rel->rd_smgr = NULL;
5576  if (rel->rd_isnailed)
5577  rel->rd_refcnt = 1;
5578  else
5579  rel->rd_refcnt = 0;
5580  rel->rd_indexvalid = false;
5581  rel->rd_indexlist = NIL;
5582  rel->rd_pkindex = InvalidOid;
5583  rel->rd_replidindex = InvalidOid;
5584  rel->rd_indexattr = NULL;
5585  rel->rd_keyattr = NULL;
5586  rel->rd_pkattr = NULL;
5587  rel->rd_idattr = NULL;
5588  rel->rd_pubactions = NULL;
5589  rel->rd_statvalid = false;
5590  rel->rd_statlist = NIL;
5591  rel->rd_fkeyvalid = false;
5592  rel->rd_fkeylist = NIL;
5595  rel->rd_amcache = NULL;
5596  MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
5597 
5598  /*
5599  * Recompute lock and physical addressing info. This is needed in
5600  * case the pg_internal.init file was copied from some other database
5601  * by CREATE DATABASE.
5602  */
5603  RelationInitLockInfo(rel);
5605  }
5606 
5607  /*
5608  * We reached the end of the init file without apparent problem. Did we
5609  * get the right number of nailed items? This is a useful crosscheck in
5610  * case the set of critical rels or indexes changes. However, that should
5611  * not happen in a normally-running system, so let's bleat if it does.
5612  *
5613  * For the shared init file, we're called before client authentication is
5614  * done, which means that elog(WARNING) will go only to the postmaster
5615  * log, where it's easily missed. To ensure that developers notice bad
5616  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
5617  * an Assert(false) there.
5618  */
5619  if (shared)
5620  {
5621  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
5622  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
5623  {
5624  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
5625  nailed_rels, nailed_indexes,
5627  /* Make sure we get developers' attention about this */
5628  Assert(false);
5629  /* In production builds, recover by bootstrapping the relcache */
5630  goto read_failed;
5631  }
5632  }
5633  else
5634  {
5635  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
5636  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
5637  {
5638  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
5639  nailed_rels, nailed_indexes,
5641  /* We don't need an Assert() in this case */
5642  goto read_failed;
5643  }
5644  }
5645 
5646  /*
5647  * OK, all appears well.
5648  *
5649  * Now insert all the new relcache entries into the cache.
5650  */
5651  for (relno = 0; relno < num_rels; relno++)
5652  {
5653  RelationCacheInsert(rels[relno], false);
5654  }
5655 
5656  pfree(rels);
5657  FreeFile(fp);
5658 
5659  if (shared)
5661  else
5662  criticalRelcachesBuilt = true;
5663  return true;
5664 
5665  /*
5666  * init file is broken, so do it the hard way. We don't bother trying to
5667  * free the clutter we just allocated; it's not in the relcache so it
5668  * won't hurt.
5669  */
5670 read_failed:
5671  pfree(rels);
5672  FreeFile(fp);
5673 
5674  return false;
5675 }
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:190
signed short int16
Definition: c.h:345
#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:1740
#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:505
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:955
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
MemoryContext rd_rulescxt
Definition: rel.h:88
bool criticalSharedRelcachesBuilt
Definition: relcache.c:147
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:1193
#define NUM_CRITICAL_SHARED_RELS
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1338
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:1271
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:2205
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:94
#define RelationGetRelationName(relation)
Definition: rel.h:453
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:192
char * DatabasePath
Definition: globals.c:93
MemoryContext rd_pdcxt
Definition: rel.h:100
#define Assert(condition)
Definition: c.h:732
MemoryContext rd_partkeycxt
Definition: rel.h:98
RuleLock * rd_rules
Definition: rel.h:87
size_t Size
Definition: c.h:466
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:204
#define InvalidSubTransactionId
Definition: c.h:513
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
int FreeFile(FILE *file)
Definition: fd.c:2404
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:226
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:141
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 1581 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().

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

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

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

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

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

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 5964 of file relcache.c.

References LWLockRelease().

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

5965 {
5966  LWLockRelease(RelCacheInitLock);
5967 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

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

5940 {
5941  char localinitfname[MAXPGPATH];
5942  char sharedinitfname[MAXPGPATH];
5943 
5944  if (DatabasePath)
5945  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
5947  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
5949 
5950  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
5951 
5952  /*
5953  * The files might not be there if no backend has been started since the
5954  * last removal. But complain about failures other than ENOENT with
5955  * ERROR. Fortunately, it's not too late to abort the transaction if we
5956  * can't get rid of the would-be-obsolete init file.
5957  */
5958  if (DatabasePath)
5959  unlink_initfile(localinitfname, ERROR);
5960  unlink_initfile(sharedinitfname, ERROR);
5961 }
#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:6036
#define snprintf
Definition: port.h:192

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

5980 {
5981  const char *tblspcdir = "pg_tblspc";
5982  DIR *dir;
5983  struct dirent *de;
5984  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
5985 
5986  snprintf(path, sizeof(path), "global/%s",
5988  unlink_initfile(path, LOG);
5989 
5990  /* Scan everything in the default tablespace */
5992 
5993  /* Scan the tablespace link directory to find non-default tablespaces */
5994  dir = AllocateDir(tblspcdir);
5995 
5996  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
5997  {
5998  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
5999  {
6000  /* Scan the tablespace dir for per-database dirs */
6001  snprintf(path, sizeof(path), "%s/%s/%s",
6002  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6004  }
6005  }
6006 
6007  FreeDir(dir);
6008 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6012
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2547
#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:2466
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6036
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2584

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6012 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6013 {
6014  DIR *dir;
6015  struct dirent *de;
6016  char initfilename[MAXPGPATH * 2];
6017 
6018  /* Scan the tablespace directory to find per-database directories */
6019  dir = AllocateDir(tblspcpath);
6020 
6021  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6022  {
6023  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6024  {
6025  /* Try to remove the init file in each database */
6026  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6027  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6028  unlink_initfile(initfilename, LOG);
6029  }
6030  }
6031 
6032  FreeDir(dir);
6033 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2547
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2466
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6036
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2584

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3580 of file relcache.c.

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

Referenced by InitPostgres().

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

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

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

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

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

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

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

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

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

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

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2735 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2736 {
2737  Relation relation;
2738 
2739  RelationIdCacheLookup(relationId, relation);
2740 
2741  if (PointerIsValid(relation))
2742  {
2744  RelationFlushRelation(relation);
2745  }
2746 }
static long relcacheInvalsReceived
Definition: relcache.c:155
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:214
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2667
#define PointerIsValid(pointer)
Definition: c.h:626

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

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

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