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/tupdesc_details.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/cost.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "partitioning/partbounds.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rowsecurity.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/relmapper.h"
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "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 */
 
#define HEURISTIC_MAX_HOT_RECHECK_EXPR_COST   1000
 

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 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)
 
static bool IsProjectionFunctionalIndex (Relation index, IndexInfo *ii)
 
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:157
static int eoxact_list_len
Definition: relcache.c:159

Definition at line 162 of file relcache.c.

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

◆ HEURISTIC_MAX_HOT_RECHECK_EXPR_COST

#define HEURISTIC_MAX_HOT_RECHECK_EXPR_COST   1000

Definition at line 4666 of file relcache.c.

Referenced by IsProjectionFunctionalIndex().

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3373 of file relcache.c.

Referenced by RelationCacheInitialize().

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 157 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:906
static HTAB * RelationIdCache
Definition: relcache.c:125
#define WARNING
Definition: elog.h:40

Definition at line 216 of file relcache.c.

Referenced by RelationClearRelation().

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
(void *) &((RELATION)->rd_id), \
HASH_ENTER, &found); \
if (found) \
{ \
/* see comments in RelationBuildDesc and RelationBuildLocalRelation */ \
Relation _old_rel = hentry->reldesc; \
Assert(replace_allowed); \
hentry->reldesc = (RELATION); \
RelationDestroyRelation(_old_rel, false); \
elog(WARNING, "leaking still-referenced relcache entry for \"%s\"", \
} \
else \
hentry->reldesc = (RELATION); \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:125
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define WARNING
Definition: elog.h:40
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372

Definition at line 182 of file relcache.c.

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

◆ RelationIdCacheLookup

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

Definition at line 204 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 97 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 379 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().

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

◆ AtEOSubXact_cleanup()

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

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

2961 {
2962  /*
2963  * Is it a relation created in the current subtransaction?
2964  *
2965  * During subcommit, mark it as belonging to the parent, instead. During
2966  * subabort, simply delete the relcache entry.
2967  */
2968  if (relation->rd_createSubid == mySubid)
2969  {
2970  if (isCommit)
2971  relation->rd_createSubid = parentSubid;
2972  else if (RelationHasReferenceCountZero(relation))
2973  {
2974  RelationClearRelation(relation, false);
2975  return;
2976  }
2977  else
2978  {
2979  /*
2980  * Hmm, somewhere there's a (leaked?) reference to the relation.
2981  * We daren't remove the entry for fear of dereferencing a
2982  * dangling pointer later. Bleat, and transfer it to the parent
2983  * subtransaction so we can try again later. This must be just a
2984  * WARNING to avoid error-during-error-recovery loops.
2985  */
2986  relation->rd_createSubid = parentSubid;
2987  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
2988  RelationGetRelationName(relation));
2989  }
2990  }
2991 
2992  /*
2993  * Likewise, update or drop any new-relfilenode-in-subtransaction hint.
2994  */
2995  if (relation->rd_newRelfilenodeSubid == mySubid)
2996  {
2997  if (isCommit)
2998  relation->rd_newRelfilenodeSubid = parentSubid;
2999  else
3001  }
3002 
3003  /*
3004  * Flush any temporary index list.
3005  */
3006  if (relation->rd_indexvalid == 2)
3007  {
3008  list_free(relation->rd_indexlist);
3009  relation->rd_indexlist = NIL;
3010  relation->rd_oidindex = InvalidOid;
3011  relation->rd_pkindex = InvalidOid;
3012  relation->rd_replidindex = InvalidOid;
3013  relation->rd_indexvalid = 0;
3014  }
3015 }
#define NIL
Definition: pg_list.h:69
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
Oid rd_replidindex
Definition: rel.h:108
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Oid rd_pkindex
Definition: rel.h:107
char rd_indexvalid
Definition: rel.h:63
#define RelationGetRelationName(relation)
Definition: rel.h:441
Oid rd_oidindex
Definition: rel.h:106
List * rd_indexlist
Definition: rel.h:105
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidOid
Definition: postgres_ext.h:36
#define InvalidSubTransactionId
Definition: c.h:480
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391
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 2912 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().

2914 {
2916  RelIdCacheEnt *idhentry;
2917  int i;
2918 
2919  /*
2920  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2921  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
2922  * logic as in AtEOXact_RelationCache.
2923  */
2925  {
2926  hash_seq_init(&status, RelationIdCache);
2927  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2928  {
2929  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
2930  mySubid, parentSubid);
2931  }
2932  }
2933  else
2934  {
2935  for (i = 0; i < eoxact_list_len; i++)
2936  {
2937  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2938  (void *) &eoxact_list[i],
2939  HASH_FIND,
2940  NULL);
2941  if (idhentry != NULL)
2942  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
2943  mySubid, parentSubid);
2944  }
2945  }
2946 
2947  /* Don't reset the list; we still need more cleanup later */
2948 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:158
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:2959
Relation reldesc
Definition: relcache.c:122
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:125
static bool eoxact_list_overflowed
Definition: relcache.c:160
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static int eoxact_list_len
Definition: relcache.c:159

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

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

2825 {
2826  /*
2827  * The relcache entry's ref count should be back to its normal
2828  * not-in-a-transaction state: 0 unless it's nailed in cache.
2829  *
2830  * In bootstrap mode, this is NOT true, so don't check it --- the
2831  * bootstrap code expects relations to stay open across start/commit
2832  * transaction calls. (That seems bogus, but it's not worth fixing.)
2833  *
2834  * Note: ideally this check would be applied to every relcache entry, not
2835  * just those that have eoxact work to do. But it's not worth forcing a
2836  * scan of the whole relcache just for this. (Moreover, doing so would
2837  * mean that assert-enabled testing never tests the hash_search code path
2838  * above, which seems a bad idea.)
2839  */
2840 #ifdef USE_ASSERT_CHECKING
2842  {
2843  int expected_refcnt;
2844 
2845  expected_refcnt = relation->rd_isnailed ? 1 : 0;
2846  Assert(relation->rd_refcnt == expected_refcnt);
2847  }
2848 #endif
2849 
2850  /*
2851  * Is it a relation created in the current transaction?
2852  *
2853  * During commit, reset the flag to zero, since we are now out of the
2854  * creating transaction. During abort, simply delete the relcache entry
2855  * --- it isn't interesting any longer. (NOTE: if we have forgotten the
2856  * new-ness of a new relation due to a forced cache flush, the entry will
2857  * get deleted anyway by shared-cache-inval processing of the aborted
2858  * pg_class insertion.)
2859  */
2860  if (relation->rd_createSubid != InvalidSubTransactionId)
2861  {
2862  if (isCommit)
2864  else if (RelationHasReferenceCountZero(relation))
2865  {
2866  RelationClearRelation(relation, false);
2867  return;
2868  }
2869  else
2870  {
2871  /*
2872  * Hmm, somewhere there's a (leaked?) reference to the relation.
2873  * We daren't remove the entry for fear of dereferencing a
2874  * dangling pointer later. Bleat, and mark it as not belonging to
2875  * the current transaction. Hopefully it'll get cleaned up
2876  * eventually. This must be just a WARNING to avoid
2877  * error-during-error-recovery loops.
2878  */
2880  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
2881  RelationGetRelationName(relation));
2882  }
2883  }
2884 
2885  /*
2886  * Likewise, reset the hint about the relfilenode being new.
2887  */
2889 
2890  /*
2891  * Flush any temporary index list.
2892  */
2893  if (relation->rd_indexvalid == 2)
2894  {
2895  list_free(relation->rd_indexlist);
2896  relation->rd_indexlist = NIL;
2897  relation->rd_oidindex = InvalidOid;
2898  relation->rd_pkindex = InvalidOid;
2899  relation->rd_replidindex = InvalidOid;
2900  relation->rd_indexvalid = 0;
2901  }
2902 }
#define NIL
Definition: pg_list.h:69
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
Oid rd_replidindex
Definition: rel.h:108
bool rd_isnailed
Definition: rel.h:61
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Oid rd_pkindex
Definition: rel.h:107
char rd_indexvalid
Definition: rel.h:63
#define RelationGetRelationName(relation)
Definition: rel.h:441
Oid rd_oidindex
Definition: rel.h:106
List * rd_indexlist
Definition: rel.h:105
#define WARNING
Definition: elog.h:40
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:699
#define InvalidSubTransactionId
Definition: c.h:480
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
int rd_refcnt
Definition: rel.h:58
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 2761 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().

2762 {
2764  RelIdCacheEnt *idhentry;
2765  int i;
2766 
2767  /*
2768  * Unless the eoxact_list[] overflowed, we only need to examine the rels
2769  * listed in it. Otherwise fall back on a hash_seq_search scan.
2770  *
2771  * For simplicity, eoxact_list[] entries are not deleted till end of
2772  * top-level transaction, even though we could remove them at
2773  * subtransaction end in some cases, or remove relations from the list if
2774  * they are cleared for other reasons. Therefore we should expect the
2775  * case that list entries are not found in the hashtable; if not, there's
2776  * nothing to do for them.
2777  */
2779  {
2780  hash_seq_init(&status, RelationIdCache);
2781  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2782  {
2783  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2784  }
2785  }
2786  else
2787  {
2788  for (i = 0; i < eoxact_list_len; i++)
2789  {
2790  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
2791  (void *) &eoxact_list[i],
2792  HASH_FIND,
2793  NULL);
2794  if (idhentry != NULL)
2795  AtEOXact_cleanup(idhentry->reldesc, isCommit);
2796  }
2797  }
2798 
2799  if (EOXactTupleDescArrayLen > 0)
2800  {
2801  Assert(EOXactTupleDescArray != NULL);
2802  for (i = 0; i < NextEOXactTupleDescNum; i++)
2805  EOXactTupleDescArray = NULL;
2806  }
2807 
2808  /* Now we're out of the transaction and can clear the lists */
2809  eoxact_list_len = 0;
2810  eoxact_list_overflowed = false;
2811  NextEOXactTupleDescNum = 0;
2813 }
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:158
static int EOXactTupleDescArrayLen
Definition: relcache.c:177
Relation reldesc
Definition: relcache.c:122
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * RelationIdCache
Definition: relcache.c:125
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:2824
static bool eoxact_list_overflowed
Definition: relcache.c:160
static int NextEOXactTupleDescNum
Definition: relcache.c:176
void pfree(void *pointer)
Definition: mcxt.c:1031
#define Assert(condition)
Definition: c.h:699
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:311
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:159
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:175

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation)
static

Definition at line 3863 of file relcache.c.

References AccessShareLock, attrDefault::adbin, attrDefault::adnum, AttrDefaultIndexId, 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().

3864 {
3865  AttrDefault *attrdef = relation->rd_att->constr->defval;
3866  int ndef = relation->rd_att->constr->num_defval;
3867  Relation adrel;
3868  SysScanDesc adscan;
3869  ScanKeyData skey;
3870  HeapTuple htup;
3871  Datum val;
3872  bool isnull;
3873  int found;
3874  int i;
3875 
3876  ScanKeyInit(&skey,
3877  Anum_pg_attrdef_adrelid,
3878  BTEqualStrategyNumber, F_OIDEQ,
3879  ObjectIdGetDatum(RelationGetRelid(relation)));
3880 
3881  adrel = heap_open(AttrDefaultRelationId, AccessShareLock);
3882  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
3883  NULL, 1, &skey);
3884  found = 0;
3885 
3886  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
3887  {
3888  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
3889  Form_pg_attribute attr = TupleDescAttr(relation->rd_att, adform->adnum - 1);
3890 
3891  for (i = 0; i < ndef; i++)
3892  {
3893  if (adform->adnum != attrdef[i].adnum)
3894  continue;
3895  if (attrdef[i].adbin != NULL)
3896  elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
3897  NameStr(attr->attname),
3898  RelationGetRelationName(relation));
3899  else
3900  found++;
3901 
3902  val = fastgetattr(htup,
3903  Anum_pg_attrdef_adbin,
3904  adrel->rd_att, &isnull);
3905  if (isnull)
3906  elog(WARNING, "null adbin for attr %s of rel %s",
3907  NameStr(attr->attname),
3908  RelationGetRelationName(relation));
3909  else
3910  {
3911  /* detoast and convert to cstring in caller's context */
3912  char *s = TextDatumGetCString(val);
3913 
3915  pfree(s);
3916  }
3917  break;
3918  }
3919 
3920  if (i >= ndef)
3921  elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
3922  adform->adnum, RelationGetRelationName(relation));
3923  }
3924 
3925  systable_endscan(adscan);
3926  heap_close(adrel, AccessShareLock);
3927 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:736
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define AccessShareLock
Definition: lockdefs.h:36
#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:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
void pfree(void *pointer)
Definition: mcxt.c:1031
AttrDefault * defval
Definition: tupdesc.h:41
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define AttrDefaultIndexId
Definition: indexing.h:86
AttrNumber adnum
Definition: tupdesc.h:24
#define RelationGetRelationName(relation)
Definition: rel.h:441
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
char * adbin
Definition: tupdesc.h:25
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:45
#define WARNING
Definition: elog.h:40
#define TextDatumGetCString(d)
Definition: builtins.h:96
uintptr_t Datum
Definition: postgres.h:365
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
uint16 num_defval
Definition: tupdesc.h:44
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
TupleConstr * constr
Definition: tupdesc.h:87
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1148
int i
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ BuildHardcodedDescriptor()

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

Definition at line 3801 of file relcache.c.

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

3803 {
3804  TupleDesc result;
3805  MemoryContext oldcxt;
3806  int i;
3807 
3809 
3810  result = CreateTemplateTupleDesc(natts, hasoids);
3811  result->tdtypeid = RECORDOID; /* not right, but we don't care */
3812  result->tdtypmod = -1;
3813 
3814  for (i = 0; i < natts; i++)
3815  {
3816  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
3817  /* make sure attcacheoff is valid */
3818  TupleDescAttr(result, i)->attcacheoff = -1;
3819  }
3820 
3821  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
3822  TupleDescAttr(result, 0)->attcacheoff = 0;
3823 
3824  /* Note: we don't bother to set up a TupleConstr entry */
3825 
3826  MemoryContextSwitchTo(oldcxt);
3827 
3828  return result;
3829 }
Oid tdtypeid
Definition: tupdesc.h:83
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int32 tdtypmod
Definition: tupdesc.h:84
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:189
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
int i
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ CheckConstraintCmp()

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

Definition at line 4004 of file relcache.c.

References constrCheck::ccname.

Referenced by CheckConstraintFetch().

4005 {
4006  const ConstrCheck *ca = (const ConstrCheck *) a;
4007  const ConstrCheck *cb = (const ConstrCheck *) b;
4008 
4009  return strcmp(ca->ccname, cb->ccname);
4010 }
char * ccname
Definition: tupdesc.h:32

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 3933 of file relcache.c.

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, constrCheck::ccbin, constrCheck::ccname, constrCheck::ccnoinherit, constrCheck::ccvalid, tupleConstr::check, CheckConstraintCmp(), tupleDesc::constr, 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().

3934 {
3935  ConstrCheck *check = relation->rd_att->constr->check;
3936  int ncheck = relation->rd_att->constr->num_check;
3937  Relation conrel;
3938  SysScanDesc conscan;
3939  ScanKeyData skey[1];
3940  HeapTuple htup;
3941  int found = 0;
3942 
3943  ScanKeyInit(&skey[0],
3944  Anum_pg_constraint_conrelid,
3945  BTEqualStrategyNumber, F_OIDEQ,
3946  ObjectIdGetDatum(RelationGetRelid(relation)));
3947 
3948  conrel = heap_open(ConstraintRelationId, AccessShareLock);
3949  conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
3950  NULL, 1, skey);
3951 
3952  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
3953  {
3955  Datum val;
3956  bool isnull;
3957  char *s;
3958 
3959  /* We want check constraints only */
3960  if (conform->contype != CONSTRAINT_CHECK)
3961  continue;
3962 
3963  if (found >= ncheck)
3964  elog(ERROR, "unexpected constraint record found for rel %s",
3965  RelationGetRelationName(relation));
3966 
3967  check[found].ccvalid = conform->convalidated;
3968  check[found].ccnoinherit = conform->connoinherit;
3970  NameStr(conform->conname));
3971 
3972  /* Grab and test conbin is actually set */
3973  val = fastgetattr(htup,
3974  Anum_pg_constraint_conbin,
3975  conrel->rd_att, &isnull);
3976  if (isnull)
3977  elog(ERROR, "null conbin for rel %s",
3978  RelationGetRelationName(relation));
3979 
3980  /* detoast and convert to cstring in caller's context */
3981  s = TextDatumGetCString(val);
3982  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
3983  pfree(s);
3984 
3985  found++;
3986  }
3987 
3988  systable_endscan(conscan);
3989  heap_close(conrel, AccessShareLock);
3990 
3991  if (found != ncheck)
3992  elog(ERROR, "%d constraint record(s) missing for rel %s",
3993  ncheck - found, RelationGetRelationName(relation));
3994 
3995  /* Sort the records so that CHECKs are applied in a deterministic order */
3996  if (ncheck > 1)
3997  qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
3998 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:736
char * ccname
Definition: tupdesc.h:32
bool ccnoinherit
Definition: tupdesc.h:35
ConstrCheck * check
Definition: tupdesc.h:42
char * ccbin
Definition: tupdesc.h:33
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4004
#define AccessShareLock
Definition: lockdefs.h:36
#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:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define TextDatumGetCString(d)
Definition: builtins.h:96
uintptr_t Datum
Definition: postgres.h:365
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
TupleConstr * constr
Definition: tupdesc.h:87
bool ccvalid
Definition: tupdesc.h:34
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1148
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
uint16 num_check
Definition: tupdesc.h:45
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:421
#define RelationGetRelid(relation)
Definition: rel.h:407
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ConstraintRelidIndexId
Definition: indexing.h:125
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ equalPartitionDescs()

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

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

1011 {
1012  int i;
1013 
1014  if (partdesc1 != NULL)
1015  {
1016  if (partdesc2 == NULL)
1017  return false;
1018  if (partdesc1->nparts != partdesc2->nparts)
1019  return false;
1020 
1021  Assert(key != NULL || partdesc1->nparts == 0);
1022 
1023  /*
1024  * Same oids? If the partitioning structure did not change, that is,
1025  * no partitions were added or removed to the relation, the oids array
1026  * should still match element-by-element.
1027  */
1028  for (i = 0; i < partdesc1->nparts; i++)
1029  {
1030  if (partdesc1->oids[i] != partdesc2->oids[i])
1031  return false;
1032  }
1033 
1034  /*
1035  * Now compare partition bound collections. The logic to iterate over
1036  * the collections is private to partition.c.
1037  */
1038  if (partdesc1->boundinfo != NULL)
1039  {
1040  if (partdesc2->boundinfo == NULL)
1041  return false;
1042 
1044  key->parttypbyval,
1045  partdesc1->boundinfo,
1046  partdesc2->boundinfo))
1047  return false;
1048  }
1049  else if (partdesc2->boundinfo != NULL)
1050  return false;
1051  }
1052  else if (partdesc2 != NULL)
1053  return false;
1054 
1055  return true;
1056 }
PartitionBoundInfo boundinfo
Definition: partition.h:30
bool * parttypbyval
Definition: partcache.h:44
#define Assert(condition)
Definition: c.h:699
int16 * parttyplen
Definition: partcache.h:43
bool partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
Definition: partbounds.c:104
int i

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

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

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

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

Referenced by RelationClearRelation().

977 {
978  ListCell *lc,
979  *rc;
980 
981  if (rsdesc1 == NULL && rsdesc2 == NULL)
982  return true;
983 
984  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
985  (rsdesc1 == NULL && rsdesc2 != NULL))
986  return false;
987 
988  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
989  return false;
990 
991  /* RelationBuildRowSecurity should build policies in order */
992  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
993  {
996 
997  if (!equalPolicy(l, r))
998  return false;
999  }
1000 
1001  return true;
1002 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:930
#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 885 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().

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

5193 {
5197 
5198  return 0; /* return value does not matter */
5199 }
#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:3051
#define RelationGetRelationName(relation)
Definition: rel.h:441
int err_generic_string(int field, const char *str)
Definition: elog.c:1191
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5209 of file relcache.c.

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

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

5210 {
5211  TupleDesc reldesc = RelationGetDescr(rel);
5212  const char *colname;
5213 
5214  /* Use reldesc if it's a user attribute, else consult the catalogs */
5215  if (attnum > 0 && attnum <= reldesc->natts)
5216  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5217  else
5218  colname = get_attname(RelationGetRelid(rel), attnum, false);
5219 
5220  return errtablecolname(rel, colname);
5221 }
#define RelationGetDescr(relation)
Definition: rel.h:433
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
NameData attname
Definition: pg_attribute.h:40
int16 attnum
Definition: pg_attribute.h:79
#define NameStr(name)
Definition: c.h:576
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:775
#define RelationGetRelid(relation)
Definition: rel.h:407
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5233

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5233 of file relcache.c.

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

Referenced by errtablecol().

5234 {
5235  errtable(rel);
5237 
5238  return 0; /* return value does not matter */
5239 }
#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:5192

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

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

5247 {
5248  errtable(rel);
5250 
5251  return 0; /* return value does not matter */
5252 }
#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:5192

◆ formrdesc()

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

Definition at line 1726 of file relcache.c.

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

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

1729 {
1730  Relation relation;
1731  int i;
1732  bool has_not_null;
1733 
1734  /*
1735  * allocate new relation desc, clear all fields of reldesc
1736  */
1737  relation = (Relation) palloc0(sizeof(RelationData));
1738 
1739  /* make sure relation is marked as having no open file yet */
1740  relation->rd_smgr = NULL;
1741 
1742  /*
1743  * initialize reference count: 1 because it is nailed in cache
1744  */
1745  relation->rd_refcnt = 1;
1746 
1747  /*
1748  * all entries built with this routine are nailed-in-cache; none are for
1749  * new or temp relations.
1750  */
1751  relation->rd_isnailed = true;
1754  relation->rd_backend = InvalidBackendId;
1755  relation->rd_islocaltemp = false;
1756 
1757  /*
1758  * initialize relation tuple form
1759  *
1760  * The data we insert here is pretty incomplete/bogus, but it'll serve to
1761  * get us launched. RelationCacheInitializePhase3() will read the real
1762  * data from pg_class and replace what we've done here. Note in
1763  * particular that relowner is left as zero; this cues
1764  * RelationCacheInitializePhase3 that the real data isn't there yet.
1765  */
1767 
1768  namestrcpy(&relation->rd_rel->relname, relationName);
1769  relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1770  relation->rd_rel->reltype = relationReltype;
1771 
1772  /*
1773  * It's important to distinguish between shared and non-shared relations,
1774  * even at bootstrap time, to make sure we know where they are stored.
1775  */
1776  relation->rd_rel->relisshared = isshared;
1777  if (isshared)
1778  relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1779 
1780  /* formrdesc is used only for permanent relations */
1781  relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1782 
1783  /* ... and they're always populated, too */
1784  relation->rd_rel->relispopulated = true;
1785 
1786  relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1787  relation->rd_rel->relpages = 0;
1788  relation->rd_rel->reltuples = 0;
1789  relation->rd_rel->relallvisible = 0;
1790  relation->rd_rel->relkind = RELKIND_RELATION;
1791  relation->rd_rel->relhasoids = hasoids;
1792  relation->rd_rel->relnatts = (int16) natts;
1793 
1794  /*
1795  * initialize attribute tuple form
1796  *
1797  * Unlike the case with the relation tuple, this data had better be right
1798  * because it will never be replaced. The data comes from
1799  * src/include/catalog/ headers via genbki.pl.
1800  */
1801  relation->rd_att = CreateTemplateTupleDesc(natts, hasoids);
1802  relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1803 
1804  relation->rd_att->tdtypeid = relationReltype;
1805  relation->rd_att->tdtypmod = -1; /* unnecessary, but... */
1806 
1807  /*
1808  * initialize tuple desc info
1809  */
1810  has_not_null = false;
1811  for (i = 0; i < natts; i++)
1812  {
1813  memcpy(TupleDescAttr(relation->rd_att, i),
1814  &attrs[i],
1816  has_not_null |= attrs[i].attnotnull;
1817  /* make sure attcacheoff is valid */
1818  TupleDescAttr(relation->rd_att, i)->attcacheoff = -1;
1819  }
1820 
1821  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
1822  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
1823 
1824  /* mark not-null status */
1825  if (has_not_null)
1826  {
1827  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1828 
1829  constr->has_not_null = true;
1830  relation->rd_att->constr = constr;
1831  }
1832 
1833  /*
1834  * initialize relation id from info in att array (my, this is ugly)
1835  */
1836  RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
1837 
1838  /*
1839  * All relations made with formrdesc are mapped. This is necessarily so
1840  * because there is no other way to know what filenode they currently
1841  * have. In bootstrap mode, add them to the initial relation mapper data,
1842  * specifying that the initial filenode is the same as the OID.
1843  */
1844  relation->rd_rel->relfilenode = InvalidOid;
1847  RelationGetRelid(relation),
1848  isshared, true);
1849 
1850  /*
1851  * initialize the relation lock manager information
1852  */
1853  RelationInitLockInfo(relation); /* see lmgr.c */
1854 
1855  /*
1856  * initialize physical addressing information for the relation
1857  */
1858  RelationInitPhysicalAddr(relation);
1859 
1860  /*
1861  * initialize the rel-has-index flag, using hardwired knowledge
1862  */
1864  {
1865  /* In bootstrap mode, we have no indexes */
1866  relation->rd_rel->relhasindex = false;
1867  }
1868  else
1869  {
1870  /* Otherwise, all the rels formrdesc is used for have indexes */
1871  relation->rd_rel->relhasindex = true;
1872  }
1873 
1874  /*
1875  * add new reldesc to relcache
1876  */
1877  RelationCacheInsert(relation, false);
1878 
1879  /* It's fully valid */
1880  relation->rd_isvalid = true;
1881 }
signed short int16
Definition: c.h:312
Oid tdtypeid
Definition: tupdesc.h:83
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Form_pg_class rd_rel
Definition: rel.h:84
int namestrcpy(Name name, const char *str)
Definition: name.c:216
int32 tdtypmod
Definition: tupdesc.h:84
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:189
bool has_not_null
Definition: tupdesc.h:46
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:955
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:182
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:84
BackendId rd_backend
Definition: rel.h:59
TupleConstr * constr
Definition: tupdesc.h:87
#define InvalidSubTransactionId
Definition: c.h:480
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
int rd_refcnt
Definition: rel.h:58
int tdrefcount
Definition: tupdesc.h:86
int i
#define RelationGetRelid(relation)
Definition: rel.h:407
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 3832 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

3833 {
3834  static TupleDesc pgclassdesc = NULL;
3835 
3836  /* Already done? */
3837  if (pgclassdesc == NULL)
3838  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
3839  Desc_pg_class,
3840  true);
3841 
3842  return pgclassdesc;
3843 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, bool hasoids)
Definition: relcache.c:3801
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:102

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 3846 of file relcache.c.

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

3847 {
3848  static TupleDesc pgindexdesc = NULL;
3849 
3850  /* Already done? */
3851  if (pgindexdesc == NULL)
3852  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
3853  Desc_pg_index,
3854  false);
3855 
3856  return pgindexdesc;
3857 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs, bool hasoids)
Definition: relcache.c:3801
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:109

◆ GetRelationPublicationActions()

struct PublicationActions* GetRelationPublicationActions ( Relation  relation)

Definition at line 5120 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::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubactions, RelationGetRelid, ReleaseSysCache(), and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

5121 {
5122  List *puboids;
5123  ListCell *lc;
5124  MemoryContext oldcxt;
5125  PublicationActions *pubactions = palloc0(sizeof(PublicationActions));
5126 
5127  if (relation->rd_pubactions)
5128  return memcpy(pubactions, relation->rd_pubactions,
5129  sizeof(PublicationActions));
5130 
5131  /* Fetch the publication membership info. */
5132  puboids = GetRelationPublications(RelationGetRelid(relation));
5133  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5134 
5135  foreach(lc, puboids)
5136  {
5137  Oid pubid = lfirst_oid(lc);
5138  HeapTuple tup;
5139  Form_pg_publication pubform;
5140 
5142 
5143  if (!HeapTupleIsValid(tup))
5144  elog(ERROR, "cache lookup failed for publication %u", pubid);
5145 
5146  pubform = (Form_pg_publication) GETSTRUCT(tup);
5147 
5148  pubactions->pubinsert |= pubform->pubinsert;
5149  pubactions->pubupdate |= pubform->pubupdate;
5150  pubactions->pubdelete |= pubform->pubdelete;
5151  pubactions->pubtruncate |= pubform->pubtruncate;
5152 
5153  ReleaseSysCache(tup);
5154 
5155  /*
5156  * If we know everything is replicated, there is no point to check for
5157  * other publications.
5158  */
5159  if (pubactions->pubinsert && pubactions->pubupdate &&
5160  pubactions->pubdelete && pubactions->pubtruncate)
5161  break;
5162  }
5163 
5164  if (relation->rd_pubactions)
5165  {
5166  pfree(relation->rd_pubactions);
5167  relation->rd_pubactions = NULL;
5168  }
5169 
5170  /* Now save copy of the actions in the relcache entry. */
5172  relation->rd_pubactions = palloc(sizeof(PublicationActions));
5173  memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions));
5174  MemoryContextSwitchTo(oldcxt);
5175 
5176  return pubactions;
5177 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
PublicationActions * rd_pubactions
Definition: rel.h:121
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:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void * palloc0(Size size)
Definition: mcxt.c:955
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * GetAllTablesPublications(void)
void * palloc(Size size)
Definition: mcxt.c:924
#define elog
Definition: elog.h:219
FormData_pg_publication * Form_pg_publication
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ IndexSupportInitialize()

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

Definition at line 1511 of file relcache.c.

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

Referenced by RelationInitIndexAccessInfo().

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

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

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

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

◆ insert_ordered_oid()

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

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

4397 {
4398  ListCell *prev;
4399 
4400  /* Does the datum belong at the front? */
4401  if (list == NIL || datum < linitial_oid(list))
4402  return lcons_oid(datum, list);
4403  /* No, so find the entry it belongs after */
4404  prev = list_head(list);
4405  for (;;)
4406  {
4407  ListCell *curr = lnext(prev);
4408 
4409  if (curr == NULL || datum < lfirst_oid(curr))
4410  break; /* it belongs after 'prev', before 'curr' */
4411 
4412  prev = curr;
4413  }
4414  /* Insert datum into list after 'prev' */
4415  lappend_cell_oid(list, prev, datum);
4416  return list;
4417 }
#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

◆ IsProjectionFunctionalIndex()

static bool IsProjectionFunctionalIndex ( Relation  index,
IndexInfo ii 
)
static

Definition at line 4681 of file relcache.c.

References cost_qual_eval(), elog, ERROR, HeapTupleIsValid, HEURISTIC_MAX_HOT_RECHECK_EXPR_COST, IndexInfo::ii_Expressions, index_generic_reloptions(), ObjectIdGetDatum, QualCost::per_tuple, pfree(), GenericIndexOpts::recheck_on_update, RelationGetRelid, ReleaseSysCache(), RELOID, SearchSysCache1(), QualCost::startup, and SysCacheGetAttr().

Referenced by RelationGetIndexAttrBitmap().

4682 {
4683  bool is_projection = false;
4684 
4685  if (ii->ii_Expressions)
4686  {
4687  HeapTuple tuple;
4688  Datum reloptions;
4689  bool isnull;
4690  QualCost index_expr_cost;
4691 
4692  /* by default functional index is considered as non-injective */
4693  is_projection = true;
4694 
4695  cost_qual_eval(&index_expr_cost, ii->ii_Expressions, NULL);
4696 
4697  /*
4698  * If index expression is too expensive, then disable projection
4699  * optimization, because extra evaluation of index expression is
4700  * expected to be more expensive than index update. Currently the
4701  * projection optimization has to calculate index expression twice
4702  * when the value of index expression has not changed and three times
4703  * when values differ because the expression is recalculated when
4704  * inserting a new index entry for the changed value.
4705  */
4706  if ((index_expr_cost.startup + index_expr_cost.per_tuple) >
4708  is_projection = false;
4709 
4711  if (!HeapTupleIsValid(tuple))
4712  elog(ERROR, "cache lookup failed for relation %u", RelationGetRelid(index));
4713 
4714  reloptions = SysCacheGetAttr(RELOID, tuple,
4715  Anum_pg_class_reloptions, &isnull);
4716  if (!isnull)
4717  {
4718  GenericIndexOpts *idxopts;
4719 
4720  idxopts = (GenericIndexOpts *) index_generic_reloptions(reloptions, false);
4721 
4722  if (idxopts != NULL)
4723  {
4724  is_projection = idxopts->recheck_on_update;
4725  pfree(idxopts);
4726  }
4727  }
4728  ReleaseSysCache(tuple);
4729  }
4730  return is_projection;
4731 }
bool recheck_on_update
Definition: rel.h:226
Cost startup
Definition: relation.h:46
Cost per_tuple
Definition: relation.h:47
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:3716
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
uintptr_t Datum
Definition: postgres.h:365
#define HEURISTIC_MAX_HOT_RECHECK_EXPR_COST
Definition: relcache.c:4666
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
bytea * index_generic_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1496
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 3767 of file relcache.c.

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

Referenced by RelationCacheInitializePhase3().

3768 {
3769  Relation ird;
3770 
3771  /*
3772  * We must lock the underlying catalog before locking the index to avoid
3773  * deadlock, since RelationBuildDesc might well need to read the catalog,
3774  * and if anyone else is exclusive-locking this catalog and index they'll
3775  * be doing it in that order.
3776  */
3777  LockRelationOid(heapoid, AccessShareLock);
3778  LockRelationOid(indexoid, AccessShareLock);
3779  ird = RelationBuildDesc(indexoid, true);
3780  if (ird == NULL)
3781  elog(PANIC, "could not open critical system index %u", indexoid);
3782  ird->rd_isnailed = true;
3783  ird->rd_refcnt = 1;
3786 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
bool rd_isnailed
Definition: rel.h:61
#define AccessShareLock
Definition: lockdefs.h:36
#define PANIC
Definition: elog.h:53
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1071
int rd_refcnt
Definition: rel.h:58
#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 5310 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(), MemoryContextCopyAndSetIdentifier, MemSet, NIL, NUM_CRITICAL_LOCAL_INDEXES, NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_SHARED_INDEXES, NUM_CRITICAL_SHARED_RELS, palloc(), palloc0(), pfree(), PG_BINARY_R, RelationData::pgstat_info, RelationData::rd_amcache, RelationData::rd_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_projidx, RelationData::rd_projindexattr, 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, repalloc(), snprintf(), HeapTupleData::t_data, tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, TupleDescAttr, VARSIZE, and WARNING.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

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

◆ LookupOpclassInfo()

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

Definition at line 1562 of file relcache.c.

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

Referenced by IndexSupportInitialize().

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1071 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(), ScanPgRelation(), and RelationData::trigdesc.

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

1072 {
1073  Relation relation;
1074  Oid relid;
1075  HeapTuple pg_class_tuple;
1076  Form_pg_class relp;
1077 
1078  /*
1079  * find the tuple in pg_class corresponding to the given relation id
1080  */
1081  pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1082 
1083  /*
1084  * if no such tuple exists, return NULL
1085  */
1086  if (!HeapTupleIsValid(pg_class_tuple))
1087  return NULL;
1088 
1089  /*
1090  * get information from the pg_class_tuple
1091  */
1092  relid = HeapTupleGetOid(pg_class_tuple);
1093  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1094  Assert(relid == targetRelId);
1095 
1096  /*
1097  * allocate storage for the relation descriptor, and copy pg_class_tuple
1098  * to relation->rd_rel.
1099  */
1100  relation = AllocateRelationDesc(relp);
1101 
1102  /*
1103  * initialize the relation's relation id (relation->rd_id)
1104  */
1105  RelationGetRelid(relation) = relid;
1106 
1107  /*
1108  * normal relations are not nailed into the cache; nor can a pre-existing
1109  * relation be new. It could be temp though. (Actually, it could be new
1110  * too, but it's okay to forget that fact if forced to flush the entry.)
1111  */
1112  relation->rd_refcnt = 0;
1113  relation->rd_isnailed = false;
1116  switch (relation->rd_rel->relpersistence)
1117  {
1118  case RELPERSISTENCE_UNLOGGED:
1119  case RELPERSISTENCE_PERMANENT:
1120  relation->rd_backend = InvalidBackendId;
1121  relation->rd_islocaltemp = false;
1122  break;
1123  case RELPERSISTENCE_TEMP:
1124  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1125  {
1126  relation->rd_backend = BackendIdForTempRelations();
1127  relation->rd_islocaltemp = true;
1128  }
1129  else
1130  {
1131  /*
1132  * If it's a temp table, but not one of ours, we have to use
1133  * the slow, grotty method to figure out the owning backend.
1134  *
1135  * Note: it's possible that rd_backend gets set to MyBackendId
1136  * here, in case we are looking at a pg_class entry left over
1137  * from a crashed backend that coincidentally had the same
1138  * BackendId we're using. We should *not* consider such a
1139  * table to be "ours"; this is why we need the separate
1140  * rd_islocaltemp flag. The pg_class entry will get flushed
1141  * if/when we clean out the corresponding temp table namespace
1142  * in preparation for using it.
1143  */
1144  relation->rd_backend =
1145  GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
1146  Assert(relation->rd_backend != InvalidBackendId);
1147  relation->rd_islocaltemp = false;
1148  }
1149  break;
1150  default:
1151  elog(ERROR, "invalid relpersistence: %c",
1152  relation->rd_rel->relpersistence);
1153  break;
1154  }
1155 
1156  /*
1157  * initialize the tuple descriptor (relation->rd_att).
1158  */
1159  RelationBuildTupleDesc(relation);
1160 
1161  /*
1162  * Fetch rules and triggers that affect this relation
1163  */
1164  if (relation->rd_rel->relhasrules)
1165  RelationBuildRuleLock(relation);
1166  else
1167  {
1168  relation->rd_rules = NULL;
1169  relation->rd_rulescxt = NULL;
1170  }
1171 
1172  if (relation->rd_rel->relhastriggers)
1173  RelationBuildTriggers(relation);
1174  else
1175  relation->trigdesc = NULL;
1176 
1177  if (relation->rd_rel->relrowsecurity)
1178  RelationBuildRowSecurity(relation);
1179  else
1180  relation->rd_rsdesc = NULL;
1181 
1182  /* foreign key data is not loaded till asked for */
1183  relation->rd_fkeylist = NIL;
1184  relation->rd_fkeyvalid = false;
1185 
1186  /* if a partitioned table, initialize key and partition descriptor info */
1187  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1188  {
1189  RelationBuildPartitionKey(relation);
1190  RelationBuildPartitionDesc(relation);
1191  }
1192  else
1193  {
1194  relation->rd_partkeycxt = NULL;
1195  relation->rd_partkey = NULL;
1196  relation->rd_partdesc = NULL;
1197  relation->rd_pdcxt = NULL;
1198  }
1199 
1200  /*
1201  * if it's an index, initialize index-related information
1202  */
1203  if (OidIsValid(relation->rd_rel->relam))
1204  RelationInitIndexAccessInfo(relation);
1205 
1206  /* extract reloptions if any */
1207  RelationParseRelOptions(relation, pg_class_tuple);
1208 
1209  /*
1210  * initialize the relation lock manager information
1211  */
1212  RelationInitLockInfo(relation); /* see lmgr.c */
1213 
1214  /*
1215  * initialize physical addressing information for the relation
1216  */
1217  RelationInitPhysicalAddr(relation);
1218 
1219  /* make sure relation is marked as having no open file yet */
1220  relation->rd_smgr = NULL;
1221 
1222  /*
1223  * now we can free the memory allocated for pg_class_tuple
1224  */
1225  heap_freetuple(pg_class_tuple);
1226 
1227  /*
1228  * Insert newly created relation into relcache hash table, if requested.
1229  *
1230  * There is one scenario in which we might find a hashtable entry already
1231  * present, even though our caller failed to find it: if the relation is a
1232  * system catalog or index that's used during relcache load, we might have
1233  * recursively created the same relcache entry during the preceding steps.
1234  * So allow RelationCacheInsert to delete any already-present relcache
1235  * entry for the same OID. The already-present entry should have refcount
1236  * zero (else somebody forgot to close it); in the event that it doesn't,
1237  * we'll elog a WARNING and leak the already-present entry.
1238  */
1239  if (insertIt)
1240  RelationCacheInsert(relation, true);
1241 
1242  /* It's fully valid */
1243  relation->rd_isvalid = true;
1244 
1245  return relation;
1246 }
#define NIL
Definition: pg_list.h:69
struct PartitionDescData * rd_partdesc
Definition: rel.h:101
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:191
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3161
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
List * rd_fkeylist
Definition: rel.h:95
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3214
MemoryContext rd_rulescxt
Definition: rel.h:89
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:379
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
void RelationBuildPartitionDesc(Relation rel)
Definition: partcache.c:261
struct PartitionKeyData * rd_partkey
Definition: rel.h:99
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define BackendIdForTempRelations()
Definition: backendid.h:34
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:435
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:492
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:182
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
MemoryContext rd_pdcxt
Definition: rel.h:100
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:699
MemoryContext rd_partkeycxt
Definition: rel.h:98
RuleLock * rd_rules
Definition: rel.h:88
#define InvalidSubTransactionId
Definition: c.h:480
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1343
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
void RelationBuildPartitionKey(Relation relation)
Definition: partcache.c:64
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1910
int rd_refcnt
Definition: rel.h:58
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:309
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:724
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
bool rd_fkeyvalid
Definition: rel.h:96
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ 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 3024 of file relcache.c.

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

Referenced by heap_create().

3034 {
3035  Relation rel;
3036  MemoryContext oldcxt;
3037  int natts = tupDesc->natts;
3038  int i;
3039  bool has_not_null;
3040  bool nailit;
3041 
3042  AssertArg(natts >= 0);
3043 
3044  /*
3045  * check for creation of a rel that must be nailed in cache.
3046  *
3047  * XXX this list had better match the relations specially handled in
3048  * RelationCacheInitializePhase2/3.
3049  */
3050  switch (relid)
3051  {
3052  case DatabaseRelationId:
3053  case AuthIdRelationId:
3054  case AuthMemRelationId:
3055  case RelationRelationId:
3056  case AttributeRelationId:
3057  case ProcedureRelationId:
3058  case TypeRelationId:
3059  nailit = true;
3060  break;
3061  default:
3062  nailit = false;
3063  break;
3064  }
3065 
3066  /*
3067  * check that hardwired list of shared rels matches what's in the
3068  * bootstrap .bki file. If you get a failure here during initdb, you
3069  * probably need to fix IsSharedRelation() to match whatever you've done
3070  * to the set of shared relations.
3071  */
3072  if (shared_relation != IsSharedRelation(relid))
3073  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3074  relname, relid);
3075 
3076  /* Shared relations had better be mapped, too */
3077  Assert(mapped_relation || !shared_relation);
3078 
3079  /*
3080  * switch to the cache context to create the relcache entry.
3081  */
3082  if (!CacheMemoryContext)
3084 
3086 
3087  /*
3088  * allocate a new relation descriptor and fill in basic state fields.
3089  */
3090  rel = (Relation) palloc0(sizeof(RelationData));
3091 
3092  /* make sure relation is marked as having no open file yet */
3093  rel->rd_smgr = NULL;
3094 
3095  /* mark it nailed if appropriate */
3096  rel->rd_isnailed = nailit;
3097 
3098  rel->rd_refcnt = nailit ? 1 : 0;
3099 
3100  /* it's being created in this transaction */
3103 
3104  /*
3105  * create a new tuple descriptor from the one passed in. We do this
3106  * partly to copy it into the cache context, and partly because the new
3107  * relation can't have any defaults or constraints yet; they have to be
3108  * added in later steps, because they require additions to multiple system
3109  * catalogs. We can copy attnotnull constraints here, however.
3110  */
3111  rel->rd_att = CreateTupleDescCopy(tupDesc);
3112  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3113  has_not_null = false;
3114  for (i = 0; i < natts; i++)
3115  {
3116  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3117  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3118 
3119  datt->attidentity = satt->attidentity;
3120  datt->attnotnull = satt->attnotnull;
3121  has_not_null |= satt->attnotnull;
3122  }
3123 
3124  if (has_not_null)
3125  {
3126  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3127 
3128  constr->has_not_null = true;
3129  rel->rd_att->constr = constr;
3130  }
3131 
3132  /*
3133  * initialize relation tuple form (caller may add/override data later)
3134  */
3136 
3137  namestrcpy(&rel->rd_rel->relname, relname);
3138  rel->rd_rel->relnamespace = relnamespace;
3139 
3140  rel->rd_rel->relkind = relkind;
3141  rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
3142  rel->rd_rel->relnatts = natts;
3143  rel->rd_rel->reltype = InvalidOid;
3144  /* needed when bootstrapping: */
3145  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3146 
3147  /* set up persistence and relcache fields dependent on it */
3148  rel->rd_rel->relpersistence = relpersistence;
3149  switch (relpersistence)
3150  {
3151  case RELPERSISTENCE_UNLOGGED:
3152  case RELPERSISTENCE_PERMANENT:
3154  rel->rd_islocaltemp = false;
3155  break;
3156  case RELPERSISTENCE_TEMP:
3159  rel->rd_islocaltemp = true;
3160  break;
3161  default:
3162  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3163  break;
3164  }
3165 
3166  /* if it's a materialized view, it's not populated initially */
3167  if (relkind == RELKIND_MATVIEW)
3168  rel->rd_rel->relispopulated = false;
3169  else
3170  rel->rd_rel->relispopulated = true;
3171 
3172  /* system relations and non-table objects don't have one */
3174  (relkind == RELKIND_RELATION ||
3175  relkind == RELKIND_MATVIEW ||
3176  relkind == RELKIND_PARTITIONED_TABLE))
3177  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3178  else
3179  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3180 
3181  /*
3182  * Insert relation physical and logical identifiers (OIDs) into the right
3183  * places. For a mapped relation, we set relfilenode to zero and rely on
3184  * RelationInitPhysicalAddr to consult the map.
3185  */
3186  rel->rd_rel->relisshared = shared_relation;
3187 
3188  RelationGetRelid(rel) = relid;
3189 
3190  for (i = 0; i < natts; i++)
3191  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3192 
3193  rel->rd_rel->reltablespace = reltablespace;
3194 
3195  if (mapped_relation)
3196  {
3197  rel->rd_rel->relfilenode = InvalidOid;
3198  /* Add it to the active mapping information */
3199  RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
3200  }
3201  else
3202  rel->rd_rel->relfilenode = relfilenode;
3203 
3204  RelationInitLockInfo(rel); /* see lmgr.c */
3205 
3207 
3208  /*
3209  * Okay to insert into the relcache hash table.
3210  *
3211  * Ordinarily, there should certainly not be an existing hash entry for
3212  * the same OID; but during bootstrap, when we create a "real" relcache
3213  * entry for one of the bootstrap relations, we'll be overwriting the
3214  * phony one created with formrdesc. So allow that to happen for nailed
3215  * rels.
3216  */
3217  RelationCacheInsert(rel, nailit);
3218 
3219  /*
3220  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3221  * can't do this before storing relid in it.
3222  */
3223  EOXactListAdd(rel);
3224 
3225  /*
3226  * done building relcache entry.
3227  */
3228  MemoryContextSwitchTo(oldcxt);
3229 
3230  /* It's fully valid */
3231  rel->rd_isvalid = true;
3232 
3233  /*
3234  * Caller expects us to pin the returned entry.
3235  */
3237 
3238  return rel;
3239 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:112
#define EOXactListAdd(rel)
Definition: relcache.c:162
Oid relnamespace
Definition: pg_class.h:32
bool tdhasoid
Definition: tupdesc.h:85
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3161
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool rd_isnailed
Definition: rel.h:61
bool rd_islocaltemp
Definition: rel.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool rd_isvalid
Definition: rel.h:62
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
Form_pg_class rd_rel
Definition: rel.h:84
int namestrcpy(Name name, const char *str)
Definition: name.c:216
int natts
Definition: tupdesc.h:82
char relkind
Definition: pg_class.h:51
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:50
Oid relfilenode
Definition: pg_class.h:39
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:68
#define BackendIdForTempRelations()
Definition: backendid.h:34
Oid reltablespace
Definition: pg_class.h:42
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define AssertArg(condition)
Definition: c.h:701
bool has_not_null
Definition: tupdesc.h:46
SubTransactionId rd_createSubid
Definition: rel.h:80
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:955
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:1963
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:220
TupleDesc rd_att
Definition: rel.h:85
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:163
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:182
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:84
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:699
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
TupleConstr * constr
Definition: tupdesc.h:87
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
#define InvalidSubTransactionId
Definition: c.h:480
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
int rd_refcnt
Definition: rel.h:58
int tdrefcount
Definition: tupdesc.h:86
int i
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 724 of file relcache.c.

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

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

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 492 of file relcache.c.

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

Referenced by RelationBuildDesc().

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

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6031 of file relcache.c.

References LWLockRelease().

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

6032 {
6033  LWLockRelease(RelCacheInitLock);
6034 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

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

6006 {
6007  char initfilename[MAXPGPATH];
6008 
6009  snprintf(initfilename, sizeof(initfilename), "%s/%s",
6011 
6012  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6013 
6014  if (unlink(initfilename) < 0)
6015  {
6016  /*
6017  * The file might not be there if no backend has been started since
6018  * the last removal. But complain about failures other than ENOENT.
6019  * Fortunately, it's not too late to abort the transaction if we can't
6020  * get rid of the would-be-obsolete init file.
6021  */
6022  if (errno != ENOENT)
6023  ereport(ERROR,
6025  errmsg("could not remove cache file \"%s\": %m",
6026  initfilename)));
6027  }
6028 }
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:94
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

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

6047 {
6048  const char *tblspcdir = "pg_tblspc";
6049  DIR *dir;
6050  struct dirent *de;
6051  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6052 
6053  /*
6054  * We zap the shared cache file too. In theory it can't get out of sync
6055  * enough to be a problem, but in data-corruption cases, who knows ...
6056  */
6057  snprintf(path, sizeof(path), "global/%s",
6059  unlink_initfile(path);
6060 
6061  /* Scan everything in the default tablespace */
6063 
6064  /* Scan the tablespace link directory to find non-default tablespaces */
6065  dir = AllocateDir(tblspcdir);
6066 
6067  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6068  {
6069  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6070  {
6071  /* Scan the tablespace dir for per-database dirs */
6072  snprintf(path, sizeof(path), "%s/%s/%s",
6073  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6075  }
6076  }
6077 
6078  FreeDir(dir);
6079 }
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6083
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2681
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
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2600
static void unlink_initfile(const char *initfilename)
Definition: relcache.c:6107
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2718

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6083 of file relcache.c.

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

Referenced by RelationCacheInitFileRemove().

6084 {
6085  DIR *dir;
6086  struct dirent *de;
6087  char initfilename[MAXPGPATH * 2];
6088 
6089  /* Scan the tablespace directory to find per-database directories */
6090  dir = AllocateDir(tblspcpath);
6091 
6092  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6093  {
6094  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6095  {
6096  /* Try to remove the init file in each database */
6097  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6098  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6099  unlink_initfile(initfilename);
6100  }
6101  }
6102 
6103  FreeDir(dir);
6104 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2681
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:2600
static void unlink_initfile(const char *initfilename)
Definition: relcache.c:6107
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2718

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3376 of file relcache.c.

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

Referenced by InitPostgres().

3377 {
3378  HASHCTL ctl;
3379 
3380  /*
3381  * make sure cache memory context exists
3382  */
3383  if (!CacheMemoryContext)
3385 
3386  /*
3387  * create hashtable that indexes the relcache
3388  */
3389  MemSet(&ctl, 0, sizeof(ctl));
3390  ctl.keysize = sizeof(Oid);
3391  ctl.entrysize = sizeof(RelIdCacheEnt);
3392  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3393  &ctl, HASH_ELEM | HASH_BLOBS);
3394 
3395  /*
3396  * relation mapper needs to be initialized too
3397  */
3399 }
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:908
static HTAB * RelationIdCache
Definition: relcache.c:125
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:3373
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3413 of file relcache.c.

References CacheMemoryContext, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, Desc_pg_shseclabel, Desc_pg_subscription, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), and RelationMapInitializePhase2().

Referenced by InitPostgres().

3414 {
3415  MemoryContext oldcxt;
3416 
3417  /*
3418  * relation mapper needs initialized too
3419  */
3421 
3422  /*
3423  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3424  * nothing.
3425  */
3427  return;
3428 
3429  /*
3430  * switch to cache memory context
3431  */
3433 
3434  /*
3435  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3436  * the cache with pre-made descriptors for the critical shared catalogs.
3437  */
3438  if (!load_relcache_init_file(true))
3439  {
3440  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3441  true, Natts_pg_database, Desc_pg_database);
3442  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3443  true, Natts_pg_authid, Desc_pg_authid);
3444  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3445  false, Natts_pg_auth_members, Desc_pg_auth_members);
3446  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3447  false, Natts_pg_shseclabel, Desc_pg_shseclabel);
3448  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3449  true, Natts_pg_subscription, Desc_pg_subscription);
3450 
3451 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3452  }
3453 
3454  MemoryContextSwitchTo(oldcxt);
3455 }
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:108
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5310
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, bool hasoids, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1726
void RelationMapInitializePhase2(void)
Definition: relmapper.c:582
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:107
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:111
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:106
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:110
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 3472 of file relcache.c.

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

Referenced by InitPostgres().

3473 {
3475  RelIdCacheEnt *idhentry;
3476  MemoryContext oldcxt;
3477  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3478 
3479  /*
3480  * relation mapper needs initialized too
3481  */
3483 
3484  /*
3485  * switch to cache memory context
3486  */
3488 
3489  /*
3490  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3491  * the cache with pre-made descriptors for the critical "nailed-in" system
3492  * catalogs.
3493  */
3494  if (IsBootstrapProcessingMode() ||
3495  !load_relcache_init_file(false))
3496  {
3497  needNewCacheFile = true;
3498 
3499  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
3500  true, Natts_pg_class, Desc_pg_class);
3501  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
3502  false, Natts_pg_attribute, Desc_pg_attribute);
3503  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
3504  true, Natts_pg_proc, Desc_pg_proc);
3505  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
3506  true, Natts_pg_type, Desc_pg_type);
3507 
3508 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
3509  }
3510 
3511  MemoryContextSwitchTo(oldcxt);
3512 
3513  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
3515  return;
3516 
3517  /*
3518  * If we didn't get the critical system indexes loaded into relcache, do
3519  * so now. These are critical because the catcache and/or opclass cache
3520  * depend on them for fetches done during relcache load. Thus, we have an
3521  * infinite-recursion problem. We can break the recursion by doing
3522  * heapscans instead of indexscans at certain key spots. To avoid hobbling
3523  * performance, we only want to do that until we have the critical indexes
3524  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
3525  * decide whether to do heapscan or indexscan at the key spots, and we set
3526  * it true after we've loaded the critical indexes.
3527  *
3528  * The critical indexes are marked as "nailed in cache", partly to make it
3529  * easy for load_relcache_init_file to count them, but mainly because we
3530  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
3531  * true. (NOTE: perhaps it would be possible to reload them by
3532  * temporarily setting criticalRelcachesBuilt to false again. For now,
3533  * though, we just nail 'em in.)
3534  *
3535  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
3536  * in the same way as the others, because the critical catalogs don't
3537  * (currently) have any rules or triggers, and so these indexes can be
3538  * rebuilt without inducing recursion. However they are used during
3539  * relcache load when a rel does have rules or triggers, so we choose to
3540  * nail them for performance reasons.
3541  */
3543  {
3545  RelationRelationId);
3547  AttributeRelationId);
3549  IndexRelationId);
3551  OperatorClassRelationId);
3553  AccessMethodProcedureRelationId);
3555  RewriteRelationId);
3557  TriggerRelationId);
3558 
3559 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
3560 
3561  criticalRelcachesBuilt = true;
3562  }
3563 
3564  /*
3565  * Process critical shared indexes too.
3566  *
3567  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
3568  * initial lookup of MyDatabaseId, without which we'll never find any
3569  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
3570  * database OID, so it instead depends on DatabaseOidIndexId. We also
3571  * need to nail up some indexes on pg_authid and pg_auth_members for use
3572  * during client authentication. SharedSecLabelObjectIndexId isn't
3573  * critical for the core system, but authentication hooks might be
3574  * interested in it.
3575  */
3577  {
3579  DatabaseRelationId);
3581  DatabaseRelationId);
3583  AuthIdRelationId);
3585  AuthIdRelationId);
3587  AuthMemRelationId);
3589  SharedSecLabelRelationId);
3590 
3591 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
3592 
3594  }
3595 
3596  /*
3597  * Now, scan all the relcache entries and update anything that might be
3598  * wrong in the results from formrdesc or the relcache cache file. If we
3599  * faked up relcache entries using formrdesc, then read the real pg_class
3600  * rows and replace the fake entries with them. Also, if any of the
3601  * relcache entries have rules, triggers, or security policies, load that
3602  * info the hard way since it isn't recorded in the cache file.
3603  *
3604  * Whenever we access the catalogs to read data, there is a possibility of
3605  * a shared-inval cache flush causing relcache entries to be removed.
3606  * Since hash_seq_search only guarantees to still work after the *current*
3607  * entry is removed, it's unsafe to continue the hashtable scan afterward.
3608  * We handle this by restarting the scan from scratch after each access.
3609  * This is theoretically O(N^2), but the number of entries that actually
3610  * need to be fixed is small enough that it doesn't matter.
3611  */
3612  hash_seq_init(&status, RelationIdCache);
3613 
3614  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3615  {
3616  Relation relation = idhentry->reldesc;
3617  bool restart = false;
3618 
3619  /*
3620  * Make sure *this* entry doesn't get flushed while we work with it.
3621  */
3623 
3624  /*
3625  * If it's a faked-up entry, read the real pg_class tuple.
3626  */
3627  if (relation->rd_rel->relowner == InvalidOid)
3628  {
3629  HeapTuple htup;
3630  Form_pg_class relp;
3631 
3632  htup = SearchSysCache1(RELOID,
3633  ObjectIdGetDatum(RelationGetRelid(relation)));
3634  if (!HeapTupleIsValid(htup))
3635  elog(FATAL, "cache lookup failed for relation %u",
3636  RelationGetRelid(relation));
3637  relp = (Form_pg_class) GETSTRUCT(htup);
3638 
3639  /*
3640  * Copy tuple to relation->rd_rel. (See notes in
3641  * AllocateRelationDesc())
3642  */
3643  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
3644 
3645  /* Update rd_options while we have the tuple */
3646  if (relation->rd_options)
3647  pfree(relation->rd_options);
3648  RelationParseRelOptions(relation, htup);
3649 
3650  /*
3651  * Check the values in rd_att were set up correctly. (We cannot
3652  * just copy them over now: formrdesc must have set up the rd_att
3653  * data correctly to start with, because it may already have been
3654  * copied into one or more catcache entries.)
3655  */
3656  Assert(relation->rd_att->tdtypeid == relp->reltype);
3657  Assert(relation->rd_att->tdtypmod == -1);
3658  Assert(relation->rd_att->tdhasoid == relp->relhasoids);
3659 
3660  ReleaseSysCache(htup);
3661 
3662  /* relowner had better be OK now, else we'll loop forever */
3663  if (relation->rd_rel->relowner == InvalidOid)
3664  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
3665  RelationGetRelationName(relation));
3666 
3667  restart = true;
3668  }
3669 
3670  /*
3671  * Fix data that isn't saved in relcache cache file.
3672  *
3673  * relhasrules or relhastriggers could possibly be wrong or out of
3674  * date. If we don't actually find any rules or triggers, clear the
3675  * local copy of the flag so that we don't get into an infinite loop
3676  * here. We don't make any attempt to fix the pg_class entry, though.
3677  */
3678  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
3679  {
3680  RelationBuildRuleLock(relation);
3681  if (relation->rd_rules == NULL)
3682  relation->rd_rel->relhasrules = false;
3683  restart = true;
3684  }
3685  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
3686  {
3687  RelationBuildTriggers(relation);
3688  if (relation->trigdesc == NULL)
3689  relation->rd_rel->relhastriggers = false;
3690  restart = true;
3691  }
3692 
3693  /*
3694  * Re-load the row security policies if the relation has them, since
3695  * they are not preserved in the cache. Note that we can never NOT
3696  * have a policy while relrowsecurity is true,
3697  * RelationBuildRowSecurity will create a single default-deny policy
3698  * if there is no policy defined in pg_policy.
3699  */
3700  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
3701  {
3702  RelationBuildRowSecurity(relation);
3703 
3704  Assert(relation->rd_rsdesc != NULL);
3705  restart = true;
3706  }
3707 
3708  /*
3709  * Reload the partition key and descriptor for a partitioned table.
3710  */
3711  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3712  relation->rd_partkey == NULL)
3713  {
3714  RelationBuildPartitionKey(relation);
3715  Assert(relation->rd_partkey != NULL);
3716 
3717  restart = true;
3718  }
3719 
3720  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
3721  relation->rd_partdesc == NULL)
3722  {
3723  RelationBuildPartitionDesc(relation);
3724  Assert(relation->rd_partdesc != NULL);
3725 
3726  restart = true;
3727  }
3728 
3729  /* Release hold on the relation */
3731 
3732  /* Now, restart the hashtable scan if needed */
3733  if (restart)
3734  {
3735  hash_seq_term(&status);
3736  hash_seq_init(&status, RelationIdCache);
3737  }
3738  }
3739 
3740  /*
3741  * Lastly, write out new relcache cache files if needed. We don't bother
3742  * to distinguish cases where only one of the two needs an update.
3743  */
3744  if (needNewCacheFile)
3745  {
3746  /*
3747  * Force all the catcaches to finish initializing and thereby open the
3748  * catalogs and indexes they use. This will preload the relcache with
3749  * entries for all the most important system catalogs and indexes, so
3750  * that the init files will be most useful for future backends.
3751  */
3753 
3754  /* now write the files */
3756  write_relcache_init_file(false);
3757  }
3758 }
#define AttributeRelidNumIndexId
Definition: indexing.h:93
struct PartitionDescData * rd_partdesc
Definition: rel.h:101
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5310
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, bool hasoids, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1726
Oid tdtypeid
Definition: tupdesc.h:83
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define IndexRelidIndexId
Definition: indexing.h:165
bool tdhasoid
Definition: tupdesc.h:85
#define RewriteRelRulenameIndexId
Definition: indexing.h:224
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:191
Relation reldesc
Definition: relcache.c:122
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool criticalSharedRelcachesBuilt
Definition: relcache.c:137
#define AuthIdOidIndexId
Definition: indexing.h:98
static HTAB * RelationIdCache
Definition: relcache.c:125
Form_pg_class rd_rel
Definition: rel.h:84
int32 tdtypmod
Definition: tupdesc.h:84
#define TriggerRelidNameIndexId
Definition: indexing.h:250
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:1976
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
void RelationBuildPartitionDesc(Relation rel)
Definition: partcache.c:261
#define FATAL
Definition: elog.h:52
static void write_relcache_init_file(bool shared)
Definition: relcache.c:5701
struct PartitionKeyData * rd_partkey
Definition: rel.h:99
TriggerDesc * trigdesc
Definition: rel.h:90
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:435
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:3767
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:104
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define DatabaseOidIndexId
Definition: indexing.h:143
#define ClassOidIndexId
Definition: indexing.h:111
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:92
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define AccessMethodProcedureIndexId
Definition: indexing.h:81
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:1963
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
TupleDesc rd_att
Definition: rel.h:85
#define OpclassOidIndexId
Definition: indexing.h:201
#define InvalidOid
Definition: postgres_ext.h:36
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:84
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define AuthMemMemRoleIndexId
Definition: indexing.h:103
RuleLock * rd_rules
Definition: rel.h:88
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
#define DatabaseNameIndexId
Definition: indexing.h:141
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define SharedSecLabelObjectIndexId
Definition: indexing.h:317
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
void RelationBuildPartitionKey(Relation relation)
Definition: partcache.c:64
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1910
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:102
void RelationMapInitializePhase3(void)
Definition: relmapper.c:603
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:724
#define elog
Definition: elog.h:219
bool criticalRelcachesBuilt
Definition: relcache.c:131
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define AuthIdRolnameIndexId
Definition: indexing.h:96
void InitCatalogCachePhase2(void)
Definition: syscache.c:1071
#define RelationGetRelid(relation)
Definition: rel.h:407
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:105
bytea * rd_options
Definition: rel.h:128
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:103
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( void  )

Definition at line 2601 of file relcache.c.

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

Referenced by InvalidateSystemCaches(), and LocalExecuteInvalidationMessage().

2602 {
2604  RelIdCacheEnt *idhentry;
2605  Relation relation;
2606  List *rebuildFirstList = NIL;
2607  List *rebuildList = NIL;
2608  ListCell *l;
2609 
2610  /*
2611  * Reload relation mapping data before starting to reconstruct cache.
2612  */
2614 
2615  /* Phase 1 */
2616  hash_seq_init(&status, RelationIdCache);
2617 
2618  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2619  {
2620  relation = idhentry->reldesc;
2621 
2622  /* Must close all smgr references to avoid leaving dangling ptrs */
2623  RelationCloseSmgr(relation);
2624 
2625  /*
2626  * Ignore new relations; no other backend will manipulate them before
2627  * we commit. Likewise, before replacing a relation's relfilenode, we
2628  * shall have acquired AccessExclusiveLock and drained any applicable
2629  * pending invalidations.
2630  */
2631  if (relation->rd_createSubid != InvalidSubTransactionId ||
2633  continue;
2634 
2636 
2637  if (RelationHasReferenceCountZero(relation))
2638  {
2639  /* Delete this entry immediately */
2640  Assert(!relation->rd_isnailed);
2641  RelationClearRelation(relation, false);
2642  }
2643  else
2644  {
2645  /*
2646  * If it's a mapped relation, immediately update its rd_node in
2647  * case its relfilenode changed. We must do this during phase 1
2648  * in case the relation is consulted during rebuild of other
2649  * relcache entries in phase 2. It's safe since consulting the
2650  * map doesn't involve any access to relcache entries.
2651  */
2652  if (RelationIsMapped(relation))
2653  RelationInitPhysicalAddr(relation);
2654 
2655  /*
2656  * Add this entry to list of stuff to rebuild in second pass.
2657  * pg_class goes to the front of rebuildFirstList while
2658  * pg_class_oid_index goes to the back of rebuildFirstList, so
2659  * they are done first and second respectively. Other nailed
2660  * relations go to the front of rebuildList, so they'll be done
2661  * next in no particular order; and everything else goes to the
2662  * back of rebuildList.
2663  */
2664  if (RelationGetRelid(relation) == RelationRelationId)
2665  rebuildFirstList = lcons(relation, rebuildFirstList);
2666  else if (RelationGetRelid(relation) == ClassOidIndexId)
2667  rebuildFirstList = lappend(rebuildFirstList, relation);
2668  else if (relation->rd_isnailed)
2669  rebuildList = lcons(relation, rebuildList);
2670  else
2671  rebuildList = lappend(rebuildList, relation);
2672  }
2673  }
2674 
2675  /*
2676  * Now zap any remaining smgr cache entries. This must happen before we
2677  * start to rebuild entries, since that may involve catalog fetches which
2678  * will re-open catalog files.
2679  */
2680  smgrcloseall();
2681 
2682  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
2683  foreach(l, rebuildFirstList)
2684  {
2685  relation = (Relation) lfirst(l);
2686  RelationClearRelation(relation, true);
2687  }
2688  list_free(rebuildFirstList);
2689  foreach(l, rebuildList)
2690  {
2691  relation = (Relation) lfirst(l);
2692  RelationClearRelation(relation, true);
2693  }
2694  list_free(rebuildList);
2695 }
#define NIL
Definition: pg_list.h:69
static long relcacheInvalsReceived
Definition: relcache.c:145
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2231
bool rd_isnailed
Definition: rel.h:61
Relation reldesc
Definition: relcache.c:122
#define RelationCloseSmgr(relation)
Definition: rel.h:477
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
static HTAB * RelationIdCache
Definition: relcache.c:125
void smgrcloseall(void)
Definition: smgr.c:326
struct RelationData * Relation
Definition: relcache.h:26
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1256
#define ClassOidIndexId
Definition: indexing.h:111
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RelationIsMapped(relation)
Definition: rel.h:458
SubTransactionId rd_createSubid
Definition: rel.h:80
List * lcons(void *datum, List *list)
Definition: list.c:259
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:480
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:391
void list_free(List *list)
Definition: list.c:1133
void RelationMapInvalidateAll(void)
Definition: relmapper.c:409
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2557 of file relcache.c.

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

Referenced by LocalExecuteInvalidationMessage().

2558 {
2559  Relation relation;
2560 
2561  RelationIdCacheLookup(relationId, relation);
2562 
2563  if (PointerIsValid(relation))
2564  {
2566  RelationFlushRelation(relation);
2567  }
2568 }
static long relcacheInvalsReceived
Definition: relcache.c:145
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:204
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2489
#define PointerIsValid(pointer)
Definition: c.h:593

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2231 of file relcache.c.

References Assert, CLASS_TUPLE_SIZE, elog, equalPartitionDescs(), equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), IsTransactionState(), RelationData::rd_att, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_partdesc, RelationData::rd_partkey, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationBuildDesc(), RelationCacheDelete, RelationCloseSmgr, RelationDestroyRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and SWAPFIELD.

Referenced by AtEOSubXact_cleanup(), AtEOXact_cleanup(), RelationCacheInvalidate(), RelationClose(), RelationFlushRelation(), RelationForgetRelation(), and RelationIdGetRelation().

2232 {
2233  /*
2234  * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of
2235  * course it would be an equally bad idea to blow away one with nonzero
2236  * refcnt, since that would leave someone somewhere with a dangling
2237  * pointer. All callers are expected to have verified that this holds.
2238  */
2239  Assert(rebuild ?
2240  !RelationHasReferenceCountZero(relation) :
2241  RelationHasReferenceCountZero(relation));
2242 
2243  /*
2244  * Make sure smgr and lower levels close the relation's files, if they
2245  * weren't closed already. If the relation is not getting deleted, the
2246  * next smgr access should reopen the files automatically. This ensures
2247  * that the low-level file access state is updated after, say, a vacuum
2248  * truncation.
2249  */
2250  RelationCloseSmgr(relation);
2251 
2252  /*
2253  * Never, never ever blow away a nailed-in system relation, because we'd
2254  * be unable to recover. However, we must redo RelationInitPhysicalAddr
2255  * in case it is a mapped relation whose mapping changed.
2256  *
2257  * If it's a nailed-but-not-mapped index, then we need to re-read the
2258  * pg_class row to see if its relfilenode changed. We do that immediately
2259  * if we're inside a valid transaction and the relation is open (not
2260  * counting the nailed refcount). Otherwise just mark the entry as
2261  * possibly invalid, and it'll be fixed when next opened.
2262  */
2263  if (relation->rd_isnailed)
2264  {
2265  RelationInitPhysicalAddr(relation);
2266 
2267  if (relation->rd_rel->relkind == RELKIND_INDEX ||
2268  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2269  {
2270  relation->rd_isvalid = false; /* needs to be revalidated */
2271  if (relation->rd_refcnt > 1 && IsTransactionState())
2272  RelationReloadIndexInfo(relation);
2273  }
2274  return;
2275  }
2276 
2277  /*
2278  * Even non-system indexes should not be blown away if they are open and
2279  * have valid index support information. This avoids problems with active
2280  * use of the index support information. As with nailed indexes, we
2281  * re-read the pg_class row to handle possible physical relocation of the
2282  * index, and we check for pg_index updates too.
2283  */
2284  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2285  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2286  relation->rd_refcnt > 0 &&
2287  relation->rd_indexcxt != NULL)
2288  {
2289  relation->rd_isvalid = false; /* needs to be revalidated */
2290  if (IsTransactionState())
2291  RelationReloadIndexInfo(relation);
2292  return;
2293  }
2294 
2295  /* Mark it invalid until we've finished rebuild */
2296  relation->rd_isvalid = false;
2297 
2298  /*
2299  * If we're really done with the relcache entry, blow it away. But if
2300  * someone is still using it, reconstruct the whole deal without moving
2301  * the physical RelationData record (so that the someone's pointer is
2302  * still valid).
2303  */
2304  if (!rebuild)
2305  {
2306  /* Remove it from the hash table */
2307  RelationCacheDelete(relation);
2308 
2309  /* And release storage */
2310  RelationDestroyRelation(relation, false);
2311  }
2312  else if (!IsTransactionState())
2313  {
2314  /*
2315  * If we're not inside a valid transaction, we can't do any catalog
2316  * access so it's not possible to rebuild yet. Just exit, leaving
2317  * rd_isvalid = false so that the rebuild will occur when the entry is
2318  * next opened.
2319  *
2320  * Note: it's possible that we come here during subtransaction abort,
2321  * and the reason for wanting to rebuild is that the rel is open in
2322  * the outer transaction. In that case it might seem unsafe to not
2323  * rebuild immediately, since whatever code has the rel already open
2324  * will keep on using the relcache entry as-is. However, in such a
2325  * case the outer transaction should be holding a lock that's
2326  * sufficient to prevent any significant change in the rel's schema,
2327  * so the existing entry contents should be good enough for its
2328  * purposes; at worst we might be behind on statistics updates or the
2329  * like. (See also CheckTableNotInUse() and its callers.) These same
2330  * remarks also apply to the cases above where we exit without having
2331  * done RelationReloadIndexInfo() yet.
2332  */
2333  return;
2334  }
2335  else
2336  {
2337  /*
2338  * Our strategy for rebuilding an open relcache entry is to build a
2339  * new entry from scratch, swap its contents with the old entry, and
2340  * finally delete the new entry (along with any infrastructure swapped
2341  * over from the old entry). This is to avoid trouble in case an
2342  * error causes us to lose control partway through. The old entry
2343  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2344  * on next access. Meanwhile it's not any less valid than it was
2345  * before, so any code that might expect to continue accessing it
2346  * isn't hurt by the rebuild failure. (Consider for example a
2347  * subtransaction that ALTERs a table and then gets canceled partway
2348  * through the cache entry rebuild. The outer transaction should
2349  * still see the not-modified cache entry as valid.) The worst
2350  * consequence of an error is leaking the necessarily-unreferenced new
2351  * entry, and this shouldn't happen often enough for that to be a big
2352  * problem.
2353  *
2354  * When rebuilding an open relcache entry, we must preserve ref count,
2355  * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state. Also
2356  * attempt to preserve the pg_class entry (rd_rel), tupledesc,
2357  * rewrite-rule, partition key, and partition descriptor substructures
2358  * in place, because various places assume that these structures won't
2359  * move while they are working with an open relcache entry. (Note:
2360