PostgreSQL Source Code  git master
relcache.c File Reference
#include "postgres.h"
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/nbtree.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "commands/policy.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
#include "optimizer/var.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/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 "utils/tqual.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 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 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, bool hasoids, 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 void RelationBuildPartitionKey (Relation relation)
 
static PartitionKey copy_partition_key (PartitionKey fromkey)
 
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 Listinsert_ordered_oid (List *list, Oid datum)
 
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)
 
static bool equalPartitionDescs (PartitionKey key, PartitionDesc partdesc1, PartitionDesc partdesc2)
 
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)
 
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 relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
 
void RelationCacheInitialize (void)
 
void RelationCacheInitializePhase2 (void)
 
void RelationCacheInitializePhase3 (void)
 
static TupleDesc BuildHardcodedDescriptor (int natts, const FormData_pg_attribute *attrs, bool hasoids)
 
ListRelationGetFKeyList (Relation relation)
 
ListRelationGetIndexList (Relation relation)
 
ListRelationGetStatExtList (Relation relation)
 
void RelationSetIndexList (Relation relation, List *indexIds, Oid oidIndex)
 
Oid RelationGetOidIndex (Relation relation)
 
Oid RelationGetPrimaryKeyIndex (Relation relation)
 
Oid RelationGetReplicaIndex (Relation relation)
 
ListRelationGetIndexExpressions (Relation relation)
 
ListRelationGetIndexPredicate (Relation relation)
 
BitmapsetRelationGetIndexAttrBitmap (Relation relation, IndexAttrBitmapKind attrKind)
 
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
 
struct PublicationActionsGetRelationPublicationActions (Relation relation)
 
int errtable (Relation rel)
 
int errtablecol (Relation rel, int attnum)
 
int errtablecolname (Relation rel, const char *colname)
 
int errtableconstraint (Relation rel, const char *conname)
 
bool RelationIdIsInInitFile (Oid relationId)
 
bool RelationHasUnloggedIndex (Relation rel)
 
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:151
static int eoxact_list_len
Definition: relcache.c:153

Definition at line 156 of file relcache.c.

Referenced by RelationBuildLocalRelation(), RelationSetIndexList(), and RelationSetNewRelfilenode().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3539 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

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

◆ 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:902
static HTAB * RelationIdCache
Definition: relcache.c:119
#define WARNING
Definition: elog.h:40

Definition at line 210 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:902
static HTAB * RelationIdCache
Definition: relcache.c:119
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:409
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:367

Definition at line 176 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:902
static HTAB * RelationIdCache
Definition: relcache.c:119

Definition at line 198 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 91 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

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 375 of file relcache.c.

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

Referenced by RelationBuildDesc().

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

◆ AtEOSubXact_cleanup()

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

Definition at line 3125 of file relcache.c.

References elog, InvalidOid, InvalidSubTransactionId, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_oidindex, RelationData::rd_pkindex, RelationData::rd_replidindex, RelationClearRelation(), RelationGetRelationName, RelationHasReferenceCountZero, and WARNING.

Referenced by AtEOSubXact_RelationCache().

3127 {
3128  /*
3129  * Is it a relation created in the current subtransaction?
3130  *
3131  * During subcommit, mark it as belonging to the parent, instead. During
3132  * subabort, simply delete the relcache entry.
3133  */
3134  if (relation->rd_createSubid == mySubid)
3135  {
3136  if (isCommit)
3137  relation->rd_createSubid = parentSubid;
3138  else if (RelationHasReferenceCountZero(relation))
3139  {
3140  RelationClearRelation(relation, false);
3141  return;
3142  }
3143  else
3144  {
3145  /*
3146  * Hmm, somewhere there's a (leaked?) reference to the relation.
3147  * We daren't remove the entry for fear of dereferencing a
3148  * dangling pointer later. Bleat, and transfer it to the parent
3149  * subtransaction so we can try again later. This must be just a
3150  * WARNING to avoid error-during-error-recovery loops.
3151  */
3152  relation->rd_createSubid = parentSubid;
3153  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3154  RelationGetRelationName(relation));
3155  }
3156  }
3157 
3158  /*
3159  * Likewise, update or drop any new-relfilenode-in-subtransaction hint.
3160  */
3161  if (relation->rd_newRelfilenodeSubid == mySubid)
3162  {
3163  if (isCommit)
3164  relation->rd_newRelfilenodeSubid = parentSubid;
3165  else
3167  }
3168 
3169  /*
3170  * Flush any temporary index list.
3171  */
3172  if (relation->rd_indexvalid == 2)
3173  {
3174  list_free(relation->rd_indexlist);
3175  relation->rd_indexlist = NIL;
3176  relation->rd_oidindex = InvalidOid;
3177  relation->rd_pkindex = InvalidOid;
3178  relation->rd_replidindex = InvalidOid;
3179  relation->rd_indexvalid = 0;
3180  }
3181 }
#define NIL
Definition: pg_list.h:69
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2399
Oid rd_replidindex
Definition: rel.h:138
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:111
Oid rd_pkindex
Definition: rel.h:137
char rd_indexvalid
Definition: rel.h:93
#define RelationGetRelationName(relation)
Definition: rel.h:445
Oid rd_oidindex
Definition: rel.h:136
List * rd_indexlist
Definition: rel.h:135
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define InvalidSubTransactionId
Definition: c.h:451
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:409
void list_free(List *list)
Definition: list.c:1133
#define elog
Definition: elog.h:219

◆ AtEOSubXact_RelationCache()

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

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

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

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 2990 of file relcache.c.

References Assert, elog, InvalidOid, InvalidSubTransactionId, IsBootstrapProcessingMode, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_isnailed, RelationData::rd_newRelfilenodeSubid, RelationData::rd_oidindex, RelationData::rd_pkindex, RelationData::rd_refcnt, RelationData::rd_replidindex, RelationClearRelation(), RelationGetRelationName, RelationHasReferenceCountZero, and WARNING.

Referenced by AtEOXact_RelationCache().

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

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

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

2928 {
2930  RelIdCacheEnt *idhentry;
2931  int i;
2932 
2933  /*
2934  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2935  * listed in it. Otherwise fall back on a hash_seq_search scan.
2936  *
2937  * For simplicity, eoxact_list[] entries are not deleted till end of
2938  * top-level transaction, even though we could remove them at
2939  * subtransaction end in some cases, or remove relations from the list if
2940  * they are cleared for other reasons. Therefore we should expect the
2941  * case that list entries are not found in the hashtable; if not, there's
2942  * nothing to do for them.
2943  */
2945  {
2946  hash_seq_init(&status, RelationIdCache);
2947  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2948  {
2949  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2950  }
2951  }
2952  else
2953  {
2954  for (i = 0; i < eoxact_list_len; i++)
2955  {
2956  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2957  (void *) &eoxact_list[i],
2958  HASH_FIND,
2959  NULL);
2960  if (idhentry != NULL)
2961  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2962  }
2963  }
2964 
2965  if (EOXactTupleDescArrayLen > 0)
2966  {
2967  Assert(EOXactTupleDescArray != NULL);
2968  for (i = 0; i < NextEOXactTupleDescNum; i++)
2971  EOXactTupleDescArray = NULL;
2972  }
2973 
2974  /* Now we're out of the transaction and can clear the lists */
2975  eoxact_list_len = 0;
2976  eoxact_list_overflowed = false;
2977  NextEOXactTupleDescNum = 0;
2979 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:152
static int EOXactTupleDescArrayLen
Definition: relcache.c:171
Relation reldesc
Definition: relcache.c:116
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
static HTAB * RelationIdCache
Definition: relcache.c:119
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:2990
static bool eoxact_list_overflowed
Definition: relcache.c:154
static int NextEOXactTupleDescNum
Definition: relcache.c:170
void pfree(void *pointer)
Definition: mcxt.c:949
#define Assert(condition)
Definition: c.h:670
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1385
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1375
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:251
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static int eoxact_list_len
Definition: relcache.c:153
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:169

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

Definition at line 4029 of file relcache.c.

References AccessShareLock, attrDefault::adbin, attrDefault::adnum, Anum_pg_attrdef_adbin, Anum_pg_attrdef_adrelid, AttrDefaultIndexId, AttrDefaultRelationId, BTEqualStrategyNumber, CacheMemoryContext, tupleDesc::constr, tupleConstr::defval, elog, fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, i, MemoryContextStrdup(), NameStr, tupleConstr::num_defval, ObjectIdGetDatum, pfree(), RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, TupleDescAttr, val, and WARNING.

Referenced by RelationBuildTupleDesc().

4030 {
4031  AttrDefault *attrdef = relation->rd_att->constr->defval;
4032  int ndef = relation->rd_att->constr->num_defval;
4033  Relation adrel;
4034  SysScanDesc adscan;
4035  ScanKeyData skey;
4036  HeapTuple htup;
4037  Datum val;
4038  bool isnull;
4039  int found;
4040  int i;
4041 
4042  ScanKeyInit(&skey,
4044  BTEqualStrategyNumber, F_OIDEQ,
4045  ObjectIdGetDatum(RelationGetRelid(relation)));
4046 
4048  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4049  NULL, 1, &skey);
4050  found = 0;
4051 
4052  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4053  {
4054  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4055  Form_pg_attribute attr = TupleDescAttr(relation->rd_att, adform->adnum - 1);
4056 
4057  for (i = 0; i < ndef; i++)
4058  {
4059  if (adform->adnum != attrdef[i].adnum)
4060  continue;
4061  if (attrdef[i].adbin != NULL)
4062  elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
4063  NameStr(attr->attname),
4064  RelationGetRelationName(relation));
4065  else
4066  found++;
4067 
4068  val = fastgetattr(htup,
4070  adrel->rd_att, &isnull);
4071  if (isnull)
4072  elog(WARNING, "null adbin for attr %s of rel %s",
4073  NameStr(attr->attname),
4074  RelationGetRelationName(relation));
4075  else
4076  {
4077  /* detoast and convert to cstring in caller's context */
4078  char *s = TextDatumGetCString(val);
4079 
4081  pfree(s);
4082  }
4083  break;
4084  }
4085 
4086  if (i >= ndef)
4087  elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
4088  adform->adnum, RelationGetRelationName(relation));
4089  }
4090 
4091  systable_endscan(adscan);
4092  heap_close(adrel, AccessShareLock);
4093 
4094  if (found != ndef)
4095  elog(WARNING, "%d attrdef record(s) missing for rel %s",
4096  ndef - found, RelationGetRelationName(relation));
4097 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:724
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define AccessShareLock
Definition: lockdefs.h:36
#define Anum_pg_attrdef_adbin
Definition: pg_attrdef.h:56
#define heap_close(r, l)
Definition: heapam.h:97
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:949
AttrDefault * defval
Definition: tupdesc.h:39
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define AttrDefaultIndexId
Definition: indexing.h:87
AttrNumber adnum
Definition: tupdesc.h:24
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
char * adbin
Definition: tupdesc.h:25
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:47
#define WARNING
Definition: elog.h:40
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
#define Anum_pg_attrdef_adrelid
Definition: pg_attrdef.h:54
uint16 num_defval
Definition: tupdesc.h:41
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
TupleConstr * constr
Definition: tupdesc.h:84
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1063
int i
#define NameStr(name)
Definition: c.h:547
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define AttrDefaultRelationId
Definition: pg_attrdef.h:29
#define RelationGetRelid(relation)
Definition: rel.h:425
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ BuildHardcodedDescriptor()

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

Definition at line 3967 of file relcache.c.

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

3969 {
3970  TupleDesc result;
3971  MemoryContext oldcxt;
3972  int i;
3973 
3975 
3976  result = CreateTemplateTupleDesc(natts, hasoids);
3977  result->tdtypeid = RECORDOID; /* not right, but we don't care */
3978  result->tdtypmod = -1;
3979 
3980  for (i = 0; i < natts; i++)
3981  {
3982  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
3983  /* make sure attcacheoff is valid */
3984  TupleDescAttr(result, i)->attcacheoff = -1;
3985  }
3986 
3987  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
3988  TupleDescAttr(result, 0)->attcacheoff = 0;
3989 
3990  /* Note: we don't bother to set up a TupleConstr entry */
3991 
3992  MemoryContextSwitchTo(oldcxt);
3993 
3994  return result;
3995 }
Oid tdtypeid
Definition: tupdesc.h:80
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int32 tdtypmod
Definition: tupdesc.h:81
#define RECORDOID
Definition: pg_type.h:680
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:179
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:43
int i
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ CheckConstraintCmp()

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

Definition at line 4174 of file relcache.c.

References constrCheck::ccname.

Referenced by CheckConstraintFetch().

4175 {
4176  const ConstrCheck *ca = (const ConstrCheck *) a;
4177  const ConstrCheck *cb = (const ConstrCheck *) b;
4178 
4179  return strcmp(ca->ccname, cb->ccname);
4180 }
char * ccname
Definition: tupdesc.h:30

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4103 of file relcache.c.

References AccessShareLock, Anum_pg_constraint_conbin, Anum_pg_constraint_conrelid, BTEqualStrategyNumber, CacheMemoryContext, constrCheck::ccbin, constrCheck::ccname, constrCheck::ccnoinherit, constrCheck::ccvalid, tupleConstr::check, CheckConstraintCmp(), tupleDesc::constr, CONSTRAINT_CHECK, ConstraintRelationId, ConstraintRelidIndexId, elog, ERROR, fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, MemoryContextStrdup(), NameStr, tupleConstr::num_check, ObjectIdGetDatum, pfree(), qsort, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, and val.

Referenced by RelationBuildTupleDesc().

4104 {
4105  ConstrCheck *check = relation->rd_att->constr->check;
4106  int ncheck = relation->rd_att->constr->num_check;
4107  Relation conrel;
4108  SysScanDesc conscan;
4109  ScanKeyData skey[1];
4110  HeapTuple htup;
4111  int found = 0;
4112 
4113  ScanKeyInit(&skey[0],
4115  BTEqualStrategyNumber, F_OIDEQ,
4116  ObjectIdGetDatum(RelationGetRelid(relation)));
4117 
4119  conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
4120  NULL, 1, skey);
4121 
4122  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4123  {
4125  Datum val;
4126  bool isnull;
4127  char *s;
4128 
4129  /* We want check constraints only */
4130  if (conform->contype != CONSTRAINT_CHECK)
4131  continue;
4132 
4133  if (found >= ncheck)
4134  elog(ERROR, "unexpected constraint record found for rel %s",
4135  RelationGetRelationName(relation));
4136 
4137  check[found].ccvalid = conform->convalidated;
4138  check[found].ccnoinherit = conform->connoinherit;
4140  NameStr(conform->conname));
4141 
4142  /* Grab and test conbin is actually set */
4143  val = fastgetattr(htup,
4145  conrel->rd_att, &isnull);
4146  if (isnull)
4147  elog(ERROR, "null conbin for rel %s",
4148  RelationGetRelationName(relation));
4149 
4150  /* detoast and convert to cstring in caller's context */
4151  s = TextDatumGetCString(val);
4152  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4153  pfree(s);
4154 
4155  found++;
4156  }
4157 
4158  systable_endscan(conscan);
4159  heap_close(conrel, AccessShareLock);
4160 
4161  if (found != ncheck)
4162  elog(ERROR, "%d constraint record(s) missing for rel %s",
4163  ncheck - found, RelationGetRelationName(relation));
4164 
4165  /* Sort the records so that CHECKs are applied in a deterministic order */
4166  if (ncheck > 1)
4167  qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
4168 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:724
char * ccname
Definition: tupdesc.h:30
bool ccnoinherit
Definition: tupdesc.h:33
ConstrCheck * check
Definition: tupdesc.h:40
char * ccbin
Definition: tupdesc.h:31
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4174
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_constraint_conbin
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define CONSTRAINT_CHECK
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
TupleConstr * constr
Definition: tupdesc.h:84
bool ccvalid
Definition: tupdesc.h:32
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1063
#define NameStr(name)
Definition: c.h:547
#define Anum_pg_constraint_conrelid
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
uint16 num_check
Definition: tupdesc.h:42
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:408
#define RelationGetRelid(relation)
Definition: rel.h:425
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ConstraintRelidIndexId
Definition: indexing.h:126
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ copy_partition_key()

static PartitionKey copy_partition_key ( PartitionKey  fromkey)
static

Definition at line 1002 of file relcache.c.

References copyObject, palloc(), PartitionKeyData::partattrs, PartitionKeyData::partcollation, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::partopcintype, PartitionKeyData::partopfamily, PartitionKeyData::partsupfunc, PartitionKeyData::parttypalign, PartitionKeyData::parttypbyval, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttyplen, PartitionKeyData::parttypmod, and PartitionKeyData::strategy.

Referenced by RelationBuildPartitionKey().

1003 {
1004  PartitionKey newkey;
1005  int n;
1006 
1007  newkey = (PartitionKey) palloc(sizeof(PartitionKeyData));
1008 
1009  newkey->strategy = fromkey->strategy;
1010  newkey->partnatts = n = fromkey->partnatts;
1011 
1012  newkey->partattrs = (AttrNumber *) palloc(n * sizeof(AttrNumber));
1013  memcpy(newkey->partattrs, fromkey->partattrs, n * sizeof(AttrNumber));
1014 
1015  newkey->partexprs = copyObject(fromkey->partexprs);
1016 
1017  newkey->partopfamily = (Oid *) palloc(n * sizeof(Oid));
1018  memcpy(newkey->partopfamily, fromkey->partopfamily, n * sizeof(Oid));
1019 
1020  newkey->partopcintype = (Oid *) palloc(n * sizeof(Oid));
1021  memcpy(newkey->partopcintype, fromkey->partopcintype, n * sizeof(Oid));
1022 
1023  newkey->partsupfunc = (FmgrInfo *) palloc(n * sizeof(FmgrInfo));
1024  memcpy(newkey->partsupfunc, fromkey->partsupfunc, n * sizeof(FmgrInfo));
1025 
1026  newkey->partcollation = (Oid *) palloc(n * sizeof(Oid));
1027  memcpy(newkey->partcollation, fromkey->partcollation, n * sizeof(Oid));
1028 
1029  newkey->parttypid = (Oid *) palloc(n * sizeof(Oid));
1030  memcpy(newkey->parttypid, fromkey->parttypid, n * sizeof(Oid));
1031 
1032  newkey->parttypmod = (int32 *) palloc(n * sizeof(int32));
1033  memcpy(newkey->parttypmod, fromkey->parttypmod, n * sizeof(int32));
1034 
1035  newkey->parttyplen = (int16 *) palloc(n * sizeof(int16));
1036  memcpy(newkey->parttyplen, fromkey->parttyplen, n * sizeof(int16));
1037 
1038  newkey->parttypbyval = (bool *) palloc(n * sizeof(bool));
1039  memcpy(newkey->parttypbyval, fromkey->parttypbyval, n * sizeof(bool));
1040 
1041  newkey->parttypalign = (char *) palloc(n * sizeof(bool));
1042  memcpy(newkey->parttypalign, fromkey->parttypalign, n * sizeof(char));
1043 
1044  newkey->parttypcoll = (Oid *) palloc(n * sizeof(Oid));
1045  memcpy(newkey->parttypcoll, fromkey->parttypcoll, n * sizeof(Oid));
1046 
1047  return newkey;
1048 }
signed short int16
Definition: c.h:283
Definition: fmgr.h:56
Oid * partopfamily
Definition: rel.h:61
FmgrInfo * partsupfunc
Definition: rel.h:63
List * partexprs
Definition: rel.h:58
char strategy
Definition: rel.h:54
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:284
Oid * parttypcoll
Definition: rel.h:74
Oid * parttypid
Definition: rel.h:69
Oid * partcollation
Definition: rel.h:66
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
char * parttypalign
Definition: rel.h:73
int32 * parttypmod
Definition: rel.h:70
bool * parttypbyval
Definition: rel.h:72
int16 * parttyplen
Definition: rel.h:71
void * palloc(Size size)
Definition: mcxt.c:848
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
Oid * partopcintype
Definition: rel.h:62
#define copyObject(obj)
Definition: nodes.h:625
int16 AttrNumber
Definition: attnum.h:21

◆ equalPartitionDescs()

static bool equalPartitionDescs ( PartitionKey  key,
PartitionDesc  partdesc1,
PartitionDesc  partdesc2 
)
static

Definition at line 1182 of file relcache.c.

References Assert, PartitionDescData::boundinfo, i, PartitionDescData::nparts, PartitionDescData::oids, partition_bounds_equal(), PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, and PartitionKeyData::parttyplen.

Referenced by RelationClearRelation().

1184 {
1185  int i;
1186 
1187  if (partdesc1 != NULL)
1188  {
1189  if (partdesc2 == NULL)
1190  return false;
1191  if (partdesc1->nparts != partdesc2->nparts)
1192  return false;
1193 
1194  Assert(key != NULL || partdesc1->nparts == 0);
1195 
1196  /*
1197  * Same oids? If the partitioning structure did not change, that is,
1198  * no partitions were added or removed to the relation, the oids array
1199  * should still match element-by-element.
1200  */
1201  for (i = 0; i < partdesc1->nparts; i++)
1202  {
1203  if (partdesc1->oids[i] != partdesc2->oids[i])
1204  return false;
1205  }
1206 
1207  /*
1208  * Now compare partition bound collections. The logic to iterate over
1209  * the collections is private to partition.c.
1210  */
1211  if (partdesc1->boundinfo != NULL)
1212  {
1213  if (partdesc2->boundinfo == NULL)
1214  return false;
1215 
1217  key->parttypbyval,
1218  partdesc1->boundinfo,
1219  partdesc2->boundinfo))
1220  return false;
1221  }
1222  else if (partdesc2->boundinfo != NULL)
1223  return false;
1224  }
1225  else if (partdesc2 != NULL)
1226  return false;
1227 
1228  return true;
1229 }
bool partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partition.c:742
PartitionBoundInfo boundinfo
Definition: partition.h:40
int16 partnatts
Definition: rel.h:55
bool * parttypbyval
Definition: rel.h:72
#define Assert(condition)
Definition: c.h:670
int16 * parttyplen
Definition: rel.h:71
int i

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

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

1104 {
1105  int i;
1106  Oid *r1,
1107  *r2;
1108 
1109  if (policy1 != NULL)
1110  {
1111  if (policy2 == NULL)
1112  return false;
1113 
1114  if (policy1->polcmd != policy2->polcmd)
1115  return false;
1116  if (policy1->hassublinks != policy2->hassublinks)
1117  return false;
1118  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
1119  return false;
1120  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
1121  return false;
1122 
1123  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
1124  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
1125 
1126  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
1127  {
1128  if (r1[i] != r2[i])
1129  return false;
1130  }
1131 
1132  if (!equal(policy1->qual, policy2->qual))
1133  return false;
1134  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
1135  return false;
1136  }
1137  else if (policy2 != NULL)
1138  return false;
1139 
1140  return true;
1141 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2984
unsigned int Oid
Definition: postgres_ext.h:31
#define ARR_DIMS(a)
Definition: array.h:279
#define ARR_DATA_PTR(a)
Definition: array.h:307
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 1149 of file relcache.c.

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

Referenced by RelationClearRelation().

1150 {
1151  ListCell *lc,
1152  *rc;
1153 
1154  if (rsdesc1 == NULL && rsdesc2 == NULL)
1155  return true;
1156 
1157  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1158  (rsdesc1 == NULL && rsdesc2 != NULL))
1159  return false;
1160 
1161  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1162  return false;
1163 
1164  /* RelationBuildRowSecurity should build policies in order */
1165  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1166  {
1169 
1170  if (!equalPolicy(l, r))
1171  return false;
1172  }
1173 
1174  return true;
1175 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:1103
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

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

1059 {
1060  int i;
1061 
1062  /*
1063  * As of 7.3 we assume the rule ordering is repeatable, because
1064  * RelationBuildRuleLock should read 'em in a consistent order. So just
1065  * compare corresponding slots.
1066  */
1067  if (rlock1 != NULL)
1068  {
1069  if (rlock2 == NULL)
1070  return false;
1071  if (rlock1->numLocks != rlock2->numLocks)
1072  return false;
1073  for (i = 0; i < rlock1->numLocks; i++)
1074  {
1075  RewriteRule *rule1 = rlock1->rules[i];
1076  RewriteRule *rule2 = rlock2->rules[i];
1077 
1078  if (rule1->ruleId != rule2->ruleId)
1079  return false;
1080  if (rule1->event != rule2->event)
1081  return false;
1082  if (rule1->enabled != rule2->enabled)
1083  return false;
1084  if (rule1->isInstead != rule2->isInstead)
1085  return false;
1086  if (!equal(rule1->qual, rule2->qual))
1087  return false;
1088  if (!equal(rule1->actions, rule2->actions))
1089  return false;
1090  }
1091  }
1092  else if (rlock2 != NULL)
1093  return false;
1094  return true;
1095 }
Node * qual
Definition: prs2lock.h:28
int numLocks
Definition: prs2lock.h:42
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2984
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 5258 of file relcache.c.

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

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

5259 {
5263 
5264  return 0; /* return value does not matter */
5265 }
#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:3066
#define RelationGetRelationName(relation)
Definition: rel.h:445
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5275 of file relcache.c.

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

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

5276 {
5277  TupleDesc reldesc = RelationGetDescr(rel);
5278  const char *colname;
5279 
5280  /* Use reldesc if it's a user attribute, else consult the catalogs */
5281  if (attnum > 0 && attnum <= reldesc->natts)
5282  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5283  else
5284  colname = get_relid_attribute_name(RelationGetRelid(rel), attnum);
5285 
5286  return errtablecolname(rel, colname);
5287 }
#define RelationGetDescr(relation)
Definition: rel.h:437
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
char * get_relid_attribute_name(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:801
#define NameStr(name)
Definition: c.h:547
#define RelationGetRelid(relation)
Definition: rel.h:425
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5299

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5299 of file relcache.c.

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

Referenced by errtablecol().

5300 {
5301  errtable(rel);
5303 
5304  return 0; /* return value does not matter */
5305 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
int errtable(Relation rel)
Definition: relcache.c:5258

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

Definition at line 5312 of file relcache.c.

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

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

5313 {
5314  errtable(rel);
5316 
5317  return 0; /* return value does not matter */
5318 }
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
int errtable(Relation rel)
Definition: relcache.c:5258

◆ formrdesc()

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

Definition at line 1898 of file relcache.c.

References ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateTemplateTupleDesc(), GLOBALTABLESPACE_OID, tupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), palloc0(), PG_CATALOG_NAMESPACE, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), RELKIND_RELATION, RELPERSISTENCE_PERMANENT, REPLICA_IDENTITY_NOTHING, tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, and TupleDescAttr.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

1901 {
1902  Relation relation;
1903  int i;
1904  bool has_not_null;
1905 
1906  /*
1907  * allocate new relation desc, clear all fields of reldesc
1908  */
1909  relation = (Relation) palloc0(sizeof(RelationData));
1910 
1911  /* make sure relation is marked as having no open file yet */
1912  relation->rd_smgr = NULL;
1913 
1914  /*
1915  * initialize reference count: 1 because it is nailed in cache
1916  */
1917  relation->rd_refcnt = 1;
1918 
1919  /*
1920  * all entries built with this routine are nailed-in-cache; none are for
1921  * new or temp relations.
1922  */
1923  relation->rd_isnailed = true;
1926  relation->rd_backend = InvalidBackendId;
1927  relation->rd_islocaltemp = false;
1928 
1929  /*
1930  * initialize relation tuple form
1931  *
1932  * The data we insert here is pretty incomplete/bogus, but it'll serve to
1933  * get us launched. RelationCacheInitializePhase3() will read the real
1934  * data from pg_class and replace what we've done here. Note in
1935  * particular that relowner is left as zero; this cues
1936  * RelationCacheInitializePhase3 that the real data isn't there yet.
1937  */
1939 
1940  namestrcpy(&relation->rd_rel->relname, relationName);
1941  relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1942  relation->rd_rel->reltype = relationReltype;
1943 
1944  /*
1945  * It's important to distinguish between shared and non-shared relations,
1946  * even at bootstrap time, to make sure we know where they are stored.
1947  */
1948  relation->rd_rel->relisshared = isshared;
1949  if (isshared)
1950  relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1951 
1952  /* formrdesc is used only for permanent relations */
1953  relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1954 
1955  /* ... and they're always populated, too */
1956  relation->rd_rel->relispopulated = true;
1957 
1958  relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1959  relation->rd_rel->relpages = 0;
1960  relation->rd_rel->reltuples = 0;
1961  relation->rd_rel->relallvisible = 0;
1962  relation->rd_rel->relkind = RELKIND_RELATION;
1963  relation->rd_rel->relhasoids = hasoids;
1964  relation->rd_rel->relnatts = (int16) natts;
1965 
1966  /*
1967  * initialize attribute tuple form
1968  *
1969  * Unlike the case with the relation tuple, this data had better be right
1970  * because it will never be replaced. The data comes from
1971  * src/include/catalog/ headers via genbki.pl.
1972  */
1973  relation->rd_att = CreateTemplateTupleDesc(natts, hasoids);
1974  relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1975 
1976  relation->rd_att->tdtypeid = relationReltype;
1977  relation->rd_att->tdtypmod = -1; /* unnecessary, but... */
1978 
1979  /*
1980  * initialize tuple desc info
1981  */
1982  has_not_null = false;
1983  for (i = 0; i < natts; i++)
1984  {
1985  memcpy(TupleDescAttr(relation->rd_att, i),
1986  &attrs[i],
1988  has_not_null |= attrs[i].attnotnull;
1989  /* make sure attcacheoff is valid */
1990  TupleDescAttr(relation->rd_att, i)->attcacheoff = -1;
1991  }
1992 
1993  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
1994  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
1995 
1996  /* mark not-null status */
1997  if (has_not_null)
1998  {
1999  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
2000 
2001  constr->has_not_null = true;
2002  relation->rd_att->constr = constr;
2003  }
2004 
2005  /*
2006  * initialize relation id from info in att array (my, this is ugly)
2007  */
2008  RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
2009 
2010  /*
2011  * All relations made with formrdesc are mapped. This is necessarily so
2012  * because there is no other way to know what filenode they currently
2013  * have. In bootstrap mode, add them to the initial relation mapper data,
2014  * specifying that the initial filenode is the same as the OID.
2015  */
2016  relation->rd_rel->relfilenode = InvalidOid;
2019  RelationGetRelid(relation),
2020  isshared, true);
2021 
2022  /*
2023  * initialize the relation lock manager information
2024  */
2025  RelationInitLockInfo(relation); /* see lmgr.c */
2026 
2027  /*
2028  * initialize physical addressing information for the relation
2029  */
2030  RelationInitPhysicalAddr(relation);
2031 
2032  /*
2033  * initialize the rel-has-index flag, using hardwired knowledge
2034  */
2036  {
2037  /* In bootstrap mode, we have no indexes */
2038  relation->rd_rel->relhasindex = false;
2039  }
2040  else
2041  {
2042  /* Otherwise, all the rels formrdesc is used for have indexes */
2043  relation->rd_rel->relhasindex = true;
2044  }
2045 
2046  /*
2047  * add new reldesc to relcache
2048  */
2049  RelationCacheInsert(relation, false);
2050 
2051  /* It's fully valid */
2052  relation->rd_isvalid = true;
2053 }
signed short int16
Definition: c.h:283
Oid tdtypeid
Definition: tupdesc.h:80
#define REPLICA_IDENTITY_NOTHING
Definition: pg_class.h:177
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
struct SMgrRelationData * rd_smgr
Definition: rel.h:87
bool rd_isnailed
Definition: rel.h:91
bool rd_islocaltemp
Definition: rel.h:90
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
bool rd_isvalid
Definition: rel.h:92
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:111
Form_pg_class rd_rel
Definition: rel.h:114
int namestrcpy(Name name, const char *str)
Definition: name.c:216
int32 tdtypmod
Definition: tupdesc.h:81
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1429
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define PG_CATALOG_NAMESPACE
Definition: pg_namespace.h:71
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:179
bool has_not_null
Definition: tupdesc.h:43
SubTransactionId rd_createSubid
Definition: rel.h:110
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:877
TupleDesc rd_att
Definition: rel.h:115
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:176
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:87
BackendId rd_backend
Definition: rel.h:89
TupleConstr * constr
Definition: tupdesc.h:84
#define InvalidSubTransactionId
Definition: c.h:451
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:43
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:367
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
int rd_refcnt
Definition: rel.h:88
int tdrefcount
Definition: tupdesc.h:83
int i
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:425
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 3998 of file relcache.c.

References BuildHardcodedDescriptor(), Desc_pg_class, and Natts_pg_class.

Referenced by RelationParseRelOptions().

3999 {
4000  static TupleDesc pgclassdesc = NULL;
4001 
4002  /* Already done? */
4003  if (pgclassdesc == NULL)
4005  Desc_pg_class,
4006  true);
4007 
4008  return pgclassdesc;
4009 }
#define Natts_pg_class
Definition: pg_class.h:102
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, bool hasoids)
Definition: relcache.c:3967
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:96

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4012 of file relcache.c.

References BuildHardcodedDescriptor(), Desc_pg_index, and Natts_pg_index.

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

4013 {
4014  static TupleDesc pgindexdesc = NULL;
4015 
4016  /* Already done? */
4017  if (pgindexdesc == NULL)
4019  Desc_pg_index,
4020  false);
4021 
4022  return pgindexdesc;
4023 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, bool hasoids)
Definition: relcache.c:3967
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:103
#define Natts_pg_index
Definition: pg_index.h:73

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5187 of file relcache.c.

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

Referenced by CheckCmdReplicaIdentity().

5188 {
5189  List *puboids;
5190  ListCell *lc;
5191  MemoryContext oldcxt;
5192  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5193 
5194  if (relation->rd_pubactions)
5195  return memcpy(pubactions, relation->rd_pubactions,
5196  sizeof(PublicationActions));
5197 
5198  /* Fetch the publication membership info. */
5199  puboids = GetRelationPublications(RelationGetRelid(relation));
5200  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5201 
5202  foreach(lc, puboids)
5203  {
5204  Oid pubid = lfirst_oid(lc);
5205  HeapTuple tup;
5206  Form_pg_publication pubform;
5207 
5209 
5210  if (!HeapTupleIsValid(tup))
5211  elog(ERROR, "cache lookup failed for publication %u", pubid);
5212 
5213  pubform = (Form_pg_publication) GETSTRUCT(tup);
5214 
5215  pubactions->pubinsert |= pubform->pubinsert;
5216  pubactions->pubupdate |= pubform->pubupdate;
5217  pubactions->pubdelete |= pubform->pubdelete;
5218 
5219  ReleaseSysCache(tup);
5220 
5221  /*
5222  * If we know everything is replicated, there is no point to check for
5223  * other publications.
5224  */
5225  if (pubactions->pubinsert && pubactions->pubupdate &&
5226  pubactions->pubdelete)
5227  break;
5228  }
5229 
5230  if (relation->rd_pubactions)
5231  {
5232  pfree(relation->rd_pubactions);
5233  relation->rd_pubactions = NULL;
5234  }
5235 
5236  /* Now save copy of the actions in the relcache entry. */
5238  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5239  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5240  MemoryContextSwitchTo(oldcxt);
5241 
5242  return pubactions;
5243 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
PublicationActions * rd_pubactions
Definition: rel.h:149
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * list_concat_unique_oid(List *list1, List *list2)
Definition: list.c:1082
List * GetRelationPublications(Oid relid)
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void * palloc0(Size size)
Definition: mcxt.c:877
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:848
#define elog
Definition: elog.h:219
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ IndexSupportInitialize()

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

Definition at line 1679 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

1685 {
1686  int attIndex;
1687 
1688  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1689  {
1690  OpClassCacheEnt *opcentry;
1691 
1692  if (!OidIsValid(indclass->values[attIndex]))
1693  elog(ERROR, "bogus pg_index tuple");
1694 
1695  /* look up the info for this opclass, using a cache */
1696  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1697  maxSupportNumber);
1698 
1699  /* copy cached data into relcache entry */
1700  opFamily[attIndex] = opcentry->opcfamily;
1701  opcInType[attIndex] = opcentry->opcintype;
1702  if (maxSupportNumber > 0)
1703  memcpy(&indexSupport[attIndex * maxSupportNumber],
1704  opcentry->supportProcs,
1705  maxSupportNumber * sizeof(RegProcedure));
1706  }
1707 }
regproc RegProcedure
Definition: c.h:443
#define OidIsValid(objectId)
Definition: c.h:576
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:235
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1730
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:534
#define elog
Definition: elog.h:219

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1492 of file relcache.c.

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

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

1493 {
1494  IndexAmRoutine *cached,
1495  *tmp;
1496 
1497  /*
1498  * Call the amhandler in current, short-lived memory context, just in case
1499  * it leaks anything (it probably won't, but let's be paranoid).
1500  */
1501  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1502 
1503  /* OK, now transfer the data into relation's rd_indexcxt. */
1504  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1505  sizeof(IndexAmRoutine));
1506  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1507  relation->rd_amroutine = cached;
1508 
1509  pfree(tmp);
1510 }
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:181
void pfree(void *pointer)
Definition: mcxt.c:949
Oid rd_amhandler
Definition: rel.h:178
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
MemoryContext rd_indexcxt
Definition: rel.h:179

◆ insert_ordered_oid()

static List * insert_ordered_oid ( List list,
Oid  datum 
)
static

Definition at line 4566 of file relcache.c.

References lappend_cell_oid(), lcons_oid(), lfirst_oid, linitial_oid, sort-test::list, list_head(), lnext, and NIL.

Referenced by RelationGetIndexList(), and RelationGetStatExtList().

4567 {
4568  ListCell *prev;
4569 
4570  /* Does the datum belong at the front? */
4571  if (list == NIL || datum < linitial_oid(list))
4572  return lcons_oid(datum, list);
4573  /* No, so find the entry it belongs after */
4574  prev = list_head(list);
4575  for (;;)
4576  {
4577  ListCell *curr = lnext(prev);
4578 
4579  if (curr == NULL || datum < lfirst_oid(curr))
4580  break; /* it belongs after 'prev', before 'curr' */
4581 
4582  prev = curr;
4583  }
4584  /* Insert datum into list after 'prev' */
4585  lappend_cell_oid(list, prev, datum);
4586  return list;
4587 }
#define NIL
Definition: pg_list.h:69
List * lcons_oid(Oid datum, List *list)
Definition: list.c:295
ListCell * lappend_cell_oid(List *list, ListCell *prev, Oid datum)
Definition: list.c:235
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
#define linitial_oid(l)
Definition: pg_list.h:113
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 3933 of file relcache.c.

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

Referenced by RelationCacheInitializePhase3().

3934 {
3935  Relation ird;
3936 
3937  /*
3938  * We must lock the underlying catalog before locking the index to avoid
3939  * deadlock, since RelationBuildDesc might well need to read the catalog,
3940  * and if anyone else is exclusive-locking this catalog and index they'll
3941  * be doing it in that order.
3942  */
3943  LockRelationOid(heapoid, AccessShareLock);
3944  LockRelationOid(indexoid, AccessShareLock);
3945  ird = RelationBuildDesc(indexoid, true);
3946  if (ird == NULL)
3947  elog(PANIC, "could not open critical system index %u", indexoid);
3948  ird->rd_isnailed = true;
3949  ird->rd_refcnt = 1;
3952 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
bool rd_isnailed
Definition: rel.h:91
#define AccessShareLock
Definition: lockdefs.h:36
#define PANIC
Definition: elog.h:53
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1244
int rd_refcnt
Definition: rel.h:88
#define elog
Definition: elog.h:219
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 5376 of file relcache.c.

References AllocateFile(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), IndexAmRoutine::amsupport, Assert, ATTRIBUTE_FIXED_PART_SIZE, CacheMemoryContext, tupleDesc::constr, CreateTemplateTupleDesc(), criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabasePath, elog, FreeFile(), GETSTRUCT, tupleConstr::has_not_null, HEAPTUPLESIZE, i, InitIndexAmRoutine(), InvalidOid, InvalidSubTransactionId, MAXPGPATH, MemoryContextAlloc(), MemoryContextAllocZero(), 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_amroutine, RelationData::rd_att, RelationData::rd_createSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_idattr, RelationData::rd_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_oidindex, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_partcheck, 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(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, RELKIND_INDEX, repalloc(), snprintf(), HeapTupleData::t_data, tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, TupleDescAttr, VARSIZE, and WARNING.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

5377 {
5378  FILE *fp;
5379  char initfilename[MAXPGPATH];
5380  Relation *rels;
5381  int relno,
5382  num_rels,
5383  max_rels,
5384  nailed_rels,
5385  nailed_indexes,
5386  magic;
5387  int i;
5388 
5389  if (shared)
5390  snprintf(initfilename, sizeof(initfilename), "global/%s",
5392  else
5393  snprintf(initfilename, sizeof(initfilename), "%s/%s",
5395 
5396  fp = AllocateFile(initfilename, PG_BINARY_R);
5397  if (fp == NULL)
5398  return false;
5399 
5400  /*
5401  * Read the index relcache entries from the file. Note we will not enter
5402  * any of them into the cache if the read fails partway through; this
5403  * helps to guard against broken init files.
5404  */
5405  max_rels = 100;
5406  rels = (Relation *) palloc(max_rels * sizeof(Relation));
5407  num_rels = 0;
5408  nailed_rels = nailed_indexes = 0;
5409 
5410  /* check for correct magic number (compatible version) */
5411  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
5412  goto read_failed;
5413  if (magic != RELCACHE_INIT_FILEMAGIC)
5414  goto read_failed;
5415 
5416  for (relno = 0;; relno++)
5417  {
5418  Size len;
5419  size_t nread;
5420  Relation rel;
5421  Form_pg_class relform;
5422  bool has_not_null;
5423 
5424  /* first read the relation descriptor length */
5425  nread = fread(&len, 1, sizeof(len), fp);
5426  if (nread != sizeof(len))
5427  {
5428  if (nread == 0)
5429  break; /* end of file */
5430  goto read_failed;
5431  }
5432 
5433  /* safety check for incompatible relcache layout */
5434  if (len != sizeof(RelationData))
5435  goto read_failed;
5436 
5437  /* allocate another relcache header */
5438  if (num_rels >= max_rels)
5439  {
5440  max_rels *= 2;
5441  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
5442  }
5443 
5444  rel = rels[num_rels++] = (Relation) palloc(len);
5445 
5446  /* then, read the Relation structure */
5447  if (fread(rel, 1, len, fp) != len)
5448  goto read_failed;
5449 
5450  /* next read the relation tuple form */
5451  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5452  goto read_failed;
5453 
5454  relform = (Form_pg_class) palloc(len);
5455  if (fread(relform, 1, len, fp) != len)
5456  goto read_failed;
5457 
5458  rel->rd_rel = relform;
5459 
5460  /* initialize attribute tuple forms */
5461  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts,
5462  relform->relhasoids);
5463  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
5464 
5465  rel->rd_att->tdtypeid = relform->reltype;
5466  rel->rd_att->tdtypmod = -1; /* unnecessary, but... */
5467 
5468  /* next read all the attribute tuple form data entries */
5469  has_not_null = false;
5470  for (i = 0; i < relform->relnatts; i++)
5471  {
5472  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
5473 
5474  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5475  goto read_failed;
5476  if (len != ATTRIBUTE_FIXED_PART_SIZE)
5477  goto read_failed;
5478  if (fread(attr, 1, len, fp) != len)
5479  goto read_failed;
5480 
5481  has_not_null |= attr->attnotnull;
5482  }
5483 
5484  /* next read the access method specific field */
5485  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5486  goto read_failed;
5487  if (len > 0)
5488  {
5489  rel->rd_options = palloc(len);
5490  if (fread(rel->rd_options, 1, len, fp) != len)
5491  goto read_failed;
5492  if (len != VARSIZE(rel->rd_options))
5493  goto read_failed; /* sanity check */
5494  }
5495  else
5496  {
5497  rel->rd_options = NULL;
5498  }
5499 
5500  /* mark not-null status */
5501  if (has_not_null)
5502  {
5503  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
5504 
5505  constr->has_not_null = true;
5506  rel->rd_att->constr = constr;
5507  }
5508 
5509  /* If it's an index, there's more to do */
5510  if (rel->rd_rel->relkind == RELKIND_INDEX)
5511  {
5512  MemoryContext indexcxt;
5513  Oid *opfamily;
5514  Oid *opcintype;
5515  RegProcedure *support;
5516  int nsupport;
5517  int16 *indoption;
5518  Oid *indcollation;
5519 
5520  /* Count nailed indexes to ensure we have 'em all */
5521  if (rel->rd_isnailed)
5522  nailed_indexes++;
5523 
5524  /* next, read the pg_index tuple */
5525  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5526  goto read_failed;
5527 
5528  rel->rd_indextuple = (HeapTuple) palloc(len);
5529  if (fread(rel->rd_indextuple, 1, len, fp) != len)
5530  goto read_failed;
5531 
5532  /* Fix up internal pointers in the tuple -- see heap_copytuple */
5533  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
5535 
5536  /*
5537  * prepare index info context --- parameters should match
5538  * RelationInitIndexAccessInfo
5539  */
5543  rel->rd_indexcxt = indexcxt;
5544 
5545  /*
5546  * Now we can fetch the index AM's API struct. (We can't store
5547  * that in the init file, since it contains function pointers that
5548  * might vary across server executions. Fortunately, it should be
5549  * safe to call the amhandler even while bootstrapping indexes.)
5550  */
5551  InitIndexAmRoutine(rel);
5552 
5553  /* next, read the vector of opfamily OIDs */
5554  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5555  goto read_failed;
5556 
5557  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
5558  if (fread(opfamily, 1, len, fp) != len)
5559  goto read_failed;
5560 
5561  rel->rd_opfamily = opfamily;
5562 
5563  /* next, read the vector of opcintype OIDs */
5564  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5565  goto read_failed;
5566 
5567  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
5568  if (fread(opcintype, 1, len, fp) != len)
5569  goto read_failed;
5570 
5571  rel->rd_opcintype = opcintype;
5572 
5573  /* next, read the vector of support procedure OIDs */
5574  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5575  goto read_failed;
5576  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
5577  if (fread(support, 1, len, fp) != len)
5578  goto read_failed;
5579 
5580  rel->rd_support = support;
5581 
5582  /* next, read the vector of collation OIDs */
5583  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5584  goto read_failed;
5585 
5586  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
5587  if (fread(indcollation, 1, len, fp) != len)
5588  goto read_failed;
5589 
5590  rel->rd_indcollation = indcollation;
5591 
5592  /* finally, read the vector of indoption values */
5593  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
5594  goto read_failed;
5595 
5596  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
5597  if (fread(indoption, 1, len, fp) != len)
5598  goto read_failed;
5599 
5600  rel->rd_indoption = indoption;
5601 
5602  /* set up zeroed fmgr-info vector */
5603  nsupport = relform->relnatts * rel->rd_amroutine->amsupport;
5604  rel->rd_supportinfo = (FmgrInfo *)
5605  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
5606  }
5607  else
5608  {
5609  /* Count nailed rels to ensure we have 'em all */
5610  if (rel->rd_isnailed)
5611  nailed_rels++;
5612 
5613  Assert(rel->rd_index == NULL);
5614  Assert(rel->rd_indextuple == NULL);
5615  Assert(rel->rd_indexcxt == NULL);
5616  Assert(rel->rd_amroutine == NULL);
5617  Assert(rel->rd_opfamily == NULL);
5618  Assert(rel->rd_opcintype == NULL);
5619  Assert(rel->rd_support == NULL);
5620  Assert(rel->rd_supportinfo == NULL);
5621  Assert(rel->rd_indoption == NULL);
5622  Assert(rel->rd_indcollation == NULL);
5623  }
5624 
5625  /*
5626  * Rules and triggers are not saved (mainly because the internal
5627  * format is complex and subject to change). They must be rebuilt if
5628  * needed by RelationCacheInitializePhase3. This is not expected to
5629  * be a big performance hit since few system catalogs have such. Ditto
5630  * for RLS policy data, index expressions, predicates, exclusion info,
5631  * and FDW info.
5632  */
5633  rel->rd_rules = NULL;
5634  rel->rd_rulescxt = NULL;
5635  rel->trigdesc = NULL;
5636  rel->rd_rsdesc = NULL;
5637  rel->rd_partkeycxt = NULL;
5638  rel->rd_partkey = NULL;
5639  rel->rd_pdcxt = NULL;
5640  rel->rd_partdesc = NULL;
5641  rel->rd_partcheck = NIL;
5642  rel->rd_indexprs = NIL;
5643  rel->rd_indpred = NIL;
5644  rel->rd_exclops = NULL;
5645  rel->rd_exclprocs = NULL;
5646  rel->rd_exclstrats = NULL;
5647  rel->rd_fdwroutine = NULL;
5648 
5649  /*
5650  * Reset transient-state fields in the relcache entry
5651  */
5652  rel->rd_smgr = NULL;
5653  if (rel->rd_isnailed)
5654  rel->rd_refcnt = 1;
5655  else
5656  rel->rd_refcnt = 0;
5657  rel->rd_indexvalid = 0;
5658  rel->rd_fkeylist = NIL;
5659  rel->rd_fkeyvalid = false;
5660  rel->rd_indexlist = NIL;
5661  rel->rd_oidindex = InvalidOid;
5662  rel->rd_pkindex = InvalidOid;
5663  rel->rd_replidindex = InvalidOid;
5664  rel->rd_indexattr = NULL;
5665  rel->rd_keyattr = NULL;
5666  rel->rd_pkattr = NULL;
5667  rel->rd_idattr = NULL;
5668  rel->rd_pubactions = NULL;
5669  rel->rd_statvalid = false;
5670  rel->rd_statlist = NIL;
5673  rel->rd_amcache = NULL;
5674  MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
5675 
5676  /*
5677  * Recompute lock and physical addressing info. This is needed in
5678  * case the pg_internal.init file was copied from some other database
5679  * by CREATE DATABASE.
5680  */
5681  RelationInitLockInfo(rel);
5683  }
5684 
5685  /*
5686  * We reached the end of the init file without apparent problem. Did we
5687  * get the right number of nailed items? This is a useful crosscheck in
5688  * case the set of critical rels or indexes changes. However, that should
5689  * not happen in a normally-running system, so let's bleat if it does.
5690  *
5691  * For the shared init file, we're called before client authentication is
5692  * done, which means that elog(WARNING) will go only to the postmaster
5693  * log, where it's easily missed. To ensure that developers notice bad
5694  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
5695  * an Assert(false) there.
5696  */
5697  if (shared)
5698  {
5699  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
5700  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
5701  {
5702  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
5703  nailed_rels, nailed_indexes,
5705  /* Make sure we get developers' attention about this */
5706  Assert(false);
5707  /* In production builds, recover by bootstrapping the relcache */
5708  goto read_failed;
5709  }
5710  }
5711  else
5712  {
5713  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
5714  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
5715  {
5716  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
5717  nailed_rels, nailed_indexes,
5719  /* We don't need an Assert() in this case */
5720  goto read_failed;
5721  }
5722  }
5723 
5724  /*
5725  * OK, all appears well.
5726  *
5727  * Now insert all the new relcache entries into the cache.
5728  */
5729  for (relno = 0; relno < num_rels; relno++)
5730  {
5731  RelationCacheInsert(rels[relno], false);
5732  }
5733 
5734  pfree(rels);
5735  FreeFile(fp);
5736 
5737  if (shared)
5739  else
5740  criticalRelcachesBuilt = true;
5741  return true;
5742 
5743  /*
5744  * init file is broken, so do it the hard way. We don't bother trying to
5745  * free the clutter we just allocated; it's not in the relcache so it
5746  * won't hurt.
5747  */
5748 read_failed:
5749  pfree(rels);
5750  FreeFile(fp);
5751 
5752  return false;
5753 }
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:204
signed short int16
Definition: c.h:283
#define NIL
Definition: pg_list.h:69
Definition: fmgr.h:56
struct PartitionDescData * rd_partdesc
Definition: rel.h:131
uint16 amsupport
Definition: amapi.h:169
HeapTupleData * HeapTuple
Definition: htup.h:70
Oid tdtypeid
Definition: tupdesc.h:80
int16 * rd_indoption
Definition: rel.h:186
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
PublicationActions * rd_pubactions
Definition: rel.h:149
FmgrInfo * rd_supportinfo
Definition: rel.h:185
Bitmapset * rd_keyattr
Definition: rel.h:145
#define VARSIZE(PTR)
Definition: postgres.h:304
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
Oid rd_replidindex
Definition: rel.h:138
struct SMgrRelationData * rd_smgr
Definition: rel.h:87
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:180
bool rd_isnailed
Definition: rel.h:91
regproc RegProcedure
Definition: c.h:443
uint16 * rd_exclstrats
Definition: rel.h:191
#define NUM_CRITICAL_LOCAL_INDEXES
List * rd_indexprs
Definition: rel.h:187
List * rd_fkeylist
Definition: rel.h:125
#define MemSet(start, val, len)
Definition: c.h:853
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:111
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
MemoryContext rd_rulescxt
Definition: rel.h:119
bool criticalSharedRelcachesBuilt
Definition: relcache.c:131
Oid * rd_exclprocs
Definition: rel.h:190
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define NUM_CRITICAL_SHARED_INDEXES
#define PG_BINARY_R
Definition: c.h:1027
#define NUM_CRITICAL_SHARED_RELS
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:181
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1492
int32 tdtypmod
Definition: tupdesc.h:81
struct HeapTupleData * rd_indextuple
Definition: rel.h:161
HeapTupleHeader t_data
Definition: htup.h:67
struct RelationData * Relation
Definition: relcache.h:26
Form_pg_index rd_index
Definition: rel.h:159
void pfree(void *pointer)
Definition: mcxt.c:949
#define NUM_CRITICAL_LOCAL_RELS
Oid * rd_indcollation
Definition: rel.h:193
Oid rd_pkindex
Definition: rel.h:137
struct PartitionKeyData * rd_partkey
Definition: rel.h:129
#define MAXPGPATH
TriggerDesc * trigdesc
Definition: rel.h:120
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1429
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
char rd_indexvalid
Definition: rel.h:93
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2342
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:91
#define RelationGetRelationName(relation)
Definition: rel.h:445
List * rd_indpred
Definition: rel.h:188
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
Oid rd_oidindex
Definition: rel.h:136
Oid * rd_opfamily
Definition: rel.h:182
Oid * rd_exclops
Definition: rel.h:189
List * rd_indexlist
Definition: rel.h:135
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:179
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:122
RegProcedure * rd_support
Definition: rel.h:184
bool has_not_null
Definition: tupdesc.h:43
#define WARNING
Definition: elog.h:40
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
SubTransactionId rd_createSubid
Definition: rel.h:110
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:342
void * palloc0(Size size)
Definition: mcxt.c:877
TupleDesc rd_att
Definition: rel.h:115
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
#define InvalidOid
Definition: postgres_ext.h:36
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
Bitmapset * rd_idattr
Definition: rel.h:147
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:176
char * DatabasePath
Definition: globals.c:85
MemoryContext rd_pdcxt
Definition: rel.h:130
#define Assert(condition)
Definition: c.h:670
MemoryContext rd_partkeycxt
Definition: rel.h:128
RuleLock * rd_rules
Definition: rel.h:118
TupleConstr * constr
Definition: tupdesc.h:84
size_t Size
Definition: c.h:404
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:218
#define InvalidSubTransactionId
Definition: c.h:451
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:43
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
int FreeFile(FILE *file)
Definition: fd.c:2534
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
Bitmapset * rd_pkattr
Definition: rel.h:146
bool rd_statvalid
Definition: rel.h:95
void * palloc(Size size)
Definition: mcxt.c:848
int rd_refcnt
Definition: rel.h:88
#define HEAPTUPLESIZE
Definition: htup.h:72
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
int tdrefcount
Definition: tupdesc.h:83
MemoryContext rd_indexcxt
Definition: rel.h:179
int i
#define RELKIND_INDEX
Definition: pg_class.h:161
#define elog
Definition: elog.h:219
bool criticalRelcachesBuilt
Definition: relcache.c:125
void * rd_amcache
Definition: rel.h:192
Oid * rd_opcintype
Definition: rel.h:183
List * rd_statlist
Definition: rel.h:141
bool rd_fkeyvalid
Definition: rel.h:126
List * rd_partcheck
Definition: rel.h:132
Bitmapset * rd_indexattr
Definition: rel.h:144
bytea * rd_options
Definition: rel.h:156
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ LookupOpclassInfo()

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

Definition at line 1730 of file relcache.c.

References AccessMethodProcedureIndexId, AccessMethodProcedureRelationId, AccessShareLock, Anum_pg_amproc_amprocfamily, Anum_pg_amproc_amproclefttype, Anum_pg_amproc_amprocrighttype, Assert, BTEqualStrategyNumber, CacheMemoryContext, CreateCacheMemoryContext(), criticalRelcachesBuilt, elog, HASHCTL::entrysize, ERROR, GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), heap_close, heap_open(), HeapTupleIsValid, INT2_BTREE_OPS_OID, HASHCTL::keysize, MemoryContextAllocZero(), MemSet, opclasscacheent::numSupport, ObjectIdAttributeNumber, ObjectIdGetDatum, OID_BTREE_OPS_OID, opclasscacheent::opcfamily, opclasscacheent::opcintype, OpclassOidIndexId, OperatorClassRelationId, ScanKeyInit(), opclasscacheent::supportProcs, systable_beginscan(), systable_endscan(), systable_getnext(), and opclasscacheent::valid.

Referenced by IndexSupportInitialize().

1732 {
1733  OpClassCacheEnt *opcentry;
1734  bool found;
1735  Relation rel;
1736  SysScanDesc scan;
1737  ScanKeyData skey[3];
1738  HeapTuple htup;
1739  bool indexOK;
1740 
1741  if (OpClassCache == NULL)
1742  {
1743  /* First time through: initialize the opclass cache */
1744  HASHCTL ctl;
1745 
1746  MemSet(&ctl, 0, sizeof(ctl));
1747  ctl.keysize = sizeof(Oid);
1748  ctl.entrysize = sizeof(OpClassCacheEnt);
1749  OpClassCache = hash_create("Operator class cache", 64,
1750  &ctl, HASH_ELEM | HASH_BLOBS);
1751 
1752  /* Also make sure CacheMemoryContext exists */
1753  if (!CacheMemoryContext)
1755  }
1756 
1757  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1758  (void *) &operatorClassOid,
1759  HASH_ENTER, &found);
1760 
1761  if (!found)
1762  {
1763  /* Need to allocate memory for new entry */
1764  opcentry->valid = false; /* until known OK */
1765  opcentry->numSupport = numSupport;
1766 
1767  if (numSupport > 0)
1768  opcentry->supportProcs = (RegProcedure *)
1770  numSupport * sizeof(RegProcedure));
1771  else
1772  opcentry->supportProcs = NULL;
1773  }
1774  else
1775  {
1776  Assert(numSupport == opcentry->numSupport);
1777  }
1778 
1779  /*
1780  * When testing for cache-flush hazards, we intentionally disable the
1781  * operator class cache and force reloading of the info on each call. This
1782  * is helpful because we want to test the case where a cache flush occurs
1783  * while we are loading the info, and it's very hard to provoke that if
1784  * this happens only once per opclass per backend.
1785  */
1786 #if defined(CLOBBER_CACHE_ALWAYS)
1787  opcentry->valid = false;
1788 #endif
1789 
1790  if (opcentry->valid)
1791  return opcentry;
1792 
1793  /*
1794  * Need to fill in new entry.
1795  *
1796  * To avoid infinite recursion during startup, force heap scans if we're
1797  * looking up info for the opclasses used by the indexes we would like to
1798  * reference here.
1799  */
1800  indexOK = criticalRelcachesBuilt ||
1801  (operatorClassOid != OID_BTREE_OPS_OID &&
1802  operatorClassOid != INT2_BTREE_OPS_OID);
1803 
1804  /*
1805  * We have to fetch the pg_opclass row to determine its opfamily and
1806  * opcintype, which are needed to look up related operators and functions.
1807  * It'd be convenient to use the syscache here, but that probably doesn't
1808  * work while bootstrapping.
1809  */
1810  ScanKeyInit(&skey[0],
1812  BTEqualStrategyNumber, F_OIDEQ,
1813  ObjectIdGetDatum(operatorClassOid));
1815  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1816  NULL, 1, skey);
1817 
1818  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1819  {
1820  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1821 
1822  opcentry->opcfamily = opclassform->opcfamily;
1823  opcentry->opcintype = opclassform->opcintype;
1824  }
1825  else
1826  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1827 
1828  systable_endscan(scan);
1830 
1831  /*
1832  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1833  * the default ones (those with lefttype = righttype = opcintype).
1834  */
1835  if (numSupport > 0)
1836  {
1837  ScanKeyInit(&skey[0],
1839  BTEqualStrategyNumber, F_OIDEQ,
1840  ObjectIdGetDatum(opcentry->opcfamily));
1841  ScanKeyInit(&skey[1],
1843  BTEqualStrategyNumber, F_OIDEQ,
1844  ObjectIdGetDatum(opcentry->opcintype));
1845  ScanKeyInit(&skey[2],
1847  BTEqualStrategyNumber, F_OIDEQ,
1848  ObjectIdGetDatum(opcentry->opcintype));
1850  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1851  NULL, 3, skey);
1852 
1853  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1854  {
1855  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1856 
1857  if (amprocform->amprocnum <= 0 ||
1858  (StrategyNumber) amprocform->amprocnum > numSupport)
1859  elog(ERROR, "invalid amproc number %d for opclass %u",
1860  amprocform->amprocnum, operatorClassOid);
1861 
1862  opcentry->supportProcs[amprocform->amprocnum - 1] =
1863  amprocform->amproc;
1864  }
1865 
1866  systable_endscan(scan);
1868  }
1869 
1870  opcentry->valid = true;
1871  return opcentry;
1872 }
struct opclasscacheent OpClassCacheEnt
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define INT2_BTREE_OPS_OID
Definition: pg_opclass.h:118
#define HASH_ELEM
Definition: hsearch.h:87
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
regproc RegProcedure
Definition: c.h:443
#define AccessShareLock
Definition: lockdefs.h:36
#define OperatorClassRelationId
Definition: pg_opclass.h:49
Size entrysize
Definition: hsearch.h:73
uint16 StrategyNumber
Definition: stratnum.h:22
#define MemSet(start, val, len)
Definition: c.h:853
#define OID_BTREE_OPS_OID
Definition: pg_opclass.h:145
#define heap_close(r, l)
Definition: heapam.h:97
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
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:328
StrategyNumber numSupport
Definition: relcache.c:232
#define Anum_pg_amproc_amproclefttype
Definition: pg_amproc.h:67
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
RegProcedure * supportProcs
Definition: relcache.c:235
#define Anum_pg_amproc_amprocfamily
Definition: pg_amproc.h:66
static HTAB * OpClassCache
Definition: relcache.c:238
#define Anum_pg_amproc_amprocrighttype
Definition: pg_amproc.h:68
#define HASH_BLOBS
Definition: hsearch.h:88
#define AccessMethodProcedureIndexId
Definition: indexing.h:82
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
Size keysize
Definition: hsearch.h:72
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
#define OpclassOidIndexId
Definition: indexing.h:200
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
bool criticalRelcachesBuilt
Definition: relcache.c:125
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
#define AccessMethodProcedureRelationId
Definition: pg_amproc.h:43
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1244 of file relcache.c.

References AllocateRelationDesc(), Assert, BackendIdForTempRelations, elog, ERROR, GETSTRUCT, GetTempNamespaceBackendId(), heap_freetuple(), HeapTupleGetOid, HeapTupleIsValid, InvalidBackendId, InvalidSubTransactionId, isTempOrTempToastNamespace(), NIL, OidIsValid, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationParseRelOptions(), RELKIND_PARTITIONED_TABLE, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, ScanPgRelation(), and RelationData::trigdesc.

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

1245 {
1246  Relation relation;
1247  Oid relid;
1248  HeapTuple pg_class_tuple;
1249  Form_pg_class relp;
1250 
1251  /*
1252  * find the tuple in pg_class corresponding to the given relation id
1253  */
1254  pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1255 
1256  /*
1257  * if no such tuple exists, return NULL
1258  */
1259  if (!HeapTupleIsValid(pg_class_tuple))
1260  return NULL;
1261 
1262  /*
1263  * get information from the pg_class_tuple
1264  */
1265  relid = HeapTupleGetOid(pg_class_tuple);
1266  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1267  Assert(relid == targetRelId);
1268 
1269  /*
1270  * allocate storage for the relation descriptor, and copy pg_class_tuple
1271  * to relation->rd_rel.
1272  */
1273  relation = AllocateRelationDesc(relp);
1274 
1275  /*
1276  * initialize the relation's relation id (relation->rd_id)
1277  */
1278  RelationGetRelid(relation) = relid;
1279 
1280  /*
1281  * normal relations are not nailed into the cache; nor can a pre-existing
1282  * relation be new. It could be temp though. (Actually, it could be new
1283  * too, but it's okay to forget that fact if forced to flush the entry.)
1284  */
1285  relation->rd_refcnt = 0;
1286  relation->rd_isnailed = false;
1289  switch (relation->rd_rel->relpersistence)
1290  {
1293  relation->rd_backend = InvalidBackendId;
1294  relation->rd_islocaltemp = false;
1295  break;
1296  case RELPERSISTENCE_TEMP:
1297  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1298  {
1299  relation->rd_backend = BackendIdForTempRelations();
1300  relation->rd_islocaltemp = true;
1301  }
1302  else
1303  {
1304  /*
1305  * If it's a temp table, but not one of ours, we have to use
1306  * the slow, grotty method to figure out the owning backend.
1307  *
1308  * Note: it's possible that rd_backend gets set to MyBackendId
1309  * here, in case we are looking at a pg_class entry left over
1310  * from a crashed backend that coincidentally had the same
1311  * BackendId we're using. We should *not* consider such a
1312  * table to be "ours"; this is why we need the separate
1313  * rd_islocaltemp flag. The pg_class entry will get flushed
1314  * if/when we clean out the corresponding temp table namespace
1315  * in preparation for using it.
1316  */
1317  relation->rd_backend =
1318  GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
1319  Assert(relation->rd_backend != InvalidBackendId);
1320  relation->rd_islocaltemp = false;
1321  }
1322  break;
1323  default:
1324  elog(ERROR, "invalid relpersistence: %c",
1325  relation->rd_rel->relpersistence);
1326  break;
1327  }
1328 
1329  /*
1330  * initialize the tuple descriptor (relation->rd_att).
1331  */
1332  RelationBuildTupleDesc(relation);
1333 
1334  /*
1335  * Fetch rules and triggers that affect this relation
1336  */
1337  if (relation->rd_rel->relhasrules)
1338  RelationBuildRuleLock(relation);
1339  else
1340  {
1341  relation->rd_rules = NULL;
1342  relation->rd_rulescxt = NULL;
1343  }
1344 
1345  if (relation->rd_rel->relhastriggers)
1346  RelationBuildTriggers(relation);
1347  else
1348  relation->trigdesc = NULL;
1349 
1350  if (relation->rd_rel->relrowsecurity)
1351  RelationBuildRowSecurity(relation);
1352  else
1353  relation->rd_rsdesc = NULL;
1354 
1355  /* foreign key data is not loaded till asked for */
1356  relation->rd_fkeylist = NIL;
1357  relation->rd_fkeyvalid = false;
1358 
1359  /* if a partitioned table, initialize key and partition descriptor info */
1360  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1361  {
1362  RelationBuildPartitionKey(relation);
1363  RelationBuildPartitionDesc(relation);
1364  }
1365  else
1366  {
1367  relation->rd_partkeycxt = NULL;
1368  relation->rd_partkey = NULL;
1369  relation->rd_partdesc = NULL;
1370  relation->rd_pdcxt = NULL;
1371  }
1372 
1373  /*
1374  * if it's an index, initialize index-related information
1375  */
1376  if (OidIsValid(relation->rd_rel->relam))
1377  RelationInitIndexAccessInfo(relation);
1378 
1379  /* extract reloptions if any */
1380  RelationParseRelOptions(relation, pg_class_tuple);
1381 
1382  /*
1383  * initialize the relation lock manager information
1384  */
1385  RelationInitLockInfo(relation); /* see lmgr.c */
1386 
1387  /*
1388  * initialize physical addressing information for the relation
1389  */
1390  RelationInitPhysicalAddr(relation);
1391 
1392  /* make sure relation is marked as having no open file yet */
1393  relation->rd_smgr = NULL;
1394 
1395  /*
1396  * now we can free the memory allocated for pg_class_tuple
1397  */
1398  heap_freetuple(pg_class_tuple);
1399 
1400  /*
1401  * Insert newly created relation into relcache hash table, if requested.
1402  *
1403  * There is one scenario in which we might find a hashtable entry already
1404  * present, even though our caller failed to find it: if the relation is a
1405  * system catalog or index that's used during relcache load, we might have
1406  * recursively created the same relcache entry during the preceding steps.
1407  * So allow RelationCacheInsert to delete any already-present relcache
1408  * entry for the same OID. The already-present entry should have refcount
1409  * zero (else somebody forgot to close it); in the event that it doesn't,
1410  * we'll elog a WARNING and leak the already-present entry.
1411  */
1412  if (insertIt)
1413  RelationCacheInsert(relation, true);
1414 
1415  /* It's fully valid */
1416  relation->rd_isvalid = true;
1417 
1418  return relation;
1419 }
#define NIL
Definition: pg_list.h:69
struct PartitionDescData * rd_partdesc
Definition: rel.h:131
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:191
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3142
struct SMgrRelationData * rd_smgr
Definition: rel.h:87
bool rd_isnailed
Definition: rel.h:91
bool rd_islocaltemp
Definition: rel.h:90
List * rd_fkeylist
Definition: rel.h:125
bool rd_isvalid
Definition: rel.h:92
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:111
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3195
MemoryContext rd_rulescxt
Definition: rel.h:119
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:375
#define OidIsValid(objectId)
Definition: c.h:576
static void RelationBuildPartitionKey(Relation relation)
Definition: relcache.c:823
void RelationBuildPartitionDesc(Relation rel)
Definition: partition.c:196
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
#define ERROR
Definition: elog.h:43
struct PartitionKeyData * rd_partkey
Definition: rel.h:129
TriggerDesc * trigdesc
Definition: rel.h:120
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1429
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define BackendIdForTempRelations()
Definition: backendid.h:34
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:431
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:483
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:122
SubTransactionId rd_createSubid
Definition: rel.h:110
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define InvalidBackendId
Definition: backendid.h:23
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:176
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
MemoryContext rd_pdcxt
Definition: rel.h:130
BackendId rd_backend
Definition: rel.h:89
#define Assert(condition)
Definition: c.h:670
MemoryContext rd_partkeycxt
Definition: rel.h:128
RuleLock * rd_rules
Definition: rel.h:118
#define InvalidSubTransactionId
Definition: c.h:451
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1516
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1683
int rd_refcnt
Definition: rel.h:88
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:305
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:655
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
bool rd_fkeyvalid
Definition: rel.h:126
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ RelationBuildLocalRelation()

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

Definition at line 3190 of file relcache.c.

References Assert, AssertArg, AttributeRelationId, AuthIdRelationId, AuthMemRelationId, BackendIdForTempRelations, BOOTSTRAP_SUPERUSERID, CacheMemoryContext, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), DatabaseRelationId, elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), tupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsSharedRelation(), IsSystemNamespace(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), tupleDesc::natts, palloc0(), ProcedureRelationId, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), RelationRelationId, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, REPLICA_IDENTITY_DEFAULT, REPLICA_IDENTITY_NOTHING, tupleDesc::tdhasoid, tupleDesc::tdrefcount, TupleDescAttr, and TypeRelationId.

Referenced by heap_create().

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

◆ RelationBuildPartitionKey()

static void RelationBuildPartitionKey ( Relation  relation)
static

Definition at line 823 of file relcache.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), Anum_pg_partitioned_table_partclass, Anum_pg_partitioned_table_partcollation, Anum_pg_partitioned_table_partexprs, Assert, BTORDER_PROC, CacheMemoryContext, CLAOID, copy_partition_key(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, eval_const_expressions(), exprCollation(), exprType(), exprTypmod(), fix_opfuncids(), fmgr_info(), format_type_be(), get_opfamily_proc(), get_typlenbyvalalign(), GETSTRUCT, HASHEXTENDED_PROC, HeapTupleIsValid, i, lfirst, list_head(), MemoryContextSwitchTo(), NameStr, ObjectIdGetDatum, OidIsValid, palloc0(), PartitionKeyData::partattrs, PartitionKeyData::partcollation, PartitionKeyData::partexprs, PARTITION_STRATEGY_HASH, PartitionKeyData::partnatts, PartitionKeyData::partopcintype, PartitionKeyData::partopfamily, PARTRELID, PartitionKeyData::partsupfunc, PartitionKeyData::parttypalign, PartitionKeyData::parttypbyval, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttyplen, PartitionKeyData::parttypmod, pfree(), RelationData::rd_att, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), PartitionKeyData::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, TupleDescAttr, and oidvector::values.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

824 {
826  HeapTuple tuple;
827  bool isnull;
828  int i;
829  PartitionKey key;
830  AttrNumber *attrs;
831  oidvector *opclass;
832  oidvector *collation;
833  ListCell *partexprs_item;
834  Datum datum;
835  MemoryContext partkeycxt,
836  oldcxt;
837  int16 procnum;
838 
839  tuple = SearchSysCache1(PARTRELID,
841 
842  /*
843  * The following happens when we have created our pg_class entry but not
844  * the pg_partitioned_table entry yet.
845  */
846  if (!HeapTupleIsValid(tuple))
847  return;
848 
849  key = (PartitionKey) palloc0(sizeof(PartitionKeyData));
850 
851  /* Fixed-length attributes */
852  form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
853  key->strategy = form->partstrat;
854  key->partnatts = form->partnatts;
855 
856  /*
857  * We can rely on the first variable-length attribute being mapped to the
858  * relevant field of the catalog's C struct, because all previous
859  * attributes are non-nullable and fixed-length.
860  */
861  attrs = form->partattrs.values;
862 
863  /* But use the hard way to retrieve further variable-length attributes */
864  /* Operator class */
865  datum = SysCacheGetAttr(PARTRELID, tuple,
867  Assert(!isnull);
868  opclass = (oidvector *) DatumGetPointer(datum);
869 
870  /* Collation */
871  datum = SysCacheGetAttr(PARTRELID, tuple,
873  Assert(!isnull);
874  collation = (oidvector *) DatumGetPointer(datum);
875 
876  /* Expressions */
877  datum = SysCacheGetAttr(PARTRELID, tuple,
879  if (!isnull)
880  {
881  char *exprString;
882  Node *expr;
883 
884  exprString = TextDatumGetCString(datum);
885  expr = stringToNode(exprString);
886  pfree(exprString);
887 
888  /*
889  * Run the expressions through const-simplification since the planner
890  * will be comparing them to similarly-processed qual clause operands,
891  * and may fail to detect valid matches without this step. We don't
892  * need to bother with canonicalize_qual() though, because partition
893  * expressions are not full-fledged qualification clauses.
894  */
895  expr = eval_const_expressions(NULL, (Node *) expr);
896 
897  /* May as well fix opfuncids too */
898  fix_opfuncids((Node *) expr);
899  key->partexprs = (List *) expr;
900  }
901 
902  key->partattrs = (AttrNumber *) palloc0(key->partnatts * sizeof(AttrNumber));
903  key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
904  key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid));
905  key->partsupfunc = (FmgrInfo *) palloc0(key->partnatts * sizeof(FmgrInfo));
906 
907  key->partcollation = (Oid *) palloc0(key->partnatts * sizeof(Oid));
908 
909  /* Gather type and collation info as well */
910  key->parttypid = (Oid *) palloc0(key->partnatts * sizeof(Oid));
911  key->parttypmod = (int32 *) palloc0(key->partnatts * sizeof(int32));
912  key->parttyplen = (int16 *) palloc0(key->partnatts * sizeof(int16));
913  key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
914  key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char));
915  key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid));
916 
917  /* For the hash partitioning, an extended hash function will be used. */
918  procnum = (key->strategy == PARTITION_STRATEGY_HASH) ?
920 
921  /* Copy partattrs and fill other per-attribute info */
922  memcpy(key->partattrs, attrs, key->partnatts * sizeof(int16));
923  partexprs_item = list_head(key->partexprs);
924  for (i = 0; i < key->partnatts; i++)
925  {
926  AttrNumber attno = key->partattrs[i];
927  HeapTuple opclasstup;
928  Form_pg_opclass opclassform;
929  Oid funcid;
930 
931  /* Collect opfamily information */
932  opclasstup = SearchSysCache1(CLAOID,
933  ObjectIdGetDatum(opclass->values[i]));
934  if (!HeapTupleIsValid(opclasstup))
935  elog(ERROR, "cache lookup failed for opclass %u", opclass->values[i]);
936 
937  opclassform = (Form_pg_opclass) GETSTRUCT(opclasstup);
938  key->partopfamily[i] = opclassform->opcfamily;
939  key->partopcintype[i] = opclassform->opcintype;
940 
941  /* Get a support function for the specified opfamily and datatypes */
942  funcid = get_opfamily_proc(opclassform->opcfamily,
943  opclassform->opcintype,
944  opclassform->opcintype,
945  procnum);
946  if (!OidIsValid(funcid))
947  ereport(ERROR,
948  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
949  errmsg("operator class \"%s\" of access method %s is missing support function %d for data type \"%s\"",
950  NameStr(opclassform->opcname),
952  "hash" : "btree",
953  procnum,
954  format_type_be(opclassform->opcintype))));
955 
956  fmgr_info(funcid, &key->partsupfunc[i]);
957 
958  /* Collation */
959  key->partcollation[i] = collation->values[i];
960 
961  /* Collect type information */
962  if (attno != 0)
963  {
964  Form_pg_attribute att = TupleDescAttr(relation->rd_att, attno - 1);
965 
966  key->parttypid[i] = att->atttypid;
967  key->parttypmod[i] = att->atttypmod;
968  key->parttypcoll[i] = att->attcollation;
969  }
970  else
971  {
972  key->parttypid[i] = exprType(lfirst(partexprs_item));
973  key->parttypmod[i] = exprTypmod(lfirst(partexprs_item));
974  key->parttypcoll[i] = exprCollation(lfirst(partexprs_item));
975  }
977  &key->parttyplen[i],
978  &key->parttypbyval[i],
979  &key->parttypalign[i]);
980 
981  ReleaseSysCache(opclasstup);
982  }
983 
984  ReleaseSysCache(tuple);
985 
986  /* Success --- now copy to the cache memory */
988  RelationGetRelationName(relation),
990  relation->rd_partkeycxt = partkeycxt;
991  oldcxt = MemoryContextSwitchTo(relation->rd_partkeycxt);
992  relation->rd_partkey = copy_partition_key(key);
993  MemoryContextSwitchTo(oldcxt);
994 }
signed short int16
Definition: c.h:283
Definition: c.h:526
Definition: fmgr.h:56
void * stringToNode(char *str)
Definition: read.c:38
#define BTORDER_PROC
Definition: nbtree.h:229
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Oid * partopfamily
Definition: rel.h:61
FmgrInfo * partsupfunc
Definition: rel.h:63
#define Anum_pg_partitioned_table_partexprs
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2040
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:180
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:512
int errcode(int sqlerrcode)
Definition: elog.c:575
#define HASHEXTENDED_PROC
Definition: hash.h:352
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2459
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
List * partexprs
Definition: rel.h:58
char strategy
Definition: rel.h:54
unsigned int Oid
Definition: postgres_ext.h:31
FormData_pg_partitioned_table * Form_pg_partitioned_table
#define OidIsValid(objectId)
Definition: c.h:576
signed int int32
Definition: c.h:284
void pfree(void *pointer)
Definition: mcxt.c:949
Oid * parttypcoll
Definition: rel.h:74
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:122
struct PartitionKeyData * rd_partkey
Definition: rel.h:129
#define Anum_pg_partitioned_table_partcollation
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:534
#define RelationGetRelationName(relation)
Definition: rel.h:445
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
Oid * parttypid
Definition: rel.h:69
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
Oid * partcollation
Definition: rel.h:66
#define TextDatumGetCString(d)
Definition: builtins.h:92
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:342
void * palloc0(Size size)
Definition: mcxt.c:877
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
char * parttypalign
Definition: rel.h:73
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
TupleDesc rd_att
Definition: rel.h:115
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
int32 * parttypmod
Definition: rel.h:70
bool * parttypbyval
Definition: rel.h:72
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
MemoryContext rd_partkeycxt
Definition: rel.h:128
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
#define DatumGetPointer(X)
Definition: postgres.h:555
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
static PartitionKey copy_partition_key(PartitionKey fromkey)
Definition: relcache.c:1002
Oid * partopcintype
Definition: rel.h:62
int i
#define NameStr(name)
Definition: c.h:547
#define elog
Definition: elog.h:219
#define Anum_pg_partitioned_table_partclass
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:425
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 655 of file relcache.c.

References AccessShareLock, RewriteRule::actions, ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), Anum_pg_rewrite_ev_action, Anum_pg_rewrite_ev_class, Anum_pg_rewrite_ev_qual, Assert, BTEqualStrategyNumber, CacheMemoryContext, RewriteRule::enabled, RewriteRule::event, GETSTRUCT, heap_close, heap_getattr, heap_open(), HeapTupleGetOid, HeapTupleIsValid, RewriteRule::isInstead, MemoryContextAlloc(), MemoryContextDelete(), MemoryContextSwitchTo(), RuleLock::numLocks, ObjectIdGetDatum, pfree(), RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, RelationData::rd_rulescxt, RelationGetDescr, RelationGetRelationName, RelationGetRelid, repalloc(), RewriteRelationId, RewriteRelRulenameIndexId, RewriteRule::ruleId, RuleLock::rules, rules, ScanKeyInit(), setRuleCheckAsUser(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), and TextDatumGetCString.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

656 {
657  MemoryContext rulescxt;
658  MemoryContext oldcxt;
659  HeapTuple rewrite_tuple;
660  Relation rewrite_desc;
661  TupleDesc rewrite_tupdesc;
662  SysScanDesc rewrite_scan;
663  ScanKeyData key;
664  RuleLock *rulelock;
665  int numlocks;
666  RewriteRule **rules;
667  int maxlocks;
668 
669  /*
670  * Make the private context. Assume it'll not contain much data.
671  */
673  RelationGetRelationName(relation),
675  relation->rd_rulescxt = rulescxt;
676 
677  /*
678  * allocate an array to hold the rewrite rules (the array is extended if
679  * necessary)
680  */
681  maxlocks = 4;
682  rules = (RewriteRule **)
683  MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
684  numlocks = 0;
685 
686  /*
687  * form a scan key
688  */
689  ScanKeyInit(&key,
691  BTEqualStrategyNumber, F_OIDEQ,
693 
694  /*
695  * open pg_rewrite and begin a scan
696  *
697  * Note: since we scan the rules using RewriteRelRulenameIndexId, we will
698  * be reading the rules in name order, except possibly during
699  * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
700  * ensures that rules will be fired in name order.
701  */
703  rewrite_tupdesc = RelationGetDescr(rewrite_desc);
704  rewrite_scan = systable_beginscan(rewrite_desc,
706  true, NULL,
707  1, &key);
708 
709  while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
710  {
711  Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
712  bool isnull;
713  Datum rule_datum;
714  char *rule_str;
715  RewriteRule *rule;
716 
717  rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
718  sizeof(RewriteRule));
719 
720  rule->ruleId = HeapTupleGetOid(rewrite_tuple);
721 
722  rule->event = rewrite_form->ev_type - '0';
723  rule->enabled = rewrite_form->ev_enabled;
724  rule->isInstead = rewrite_form->is_instead;
725 
726  /*
727  * Must use heap_getattr to fetch ev_action and ev_qual. Also, the
728  * rule strings are often large enough to be toasted. To avoid
729  * leaking memory in the caller's context, do the detoasting here so
730  * we can free the detoasted version.
731  */
732  rule_datum = heap_getattr(rewrite_tuple,
734  rewrite_tupdesc,
735  &isnull);
736  Assert(!isnull);
737  rule_str = TextDatumGetCString(rule_datum);
738  oldcxt = MemoryContextSwitchTo(rulescxt);
739  rule->actions = (List *) stringToNode(rule_str);
740  MemoryContextSwitchTo(oldcxt);
741  pfree(rule_str);
742 
743  rule_datum = heap_getattr(rewrite_tuple,
745  rewrite_tupdesc,
746  &isnull);
747  Assert(!isnull);
748  rule_str = TextDatumGetCString(rule_datum);
749  oldcxt = MemoryContextSwitchTo(rulescxt);
750  rule->qual = (Node *) stringToNode(rule_str);
751  MemoryContextSwitchTo(oldcxt);
752  pfree(rule_str);
753 
754  /*
755  * We want the rule's table references to be checked as though by the
756  * table owner, not the user referencing the rule. Therefore, scan
757  * through the rule's actions and set the checkAsUser field on all
758  * rtable entries. We have to look at the qual as well, in case it
759  * contains sublinks.
760  *
761  * The reason for doing this when the rule is loaded, rather than when
762  * it is stored, is that otherwise ALTER TABLE OWNER would have to
763  * grovel through stored rules to update checkAsUser fields. Scanning
764  * the rule tree during load is relatively cheap (compared to
765  * constructing it in the first place), so we do it here.
766  */
767  setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner);
768  setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner);
769 
770  if (numlocks >= maxlocks)
771  {
772  maxlocks *= 2;
773  rules = (RewriteRule **)
774  repalloc(rules, sizeof(RewriteRule *) * maxlocks);
775  }
776  rules[numlocks++] = rule;
777  }
778 
779  /*
780  * end the scan and close the attribute relation
781  */
782  systable_endscan(rewrite_scan);
783  heap_close(rewrite_desc, AccessShareLock);
784 
785  /*
786  * there might not be any rules (if relhasrules is out-of-date)
787  */
788  if (numlocks == 0)
789  {
790  relation->rd_rules = NULL;
791  relation->rd_rulescxt = NULL;
792  MemoryContextDelete(rulescxt);
793  return;
794  }
795 
796  /*
797  * form a RuleLock and insert into relation
798  */
799  rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
800  rulelock->numLocks = numlocks;
801  rulelock->rules = rules;
802 
803  relation->rd_rules = rulelock;
804 }
void * stringToNode(char *str)
Definition: read.c:38
Node * qual
Definition: prs2lock.h:28
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
int numLocks
Definition: prs2lock.h:42
void setRuleCheckAsUser(Node *node, Oid userid)
#define Anum_pg_rewrite_ev_action
Definition: pg_rewrite.h:66
#define RelationGetDescr(relation)
Definition: rel.h:437
#define RewriteRelRulenameIndexId
Definition: indexing.h:223
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:180
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:512
#define Anum_pg_rewrite_ev_class
Definition: pg_rewrite.h:61
MemoryContext rd_rulescxt
Definition: rel.h:119
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
bool isInstead
Definition: prs2lock.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
Definition: localtime.c:78
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
CmdType event
Definition: prs2lock.h:27
static struct rule * rules
Definition: zic.c:269
#define RelationGetRelationName(relation)
Definition: rel.h:445
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:774
#define TextDatumGetCString(d)
Definition: builtins.h:92
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:342
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define RewriteRelationId
Definition: pg_rewrite.h:32
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
RuleLock * rd_rules
Definition: rel.h:118
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
FormData_pg_rewrite * Form_pg_rewrite
Definition: pg_rewrite.h:53
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
Oid ruleId
Definition: prs2lock.h:26
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define Anum_pg_rewrite_ev_qual
Definition: pg_rewrite.h:65
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
char enabled
Definition: prs2lock.h:30

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 483 of file relcache.c.

References AccessShareLock, attrDefault::adbin, attrDefault::adnum, Anum_pg_attribute_attnum, Anum_pg_attribute_attrelid, Assert, AttrDefaultFetch(), ATTRIBUTE_FIXED_PART_SIZE, AttributeRelationId, AttributeRelidNumIndexId, BTEqualStrategyNumber, BTGreaterStrategyNumber, CacheMemoryContext, tupleConstr::check, CheckConstraintFetch(), tupleDesc::constr, criticalRelcachesBuilt, tupleConstr::defval, elog, ERROR, GETSTRUCT, tupleConstr::has_not_null, heap_close, heap_open(), HeapTupleIsValid, i, Int16GetDatum, MemoryContextAlloc(), MemoryContextAllocZero(), tupleConstr::num_check, tupleConstr::num_defval, ObjectIdGetDatum, pfree(), RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, repalloc(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), tupleDesc::tdhasoid, tupleDesc::tdtypeid, tupleDesc::tdtypmod, and TupleDescAttr.

Referenced by RelationBuildDesc().

484 {
485  HeapTuple pg_attribute_tuple;
486  Relation pg_attribute_desc;
487  SysScanDesc pg_attribute_scan;
488  ScanKeyData skey[2];
489  int need;
490  TupleConstr *constr;
491  AttrDefault *attrdef = NULL;
492  int ndef = 0;
493 
494  /* copy some fields from pg_class row to rd_att */
495  relation->rd_att->tdtypeid = relation->rd_rel->reltype;
496  relation->rd_att->tdtypmod = -1; /* unnecessary, but... */
497  relation->rd_att->tdhasoid = relation->rd_rel->relhasoids;
498 
500  sizeof(TupleConstr));
501  constr->has_not_null = false;
502 
503  /*
504  * Form a scan key that selects only user attributes (attnum > 0).
505  * (Eliminating system attribute rows at the index level is lots faster
506  * than fetching them.)
507  */
508  ScanKeyInit(&skey[0],
510  BTEqualStrategyNumber, F_OIDEQ,
512  ScanKeyInit(&skey[1],
514  BTGreaterStrategyNumber, F_INT2GT,
515  Int16GetDatum(0));
516 
517  /*
518  * Open pg_attribute and begin a scan. Force heap scan if we haven't yet
519  * built the critical relcache entries (this includes initdb and startup
520  * without a pg_internal.init file).
521  */
522  pg_attribute_desc = heap_open(AttributeRelationId, AccessShareLock);
523  pg_attribute_scan = systable_beginscan(pg_attribute_desc,
526  NULL,
527  2, skey);
528 
529  /*
530  * add attribute data to relation->rd_att
531  */
532  need = relation->rd_rel->relnatts;
533 
534  while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
535  {
536  Form_pg_attribute attp;
537 
538  attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
539 
540  if (attp->attnum <= 0 ||
541  attp->attnum > relation->rd_rel->relnatts)
542  elog(ERROR, "invalid attribute number %d for %s",
543  attp->attnum, RelationGetRelationName(relation));
544 
545  memcpy(TupleDescAttr(relation->rd_att, attp->attnum - 1),
546  attp,
548 
549  /* Update constraint/default info */
550  if (attp->attnotnull)
551  constr->has_not_null = true;
552 
553  if (attp->atthasdef)
554  {
555  if (attrdef == NULL)
556  attrdef = (AttrDefault *)
558  relation->rd_rel->relnatts *
559  sizeof(AttrDefault));
560  attrdef[ndef].adnum = attp->attnum;
561  attrdef[ndef].adbin = NULL;
562  ndef++;
563  }
564  need--;
565  if (need == 0)
566  break;
567  }
568 
569  /*
570  * end the scan and close the attribute relation
571  */
572  systable_endscan(pg_attribute_scan);
573  heap_close(pg_attribute_desc, AccessShareLock);
574 
575  if (need != 0)
576  elog(ERROR, "catalog is missing %d attribute(s) for relid %u",
577  need, RelationGetRelid(relation));
578 
579  /*
580  * The attcacheoff values we read from pg_attribute should all be -1
581  * ("unknown"). Verify this if assert checking is on. They will be
582  * computed when and if needed during tuple access.
583  */
584 #ifdef USE_ASSERT_CHECKING
585  {
586  int i;
587 
588  for (i = 0; i < relation->rd_rel->relnatts; i++)
589  Assert(TupleDescAttr(relation->rd_att, i)->attcacheoff == -1);
590  }
591 #endif
592 
593  /*
594  * However, we can easily set the attcacheoff value for the first
595  * attribute: it must be zero. This eliminates the need for special cases
596  * for attnum=1 that used to exist in fastgetattr() and index_getattr().
597  */
598  if (relation->rd_rel->relnatts > 0)
599  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
600 
601  /*
602  * Set up constraint/default info
603  */
604  if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
605  {
606  relation->rd_att->constr = constr;
607 
608  if (ndef > 0) /* DEFAULTs */
609  {
610  if (ndef < relation->rd_rel->relnatts)
611  constr->defval = (AttrDefault *)
612  repalloc(attrdef, ndef * sizeof(AttrDefault));
613  else
614  constr->defval = attrdef;
615  constr->num_defval = ndef;
616  AttrDefaultFetch(relation);
617  }
618  else
619  constr->num_defval = 0;
620 
621  if (relation->rd_rel->relchecks > 0) /* CHECKs */
622  {
623  constr->num_check = relation->rd_rel->relchecks;
624  constr->check = (ConstrCheck *)
626  constr->num_check * sizeof(ConstrCheck));
627  CheckConstraintFetch(relation);
628  }
629  else
630  constr->num_check = 0;
631  }
632  else
633  {
634  pfree(constr);
635  relation->rd_att->constr = NULL;
636  }
637 }
#define AttributeRelidNumIndexId
Definition: indexing.h:94
static void AttrDefaultFetch(Relation relation)
Definition: relcache.c:4029
#define Anum_pg_attribute_attrelid
Definition: pg_attribute.h:195
Oid tdtypeid
Definition: tupdesc.h:80
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
bool tdhasoid
Definition: tupdesc.h:82
#define Anum_pg_attribute_attnum
Definition: pg_attribute.h:200
ConstrCheck * check
Definition: tupdesc.h:40
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define Int16GetDatum(X)
Definition: postgres.h:457
#define AccessShareLock
Definition: lockdefs.h:36
#define AttributeRelationId
Definition: pg_attribute.h:33
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
int32 tdtypmod
Definition: tupdesc.h:81
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:949
AttrDefault * defval
Definition: tupdesc.h:39
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
AttrNumber adnum
Definition: tupdesc.h:24
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
char * adbin
Definition: tupdesc.h:25
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:179
bool has_not_null
Definition: tupdesc.h:43
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
uint16 num_defval
Definition: tupdesc.h:41
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4103
TupleConstr * constr
Definition: tupdesc.h:84
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
uint16 num_check
Definition: tupdesc.h:42
#define elog
Definition: elog.h:219
bool criticalRelcachesBuilt
Definition: relcache.c:125
#define RelationGetRelid(relation)
Definition: rel.h:425
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6087 of file relcache.c.

References LWLockRelease().

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

6088 {
6089  LWLockRelease(RelCacheInitLock);
6090 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1722

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6061 of file relcache.c.

References DatabasePath, ereport, errcode_for_file_access(), errmsg(), ERROR, LW_EXCLUSIVE, LWLockAcquire(), MAXPGPATH, RELCACHE_INIT_FILENAME, and snprintf().

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

6062 {
6063  char initfilename[MAXPGPATH];
6064 
6065  snprintf(initfilename, sizeof(initfilename), "%s/%s",
6067 
6068  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6069 
6070  if (unlink(initfilename) < 0)
6071  {
6072  /*
6073  * The file might not be there if no backend has been started since
6074  * the last removal. But complain about failures other than ENOENT.
6075  * Fortunately, it's not too late to abort the transaction if we can't
6076  * get rid of the would-be-obsolete init file.
6077  */
6078  if (errno != ENOENT)
6079  ereport(ERROR,
6081  errmsg("could not remove cache file \"%s\": %m",
6082  initfilename)));
6083  }
6084 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char * DatabasePath
Definition: globals.c:85
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1118
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

6103 {
6104  const char *tblspcdir = "pg_tblspc";
6105  DIR *dir;
6106  struct dirent *de;
6107  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6108 
6109  /*
6110  * We zap the shared cache file too. In theory it can't get out of sync
6111  * enough to be a problem, but in data-corruption cases, who knows ...
6112  */
6113  snprintf(path, sizeof(path), "global/%s",
6115  unlink_initfile(path);
6116 
6117  /* Scan everything in the default tablespace */
6119 
6120  /* Scan the tablespace link directory to find non-default tablespaces */
6121  dir = AllocateDir(tblspcdir);
6122 
6123  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6124  {
6125  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6126  {
6127  /* Scan the tablespace dir for per-database dirs */
6128  snprintf(path, sizeof(path), "%s/%s/%s",
6129  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6131  }
6132  }
6133 
6134  FreeDir(dir);
6135 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6139
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2677
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2596
static void unlink_initfile(const char *initfilename)
Definition: relcache.c:6163
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
#define TABLESPACE_VERSION_DIRECTORY
Definition: catalog.h:26
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2714

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6139 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6140 {
6141  DIR *dir;
6142  struct dirent *de;
6143  char initfilename[MAXPGPATH * 2];
6144 
6145  /* Scan the tablespace directory to find per-database directories */
6146  dir = AllocateDir(tblspcpath);
6147 
6148  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6149  {
6150  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6151  {
6152  /* Try to remove the init file in each database */
6153  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6154  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6155  unlink_initfile(initfilename);
6156  }
6157  }
6158 
6159  FreeDir(dir);
6160 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2677
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
Definition: dirent.c:25
#define MAXPGPATH
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2596
static void unlink_initfile(const char *initfilename)
Definition: relcache.c:6163
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2714

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3542 of file relcache.c.

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

Referenced by InitPostgres().

3543 {
3544  HASHCTL ctl;
3545 
3546  /*
3547  * make sure cache memory context exists
3548  */
3549  if (!CacheMemoryContext)
3551 
3552  /*
3553  * create hashtable that indexes the relcache
3554  */
3555  MemSet(&ctl, 0, sizeof(ctl));
3556  ctl.keysize = sizeof(Oid);
3557  ctl.entrysize = sizeof(RelIdCacheEnt);
3558  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3559  &ctl, HASH_ELEM | HASH_BLOBS);
3560 
3561  /*
3562  * relation mapper needs to be initialized too
3563  */
3565 }
void RelationMapInitialize(void)
Definition: relmapper.c:562
#define HASH_ELEM
Definition: hsearch.h:87
struct relidcacheent RelIdCacheEnt
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:853
static HTAB * RelationIdCache
Definition: relcache.c:119
unsigned int Oid
Definition: postgres_ext.h:31
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
#define INITRELCACHESIZE
Definition: relcache.c:3539
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3579 of file relcache.c.

References AuthIdRelation_Rowtype_Id, AuthMemRelation_Rowtype_Id, CacheMemoryContext, DatabaseRelation_Rowtype_Id, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, Desc_pg_shseclabel, Desc_pg_subscription, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), Natts_pg_auth_members, Natts_pg_authid, Natts_pg_database, Natts_pg_shseclabel, Natts_pg_subscription, RelationMapInitializePhase2(), SharedSecLabelRelation_Rowtype_Id, and SubscriptionRelation_Rowtype_Id.

Referenced by InitPostgres().

3580 {
3581  MemoryContext oldcxt;
3582 
3583  /*
3584  * relation mapper needs initialized too
3585  */
3587 
3588  /*
3589  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3590  * nothing.
3591  */
3593  return;
3594 
3595  /*
3596  * switch to cache memory context
3597  */
3599 
3600  /*
3601  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3602  * the cache with pre-made descriptors for the critical shared catalogs.
3603  */
3604  if (!load_relcache_init_file(true))
3605  {
3606  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3608  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3610  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3612  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3614  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3616 
3617 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3618  }
3619 
3620  MemoryContextSwitchTo(oldcxt);
3621 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:102
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5376
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, bool hasoids, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1898
#define SubscriptionRelation_Rowtype_Id
void RelationMapInitializePhase2(void)
Definition: relmapper.c:582
#define Natts_pg_database
Definition: pg_database.h:63
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:101
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:105
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Natts_pg_auth_members
#define SharedSecLabelRelation_Rowtype_Id
Definition: pg_shseclabel.h:22
#define Natts_pg_subscription
#define AuthIdRelation_Rowtype_Id
Definition: pg_authid.h:43
#define AuthMemRelation_Rowtype_Id
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:100
#define Natts_pg_shseclabel
Definition: pg_shseclabel.h:41
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:104
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:367
#define DatabaseRelation_Rowtype_Id
Definition: pg_database.h:30
#define Natts_pg_authid
Definition: pg_authid.h:78
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3638 of file relcache.c.

References AccessMethodProcedureIndexId, AccessMethodProcedureRelationId, Assert, AttributeRelation_Rowtype_Id, AttributeRelationId, AttributeRelidNumIndexId, AuthIdOidIndexId, AuthIdRelationId, AuthIdRolnameIndexId, AuthMemMemRoleIndexId, AuthMemRelationId, CacheMemoryContext, CLASS_TUPLE_SIZE, ClassOidIndexId, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabaseNameIndexId, DatabaseOidIndexId, DatabaseRelationId, 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, IndexRelationId, IndexRelidIndexId, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), Natts_pg_attribute, Natts_pg_class, Natts_pg_proc, Natts_pg_type, ObjectIdGetDatum, OpclassOidIndexId, OperatorClassRelationId, pfree(), ProcedureRelation_Rowtype_Id, RelationData::rd_att, RelationData::rd_options, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationBuildPartitionDesc(), RelationBuildPartitionKey(), RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIncrementReferenceCount(), RelationMapInitializePhase3(), RelationParseRelOptions(), RelationRelation_Rowtype_Id, RelationRelationId, relidcacheent::reldesc, ReleaseSysCache(), RELKIND_PARTITIONED_TABLE, RELOID, RewriteRelationId, RewriteRelRulenameIndexId, SearchSysCache1(), SharedSecLabelObjectIndexId, SharedSecLabelRelationId, status(), tupleDesc::tdhasoid, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, TriggerRelationId, TriggerRelidNameIndexId, TypeRelation_Rowtype_Id, and write_relcache_init_file().

Referenced by InitPostgres().

3639 {
3641  RelIdCacheEnt *idhentry;
3642  MemoryContext oldcxt;
3643  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3644 
3645  /*
3646  * relation mapper needs initialized too
3647  */
3649 
3650  /*
3651  * switch to cache memory context
3652  */
3654 
3655  /*
3656  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3657  * the cache with pre-made descriptors for the critical "nailed-in" system
3658  * catalogs.
3659  */
3660  if (IsBootstrapProcessingMode() ||
3661  !load_relcache_init_file(false))
3662  {
3663  needNewCacheFile = true;
3664 
3665  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3666  true, Natts_pg_class, Desc_pg_class);
3667  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3669  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3670  true, Natts_pg_proc, Desc_pg_proc);
3671  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3672  true, Natts_pg_type, Desc_pg_type);
3673 
3674 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3675  }
3676 
3677  MemoryContextSwitchTo(oldcxt);
3678 
3679  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3681  return;
3682 
3683  /*
3684  * If we didn't get the critical system indexes loaded into relcache, do
3685  * so now. These are critical because the catcache and/or opclass cache
3686  * depend on them for fetches done during relcache load. Thus, we have an
3687  * infinite-recursion problem. We can break the recursion by doing
3688  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3689  * performance, we only want to do that until we have the critical indexes
3690  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3691  * decide whether to do heapscan or indexscan at the key spots, and we set
3692  * it true after we've loaded the critical indexes.
3693  *
3694  * The critical indexes are marked as "nailed in cache", partly to make it
3695  * easy for load_relcache_init_file to count them, but mainly because we
3696  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3697  * true. (NOTE: perhaps it would be possible to reload them by
3698  * temporarily setting criticalRelcachesBuilt to false again. For now,
3699  * though, we just nail 'em in.)
3700  *
3701  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3702  * in the same way as the others, because the critical catalogs don't
3703  * (currently) have any rules or triggers, and so these indexes can be
3704  * rebuilt without inducing recursion. However they are used during
3705  * relcache load when a rel does have rules or triggers, so we choose to
3706  * nail them for performance reasons.
3707  */
3709  {
3715  IndexRelationId);
3724 
3725 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3726 
3727  criticalRelcachesBuilt = true;
3728  }
3729 
3730  /*
3731  * Process critical shared indexes too.
3732  *
3733  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3734  * initial lookup of MyDatabaseId, without which we'll never find any
3735  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3736  * database OID, so it instead depends on DatabaseOidIndexId. We also
3737  * need to nail up some indexes on pg_authid and pg_auth_members for use
3738  * during client authentication. SharedSecLabelObjectIndexId isn't
3739  * critical for the core system, but authentication hooks might be
3740  * interested in it.
3741  */
3743  {
3756 
3757 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3758 
3760  }
3761 
3762  /*
3763  * Now, scan all the relcache entries and update anything that might be
3764  * wrong in the results from formrdesc or the relcache cache file. If we
3765  * faked up relcache entries using formrdesc, then read the real pg_class
3766  * rows and replace the fake entries with them. Also, if any of the
3767  * relcache entries have rules, triggers, or security policies, load that
3768  * info the hard way since it isn't recorded in the cache file.
3769  *
3770  * Whenever we access the catalogs to read data, there is a possibility of
3771  * a shared-inval cache flush causing relcache entries to be removed.
3772  * Since hash_seq_search only guarantees to still work after the *current*
3773  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3774  * We handle this by restarting the scan from scratch after each access.
3775  * This is theoretically O(N^2), but the number of entries that actually
3776  * need to be fixed is small enough that it doesn't matter.
3777  */
3778  hash_seq_init(&status, RelationIdCache);
3779 
3780  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3781  {
3782  Relation relation = idhentry->reldesc;
3783  bool restart = false;
3784 
3785  /*
3786  * Make sure *this* entry doesn't get flushed while we work with it.
3787  */
3789 
3790  /*
3791  * If it's a faked-up entry, read the real pg_class tuple.
3792  */
3793  if (relation->rd_rel->relowner == InvalidOid)
3794  {
3795  HeapTuple htup;
3796  Form_pg_class relp;
3797 
3798  htup = SearchSysCache1(RELOID,
3799  ObjectIdGetDatum(RelationGetRelid(relation)));
3800  if (!HeapTupleIsValid(htup))
3801  elog(FATAL, "cache lookup failed for relation %u",
3802  RelationGetRelid(relation));
3803  relp = (Form_pg_class) GETSTRUCT(htup);
3804 
3805  /*
3806  * Copy tuple to relation->rd_rel. (See notes in
3807  * AllocateRelationDesc())
3808  */
3809  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
3810 
3811  /* Update rd_options while we have the tuple */
3812  if (relation->rd_options)
3813  pfree(relation->rd_options);
3814  RelationParseRelOptions(relation, htup);
3815 
3816  /*
3817  * Check the values in rd_att were set up correctly. (We cannot
3818  * just copy them over now: formrdesc must have set up the rd_att
3819  * data correctly to start with, because it may already have been
3820  * copied into one or more catcache entries.)
3821  */
3822  Assert(relation->rd_att->tdtypeid == relp->reltype);
3823  Assert(relation->rd_att->tdtypmod == -1);
3824  Assert(relation->rd_att->tdhasoid == relp->relhasoids);
3825 
3826  ReleaseSysCache(htup);
3827 
3828  /* relowner had better be OK now, else we'll loop forever */
3829  if (relation->rd_rel->relowner == InvalidOid)
3830  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
3831  RelationGetRelationName(relation));
3832 
3833  restart = true;
3834  }
3835 
3836  /*
3837  * Fix data that isn't saved in relcache cache file.
3838  *
3839  * relhasrules or relhastriggers could possibly be wrong or out of
3840  * date. If we don't actually find any rules or triggers, clear the
3841  * local copy of the flag so that we don't get into an infinite loop
3842  * here. We don't make any attempt to fix the pg_class entry, though.
3843  */
3844  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
3845  {
3846  RelationBuildRuleLock(relation);
3847  if (relation->rd_rules == NULL)
3848  relation->rd_rel->relhasrules = false;
3849  restart = true;
3850  }
3851  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
3852  {
3853  RelationBuildTriggers(relation);
3854  if (relation->trigdesc == NULL)
3855  relation->rd_rel->relhastriggers = false;
3856  restart = true;
3857  }
3858 
3859  /*
3860  * Re-load the row security policies if the relation has them, since
3861  * they are not preserved in the cache. Note that we can never NOT
3862  * have a policy while relrowsecurity is true,
3863  * RelationBuildRowSecurity will create a single default-deny policy
3864  * if there is no policy defined in pg_policy.
3865  */
3866  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
3867  {
3868  RelationBuildRowSecurity(relation);
3869 
3870  Assert(relation->rd_rsdesc != NULL);
3871  restart = true;
3872  }
3873 
3874  /*
3875  * Reload the partition key and descriptor for a partitioned table.
3876  */
3877  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3878  relation->rd_partkey == NULL)
3879  {
3880  RelationBuildPartitionKey(relation);
3881  Assert(relation->rd_partkey != NULL);
3882 
3883  restart = true;
3884  }
3885 
3886  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3887  relation->rd_partdesc == NULL)
3888  {
3889  RelationBuildPartitionDesc(relation);
3890  Assert(relation->rd_partdesc != NULL);
3891 
3892  restart = true;
3893  }
3894 
3895  /* Release hold on the relation */
3897 
3898  /* Now, restart the hashtable scan if needed */
3899  if (restart)
3900  {
3901  hash_seq_term(&status);
3902  hash_seq_init(&status, RelationIdCache);
3903  }
3904  }
3905 
3906  /*
3907  * Lastly, write out new relcache cache files if needed. We don't bother
3908  * to distinguish cases where only one of the two needs an update.
3909  */
3910  if (needNewCacheFile)
3911  {
3912  /*
3913  * Force all the catcaches to finish initializing and thereby open the
3914  * catalogs and indexes they use. This will preload the relcache with
3915  * entries for all the most important system catalogs and indexes, so
391