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/parallel.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/tupdesc_details.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "commands/policy.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rowsecurity.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relmapper.h"
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for relcache.c:

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  opclasscacheent
 

Macros

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

Typedefs

typedef struct relidcacheent RelIdCacheEnt
 
typedef struct opclasscacheent OpClassCacheEnt
 

Functions

static void RelationDestroyRelation (Relation relation, bool remember_tupdesc)
 
static void RelationClearRelation (Relation relation, bool rebuild)
 
static void RelationReloadIndexInfo (Relation relation)
 
static void RelationReloadNailed (Relation relation)
 
static void RelationFlushRelation (Relation relation)
 
static void RememberToFreeTupleDescAtEOX (TupleDesc td)
 
static void AtEOXact_cleanup (Relation relation, bool isCommit)
 
static void AtEOSubXact_cleanup (Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
static bool load_relcache_init_file (bool shared)
 
static void write_relcache_init_file (bool shared)
 
static void write_item (const void *data, Size len, FILE *fp)
 
static void formrdesc (const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
 
static HeapTuple ScanPgRelation (Oid targetRelId, bool indexOK, bool force_non_historic)
 
static Relation AllocateRelationDesc (Form_pg_class relp)
 
static void RelationParseRelOptions (Relation relation, HeapTuple tuple)
 
static void RelationBuildTupleDesc (Relation relation)
 
static Relation RelationBuildDesc (Oid targetRelId, bool insertIt)
 
static void RelationInitPhysicalAddr (Relation relation)
 
static void load_critical_index (Oid indexoid, Oid heapoid)
 
static TupleDesc GetPgClassDescriptor (void)
 
static TupleDesc GetPgIndexDescriptor (void)
 
static void AttrDefaultFetch (Relation relation)
 
static void CheckConstraintFetch (Relation relation)
 
static int CheckConstraintCmp (const void *a, const void *b)
 
static void InitIndexAmRoutine (Relation relation)
 
static void IndexSupportInitialize (oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
 
static OpClassCacheEntLookupOpclassInfo (Oid operatorClassOid, StrategyNumber numSupport)
 
static void RelationCacheInitFileRemoveInDir (const char *tblspcpath)
 
static void unlink_initfile (const char *initfilename, int elevel)
 
static void RelationBuildRuleLock (Relation relation)
 
static bool equalRuleLocks (RuleLock *rlock1, RuleLock *rlock2)
 
static bool equalPolicy (RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
 
static bool equalRSDesc (RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
 
void RelationInitIndexAccessInfo (Relation relation)
 
static void InitTableAmRoutine (Relation relation)
 
void RelationInitTableAccessMethod (Relation relation)
 
Relation RelationIdGetRelation (Oid relationId)
 
void RelationIncrementReferenceCount (Relation rel)
 
void RelationDecrementReferenceCount (Relation rel)
 
void RelationClose (Relation relation)
 
void RelationForgetRelation (Oid rid)
 
void RelationCacheInvalidateEntry (Oid relationId)
 
void RelationCacheInvalidate (void)
 
void RelationCloseSmgrByOid (Oid relationId)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
Relation RelationBuildLocalRelation (const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid accessmtd, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence)
 
void RelationAssumeNewRelfilenode (Relation relation)
 
void RelationCacheInitialize (void)
 
void RelationCacheInitializePhase2 (void)
 
void RelationCacheInitializePhase3 (void)
 
static TupleDesc BuildHardcodedDescriptor (int natts, const FormData_pg_attribute *attrs)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetDummyIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (Relation relation)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
struct PublicationActionsGetRelationPublicationActions (Relation relation)
 
DatumRelationGetIndexRawAttOptions (Relation indexrel)
 
static bytea ** CopyIndexAttOptions (bytea **srcopts, int natts)
 
bytea ** RelationGetIndexAttOptions (Relation relation, bool copy)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
bool RelationIdIsInInitFile (Oid relationId)
 
void RelationCacheInitFilePreInvalidate (void)
 
void RelationCacheInitFilePostInvalidate (void)
 
void RelationCacheInitFileRemove (void)
 

Variables

static const FormData_pg_attribute Desc_pg_class [Natts_pg_class] = {Schema_pg_class}
 
static const FormData_pg_attribute Desc_pg_attribute [Natts_pg_attribute] = {Schema_pg_attribute}
 
static const FormData_pg_attribute Desc_pg_proc [Natts_pg_proc] = {Schema_pg_proc}
 
static const FormData_pg_attribute Desc_pg_type [Natts_pg_type] = {Schema_pg_type}
 
static const FormData_pg_attribute Desc_pg_database [Natts_pg_database] = {Schema_pg_database}
 
static const FormData_pg_attribute Desc_pg_authid [Natts_pg_authid] = {Schema_pg_authid}
 
static const FormData_pg_attribute Desc_pg_auth_members [Natts_pg_auth_members] = {Schema_pg_auth_members}
 
static const FormData_pg_attribute Desc_pg_index [Natts_pg_index] = {Schema_pg_index}
 
static const FormData_pg_attribute Desc_pg_shseclabel [Natts_pg_shseclabel] = {Schema_pg_shseclabel}
 
static const FormData_pg_attribute Desc_pg_subscription [Natts_pg_subscription] = {Schema_pg_subscription}
 
static HTABRelationIdCache
 
bool criticalRelcachesBuilt = false
 
bool criticalSharedRelcachesBuilt = false
 
static long relcacheInvalsReceived = 0L
 
static 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:163
static int eoxact_list_len
Definition: relcache.c:165

Definition at line 168 of file relcache.c.

Referenced by RelationAssumeNewRelfilenode(), and RelationBuildLocalRelation().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3761 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 163 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 101 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:919
static HTAB * RelationIdCache
Definition: relcache.c:131
#define WARNING
Definition: elog.h:40

Definition at line 222 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:919
static HTAB * RelationIdCache
Definition: relcache.c:131
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:440
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393

Definition at line 188 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:919
static HTAB * RelationIdCache
Definition: relcache.c:131

Definition at line 210 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 90 of file relcache.c.

Referenced by load_relcache_init_file(), and write_relcache_init_file().

◆ SWAPFIELD

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

Referenced by RelationClearRelation().

Typedef Documentation

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 385 of file relcache.c.

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

Referenced by RelationBuildDesc().

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

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

Referenced by AtEOSubXact_RelationCache().

3263 {
3264  /*
3265  * Is it a relation created in the current subtransaction?
3266  *
3267  * During subcommit, mark it as belonging to the parent, instead, as long
3268  * as it has not been dropped. Otherwise simply delete the relcache entry.
3269  * --- it isn't interesting any longer.
3270  */
3271  if (relation->rd_createSubid == mySubid)
3272  {
3273  /*
3274  * Valid rd_droppedSubid means the corresponding relation is dropped
3275  * but the relcache entry is preserved for at-commit pending sync. We
3276  * need to drop it explicitly here not to make the entry orphan.
3277  */
3278  Assert(relation->rd_droppedSubid == mySubid ||
3280  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3281  relation->rd_createSubid = parentSubid;
3282  else if (RelationHasReferenceCountZero(relation))
3283  {
3284  /* allow the entry to be removed */
3289  RelationClearRelation(relation, false);
3290  return;
3291  }
3292  else
3293  {
3294  /*
3295  * Hmm, somewhere there's a (leaked?) reference to the relation.
3296  * We daren't remove the entry for fear of dereferencing a
3297  * dangling pointer later. Bleat, and transfer it to the parent
3298  * subtransaction so we can try again later. This must be just a
3299  * WARNING to avoid error-during-error-recovery loops.
3300  */
3301  relation->rd_createSubid = parentSubid;
3302  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3303  RelationGetRelationName(relation));
3304  }
3305  }
3306 
3307  /*
3308  * Likewise, update or drop any new-relfilenode-in-subtransaction record
3309  * or drop record.
3310  */
3311  if (relation->rd_newRelfilenodeSubid == mySubid)
3312  {
3313  if (isCommit)
3314  relation->rd_newRelfilenodeSubid = parentSubid;
3315  else
3317  }
3318 
3319  if (relation->rd_firstRelfilenodeSubid == mySubid)
3320  {
3321  if (isCommit)
3322  relation->rd_firstRelfilenodeSubid = parentSubid;
3323  else
3325  }
3326 
3327  if (relation->rd_droppedSubid == mySubid)
3328  {
3329  if (isCommit)
3330  relation->rd_droppedSubid = parentSubid;
3331  else
3333  }
3334 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define Assert(condition)
Definition: c.h:745
#define InvalidSubTransactionId
Definition: c.h:526
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:440
#define elog(elevel,...)
Definition: elog.h:214
SubTransactionId rd_droppedSubid
Definition: rel.h:107

◆ AtEOSubXact_RelationCache()

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

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

3216 {
3218  RelIdCacheEnt *idhentry;
3219  int i;
3220 
3221  /*
3222  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3223  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3224  * logic as in AtEOXact_RelationCache.
3225  */
3227  {
3228  hash_seq_init(&status, RelationIdCache);
3229  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3230  {
3231  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3232  mySubid, parentSubid);
3233  }
3234  }
3235  else
3236  {
3237  for (i = 0; i < eoxact_list_len; i++)
3238  {
3239  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3240  (void *) &eoxact_list[i],
3241  HASH_FIND,
3242  NULL);
3243  if (idhentry != NULL)
3244  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3245  mySubid, parentSubid);
3246  }
3247  }
3248 
3249  /* Don't reset the list; we still need more cleanup later */
3250 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:164
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3261
Relation reldesc
Definition: relcache.c:128
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
static HTAB * RelationIdCache
Definition: relcache.c:131
static bool eoxact_list_overflowed
Definition: relcache.c:166
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
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:165

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3132 of file relcache.c.

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

Referenced by AtEOXact_RelationCache().

3133 {
3134  bool clear_relcache = false;
3135 
3136  /*
3137  * The relcache entry's ref count should be back to its normal
3138  * not-in-a-transaction state: 0 unless it's nailed in cache.
3139  *
3140  * In bootstrap mode, this is NOT true, so don't check it --- the
3141  * bootstrap code expects relations to stay open across start/commit
3142  * transaction calls. (That seems bogus, but it's not worth fixing.)
3143  *
3144  * Note: ideally this check would be applied to every relcache entry, not
3145  * just those that have eoxact work to do. But it's not worth forcing a
3146  * scan of the whole relcache just for this. (Moreover, doing so would
3147  * mean that assert-enabled testing never tests the hash_search code path
3148  * above, which seems a bad idea.)
3149  */
3150 #ifdef USE_ASSERT_CHECKING
3152  {
3153  int expected_refcnt;
3154 
3155  expected_refcnt = relation->rd_isnailed ? 1 : 0;
3156  Assert(relation->rd_refcnt == expected_refcnt);
3157  }
3158 #endif
3159 
3160  /*
3161  * Is the relation live after this transaction ends?
3162  *
3163  * During commit, clear the relcache entry if it is preserved after
3164  * relation drop, in order not to orphan the entry. During rollback,
3165  * clear the relcache entry if the relation is created in the current
3166  * transaction since it isn't interesting any longer once we are out of
3167  * the transaction.
3168  */
3169  clear_relcache =
3170  (isCommit ?
3173 
3174  /*
3175  * Since we are now out of the transaction, reset the subids to zero. That
3176  * also lets RelationClearRelation() drop the relcache entry.
3177  */
3182 
3183  if (clear_relcache)
3184  {
3185  if (RelationHasReferenceCountZero(relation))
3186  {
3187  RelationClearRelation(relation, false);
3188  return;
3189  }
3190  else
3191  {
3192  /*
3193  * Hmm, somewhere there's a (leaked?) reference to the relation.
3194  * We daren't remove the entry for fear of dereferencing a
3195  * dangling pointer later. Bleat, and mark it as not belonging to
3196  * the current transaction. Hopefully it'll get cleaned up
3197  * eventually. This must be just a WARNING to avoid
3198  * error-during-error-recovery loops.
3199  */
3200  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3201  RelationGetRelationName(relation));
3202  }
3203  }
3204 }
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
bool rd_isnailed
Definition: rel.h:61
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define Assert(condition)
Definition: c.h:745
#define InvalidSubTransactionId
Definition: c.h:526
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:440
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:214
SubTransactionId rd_droppedSubid
Definition: rel.h:107

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

3070 {
3072  RelIdCacheEnt *idhentry;
3073  int i;
3074 
3075  /*
3076  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3077  * listed in it. Otherwise fall back on a hash_seq_search scan.
3078  *
3079  * For simplicity, eoxact_list[] entries are not deleted till end of
3080  * top-level transaction, even though we could remove them at
3081  * subtransaction end in some cases, or remove relations from the list if
3082  * they are cleared for other reasons. Therefore we should expect the
3083  * case that list entries are not found in the hashtable; if not, there's
3084  * nothing to do for them.
3085  */
3087  {
3088  hash_seq_init(&status, RelationIdCache);
3089  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3090  {
3091  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3092  }
3093  }
3094  else
3095  {
3096  for (i = 0; i < eoxact_list_len; i++)
3097  {
3098  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3099  (void *) &eoxact_list[i],
3100  HASH_FIND,
3101  NULL);
3102  if (idhentry != NULL)
3103  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3104  }
3105  }
3106 
3107  if (EOXactTupleDescArrayLen > 0)
3108  {
3109  Assert(EOXactTupleDescArray != NULL);
3110  for (i = 0; i < NextEOXactTupleDescNum; i++)
3113  EOXactTupleDescArray = NULL;
3114  }
3115 
3116  /* Now we're out of the transaction and can clear the lists */
3117  eoxact_list_len = 0;
3118  eoxact_list_overflowed = false;
3119  NextEOXactTupleDescNum = 0;
3121 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:164
static int EOXactTupleDescArrayLen
Definition: relcache.c:183
Relation reldesc
Definition: relcache.c:128
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
static HTAB * RelationIdCache
Definition: relcache.c:131
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3132
static bool eoxact_list_overflowed
Definition: relcache.c:166
static int NextEOXactTupleDescNum
Definition: relcache.c:182
void pfree(void *pointer)
Definition: mcxt.c:1057
#define Assert(condition)
Definition: c.h:745
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
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:165
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:181

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

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

4242 {
4243  AttrDefault *attrdef = relation->rd_att->constr->defval;
4244  int ndef = relation->rd_att->constr->num_defval;
4245  Relation adrel;
4246  SysScanDesc adscan;
4247  ScanKeyData skey;
4248  HeapTuple htup;
4249  Datum val;
4250  bool isnull;
4251  int found;
4252  int i;
4253 
4254  ScanKeyInit(&skey,
4255  Anum_pg_attrdef_adrelid,
4256  BTEqualStrategyNumber, F_OIDEQ,
4257  ObjectIdGetDatum(RelationGetRelid(relation)));
4258 
4259  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4260  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4261  NULL, 1, &skey);
4262  found = 0;
4263 
4264  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4265  {
4266  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4267  Form_pg_attribute attr = TupleDescAttr(relation->rd_att, adform->adnum - 1);
4268 
4269  for (i = 0; i < ndef; i++)
4270  {
4271  if (adform->adnum != attrdef[i].adnum)
4272  continue;
4273  if (attrdef[i].adbin != NULL)
4274  elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
4275  NameStr(attr->attname),
4276  RelationGetRelationName(relation));
4277  else
4278  found++;
4279 
4280  val = fastgetattr(htup,
4281  Anum_pg_attrdef_adbin,
4282  adrel->rd_att, &isnull);
4283  if (isnull)
4284  elog(WARNING, "null adbin for attr %s of rel %s",
4285  NameStr(attr->attname),
4286  RelationGetRelationName(relation));
4287  else
4288  {
4289  /* detoast and convert to cstring in caller's context */
4290  char *s = TextDatumGetCString(val);
4291 
4293  pfree(s);
4294  }
4295  break;
4296  }
4297 
4298  if (i >= ndef)
4299  elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
4300  adform->adnum, RelationGetRelationName(relation));
4301  }
4302 
4303  systable_endscan(adscan);
4304  table_close(adrel, AccessShareLock);
4305 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#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:357
AttrDefault * defval
Definition: tupdesc.h:39
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define AttrDefaultIndexId
Definition: indexing.h:100
TupleConstr * constr
Definition: tupdesc.h:85
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:47
#define WARNING
Definition: elog.h:40
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
uint16 num_defval
Definition: tupdesc.h:42
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174
#define elog(elevel,...)
Definition: elog.h:214
int i
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25
#define NameStr(name)
Definition: c.h:622
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:456
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ BuildHardcodedDescriptor()

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

Definition at line 4182 of file relcache.c.

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

4183 {
4184  TupleDesc result;
4185  MemoryContext oldcxt;
4186  int i;
4187 
4189 
4190  result = CreateTemplateTupleDesc(natts);
4191  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4192  result->tdtypmod = -1;
4193 
4194  for (i = 0; i < natts; i++)
4195  {
4196  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4197  /* make sure attcacheoff is valid */
4198  TupleDescAttr(result, i)->attcacheoff = -1;
4199  }
4200 
4201  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4202  TupleDescAttr(result, 0)->attcacheoff = 0;
4203 
4204  /* Note: we don't bother to set up a TupleConstr entry */
4205 
4206  MemoryContextSwitchTo(oldcxt);
4207 
4208  return result;
4209 }
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:185
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 4382 of file relcache.c.

References ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

4383 {
4384  const ConstrCheck *ca = (const ConstrCheck *) a;
4385  const ConstrCheck *cb = (const ConstrCheck *) b;
4386 
4387  return strcmp(ca->ccname, cb->ccname);
4388 }
char * ccname
Definition: tupdesc.h:30

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

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

4312 {
4313  ConstrCheck *check = relation->rd_att->constr->check;
4314  int ncheck = relation->rd_att->constr->num_check;
4315  Relation conrel;
4316  SysScanDesc conscan;
4317  ScanKeyData skey[1];
4318  HeapTuple htup;
4319  int found = 0;
4320 
4321  ScanKeyInit(&skey[0],
4322  Anum_pg_constraint_conrelid,
4323  BTEqualStrategyNumber, F_OIDEQ,
4324  ObjectIdGetDatum(RelationGetRelid(relation)));
4325 
4326  conrel = table_open(ConstraintRelationId, AccessShareLock);
4327  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4328  NULL, 1, skey);
4329 
4330  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4331  {
4333  Datum val;
4334  bool isnull;
4335  char *s;
4336 
4337  /* We want check constraints only */
4338  if (conform->contype != CONSTRAINT_CHECK)
4339  continue;
4340 
4341  if (found >= ncheck)
4342  elog(ERROR, "unexpected constraint record found for rel %s",
4343  RelationGetRelationName(relation));
4344 
4345  check[found].ccvalid = conform->convalidated;
4346  check[found].ccnoinherit = conform->connoinherit;
4348  NameStr(conform->conname));
4349 
4350  /* Grab and test conbin is actually set */
4351  val = fastgetattr(htup,
4352  Anum_pg_constraint_conbin,
4353  conrel->rd_att, &isnull);
4354  if (isnull)
4355  elog(ERROR, "null conbin for rel %s",
4356  RelationGetRelationName(relation));
4357 
4358  /* detoast and convert to cstring in caller's context */
4359  s = TextDatumGetCString(val);
4360  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4361  pfree(s);
4362 
4363  found++;
4364  }
4365 
4366  systable_endscan(conscan);
4367  table_close(conrel, AccessShareLock);
4368 
4369  if (found != ncheck)
4370  elog(ERROR, "%d constraint record(s) missing for rel %s",
4371  ncheck - found, RelationGetRelationName(relation));
4372 
4373  /* Sort the records so that CHECKs are applied in a deterministic order */
4374  if (ncheck > 1)
4375  qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
4376 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#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:4382
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
void pfree(void *pointer)
Definition: mcxt.c:1057
#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:490
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
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:139
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:622
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:475
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
char * ccbin
Definition: tupdesc.h:31
#define RelationGetRelid(relation)
Definition: rel.h:456
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool ccnoinherit
Definition: tupdesc.h:33
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ CopyIndexAttOptions()

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

Definition at line 5416 of file relcache.c.

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

Referenced by RelationGetIndexAttOptions().

5417 {
5418  bytea **opts = palloc(sizeof(*opts) * natts);
5419 
5420  for (int i = 0; i < natts; i++)
5421  {
5422  bytea *opt = srcopts[i];
5423 
5424  opts[i] = !opt ? NULL : (bytea *)
5425  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5426  }
5427 
5428  return opts;
5429 }
#define PointerGetDatum(X)
Definition: postgres.h:556
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define DatumGetPointer(X)
Definition: postgres.h:549
void * palloc(Size size)
Definition: mcxt.c:950
int i
Definition: c.h:562

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

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

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

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

Referenced by RelationClearRelation().

988 {
989  ListCell *lc,
990  *rc;
991 
992  if (rsdesc1 == NULL && rsdesc2 == NULL)
993  return true;
994 
995  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
996  (rsdesc1 == NULL && rsdesc2 != NULL))
997  return false;
998 
999  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1000  return false;
1001 
1002  /* RelationBuildRowSecurity should build policies in order */
1003  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1004  {
1007 
1008  if (!equalPolicy(l, r))
1009  return false;
1010  }
1011 
1012  return true;
1013 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:434
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:941
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

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

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

5498 {
5502 
5503  return 0; /* return value does not matter */
5504 }
#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:3191
#define RelationGetRelationName(relation)
Definition: rel.h:490
int err_generic_string(int field, const char *str)
Definition: elog.c:1265
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5514 of file relcache.c.

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

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

5515 {
5516  TupleDesc reldesc = RelationGetDescr(rel);
5517  const char *colname;
5518 
5519  /* Use reldesc if it's a user attribute, else consult the catalogs */
5520  if (attnum > 0 && attnum <= reldesc->natts)
5521  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5522  else
5523  colname = get_attname(RelationGetRelid(rel), attnum, false);
5524 
5525  return errtablecolname(rel, colname);
5526 }
#define RelationGetDescr(relation)
Definition: rel.h:482
#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:622
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
#define RelationGetRelid(relation)
Definition: rel.h:456
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5538

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5538 of file relcache.c.

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

Referenced by errtablecol().

5539 {
5540  errtable(rel);
5542 
5543  return 0; /* return value does not matter */
5544 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1265
int errtable(Relation rel)
Definition: relcache.c:5497

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5551 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(), and ri_ReportViolation().

5552 {
5553  errtable(rel);
5555 
5556  return 0; /* return value does not matter */
5557 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1265
int errtable(Relation rel)
Definition: relcache.c:5497

◆ formrdesc()

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

Definition at line 1816 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_droppedSubid, RelationData::rd_firstRelfilenodeSubid, 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().

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

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

4213 {
4214  static TupleDesc pgclassdesc = NULL;
4215 
4216  /* Already done? */
4217  if (pgclassdesc == NULL)
4218  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4219  Desc_pg_class);
4220 
4221  return pgclassdesc;
4222 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4182
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:108

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4225 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

4226 {
4227  static TupleDesc pgindexdesc = NULL;
4228 
4229  /* Already done? */
4230  if (pgindexdesc == NULL)
4231  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4232  Desc_pg_index);
4233 
4234  return pgindexdesc;
4235 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:115
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4182

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5306 of file relcache.c.

References CacheMemoryContext, elog, ERROR, get_partition_ancestors(), 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, RelationData::rd_rel, RelationGetRelid, ReleaseSysCache(), and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

5307 {
5308  List *puboids;
5309  ListCell *lc;
5310  MemoryContext oldcxt;
5311  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5312 
5313  /*
5314  * If not publishable, it publishes no actions. (pgoutput_change() will
5315  * ignore it.)
5316  */
5317  if (!is_publishable_relation(relation))
5318  return pubactions;
5319 
5320  if (relation->rd_pubactions)
5321  return memcpy(pubactions, relation->rd_pubactions,
5322  sizeof(PublicationActions));
5323 
5324  /* Fetch the publication membership info. */
5325  puboids = GetRelationPublications(RelationGetRelid(relation));
5326  if (relation->rd_rel->relispartition)
5327  {
5328  /* Add publications that the ancestors are in too. */
5329  List *ancestors = get_partition_ancestors(RelationGetRelid(relation));
5330  ListCell *lc;
5331 
5332  foreach(lc, ancestors)
5333  {
5334  Oid ancestor = lfirst_oid(lc);
5335 
5336  puboids = list_concat_unique_oid(puboids,
5337  GetRelationPublications(ancestor));
5338  }
5339  }
5340  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5341 
5342  foreach(lc, puboids)
5343  {
5344  Oid pubid = lfirst_oid(lc);
5345  HeapTuple tup;
5346  Form_pg_publication pubform;
5347 
5349 
5350  if (!HeapTupleIsValid(tup))
5351  elog(ERROR, "cache lookup failed for publication %u", pubid);
5352 
5353  pubform = (Form_pg_publication) GETSTRUCT(tup);
5354 
5355  pubactions->pubinsert |= pubform->pubinsert;
5356  pubactions->pubupdate |= pubform->pubupdate;
5357  pubactions->pubdelete |= pubform->pubdelete;
5358  pubactions->pubtruncate |= pubform->pubtruncate;
5359 
5360  ReleaseSysCache(tup);
5361 
5362  /*
5363  * If we know everything is replicated, there is no point to check for
5364  * other publications.
5365  */
5366  if (pubactions->pubinsert && pubactions->pubupdate &&
5367  pubactions->pubdelete && pubactions->pubtruncate)
5368  break;
5369  }
5370 
5371  if (relation->rd_pubactions)
5372  {
5373  pfree(relation->rd_pubactions);
5374  relation->rd_pubactions = NULL;
5375  }
5376 
5377  /* Now save copy of the actions in the relcache entry. */
5379  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5380  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5381  MemoryContextSwitchTo(oldcxt);
5382 
5383  return pubactions;
5384 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:150
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:1057
#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:1301
bool is_publishable_relation(Relation rel)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void * palloc0(Size size)
Definition: mcxt.c:981
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:214
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:50
List * get_partition_ancestors(Oid relid)
Definition: partition.c:115
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:171
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 1542 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

1548 {
1549  int attIndex;
1550 
1551  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1552  {
1553  OpClassCacheEnt *opcentry;
1554 
1555  if (!OidIsValid(indclass->values[attIndex]))
1556  elog(ERROR, "bogus pg_index tuple");
1557 
1558  /* look up the info for this opclass, using a cache */
1559  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1560  maxSupportNumber);
1561 
1562  /* copy cached data into relcache entry */
1563  opFamily[attIndex] = opcentry->opcfamily;
1564  opcInType[attIndex] = opcentry->opcintype;
1565  if (maxSupportNumber > 0)
1566  memcpy(&indexSupport[attIndex * maxSupportNumber],
1567  opcentry->supportProcs,
1568  maxSupportNumber * sizeof(RegProcedure));
1569  }
1570 }
regproc RegProcedure
Definition: c.h:518
#define OidIsValid(objectId)
Definition: c.h:651
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:247
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1593
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:609
#define elog(elevel,...)
Definition: elog.h:214

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

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

1349 {
1350  IndexAmRoutine *cached,
1351  *tmp;
1352 
1353  /*
1354  * Call the amhandler in current, short-lived memory context, just in case
1355  * it leaks anything (it probably won't, but let's be paranoid).
1356  */
1357  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1358 
1359  /* OK, now transfer the data into relation's rd_indexcxt. */
1360  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1361  sizeof(IndexAmRoutine));
1362  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1363  relation->rd_indam = cached;
1364 
1365  pfree(tmp);
1366 }
struct IndexAmRoutine * rd_indam
Definition: rel.h:188
void pfree(void *pointer)
Definition: mcxt.c:1057
Oid rd_amhandler
Definition: rel.h:166
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
MemoryContext rd_indexcxt
Definition: rel.h:186

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1743 of file relcache.c.

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

Referenced by RelationInitTableAccessMethod().

1744 {
1745  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1746 }
Oid rd_amhandler
Definition: rel.h:166
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:34
const struct TableAmRoutine * rd_tableam
Definition: rel.h:171

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 4146 of file relcache.c.

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

Referenced by RelationCacheInitializePhase3().

4147 {
4148  Relation ird;
4149 
4150  /*
4151  * We must lock the underlying catalog before locking the index to avoid
4152  * deadlock, since RelationBuildDesc might well need to read the catalog,
4153  * and if anyone else is exclusive-locking this catalog and index they'll
4154  * be doing it in that order.
4155  */
4156  LockRelationOid(heapoid, AccessShareLock);
4157  LockRelationOid(indexoid, AccessShareLock);
4158  ird = RelationBuildDesc(indexoid, true);
4159  if (ird == NULL)
4160  elog(PANIC, "could not open critical system index %u", indexoid);
4161  ird->rd_isnailed = true;
4162  ird->rd_refcnt = 1;
4165 
4166  (void) RelationGetIndexAttOptions(ird, false);
4167 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
bool rd_isnailed
Definition: rel.h:61
#define AccessShareLock
Definition: lockdefs.h:36
#define PANIC
Definition: elog.h:53
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1028
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:214
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5436
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 5615 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_droppedSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_firstRelfilenodeSubid, 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_opcoptions, 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().

5616 {
5617  FILE *fp;
5618  char initfilename[MAXPGPATH];
5619  Relation *rels;
5620  int relno,
5621  num_rels,
5622  max_rels,
5623  nailed_rels,
5624  nailed_indexes,
5625  magic;
5626  int i;
5627 
5628  if (shared)
5629  snprintf(initfilename, sizeof(initfilename), "global/%s",
5631  else
5632  snprintf(initfilename, sizeof(initfilename), "%s/%s",
5634 
5635  fp = AllocateFile(initfilename, PG_BINARY_R);
5636  if (fp == NULL)
5637  return false;
5638 
5639  /*
5640  * Read the index relcache entries from the file. Note we will not enter
5641  * any of them into the cache if the read fails partway through; this
5642  * helps to guard against broken init files.
5643  */
5644  max_rels = 100;
5645  rels = (Relation *) palloc(max_rels * sizeof(Relation));
5646  num_rels = 0;
5647  nailed_rels = nailed_indexes = 0;
5648 
5649  /* check for correct magic number (compatible version) */
5650  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
5651  goto read_failed;
5652  if (magic != RELCACHE_INIT_FILEMAGIC)
5653  goto read_failed;
5654 
5655  for (relno = 0;; relno++)
5656  {
5657  Size len;
5658  size_t nread;
5659  Relation rel;
5660  Form_pg_class relform;
5661  bool has_not_null;
5662 
5663  /* first read the relation descriptor length */
5664  nread = fread(&len, 1, sizeof(len), fp);
5665  if (nread != sizeof(len))
5666  {
5667  if (nread == 0)
5668  break; /* end of file */
5669  goto read_failed;
5670  }
5671 
5672  /* safety check for incompatible relcache layout */
5673  if (len != sizeof(RelationData))
5674  goto read_failed;
5675 
5676  /* allocate another relcache header */
5677  if (num_rels >= max_rels)
5678  {
5679  max_rels *= 2;
5680  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
5681  }
5682 
5683  rel = rels[num_rels++] = (Relation) palloc(len);
5684 
5685  /* then, read the Relation structure */
5686  if (fread(rel, 1, len, fp) != len)
5687  goto read_failed;
5688 
5689  /* next read the relation tuple form */
5690  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5691  goto read_failed;
5692 
5693  relform = (Form_pg_class) palloc(len);
5694  if (fread(relform, 1, len, fp) != len)
5695  goto read_failed;
5696 
5697  rel->rd_rel = relform;
5698 
5699  /* initialize attribute tuple forms */
5700  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
5701  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
5702 
5703  rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
5704  rel->rd_att->tdtypmod = -1; /* just to be sure */
5705 
5706  /* next read all the attribute tuple form data entries */
5707  has_not_null = false;
5708  for (i = 0; i < relform->relnatts; i++)
5709  {
5710  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
5711 
5712  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5713  goto read_failed;
5714  if (len != ATTRIBUTE_FIXED_PART_SIZE)
5715  goto read_failed;
5716  if (fread(attr, 1, len, fp) != len)
5717  goto read_failed;
5718 
5719  has_not_null |= attr->attnotnull;
5720  }
5721 
5722  /* next read the access method specific field */
5723  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5724  goto read_failed;
5725  if (len > 0)
5726  {
5727  rel->rd_options = palloc(len);
5728  if (fread(rel->rd_options, 1, len, fp) != len)
5729  goto read_failed;
5730  if (len != VARSIZE(rel->rd_options))
5731  goto read_failed; /* sanity check */
5732  }
5733  else
5734  {
5735  rel->rd_options = NULL;
5736  }
5737 
5738  /* mark not-null status */
5739  if (has_not_null)
5740  {
5741  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
5742 
5743  constr->has_not_null = true;
5744  rel->rd_att->constr = constr;
5745  }
5746 
5747  /*
5748  * If it's an index, there's more to do. Note we explicitly ignore
5749  * partitioned indexes here.
5750  */
5751  if (rel->rd_rel->relkind == RELKIND_INDEX)
5752  {
5753  MemoryContext indexcxt;
5754  Oid *opfamily;
5755  Oid *opcintype;
5756  RegProcedure *support;
5757  int nsupport;
5758  int16 *indoption;
5759  Oid *indcollation;
5760 
5761  /* Count nailed indexes to ensure we have 'em all */
5762  if (rel->rd_isnailed)
5763  nailed_indexes++;
5764 
5765  /* next, read the pg_index tuple */
5766  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5767  goto read_failed;
5768 
5769  rel->rd_indextuple = (HeapTuple) palloc(len);
5770  if (fread(rel->rd_indextuple, 1, len, fp) != len)
5771  goto read_failed;
5772 
5773  /* Fix up internal pointers in the tuple -- see heap_copytuple */
5774  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
5776 
5777  /*
5778  * prepare index info context --- parameters should match
5779  * RelationInitIndexAccessInfo
5780  */
5782  "index info",
5784  rel->rd_indexcxt = indexcxt;
5787 
5788  /*
5789  * Now we can fetch the index AM's API struct. (We can't store
5790  * that in the init file, since it contains function pointers that
5791  * might vary across server executions. Fortunately, it should be
5792  * safe to call the amhandler even while bootstrapping indexes.)
5793  */
5794  InitIndexAmRoutine(rel);
5795 
5796  /* next, read the vector of opfamily OIDs */
5797  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5798  goto read_failed;
5799 
5800  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
5801  if (fread(opfamily, 1, len, fp) != len)
5802  goto read_failed;
5803 
5804  rel->rd_opfamily = opfamily;
5805 
5806  /* next, read the vector of opcintype OIDs */
5807  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5808  goto read_failed;
5809 
5810  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
5811  if (fread(opcintype, 1, len, fp) != len)
5812  goto read_failed;
5813 
5814  rel->rd_opcintype = opcintype;
5815 
5816  /* next, read the vector of support procedure OIDs */
5817  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5818  goto read_failed;
5819  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
5820  if (fread(support, 1, len, fp) != len)
5821  goto read_failed;
5822 
5823  rel->rd_support = support;
5824 
5825  /* next, read the vector of collation OIDs */
5826  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5827  goto read_failed;
5828 
5829  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
5830  if (fread(indcollation, 1, len, fp) != len)
5831  goto read_failed;
5832 
5833  rel->rd_indcollation = indcollation;
5834 
5835  /* finally, read the vector of indoption values */
5836  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5837  goto read_failed;
5838 
5839  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
5840  if (fread(indoption, 1, len, fp) != len)
5841  goto read_failed;
5842 
5843  rel->rd_indoption = indoption;
5844 
5845  /* finally, read the vector of opcoptions values */
5846  rel->rd_opcoptions = (bytea **)
5847  MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
5848 
5849  for (i = 0; i < relform->relnatts; i++)
5850  {
5851  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5852  goto read_failed;
5853 
5854  if (len > 0)
5855  {
5856  rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
5857  if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
5858  goto read_failed;
5859  }
5860  }
5861 
5862  /* set up zeroed fmgr-info vector */
5863  nsupport = relform->relnatts * rel->rd_indam->amsupport;
5864  rel->rd_supportinfo = (FmgrInfo *)
5865  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
5866  }
5867  else
5868  {
5869  /* Count nailed rels to ensure we have 'em all */
5870  if (rel->rd_isnailed)
5871  nailed_rels++;
5872 
5873  /* Load table AM data */
5874  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5875  rel->rd_rel->relkind == RELKIND_SEQUENCE ||
5876  rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
5877  rel->rd_rel->relkind == RELKIND_MATVIEW)
5879 
5880  Assert(rel->rd_index == NULL);
5881  Assert(rel->rd_indextuple == NULL);
5882  Assert(rel->rd_indexcxt == NULL);
5883  Assert(rel->rd_indam == NULL);
5884  Assert(rel->rd_opfamily == NULL);
5885  Assert(rel->rd_opcintype == NULL);
5886  Assert(rel->rd_support == NULL);
5887  Assert(rel->rd_supportinfo == NULL);
5888  Assert(rel->rd_indoption == NULL);
5889  Assert(rel->rd_indcollation == NULL);
5890  Assert(rel->rd_opcoptions == NULL);
5891  }
5892 
5893  /*
5894  * Rules and triggers are not saved (mainly because the internal
5895  * format is complex and subject to change). They must be rebuilt if
5896  * needed by RelationCacheInitializePhase3. This is not expected to
5897  * be a big performance hit since few system catalogs have such. Ditto
5898  * for RLS policy data, partition info, index expressions, predicates,
5899  * exclusion info, and FDW info.
5900  */
5901  rel->rd_rules = NULL;
5902  rel->rd_rulescxt = NULL;
5903  rel->trigdesc = NULL;
5904  rel->rd_rsdesc = NULL;
5905  rel->rd_partkey = NULL;
5906  rel->rd_partkeycxt = NULL;
5907  rel->rd_partdesc = NULL;
5908  rel->rd_pdcxt = NULL;
5909  rel->rd_partcheck = NIL;
5910  rel->rd_partcheckvalid = false;
5911  rel->rd_partcheckcxt = NULL;
5912  rel->rd_indexprs = NIL;
5913  rel->rd_indpred = NIL;
5914  rel->rd_exclops = NULL;
5915  rel->rd_exclprocs = NULL;
5916  rel->rd_exclstrats = NULL;
5917  rel->rd_fdwroutine = NULL;
5918 
5919  /*
5920  * Reset transient-state fields in the relcache entry
5921  */
5922  rel->rd_smgr = NULL;
5923  if (rel->rd_isnailed)
5924  rel->rd_refcnt = 1;
5925  else
5926  rel->rd_refcnt = 0;
5927  rel->rd_indexvalid = false;
5928  rel->rd_indexlist = NIL;
5929  rel->rd_pkindex = InvalidOid;
5930  rel->rd_replidindex = InvalidOid;
5931  rel->rd_indexattr = NULL;
5932  rel->rd_keyattr = NULL;
5933  rel->rd_pkattr = NULL;
5934  rel->rd_idattr = NULL;
5935  rel->rd_pubactions = NULL;
5936  rel->rd_statvalid = false;
5937  rel->rd_statlist = NIL;
5938  rel->rd_fkeyvalid = false;
5939  rel->rd_fkeylist = NIL;
5944  rel->rd_amcache = NULL;
5945  MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
5946 
5947  /*
5948  * Recompute lock and physical addressing info. This is needed in
5949  * case the pg_internal.init file was copied from some other database
5950  * by CREATE DATABASE.
5951  */
5952  RelationInitLockInfo(rel);
5954  }
5955 
5956  /*
5957  * We reached the end of the init file without apparent problem. Did we
5958  * get the right number of nailed items? This is a useful crosscheck in
5959  * case the set of critical rels or indexes changes. However, that should
5960  * not happen in a normally-running system, so let's bleat if it does.
5961  *
5962  * For the shared init file, we're called before client authentication is
5963  * done, which means that elog(WARNING) will go only to the postmaster
5964  * log, where it's easily missed. To ensure that developers notice bad
5965  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
5966  * an Assert(false) there.
5967  */
5968  if (shared)
5969  {
5970  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
5971  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
5972  {
5973  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
5974  nailed_rels, nailed_indexes,
5976  /* Make sure we get developers' attention about this */
5977  Assert(false);
5978  /* In production builds, recover by bootstrapping the relcache */
5979  goto read_failed;
5980  }
5981  }
5982  else
5983  {
5984  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
5985  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
5986  {
5987  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
5988  nailed_rels, nailed_indexes,
5990  /* We don't need an Assert() in this case */
5991  goto read_failed;
5992  }
5993  }
5994 
5995  /*
5996  * OK, all appears well.
5997  *
5998  * Now insert all the new relcache entries into the cache.
5999  */
6000  for (relno = 0; relno < num_rels; relno++)
6001  {
6002  RelationCacheInsert(rels[relno], false);
6003  }
6004 
6005  pfree(rels);
6006  FreeFile(fp);
6007 
6008  if (shared)
6010  else
6011  criticalRelcachesBuilt = true;
6012  return true;
6013 
6014  /*
6015  * init file is broken, so do it the hard way. We don't bother trying to
6016  * free the clutter we just allocated; it's not in the relcache so it
6017  * won't hurt.
6018  */
6019 read_failed:
6020  pfree(rels);
6021  FreeFile(fp);
6022 
6023  return false;
6024 }
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:222
signed short int16
Definition: c.h:361
#define NIL
Definition: pg_list.h:65
struct IndexAmRoutine * rd_indam
Definition: rel.h:188
Definition: fmgr.h:56
uint16 amsupport
Definition: amapi.h:215
#define AllocSetContextCreate
Definition: memutils.h:170
HeapTupleData * HeapTuple
Definition: htup.h:71
int16 * rd_indoption
Definition: rel.h:193
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
PublicationActions * rd_pubactions
Definition: rel.h:150
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
struct FmgrInfo * rd_supportinfo
Definition: rel.h:192
Bitmapset * rd_keyattr
Definition: rel.h:146
#define VARSIZE(PTR)
Definition: postgres.h:303
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1752
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Oid rd_replidindex
Definition: rel.h:139
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
bool rd_isnailed
Definition: rel.h:61
regproc RegProcedure
Definition: c.h:518
uint16 * rd_exclstrats
Definition: rel.h:198
#define NUM_CRITICAL_LOCAL_INDEXES
List * rd_indexprs
Definition: rel.h:194
bytea ** rd_opcoptions
Definition: rel.h:200
List * rd_fkeylist
Definition: rel.h:120
bool rd_partcheckvalid
Definition: rel.h:133
#define MemSet(start, val, len)
Definition: c.h:949
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
MemoryContext rd_rulescxt
Definition: rel.h:114
bool criticalSharedRelcachesBuilt
Definition: relcache.c:143
Oid * rd_exclprocs
Definition: rel.h:197
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define NUM_CRITICAL_SHARED_INDEXES
#define PG_BINARY_R
Definition: c.h:1213
#define NUM_CRITICAL_SHARED_RELS
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1348
struct HeapTupleData * rd_indextuple
Definition: rel.h:176
HeapTupleHeader t_data
Definition: htup.h:68
struct RelationData * Relation
Definition: relcache.h:27
Form_pg_index rd_index
Definition: rel.h:174
PartitionKey rd_partkey
Definition: rel.h:124
void pfree(void *pointer)
Definition: mcxt.c:1057
#define NUM_CRITICAL_LOCAL_RELS
Oid * rd_indcollation
Definition: rel.h:199
int32 tdtypmod
Definition: tupdesc.h:83
Oid rd_pkindex
Definition: rel.h:138
#define MAXPGPATH
TriggerDesc * trigdesc
Definition: rel.h:115
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1266
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:2322
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:90
#define RelationGetRelationName(relation)
Definition: rel.h:490
List * rd_indpred
Definition: rel.h:195
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Oid * rd_opfamily
Definition: rel.h:189
Oid * rd_exclops
Definition: rel.h:196
PartitionDesc rd_partdesc
Definition: rel.h:128
List * rd_indexlist
Definition: rel.h:137
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:185
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
RegProcedure * rd_support
Definition: rel.h:191
#define WARNING
Definition: elog.h:40
FormData_pg_index * Form_pg_index
Definition: pg_index.h:68
SubTransactionId rd_createSubid
Definition: rel.h:102
bool rd_indexvalid
Definition: rel.h:63
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
void * palloc0(Size size)
Definition: mcxt.c:981
TupleDesc rd_att
Definition: rel.h:110
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:840
#define InvalidOid
Definition: postgres_ext.h:36
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
Bitmapset * rd_idattr
Definition: rel.h:148
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:188
char * DatabasePath
Definition: globals.c:93
MemoryContext rd_pdcxt
Definition: rel.h:129
#define Assert(condition)
Definition: c.h:745
MemoryContext rd_partkeycxt
Definition: rel.h:125
RuleLock * rd_rules
Definition: rel.h:113
size_t Size
Definition: c.h:473
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:236
#define InvalidSubTransactionId
Definition: c.h:526
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
int FreeFile(FILE *file)
Definition: fd.c:2521
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
Bitmapset * rd_pkattr
Definition: rel.h:147
Oid tdtypeid
Definition: tupdesc.h:82
bool rd_statvalid
Definition: rel.h:65
void * palloc(Size size)
Definition: mcxt.c:950
int rd_refcnt
Definition: rel.h:58
#define HEAPTUPLESIZE
Definition: htup.h:73
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
#define elog(elevel,...)
Definition: elog.h:214
MemoryContext rd_indexcxt
Definition: rel.h:186
int i
int tdrefcount
Definition: tupdesc.h:84
Definition: c.h:562
MemoryContext rd_partcheckcxt
Definition: rel.h:134
bool criticalRelcachesBuilt
Definition: relcache.c:137
void * rd_amcache
Definition: rel.h:211
Oid * rd_opcintype
Definition: rel.h:190
bool has_not_null
Definition: tupdesc.h:44
List * rd_statlist
Definition: rel.h:142
#define snprintf
Definition: port.h:193
bool rd_fkeyvalid
Definition: rel.h:121
List * rd_partcheck
Definition: rel.h:132
Bitmapset * rd_indexattr
Definition: rel.h:145
bytea * rd_options
Definition: rel.h:157
SubTransactionId rd_droppedSubid
Definition: rel.h:107
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ LookupOpclassInfo()

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

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

1595 {
1596  OpClassCacheEnt *opcentry;
1597  bool found;
1598  Relation rel;
1599  SysScanDesc scan;
1600  ScanKeyData skey[3];
1601  HeapTuple htup;
1602  bool indexOK;
1603 
1604  if (OpClassCache == NULL)
1605  {
1606  /* First time through: initialize the opclass cache */
1607  HASHCTL ctl;
1608 
1609  MemSet(&ctl, 0, sizeof(ctl));
1610  ctl.keysize = sizeof(Oid);
1611  ctl.entrysize = sizeof(OpClassCacheEnt);
1612  OpClassCache = hash_create("Operator class cache", 64,
1613  &ctl, HASH_ELEM | HASH_BLOBS);
1614 
1615  /* Also make sure CacheMemoryContext exists */
1616  if (!CacheMemoryContext)
1618  }
1619 
1620  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1621  (void *) &operatorClassOid,
1622  HASH_ENTER, &found);
1623 
1624  if (!found)
1625  {
1626  /* Need to allocate memory for new entry */
1627  opcentry->valid = false; /* until known OK */
1628  opcentry->numSupport = numSupport;
1629 
1630  if (numSupport > 0)
1631  opcentry->supportProcs = (RegProcedure *)
1633  (numSupport + 1) * sizeof(RegProcedure));
1634  else
1635  opcentry->supportProcs = NULL;
1636  }
1637  else
1638  {
1639  Assert(numSupport == opcentry->numSupport);
1640  }
1641 
1642  /*
1643  * When testing for cache-flush hazards, we intentionally disable the
1644  * operator class cache and force reloading of the info on each call. This
1645  * is helpful because we want to test the case where a cache flush occurs
1646  * while we are loading the info, and it's very hard to provoke that if
1647  * this happens only once per opclass per backend.
1648  */
1649 #if defined(CLOBBER_CACHE_ALWAYS)
1650  opcentry->valid = false;
1651 #endif
1652 
1653  if (opcentry->valid)
1654  return opcentry;
1655 
1656  /*
1657  * Need to fill in new entry.
1658  *
1659  * To avoid infinite recursion during startup, force heap scans if we're
1660  * looking up info for the opclasses used by the indexes we would like to
1661  * reference here.
1662  */
1663  indexOK = criticalRelcachesBuilt ||
1664  (operatorClassOid != OID_BTREE_OPS_OID &&
1665  operatorClassOid != INT2_BTREE_OPS_OID);
1666 
1667  /*
1668  * We have to fetch the pg_opclass row to determine its opfamily and
1669  * opcintype, which are needed to look up related operators and functions.
1670  * It'd be convenient to use the syscache here, but that probably doesn't
1671  * work while bootstrapping.
1672  */
1673  ScanKeyInit(&skey[0],
1674  Anum_pg_opclass_oid,
1675  BTEqualStrategyNumber, F_OIDEQ,
1676  ObjectIdGetDatum(operatorClassOid));
1677  rel = table_open(OperatorClassRelationId, AccessShareLock);
1678  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1679  NULL, 1, skey);
1680 
1681  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1682  {
1683  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1684 
1685  opcentry->opcfamily = opclassform->opcfamily;
1686  opcentry->opcintype = opclassform->opcintype;
1687  }
1688  else
1689  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1690 
1691  systable_endscan(scan);
1693 
1694  /*
1695  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1696  * the default ones (those with lefttype = righttype = opcintype).
1697  */
1698  if (numSupport > 0)
1699  {
1700  ScanKeyInit(&skey[0],
1701  Anum_pg_amproc_amprocfamily,
1702  BTEqualStrategyNumber, F_OIDEQ,
1703  ObjectIdGetDatum(opcentry->opcfamily));
1704  ScanKeyInit(&skey[1],
1705  Anum_pg_amproc_amproclefttype,
1706  BTEqualStrategyNumber, F_OIDEQ,
1707  ObjectIdGetDatum(opcentry->opcintype));
1708  ScanKeyInit(&skey[2],
1709  Anum_pg_amproc_amprocrighttype,
1710  BTEqualStrategyNumber, F_OIDEQ,
1711  ObjectIdGetDatum(opcentry->opcintype));
1712  rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1713  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1714  NULL, 3, skey);
1715 
1716  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1717  {
1718  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1719 
1720  if (amprocform->amprocnum <= 0 ||
1721  (StrategyNumber) amprocform->amprocnum > numSupport)
1722  elog(ERROR, "invalid amproc number %d for opclass %u",
1723  amprocform->amprocnum, operatorClassOid);
1724 
1725  opcentry->supportProcs[amprocform->amprocnum - 1] =
1726  amprocform->amproc;
1727  }
1728 
1729  systable_endscan(scan);
1731  }
1732 
1733  opcentry->valid = true;
1734  return opcentry;
1735 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
struct opclasscacheent OpClassCacheEnt
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define HASH_ELEM
Definition: hsearch.h:85
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
regproc RegProcedure
Definition: c.h:518
#define AccessShareLock
Definition: lockdefs.h:36
Size entrysize
Definition: hsearch.h:72
uint16 StrategyNumber
Definition: stratnum.h:22
#define MemSet(start, val, len)
Definition: c.h:949
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
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:357
StrategyNumber numSupport
Definition: relcache.c:244
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:247
static HTAB * OpClassCache
Definition: relcache.c:250
#define HASH_BLOBS
Definition: hsearch.h:86
#define AccessMethodProcedureIndexId
Definition: indexing.h:95
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:840
#define OpclassOidIndexId
Definition: indexing.h:208
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool criticalRelcachesBuilt
Definition: relcache.c:137
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

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3738 of file relcache.c.

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilenodeSubid, and RelationData::rd_newRelfilenodeSubid.

Referenced by ATExecSetTableSpace(), RelationSetNewRelfilenode(), and swap_relation_files().

3739 {
3742  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3743 
3744  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3745  EOXactListAdd(relation);
3746 }
#define EOXactListAdd(rel)
Definition: relcache.c:168
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define InvalidSubTransactionId
Definition: c.h:526

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1028 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_droppedSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationParseRelOptions(), ScanPgRelation(), and RelationData::trigdesc.

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

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

◆ RelationBuildLocalRelation()

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

Definition at line 3343 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_droppedSubid, RelationData::rd_firstRelfilenodeSubid, 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(), TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

3354 {
3355  Relation rel;
3356  MemoryContext oldcxt;
3357  int natts = tupDesc->natts;
3358  int i;
3359  bool has_not_null;
3360  bool nailit;
3361 
3362  AssertArg(natts >= 0);
3363 
3364  /*
3365  * check for creation of a rel that must be nailed in cache.
3366  *
3367  * XXX this list had better match the relations specially handled in
3368  * RelationCacheInitializePhase2/3.
3369  */
3370  switch (relid)
3371  {
3372  case DatabaseRelationId:
3373  case AuthIdRelationId:
3374  case AuthMemRelationId:
3375  case RelationRelationId:
3376  case AttributeRelationId:
3377  case ProcedureRelationId:
3378  case TypeRelationId:
3379  nailit = true;
3380  break;
3381  default:
3382  nailit = false;
3383  break;
3384  }
3385 
3386  /*
3387  * check that hardwired list of shared rels matches what's in the
3388  * bootstrap .bki file. If you get a failure here during initdb, you
3389  * probably need to fix IsSharedRelation() to match whatever you've done
3390  * to the set of shared relations.
3391  */
3392  if (shared_relation != IsSharedRelation(relid))
3393  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3394  relname, relid);
3395 
3396  /* Shared relations had better be mapped, too */
3397  Assert(mapped_relation || !shared_relation);
3398 
3399  /*
3400  * switch to the cache context to create the relcache entry.
3401  */
3402  if (!CacheMemoryContext)
3404 
3406 
3407  /*
3408  * allocate a new relation descriptor and fill in basic state fields.
3409  */
3410  rel = (Relation) palloc0(sizeof(RelationData));
3411 
3412  /* make sure relation is marked as having no open file yet */
3413  rel->rd_smgr = NULL;
3414 
3415  /* mark it nailed if appropriate */
3416  rel->rd_isnailed = nailit;
3417 
3418  rel->rd_refcnt = nailit ? 1 : 0;
3419 
3420  /* it's being created in this transaction */
3425 
3426  /*
3427  * create a new tuple descriptor from the one passed in. We do this
3428  * partly to copy it into the cache context, and partly because the new
3429  * relation can't have any defaults or constraints yet; they have to be
3430  * added in later steps, because they require additions to multiple system
3431  * catalogs. We can copy attnotnull constraints here, however.
3432  */
3433  rel->rd_att = CreateTupleDescCopy(tupDesc);
3434  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3435  has_not_null = false;
3436  for (i = 0; i < natts; i++)
3437  {
3438  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3439  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3440 
3441  datt->attidentity = satt->attidentity;
3442  datt->attgenerated = satt->attgenerated;
3443  datt->attnotnull = satt->attnotnull;
3444  has_not_null |= satt->attnotnull;
3445  }
3446 
3447  if (has_not_null)
3448  {
3449  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3450 
3451  constr->has_not_null = true;
3452  rel->rd_att->constr = constr;
3453  }
3454 
3455  /*
3456  * initialize relation tuple form (caller may add/override data later)
3457  */
3459 
3460  namestrcpy(&rel->rd_rel->relname, relname);
3461  rel->rd_rel->relnamespace = relnamespace;
3462 
3463  rel->rd_rel->relkind = relkind;
3464  rel->rd_rel->relnatts = natts;
3465  rel->rd_rel->reltype = InvalidOid;
3466  /* needed when bootstrapping: */
3467  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3468 
3469  /* set up persistence and relcache fields dependent on it */
3470  rel->rd_rel->relpersistence = relpersistence;
3471  switch (relpersistence)
3472  {
3473  case RELPERSISTENCE_UNLOGGED:
3474  case RELPERSISTENCE_PERMANENT:
3476  rel->rd_islocaltemp = false;
3477  break;
3478  case RELPERSISTENCE_TEMP:
3479  Assert(isTempOrTempToastNamespace(relnamespace));
3481  rel->rd_islocaltemp = true;
3482  break;
3483  default:
3484  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3485  break;
3486  }
3487 
3488  /* if it's a materialized view, it's not populated initially */
3489  if (relkind == RELKIND_MATVIEW)
3490  rel->rd_rel->relispopulated = false;
3491  else
3492  rel->rd_rel->relispopulated = true;
3493 
3494  /* set replica identity -- system catalogs and non-tables don't have one */
3495  if (!IsCatalogNamespace(relnamespace) &&
3496  (relkind == RELKIND_RELATION ||
3497  relkind == RELKIND_MATVIEW ||
3498  relkind == RELKIND_PARTITIONED_TABLE))
3499  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3500  else
3501  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3502 
3503  /*
3504  * Insert relation physical and logical identifiers (OIDs) into the right
3505  * places. For a mapped relation, we set relfilenode to zero and rely on
3506  * RelationInitPhysicalAddr to consult the map.
3507  */
3508  rel->rd_rel->relisshared = shared_relation;
3509 
3510  RelationGetRelid(rel) = relid;
3511 
3512  for (i = 0; i < natts; i++)
3513  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3514 
3515  rel->rd_rel->reltablespace = reltablespace;
3516 
3517  if (mapped_relation)
3518  {
3519  rel->rd_rel->relfilenode = InvalidOid;
3520  /* Add it to the active mapping information */
3521  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3522  }
3523  else
3524  rel->rd_rel->relfilenode = relfilenode;
3525 
3526  RelationInitLockInfo(rel); /* see lmgr.c */
3527 
3529 
3530  rel->rd_rel->relam = accessmtd;
3531 
3532  if (relkind == RELKIND_RELATION ||
3533  relkind == RELKIND_SEQUENCE ||
3534  relkind == RELKIND_TOASTVALUE ||
3535  relkind == RELKIND_MATVIEW)
3537 
3538  /*
3539  * Okay to insert into the relcache hash table.
3540  *
3541  * Ordinarily, there should certainly not be an existing hash entry for
3542  * the same OID; but during bootstrap, when we create a "real" relcache
3543  * entry for one of the bootstrap relations, we'll be overwriting the
3544  * phony one created with formrdesc. So allow that to happen for nailed
3545  * rels.
3546  */
3547  RelationCacheInsert(rel, nailit);
3548 
3549  /*
3550  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3551  * can't do this before storing relid in it.
3552  */
3553  EOXactListAdd(rel);
3554 
3555  /*
3556  * done building relcache entry.
3557  */
3558  MemoryContextSwitchTo(oldcxt);
3559 
3560  /* It's fully valid */
3561  rel->rd_isvalid = true;
3562 
3563  /*
3564  * Caller expects us to pin the returned entry.
3565  */
3567 
3568  return rel;
3569 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define EOXactListAdd(rel)
Definition: relcache.c:168
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3180
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1752
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
Form_pg_class rd_rel
Definition: rel.h:109
NameData relname
Definition: pg_class.h:38
struct RelationData * Relation
Definition: relcache.h:27
#define ERROR
Definition: elog.h:43
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1266
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:193
#define AssertArg(condition)
Definition: c.h:747
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:981
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2077
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:238
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:188
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:745
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define InvalidSubTransactionId
Definition: c.h:526
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:177
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int rd_refcnt
Definition: rel.h:58
#define elog(elevel,...)
Definition: elog.h:214
int i
int tdrefcount
Definition: tupdesc.h:84
bool has_not_null
Definition: tupdesc.h:44
#define RelationGetRelid(relation)
Definition: rel.h:456
SubTransactionId rd_droppedSubid
Definition: rel.h:107
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 735 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().

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

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 497 of file relcache.c.

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

Referenced by RelationBuildDesc().

498 {
499  HeapTuple pg_attribute_tuple;
500  Relation pg_attribute_desc;
501  SysScanDesc pg_attribute_scan;
502  ScanKeyData skey[2];
503  int need;
504  TupleConstr *constr;
505  AttrDefault *attrdef = NULL;
506  AttrMissing *attrmiss = NULL;
507  int ndef = 0;
508 
509  /* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */
510  relation->rd_att->tdtypeid =
511  relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
512  relation->rd_att->tdtypmod = -1; /* just to be sure */
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 ||
679  constr->has_generated_stored ||
680  ndef > 0 ||
681  attrmiss ||
682  relation->rd_rel->relchecks)
683  {
684  relation->rd_att->constr = constr;
685 
686  if (ndef > 0) /* DEFAULTs */
687  {
688  if (ndef < RelationGetNumberOfAttributes(relation))
689  constr->defval = (AttrDefault *)
690  repalloc(attrdef, ndef * sizeof(AttrDefault));
691  else
692  constr->defval = attrdef;
693  constr->num_defval = ndef;
694  AttrDefaultFetch(relation);
695  }
696  else
697  constr->num_defval = 0;
698 
699  constr->missing = attrmiss;
700 
701  if (relation->rd_rel->relchecks > 0) /* CHECKs */
702  {
703  constr->num_check = relation->rd_rel->relchecks;
704  constr->check = (ConstrCheck *)
706  constr->num_check * sizeof(ConstrCheck));
707  CheckConstraintFetch(relation);
708  }
709  else
710  constr->num_check = 0;
711  }
712  else
713  {
714  pfree(constr);
715  relation->rd_att->constr = NULL;
716  }
717 }
#define AttributeRelidNumIndexId
Definition: indexing.h:107
static void AttrDefaultFetch(Relation relation)
Definition: relcache.c:4241
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:462
#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:109
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
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:476
void pfree(void *pointer)
Definition: mcxt.c:1057
#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:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:185
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#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:110
uint16 num_check
Definition: tupdesc.h:43
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:840
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:1841
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4311
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
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:797
#define elog(elevel,...)
Definition: elog.h:214
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:137
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:456
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6323 of file relcache.c.

References LWLockRelease().

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

6324 {
6325  LWLockRelease(RelCacheInitLock);
6326 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

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

6299 {
6300  char localinitfname[MAXPGPATH];
6301  char sharedinitfname[MAXPGPATH];
6302 
6303  if (DatabasePath)
6304  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6306  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6308 
6309  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6310 
6311  /*
6312  * The files might not be there if no backend has been started since the
6313  * last removal. But complain about failures other than ENOENT with
6314  * ERROR. Fortunately, it's not too late to abort the transaction if we
6315  * can't get rid of the would-be-obsolete init file.
6316  */
6317  if (DatabasePath)
6318  unlink_initfile(localinitfname, ERROR);
6319  unlink_initfile(sharedinitfname, ERROR);
6320 }
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
char * DatabasePath
Definition: globals.c:93
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6395
#define snprintf
Definition: port.h:193

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

6339 {
6340  const char *tblspcdir = "pg_tblspc";
6341  DIR *dir;
6342  struct dirent *de;
6343  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6344 
6345  snprintf(path, sizeof(path), "global/%s",
6347  unlink_initfile(path, LOG);
6348 
6349  /* Scan everything in the default tablespace */
6351 
6352  /* Scan the tablespace link directory to find non-default tablespaces */
6353  dir = AllocateDir(tblspcdir);
6354 
6355  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6356  {
6357  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6358  {
6359  /* Scan the tablespace dir for per-database dirs */
6360  snprintf(path, sizeof(path), "%s/%s/%s",
6361  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6363  }
6364  }
6365 
6366  FreeDir(dir);
6367 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6371
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2664
#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:2583
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6395
char d_name[MAX_PATH]
Definition: dirent.h:15
#define snprintf
Definition: port.h:193
int FreeDir(DIR *dir)
Definition: fd.c:2701

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6371 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6372 {
6373  DIR *dir;
6374  struct dirent *de;
6375  char initfilename[MAXPGPATH * 2];
6376 
6377  /* Scan the tablespace directory to find per-database directories */
6378  dir = AllocateDir(tblspcpath);
6379 
6380  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6381  {
6382  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6383  {
6384  /* Try to remove the init file in each database */
6385  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6386  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6387  unlink_initfile(initfilename, LOG);
6388  }
6389  }
6390 
6391  FreeDir(dir);
6392 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2664
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2583
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6395
char d_name[MAX_PATH]
Definition: dirent.h:15
#define snprintf
Definition: port.h:193
int FreeDir(DIR *dir)
Definition: fd.c:2701

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3764 of file relcache.c.

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

Referenced by InitPostgres().

3765 {
3766  HASHCTL ctl;
3767 
3768  /*
3769  * make sure cache memory context exists
3770  */
3771  if (!CacheMemoryContext)
3773 
3774  /*
3775  * create hashtable that indexes the relcache
3776  */
3777  MemSet(&ctl, 0, sizeof(ctl));
3778  ctl.keysize = sizeof(Oid);
3779  ctl.entrysize = sizeof(RelIdCacheEnt);
3780  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3781  &ctl, HASH_ELEM | HASH_BLOBS);
3782 
3783  /*
3784  * relation mapper needs to be initialized too
3785  */
3787 }
void RelationMapInitialize(void)
Definition: relmapper.c:584
#define HASH_ELEM
Definition: hsearch.h:85
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:72
#define MemSet(start, val, len)
Definition: c.h:949
static HTAB * RelationIdCache
Definition: relcache.c:131
unsigned int Oid
Definition: postgres_ext.h:31
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define INITRELCACHESIZE
Definition: relcache.c:3761
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

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

3802 {
3803  MemoryContext oldcxt;
3804 
3805  /*
3806  * relation mapper needs initialized too
3807  */
3809 
3810  /*
3811  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3812  * nothing.
3813  */
3815  return;
3816 
3817  /*
3818  * switch to cache memory context
3819  */
3821 
3822  /*
3823  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3824  * the cache with pre-made descriptors for the critical shared catalogs.
3825  */
3826  if (!load_relcache_init_file(true))
3827  {
3828  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3829  Natts_pg_database, Desc_pg_database);
3830  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3831  Natts_pg_authid, Desc_pg_authid);
3832  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3833  Natts_pg_auth_members, Desc_pg_auth_members);
3834  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3835  Natts_pg_shseclabel, Desc_pg_shseclabel);
3836  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3837  Natts_pg_subscription, Desc_pg_subscription);
3838 
3839 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3840  }
3841 
3842  MemoryContextSwitchTo(oldcxt);
3843 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:114
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5615
void RelationMapInitializePhase2(void)
Definition: relmapper.c:604
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:113
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:117
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:116
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1816
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3860 of file relcache.c.

References AccessMethodProcedureIndexId, Assert, AttributeRelidNumIndexId, AuthIdOidIndexId, AuthIdRolnameIndexId, AuthMemMemRoleIndexId, CacheMemoryContext, CLASS_TUPLE_SIZE, ClassOidIndexId, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabaseNameIndexId, DatabaseOidIndexId, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ERROR, FATAL, formrdesc(), GETSTRUCT, hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, IndexRelidIndexId, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum, OpclassOidIndexId, pfree(), RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, RewriteRelRulenameIndexId, SearchSysCache1(), SharedSecLabelObjectIndexId, status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, TriggerRelidNameIndexId, and write_relcache_init_file().

Referenced by InitPostgres().

3861 {
3863  RelIdCacheEnt *idhentry;
3864  MemoryContext oldcxt;
3865  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3866 
3867  /*
3868  * relation mapper needs initialized too
3869  */
3871 
3872  /*
3873  * switch to cache memory context
3874  */
3876 
3877  /*
3878  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3879  * the cache with pre-made descriptors for the critical "nailed-in" system
3880  * catalogs.
3881  */
3882  if (IsBootstrapProcessingMode() ||
3883  !load_relcache_init_file(false))
3884  {
3885  needNewCacheFile = true;
3886 
3887  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3888  Natts_pg_class, Desc_pg_class);
3889  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3890  Natts_pg_attribute, Desc_pg_attribute);
3891  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3892  Natts_pg_proc, Desc_pg_proc);
3893  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3894  Natts_pg_type, Desc_pg_type);
3895 
3896 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3897  }
3898 
3899  MemoryContextSwitchTo(oldcxt);
3900 
3901  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3903  return;
3904 
3905  /*
3906  * If we didn't get the critical system indexes loaded into relcache, do
3907  * so now. These are critical because the catcache and/or opclass cache
3908  * depend on them for fetches done during relcache load. Thus, we have an
3909  * infinite-recursion problem. We can break the recursion by doing
3910  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3911  * performance, we only want to do that until we have the critical indexes
3912  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3913  * decide whether to do heapscan or indexscan at the key spots, and we set
3914  * it true after we've loaded the critical indexes.
3915  *
3916  * The critical indexes are marked as "nailed in cache", partly to make it
3917  * easy for load_relcache_init_file to count them, but mainly because we
3918  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3919  * true. (NOTE: perhaps it would be possible to reload them by
3920  * temporarily setting criticalRelcachesBuilt to false again. For now,
3921  * though, we just nail 'em in.)
3922  *
3923  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3924  * in the same way as the others, because the critical catalogs don't
3925  * (currently) have any rules or triggers, and so these indexes can be
3926  * rebuilt without inducing recursion. However they are used during
3927  * relcache load when a rel does have rules or triggers, so we choose to
3928  * nail them for performance reasons.
3929  */
3931  {
3933  RelationRelationId);
3935  AttributeRelationId);
3937  IndexRelationId);
3939  OperatorClassRelationId);
3941  AccessMethodProcedureRelationId);
3943  RewriteRelationId);
3945  TriggerRelationId);
3946 
3947 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3948 
3949  criticalRelcachesBuilt = true;
3950  }
3951 
3952  /*
3953  * Process critical shared indexes too.
3954  *
3955  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3956  * initial lookup of MyDatabaseId, without which we'll never find any
3957  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3958  * database OID, so it instead depends on DatabaseOidIndexId. We also
3959  * need to nail up some indexes on pg_authid and pg_auth_members for use
3960  * during client authentication. SharedSecLabelObjectIndexId isn't
3961  * critical for the core system, but authentication hooks might be
3962  * interested in it.
3963  */
3965  {
3967  DatabaseRelationId);
3969  DatabaseRelationId);
3971  AuthIdRelationId);
3973  AuthIdRelationId);
3975  AuthMemRelationId);
3977  SharedSecLabelRelationId);
3978 
3979 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3980 
3982  }
3983 
3984  /*
3985  * Now, scan all the relcache entries and update anything that might be
3986  * wrong in the results from formrdesc or the relcache cache file. If we
3987  * faked up relcache entries using formrdesc, then read the real pg_class
3988  * rows and replace the fake entries with them. Also, if any of the
3989  * relcache entries have rules, triggers, or security policies, load that
3990  * info the hard way since it isn't recorded in the cache file.
3991  *
3992  * Whenever we access the catalogs to read data, there is a possibility of
3993  * a shared-inval cache flush causing relcache entries to be removed.
3994  * Since hash_seq_search only guarantees to still work after the *current*
3995  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3996  * We handle this by restarting the scan from scratch after each access.
3997  * This is theoretically O(N^2), but the number of entries that actually
3998  * need to be fixed is small enough that it doesn't matter.
3999  */
4000  hash_seq_init(&status, RelationIdCache);
4001 
4002  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4003  {
4004  Relation relation = idhentry->reldesc;
4005  bool restart = false;
4006 
4007  /*
4008  * Make sure *this* entry doesn't get flushed while we work with it.
4009  */
4011 
4012  /*
4013  * If it's a faked-up entry, read the real pg_class tuple.
4014  */
4015  if (relation->rd_rel->relowner == InvalidOid)
4016  {
4017  HeapTuple htup;
4018  Form_pg_class relp;
4019 
4020  htup = SearchSysCache1(RELOID,
4021  ObjectIdGetDatum(RelationGetRelid(relation)));
4022  if (!HeapTupleIsValid(htup))
4023  elog(FATAL, "cache lookup failed for relation %u",
4024  RelationGetRelid(relation));
4025  relp = (Form_pg_class) GETSTRUCT(htup);
4026 
4027  /*
4028  * Copy tuple to relation->rd_rel. (See notes in
4029  * AllocateRelationDesc())
4030  */
4031  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4032 
4033  /* Update rd_options while we have the tuple */
4034  if (relation->rd_options)
4035  pfree(relation->rd_options);
4036  RelationParseRelOptions(relation, htup);
4037 
4038  /*
4039  * Check the values in rd_att were set up correctly. (We cannot
4040  * just copy them over now: formrdesc must have set up the rd_att
4041  * data correctly to start with, because it may already have been
4042  * copied into one or more catcache entries.)
4043  */
4044  Assert(relation->rd_att->tdtypeid == relp->reltype);
4045  Assert(relation->rd_att->tdtypmod == -1);
4046 
4047  ReleaseSysCache(htup);
4048 
4049  /* relowner had better be OK now, else we'll loop forever */
4050  if (relation->rd_rel->relowner == InvalidOid)
4051  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4052  RelationGetRelationName(relation));
4053 
4054  restart = true;
4055  }
4056 
4057  /*
4058  * Fix data that isn't saved in relcache cache file.
4059  *
4060  * relhasrules or relhastriggers could possibly be wrong or out of
4061  * date. If we don't actually find any rules or triggers, clear the
4062  * local copy of the flag so that we don't get into an infinite loop
4063  * here. We don't make any attempt to fix the pg_class entry, though.
4064  */
4065  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4066  {
4067  RelationBuildRuleLock(relation);
4068  if (relation->rd_rules == NULL)
4069  relation->rd_rel->relhasrules = false;
4070  restart = true;
4071  }
4072  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4073  {
4074  RelationBuildTriggers(relation);
4075  if (relation->trigdesc == NULL)
4076  relation->rd_rel->relhastriggers = false;
4077  restart = true;
4078  }
4079 
4080  /*
4081  * Re-load the row security policies if the relation has them, since
4082  * they are not preserved in the cache. Note that we can never NOT
4083  * have a policy while relrowsecurity is true,
4084  * RelationBuildRowSecurity will create a single default-deny policy
4085  * if there is no policy defined in pg_policy.
4086  */
4087  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4088  {
4089  RelationBuildRowSecurity(relation);
4090 
4091  Assert(relation->rd_rsdesc != NULL);
4092  restart = true;
4093  }
4094 
4095  /* Reload tableam data if needed */
4096  if (relation->rd_tableam == NULL &&
4097  (relation->rd_rel->relkind == RELKIND_RELATION ||
4098  relation->rd_rel->relkind == RELKIND_SEQUENCE ||
4099  relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
4100  relation->rd_rel->relkind == RELKIND_MATVIEW))
4101  {
4103  Assert(relation->rd_tableam != NULL);
4104 
4105  restart = true;
4106  }
4107 
4108  /* Release hold on the relation */
4110 
4111  /* Now, restart the hashtable scan if needed */
4112  if (restart)
4113  {
4114  hash_seq_term(&status);
4115  hash_seq_init(&status, RelationIdCache);
4116  }
4117  }
4118 
4119  /*
4120  * Lastly, write out new relcache cache files if needed. We don't bother
4121  * to distinguish cases where only one of the two needs an update.
4122  */
4123  if (needNewCacheFile)
4124  {
4125  /*
4126  * Force all the catcaches to finish initializing and thereby open the
4127  * catalogs and indexes they use. This will preload the relcache with
4128  * entries for all the most important system catalogs and indexes, so
4129  * that the init files will be most useful for future backends.
4130  */
4132 
4133  /* now write the files */
4135  write_relcache_init_file(false);
4136  }
4137 }
#define AttributeRelidNumIndexId
Definition: indexing.h:107
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5615
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define IndexRelidIndexId
Definition: indexing.h:179
#define RewriteRelRulenameIndexId
Definition: indexing.h:228
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:195
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1752
Relation reldesc
Definition: relcache.c:128
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:143
#define AuthIdOidIndexId
Definition: indexing.h:112
static HTAB * RelationIdCache
Definition: relcache.c:131
Form_pg_class rd_rel
Definition: rel.h:109
#define TriggerRelidNameIndexId
Definition: indexing.h:264
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2090
void pfree(void *pointer)
Definition: mcxt.c:1057
#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:6031
TriggerDesc * trigdesc
Definition: rel.h:115
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:440
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4146
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:110
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define DatabaseOidIndexId
Definition: indexing.h:157
#define ClassOidIndexId
Definition: indexing.h:125
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
#define AccessMethodProcedureIndexId
Definition: indexing.h:95
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2077
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
const struct TableAmRoutine * rd_tableam
Definition: rel.h:171
TupleDesc rd_att
Definition: rel.h:110
#define OpclassOidIndexId
Definition: indexing.h:208
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
#define AuthMemMemRoleIndexId
Definition: indexing.h:117
RuleLock * rd_rules
Definition: rel.h:113
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
#define DatabaseNameIndexId
Definition: indexing.h:155
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#define SharedSecLabelObjectIndexId
Definition: indexing.h:331
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
Oid tdtypeid
Definition: tupdesc.h:82
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1592
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1816
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:108
#define elog(elevel,...)
Definition: elog.h:214
void RelationMapInitializePhase3(void)
Definition: relmapper.c:625
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:735
bool criticalRelcachesBuilt
Definition: relcache.c:137
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define AuthIdRolnameIndexId
Definition: indexing.h:110
void InitCatalogCachePhase2(void)
Definition: syscache.c:1075
#define RelationGetRelid(relation)
Definition: rel.h:456
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:111
bytea * rd_options
Definition: rel.h:157
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1477
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:109
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2831 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_firstRelfilenodeSubid, RelationData::rd_isnailed, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCaches(), and LocalExecuteInvalidationMessage().

2832 {
2834  RelIdCacheEnt *idhentry;
2835  Relation relation;
2836  List *rebuildFirstList = NIL;
2837  List *rebuildList = NIL;
2838  ListCell *l;
2839 
2840  /*
2841  * Reload relation mapping data before starting to reconstruct cache.
2842  */
2844 
2845  /* Phase 1 */
2846  hash_seq_init(&status, RelationIdCache);
2847 
2848  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2849  {
2850  relation = idhentry->reldesc;
2851 
2852  /* Must close all smgr references to avoid leaving dangling ptrs */
2853  RelationCloseSmgr(relation);
2854 
2855  /*
2856  * Ignore new relations; no other backend will manipulate them before
2857  * we commit. Likewise, before replacing a relation's relfilenode, we
2858  * shall have acquired AccessExclusiveLock and drained any applicable
2859  * pending invalidations.
2860  */
2861  if (relation->rd_createSubid != InvalidSubTransactionId ||
2863  continue;
2864 
2866 
2867  if (RelationHasReferenceCountZero(relation))
2868  {
2869  /* Delete this entry immediately */
2870  Assert(!relation->rd_isnailed);
2871  RelationClearRelation(relation, false);
2872  }
2873  else
2874  {
2875  /*
2876  * If it's a mapped relation, immediately update its rd_node in
2877  * case its relfilenode changed. We must do this during phase 1
2878  * in case the relation is consulted during rebuild of other
2879  * relcache entries in phase 2. It's safe since consulting the
2880  * map doesn't involve any access to relcache entries.
2881  */
2882  if (RelationIsMapped(relation))
2883  RelationInitPhysicalAddr(relation);
2884 
2885  /*
2886  * Add this entry to list of stuff to rebuild in second pass.
2887  * pg_class goes to the front of rebuildFirstList while
2888  * pg_class_oid_index goes to the back of rebuildFirstList, so
2889  * they are done first and second respectively. Other nailed
2890  * relations go to the front of rebuildList, so they'll be done
2891  * next in no particular order; and everything else goes to the
2892  * back of rebuildList.
2893  */
2894  if (RelationGetRelid(relation) == RelationRelationId)
2895  rebuildFirstList = lcons(relation, rebuildFirstList);
2896  else if (RelationGetRelid(relation) == ClassOidIndexId)
2897  rebuildFirstList = lappend(rebuildFirstList, relation);
2898  else if (relation->rd_isnailed)
2899  rebuildList = lcons(relation, rebuildList);
2900  else
2901  rebuildList = lappend(rebuildList, relation);
2902  }
2903  }
2904 
2905  /*
2906  * Now zap any remaining smgr cache entries. This must happen before we
2907  * start to rebuild entries, since that may involve catalog fetches which
2908  * will re-open catalog files.
2909  */
2910  smgrcloseall();
2911 
2912  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2913  foreach(l, rebuildFirstList)
2914  {
2915  relation = (Relation) lfirst(l);
2916  RelationClearRelation(relation, true);
2917  }
2918  list_free(rebuildFirstList);
2919  foreach(l, rebuildList)
2920  {
2921  relation = (Relation) lfirst(l);
2922  RelationClearRelation(relation, true);
2923  }
2924  list_free(rebuildList);
2925 }
#define NIL
Definition: pg_list.h:65
static long relcacheInvalsReceived
Definition: relcache.c:151
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2431
bool rd_isnailed
Definition: rel.h:61
Relation reldesc
Definition: relcache.c:128
#define RelationCloseSmgr(relation)
Definition: rel.h:525
static HTAB * RelationIdCache
Definition: relcache.c:131
void smgrcloseall(void)
Definition: smgr.c:287
struct RelationData * Relation
Definition: relcache.h:27
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1266
#define ClassOidIndexId
Definition: indexing.h:125
List * lappend(List *list, void *datum)
Definition: list.c:321
#define RelationIsMapped(relation)
Definition: rel.h:505
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
List * lcons(void *datum, List *list)
Definition: list.c:453
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:526
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:440
void list_free(List *list)
Definition: list.c:1376
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:456

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2788 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2789 {
2790  Relation relation;
2791 
2792  RelationIdCacheLookup(relationId, relation);
2793 
2794  if (PointerIsValid(relation))
2795  {
2797  RelationFlushRelation(relation);
2798  }
2799 }
static long relcacheInvalsReceived
Definition: relcache.c:151
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:210
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2711
#define PointerIsValid(pointer)
Definition: c.h:639

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2431 of file relcache.c.

References Assert, CLASS_TUPLE_SIZE, elog, equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), InvalidSubTransactionId, IsTransactionState(), MemoryContextSetParent(), pfree(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_droppedSubid, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_partdesc, RelationData::rd_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().

2432 {
2433  /*
2434  * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of
2435  * course it would be an equally bad idea to blow away one with nonzero
2436  * refcnt, since that would leave someone somewhere with a dangling
2437  * pointer. All callers are expected to have verified that this holds.
2438  */
2439  Assert(rebuild ?
2440  !RelationHasReferenceCountZero(relation) :
2441  RelationHasReferenceCountZero(relation));
2442 
2443  /*
2444  * Make sure smgr and lower levels close the relation's files, if they
2445  * weren't closed already. If the relation is not getting deleted, the
2446  * next smgr access should reopen the files automatically. This ensures
2447  * that the low-level file access state is updated after, say, a vacuum
2448  * truncation.
2449  */
2450  RelationCloseSmgr(relation);
2451 
2452  /* Free AM cached data, if any */
2453  if (relation->rd_amcache)
2454  pfree(relation->rd_amcache);
2455  relation->rd_amcache = NULL;
2456 
2457  /*
2458  * Treat nailed-in system relations separately, they always need to be
2459  * accessible, so we can't blow them away.
2460  */
2461  if (relation->rd_isnailed)
2462  {
2463  RelationReloadNailed(relation);
2464  return;
2465  }
2466 
2467  /* Mark it invalid until we've finished rebuild */
2468  relation->rd_isvalid = false;
2469 
2470  /* See RelationForgetRelation(). */
2471  if (relation->rd_droppedSubid != InvalidSubTransactionId)
2472  return;
2473 
2474  /*
2475  * Even non-system indexes should not be blown away if they are open and
2476  * have valid index support information. This avoids problems with active
2477  * use of the index support information. As with nailed indexes, we
2478  * re-read the pg_class row to handle possible physical relocation of the
2479  * index, and we check for pg_index updates too.
2480  */
2481  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2482  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2483  relation->rd_refcnt > 0 &&
2484  relation->rd_indexcxt != NULL)
2485  {
2486  if (IsTransactionState())
2487  RelationReloadIndexInfo(relation);
2488  return;
2489  }
2490 
2491  /*
2492  * If we're really done with the relcache entry, blow it away. But if
2493  * someone is still using it, reconstruct the whole deal without moving
2494  * the physical RelationData record (so that the someone's pointer is
2495  * still valid).
2496  */
2497  if (!rebuild)
2498  {
2499  /* Remove it from the hash table */
2500  RelationCacheDelete(relation);
2501 
2502  /* And release storage */
2503  RelationDestroyRelation(relation, false);
2504  }
2505  else if (!IsTransactionState())
2506  {
2507  /*
2508  * If we're not inside a valid transaction, we can't do any catalog
2509  * access so it's not possible to rebuild yet. Just exit, leaving
2510  * rd_isvalid = false so that the rebuild will occur when the entry is
2511  * next opened.
2512  *
2513  * Note: it's possible that we come here during subtransaction abort,
2514  * and the reason for wanting to rebuild is that the rel is open in
2515  * the outer transaction. In that case it might seem unsafe to not
2516  * rebuild immediately, since whatever code has the rel already open
2517  * will keep on using the relcache entry as-is. However, in such a
2518  * case the outer transaction should be holding a lock that's
2519  * sufficient to prevent any significant change in the rel's schema,
2520  * so the existing entry contents should be good enough for its
2521  * purposes; at worst we might be behind on statistics updates or the
2522  * like. (See also CheckTableNotInUse() and its callers.) These same
2523  * remarks also apply to the cases above where we exit without having
2524  * done RelationReloadIndexInfo() yet.
2525  */
2526  return;
2527  }
2528  else
2529  {
2530  /*
2531  * Our strategy for rebuilding an open relcache entry is to build a
2532  * new entry from scratch, swap its contents with the old entry, and
2533  * finally delete the new entry (along with any infrastructure swapped
2534  * over from the old entry). This is to avoid trouble in case an
2535  * error causes us to lose control partway through. The old entry
2536  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2537  * on next access. Meanwhile it's not any less valid than it was
2538  * before, so any code that might expect to continue accessing it
2539  * isn't hurt by the rebuild failure. (Consider for example a
2540  * subtransaction that ALTERs a table and then gets canceled partway
2541  * through the cache entry rebuild. The outer transaction should
2542  * still see the not-modified cache entry as valid.) The worst
2543  * consequence of an error is leaking the necessarily-unreferenced new
2544  * entry, and this shouldn't happen often enough for that to be a big
2545  * problem.
2546  *
2547  * When rebuilding an open relcache entry, we must preserve ref count,
2548  * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2549  * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2550  * and partition descriptor substructures in place, because various
2551  * places assume that these structures won't move while they are
2552  * working with an open relcache entry. (Note: the refcount
2553  * mechanism for tupledescs might someday allow us to remove this hack
2554  * for the tupledesc.)
2555  *
2556  * Note that this process does not touch CurrentResourceOwner; which
2557  * is good because whatever ref counts the entry may have do not
2558  * necessarily belong to that resource owner.
2559  */
2560  Relation newrel;
2561  Oid save_relid = RelationGetRelid(relation);
2562  bool keep_tupdesc;
2563  bool keep_rules;
2564  bool keep_policies;
2565  bool keep_partkey;
2566 
2567  /* Build temporary entry, but don't link it into hashtable */
2568  newrel = RelationBuildDesc(save_relid, false);
2569  if (newrel == NULL)
2570  {
2571  /*
2572  * We can validly get here, if we're using a historic snapshot in
2573  * which a relation, accessed from outside logical decoding, is
2574  * still invisible. In that case it's fine to just mark the
2575  * relation as invalid and return - it'll fully get reloaded by
2576  * the cache reset at the end of logical decoding (or at the next
2577  * access). During normal processing we don't want to ignore this
2578  * case as it shouldn't happen there, as explained below.
2579  */
2580  if (HistoricSnapshotActive())
2581  return;
2582 
2583  /*
2584  * This shouldn't happen as dropping a relation is intended to be
2585  * impossible if still referenced (cf. CheckTableNotInUse()). But
2586  * if we get here anyway, we can't just delete the relcache entry,
2587  * as it possibly could get accessed later (as e.g. the error
2588  * might get trapped and handled via a subtransaction rollback).
2589  */
2590  elog(ERROR, "relation %u deleted while still in use", save_relid);
2591  }
2592 
2593  keep_tupdesc = equalTupleDescs(relation->