PostgreSQL Source Code  git master
relcache.c File Reference
#include "postgres.h"
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/parallel.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/tupdesc_details.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "commands/policy.h"
#include "commands/publicationcmds.h"
#include "commands/trigger.h"
#include "common/int.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.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/catcache.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relmapper.h"
#include "utils/resowner.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for relcache.c:

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

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

Typedefs

typedef struct relidcacheent RelIdCacheEnt
 
typedef struct inprogressent InProgressEnt
 
typedef struct opclasscacheent OpClassCacheEnt
 

Functions

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

Variables

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

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:184
static int eoxact_list_len
Definition: relcache.c:186

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3941 of file relcache.c.

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 184 of file relcache.c.

◆ NUM_CRITICAL_LOCAL_INDEXES

#define NUM_CRITICAL_LOCAL_INDEXES   7 /* fix if you change list above */

◆ NUM_CRITICAL_LOCAL_RELS

#define NUM_CRITICAL_LOCAL_RELS   4 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_INDEXES

#define NUM_CRITICAL_SHARED_INDEXES   6 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_RELS

#define NUM_CRITICAL_SHARED_RELS   5 /* fix if you change list above */

◆ RECOVER_RELATION_BUILD_MEMORY

#define RECOVER_RELATION_BUILD_MEMORY   0

Definition at line 102 of file relcache.c.

◆ RelationCacheDelete

#define RelationCacheDelete (   RELATION)
Value:
do { \
RelIdCacheEnt *hentry; \
&((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:955
#define WARNING
Definition: elog.h:36
static HTAB * RelationIdCache
Definition: relcache.c:134

Definition at line 243 of file relcache.c.

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
&((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)
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:489
#define RelationGetRelationName(relation)
Definition: rel.h:539

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

#define RelationIdCacheLookup (   ID,
  RELATION 
)
Value:
do { \
RelIdCacheEnt *hentry; \
&(ID), \
HASH_FIND, NULL); \
if (hentry) \
RELATION = hentry->reldesc; \
else \
RELATION = NULL; \
} while(0)

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

#define RELCACHE_INIT_FILEMAGIC   0x573266 /* version ID value */

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

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

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 408 of file relcache.c.

409 {
410  Relation relation;
411  MemoryContext oldcxt;
412  Form_pg_class relationForm;
413 
414  /* Relcache entries must live in CacheMemoryContext */
416 
417  /*
418  * allocate and zero space for new relation descriptor
419  */
420  relation = (Relation) palloc0(sizeof(RelationData));
421 
422  /* make sure relation is marked as having no open file yet */
423  relation->rd_smgr = NULL;
424 
425  /*
426  * Copy the relation tuple form
427  *
428  * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. The
429  * variable-length fields (relacl, reloptions) are NOT stored in the
430  * relcache --- there'd be little point in it, since we don't copy the
431  * tuple's nulls bitmap and hence wouldn't know if the values are valid.
432  * Bottom line is that relacl *cannot* be retrieved from the relcache. Get
433  * it from the syscache if you need it. The same goes for the original
434  * form of reloptions (however, we do store the parsed form of reloptions
435  * in rd_options).
436  */
437  relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
438 
439  memcpy(relationForm, relp, CLASS_TUPLE_SIZE);
440 
441  /* initialize relation tuple form */
442  relation->rd_rel = relationForm;
443 
444  /* and allocate attribute tuple form storage */
445  relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
446  /* which we mark as a reference-counted tupdesc */
447  relation->rd_att->tdrefcount = 1;
448 
449  MemoryContextSwitchTo(oldcxt);
450 
451  return relation;
452 }
void * palloc0(Size size)
Definition: mcxt.c:1334
MemoryContext CacheMemoryContext
Definition: mcxt.c:140
void * palloc(Size size)
Definition: mcxt.c:1304
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
struct RelationData * Relation
Definition: relcache.h:27
TupleDesc rd_att
Definition: rel.h:112
SMgrRelation rd_smgr
Definition: rel.h:58
Form_pg_class rd_rel
Definition: rel.h:111
int tdrefcount
Definition: tupdesc.h:84
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67

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

Referenced by RelationBuildDesc().

◆ AtEOSubXact_cleanup()

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

Definition at line 3394 of file relcache.c.

3396 {
3397  /*
3398  * Is it a relation created in the current subtransaction?
3399  *
3400  * During subcommit, mark it as belonging to the parent, instead, as long
3401  * as it has not been dropped. Otherwise simply delete the relcache entry.
3402  * --- it isn't interesting any longer.
3403  */
3404  if (relation->rd_createSubid == mySubid)
3405  {
3406  /*
3407  * Valid rd_droppedSubid means the corresponding relation is dropped
3408  * but the relcache entry is preserved for at-commit pending sync. We
3409  * need to drop it explicitly here not to make the entry orphan.
3410  */
3411  Assert(relation->rd_droppedSubid == mySubid ||
3413  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3414  relation->rd_createSubid = parentSubid;
3415  else if (RelationHasReferenceCountZero(relation))
3416  {
3417  /* allow the entry to be removed */
3422  RelationClearRelation(relation, false);
3423  return;
3424  }
3425  else
3426  {
3427  /*
3428  * Hmm, somewhere there's a (leaked?) reference to the relation.
3429  * We daren't remove the entry for fear of dereferencing a
3430  * dangling pointer later. Bleat, and transfer it to the parent
3431  * subtransaction so we can try again later. This must be just a
3432  * WARNING to avoid error-during-error-recovery loops.
3433  */
3434  relation->rd_createSubid = parentSubid;
3435  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3436  RelationGetRelationName(relation));
3437  }
3438  }
3439 
3440  /*
3441  * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3442  * or drop record.
3443  */
3444  if (relation->rd_newRelfilelocatorSubid == mySubid)
3445  {
3446  if (isCommit)
3447  relation->rd_newRelfilelocatorSubid = parentSubid;
3448  else
3450  }
3451 
3452  if (relation->rd_firstRelfilelocatorSubid == mySubid)
3453  {
3454  if (isCommit)
3455  relation->rd_firstRelfilelocatorSubid = parentSubid;
3456  else
3458  }
3459 
3460  if (relation->rd_droppedSubid == mySubid)
3461  {
3462  if (isCommit)
3463  relation->rd_droppedSubid = parentSubid;
3464  else
3466  }
3467 }
#define InvalidSubTransactionId
Definition: c.h:645
#define elog(elevel,...)
Definition: elog.h:224
Assert(fmt[strlen(fmt) - 1] !='\n')
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2528
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_droppedSubid
Definition: rel.h:109

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

Referenced by AtEOSubXact_RelationCache().

◆ AtEOSubXact_RelationCache()

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

Definition at line 3339 of file relcache.c.

3341 {
3342  HASH_SEQ_STATUS status;
3343  RelIdCacheEnt *idhentry;
3344  int i;
3345 
3346  /*
3347  * Forget in_progress_list. This is relevant when we're aborting due to
3348  * an error during RelationBuildDesc(). We don't commit subtransactions
3349  * during RelationBuildDesc().
3350  */
3351  Assert(in_progress_list_len == 0 || !isCommit);
3353 
3354  /*
3355  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3356  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3357  * logic as in AtEOXact_RelationCache.
3358  */
3360  {
3361  hash_seq_init(&status, RelationIdCache);
3362  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3363  {
3364  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3365  mySubid, parentSubid);
3366  }
3367  }
3368  else
3369  {
3370  for (i = 0; i < eoxact_list_len; i++)
3371  {
3372  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3373  &eoxact_list[i],
3374  HASH_FIND,
3375  NULL);
3376  if (idhentry != NULL)
3377  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3378  mySubid, parentSubid);
3379  }
3380  }
3381 
3382  /* Don't reset the list; we still need more cleanup later */
3383 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3394
static bool eoxact_list_overflowed
Definition: relcache.c:187
Relation reldesc
Definition: relcache.c:131

References Assert(), AtEOSubXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, RelationIdCache, and relidcacheent::reldesc.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3257 of file relcache.c.

3258 {
3259  bool clear_relcache = false;
3260 
3261  /*
3262  * The relcache entry's ref count should be back to its normal
3263  * not-in-a-transaction state: 0 unless it's nailed in cache.
3264  *
3265  * In bootstrap mode, this is NOT true, so don't check it --- the
3266  * bootstrap code expects relations to stay open across start/commit
3267  * transaction calls. (That seems bogus, but it's not worth fixing.)
3268  *
3269  * Note: ideally this check would be applied to every relcache entry, not
3270  * just those that have eoxact work to do. But it's not worth forcing a
3271  * scan of the whole relcache just for this. (Moreover, doing so would
3272  * mean that assert-enabled testing never tests the hash_search code path
3273  * above, which seems a bad idea.)
3274  */
3275 #ifdef USE_ASSERT_CHECKING
3277  {
3278  int expected_refcnt;
3279 
3280  expected_refcnt = relation->rd_isnailed ? 1 : 0;
3281  Assert(relation->rd_refcnt == expected_refcnt);
3282  }
3283 #endif
3284 
3285  /*
3286  * Is the relation live after this transaction ends?
3287  *
3288  * During commit, clear the relcache entry if it is preserved after
3289  * relation drop, in order not to orphan the entry. During rollback,
3290  * clear the relcache entry if the relation is created in the current
3291  * transaction since it isn't interesting any longer once we are out of
3292  * the transaction.
3293  */
3294  clear_relcache =
3295  (isCommit ?
3298 
3299  /*
3300  * Since we are now out of the transaction, reset the subids to zero. That
3301  * also lets RelationClearRelation() drop the relcache entry.
3302  */
3307 
3308  if (clear_relcache)
3309  {
3310  if (RelationHasReferenceCountZero(relation))
3311  {
3312  RelationClearRelation(relation, false);
3313  return;
3314  }
3315  else
3316  {
3317  /*
3318  * Hmm, somewhere there's a (leaked?) reference to the relation.
3319  * We daren't remove the entry for fear of dereferencing a
3320  * dangling pointer later. Bleat, and mark it as not belonging to
3321  * the current transaction. Hopefully it'll get cleaned up
3322  * eventually. This must be just a WARNING to avoid
3323  * error-during-error-recovery loops.
3324  */
3325  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3326  RelationGetRelationName(relation));
3327  }
3328  }
3329 }
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62

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

Referenced by AtEOXact_RelationCache().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3187 of file relcache.c.

3188 {
3189  HASH_SEQ_STATUS status;
3190  RelIdCacheEnt *idhentry;
3191  int i;
3192 
3193  /*
3194  * Forget in_progress_list. This is relevant when we're aborting due to
3195  * an error during RelationBuildDesc().
3196  */
3197  Assert(in_progress_list_len == 0 || !isCommit);
3199 
3200  /*
3201  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3202  * listed in it. Otherwise fall back on a hash_seq_search scan.
3203  *
3204  * For simplicity, eoxact_list[] entries are not deleted till end of
3205  * top-level transaction, even though we could remove them at
3206  * subtransaction end in some cases, or remove relations from the list if
3207  * they are cleared for other reasons. Therefore we should expect the
3208  * case that list entries are not found in the hashtable; if not, there's
3209  * nothing to do for them.
3210  */
3212  {
3213  hash_seq_init(&status, RelationIdCache);
3214  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3215  {
3216  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3217  }
3218  }
3219  else
3220  {
3221  for (i = 0; i < eoxact_list_len; i++)
3222  {
3223  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3224  &eoxact_list[i],
3225  HASH_FIND,
3226  NULL);
3227  if (idhentry != NULL)
3228  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3229  }
3230  }
3231 
3232  if (EOXactTupleDescArrayLen > 0)
3233  {
3234  Assert(EOXactTupleDescArray != NULL);
3235  for (i = 0; i < NextEOXactTupleDescNum; i++)
3238  EOXactTupleDescArray = NULL;
3239  }
3240 
3241  /* Now we're out of the transaction and can clear the lists */
3242  eoxact_list_len = 0;
3243  eoxact_list_overflowed = false;
3246 }
void pfree(void *pointer)
Definition: mcxt.c:1508
static int NextEOXactTupleDescNum
Definition: relcache.c:203
static int EOXactTupleDescArrayLen
Definition: relcache.c:204
static void AtEOXact_cleanup(Relation relation, bool isCommit)
Definition: relcache.c:3257
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331

References Assert(), AtEOXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, EOXactTupleDescArray, EOXactTupleDescArrayLen, FreeTupleDesc(), HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, NextEOXactTupleDescNum, pfree(), RelationIdCache, and relidcacheent::reldesc.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ AttrDefaultCmp()

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

Definition at line 4513 of file relcache.c.

4514 {
4515  const AttrDefault *ada = (const AttrDefault *) a;
4516  const AttrDefault *adb = (const AttrDefault *) b;
4517 
4518  return pg_cmp_s16(ada->adnum, adb->adnum);
4519 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:471
int b
Definition: isn.c:70
int a
Definition: isn.c:69
AttrNumber adnum
Definition: tupdesc.h:24

References a, AttrDefault::adnum, b, and pg_cmp_s16().

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4433 of file relcache.c.

4434 {
4435  AttrDefault *attrdef;
4436  Relation adrel;
4437  SysScanDesc adscan;
4438  ScanKeyData skey;
4439  HeapTuple htup;
4440  int found = 0;
4441 
4442  /* Allocate array with room for as many entries as expected */
4443  attrdef = (AttrDefault *)
4445  ndef * sizeof(AttrDefault));
4446 
4447  /* Search pg_attrdef for relevant entries */
4448  ScanKeyInit(&skey,
4449  Anum_pg_attrdef_adrelid,
4450  BTEqualStrategyNumber, F_OIDEQ,
4451  ObjectIdGetDatum(RelationGetRelid(relation)));
4452 
4453  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4454  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4455  NULL, 1, &skey);
4456 
4457  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4458  {
4459  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4460  Datum val;
4461  bool isnull;
4462 
4463  /* protect limited size of array */
4464  if (found >= ndef)
4465  {
4466  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4467  adform->adnum, RelationGetRelationName(relation));
4468  break;
4469  }
4470 
4471  val = fastgetattr(htup,
4472  Anum_pg_attrdef_adbin,
4473  adrel->rd_att, &isnull);
4474  if (isnull)
4475  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4476  adform->adnum, RelationGetRelationName(relation));
4477  else
4478  {
4479  /* detoast and convert to cstring in caller's context */
4480  char *s = TextDatumGetCString(val);
4481 
4482  attrdef[found].adnum = adform->adnum;
4483  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4484  pfree(s);
4485  found++;
4486  }
4487  }
4488 
4489  systable_endscan(adscan);
4490  table_close(adrel, AccessShareLock);
4491 
4492  if (found != ndef)
4493  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4494  ndef - found, RelationGetRelationName(relation));
4495 
4496  /*
4497  * Sort the AttrDefault entries by adnum, for the convenience of
4498  * equalTupleDescs(). (Usually, they already will be in order, but this
4499  * might not be so if systable_getnext isn't using an index.)
4500  */
4501  if (found > 1)
4502  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4503 
4504  /* Install array only after it's fully valid */
4505  relation->rd_att->constr->defval = attrdef;
4506  relation->rd_att->constr->num_defval = found;
4507 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1202
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1670
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:449
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetRelid(relation)
Definition: rel.h:505
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4513
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char * adbin
Definition: tupdesc.h:25
AttrDefault * defval
Definition: tupdesc.h:39
uint16 num_defval
Definition: tupdesc.h:42
TupleConstr * constr
Definition: tupdesc.h:85
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, AttrDefault::adbin, AttrDefault::adnum, AttrDefaultCmp(), BTEqualStrategyNumber, CacheMemoryContext, TupleDescData::constr, TupleConstr::defval, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), TupleConstr::num_defval, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ BuildHardcodedDescriptor()

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

Definition at line 4368 of file relcache.c.

4369 {
4370  TupleDesc result;
4371  MemoryContext oldcxt;
4372  int i;
4373 
4375 
4376  result = CreateTemplateTupleDesc(natts);
4377  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4378  result->tdtypmod = -1;
4379 
4380  for (i = 0; i < natts; i++)
4381  {
4382  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4383  /* make sure attcacheoff is valid */
4384  TupleDescAttr(result, i)->attcacheoff = -1;
4385  }
4386 
4387  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4388  TupleDescAttr(result, 0)->attcacheoff = 0;
4389 
4390  /* Note: we don't bother to set up a TupleConstr entry */
4391 
4392  MemoryContextSwitchTo(oldcxt);
4393 
4394  return result;
4395 }
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:201
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

◆ CheckConstraintCmp()

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

Definition at line 4617 of file relcache.c.

4618 {
4619  const ConstrCheck *ca = (const ConstrCheck *) a;
4620  const ConstrCheck *cb = (const ConstrCheck *) b;
4621 
4622  return strcmp(ca->ccname, cb->ccname);
4623 }
char * ccname
Definition: tupdesc.h:30

References a, b, and ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4528 of file relcache.c.

4529 {
4530  ConstrCheck *check;
4531  int ncheck = relation->rd_rel->relchecks;
4532  Relation conrel;
4533  SysScanDesc conscan;
4534  ScanKeyData skey[1];
4535  HeapTuple htup;
4536  int found = 0;
4537 
4538  /* Allocate array with room for as many entries as expected */
4539  check = (ConstrCheck *)
4541  ncheck * sizeof(ConstrCheck));
4542 
4543  /* Search pg_constraint for relevant entries */
4544  ScanKeyInit(&skey[0],
4545  Anum_pg_constraint_conrelid,
4546  BTEqualStrategyNumber, F_OIDEQ,
4547  ObjectIdGetDatum(RelationGetRelid(relation)));
4548 
4549  conrel = table_open(ConstraintRelationId, AccessShareLock);
4550  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4551  NULL, 1, skey);
4552 
4553  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4554  {
4556  Datum val;
4557  bool isnull;
4558 
4559  /* We want check constraints only */
4560  if (conform->contype != CONSTRAINT_CHECK)
4561  continue;
4562 
4563  /* protect limited size of array */
4564  if (found >= ncheck)
4565  {
4566  elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4567  RelationGetRelationName(relation));
4568  break;
4569  }
4570 
4571  check[found].ccvalid = conform->convalidated;
4572  check[found].ccnoinherit = conform->connoinherit;
4574  NameStr(conform->conname));
4575 
4576  /* Grab and test conbin is actually set */
4577  val = fastgetattr(htup,
4578  Anum_pg_constraint_conbin,
4579  conrel->rd_att, &isnull);
4580  if (isnull)
4581  elog(WARNING, "null conbin for relation \"%s\"",
4582  RelationGetRelationName(relation));
4583  else
4584  {
4585  /* detoast and convert to cstring in caller's context */
4586  char *s = TextDatumGetCString(val);
4587 
4588  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4589  pfree(s);
4590  found++;
4591  }
4592  }
4593 
4594  systable_endscan(conscan);
4595  table_close(conrel, AccessShareLock);
4596 
4597  if (found != ncheck)
4598  elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4599  ncheck - found, RelationGetRelationName(relation));
4600 
4601  /*
4602  * Sort the records by name. This ensures that CHECKs are applied in a
4603  * deterministic order, and it also makes equalTupleDescs() faster.
4604  */
4605  if (found > 1)
4606  qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4607 
4608  /* Install array only after it's fully valid */
4609  relation->rd_att->constr->check = check;
4610  relation->rd_att->constr->num_check = found;
4611 }
#define NameStr(name)
Definition: c.h:733
FormData_pg_constraint * Form_pg_constraint
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4617
bool ccnoinherit
Definition: tupdesc.h:33
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_check
Definition: tupdesc.h:43

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ConstrCheck::ccbin, ConstrCheck::ccname, ConstrCheck::ccnoinherit, ConstrCheck::ccvalid, TupleConstr::check, CheckConstraintCmp(), TupleDescData::constr, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), NameStr, TupleConstr::num_check, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ CopyIndexAttOptions()

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

Definition at line 5853 of file relcache.c.

5854 {
5855  bytea **opts = palloc(sizeof(*opts) * natts);
5856 
5857  for (int i = 0; i < natts; i++)
5858  {
5859  bytea *opt = srcopts[i];
5860 
5861  opts[i] = !opt ? NULL : (bytea *)
5862  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5863  }
5864 
5865  return opts;
5866 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
static AmcheckOptions opts
Definition: pg_amcheck.c:111
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
Definition: c.h:674

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 952 of file relcache.c.

953 {
954  int i;
955  Oid *r1,
956  *r2;
957 
958  if (policy1 != NULL)
959  {
960  if (policy2 == NULL)
961  return false;
962 
963  if (policy1->polcmd != policy2->polcmd)
964  return false;
965  if (policy1->hassublinks != policy2->hassublinks)
966  return false;
967  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
968  return false;
969  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
970  return false;
971 
972  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
973  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
974 
975  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
976  {
977  if (r1[i] != r2[i])
978  return false;
979  }
980 
981  if (!equal(policy1->qual, policy2->qual))
982  return false;
983  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
984  return false;
985  }
986  else if (policy2 != NULL)
987  return false;
988 
989  return true;
990 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_DIMS(a)
Definition: array.h:294
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
unsigned int Oid
Definition: postgres_ext.h:31
ArrayType * roles
Definition: rowsecurity.h:24
Expr * with_check_qual
Definition: rowsecurity.h:27

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

◆ equalRSDesc()

static bool equalRSDesc ( RowSecurityDesc rsdesc1,
RowSecurityDesc rsdesc2 
)
static

Definition at line 998 of file relcache.c.

999 {
1000  ListCell *lc,
1001  *rc;
1002 
1003  if (rsdesc1 == NULL && rsdesc2 == NULL)
1004  return true;
1005 
1006  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1007  (rsdesc1 == NULL && rsdesc2 != NULL))
1008  return false;
1009 
1010  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1011  return false;
1012 
1013  /* RelationBuildRowSecurity should build policies in order */
1014  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1015  {
1018 
1019  if (!equalPolicy(l, r))
1020  return false;
1021  }
1022 
1023  return true;
1024 }
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
static bool equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
Definition: relcache.c:952

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

Referenced by RelationClearRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 907 of file relcache.c.

908 {
909  int i;
910 
911  /*
912  * As of 7.3 we assume the rule ordering is repeatable, because
913  * RelationBuildRuleLock should read 'em in a consistent order. So just
914  * compare corresponding slots.
915  */
916  if (rlock1 != NULL)
917  {
918  if (rlock2 == NULL)
919  return false;
920  if (rlock1->numLocks != rlock2->numLocks)
921  return false;
922  for (i = 0; i < rlock1->numLocks; i++)
923  {
924  RewriteRule *rule1 = rlock1->rules[i];
925  RewriteRule *rule2 = rlock2->rules[i];
926 
927  if (rule1->ruleId != rule2->ruleId)
928  return false;
929  if (rule1->event != rule2->event)
930  return false;
931  if (rule1->enabled != rule2->enabled)
932  return false;
933  if (rule1->isInstead != rule2->isInstead)
934  return false;
935  if (!equal(rule1->qual, rule2->qual))
936  return false;
937  if (!equal(rule1->actions, rule2->actions))
938  return false;
939  }
940  }
941  else if (rlock2 != NULL)
942  return false;
943  return true;
944 }
Oid ruleId
Definition: prs2lock.h:26
CmdType event
Definition: prs2lock.h:27
List * actions
Definition: prs2lock.h:29
bool isInstead
Definition: prs2lock.h:31
Node * qual
Definition: prs2lock.h:28
char enabled
Definition: prs2lock.h:30
RewriteRule ** rules
Definition: prs2lock.h:43
int numLocks
Definition: prs2lock.h:42

References RewriteRule::actions, RewriteRule::enabled, equal(), RewriteRule::event, i, RewriteRule::isInstead, RuleLock::numLocks, RewriteRule::qual, RewriteRule::ruleId, and RuleLock::rules.

Referenced by RelationClearRelation().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5934 of file relcache.c.

5935 {
5939 
5940  return 0; /* return value does not matter */
5941 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3322
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define RelationGetNamespace(relation)
Definition: rel.h:546

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

Referenced by ATPrepChangePersistence(), ATRewriteTable(), BuildRelationExtStatistics(), check_default_partition_contents(), errtablecolname(), errtableconstraint(), ExecFindPartition(), and ExecPartitionCheckEmitError().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5951 of file relcache.c.

5952 {
5953  TupleDesc reldesc = RelationGetDescr(rel);
5954  const char *colname;
5955 
5956  /* Use reldesc if it's a user attribute, else consult the catalogs */
5957  if (attnum > 0 && attnum <= reldesc->natts)
5958  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5959  else
5960  colname = get_attname(RelationGetRelid(rel), attnum, false);
5961 
5962  return errtablecolname(rel, colname);
5963 }
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetDescr(relation)
Definition: rel.h:531
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5975

References attname, attnum, errtablecolname(), get_attname(), NameStr, RelationGetDescr, RelationGetRelid, and TupleDescAttr.

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5975 of file relcache.c.

5976 {
5977  errtable(rel);
5979 
5980  return 0; /* return value does not matter */
5981 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5934

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ formrdesc()

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

Definition at line 1867 of file relcache.c.

1870 {
1871  Relation relation;
1872  int i;
1873  bool has_not_null;
1874 
1875  /*
1876  * allocate new relation desc, clear all fields of reldesc
1877  */
1878  relation = (Relation) palloc0(sizeof(RelationData));
1879 
1880  /* make sure relation is marked as having no open file yet */
1881  relation->rd_smgr = NULL;
1882 
1883  /*
1884  * initialize reference count: 1 because it is nailed in cache
1885  */
1886  relation->rd_refcnt = 1;
1887 
1888  /*
1889  * all entries built with this routine are nailed-in-cache; none are for
1890  * new or temp relations.
1891  */
1892  relation->rd_isnailed = true;
1897  relation->rd_backend = INVALID_PROC_NUMBER;
1898  relation->rd_islocaltemp = false;
1899 
1900  /*
1901  * initialize relation tuple form
1902  *
1903  * The data we insert here is pretty incomplete/bogus, but it'll serve to
1904  * get us launched. RelationCacheInitializePhase3() will read the real
1905  * data from pg_class and replace what we've done here. Note in
1906  * particular that relowner is left as zero; this cues
1907  * RelationCacheInitializePhase3 that the real data isn't there yet.
1908  */
1910 
1911  namestrcpy(&relation->rd_rel->relname, relationName);
1912  relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1913  relation->rd_rel->reltype = relationReltype;
1914 
1915  /*
1916  * It's important to distinguish between shared and non-shared relations,
1917  * even at bootstrap time, to make sure we know where they are stored.
1918  */
1919  relation->rd_rel->relisshared = isshared;
1920  if (isshared)
1921  relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1922 
1923  /* formrdesc is used only for permanent relations */
1924  relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1925 
1926  /* ... and they're always populated, too */
1927  relation->rd_rel->relispopulated = true;
1928 
1929  relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1930  relation->rd_rel->relpages = 0;
1931  relation->rd_rel->reltuples = -1;
1932  relation->rd_rel->relallvisible = 0;
1933  relation->rd_rel->relkind = RELKIND_RELATION;
1934  relation->rd_rel->relnatts = (int16) natts;
1935  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
1936 
1937  /*
1938  * initialize attribute tuple form
1939  *
1940  * Unlike the case with the relation tuple, this data had better be right
1941  * because it will never be replaced. The data comes from
1942  * src/include/catalog/ headers via genbki.pl.
1943  */
1944  relation->rd_att = CreateTemplateTupleDesc(natts);
1945  relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1946 
1947  relation->rd_att->tdtypeid = relationReltype;
1948  relation->rd_att->tdtypmod = -1; /* just to be sure */
1949 
1950  /*
1951  * initialize tuple desc info
1952  */
1953  has_not_null = false;
1954  for (i = 0; i < natts; i++)
1955  {
1956  memcpy(TupleDescAttr(relation->rd_att, i),
1957  &attrs[i],
1959  has_not_null |= attrs[i].attnotnull;
1960  /* make sure attcacheoff is valid */
1961  TupleDescAttr(relation->rd_att, i)->attcacheoff = -1;
1962  }
1963 
1964  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
1965  TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
1966 
1967  /* mark not-null status */
1968  if (has_not_null)
1969  {
1970  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1971 
1972  constr->has_not_null = true;
1973  relation->rd_att->constr = constr;
1974  }
1975 
1976  /*
1977  * initialize relation id from info in att array (my, this is ugly)
1978  */
1979  RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
1980 
1981  /*
1982  * All relations made with formrdesc are mapped. This is necessarily so
1983  * because there is no other way to know what filenumber they currently
1984  * have. In bootstrap mode, add them to the initial relation mapper data,
1985  * specifying that the initial filenumber is the same as the OID.
1986  */
1987  relation->rd_rel->relfilenode = InvalidRelFileNumber;
1990  RelationGetRelid(relation),
1991  isshared, true);
1992 
1993  /*
1994  * initialize the relation lock manager information
1995  */
1996  RelationInitLockInfo(relation); /* see lmgr.c */
1997 
1998  /*
1999  * initialize physical addressing information for the relation
2000  */
2001  RelationInitPhysicalAddr(relation);
2002 
2003  /*
2004  * initialize the table am handler
2005  */
2006  relation->rd_rel->relam = HEAP_TABLE_AM_OID;
2007  relation->rd_tableam = GetHeapamTableAmRoutine();
2008 
2009  /*
2010  * initialize the rel-has-index flag, using hardwired knowledge
2011  */
2013  {
2014  /* In bootstrap mode, we have no indexes */
2015  relation->rd_rel->relhasindex = false;
2016  }
2017  else
2018  {
2019  /* Otherwise, all the rels formrdesc is used for have indexes */
2020  relation->rd_rel->relhasindex = true;
2021  }
2022 
2023  /*
2024  * add new reldesc to relcache
2025  */
2026  RelationCacheInsert(relation, false);
2027 
2028  /* It's fully valid */
2029  relation->rd_isvalid = true;
2030 }
signed short int16
Definition: c.h:480
const TableAmRoutine * GetHeapamTableAmRoutine(void)
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:71
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
#define RelationCacheInsert(RELATION, replace_allowed)
Definition: relcache.c:209
static void RelationInitPhysicalAddr(Relation relation)
Definition: relcache.c:1312
void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared, bool immediate)
Definition: relmapper.c:325
#define InvalidRelFileNumber
Definition: relpath.h:26
ProcNumber rd_backend
Definition: rel.h:60
const struct TableAmRoutine * rd_tableam
Definition: rel.h:189
bool rd_isvalid
Definition: rel.h:63
bool rd_islocaltemp
Definition: rel.h:61
bool has_not_null
Definition: tupdesc.h:44

References ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateTemplateTupleDesc(), GetHeapamTableAmRoutine(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidRelFileNumber, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationData::rd_tableam, RelationCacheInsert, RelationGetRelid, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4398 of file relcache.c.

4399 {
4400  static TupleDesc pgclassdesc = NULL;
4401 
4402  /* Already done? */
4403  if (pgclassdesc == NULL)
4404  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4405  Desc_pg_class);
4406 
4407  return pgclassdesc;
4408 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4368
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4411 of file relcache.c.

4412 {
4413  static TupleDesc pgindexdesc = NULL;
4414 
4415  /* Already done? */
4416  if (pgindexdesc == NULL)
4417  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4418  Desc_pg_index);
4419 
4420  return pgindexdesc;
4421 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:118

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

◆ IndexSupportInitialize()

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

Definition at line 1589 of file relcache.c.

1595 {
1596  int attIndex;
1597 
1598  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1599  {
1600  OpClassCacheEnt *opcentry;
1601 
1602  if (!OidIsValid(indclass->values[attIndex]))
1603  elog(ERROR, "bogus pg_index tuple");
1604 
1605  /* look up the info for this opclass, using a cache */
1606  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1607  maxSupportNumber);
1608 
1609  /* copy cached data into relcache entry */
1610  opFamily[attIndex] = opcentry->opcfamily;
1611  opcInType[attIndex] = opcentry->opcintype;
1612  if (maxSupportNumber > 0)
1613  memcpy(&indexSupport[attIndex * maxSupportNumber],
1614  opcentry->supportProcs,
1615  maxSupportNumber * sizeof(RegProcedure));
1616  }
1617 }
regproc RegProcedure
Definition: c.h:637
#define OidIsValid(objectId)
Definition: c.h:762
#define ERROR
Definition: elog.h:39
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1640
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:720
RegProcedure * supportProcs
Definition: relcache.c:268

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

Referenced by RelationInitIndexAccessInfo().

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1394 of file relcache.c.

1395 {
1396  IndexAmRoutine *cached,
1397  *tmp;
1398 
1399  /*
1400  * Call the amhandler in current, short-lived memory context, just in case
1401  * it leaks anything (it probably won't, but let's be paranoid).
1402  */
1403  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1404 
1405  /* OK, now transfer the data into relation's rd_indexcxt. */
1406  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1407  sizeof(IndexAmRoutine));
1408  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1409  relation->rd_indam = cached;
1410 
1411  pfree(tmp);
1412 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1168
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
Oid rd_amhandler
Definition: rel.h:184
MemoryContext rd_indexcxt
Definition: rel.h:204

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

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1793 of file relcache.c.

1794 {
1795  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1796 }
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:28

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

Referenced by RelationInitTableAccessMethod().

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 4332 of file relcache.c.

4333 {
4334  Relation ird;
4335 
4336  /*
4337  * We must lock the underlying catalog before locking the index to avoid
4338  * deadlock, since RelationBuildDesc might well need to read the catalog,
4339  * and if anyone else is exclusive-locking this catalog and index they'll
4340  * be doing it in that order.
4341  */
4342  LockRelationOid(heapoid, AccessShareLock);
4343  LockRelationOid(indexoid, AccessShareLock);
4344  ird = RelationBuildDesc(indexoid, true);
4345  if (ird == NULL)
4346  elog(PANIC, "could not open critical system index %u", indexoid);
4347  ird->rd_isnailed = true;
4348  ird->rd_refcnt = 1;
4351 
4352  (void) RelationGetIndexAttOptions(ird, false);
4353 }
#define PANIC
Definition: elog.h:42
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1039
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5873

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

Referenced by RelationCacheInitializePhase3().

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 6052 of file relcache.c.

6053 {
6054  FILE *fp;
6055  char initfilename[MAXPGPATH];
6056  Relation *rels;
6057  int relno,
6058  num_rels,
6059  max_rels,
6060  nailed_rels,
6061  nailed_indexes,
6062  magic;
6063  int i;
6064 
6065  if (shared)
6066  snprintf(initfilename, sizeof(initfilename), "global/%s",
6068  else
6069  snprintf(initfilename, sizeof(initfilename), "%s/%s",
6071 
6072  fp = AllocateFile(initfilename, PG_BINARY_R);
6073  if (fp == NULL)
6074  return false;
6075 
6076  /*
6077  * Read the index relcache entries from the file. Note we will not enter
6078  * any of them into the cache if the read fails partway through; this
6079  * helps to guard against broken init files.
6080  */
6081  max_rels = 100;
6082  rels = (Relation *) palloc(max_rels * sizeof(Relation));
6083  num_rels = 0;
6084  nailed_rels = nailed_indexes = 0;
6085 
6086  /* check for correct magic number (compatible version) */
6087  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6088  goto read_failed;
6089  if (magic != RELCACHE_INIT_FILEMAGIC)
6090  goto read_failed;
6091 
6092  for (relno = 0;; relno++)
6093  {
6094  Size len;
6095  size_t nread;
6096  Relation rel;
6097  Form_pg_class relform;
6098  bool has_not_null;
6099 
6100  /* first read the relation descriptor length */
6101  nread = fread(&len, 1, sizeof(len), fp);
6102  if (nread != sizeof(len))
6103  {
6104  if (nread == 0)
6105  break; /* end of file */
6106  goto read_failed;
6107  }
6108 
6109  /* safety check for incompatible relcache layout */
6110  if (len != sizeof(RelationData))
6111  goto read_failed;
6112 
6113  /* allocate another relcache header */
6114  if (num_rels >= max_rels)
6115  {
6116  max_rels *= 2;
6117  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
6118  }
6119 
6120  rel = rels[num_rels++] = (Relation) palloc(len);
6121 
6122  /* then, read the Relation structure */
6123  if (fread(rel, 1, len, fp) != len)
6124  goto read_failed;
6125 
6126  /* next read the relation tuple form */
6127  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6128  goto read_failed;
6129 
6130  relform = (Form_pg_class) palloc(len);
6131  if (fread(relform, 1, len, fp) != len)
6132  goto read_failed;
6133 
6134  rel->rd_rel = relform;
6135 
6136  /* initialize attribute tuple forms */
6137  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
6138  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
6139 
6140  rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
6141  rel->rd_att->tdtypmod = -1; /* just to be sure */
6142 
6143  /* next read all the attribute tuple form data entries */
6144  has_not_null = false;
6145  for (i = 0; i < relform->relnatts; i++)
6146  {
6147  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
6148 
6149  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6150  goto read_failed;
6152  goto read_failed;
6153  if (fread(attr, 1, len, fp) != len)
6154  goto read_failed;
6155 
6156  has_not_null |= attr->attnotnull;
6157  }
6158 
6159  /* next read the access method specific field */
6160  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6161  goto read_failed;
6162  if (len > 0)
6163  {
6164  rel->rd_options = palloc(len);
6165  if (fread(rel->rd_options, 1, len, fp) != len)
6166  goto read_failed;
6167  if (len != VARSIZE(rel->rd_options))
6168  goto read_failed; /* sanity check */
6169  }
6170  else
6171  {
6172  rel->rd_options = NULL;
6173  }
6174 
6175  /* mark not-null status */
6176  if (has_not_null)
6177  {
6178  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
6179 
6180  constr->has_not_null = true;
6181  rel->rd_att->constr = constr;
6182  }
6183 
6184  /*
6185  * If it's an index, there's more to do. Note we explicitly ignore
6186  * partitioned indexes here.
6187  */
6188  if (rel->rd_rel->relkind == RELKIND_INDEX)
6189  {
6190  MemoryContext indexcxt;
6191  Oid *opfamily;
6192  Oid *opcintype;
6193  RegProcedure *support;
6194  int nsupport;
6195  int16 *indoption;
6196  Oid *indcollation;
6197 
6198  /* Count nailed indexes to ensure we have 'em all */
6199  if (rel->rd_isnailed)
6200  nailed_indexes++;
6201 
6202  /* read the pg_index tuple */
6203  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6204  goto read_failed;
6205 
6206  rel->rd_indextuple = (HeapTuple) palloc(len);
6207  if (fread(rel->rd_indextuple, 1, len, fp) != len)
6208  goto read_failed;
6209 
6210  /* Fix up internal pointers in the tuple -- see heap_copytuple */
6211  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
6213 
6214  /*
6215  * prepare index info context --- parameters should match
6216  * RelationInitIndexAccessInfo
6217  */
6219  "index info",
6221  rel->rd_indexcxt = indexcxt;
6224 
6225  /*
6226  * Now we can fetch the index AM's API struct. (We can't store
6227  * that in the init file, since it contains function pointers that
6228  * might vary across server executions. Fortunately, it should be
6229  * safe to call the amhandler even while bootstrapping indexes.)
6230  */
6231  InitIndexAmRoutine(rel);
6232 
6233  /* read the vector of opfamily OIDs */
6234  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6235  goto read_failed;
6236 
6237  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
6238  if (fread(opfamily, 1, len, fp) != len)
6239  goto read_failed;
6240 
6241  rel->rd_opfamily = opfamily;
6242 
6243  /* read the vector of opcintype OIDs */
6244  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6245  goto read_failed;
6246 
6247  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
6248  if (fread(opcintype, 1, len, fp) != len)
6249  goto read_failed;
6250 
6251  rel->rd_opcintype = opcintype;
6252 
6253  /* read the vector of support procedure OIDs */
6254  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6255  goto read_failed;
6256  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
6257  if (fread(support, 1, len, fp) != len)
6258  goto read_failed;
6259 
6260  rel->rd_support = support;
6261 
6262  /* read the vector of collation OIDs */
6263  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6264  goto read_failed;
6265 
6266  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
6267  if (fread(indcollation, 1, len, fp) != len)
6268  goto read_failed;
6269 
6270  rel->rd_indcollation = indcollation;
6271 
6272  /* read the vector of indoption values */
6273  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6274  goto read_failed;
6275 
6276  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
6277  if (fread(indoption, 1, len, fp) != len)
6278  goto read_failed;
6279 
6280  rel->rd_indoption = indoption;
6281 
6282  /* read the vector of opcoptions values */
6283  rel->rd_opcoptions = (bytea **)
6284  MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
6285 
6286  for (i = 0; i < relform->relnatts; i++)
6287  {
6288  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6289  goto read_failed;
6290 
6291  if (len > 0)
6292  {
6293  rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
6294  if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
6295  goto read_failed;
6296  }
6297  }
6298 
6299  /* set up zeroed fmgr-info vector */
6300  nsupport = relform->relnatts * rel->rd_indam->amsupport;
6301  rel->rd_supportinfo = (FmgrInfo *)
6302  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
6303  }
6304  else
6305  {
6306  /* Count nailed rels to ensure we have 'em all */
6307  if (rel->rd_isnailed)
6308  nailed_rels++;
6309 
6310  /* Load table AM data */
6311  if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
6313 
6314  Assert(rel->rd_index == NULL);
6315  Assert(rel->rd_indextuple == NULL);
6316  Assert(rel->rd_indexcxt == NULL);
6317  Assert(rel->rd_indam == NULL);
6318  Assert(rel->rd_opfamily == NULL);
6319  Assert(rel->rd_opcintype == NULL);
6320  Assert(rel->rd_support == NULL);
6321  Assert(rel->rd_supportinfo == NULL);
6322  Assert(rel->rd_indoption == NULL);
6323  Assert(rel->rd_indcollation == NULL);
6324  Assert(rel->rd_opcoptions == NULL);
6325  }
6326 
6327  /*
6328  * Rules and triggers are not saved (mainly because the internal
6329  * format is complex and subject to change). They must be rebuilt if
6330  * needed by RelationCacheInitializePhase3. This is not expected to
6331  * be a big performance hit since few system catalogs have such. Ditto
6332  * for RLS policy data, partition info, index expressions, predicates,
6333  * exclusion info, and FDW info.
6334  */
6335  rel->rd_rules = NULL;
6336  rel->rd_rulescxt = NULL;
6337  rel->trigdesc = NULL;
6338  rel->rd_rsdesc = NULL;
6339  rel->rd_partkey = NULL;
6340  rel->rd_partkeycxt = NULL;
6341  rel->rd_partdesc = NULL;
6342  rel->rd_partdesc_nodetached = NULL;
6344  rel->rd_pdcxt = NULL;
6345  rel->rd_pddcxt = NULL;
6346  rel->rd_partcheck = NIL;
6347  rel->rd_partcheckvalid = false;
6348  rel->rd_partcheckcxt = NULL;
6349  rel->rd_indexprs = NIL;
6350  rel->rd_indpred = NIL;
6351  rel->rd_exclops = NULL;
6352  rel->rd_exclprocs = NULL;
6353  rel->rd_exclstrats = NULL;
6354  rel->rd_fdwroutine = NULL;
6355 
6356  /*
6357  * Reset transient-state fields in the relcache entry
6358  */
6359  rel->rd_smgr = NULL;
6360  if (rel->rd_isnailed)
6361  rel->rd_refcnt = 1;
6362  else
6363  rel->rd_refcnt = 0;
6364  rel->rd_indexvalid = false;
6365  rel->rd_indexlist = NIL;
6366  rel->rd_pkindex = InvalidOid;
6367  rel->rd_replidindex = InvalidOid;
6368  rel->rd_attrsvalid = false;
6369  rel->rd_keyattr = NULL;
6370  rel->rd_pkattr = NULL;
6371  rel->rd_idattr = NULL;
6372  rel->rd_pubdesc = NULL;
6373  rel->rd_statvalid = false;
6374  rel->rd_statlist = NIL;
6375  rel->rd_fkeyvalid = false;
6376  rel->rd_fkeylist = NIL;
6381  rel->rd_amcache = NULL;
6382  rel->pgstat_info = NULL;
6383 
6384  /*
6385  * Recompute lock and physical addressing info. This is needed in
6386  * case the pg_internal.init file was copied from some other database
6387  * by CREATE DATABASE.
6388  */
6389  RelationInitLockInfo(rel);
6391  }
6392 
6393  /*
6394  * We reached the end of the init file without apparent problem. Did we
6395  * get the right number of nailed items? This is a useful crosscheck in
6396  * case the set of critical rels or indexes changes. However, that should
6397  * not happen in a normally-running system, so let's bleat if it does.
6398  *
6399  * For the shared init file, we're called before client authentication is
6400  * done, which means that elog(WARNING) will go only to the postmaster
6401  * log, where it's easily missed. To ensure that developers notice bad
6402  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
6403  * an Assert(false) there.
6404  */
6405  if (shared)
6406  {
6407  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
6408  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
6409  {
6410  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
6411  nailed_rels, nailed_indexes,
6413  /* Make sure we get developers' attention about this */
6414  Assert(false);
6415  /* In production builds, recover by bootstrapping the relcache */
6416  goto read_failed;
6417  }
6418  }
6419  else
6420  {
6421  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
6422  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
6423  {
6424  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
6425  nailed_rels, nailed_indexes,
6427  /* We don't need an Assert() in this case */
6428  goto read_failed;
6429  }
6430  }
6431 
6432  /*
6433  * OK, all appears well.
6434  *
6435  * Now insert all the new relcache entries into the cache.
6436  */
6437  for (relno = 0; relno < num_rels; relno++)
6438  {
6439  RelationCacheInsert(rels[relno], false);
6440  }
6441 
6442  pfree(rels);
6443  FreeFile(fp);
6444 
6445  if (shared)
6447  else
6448  criticalRelcachesBuilt = true;
6449  return true;
6450 
6451  /*
6452  * init file is broken, so do it the hard way. We don't bother trying to
6453  * free the clutter we just allocated; it's not in the relcache so it
6454  * won't hurt.
6455  */
6456 read_failed:
6457  pfree(rels);
6458  FreeFile(fp);
6459 
6460  return false;
6461 }
#define PG_BINARY_R
Definition: c.h:1262
size_t Size
Definition: c.h:592
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2583
int FreeFile(FILE *file)
Definition: fd.c:2781
char * DatabasePath
Definition: globals.c:101
#define HEAPTUPLESIZE
Definition: htup.h:73
HeapTupleData * HeapTuple
Definition: htup.h:71
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define MAXPGPATH
const void size_t len
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define NIL
Definition: pg_list.h:68
#define snprintf
Definition: port.h:238
#define InvalidOid
Definition: postgres_ext.h:36
#define NUM_CRITICAL_LOCAL_RELS
#define NUM_CRITICAL_SHARED_INDEXES
bool criticalRelcachesBuilt
Definition: relcache.c:140
bool criticalSharedRelcachesBuilt
Definition: relcache.c:146
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1394
#define NUM_CRITICAL_SHARED_RELS
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1802
#define NUM_CRITICAL_LOCAL_INDEXES
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:93
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:25
Definition: fmgr.h:57
HeapTupleHeader t_data
Definition: htup.h:68
uint16 amsupport
Definition: amapi.h:219
List * rd_partcheck
Definition: rel.h:147
Bitmapset * rd_keyattr
Definition: rel.h:162
bool rd_partcheckvalid
Definition: rel.h:148
MemoryContext rd_pdcxt
Definition: rel.h:131
MemoryContext rd_partkeycxt
Definition: rel.h:127
TransactionId rd_partdesc_nodetached_xmin
Definition: rel.h:144
bool rd_indexvalid
Definition: rel.h:64
List * rd_indpred
Definition: rel.h:213
List * rd_fkeylist
Definition: rel.h:122
Oid * rd_exclprocs
Definition: rel.h:215
uint16 * rd_exclstrats
Definition: rel.h:216
List * rd_indexlist
Definition: rel.h:152
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:119
PartitionDesc rd_partdesc
Definition: rel.h:130
Oid rd_replidindex
Definition: rel.h:155
RegProcedure * rd_support
Definition: rel.h:209
PartitionDesc rd_partdesc_nodetached
Definition: rel.h:134
bytea ** rd_opcoptions
Definition: rel.h:218
PublicationDesc * rd_pubdesc
Definition: rel.h:168
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:240
TriggerDesc * trigdesc
Definition: rel.h:117
Bitmapset * rd_idattr
Definition: rel.h:164
List * rd_indexprs
Definition: rel.h:212
bool rd_attrsvalid
Definition: rel.h:161
Oid * rd_exclops
Definition: rel.h:214
Oid * rd_opcintype
Definition: rel.h:208
struct HeapTupleData * rd_indextuple
Definition: rel.h:194
MemoryContext rd_partcheckcxt
Definition: rel.h:149
int16 * rd_indoption
Definition: rel.h:211
Form_pg_index rd_index
Definition: rel.h:192
void * rd_amcache
Definition: rel.h:229
Oid rd_pkindex
Definition: rel.h:153
bool rd_fkeyvalid
Definition: rel.h:123
bool rd_statvalid
Definition: rel.h:66
List * rd_statlist
Definition: rel.h:158
MemoryContext rd_pddcxt
Definition: rel.h:135
RuleLock * rd_rules
Definition: rel.h:115
struct FmgrInfo * rd_supportinfo
Definition: rel.h:210
Oid * rd_opfamily
Definition: rel.h:207
MemoryContext rd_rulescxt
Definition: rel.h:116
Bitmapset * rd_pkattr
Definition: rel.h:163
PartitionKey rd_partkey
Definition: rel.h:126
bytea * rd_options
Definition: rel.h:175
Oid * rd_indcollation
Definition: rel.h:217
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:255
#define InvalidTransactionId
Definition: transam.h:31
#define VARSIZE(PTR)
Definition: varatt.h:279

References AllocateFile(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert(), ATTRIBUTE_FIXED_PART_SIZE, CacheMemoryContext, TupleDescData::constr, CreateTemplateTupleDesc(), criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabasePath, elog, FreeFile(), GETSTRUCT, TupleConstr::has_not_null, HEAPTUPLESIZE, i, InitIndexAmRoutine(), InvalidOid, InvalidSubTransactionId, InvalidTransactionId, len, MAXPGPATH, MemoryContextAlloc(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, NIL, NUM_CRITICAL_LOCAL_INDEXES, NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_SHARED_INDEXES, NUM_CRITICAL_SHARED_RELS, palloc(), palloc0(), pfree(), PG_BINARY_R, RelationData::pgstat_info, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_attrsvalid, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, 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_newRelfilelocatorSubid, RelationData::rd_opcintype, RelationData::rd_opcoptions, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_pubdesc, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_replidindex, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationData::rd_statlist, RelationData::rd_statvalid, RelationData::rd_support, RelationData::rd_supportinfo, RelationCacheInsert, RelationGetRelationName, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, repalloc(), snprintf, HeapTupleData::t_data, TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, TupleDescAttr, VARSIZE, and WARNING.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ LookupOpclassInfo()

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

Definition at line 1640 of file relcache.c.

1642 {
1643  OpClassCacheEnt *opcentry;
1644  bool found;
1645  Relation rel;
1646  SysScanDesc scan;
1647  ScanKeyData skey[3];
1648  HeapTuple htup;
1649  bool indexOK;
1650 
1651  if (OpClassCache == NULL)
1652  {
1653  /* First time through: initialize the opclass cache */
1654  HASHCTL ctl;
1655 
1656  /* Also make sure CacheMemoryContext exists */
1657  if (!CacheMemoryContext)
1659 
1660  ctl.keysize = sizeof(Oid);
1661  ctl.entrysize = sizeof(OpClassCacheEnt);
1662  OpClassCache = hash_create("Operator class cache", 64,
1663  &ctl, HASH_ELEM | HASH_BLOBS);
1664  }
1665 
1666  opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1667  &operatorClassOid,
1668  HASH_ENTER, &found);
1669 
1670  if (!found)
1671  {
1672  /* Initialize new entry */
1673  opcentry->valid = false; /* until known OK */
1674  opcentry->numSupport = numSupport;
1675  opcentry->supportProcs = NULL; /* filled below */
1676  }
1677  else
1678  {
1679  Assert(numSupport == opcentry->numSupport);
1680  }
1681 
1682  /*
1683  * When aggressively testing cache-flush hazards, we disable the operator
1684  * class cache and force reloading of the info on each call. This models
1685  * no real-world behavior, since the cache entries are never invalidated
1686  * otherwise. However it can be helpful for detecting bugs in the cache
1687  * loading logic itself, such as reliance on a non-nailed index. Given
1688  * the limited use-case and the fact that this adds a great deal of
1689  * expense, we enable it only for high values of debug_discard_caches.
1690  */
1691 #ifdef DISCARD_CACHES_ENABLED
1692  if (debug_discard_caches > 2)
1693  opcentry->valid = false;
1694 #endif
1695 
1696  if (opcentry->valid)
1697  return opcentry;
1698 
1699  /*
1700  * Need to fill in new entry. First allocate space, unless we already did
1701  * so in some previous attempt.
1702  */
1703  if (opcentry->supportProcs == NULL && numSupport > 0)
1704  opcentry->supportProcs = (RegProcedure *)
1706  numSupport * sizeof(RegProcedure));
1707 
1708  /*
1709  * To avoid infinite recursion during startup, force heap scans if we're
1710  * looking up info for the opclasses used by the indexes we would like to
1711  * reference here.
1712  */
1713  indexOK = criticalRelcachesBuilt ||
1714  (operatorClassOid != OID_BTREE_OPS_OID &&
1715  operatorClassOid != INT2_BTREE_OPS_OID);
1716 
1717  /*
1718  * We have to fetch the pg_opclass row to determine its opfamily and
1719  * opcintype, which are needed to look up related operators and functions.
1720  * It'd be convenient to use the syscache here, but that probably doesn't
1721  * work while bootstrapping.
1722  */
1723  ScanKeyInit(&skey[0],
1724  Anum_pg_opclass_oid,
1725  BTEqualStrategyNumber, F_OIDEQ,
1726  ObjectIdGetDatum(operatorClassOid));
1727  rel = table_open(OperatorClassRelationId, AccessShareLock);
1728  scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1729  NULL, 1, skey);
1730 
1731  if (HeapTupleIsValid(htup = systable_getnext(scan)))
1732  {
1733  Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1734 
1735  opcentry->opcfamily = opclassform->opcfamily;
1736  opcentry->opcintype = opclassform->opcintype;
1737  }
1738  else
1739  elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1740 
1741  systable_endscan(scan);
1743 
1744  /*
1745  * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1746  * the default ones (those with lefttype = righttype = opcintype).
1747  */
1748  if (numSupport > 0)
1749  {
1750  ScanKeyInit(&skey[0],
1751  Anum_pg_amproc_amprocfamily,
1752  BTEqualStrategyNumber, F_OIDEQ,
1753  ObjectIdGetDatum(opcentry->opcfamily));
1754  ScanKeyInit(&skey[1],
1755  Anum_pg_amproc_amproclefttype,
1756  BTEqualStrategyNumber, F_OIDEQ,
1757  ObjectIdGetDatum(opcentry->opcintype));
1758  ScanKeyInit(&skey[2],
1759  Anum_pg_amproc_amprocrighttype,
1760  BTEqualStrategyNumber, F_OIDEQ,
1761  ObjectIdGetDatum(opcentry->opcintype));
1762  rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1763  scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1764  NULL, 3, skey);
1765 
1766  while (HeapTupleIsValid(htup = systable_getnext(scan)))
1767  {
1768  Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1769 
1770  if (amprocform->amprocnum <= 0 ||
1771  (StrategyNumber) amprocform->amprocnum > numSupport)
1772  elog(ERROR, "invalid amproc number %d for opclass %u",
1773  amprocform->amprocnum, operatorClassOid);
1774 
1775  opcentry->supportProcs[amprocform->amprocnum - 1] =
1776  amprocform->amproc;
1777  }
1778 
1779  systable_endscan(scan);
1781  }
1782 
1783  opcentry->valid = true;
1784  return opcentry;
1785 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:666
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int debug_discard_caches
Definition: inval.c:240
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
static HTAB * OpClassCache
Definition: relcache.c:271
struct opclasscacheent OpClassCacheEnt
uint16 StrategyNumber
Definition: stratnum.h:22
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
StrategyNumber numSupport
Definition: relcache.c:265

References AccessShareLock, Assert(), BTEqualStrategyNumber, CacheMemoryContext, CreateCacheMemoryContext(), criticalRelcachesBuilt, debug_discard_caches, elog, HASHCTL::entrysize, ERROR, GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HeapTupleIsValid, HASHCTL::keysize, MemoryContextAllocZero(), opclasscacheent::numSupport, ObjectIdGetDatum(), opclasscacheent::opcfamily, opclasscacheent::opcintype, OpClassCache, ScanKeyInit(), opclasscacheent::supportProcs, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and opclasscacheent::valid.

Referenced by IndexSupportInitialize().

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3918 of file relcache.c.

3919 {
3923 
3924  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3925  EOXactListAdd(relation);
3926 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:781

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilelocatorSubid, and RelationData::rd_newRelfilelocatorSubid.

Referenced by ATExecSetTableSpace(), reindex_index(), RelationSetNewRelfilenumber(), and swap_relation_files().

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1039 of file relcache.c.

1040 {
1041  int in_progress_offset;
1042  Relation relation;
1043  Oid relid;
1044  HeapTuple pg_class_tuple;
1045  Form_pg_class relp;
1046 
1047  /*
1048  * This function and its subroutines can allocate a good deal of transient
1049  * data in CurrentMemoryContext. Traditionally we've just leaked that
1050  * data, reasoning that the caller's context is at worst of transaction
1051  * scope, and relcache loads shouldn't happen so often that it's essential
1052  * to recover transient data before end of statement/transaction. However
1053  * that's definitely not true when debug_discard_caches is active, and
1054  * perhaps it's not true in other cases.
1055  *
1056  * When debug_discard_caches is active or when forced to by
1057  * RECOVER_RELATION_BUILD_MEMORY=1, arrange to allocate the junk in a
1058  * temporary context that we'll free before returning. Make it a child of
1059  * caller's context so that it will get cleaned up appropriately if we
1060  * error out partway through.
1061  */
1062 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1063  MemoryContext tmpcxt = NULL;
1064  MemoryContext oldcxt = NULL;
1065 
1067  {
1069  "RelationBuildDesc workspace",
1071  oldcxt = MemoryContextSwitchTo(tmpcxt);
1072  }
1073 #endif
1074 
1075  /* Register to catch invalidation messages */
1077  {
1078  int allocsize;
1079 
1080  allocsize = in_progress_list_maxlen * 2;
1082  allocsize * sizeof(*in_progress_list));
1083  in_progress_list_maxlen = allocsize;
1084  }
1085  in_progress_offset = in_progress_list_len++;
1086  in_progress_list[in_progress_offset].reloid = targetRelId;
1087 retry:
1088  in_progress_list[in_progress_offset].invalidated = false;
1089 
1090  /*
1091  * find the tuple in pg_class corresponding to the given relation id
1092  */
1093  pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1094 
1095  /*
1096  * if no such tuple exists, return NULL
1097  */
1098  if (!HeapTupleIsValid(pg_class_tuple))
1099  {
1100 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1101  if (tmpcxt)
1102  {
1103  /* Return to caller's context, and blow away the temporary context */
1104  MemoryContextSwitchTo(oldcxt);
1105  MemoryContextDelete(tmpcxt);
1106  }
1107 #endif
1108  Assert(in_progress_offset + 1 == in_progress_list_len);
1110  return NULL;
1111  }
1112 
1113  /*
1114  * get information from the pg_class_tuple
1115  */
1116  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1117  relid = relp->oid;
1118  Assert(relid == targetRelId);
1119 
1120  /*
1121  * allocate storage for the relation descriptor, and copy pg_class_tuple
1122  * to relation->rd_rel.
1123  */
1124  relation = AllocateRelationDesc(relp);
1125 
1126  /*
1127  * initialize the relation's relation id (relation->rd_id)
1128  */
1129  RelationGetRelid(relation) = relid;
1130 
1131  /*
1132  * Normal relations are not nailed into the cache. Since we don't flush
1133  * new relations, it won't be new. It could be temp though.
1134  */
1135  relation->rd_refcnt = 0;
1136  relation->rd_isnailed = false;
1141  switch (relation->rd_rel->relpersistence)
1142  {
1143  case RELPERSISTENCE_UNLOGGED:
1144  case RELPERSISTENCE_PERMANENT:
1145  relation->rd_backend = INVALID_PROC_NUMBER;
1146  relation->rd_islocaltemp = false;
1147  break;
1148  case RELPERSISTENCE_TEMP:
1149  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1150  {
1151  relation->rd_backend = ProcNumberForTempRelations();
1152  relation->rd_islocaltemp = true;
1153  }
1154  else
1155  {
1156  /*
1157  * If it's a temp table, but not one of ours, we have to use
1158  * the slow, grotty method to figure out the owning backend.
1159  *
1160  * Note: it's possible that rd_backend gets set to
1161  * MyProcNumber here, in case we are looking at a pg_class
1162  * entry left over from a crashed backend that coincidentally
1163  * had the same ProcNumber we're using. We should *not*
1164  * consider such a table to be "ours"; this is why we need the
1165  * separate rd_islocaltemp flag. The pg_class entry will get
1166  * flushed if/when we clean out the corresponding temp table
1167  * namespace in preparation for using it.
1168  */
1169  relation->rd_backend =
1170  GetTempNamespaceProcNumber(relation->rd_rel->relnamespace);
1171  Assert(relation->rd_backend != INVALID_PROC_NUMBER);
1172  relation->rd_islocaltemp = false;
1173  }
1174  break;
1175  default:
1176  elog(ERROR, "invalid relpersistence: %c",
1177  relation->rd_rel->relpersistence);
1178  break;
1179  }
1180 
1181  /*
1182  * initialize the tuple descriptor (relation->rd_att).
1183  */
1184  RelationBuildTupleDesc(relation);
1185 
1186  /* foreign key data is not loaded till asked for */
1187  relation->rd_fkeylist = NIL;
1188  relation->rd_fkeyvalid = false;
1189 
1190  /* partitioning data is not loaded till asked for */
1191  relation->rd_partkey = NULL;
1192  relation->rd_partkeycxt = NULL;
1193  relation->rd_partdesc = NULL;
1194  relation->rd_partdesc_nodetached = NULL;
1196  relation->rd_pdcxt = NULL;
1197  relation->rd_pddcxt = NULL;
1198  relation->rd_partcheck = NIL;
1199  relation->rd_partcheckvalid = false;
1200  relation->rd_partcheckcxt = NULL;
1201 
1202  /*
1203  * initialize access method information
1204  */
1205  if (relation->rd_rel->relkind == RELKIND_INDEX ||
1206  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
1207  RelationInitIndexAccessInfo(relation);
1208  else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) ||
1209  relation->rd_rel->relkind == RELKIND_SEQUENCE)
1211  else
1212  Assert(relation->rd_rel->relam == InvalidOid);
1213 
1214  /* extract reloptions if any */
1215  RelationParseRelOptions(relation, pg_class_tuple);
1216 
1217  /*
1218  * Fetch rules and triggers that affect this relation.
1219  *
1220  * Note that RelationBuildRuleLock() relies on this being done after
1221  * extracting the relation's reloptions.
1222  */
1223  if (relation->rd_rel->relhasrules)
1224  RelationBuildRuleLock(relation);
1225  else
1226  {
1227  relation->rd_rules = NULL;
1228  relation->rd_rulescxt = NULL;
1229  }
1230 
1231  if (relation->rd_rel->relhastriggers)
1232  RelationBuildTriggers(relation);
1233  else
1234  relation->trigdesc = NULL;
1235 
1236  if (relation->rd_rel->relrowsecurity)
1237  RelationBuildRowSecurity(relation);
1238  else
1239  relation->rd_rsdesc = NULL;
1240 
1241  /*
1242  * initialize the relation lock manager information
1243  */
1244  RelationInitLockInfo(relation); /* see lmgr.c */
1245 
1246  /*
1247  * initialize physical addressing information for the relation
1248  */
1249  RelationInitPhysicalAddr(relation);
1250 
1251  /* make sure relation is marked as having no open file yet */
1252  relation->rd_smgr = NULL;
1253 
1254  /*
1255  * now we can free the memory allocated for pg_class_tuple
1256  */
1257  heap_freetuple(pg_class_tuple);
1258 
1259  /*
1260  * If an invalidation arrived mid-build, start over. Between here and the
1261  * end of this function, don't add code that does or reasonably could read
1262  * system catalogs. That range must be free from invalidation processing
1263  * for the !insertIt case. For the insertIt case, RelationCacheInsert()
1264  * will enroll this relation in ordinary relcache invalidation processing,
1265  */
1266  if (in_progress_list[in_progress_offset].invalidated)
1267  {
1268  RelationDestroyRelation(relation, false);
1269  goto retry;
1270  }
1271  Assert(in_progress_offset + 1 == in_progress_list_len);
1273 
1274  /*
1275  * Insert newly created relation into relcache hash table, if requested.
1276  *
1277  * There is one scenario in which we might find a hashtable entry already
1278  * present, even though our caller failed to find it: if the relation is a
1279  * system catalog or index that's used during relcache load, we might have
1280  * recursively created the same relcache entry during the preceding steps.
1281  * So allow RelationCacheInsert to delete any already-present relcache
1282  * entry for the same OID. The already-present entry should have refcount
1283  * zero (else somebody forgot to close it); in the event that it doesn't,
1284  * we'll elog a WARNING and leak the already-present entry.
1285  */
1286  if (insertIt)
1287  RelationCacheInsert(relation, true);
1288 
1289  /* It's fully valid */
1290  relation->rd_isvalid = true;
1291 
1292 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1293  if (tmpcxt)
1294  {
1295  /* Return to caller's context, and blow away the temporary context */
1296  MemoryContextSwitchTo(oldcxt);
1297  MemoryContextDelete(tmpcxt);
1298  }
1299 #endif
1300 
1301  return relation;
1302 }
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3658
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3751
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
#define ProcNumberForTempRelations()
Definition: proc.h:320
#define RECOVER_RELATION_BUILD_MEMORY
Definition: relcache.c:102
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:463
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:408
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1418
static int in_progress_list_maxlen
Definition: relcache.c:172
static void RelationDestroyRelation(Relation relation, bool remember_tupdesc)
Definition: relcache.c:2435
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:732
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:338
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:520
static InProgressEnt * in_progress_list
Definition: relcache.c:170
bool invalidated
Definition: relcache.c:167
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1856

References AllocateRelationDesc(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), CurrentMemoryContext, debug_discard_caches, elog, ERROR, GETSTRUCT, GetTempNamespaceProcNumber(), heap_freetuple(), HeapTupleIsValid, in_progress_list, in_progress_list_len, in_progress_list_maxlen, INVALID_PROC_NUMBER, inprogressent::invalidated, InvalidOid, InvalidSubTransactionId, InvalidTransactionId, isTempOrTempToastNamespace(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, ProcNumberForTempRelations, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_partcheck, RelationData::rd_partcheckcxt, RelationData::rd_partcheckvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RECOVER_RELATION_BUILD_MEMORY, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationDestroyRelation(), RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationParseRelOptions(), inprogressent::reloid, repalloc(), ScanPgRelation(), and RelationData::trigdesc.

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

◆ RelationBuildLocalRelation()

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

Definition at line 3476 of file relcache.c.

3487 {
3488  Relation rel;
3489  MemoryContext oldcxt;
3490  int natts = tupDesc->natts;
3491  int i;
3492  bool has_not_null;
3493  bool nailit;
3494 
3495  Assert(natts >= 0);
3496 
3497  /*
3498  * check for creation of a rel that must be nailed in cache.
3499  *
3500  * XXX this list had better match the relations specially handled in
3501  * RelationCacheInitializePhase2/3.
3502  */
3503  switch (relid)
3504  {
3505  case DatabaseRelationId:
3506  case AuthIdRelationId:
3507  case AuthMemRelationId:
3508  case RelationRelationId:
3509  case AttributeRelationId:
3510  case ProcedureRelationId:
3511  case TypeRelationId:
3512  nailit = true;
3513  break;
3514  default:
3515  nailit = false;
3516  break;
3517  }
3518 
3519  /*
3520  * check that hardwired list of shared rels matches what's in the
3521  * bootstrap .bki file. If you get a failure here during initdb, you
3522  * probably need to fix IsSharedRelation() to match whatever you've done
3523  * to the set of shared relations.
3524  */
3525  if (shared_relation != IsSharedRelation(relid))
3526  elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3527  relname, relid);
3528 
3529  /* Shared relations had better be mapped, too */
3530  Assert(mapped_relation || !shared_relation);
3531 
3532  /*
3533  * switch to the cache context to create the relcache entry.
3534  */
3535  if (!CacheMemoryContext)
3537 
3539 
3540  /*
3541  * allocate a new relation descriptor and fill in basic state fields.
3542  */
3543  rel = (Relation) palloc0(sizeof(RelationData));
3544 
3545  /* make sure relation is marked as having no open file yet */
3546  rel->rd_smgr = NULL;
3547 
3548  /* mark it nailed if appropriate */
3549  rel->rd_isnailed = nailit;
3550 
3551  rel->rd_refcnt = nailit ? 1 : 0;
3552 
3553  /* it's being created in this transaction */
3558 
3559  /*
3560  * create a new tuple descriptor from the one passed in. We do this
3561  * partly to copy it into the cache context, and partly because the new
3562  * relation can't have any defaults or constraints yet; they have to be
3563  * added in later steps, because they require additions to multiple system
3564  * catalogs. We can copy attnotnull constraints here, however.
3565  */
3566  rel->rd_att = CreateTupleDescCopy(tupDesc);
3567  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3568  has_not_null = false;
3569  for (i = 0; i < natts; i++)
3570  {
3571  Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3572  Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3573 
3574  datt->attidentity = satt->attidentity;
3575  datt->attgenerated = satt->attgenerated;
3576  datt->attnotnull = satt->attnotnull;
3577  has_not_null |= satt->attnotnull;
3578  }
3579 
3580  if (has_not_null)
3581  {
3582  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
3583 
3584  constr->has_not_null = true;
3585  rel->rd_att->constr = constr;
3586  }
3587 
3588  /*
3589  * initialize relation tuple form (caller may add/override data later)
3590  */
3592 
3593  namestrcpy(&rel->rd_rel->relname, relname);
3594  rel->rd_rel->relnamespace = relnamespace;
3595 
3596  rel->rd_rel->relkind = relkind;
3597  rel->rd_rel->relnatts = natts;
3598  rel->rd_rel->reltype = InvalidOid;
3599  /* needed when bootstrapping: */
3600  rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3601 
3602  /* set up persistence and relcache fields dependent on it */
3603  rel->rd_rel->relpersistence = relpersistence;
3604  switch (relpersistence)
3605  {
3606  case RELPERSISTENCE_UNLOGGED:
3607  case RELPERSISTENCE_PERMANENT:
3609  rel->rd_islocaltemp = false;
3610  break;
3611  case RELPERSISTENCE_TEMP:
3612  Assert(isTempOrTempToastNamespace(relnamespace));
3614  rel->rd_islocaltemp = true;
3615  break;
3616  default:
3617  elog(ERROR, "invalid relpersistence: %c", relpersistence);
3618  break;
3619  }
3620 
3621  /* if it's a materialized view, it's not populated initially */
3622  if (relkind == RELKIND_MATVIEW)
3623  rel->rd_rel->relispopulated = false;
3624  else
3625  rel->rd_rel->relispopulated = true;
3626 
3627  /* set replica identity -- system catalogs and non-tables don't have one */
3628  if (!IsCatalogNamespace(relnamespace) &&
3629  (relkind == RELKIND_RELATION ||
3630  relkind == RELKIND_MATVIEW ||
3631  relkind == RELKIND_PARTITIONED_TABLE))
3632  rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3633  else
3634  rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3635 
3636  /*
3637  * Insert relation physical and logical identifiers (OIDs) into the right
3638  * places. For a mapped relation, we set relfilenumber to zero and rely
3639  * on RelationInitPhysicalAddr to consult the map.
3640  */
3641  rel->rd_rel->relisshared = shared_relation;
3642 
3643  RelationGetRelid(rel) = relid;
3644 
3645  for (i = 0; i < natts; i++)
3646  TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3647 
3648  rel->rd_rel->reltablespace = reltablespace;
3649 
3650  if (mapped_relation)
3651  {
3652  rel->rd_rel->relfilenode = InvalidRelFileNumber;
3653  /* Add it to the active mapping information */
3654  RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3655  }
3656  else
3657  rel->rd_rel->relfilenode = relfilenumber;
3658 
3659  RelationInitLockInfo(rel); /* see lmgr.c */
3660 
3662 
3663  rel->rd_rel->relam = accessmtd;
3664 
3665  /*
3666  * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3667  * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3668  * require a long-lived current context.
3669  */
3670  MemoryContextSwitchTo(oldcxt);
3671 
3672  if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3674 
3675  /*
3676  * Okay to insert into the relcache hash table.
3677  *
3678  * Ordinarily, there should certainly not be an existing hash entry for
3679  * the same OID; but during bootstrap, when we create a "real" relcache
3680  * entry for one of the bootstrap relations, we'll be overwriting the
3681  * phony one created with formrdesc. So allow that to happen for nailed
3682  * rels.
3683  */
3684  RelationCacheInsert(rel, nailit);
3685 
3686  /*
3687  * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3688  * can't do this before storing relid in it.
3689  */
3690  EOXactListAdd(rel);
3691 
3692  /* It's fully valid */
3693  rel->rd_isvalid = true;
3694 
3695  /*
3696  * Caller expects us to pin the returned entry.
3697  */
3699 
3700  return rel;
3701 }
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:243
NameData relname
Definition: pg_class.h:38
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2153
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), ProcNumberForTempRelations, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationMapUpdateMap(), relname, TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5705 of file relcache.c.

5706 {
5707  List *puboids;
5708  ListCell *lc;
5709  MemoryContext oldcxt;
5710  Oid schemaid;
5711  List *ancestors = NIL;
5712  Oid relid = RelationGetRelid(relation);
5713 
5714  /*
5715  * If not publishable, it publishes no actions. (pgoutput_change() will
5716  * ignore it.)
5717  */
5718  if (!is_publishable_relation(relation))
5719  {
5720  memset(pubdesc, 0, sizeof(PublicationDesc));
5721  pubdesc->rf_valid_for_update = true;
5722  pubdesc->rf_valid_for_delete = true;
5723  pubdesc->cols_valid_for_update = true;
5724  pubdesc->cols_valid_for_delete = true;
5725  return;
5726  }
5727 
5728  if (relation->rd_pubdesc)
5729  {
5730  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5731  return;
5732  }
5733 
5734  memset(pubdesc, 0, sizeof(PublicationDesc));
5735  pubdesc->rf_valid_for_update = true;
5736  pubdesc->rf_valid_for_delete = true;
5737  pubdesc->cols_valid_for_update = true;
5738  pubdesc->cols_valid_for_delete = true;
5739 
5740  /* Fetch the publication membership info. */
5741  puboids = GetRelationPublications(relid);
5742  schemaid = RelationGetNamespace(relation);
5743  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5744 
5745  if (relation->rd_rel->relispartition)
5746  {
5747  /* Add publications that the ancestors are in too. */
5748  ancestors = get_partition_ancestors(relid);
5749 
5750  foreach(lc, ancestors)
5751  {
5752  Oid ancestor = lfirst_oid(lc);
5753 
5754  puboids = list_concat_unique_oid(puboids,
5755  GetRelationPublications(ancestor));
5756  schemaid = get_rel_namespace(ancestor);
5757  puboids = list_concat_unique_oid(puboids,
5758  GetSchemaPublications(schemaid));
5759  }
5760  }
5761  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5762 
5763  foreach(lc, puboids)
5764  {
5765  Oid pubid = lfirst_oid(lc);
5766  HeapTuple tup;
5767  Form_pg_publication pubform;
5768 
5769  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5770 
5771  if (!HeapTupleIsValid(tup))
5772  elog(ERROR, "cache lookup failed for publication %u", pubid);
5773 
5774  pubform = (Form_pg_publication) GETSTRUCT(tup);
5775 
5776  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5777  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5778  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5779  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5780 
5781  /*
5782  * Check if all columns referenced in the filter expression are part
5783  * of the REPLICA IDENTITY index or not.
5784  *
5785  * If the publication is FOR ALL TABLES then it means the table has no
5786  * row filters and we can skip the validation.
5787  */
5788  if (!pubform->puballtables &&
5789  (pubform->pubupdate || pubform->pubdelete) &&
5790  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5791  pubform->pubviaroot))
5792  {
5793  if (pubform->pubupdate)
5794  pubdesc->rf_valid_for_update = false;
5795  if (pubform->pubdelete)
5796  pubdesc->rf_valid_for_delete = false;
5797  }
5798 
5799  /*
5800  * Check if all columns are part of the REPLICA IDENTITY index or not.
5801  *
5802  * If the publication is FOR ALL TABLES then it means the table has no
5803  * column list and we can skip the validation.
5804  */
5805  if (!pubform->puballtables &&
5806  (pubform->pubupdate || pubform->pubdelete) &&
5807  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5808  pubform->pubviaroot))
5809  {
5810  if (pubform->pubupdate)
5811  pubdesc->cols_valid_for_update = false;
5812  if (pubform->pubdelete)
5813  pubdesc->cols_valid_for_delete = false;
5814  }
5815 
5816  ReleaseSysCache(tup);
5817 
5818  /*
5819  * If we know everything is replicated and the row filter is invalid
5820  * for update and delete, there is no point to check for other
5821  * publications.
5822  */
5823  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5824  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5825  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5826  break;
5827 
5828  /*
5829  * If we know everything is replicated and the column list is invalid
5830  * for update and delete, there is no point to check for other
5831  * publications.
5832  */
5833  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5834  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5835  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5836  break;
5837  }
5838 
5839  if (relation->rd_pubdesc)
5840  {
5841  pfree(relation->rd_pubdesc);
5842  relation->rd_pubdesc = NULL;
5843  }
5844 
5845  /* Now save copy of the descriptor in the relcache entry. */
5847  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5848  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5849  MemoryContextSwitchTo(oldcxt);
5850 }
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1930
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
bool pub_collist_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
Definition: pg_list.h:54
PublicationActions pubactions
bool cols_valid_for_delete
bool cols_valid_for_update
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References CacheMemoryContext, PublicationDesc::cols_valid_for_delete, PublicationDesc::cols_valid_for_update, elog, ERROR, get_partition_ancestors(), get_rel_namespace(), GetAllTablesPublications(), GetRelationPublications(), GetSchemaPublications(), GETSTRUCT, HeapTupleIsValid, is_publishable_relation(), lfirst_oid, list_concat_unique_oid(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), palloc(), pfree(), pub_collist_contains_invalid_column(), pub_rf_contains_invalid_column(), PublicationDesc::pubactions, PublicationActions::pubdelete, PublicationActions::pubinsert, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationData::rd_pubdesc, RelationData::rd_rel, RelationGetNamespace, RelationGetRelid, ReleaseSysCache(), PublicationDesc::rf_valid_for_delete, PublicationDesc::rf_valid_for_update, and SearchSysCache1().

Referenced by CheckCmdReplicaIdentity().

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 732 of file relcache.c.

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

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), BTEqualStrategyNumber, CacheMemoryContext, CMD_SELECT, GETSTRUCT, heap_getattr(), HeapTupleIsValid, InvalidOid, sort-test::key, MemoryContextAlloc(), MemoryContextCopyAndSetIdentifier, MemoryContextDelete(), MemoryContextSwitchTo(), RuleLock::numLocks, ObjectIdGetDatum(), pfree(), RelationData::rd_rel, RelationData::rd_rules, RelationData::rd_rulescxt, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationHasSecurityInvoker, repalloc(), RuleLock::rules, rules, ScanKeyInit(), setRuleCheckAsUser(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 520 of file relcache.c.

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

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

Referenced by RelationBuildDesc().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6760 of file relcache.c.

6761 {
6762  LWLockRelease(RelCacheInitLock);
6763 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1785

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6735 of file relcache.c.

6736 {
6737  char localinitfname[MAXPGPATH];
6738  char sharedinitfname[MAXPGPATH];
6739 
6740  if (DatabasePath)
6741  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6743  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6745 
6746  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6747 
6748  /*
6749  * The files might not be there if no backend has been started since the
6750  * last removal. But complain about failures other than ENOENT with
6751  * ERROR. Fortunately, it's not too late to abort the transaction if we
6752  * can't get rid of the would-be-obsolete init file.
6753  */
6754  if (DatabasePath)
6755  unlink_initfile(localinitfname, ERROR);
6756  unlink_initfile(sharedinitfname, ERROR);
6757 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1172
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6832

References DatabasePath, ERROR, LW_EXCLUSIVE, LWLockAcquire(), MAXPGPATH, RELCACHE_INIT_FILENAME, snprintf, and unlink_initfile().

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6775 of file relcache.c.

6776 {
6777  const char *tblspcdir = "pg_tblspc";
6778  DIR *dir;
6779  struct dirent *de;
6780  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6781 
6782  snprintf(path, sizeof(path), "global/%s",
6784  unlink_initfile(path, LOG);
6785 
6786  /* Scan everything in the default tablespace */
6788 
6789  /* Scan the tablespace link directory to find non-default tablespaces */
6790  dir = AllocateDir(tblspcdir);
6791 
6792  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6793  {
6794  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6795  {
6796  /* Scan the tablespace dir for per-database dirs */
6797  snprintf(path, sizeof(path), "%s/%s/%s",
6798  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6800  }
6801  }
6802 
6803  FreeDir(dir);
6804 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2961
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2924
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6808
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6808 of file relcache.c.

6809 {
6810  DIR *dir;
6811  struct dirent *de;
6812  char initfilename[MAXPGPATH * 2];
6813 
6814  /* Scan the tablespace directory to find per-database directories */
6815  dir = AllocateDir(tblspcpath);
6816 
6817  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6818  {
6819  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6820  {
6821  /* Try to remove the init file in each database */
6822  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6823  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6824  unlink_initfile(initfilename, LOG);
6825  }
6826  }
6827 
6828  FreeDir(dir);
6829 }

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

Referenced by RelationCacheInitFileRemove().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3944 of file relcache.c.

3945 {
3946  HASHCTL ctl;
3947  int allocsize;
3948 
3949  /*
3950  * make sure cache memory context exists
3951  */
3952  if (!CacheMemoryContext)
3954 
3955  /*
3956  * create hashtable that indexes the relcache
3957  */
3958  ctl.keysize = sizeof(Oid);
3959  ctl.entrysize = sizeof(RelIdCacheEnt);
3960  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3961  &ctl, HASH_ELEM | HASH_BLOBS);
3962 
3963  /*
3964  * reserve enough in_progress_list slots for many cases
3965  */
3966  allocsize = 4;
3969  allocsize * sizeof(*in_progress_list));
3970  in_progress_list_maxlen = allocsize;
3971 
3972  /*
3973  * relation mapper needs to be initialized too
3974  */
3976 }
#define INITRELCACHESIZE
Definition: relcache.c:3941
struct relidcacheent RelIdCacheEnt
void RelationMapInitialize(void)
Definition: relmapper.c:651

References CacheMemoryContext, CreateCacheMemoryContext(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, in_progress_list, in_progress_list_maxlen, INITRELCACHESIZE, HASHCTL::keysize, MemoryContextAlloc(), RelationIdCache, and RelationMapInitialize().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3990 of file relcache.c.

3991 {
3992  MemoryContext oldcxt;
3993 
3994  /*
3995  * relation mapper needs initialized too
3996  */
3998 
3999  /*
4000  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4001  * nothing.
4002  */
4004  return;
4005 
4006  /*
4007  * switch to cache memory context
4008  */
4010 
4011  /*
4012  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4013  * the cache with pre-made descriptors for the critical shared catalogs.
4014  */
4015  if (!load_relcache_init_file(true))
4016  {
4017  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4018  Natts_pg_database, Desc_pg_database);
4019  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4020  Natts_pg_authid, Desc_pg_authid);
4021  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4022  Natts_pg_auth_members, Desc_pg_auth_members);
4023  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4024  Natts_pg_shseclabel, Desc_pg_shseclabel);
4025  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4026  Natts_pg_subscription, Desc_pg_subscription);
4027 
4028 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4029  }
4030 
4031  MemoryContextSwitchTo(oldcxt);
4032 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6052
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:119
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1867
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:120
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:117
void RelationMapInitializePhase2(void)
Definition: relmapper.c:671

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

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 4049 of file relcache.c.

4050 {
4051  HASH_SEQ_STATUS status;
4052  RelIdCacheEnt *idhentry;
4053  MemoryContext oldcxt;
4054  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
4055 
4056  /*
4057  * relation mapper needs initialized too
4058  */
4060 
4061  /*
4062  * switch to cache memory context
4063  */
4065 
4066  /*
4067  * Try to load the local relcache cache file. If unsuccessful, bootstrap
4068  * the cache with pre-made descriptors for the critical "nailed-in" system
4069  * catalogs.
4070  */
4071  if (IsBootstrapProcessingMode() ||
4072  !load_relcache_init_file(false))
4073  {
4074  needNewCacheFile = true;
4075 
4076  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4077  Natts_pg_class, Desc_pg_class);
4078  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4079  Natts_pg_attribute, Desc_pg_attribute);
4080  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4081  Natts_pg_proc, Desc_pg_proc);
4082  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4083  Natts_pg_type, Desc_pg_type);
4084 
4085 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4086  }
4087 
4088  MemoryContextSwitchTo(oldcxt);
4089 
4090  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4092  return;
4093 
4094  /*
4095  * If we didn't get the critical system indexes loaded into relcache, do
4096  * so now. These are critical because the catcache and/or opclass cache
4097  * depend on them for fetches done during relcache load. Thus, we have an
4098  * infinite-recursion problem. We can break the recursion by doing
4099  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4100  * performance, we only want to do that until we have the critical indexes
4101  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4102  * decide whether to do heapscan or indexscan at the key spots, and we set
4103  * it true after we've loaded the critical indexes.
4104  *
4105  * The critical indexes are marked as "nailed in cache", partly to make it
4106  * easy for load_relcache_init_file to count them, but mainly because we
4107  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4108  * true. (NOTE: perhaps it would be possible to reload them by
4109  * temporarily setting criticalRelcachesBuilt to false again. For now,
4110  * though, we just nail 'em in.)
4111  *
4112  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4113  * in the same way as the others, because the critical catalogs don't
4114  * (currently) have any rules or triggers, and so these indexes can be
4115  * rebuilt without inducing recursion. However they are used during
4116  * relcache load when a rel does have rules or triggers, so we choose to
4117  * nail them for performance reasons.
4118  */
4120  {
4121  load_critical_index(ClassOidIndexId,
4122  RelationRelationId);
4123  load_critical_index(AttributeRelidNumIndexId,
4124  AttributeRelationId);
4125  load_critical_index(IndexRelidIndexId,
4126  IndexRelationId);
4127  load_critical_index(OpclassOidIndexId,
4128  OperatorClassRelationId);
4129  load_critical_index(AccessMethodProcedureIndexId,
4130  AccessMethodProcedureRelationId);
4131  load_critical_index(RewriteRelRulenameIndexId,
4132  RewriteRelationId);
4133  load_critical_index(TriggerRelidNameIndexId,
4134  TriggerRelationId);
4135 
4136 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4137 
4138  criticalRelcachesBuilt = true;
4139  }
4140 
4141  /*
4142  * Process critical shared indexes too.
4143  *
4144  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4145  * initial lookup of MyDatabaseId, without which we'll never find any
4146  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4147  * database OID, so it instead depends on DatabaseOidIndexId. We also
4148  * need to nail up some indexes on pg_authid and pg_auth_members for use
4149  * during client authentication. SharedSecLabelObjectIndexId isn't
4150  * critical for the core system, but authentication hooks might be
4151  * interested in it.
4152  */
4154  {
4155  load_critical_index(DatabaseNameIndexId,
4156  DatabaseRelationId);
4157  load_critical_index(DatabaseOidIndexId,
4158  DatabaseRelationId);
4159  load_critical_index(AuthIdRolnameIndexId,
4160  AuthIdRelationId);
4161  load_critical_index(AuthIdOidIndexId,
4162  AuthIdRelationId);
4163  load_critical_index(AuthMemMemRoleIndexId,
4164  AuthMemRelationId);
4165  load_critical_index(SharedSecLabelObjectIndexId,
4166  SharedSecLabelRelationId);
4167 
4168 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4169 
4171  }
4172 
4173  /*
4174  * Now, scan all the relcache entries and update anything that might be
4175  * wrong in the results from formrdesc or the relcache cache file. If we
4176  * faked up relcache entries using formrdesc, then read the real pg_class
4177  * rows and replace the fake entries with them. Also, if any of the
4178  * relcache entries have rules, triggers, or security policies, load that
4179  * info the hard way since it isn't recorded in the cache file.
4180  *
4181  * Whenever we access the catalogs to read data, there is a possibility of
4182  * a shared-inval cache flush causing relcache entries to be removed.
4183  * Since hash_seq_search only guarantees to still work after the *current*
4184  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4185  * We handle this by restarting the scan from scratch after each access.
4186  * This is theoretically O(N^2), but the number of entries that actually
4187  * need to be fixed is small enough that it doesn't matter.
4188  */
4189  hash_seq_init(&status, RelationIdCache);
4190 
4191  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4192  {
4193  Relation relation = idhentry->reldesc;
4194  bool restart = false;
4195 
4196  /*
4197  * Make sure *this* entry doesn't get flushed while we work with it.
4198  */
4200 
4201  /*
4202  * If it's a faked-up entry, read the real pg_class tuple.
4203  */
4204  if (relation->rd_rel->relowner == InvalidOid)
4205  {
4206  HeapTuple htup;
4207  Form_pg_class relp;
4208 
4209  htup = SearchSysCache1(RELOID,
4210  ObjectIdGetDatum(RelationGetRelid(relation)));
4211  if (!HeapTupleIsValid(htup))
4212  elog(FATAL, "cache lookup failed for relation %u",
4213  RelationGetRelid(relation));
4214  relp = (Form_pg_class) GETSTRUCT(htup);
4215 
4216  /*
4217  * Copy tuple to relation->rd_rel. (See notes in
4218  * AllocateRelationDesc())
4219  */
4220  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4221 
4222  /* Update rd_options while we have the tuple */
4223  if (relation->rd_options)
4224  pfree(relation->rd_options);
4225  RelationParseRelOptions(relation, htup);
4226 
4227  /*
4228  * Check the values in rd_att were set up correctly. (We cannot
4229  * just copy them over now: formrdesc must have set up the rd_att
4230  * data correctly to start with, because it may already have been
4231  * copied into one or more catcache entries.)
4232  */
4233  Assert(relation->rd_att->tdtypeid == relp->reltype);
4234  Assert(relation->rd_att->tdtypmod == -1);
4235 
4236  ReleaseSysCache(htup);
4237 
4238  /* relowner had better be OK now, else we'll loop forever */
4239  if (relation->rd_rel->relowner == InvalidOid)
4240  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4241  RelationGetRelationName(relation));
4242 
4243  restart = true;
4244  }
4245 
4246  /*
4247  * Fix data that isn't saved in relcache cache file.
4248  *
4249  * relhasrules or relhastriggers could possibly be wrong or out of
4250  * date. If we don't actually find any rules or triggers, clear the
4251  * local copy of the flag so that we don't get into an infinite loop
4252  * here. We don't make any attempt to fix the pg_class entry, though.
4253  */
4254  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4255  {
4256  RelationBuildRuleLock(relation);
4257  if (relation->rd_rules == NULL)
4258  relation->rd_rel->relhasrules = false;
4259  restart = true;
4260  }
4261  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4262  {
4263  RelationBuildTriggers(relation);
4264  if (relation->trigdesc == NULL)
4265  relation->rd_rel->relhastriggers = false;
4266  restart = true;
4267  }
4268 
4269  /*
4270  * Re-load the row security policies if the relation has them, since
4271  * they are not preserved in the cache. Note that we can never NOT
4272  * have a policy while relrowsecurity is true,
4273  * RelationBuildRowSecurity will create a single default-deny policy
4274  * if there is no policy defined in pg_policy.
4275  */
4276  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4277  {
4278  RelationBuildRowSecurity(relation);
4279 
4280  Assert(relation->rd_rsdesc != NULL);
4281  restart = true;
4282  }
4283 
4284  /* Reload tableam data if needed */
4285  if (relation->rd_tableam == NULL &&
4286  (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4287  {
4289  Assert(relation->rd_tableam != NULL);
4290 
4291  restart = true;
4292  }
4293 
4294  /* Release hold on the relation */
4296 
4297  /* Now, restart the hashtable scan if needed */
4298  if (restart)
4299  {
4300  hash_seq_term(&status);
4301  hash_seq_init(&status, RelationIdCache);
4302  }
4303  }
4304 
4305  /*
4306  * Lastly, write out new relcache cache files if needed. We don't bother
4307  * to distinguish cases where only one of the two needs an update.
4308  */
4309  if (needNewCacheFile)
4310  {
4311  /*
4312  * Force all the catcaches to finish initializing and thereby open the
4313  * catalogs and indexes they use. This will preload the relcache with
4314  * entries for all the most important system catalogs and indexes, so
4315  * that the init files will be most useful for future backends.
4316  */
4318 
4319  /* now write the files */
4321  write_relcache_init_file(false);
4322  }
4323 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1471
#define FATAL
Definition: elog.h:41
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2166
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:112
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:113
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6468
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:114
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4332
void RelationMapInitializePhase3(void)
Definition: relmapper.c:692
void InitCatalogCachePhase2(void)
Definition: syscache.c:177

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, 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, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum(), pfree(), RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIdCache, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), SearchSysCache1(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2966 of file relcache.c.

2967 {
2968  HASH_SEQ_STATUS status;
2969  RelIdCacheEnt *idhentry;
2970  Relation relation;
2971  List *rebuildFirstList = NIL;
2972  List *rebuildList = NIL;
2973  ListCell *l;
2974  int i;
2975 
2976  /*
2977  * Reload relation mapping data before starting to reconstruct cache.
2978  */
2980 
2981  /* Phase 1 */
2982  hash_seq_init(&status, RelationIdCache);
2983 
2984  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2985  {
2986  relation = idhentry->reldesc;
2987 
2988  /*
2989  * Ignore new relations; no other backend will manipulate them before
2990  * we commit. Likewise, before replacing a relation's relfilelocator,
2991  * we shall have acquired AccessExclusiveLock and drained any
2992  * applicable pending invalidations.
2993  */
2994  if (relation->rd_createSubid != InvalidSubTransactionId ||
2996  continue;
2997 
2999 
3000  if (RelationHasReferenceCountZero(relation))
3001  {
3002  /* Delete this entry immediately */
3003  Assert(!relation->rd_isnailed);
3004  RelationClearRelation(relation, false);
3005  }
3006  else
3007  {
3008  /*
3009  * If it's a mapped relation, immediately update its rd_locator in
3010  * case its relfilenumber changed. We must do this during phase 1
3011  * in case the relation is consulted during rebuild of other
3012  * relcache entries in phase 2. It's safe since consulting the
3013  * map doesn't involve any access to relcache entries.
3014  */
3015  if (RelationIsMapped(relation))
3016  RelationInitPhysicalAddr(relation);
3017 
3018  /*
3019  * Add this entry to list of stuff to rebuild in second pass.
3020  * pg_class goes to the front of rebuildFirstList while
3021  * pg_class_oid_index goes to the back of rebuildFirstList, so
3022  * they are done first and second respectively. Other nailed
3023  * relations go to the front of rebuildList, so they'll be done
3024  * next in no particular order; and everything else goes to the
3025  * back of rebuildList.
3026  */
3027  if (RelationGetRelid(relation) == RelationRelationId)
3028  rebuildFirstList = lcons(relation, rebuildFirstList);
3029  else if (RelationGetRelid(relation) == ClassOidIndexId)
3030  rebuildFirstList = lappend(rebuildFirstList, relation);
3031  else if (relation->rd_isnailed)
3032  rebuildList = lcons(relation, rebuildList);
3033  else
3034  rebuildList = lappend(rebuildList, relation);
3035  }
3036  }
3037 
3038  /*
3039  * We cannot destroy the SMgrRelations as there might still be references
3040  * to them, but close the underlying file descriptors.
3041  */
3042  smgrreleaseall();
3043 
3044  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3045  foreach(l, rebuildFirstList)
3046  {
3047  relation = (Relation) lfirst(l);
3048  RelationClearRelation(relation, true);
3049  }
3050  list_free(rebuildFirstList);
3051  foreach(l, rebuildList)
3052  {
3053  relation = (Relation) lfirst(l);
3054  RelationClearRelation(relation, true);
3055  }
3056  list_free(rebuildList);
3057 
3058  if (!debug_discard)
3059  /* Any RelationBuildDesc() on the stack must start over. */
3060  for (i = 0; i < in_progress_list_len; i++)
3061  in_progress_list[i].invalidated = true;
3062 }
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
List * lcons(void *datum, List *list)
Definition: list.c:495
#define RelationIsMapped(relation)
Definition: rel.h:554
static long relcacheInvalsReceived
Definition: relcache.c:154
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:353

References Assert(), hash_seq_init(), hash_seq_search(), i, in_progress_list, in_progress_list_len, InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NIL, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationClearRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, and smgrreleaseall().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2910 of file relcache.c.

2911 {
2912  Relation relation;
2913 
2914  RelationIdCacheLookup(relationId, relation);
2915 
2916  if (PointerIsValid(relation))
2917  {
2919  RelationFlushRelation(relation);
2920  }
2921  else
2922  {
2923  int i;
2924 
2925  for (i = 0; i < in_progress_list_len; i++)
2926  if (in_progress_list[i].reloid == relationId)
2927  in_progress_list[i].invalidated = true;
2928  }
2929 }
#define PointerIsValid(pointer)
Definition: c.h:750
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2833

References i, in_progress_list, in_progress_list_len, inprogressent::invalidated, PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2528 of file relcache.c.

2529 {
2530  /*
2531  * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of
2532  * course it would be an equally bad idea to blow away one with nonzero
2533  * refcnt, since that would leave someone somewhere with a dangling
2534  * pointer. All callers are expected to have verified that this holds.
2535  */
2536  Assert(rebuild ?
2537  !RelationHasReferenceCountZero(relation) :
2538  RelationHasReferenceCountZero(relation));
2539 
2540  /*
2541  * Make sure smgr and lower levels close the relation's files, if they
2542  * weren't closed already. If the relation is not getting deleted, the
2543  * next smgr access should reopen the files automatically. This ensures
2544  * that the low-level file access state is updated after, say, a vacuum
2545  * truncation.
2546  */
2547  RelationCloseSmgr(relation);
2548 
2549  /* Free AM cached data, if any */
2550  if (relation->rd_amcache)
2551  pfree(relation->rd_amcache);
2552  relation->rd_amcache = NULL;
2553 
2554  /*
2555  * Treat nailed-in system relations separately, they always need to be
2556  * accessible, so we can't blow them away.
2557  */
2558  if (relation->rd_isnailed)
2559  {
2560  RelationReloadNailed(relation);
2561  return;
2562  }
2563 
2564  /* Mark it invalid until we've finished rebuild */
2565  relation->rd_isvalid = false;
2566 
2567  /* See RelationForgetRelation(). */
2568  if (relation->rd_droppedSubid != InvalidSubTransactionId)
2569  return;
2570 
2571  /*
2572  * Even non-system indexes should not be blown away if they are open and
2573  * have valid index support information. This avoids problems with active
2574  * use of the index support information. As with nailed indexes, we
2575  * re-read the pg_class row to handle possible physical relocation of the
2576  * index, and we check for pg_index updates too.
2577  */
2578  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2579  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2580  relation->rd_refcnt > 0 &&
2581  relation->rd_indexcxt != NULL)
2582  {
2583  if (IsTransactionState())
2584  RelationReloadIndexInfo(relation);
2585  return;
2586  }
2587 
2588  /*
2589  * If we're really done with the relcache entry, blow it away. But if
2590  * someone is still using it, reconstruct the whole deal without moving
2591  * the physical RelationData record (so that the someone's pointer is
2592  * still valid).
2593  */
2594  if (!rebuild)
2595  {
2596  /* Remove it from the hash table */
2597  RelationCacheDelete(relation);
2598 
2599  /* And release storage */
2600  RelationDestroyRelation(relation, false);
2601  }
2602  else if (!IsTransactionState())
2603  {
2604  /*
2605  * If we're not inside a valid transaction, we can't do any catalog
2606  * access so it's not possible to rebuild yet. Just exit, leaving
2607  * rd_isvalid = false so that the rebuild will occur when the entry is
2608  * next opened.
2609  *
2610  * Note: it's possible that we come here during subtransaction abort,
2611  * and the reason for wanting to rebuild is that the rel is open in
2612  * the outer transaction. In that case it might seem unsafe to not
2613  * rebuild immediately, since whatever code has the rel already open
2614  * will keep on using the relcache entry as-is. However, in such a
2615  * case the outer transaction should be holding a lock that's
2616  * sufficient to prevent any significant change in the rel's schema,
2617  * so the existing entry contents should be good enough for its
2618  * purposes; at worst we might be behind on statistics updates or the
2619  * like. (See also CheckTableNotInUse() and its callers.) These same
2620  * remarks also apply to the cases above where we exit without having
2621  * done RelationReloadIndexInfo() yet.
2622  */
2623  return;
2624  }
2625  else
2626  {
2627  /*
2628  * Our strategy for rebuilding an open relcache entry is to build a
2629  * new entry from scratch, swap its contents with the old entry, and
2630  * finally delete the new entry (along with any infrastructure swapped
2631  * over from the old entry). This is to avoid trouble in case an
2632  * error causes us to lose control partway through. The old entry
2633  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2634  * on next access. Meanwhile it's not any less valid than it was
2635  * before, so any code that might expect to continue accessing it
2636  * isn't hurt by the rebuild failure. (Consider for example a
2637  * subtransaction that ALTERs a table and then gets canceled partway
2638  * through the cache entry rebuild. The outer transaction should
2639  * still see the not-modified cache entry as valid.) The worst
2640  * consequence of an error is leaking the necessarily-unreferenced new
2641  * entry, and this shouldn't happen often enough for that to be a big
2642  * problem.
2643  *
2644  * When rebuilding an open relcache entry, we must preserve ref count,
2645  * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2646  * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2647  * and partition descriptor substructures in place, because various
2648  * places assume that these structures won't move while they are
2649  * working with an open relcache entry. (Note: the refcount
2650  * mechanism for tupledescs might someday allow us to remove this hack
2651  * for the tupledesc.)
2652  *
2653  * Note that this process does not touch CurrentResourceOwner; which
2654  * is good because whatever ref counts the entry may have do not
2655  * necessarily belong to that resource owner.
2656  */
2657  Relation newrel;
2658  Oid save_relid = RelationGetRelid(relation);
2659  bool keep_tupdesc;
2660  bool keep_rules;
2661  bool keep_policies;
2662  bool keep_partkey;
2663 
2664  /* Build temporary entry, but don't link it into hashtable */
2665  newrel = RelationBuildDesc(save_relid, false);
2666 
2667  /*
2668  * Between here and the end of the swap, don't add code that does or
2669  * reasonably could read system catalogs. That range must be free
2670  * from invalidation processing. See RelationBuildDesc() manipulation
2671  * of in_progress_list.
2672  */
2673 
2674  if (newrel == NULL)
2675  {
2676  /*
2677  * We can validly get here, if we're using a historic snapshot in
2678  * which a relation, accessed from outside logical decoding, is
2679  * still invisible. In that case it's fine to just mark the
2680  * relation as invalid and return - it'll fully get reloaded by
2681  * the cache reset at the end of logical decoding (or at the next
2682  * access). During normal processing we don't want to ignore this
2683  * case as it shouldn't happen there, as explained below.
2684  */
2685  if (HistoricSnapshotActive())
2686  return;
2687 
2688  /*
2689  * This shouldn't happen as dropping a relation is intended to be
2690  * impossible if still referenced (cf. CheckTableNotInUse()). But
2691  * if we get here anyway, we can't just delete the relcache entry,
2692  * as it possibly could get accessed later (as e.g. the error
2693  * might get trapped and handled via a subtransaction rollback).
2694  */
2695  elog(ERROR, "relation %u deleted while still in use", save_relid);
2696  }
2697 
2698  /*
2699  * If we were to, again, have cases of the relkind of a relcache entry
2700  * changing, we would need to ensure that pgstats does not get
2701  * confused.
2702  */
2703  Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind);
2704 
2705  keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2706  keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2707  keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2708  /* partkey is immutable once set up, so we can always keep it */
2709  keep_partkey = (relation->rd_partkey != NULL);
2710 
2711  /*
2712  * Perform swapping of the relcache entry contents. Within this
2713  * process the old entry is momentarily invalid, so there *must* be no
2714  * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2715  * all-in-line code for safety.
2716  *
2717  * Since the vast majority of fields should be swapped, our method is
2718  * to swap the whole structures and then re-swap those few fields we
2719  * didn't want swapped.
2720  */
2721 #define SWAPFIELD(fldtype, fldname) \
2722  do { \
2723  fldtype _tmp = newrel->fldname; \
2724  newrel->fldname = relation->fldname; \
2725  relation->fldname = _tmp; \
2726  } while (0)
2727 
2728  /* swap all Relation struct fields */
2729  {
2730  RelationData tmpstruct;
2731 
2732  memcpy(&tmpstruct, newrel, sizeof(RelationData));
2733  memcpy(newrel, relation, sizeof(RelationData));
2734  memcpy(relation, &tmpstruct, sizeof(RelationData));
2735  }
2736 
2737  /* rd_smgr must not be swapped, due to back-links from smgr level */
2738  SWAPFIELD(SMgrRelation, rd_smgr);
2739  /* rd_refcnt must be preserved */
2740  SWAPFIELD(int, rd_refcnt);
2741  /* isnailed shouldn't change */
2742  Assert(newrel->rd_isnailed == relation->rd_isnailed);
2743  /* creation sub-XIDs must be preserved */
2744  SWAPFIELD(SubTransactionId, rd_createSubid);
2745  SWAPFIELD(SubTransactionId, rd_newRelfilelocatorSubid);
2746  SWAPFIELD(SubTransactionId, rd_firstRelfilelocatorSubid);
2747  SWAPFIELD(SubTransactionId, rd_droppedSubid);
2748  /* un-swap rd_rel pointers, swap contents instead */
2749  SWAPFIELD(Form_pg_class, rd_rel);
2750  /* ... but actually, we don't have to update newrel->rd_rel */
2751  memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2752  /* preserve old tupledesc, rules, policies if no logical change */
2753  if (keep_tupdesc)
2754  SWAPFIELD(TupleDesc, rd_att);
2755  if (keep_rules)
2756  {
2757  SWAPFIELD(RuleLock *, rd_rules);
2758  SWAPFIELD(MemoryContext, rd_rulescxt);
2759  }
2760  if (keep_policies)
2761  SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2762  /* toast OID override must be preserved */
2763  SWAPFIELD(Oid, rd_toastoid);
2764  /* pgstat_info / enabled must be preserved */
2765  SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2766  SWAPFIELD(bool, pgstat_enabled);
2767  /* preserve old partition key if we have one */
2768  if (keep_partkey)
2769  {
2770  SWAPFIELD(PartitionKey, rd_partkey);
2771  SWAPFIELD(MemoryContext, rd_partkeycxt);
2772  }
2773  if (newrel->rd_pdcxt != NULL || newrel->rd_pddcxt != NULL)
2774  {
2775  /*
2776  * We are rebuilding a partitioned relation with a non-zero
2777  * reference count, so we must keep the old partition descriptor
2778  * around, in case there's a PartitionDirectory with a pointer to
2779  * it. This means we can't free the old rd_pdcxt yet. (This is
2780  * necessary because RelationGetPartitionDesc hands out direct
2781  * pointers to the relcache's data structure, unlike our usual
2782  * practice which is to hand out copies. We'd have the same
2783  * problem with rd_partkey, except that we always preserve that
2784  * once created.)
2785  *
2786  * To ensure that it's not leaked completely, re-attach it to the
2787  * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2788  * in the unlikely event that there is one already. (Compare hack
2789  * in RelationBuildPartitionDesc.) RelationClose will clean up
2790  * any such contexts once the reference count reaches zero.
2791  *
2792  * In the case where the reference count is zero, this code is not
2793  * reached, which should be OK because in that case there should
2794  * be no PartitionDirectory with a pointer to the old entry.
2795  *
2796  * Note that newrel and relation have already been swapped, so the
2797  * "old" partition descriptor is actually the one hanging off of
2798  * newrel.
2799  */
2800  relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2801  relation->rd_partdesc_nodetached = NULL;
2803  if (relation->rd_pdcxt != NULL) /* probably never happens */
2804  MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2805  else
2806  relation->rd_pdcxt = newrel->rd_pdcxt;
2807  if (relation->rd_pddcxt != NULL)
2808  MemoryContextSetParent(newrel->rd_pddcxt, relation->rd_pddcxt);
2809  else
2810  relation->rd_pddcxt = newrel->rd_pddcxt;
2811  /* drop newrel's pointers so we don't destroy it below */
2812  newrel->rd_partdesc = NULL;
2813  newrel->rd_partdesc_nodetached = NULL;
2815  newrel->rd_pdcxt = NULL;
2816  newrel->rd_pddcxt = NULL;
2817  }
2818 
2819 #undef SWAPFIELD
2820 
2821  /* And now we can throw away the temporary entry */
2822  RelationDestroyRelation(newrel, !keep_tupdesc);
2823  }
2824 }
uint32 SubTransactionId
Definition: c.h:643
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:625
static void RelationCloseSmgr(Relation relation)
Definition: rel.h:582
static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
Definition: relcache.c:907
static void RelationReloadNailed(Relation relation)
Definition: relcache.c:2363
#define RelationCacheDelete(RELATION)
Definition: relcache.c:243
static bool equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
Definition: relcache.c:998
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2249
#define SWAPFIELD(fldtype, fldname)
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:419
bool IsTransactionState(void)
Definition: xact.c:379

References Assert(), CLASS_TUPLE_SIZE, elog, equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), InvalidSubTransactionId, InvalidTransactionId, IsTransactionState(), MemoryContextSetParent(), pfree(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_droppedSubid, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationBuildDesc(), RelationCacheDelete, RelationCloseSmgr(), RelationDestroyRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationReloadIndexInfo(), RelationReloadNailed(), and SWAPFIELD.

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2186 of file relcache.c.

2187 {
2188  /* Note: no locking manipulations needed */
2190 
2191  RelationCloseCleanup(relation);
2192 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2195

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

Referenced by index_close(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), pgoutput_row_filter_init(), relation_close(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), and ReorderBufferToastReplace().

◆ RelationCloseCleanup()

static void RelationCloseCleanup ( Relation  relation)
static

Definition at line 2195 of file relcache.c.

2196 {
2197  /*
2198  * If the relation is no longer open in this session, we can clean up any
2199  * stale partition descriptors it has. This is unlikely, so check to see
2200  * if there are child contexts before expending a call to mcxt.c.
2201  */
2202  if (RelationHasReferenceCountZero(relation))
2203  {
2204  if (relation->rd_pdcxt != NULL &&
2205  relation->rd_pdcxt->firstchild != NULL)
2207 
2208  if (relation->rd_pddcxt != NULL &&
2209  relation->rd_pddcxt->firstchild != NULL)
2211  }
2212 
2213 #ifdef RELCACHE_FORCE_RELEASE
2214  if (RelationHasReferenceCountZero(relation) &&
2215  relation->rd_createSubid == InvalidSubTransactionId &&
2217  RelationClearRelation(relation, false);
2218 #endif
2219 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:527
MemoryContext firstchild
Definition: memnodes.h:128

References MemoryContextData::firstchild, InvalidSubTransactionId, MemoryContextDeleteChildren(), RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationClearRelation(), and RelationHasReferenceCountZero.

Referenced by RelationClose(), and ResOwnerReleaseRelation().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2166 of file relcache.c.

2167 {
2168  Assert(rel->rd_refcnt > 0);
2169  rel->rd_refcnt -= 1;
2172 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2139
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References Assert(), CurrentResourceOwner, IsBootstrapProcessingMode, RelationData::rd_refcnt, and ResourceOwnerForgetRelationRef().

Referenced by DestroyPartitionDirectory(), heap_endscan(), index_endscan(), RelationCacheInitializePhase3(), RelationClose(), and RelationFlushRelation().

◆ RelationDestroyRelation()

static void RelationDestroyRelation ( Relation  relation,
bool  remember_tupdesc 
)
static

Definition at line 2435 of file relcache.c.

2436 {
2438 
2439  /*
2440  * Make sure smgr and lower levels close the relation's files, if they
2441  * weren't closed already. (This was probably done by caller, but let's
2442  * just be real sure.)
2443  */
2444  RelationCloseSmgr(relation);
2445 
2446  /* break mutual link with stats entry */
2447  pgstat_unlink_relation(relation);
2448 
2449  /*
2450  * Free all the subsidiary data structures of the relcache entry, then the
2451  * entry itself.
2452  */
2453  if (relation->rd_rel)
2454  pfree(relation->rd_rel);
2455  /* can't use DecrTupleDescRefCount here */
2456  Assert(relation->rd_att->tdrefcount > 0);
2457  if (--relation->rd_att->tdrefcount == 0)
2458  {
2459  /*
2460  * If we Rebuilt a relcache entry during a transaction then its
2461  * possible we did that because the TupDesc changed as the result of
2462  * an ALTER TABLE that ran at less than AccessExclusiveLock. It's
2463  * possible someone copied that TupDesc, in which case the copy would
2464  * point to free'd memory. So if we rebuild an entry we keep the
2465  * TupDesc around until end of transaction, to be safe.
2466  */
2467  if (remember_tupdesc)
2469  else
2470  FreeTupleDesc(relation->rd_att);
2471  }
2472  FreeTriggerDesc(relation->trigdesc);
2473  list_free_deep(relation->rd_fkeylist);
2474  list_free(relation->rd_indexlist);
2475  list_free(relation->rd_statlist);
2476  bms_free(relation->rd_keyattr);
2477  bms_free(relation->rd_pkattr);
2478  bms_free(relation->rd_idattr);
2479  bms_free(relation->rd_hotblockingattr);
2480  bms_free(relation->rd_summarizedattr);
2481  if (relation->rd_pubdesc)
2482  pfree(relation->rd_pubdesc);
2483  if (relation->rd_options)
2484  pfree(relation->rd_options);
2485  if (relation->rd_indextuple)
2486  pfree(relation->rd_indextuple);
2487  if (relation->rd_amcache)
2488  pfree(relation->rd_amcache);
2489  if (relation->rd_fdwroutine)
2490  pfree(relation->rd_fdwroutine);
2491  if (relation->rd_indexcxt)
2492  MemoryContextDelete(relation->rd_indexcxt);
2493  if (relation->rd_rulescxt)
2494  MemoryContextDelete(relation->rd_rulescxt);
2495  if (relation->rd_rsdesc)
2496  MemoryContextDelete(relation->rd_rsdesc->rscxt);
2497  if (relation->rd_partkeycxt)
2499  if (relation->rd_pdcxt)
2500  MemoryContextDelete(relation->rd_pdcxt);
2501  if (relation->rd_pddcxt)
2502  MemoryContextDelete(relation->rd_pddcxt);
2503  if (relation->rd_partcheckcxt)
2505  pfree(relation);
2506 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
void list_free_deep(List *list)
Definition: list.c:1560
void pgstat_unlink_relation(Relation rel)
static void RememberToFreeTupleDescAtEOX(TupleDesc td)
Definition: relcache.c:3065
Bitmapset * rd_hotblockingattr
Definition: rel.h:165
Bitmapset * rd_summarizedattr
Definition: rel.h:166
MemoryContext rscxt
Definition: rowsecurity.h:33
void FreeTriggerDesc(TriggerDesc *trigdesc)
Definition: trigger.c:2140

References Assert(), bms_free(), FreeTriggerDesc(), FreeTupleDesc(), list_free(), list_free_deep(), MemoryContextDelete(), pfree(), pgstat_unlink_relation(), RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_fdwroutine, RelationData::rd_fkeylist, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indexcxt, RelationData::rd_indexlist, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_options, RelationData::rd_partcheckcxt, RelationData::rd_partkeycxt, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_pkattr, RelationData::rd_pubdesc, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rulescxt, RelationData::rd_statlist, RelationData::rd_summarizedattr, RelationCloseSmgr(), RelationHasReferenceCountZero, RememberToFreeTupleDescAtEOX(), RowSecurityDesc::rscxt, TupleDescData::tdrefcount, and RelationData::trigdesc.

Referenced by RelationBuildDesc(), and RelationClearRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2833 of file relcache.c.

2834 {
2835  if (relation->rd_createSubid != InvalidSubTransactionId ||
2837  {
2838  /*
2839  * New relcache entries are always rebuilt, not flushed; else we'd
2840  * forget the "new" status of the relation. Ditto for the
2841  * new-relfilenumber status.
2842  *
2843  * The rel could have zero refcnt here, so temporarily increment the
2844  * refcnt to ensure it's safe to rebuild it. We can assume that the
2845  * current transaction has some lock on the rel already.
2846  */
2848  RelationClearRelation(relation, true);
2850  }
2851  else
2852  {
2853  /*
2854  * Pre-existing rels can be dropped from the relcache if not open.
2855  */
2856  bool rebuild = !RelationHasReferenceCountZero(relation);
2857 
2858  RelationClearRelation(relation, rebuild);
2859  }
2860 }

References InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationClearRelation(), RelationDecrementReferenceCount(), RelationHasReferenceCountZero, and RelationIncrementReferenceCount().

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2866 of file relcache.c.

2867 {
2868  Relation relation;
2869 
2870  RelationIdCacheLookup(rid, relation);
2871 
2872  if (!PointerIsValid(relation))
2873  return; /* not in cache, nothing to do */
2874 
2875  if (!RelationHasReferenceCountZero(relation))
2876  elog(ERROR, "relation %u is still open", rid);
2877 
2879  if (relation->rd_createSubid != InvalidSubTransactionId ||
2881  {
2882  /*
2883  * In the event of subtransaction rollback, we must not forget
2884  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2885  * invalidates it in lieu of destroying it. (If we're in a top
2886  * transaction, we could opt to destroy the entry.)
2887  */
2889  }
2890 
2891  RelationClearRelation(relation, false);
2892 }

References Assert(), elog, ERROR, GetCurrentSubTransactionId(), InvalidSubTransactionId, PointerIsValid, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationClearRelation(), RelationHasReferenceCountZero, and RelationIdCacheLookup.

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5073 of file relcache.c.

5074 {
5075  List *result;
5076  Datum exprsDatum;
5077  bool isnull;
5078  char *exprsString;
5079  List *rawExprs;
5080  ListCell *lc;
5081 
5082  /* Quick exit if there is nothing to do. */
5083  if (relation->rd_indextuple == NULL ||
5084  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5085  return NIL;
5086 
5087  /* Extract raw node tree(s) from index tuple. */
5088  exprsDatum = heap_getattr(relation->rd_indextuple,
5089  Anum_pg_index_indexprs,
5091  &isnull);
5092  Assert(!isnull);
5093  exprsString = TextDatumGetCString(exprsDatum);
5094  rawExprs = (List *) stringToNode(exprsString);
5095  pfree(exprsString);
5096 
5097  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5098  result = NIL;
5099  foreach(lc, rawExprs)
5100  {
5101  Node *rawExpr = (Node *) lfirst(lc);
5102 
5103  result = lappend(result,
5104  makeConst(exprType(rawExpr),
5105  exprTypmod(rawExpr),
5106  exprCollation(rawExpr),
5107  1,
5108  (Datum) 0,
5109  true,
5110  true));
5111  }
5112 
5113  return result;
5114 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:284
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4411

References Assert(), exprCollation(), exprType(), exprTypmod(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), lappend(), lfirst, makeConst(), NIL, pfree(), RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by BuildDummyIndexInfo().

◆ RelationGetExclusionInfo()

void RelationGetExclusionInfo ( Relation  indexRelation,
Oid **  operators,
Oid **  procs,
uint16 **  strategies 
)

Definition at line 5570 of file relcache.c.

5574 {
5575  int indnkeyatts;
5576  Oid *ops;
5577  Oid *funcs;
5578  uint16 *strats;
5579  Relation conrel;
5580  SysScanDesc conscan;
5581  ScanKeyData skey[1];
5582  HeapTuple htup;
5583  bool found;
5584  MemoryContext oldcxt;
5585  int i;
5586 
5587  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5588 
5589  /* Allocate result space in caller context */
5590  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5591  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5592  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5593 
5594  /* Quick exit if we have the data cached already */
5595  if (indexRelation->rd_exclstrats != NULL)
5596  {
5597  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5598  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5599  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5600  return;
5601  }
5602 
5603  /*
5604  * Search pg_constraint for the constraint associated with the index. To
5605  * make this not too painfully slow, we use the index on conrelid; that
5606  * will hold the parent relation's OID not the index's own OID.
5607  *
5608  * Note: if we wanted to rely on the constraint name matching the index's
5609  * name, we could just do a direct lookup using pg_constraint's unique
5610  * index. For the moment it doesn't seem worth requiring that.
5611  */
5612  ScanKeyInit(&skey[0],
5613  Anum_pg_constraint_conrelid,
5614  BTEqualStrategyNumber, F_OIDEQ,
5615  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5616 
5617  conrel = table_open(ConstraintRelationId, AccessShareLock);
5618  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5619  NULL, 1, skey);
5620  found = false;
5621 
5622  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5623  {
5625  Datum val;
5626  bool isnull;
5627  ArrayType *arr;
5628  int nelem;
5629 
5630  /* We want the exclusion constraint owning the index */
5631  if ((conform->contype != CONSTRAINT_EXCLUSION &&
5632  !(conform->conperiod && (
5633  conform->contype == CONSTRAINT_PRIMARY
5634  || conform->contype == CONSTRAINT_UNIQUE))) ||
5635  conform->conindid != RelationGetRelid(indexRelation))
5636  continue;
5637 
5638  /* There should be only one */
5639  if (found)
5640  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5641  RelationGetRelationName(indexRelation));
5642  found = true;
5643 
5644  /* Extract the operator OIDS from conexclop */
5645  val = fastgetattr(htup,
5646  Anum_pg_constraint_conexclop,
5647  conrel->rd_att, &isnull);
5648  if (isnull)
5649  elog(ERROR, "null conexclop for rel %s",
5650  RelationGetRelationName(indexRelation));
5651 
5652  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5653  nelem = ARR_DIMS(arr)[0];
5654  if (ARR_NDIM(arr) != 1 ||
5655  nelem != indnkeyatts ||
5656  ARR_HASNULL(arr) ||
5657  ARR_ELEMTYPE(arr) != OIDOID)
5658  elog(ERROR, "conexclop is not a 1-D Oid array");
5659 
5660  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5661  }
5662 
5663  systable_endscan(conscan);
5664  table_close(conrel, AccessShareLock);
5665 
5666  if (!found)
5667  elog(ERROR, "exclusion constraint record missing for rel %s",
5668  RelationGetRelationName(indexRelation));
5669 
5670  /* We need the func OIDs and strategy numbers too */
5671  for (i = 0; i < indnkeyatts; i++)
5672  {
5673  funcs[i] = get_opcode(ops[i]);
5674  strats[i] = get_op_opfamily_strategy(ops[i],
5675  indexRelation->rd_opfamily[i]);
5676  /* shouldn't fail, since it was checked at index creation */
5677  if (strats[i] == InvalidStrategy)
5678  elog(ERROR, "could not find strategy for operator %u in family %u",
5679  ops[i], indexRelation->rd_opfamily[i]);
5680  }
5681 
5682  /* Save a copy of the results in the relcache entry. */
5683  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5684  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5685  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5686  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5687  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5688  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5689  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5690  MemoryContextSwitchTo(oldcxt);
5691 }
#define ARR_NDIM(a)
Definition: array.h:290
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_HASNULL(a)
Definition: array.h:291
unsigned short uint16
Definition: c.h:492
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1263
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:83
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define InvalidStrategy
Definition: stratnum.h:24

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, DatumGetArrayTypeP, elog, ERROR, fastgetattr(), get_op_opfamily_strategy(), get_opcode(), GETSTRUCT, HeapTupleIsValid, i, IndexRelationGetNumberOfKeyAttributes, InvalidStrategy, MemoryContextSwitchTo(), ObjectIdGetDatum(), palloc(), RelationData::rd_att, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_opfamily, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and val.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4640 of file relcache.c.

4641 {
4642  List *result;
4643  Relation conrel;
4644  SysScanDesc conscan;
4645  ScanKeyData skey;
4646  HeapTuple htup;
4647  List *oldlist;
4648  MemoryContext oldcxt;
4649 
4650  /* Quick exit if we already computed the list. */
4651  if (relation->rd_fkeyvalid)
4652  return relation->rd_fkeylist;
4653 
4654  /* Fast path: non-partitioned tables without triggers can't have FKs */
4655  if (!relation->rd_rel->relhastriggers &&
4656  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
4657  return NIL;
4658 
4659  /*
4660  * We build the list we intend to return (in the caller's context) while
4661  * doing the scan. After successfully completing the scan, we copy that
4662  * list into the relcache entry. This avoids cache-context memory leakage
4663  * if we get some sort of error partway through.
4664  */
4665  result = NIL;
4666 
4667  /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4668  ScanKeyInit(&skey,
4669  Anum_pg_constraint_conrelid,
4670  BTEqualStrategyNumber, F_OIDEQ,
4671  ObjectIdGetDatum(RelationGetRelid(relation)));
4672 
4673  conrel = table_open(ConstraintRelationId, AccessShareLock);
4674  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4675  NULL, 1, &skey);
4676 
4677  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4678  {
4679  Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4680  ForeignKeyCacheInfo *info;
4681 
4682  /* consider only foreign keys */
4683  if (constraint->contype != CONSTRAINT_FOREIGN)
4684  continue;
4685 
4686  info = makeNode(ForeignKeyCacheInfo);
4687  info->conoid = constraint->oid;
4688  info->conrelid = constraint->conrelid;
4689  info->confrelid = constraint->confrelid;
4690 
4691  DeconstructFkConstraintRow(htup, &info->nkeys,
4692  info->conkey,
4693  info->confkey,
4694  info->conpfeqop,
4695  NULL, NULL, NULL, NULL);
4696 
4697  /* Add FK's node to the result list */
4698  result = lappend(result, info);
4699  }
4700 
4701  systable_endscan(conscan);
4702  table_close(conrel, AccessShareLock);
4703 
4704  /* Now save a copy of the completed list in the relcache entry. */
4706  oldlist = relation->rd_fkeylist;
4707  relation->rd_fkeylist = copyObject(result);
4708  relation->rd_fkeyvalid = true;
4709  MemoryContextSwitchTo(oldcxt);
4710 
4711  /* Don't leak the old list, if there is one */
4712  list_free_deep(oldlist);
4713 
4714  return result;
4715 }
#define copyObject(obj)
Definition: nodes.h:223
#define makeNode(_type_)
Definition: nodes.h:155
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conrelid, copyObject, DeconstructFkConstraintRow(), GETSTRUCT, HeapTupleIsValid, lappend(), list_free_deep(), makeNode, MemoryContextSwitchTo(), NIL, ForeignKeyCacheInfo::nkeys, ObjectIdGetDatum(), RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_rel, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferencing(), CloneFkReferencing(), DetachPartitionFinalize(), and get_relation_foreign_keys().

◆ RelationGetIdentityKeyBitmap()

Bitmapset* RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5493 of file relcache.c.

5494 {
5495  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5496  Relation indexDesc;
5497  int i;
5498  Oid replidindex;
5499  MemoryContext oldcxt;
5500 
5501  /* Quick exit if we already computed the result */
5502  if (relation->rd_idattr != NULL)
5503  return bms_copy(relation->rd_idattr);
5504 
5505  /* Fast path if definitely no indexes */
5506  if (!RelationGetForm(relation)->relhasindex)
5507  return NULL;
5508 
5509  /* Historic snapshot must be set. */
5511 
5512  replidindex = RelationGetReplicaIndex(relation);
5513 
5514  /* Fall out if there is no replica identity index */
5515  if (!OidIsValid(replidindex))
5516  return NULL;
5517 
5518  /* Look up the description for the replica identity index */
5519  indexDesc = RelationIdGetRelation(replidindex);
5520 
5521  if (!RelationIsValid(indexDesc))
5522  elog(ERROR, "could not open relation with OID %u",
5523  relation->rd_replidindex);
5524 
5525  /* Add referenced attributes to idindexattrs */
5526  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5527  {
5528  int attrnum = indexDesc->rd_index->indkey.values[i];
5529 
5530  /*
5531  * We don't include non-key columns into idindexattrs bitmaps. See
5532  * RelationGetIndexAttrBitmap.
5533  */
5534  if (attrnum != 0)
5535  {
5536  if (i < indexDesc->rd_index->indnkeyatts)
5537  idindexattrs = bms_add_member(idindexattrs,
5539  }
5540  }
5541 
5542  RelationClose(indexDesc);
5543 
5544  /* Don't leak the old values of these bitmaps, if any */
5545  bms_free(relation->rd_idattr);
5546  relation->rd_idattr = NULL;
5547 
5548  /* Now save copy of the bitmap in the relcache entry */
5550  relation->rd_idattr = bms_copy(idindexattrs);
5551  MemoryContextSwitchTo(oldcxt);
5552 
5553  /* We return our original working copy for caller to play with */
5554  return idindexattrs;
5555 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationIsValid(relation)
Definition: rel.h:478
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4989
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2055
void RelationClose(Relation relation)
Definition: relcache.c:2186
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References Assert(), bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, ERROR, FirstLowInvalidHeapAttributeNumber, HistoricSnapshotActive(), i, MemoryContextSwitchTo(), OidIsValid, RelationData::rd_idattr, RelationData::rd_index, RelationData::rd_replidindex, RelationClose(), RelationGetForm, RelationGetReplicaIndex(), RelationIdGetRelation(), and RelationIsValid.

Referenced by logicalrep_write_attrs().

◆ RelationGetIndexAttOptions()

bytea** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5873 of file relcache.c.

5874 {
5875  MemoryContext oldcxt;
5876  bytea **opts = relation->rd_opcoptions;
5877  Oid relid = RelationGetRelid(relation);
5878  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5879  * IndexRelationGetNumberOfKeyAttributes */
5880  int i;
5881 
5882  /* Try to copy cached options. */
5883  if (opts)
5884  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5885 
5886  /* Get and parse opclass options. */
5887  opts = palloc0(sizeof(*opts) * natts);
5888 
5889  for (i = 0; i < natts; i++)
5890  {
5891  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5892  {
5893  Datum attoptions = get_attoptions(relid, i + 1);
5894 
5895  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5896 
5897  if (attoptions != (Datum) 0)
5898  pfree(DatumGetPointer(attoptions));
5899  }
5900  }
5901 
5902  /* Copy parsed options to the cache. */
5903  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5904  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5905  MemoryContextSwitchTo(oldcxt);
5906 
5907  if (copy)
5908  return opts;
5909 
5910  for (i = 0; i < natts; i++)
5911  {
5912  if (opts[i])
5913  pfree(opts[i]);
5914  }
5915 
5916  pfree(opts);
5917 
5918  return relation->rd_opcoptions;
5919 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:999
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5853

References CopyIndexAttOptions(), criticalRelcachesBuilt, DatumGetPointer(), get_attoptions(), i, index_opclass_options(), MemoryContextSwitchTo(), opts, palloc0(), pfree(), RelationData::rd_indexcxt, RelationData::rd_opcoptions, RelationGetNumberOfAttributes, and RelationGetRelid.

Referenced by get_relation_info(), index_getprocinfo(), load_critical_index(), and RelationInitIndexAccessInfo().

◆ RelationGetIndexAttrBitmap()

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5220 of file relcache.c.

5221 {
5222  Bitmapset *uindexattrs; /* columns in unique indexes */
5223  Bitmapset *pkindexattrs; /* columns in the primary index */
5224  Bitmapset *idindexattrs; /* columns in the replica identity */
5225  Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5226  Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5227  List *indexoidlist;
5228  List *newindexoidlist;
5229  Oid relpkindex;
5230  Oid relreplindex;
5231  ListCell *l;
5232  MemoryContext oldcxt;
5233 
5234  /* Quick exit if we already computed the result. */
5235  if (relation->rd_attrsvalid)
5236  {
5237  switch (attrKind)
5238  {
5239  case INDEX_ATTR_BITMAP_KEY:
5240  return bms_copy(relation->rd_keyattr);
5242  return bms_copy(relation->rd_pkattr);
5244  return bms_copy(relation->rd_idattr);
5246  return bms_copy(relation->rd_hotblockingattr);
5248  return bms_copy(relation->rd_summarizedattr);
5249  default:
5250  elog(ERROR, "unknown attrKind %u", attrKind);
5251  }
5252  }
5253 
5254  /* Fast path if definitely no indexes */
5255  if (!RelationGetForm(relation)->relhasindex)
5256  return NULL;
5257 
5258  /*
5259  * Get cached list of index OIDs. If we have to start over, we do so here.
5260  */
5261 restart:
5262  indexoidlist = RelationGetIndexList(relation);
5263 
5264  /* Fall out if no indexes (but relhasindex was set) */
5265  if (indexoidlist == NIL)
5266  return NULL;
5267 
5268  /*
5269  * Copy the rd_pkindex and rd_replidindex values computed by
5270  * RelationGetIndexList before proceeding. This is needed because a
5271  * relcache flush could occur inside index_open below, resetting the
5272  * fields managed by RelationGetIndexList. We need to do the work with
5273  * stable values of these fields.
5274  */
5275  relpkindex = relation->rd_pkindex;
5276  relreplindex = relation->rd_replidindex;
5277 
5278  /*
5279  * For each index, add referenced attributes to indexattrs.
5280  *
5281  * Note: we consider all indexes returned by RelationGetIndexList, even if
5282  * they are not indisready or indisvalid. This is important because an
5283  * index for which CREATE INDEX CONCURRENTLY has just started must be
5284  * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5285  * CONCURRENTLY is far enough along that we should ignore the index, it
5286  * won't be returned at all by RelationGetIndexList.
5287  */
5288  uindexattrs = NULL;
5289  pkindexattrs = NULL;
5290  idindexattrs = NULL;
5291  hotblockingattrs = NULL;
5292  summarizedattrs = NULL;
5293  foreach(l, indexoidlist)
5294  {
5295  Oid indexOid = lfirst_oid(l);
5296  Relation indexDesc;
5297  Datum datum;
5298  bool isnull;
5299  Node *indexExpressions;
5300  Node *indexPredicate;
5301  int i;
5302  bool isKey; /* candidate key */
5303  bool isPK; /* primary key */
5304  bool isIDKey; /* replica identity index */
5305  Bitmapset **attrs;
5306 
5307  indexDesc = index_open(indexOid, AccessShareLock);
5308 
5309  /*
5310  * Extract index expressions and index predicate. Note: Don't use
5311  * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5312  * those might run constant expressions evaluation, which needs a
5313  * snapshot, which we might not have here. (Also, it's probably more
5314  * sound to collect the bitmaps before any transformations that might
5315  * eliminate columns, but the practical impact of this is limited.)
5316  */
5317 
5318  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5319  GetPgIndexDescriptor(), &isnull);
5320  if (!isnull)
5321  indexExpressions = stringToNode(TextDatumGetCString(datum));
5322  else
5323  indexExpressions = NULL;
5324 
5325  datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5326  GetPgIndexDescriptor(), &isnull);
5327  if (!isnull)
5328  indexPredicate = stringToNode(TextDatumGetCString(datum));
5329  else
5330  indexPredicate = NULL;
5331 
5332  /* Can this index be referenced by a foreign key? */
5333  isKey = indexDesc->rd_index->indisunique &&
5334  indexExpressions == NULL &&
5335  indexPredicate == NULL;
5336 
5337  /* Is this a primary key? */
5338  isPK = (indexOid == relpkindex);
5339 
5340  /* Is this index the configured (or default) replica identity? */
5341  isIDKey = (indexOid == relreplindex);
5342 
5343  /*
5344  * If the index is summarizing, it doesn't block HOT updates, but we
5345  * may still need to update it (if the attributes were modified). So
5346  * decide which bitmap we'll update in the following loop.
5347  */
5348  if (indexDesc->rd_indam->amsummarizing)
5349  attrs = &summarizedattrs;
5350  else
5351  attrs = &hotblockingattrs;
5352 
5353  /* Collect simple attribute references */
5354  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5355  {
5356  int attrnum = indexDesc->rd_index->indkey.values[i];
5357 
5358  /*
5359  * Since we have covering indexes with non-key columns, we must
5360  * handle them accurately here. non-key columns must be added into
5361  * hotblockingattrs or summarizedattrs, since they are in index,
5362  * and update shouldn't miss them.
5363  *
5364  * Summarizing indexes do not block HOT, but do need to be updated
5365  * when the column value changes, thus require a separate
5366  * attribute bitmapset.
5367  *
5368  * Obviously, non-key columns couldn't be referenced by foreign
5369  * key or identity key. Hence we do not include them into
5370  * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5371  */
5372  if (attrnum != 0)
5373  {
5374  *attrs = bms_add_member(*attrs,
5376 
5377  if (isKey && i < indexDesc->rd_index->indnkeyatts)
5378  uindexattrs = bms_add_member(uindexattrs,
5380 
5381  if (isPK && i < indexDesc->rd_index->indnkeyatts)
5382  pkindexattrs = bms_add_member(pkindexattrs,
5384 
5385  if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5386  idindexattrs = bms_add_member(idindexattrs,
5388  }
5389  }
5390 
5391  /* Collect all attributes used in expressions, too */
5392  pull_varattnos(indexExpressions, 1, attrs);
5393 
5394  /* Collect all attributes in the index predicate, too */
5395  pull_varattnos(indexPredicate, 1, attrs);
5396 
5397  index_close(indexDesc, AccessShareLock);
5398  }
5399 
5400  /*
5401  * During one of the index_opens in the above loop, we might have received
5402  * a relcache flush event on this relcache entry, which might have been
5403  * signaling a change in the rel's index list. If so, we'd better start
5404  * over to ensure we deliver up-to-date attribute bitmaps.
5405  */
5406  newindexoidlist = RelationGetIndexList(relation);
5407  if (equal(indexoidlist, newindexoidlist) &&
5408  relpkindex == relation->rd_pkindex &&
5409  relreplindex == relation->rd_replidindex)
5410  {
5411  /* Still the same index set, so proceed */
5412  list_free(newindexoidlist);
5413  list_free(indexoidlist);
5414  }
5415  else
5416  {
5417  /* Gotta do it over ... might as well not leak memory */
5418  list_free(newindexoidlist);
5419  list_free(indexoidlist);
5420  bms_free(uindexattrs);
5421  bms_free(pkindexattrs);
5422  bms_free(idindexattrs);
5423  bms_free(hotblockingattrs);
5424  bms_free(summarizedattrs);
5425 
5426  goto restart;
5427  }
5428 
5429  /* Don't leak the old values of these bitmaps, if any */
5430  relation->rd_attrsvalid = false;
5431  bms_free(relation->rd_keyattr);
5432  relation->rd_keyattr = NULL;
5433  bms_free(relation->rd_pkattr);
5434  relation->rd_pkattr = NULL;
5435  bms_free(relation->rd_idattr);
5436  relation->rd_idattr = NULL;
5437  bms_free(relation->rd_hotblockingattr);
5438  relation->rd_hotblockingattr = NULL;
5439  bms_free(relation->rd_summarizedattr);
5440  relation->rd_summarizedattr = NULL;
5441 
5442  /*
5443  * Now save copies of the bitmaps in the relcache entry. We intentionally
5444  * set rd_attrsvalid last, because that's the one that signals validity of
5445  * the values; if we run out of memory before making that copy, we won't
5446  * leave the relcache entry looking like the other ones are valid but
5447  * empty.
5448  */
5450  relation->rd_keyattr = bms_copy(uindexattrs);
5451  relation->rd_pkattr = bms_copy(pkindexattrs);
5452  relation->rd_idattr = bms_copy(idindexattrs);
5453  relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5454  relation->rd_summarizedattr = bms_copy(summarizedattrs);
5455  relation->rd_attrsvalid = true;
5456  MemoryContextSwitchTo(oldcxt);
5457 
5458  /* We return our original working copy for caller to play with */
5459  switch (attrKind)
5460  {
5461  case INDEX_ATTR_BITMAP_KEY:
5462  return uindexattrs;
5464  return pkindexattrs;
5466  return idindexattrs;
5468  return hotblockingattrs;
5470  return summarizedattrs;
5471  default:
5472  elog(ERROR, "unknown attrKind %u", attrKind);
5473  return NULL;
5474  }
5475 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4749
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:64
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:65
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
bool amsummarizing
Definition: amapi.h:253
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291

References AccessShareLock, IndexAmRoutine::amsummarizing, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, GetPgIndexDescriptor(), heap_getattr(), i, INDEX_ATTR_BITMAP_HOT_BLOCKING, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_SUMMARIZED, index_close(), index_open(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, pull_varattnos(), RelationData::rd_attrsvalid, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_replidindex, RelationData::rd_summarizedattr, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

Referenced by ATExecDropNotNull(), ATInheritAdjustNotNulls(), dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), MergeAttributes(), pub_collist_contains_invalid_column(), pub_rf_contains_invalid_column(), and transformTableLikeClause().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5014 of file relcache.c.

5015 {
5016  List *result;
5017  Datum exprsDatum;
5018  bool isnull;
5019  char *exprsString;
5020  MemoryContext oldcxt;
5021 
5022  /* Quick exit if we already computed the result. */
5023  if (relation->rd_indexprs)
5024  return copyObject(relation->rd_indexprs);
5025 
5026  /* Quick exit if there is nothing to do. */
5027  if (relation->rd_indextuple == NULL ||
5028  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5029  return NIL;
5030 
5031  /*
5032  * We build the tree we intend to return in the caller's context. After
5033  * successfully completing the work, we copy it into the relcache entry.
5034  * This avoids problems if we get some sort of error partway through.
5035  */
5036  exprsDatum = heap_getattr(relation->rd_indextuple,
5037  Anum_pg_index_indexprs,
5039  &isnull);
5040  Assert(!isnull);
5041  exprsString = TextDatumGetCString(exprsDatum);
5042  result = (List *) stringToNode(exprsString);
5043  pfree(exprsString);
5044 
5045  /*
5046  * Run the expressions through eval_const_expressions. This is not just an
5047  * optimization, but is necessary, because the planner will be comparing
5048  * them to similarly-processed qual clauses, and may fail to detect valid
5049  * matches without this. We must not use canonicalize_qual, however,
5050  * since these aren't qual expressions.
5051  */
5052  result = (List *) eval_const_expressions(NULL, (Node *) result);
5053 
5054  /* May as well fix opfuncids too */
5055  fix_opfuncids((Node *) result);
5056 
5057  /* Now save a copy of the completed tree in the relcache entry. */
5058  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5059  relation->rd_indexprs = copyObject(result);
5060  MemoryContextSwitchTo(oldcxt);
5061 
5062  return result;
5063 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2234
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1759

References Assert(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_relation_info(), GetIndexInputType(), index_unchanged_by_update(), infer_arbiter_indexes(), plan_create_index_workers(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4749 of file relcache.c.

4750 {
4751  Relation indrel;
4752  SysScanDesc indscan;
4753  ScanKeyData skey;
4754  HeapTuple htup;
4755  List *result;
4756  List *oldlist;
4757  char replident = relation->rd_rel->relreplident;
4758  Oid pkeyIndex = InvalidOid;
4759  Oid candidateIndex = InvalidOid;
4760  bool pkdeferrable = false;
4761  MemoryContext oldcxt;
4762 
4763  /* Quick exit if we already computed the list. */
4764  if (relation->rd_indexvalid)
4765  return list_copy(relation->rd_indexlist);
4766 
4767  /*
4768  * We build the list we intend to return (in the caller's context) while
4769  * doing the scan. After successfully completing the scan, we copy that
4770  * list into the relcache entry. This avoids cache-context memory leakage
4771  * if we get some sort of error partway through.
4772  */
4773  result = NIL;
4774 
4775  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4776  ScanKeyInit(&skey,
4777  Anum_pg_index_indrelid,
4778  BTEqualStrategyNumber, F_OIDEQ,
4779  ObjectIdGetDatum(RelationGetRelid(relation)));
4780 
4781  indrel = table_open(IndexRelationId, AccessShareLock);
4782  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4783  NULL, 1, &skey);
4784 
4785  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4786  {
4788 
4789  /*
4790  * Ignore any indexes that are currently being dropped. This will
4791  * prevent them from being searched, inserted into, or considered in
4792  * HOT-safety decisions. It's unsafe to touch such an index at all
4793  * since its catalog entries could disappear at any instant.
4794  */
4795  if (!index->indislive)
4796  continue;
4797 
4798  /* add index's OID to result list */
4799  result = lappend_oid(result, index->indexrelid);
4800 
4801  /*
4802  * Non-unique or predicate indexes aren't interesting for either oid
4803  * indexes or replication identity indexes, so don't check them.
4804  * Deferred ones are not useful for replication identity either; but
4805  * we do include them if they are PKs.
4806  */
4807  if (!index->indisunique ||
4808  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4809  continue;
4810 
4811  /*
4812  * Remember primary key index, if any. We do this only if the index
4813  * is valid; but if the table is partitioned, then we do it even if
4814  * it's invalid.
4815  *
4816  * The reason for returning invalid primary keys for foreign tables is
4817  * because of pg_dump of NOT NULL constraints, and the fact that PKs
4818  * remain marked invalid until the partitions' PKs are attached to it.
4819  * If we make rd_pkindex invalid, then the attnotnull flag is reset
4820  * after the PK is created, which causes the ALTER INDEX ATTACH
4821  * PARTITION to fail with 'column ... is not marked NOT NULL'. With
4822  * this, dropconstraint_internal() will believe that the columns must
4823  * not have attnotnull reset, so the PKs-on-partitions can be attached
4824  * correctly, until finally the PK-on-parent is marked valid.
4825  *
4826  * Also, this doesn't harm anything, because rd_pkindex is not a
4827  * "real" index anyway, but a RELKIND_PARTITIONED_INDEX.
4828  */
4829  if (index->indisprimary &&
4830  (index->indisvalid ||
4831  relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4832  {
4833  pkeyIndex = index->indexrelid;
4834  pkdeferrable = !index->indimmediate;
4835  }
4836 
4837  if (!index->indimmediate)
4838  continue;
4839 
4840  if (!index->indisvalid)
4841  continue;
4842 
4843  /* remember explicitly chosen replica index */
4844  if (index->indisreplident)
4845  candidateIndex = index->indexrelid;
4846  }
4847 
4848  systable_endscan(indscan);
4849 
4850  table_close(indrel, AccessShareLock);
4851 
4852  /* Sort the result list into OID order, per API spec. */
4853  list_sort(result, list_oid_cmp);
4854 
4855  /* Now save a copy of the completed list in the relcache entry. */
4857  oldlist = relation->rd_indexlist;
4858  relation->rd_indexlist = list_copy(result);
4859  relation->rd_pkindex = pkeyIndex;
4860  relation->rd_ispkdeferrable = pkdeferrable;
4861  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4862  relation->rd_replidindex = pkeyIndex;
4863  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4864  relation->rd_replidindex = candidateIndex;
4865  else
4866  relation->rd_replidindex = InvalidOid;
4867  relation->rd_indexvalid = true;
4868  MemoryContextSwitchTo(oldcxt);
4869 
4870  /* Don't leak the old list, if there is one */
4871  list_free(oldlist);
4872 
4873  return result;
4874 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
bool rd_ispkdeferrable
Definition: rel.h:154
Definition: type.h:95

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT, heap_attisnull(), HeapTupleIsValid, InvalidOid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), OidIsValid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterIndexNamespaces(), ATExecChangeOwner(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), ExecRefreshMatView(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List* RelationGetIndexPredicate ( Relation  relation)

Definition at line 5127 of file relcache.c.

5128 {
5129  List *result;
5130  Datum predDatum;
5131  bool isnull;
5132  char *predString;
5133  MemoryContext oldcxt;
5134 
5135  /* Quick exit if we already computed the result. */
5136  if (relation->rd_indpred)
5137  return copyObject(relation->rd_indpred);
5138 
5139  /* Quick exit if there is nothing to do. */
5140  if (relation->rd_indextuple == NULL ||
5141  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5142  return NIL;
5143 
5144  /*
5145  * We build the tree we intend to return in the caller's context. After
5146  * successfully completing the work, we copy it into the relcache entry.
5147  * This avoids problems if we get some sort of error partway through.
5148  */
5149  predDatum = heap_getattr(relation->rd_indextuple,
5150  Anum_pg_index_indpred,
5152  &isnull);
5153  Assert(!isnull);
5154  predString = TextDatumGetCString(predDatum);
5155  result = (List *) stringToNode(predString);
5156  pfree(predString);
5157 
5158  /*
5159  * Run the expression through const-simplification and canonicalization.
5160  * This is not just an optimization, but is necessary, because the planner
5161  * will be comparing it to similarly-processed qual clauses, and may fail
5162  * to detect valid matches without this. This must match the processing
5163  * done to qual clauses in preprocess_expression()! (We can skip the
5164  * stuff involving subqueries, however, since we don't allow any in index
5165  * predicates.)
5166  */
5167  result = (List *) eval_const_expressions(NULL, (Node *) result);
5168 
5169  result = (List *) canonicalize_qual((Expr *) result, false);
5170 
5171  /* Also convert to implicit-AND format */
5172  result = make_ands_implicit((Expr *) result);
5173 
5174  /* May as well fix opfuncids too */
5175  fix_opfuncids((Node *) result);
5176 
5177  /* Now save a copy of the completed tree in the relcache entry. */
5178  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5179  relation->rd_indpred = copyObject(result);
5180  MemoryContextSwitchTo(oldcxt);
5181 
5182  return result;
5183 }
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:721
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293

References Assert(), canonicalize_qual(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), make_ands_implicit(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indextuple, RelationData::rd_indpred, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_relation_info(), infer_arbiter_indexes(), is_usable_unique_index(), plan_create_index_workers(), and transformIndexConstraint().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation)

Definition at line 4968 of file relcache.c.

4969 {
4970  List *ilist;
4971 
4972  if (!relation->rd_indexvalid)
4973  {
4974  /* RelationGetIndexList does the heavy lifting. */
4975  ilist = RelationGetIndexList(relation);
4976  list_free(ilist);
4977  Assert(relation->rd_indexvalid);
4978  }
4979 
4980  return relation->rd_ispkdeferrable ? InvalidOid : relation->rd_pkindex;
4981 }

References Assert(), InvalidOid, list_free(), RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, and RelationGetIndexList().

Referenced by GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 4989 of file relcache.c.

4990 {
4991  List *ilist;
4992 
4993  if (!relation->rd_indexvalid)
4994  {
4995  /* RelationGetIndexList does the heavy lifting. */
4996  ilist = RelationGetIndexList(relation);
4997  list_free(ilist);
4998  Assert(relation->rd_indexvalid);
4999  }
5000 
5001  return relation->rd_replidindex;
5002 }

References Assert(), list_free(), RelationData::rd_indexvalid, RelationData::rd_replidindex, and RelationGetIndexList().

Referenced by CheckCmdReplicaIdentity(), GetRelationIdentityOrPK(), pg_get_replica_identity_index(), and RelationGetIdentityKeyBitmap().

◆ RelationGetStatExtList()

List* RelationGetStatExtList ( Relation  relation)

Definition at line 4898 of file relcache.c.

4899 {
4900  Relation indrel;
4901  SysScanDesc indscan;
4902  ScanKeyData skey;
4903  HeapTuple htup;
4904  List *result;
4905  List *oldlist;
4906  MemoryContext oldcxt;
4907 
4908  /* Quick exit if we already computed the list. */
4909  if (relation->rd_statvalid != 0)
4910  return list_copy(relation->rd_statlist);
4911 
4912  /*
4913  * We build the list we intend to return (in the caller's context) while
4914  * doing the scan. After successfully completing the scan, we copy that
4915  * list into the relcache entry. This avoids cache-context memory leakage
4916  * if we get some sort of error partway through.
4917  */
4918  result = NIL;
4919 
4920  /*
4921  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
4922  * rel.
4923  */
4924  ScanKeyInit(&skey,
4925  Anum_pg_statistic_ext_stxrelid,
4926  BTEqualStrategyNumber, F_OIDEQ,
4927  ObjectIdGetDatum(RelationGetRelid(relation)));
4928 
4929  indrel = table_open(StatisticExtRelationId, AccessShareLock);
4930  indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
4931  NULL, 1, &skey);
4932 
4933  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4934  {
4935  Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
4936 
4937  result = lappend_oid(result, oid);
4938  }
4939 
4940  systable_endscan(indscan);
4941 
4942  table_close(indrel, AccessShareLock);
4943 
4944  /* Sort the result list into OID order, per API spec. */
4945  list_sort(result, list_oid_cmp);
4946 
4947  /* Now save a copy of the completed list in the relcache entry. */
4949  oldlist = relation->rd_statlist;
4950  relation->rd_statlist = list_copy(result);
4951 
4952  relation->rd_statvalid = true;
4953  MemoryContextSwitchTo(oldcxt);
4954 
4955  /* Don't leak the old list, if there is one */
4956  list_free(oldlist);
4957 
4958  return result;
4959 }
FormData_pg_statistic_ext * Form_pg_statistic_ext

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT, HeapTupleIsValid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_statlist, RelationData::rd_statvalid, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_relation_statistics(), and transformTableLikeClause().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2055 of file relcache.c.

2056 {
2057  Relation rd;
2058 
2059  /* Make sure we're in an xact, even if this ends up being a cache hit */
2061 
2062  /*
2063  * first try to find reldesc in the cache
2064  */
2065  RelationIdCacheLookup(relationId, rd);
2066 
2067  if (RelationIsValid(rd))
2068  {
2069  /* return NULL for dropped relations */
2071  {
2072  Assert(!rd->rd_isvalid);
2073  return NULL;
2074  }
2075 
2077  /* revalidate cache entry if necessary */
2078  if (!rd->rd_isvalid)
2079  {
2080  /*
2081  * Indexes only have a limited number of possible schema changes,
2082  * and we don't want to use the full-blown procedure because it's
2083  * a headache for indexes that reload itself depends on.
2084  */
2085  if (rd->rd_rel->relkind == RELKIND_INDEX ||
2086  rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2088  else
2089  RelationClearRelation(rd, true);
2090 
2091  /*
2092  * Normally entries need to be valid here, but before the relcache
2093  * has been initialized, not enough infrastructure exists to
2094  * perform pg_class lookups. The structure of such entries doesn't
2095  * change, but we still want to update the rd_rel entry. So
2096  * rd_isvalid = false is left in place for a later lookup.
2097  */
2098  Assert(rd->rd_isvalid ||
2100  }
2101  return rd;
2102  }
2103 
2104  /*
2105  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2106  * it.
2107  */
2108  rd = RelationBuildDesc(relationId, true);
2109  if (RelationIsValid(rd))
2111  return rd;
2112 }

References Assert(), criticalRelcachesBuilt, InvalidSubTransactionId, IsTransactionState(), RelationData::rd_droppedSubid, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_rel, RelationBuildDesc(), RelationClearRelation(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, and RelationReloadIndexInfo().

Referenced by init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), pgoutput_ensure_entry_cxt(), pgoutput_row_filter_init(), relation_open(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6695 of file relcache.c.

6696 {
6697  if (relationId == SharedSecLabelRelationId ||
6698  relationId == TriggerRelidNameIndexId ||
6699  relationId == DatabaseNameIndexId ||
6700  relationId == SharedSecLabelObjectIndexId)
6701  {
6702  /*
6703  * If this Assert fails, we don't need the applicable special case
6704  * anymore.
6705  */
6706  Assert(!RelationSupportsSysCache(relationId));
6707  return true;
6708  }
6709  return RelationSupportsSysCache(relationId);
6710 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:649

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationIncrementReferenceCount()

void RelationIncrementReferenceCount ( Relation  rel)

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1418 of file relcache.c.

1419 {
1420  HeapTuple tuple;
1421  Form_pg_am aform;
1422  Datum indcollDatum;
1423  Datum indclassDatum;
1424  Datum indoptionDatum;
1425  bool isnull;
1426  oidvector *indcoll;
1427  oidvector *indclass;
1428  int2vector *indoption;
1429  MemoryContext indexcxt;
1430  MemoryContext oldcontext;
1431  int indnatts;
1432  int indnkeyatts;
1433  uint16 amsupport;
1434 
1435  /*
1436  * Make a copy of the pg_index entry for the index. Since pg_index
1437  * contains variable-length and possibly-null fields, we have to do this
1438  * honestly rather than just treating it as a Form_pg_index struct.
1439  */
1440  tuple = SearchSysCache1(INDEXRELID,
1441  ObjectIdGetDatum(RelationGetRelid(relation)));
1442  if (!HeapTupleIsValid(tuple))
1443  elog(ERROR, "cache lookup failed for index %u",
1444  RelationGetRelid(relation));
1446  relation->rd_indextuple = heap_copytuple(tuple);
1447  relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1448  MemoryContextSwitchTo(oldcontext);
1449  ReleaseSysCache(tuple);
1450 
1451  /*
1452  * Look up the index's access method, save the OID of its handler function
1453  */
1454  Assert(relation->rd_rel->relam != InvalidOid);
1455  tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1456  if (!HeapTupleIsValid(tuple))
1457  elog(ERROR, "cache lookup failed for access method %u",
1458  relation->rd_rel->relam);
1459  aform = (Form_pg_am) GETSTRUCT(tuple);
1460  relation->rd_amhandler = aform->amhandler;
1461  ReleaseSysCache(tuple);
1462 
1463  indnatts = RelationGetNumberOfAttributes(relation);
1464  if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1465  elog(ERROR, "relnatts disagrees with indnatts for index %u",
1466  RelationGetRelid(relation));
1467  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1468 
1469  /*
1470  * Make the private context to hold index access info. The reason we need
1471  * a context, and not just a couple of pallocs, is so that we won't leak
1472  * any subsidiary info attached to fmgr lookup records.
1473  */
1475  "index info",
1477  relation->rd_indexcxt = indexcxt;
1479  RelationGetRelationName(relation));
1480 
1481  /*
1482  * Now we can fetch the index AM's API struct
1483  */
1484  InitIndexAmRoutine(relation);
1485 
1486  /*
1487  * Allocate arrays to hold data. Opclasses are not used for included
1488  * columns, so allocate them for indnkeyatts only.
1489  */
1490  relation->rd_opfamily = (Oid *)
1491  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1492  relation->rd_opcintype = (Oid *)
1493  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1494 
1495  amsupport = relation->rd_indam->amsupport;
1496  if (amsupport > 0)
1497  {
1498  int nsupport = indnatts * amsupport;
1499 
1500  relation->rd_support = (RegProcedure *)
1501  MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1502  relation->rd_supportinfo = (FmgrInfo *)
1503  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1504  }
1505  else
1506  {
1507  relation->rd_support = NULL;
1508  relation->rd_supportinfo = NULL;
1509  }
1510 
1511  relation->rd_indcollation = (Oid *)
1512  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1513 
1514  relation->rd_indoption = (int16 *)
1515  MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1516 
1517  /*
1518  * indcollation cannot be referenced directly through the C struct,
1519  * because it comes after the variable-width indkey field. Must extract
1520  * the datum the hard way...
1521  */
1522  indcollDatum = fastgetattr(relation->rd_indextuple,
1523  Anum_pg_index_indcollation,
1525  &isnull);
1526  Assert(!isnull);
1527  indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1528  memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1529 
1530  /*
1531  * indclass cannot be referenced directly through the C struct, because it
1532  * comes after the variable-width indkey field. Must extract the datum
1533  * the hard way...
1534  */
1535  indclassDatum = fastgetattr(relation->rd_indextuple,
1536  Anum_pg_index_indclass,
1538  &isnull);
1539  Assert(!isnull);
1540  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1541 
1542  /*
1543  * Fill the support procedure OID array, as well as the info about
1544  * opfamilies and opclass input types. (aminfo and supportinfo are left
1545  * as zeroes, and are filled on-the-fly when used)
1546  */
1547  IndexSupportInitialize(indclass, relation->rd_support,
1548  relation->rd_opfamily, relation->rd_opcintype,
1549  amsupport, indnkeyatts);
1550 
1551  /*
1552  * Similarly extract indoption and copy it to the cache entry
1553  */
1554  indoptionDatum = fastgetattr(relation->rd_indextuple,
1555  Anum_pg_index_indoption,
1557  &isnull);
1558  Assert(!isnull);
1559  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1560  memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1561 
1562  (void) RelationGetIndexAttOptions(relation, false);
1563 
1564  /*
1565  * expressions, predicate, exclusion caches will be filled later
1566  */
1567  relation->rd_indexprs = NIL;
1568  relation->rd_indpred = NIL;
1569  relation->rd_exclops = NULL;
1570  relation->rd_exclprocs = NULL;
1571  relation->rd_exclstrats = NULL;
1572  relation->rd_amcache = NULL;
1573 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:517
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1589
Definition: c.h:702
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:709
Definition: c.h:713

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert(), CacheMemoryContext, DatumGetPointer(), elog, ERROR, fastgetattr(), GetPgIndexDescriptor(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, IndexSupportInitialize(), InitIndexAmRoutine(), InvalidOid, MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_amcache, RelationData::rd_amhandler, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_support, RelationData::rd_supportinfo, RelationGetIndexAttOptions(), RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitPhysicalAddr()

static void RelationInitPhysicalAddr ( Relation  relation)
static

Definition at line 1312 of file relcache.c.

1313 {
1314  RelFileNumber oldnumber = relation->rd_locator.relNumber;
1315 
1316  /* these relations kinds never have storage */
1317  if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
1318  return;
1319 
1320  if (relation->rd_rel->reltablespace)
1321  relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
1322  else
1324  if (relation->rd_locator.spcOid == GLOBALTABLESPACE_OID)
1325  relation->rd_locator.dbOid = InvalidOid;
1326  else
1327  relation->rd_locator.dbOid = MyDatabaseId;
1328 
1329  if (relation->rd_rel->relfilenode)
1330  {
1331  /*
1332  * Even if we are using a decoding snapshot that doesn't represent the
1333  * current state of the catalog we need to make sure the filenode
1334  * points to the current file since the older file will be gone (or
1335  * truncated). The new file will still contain older rows so lookups
1336  * in them will work correctly. This wouldn't work correctly if
1337  * rewrites were allowed to change the schema in an incompatible way,
1338  * but those are prevented both on catalog tables and on user tables
1339  * declared as additional catalog tables.
1340  */
1343  && IsTransactionState())
1344  {
1345  HeapTuple phys_tuple;
1346  Form_pg_class physrel;
1347 
1348  phys_tuple = ScanPgRelation(RelationGetRelid(relation),
1349  RelationGetRelid(relation) != ClassOidIndexId,
1350  true);
1351  if (!HeapTupleIsValid(phys_tuple))
1352  elog(ERROR, "could not find pg_class entry for %u",
1353  RelationGetRelid(relation));
1354  physrel = (Form_pg_class) GETSTRUCT(phys_tuple);
1355 
1356  relation->rd_rel->reltablespace = physrel->reltablespace;
1357  relation->rd_rel->relfilenode = physrel->relfilenode;
1358  heap_freetuple(phys_tuple);
1359  }
1360 
1361  relation->rd_locator.relNumber = relation->rd_rel->relfilenode;
1362  }
1363  else
1364  {
1365  /* Consult the relation mapper */
1366  relation->rd_locator.relNumber =
1368  relation->rd_rel->relisshared);
1369  if (!RelFileNumberIsValid(relation->rd_locator.relNumber))
1370  elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1371  RelationGetRelationName(relation), relation->rd_id);
1372  }
1373 
1374  /*
1375  * For RelationNeedsWAL() to answer correctly on parallel workers, restore
1376  * rd_firstRelfilelocatorSubid. No subtransactions start or end while in
1377  * parallel mode, so the specific SubTransactionId does not matter.
1378  */
1379  if (IsParallelWorker() && oldnumber != relation->rd_locator.relNumber)
1380  {
1381  if (RelFileLocatorSkippingWAL(relation->rd_locator))
1383  else
1385  }
1386 }
#define TopSubTransactionId
Definition: c.h:646
Oid MyDatabaseTableSpace
Definition: globals.c:93
Oid MyDatabaseId
Definition: globals.c:91
#define IsParallelWorker()
Definition: parallel.h:60
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool RelFileLocatorSkippingWAL(RelFileLocator rlocator)
Definition: storage.c:532
RelFileNumber relNumber
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

References RelFileLocator::dbOid, elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, HistoricSnapshotActive(), InvalidOid, InvalidSubTransactionId, IsParallelWorker, IsTransactionState(), MyDatabaseId, MyDatabaseTableSpace, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_id, RelationData::rd_locator, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationMapOidToFilenumber(), RelFileLocatorSkippingWAL(), RelFileNumberIsValid, RelFileLocator::relNumber, ScanPgRelation(), RelFileLocator::spcOid, and TopSubTransactionId.

Referenced by formrdesc(), load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), RelationCacheInvalidate(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1802 of file relcache.c.

1803 {
1804  HeapTuple tuple;
1805  Form_pg_am aform;
1806 
1807  if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1808  {
1809  /*
1810  * Sequences are currently accessed like heap tables, but it doesn't
1811  * seem prudent to show that in the catalog. So just overwrite it
1812  * here.
1813  */
1814  Assert(relation->rd_rel->relam == InvalidOid);
1815  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1816  }
1817  else if (IsCatalogRelation(relation))
1818  {
1819  /*
1820  * Avoid doing a syscache lookup for catalog tables.
1821  */
1822  Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1823  relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1824  }
1825  else
1826  {
1827  /*
1828  * Look up the table access method, save the OID of its handler
1829  * function.
1830  */
1831  Assert(relation->rd_rel->relam != InvalidOid);
1832  tuple = SearchSysCache1(AMOID,
1833  ObjectIdGetDatum(relation->rd_rel->relam));
1834  if (!HeapTupleIsValid(tuple))
1835  elog(ERROR, "cache lookup failed for access method %u",
1836  relation->rd_rel->relam);
1837  aform = (Form_pg_am) GETSTRUCT(tuple);
1838  relation->rd_amhandler = aform->amhandler;
1839  ReleaseSysCache(tuple);
1840  }
1841 
1842  /*
1843  * Now we can fetch the table AM's API struct
1844  */
1845  InitTableAmRoutine(relation);
1846 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1793

References Assert(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, InitTableAmRoutine(), InvalidOid, IsCatalogRelation(), ObjectIdGetDatum(), RelationData::rd_amhandler, RelationData::rd_rel, ReleaseSysCache(), and SearchSysCache1().

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

◆ RelationParseRelOptions()

static void RelationParseRelOptions ( Relation  relation,
HeapTuple  tuple 
)
static

Definition at line 463 of file relcache.c.

464 {
465  bytea *options;
466  amoptions_function amoptsfn;
467 
468  relation->rd_options = NULL;
469 
470  /*
471  * Look up any AM-specific parse function; fall out if relkind should not
472  * have options.
473  */
474  switch (relation->rd_rel->relkind)
475  {
476  case RELKIND_RELATION:
477  case RELKIND_TOASTVALUE:
478  case RELKIND_VIEW:
479  case RELKIND_MATVIEW:
480  case RELKIND_PARTITIONED_TABLE:
481  amoptsfn = NULL;
482  break;
483  case RELKIND_INDEX:
484  case RELKIND_PARTITIONED_INDEX:
485  amoptsfn = relation->rd_indam->amoptions;
486  break;
487  default:
488  return;
489  }
490 
491  /*
492  * Fetch reloptions from tuple; have to use a hardwired descriptor because
493  * we might not have any other for pg_class yet (consider executing this
494  * code for pg_class itself)
495  */
496  options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
497 
498  /*
499  * Copy parsed data into CacheMemoryContext. To guard against the
500  * possibility of leaks in the reloptions code, we want to do the actual
501  * parsing in the caller's memory context and copy the results into
502  * CacheMemoryContext after the fact.
503  */
504  if (options)
505  {
507  VARSIZE(options));
508  memcpy(relation->rd_options, options, VARSIZE(options));
509  pfree(options);
510  }
511 }
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:143
static char ** options
static TupleDesc GetPgClassDescriptor(void)
Definition: relcache.c:4398
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
Definition: reloptions.c:1379
amoptions_function amoptions
Definition: amapi.h:274

References IndexAmRoutine::amoptions, CacheMemoryContext, extractRelOptions(), GetPgClassDescriptor(), MemoryContextAlloc(), options, pfree(), RelationData::rd_indam, RelationData::rd_options, RelationData::rd_rel, and VARSIZE.

Referenced by RelationBuildDesc(), RelationCacheInitializePhase3(), and RelationReloadIndexInfo().

◆ RelationReloadIndexInfo()

static void RelationReloadIndexInfo ( Relation  relation)
static

Definition at line 2249 of file relcache.c.

2250 {
2251  bool indexOK;
2252  HeapTuple pg_class_tuple;
2253  Form_pg_class relp;
2254 
2255  /* Should be called only for invalidated, live indexes */
2256  Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
2257  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2258  !relation->rd_isvalid &&
2260 
2261  /* Ensure it's closed at smgr level */
2262  RelationCloseSmgr(relation);
2263 
2264  /* Must free any AM cached data upon relcache flush */
2265  if (relation->rd_amcache)
2266  pfree(relation->rd_amcache);
2267  relation->rd_amcache = NULL;
2268 
2269  /*
2270  * If it's a shared index, we might be called before backend startup has
2271  * finished selecting a database, in which case we have no way to read
2272  * pg_class yet. However, a shared index can never have any significant
2273  * schema updates, so it's okay to ignore the invalidation signal. Just
2274  * mark it valid and return without doing anything more.
2275  */
2276  if (relation->rd_rel->relisshared && !criticalRelcachesBuilt)
2277  {
2278  relation->rd_isvalid = true;
2279  return;
2280  }
2281 
2282  /*
2283  * Read the pg_class row
2284  *
2285  * Don't try to use an indexscan of pg_class_oid_index to reload the info
2286  * for pg_class_oid_index ...
2287  */
2288  indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
2289  pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK, false);
2290  if (!HeapTupleIsValid(pg_class_tuple))
2291  elog(ERROR, "could not find pg_class tuple for index %u",
2292  RelationGetRelid(relation));
2293  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2294  memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2295  /* Reload reloptions in case they changed */
2296  if (relation->rd_options)
2297  pfree(relation->rd_options);
2298  RelationParseRelOptions(relation, pg_class_tuple);
2299  /* done with pg_class tuple */
2300  heap_freetuple(pg_class_tuple);
2301  /* We must recalculate physical address in case it changed */
2302  RelationInitPhysicalAddr(relation);
2303 
2304  /*
2305  * For a non-system index, there are fields of the pg_index row that are
2306  * allowed to change, so re-read that row and update the relcache entry.
2307  * Most of the info derived from pg_index (such as support function lookup
2308  * info) cannot change, and indeed the whole point of this routine is to
2309  * update the relcache entry without clobbering that data; so wholesale
2310  * replacement is not appropriate.
2311  */
2312  if (!IsSystemRelation(relation))
2313  {
2314  HeapTuple tuple;
2316 
2317  tuple = SearchSysCache1(INDEXRELID,
2318  ObjectIdGetDatum(RelationGetRelid(relation)));
2319  if (!HeapTupleIsValid(tuple))
2320  elog(ERROR, "cache lookup failed for index %u",
2321  RelationGetRelid(relation));
2322  index = (Form_pg_index) GETSTRUCT(tuple);
2323 
2324  /*
2325  * Basically, let's just copy all the bool fields. There are one or
2326  * two of these that can't actually change in the current code, but
2327  * it's not worth it to track exactly which ones they are. None of
2328  * the array fields are allowed to change, though.
2329  */
2330  relation->rd_index->indisunique = index->indisunique;
2331  relation->rd_index->indnullsnotdistinct = index->indnullsnotdistinct;
2332  relation->rd_index->indisprimary = index->indisprimary;
2333  relation->rd_index->indisexclusion = index->indisexclusion;
2334  relation->rd_index->indimmediate = index->indimmediate;
2335  relation->rd_index->indisclustered = index->indisclustered;
2336  relation->rd_index->indisvalid = index->indisvalid;
2337  relation->rd_index->indcheckxmin = index->indcheckxmin;
2338  relation->rd_index->indisready = index->indisready;
2339  relation->rd_index->indislive = index->indislive;
2340  relation->rd_index->indisreplident = index->indisreplident;
2341 
2342  /* Copy xmin too, as that is needed to make sense of indcheckxmin */
2344  HeapTupleHeaderGetXmin(tuple->t_data));
2345 
2346  ReleaseSysCache(tuple);
2347  }
2348 
2349  /* Okay, now it's valid again */
2350  relation->rd_isvalid = true;
2351 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:315
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309

References Assert(), CLASS_TUPLE_SIZE, criticalRelcachesBuilt, elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleHeaderGetXmin, HeapTupleHeaderSetXmin, HeapTupleIsValid, InvalidSubTransactionId, IsSystemRelation(), ObjectIdGetDatum(), pfree(), RelationData::rd_amcache, RelationData::rd_droppedSubid, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_isvalid, RelationData::rd_options, RelationData::rd_rel, RelationCloseSmgr(), RelationGetRelid, RelationInitPhysicalAddr(), RelationParseRelOptions(), ReleaseSysCache(), ScanPgRelation(), SearchSysCache1(), and HeapTupleData::t_data.

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

◆ RelationReloadNailed()

static void RelationReloadNailed ( Relation  relation)
static

Definition at line 2363 of file relcache.c.

2364 {
2365  Assert(relation->rd_isnailed);
2366 
2367  /*
2368  * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2369  * mapping changed.
2370  */
2371  RelationInitPhysicalAddr(relation);
2372 
2373  /* flag as needing to be revalidated */
2374  relation->rd_isvalid = false;
2375 
2376  /*
2377  * Can only reread catalog contents if in a transaction. If the relation
2378  * is currently open (not counting the nailed refcount), do so
2379  * immediately. Otherwise we've already marked the entry as possibly
2380  * invalid, and it'll be fixed when next opened.
2381  */
2382  if (!IsTransactionState() || relation->rd_refcnt <= 1)
2383  return;
2384 
2385  if (relation->rd_rel->relkind == RELKIND_INDEX)
2386  {
2387  /*
2388  * If it's a nailed-but-not-mapped index, then we need to re-read the
2389  * pg_class row to see if its relfilenumber changed.
2390  */
2391  RelationReloadIndexInfo(relation);
2392  }
2393  else
2394  {
2395  /*
2396  * Reload a non-index entry. We can't easily do so if relcaches
2397  * aren't yet built, but that's fine because at that stage the
2398  * attributes that need to be current (like relfrozenxid) aren't yet
2399  * accessed. To ensure the entry will later be revalidated, we leave
2400  * it in invalid state, but allow use (cf. RelationIdGetRelation()).
2401  */
2403  {
2404  HeapTuple pg_class_tuple;
2405  Form_pg_class relp;
2406 
2407  /*
2408  * NB: Mark the entry as valid before starting to scan, to avoid
2409  * self-recursion when re-building pg_class.
2410  */
2411  relation->rd_isvalid = true;
2412 
2413  pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
2414  true, false);
2415  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2416  memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2417  heap_freetuple(pg_class_tuple);
2418 
2419  /*
2420  * Again mark as valid, to protect against concurrently arriving
2421  * invalidations.
2422  */
2423  relation->rd_isvalid = true;
2424  }
2425  }
2426 }

References Assert(), CLASS_TUPLE_SIZE, criticalRelcachesBuilt, GETSTRUCT, heap_freetuple(), IsTransactionState(), RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_refcnt, RelationData::rd_rel, RelationGetRelid, RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and ScanPgRelation().

Referenced by RelationClearRelation().

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3719 of file relcache.c.

3720 {
3721  RelFileNumber newrelfilenumber;
3722  Relation pg_class;
3723  HeapTuple tuple;
3724  Form_pg_class classform;
3725  MultiXactId minmulti = InvalidMultiXactId;
3726  TransactionId freezeXid = InvalidTransactionId;
3727  RelFileLocator newrlocator;
3728 
3729  if (!IsBinaryUpgrade)
3730  {
3731  /* Allocate a new relfilenumber */
3732  newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3733  NULL, persistence);
3734  }
3735  else if (relation->rd_rel->relkind == RELKIND_INDEX)
3736  {
3738  ereport(ERROR,
3739  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3740  errmsg("index relfilenumber value not set when in binary upgrade mode")));
3741 
3744  }
3745  else if (relation->rd_rel->relkind == RELKIND_RELATION)
3746  {
3748  ereport(ERROR,
3749  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3750  errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3751 
3754  }
3755  else
3756  ereport(ERROR,
3757  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3758  errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3759 
3760  /*
3761  * Get a writable copy of the pg_class tuple for the given relation.
3762  */
3763  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3764 
3765  tuple = SearchSysCacheCopy1(RELOID,
3766  ObjectIdGetDatum(RelationGetRelid(relation)));
3767  if (!HeapTupleIsValid(tuple))
3768  elog(ERROR, "could not find tuple for relation %u",
3769  RelationGetRelid(relation));
3770  classform = (Form_pg_class) GETSTRUCT(tuple);
3771 
3772  /*
3773  * Schedule unlinking of the old storage at transaction commit, except
3774  * when performing a binary upgrade, when we must do it immediately.
3775  */
3776  if (IsBinaryUpgrade)
3777  {
3778  SMgrRelation srel;
3779 
3780  /*
3781  * During a binary upgrade, we use this code path to ensure that
3782  * pg_largeobject and its index have the same relfilenumbers as in the
3783  * old cluster. This is necessary because pg_upgrade treats
3784  * pg_largeobject like a user table, not a system table. It is however
3785  * possible that a table or index may need to end up with the same
3786  * relfilenumber in the new cluster as what it had in the old cluster.
3787  * Hence, we can't wait until commit time to remove the old storage.
3788  *
3789  * In general, this function needs to have transactional semantics,
3790  * and removing the old storage before commit time surely isn't.
3791  * However, it doesn't really matter, because if a binary upgrade
3792  * fails at this stage, the new cluster will need to be recreated
3793  * anyway.
3794  */
3795  srel = smgropen(relation->rd_locator, relation->rd_backend);
3796  smgrdounlinkall(&srel, 1, false);
3797  smgrclose(srel);
3798  }
3799  else
3800  {
3801  /* Not a binary upgrade, so just schedule it to happen later. */
3802  RelationDropStorage(relation);
3803  }
3804 
3805  /*
3806  * Create storage for the main fork of the new relfilenumber. If it's a
3807  * table-like object, call into the table AM to do so, which'll also
3808  * create the table's init fork if needed.
3809  *
3810  * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3811  * be caught here, if GetNewRelFileNumber messes up for any reason.
3812  */
3813  newrlocator = relation->rd_locator;
3814  newrlocator.relNumber = newrelfilenumber;
3815 
3816  if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3817  {
3818  table_relation_set_new_filelocator(relation, &newrlocator,
3819  persistence,
3820  &freezeXid, &minmulti);
3821  }
3822  else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3823  {
3824  /* handle these directly, at least for now */
3825  SMgrRelation srel;
3826 
3827  srel = RelationCreateStorage(newrlocator, persistence, true);
3828  smgrclose(srel);
3829  }
3830  else
3831  {
3832  /* we shouldn't be called for anything else */
3833  elog(ERROR, "relation \"%s\" does not have storage",
3834  RelationGetRelationName(relation));
3835  }
3836 
3837  /*
3838  * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3839  * change; instead we have to send the update to the relation mapper.
3840  *
3841  * For mapped indexes, we don't actually change the pg_class entry at all;
3842  * this is essential when reindexing pg_class itself. That leaves us with
3843  * possibly-inaccurate values of relpages etc, but those will be fixed up
3844  * later.
3845  */
3846  if (RelationIsMapped(relation))
3847  {
3848  /* This case is only supported for indexes */
3849  Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3850 
3851  /* Since we're not updating pg_class, these had better not change */
3852  Assert(classform->relfrozenxid == freezeXid);
3853  Assert(classform->relminmxid == minmulti);
3854  Assert(classform->relpersistence == persistence);
3855 
3856  /*
3857  * In some code paths it's possible that the tuple update we'd
3858  * otherwise do here is the only thing that would assign an XID for
3859  * the current transaction. However, we must have an XID to delete
3860  * files, so make sure one is assigned.
3861  */
3862  (void) GetCurrentTransactionId();
3863 
3864  /* Do the deed */
3866  newrelfilenumber,
3867  relation->rd_rel->relisshared,
3868  false);
3869 
3870  /* Since we're not updating pg_class, must trigger inval manually */
3871  CacheInvalidateRelcache(relation);
3872  }
3873  else
3874  {
3875  /* Normal case, update the pg_class entry */
3876  classform->relfilenode = newrelfilenumber;
3877 
3878  /* relpages etc. never change for sequences */
3879  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3880  {
3881  classform->relpages = 0; /* it's empty until further notice */
3882  classform->reltuples = -1;
3883  classform->relallvisible = 0;
3884  }
3885  classform->relfrozenxid = freezeXid;
3886  classform->relminmxid = minmulti;
3887  classform->relpersistence = persistence;
3888 
3889  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3890  }
3891 
3892  heap_freetuple(tuple);
3893 
3894  table_close(pg_class, RowExclusiveLock);
3895 
3896  /*
3897  * Make the pg_class row change or relation map change visible. This will
3898  * cause the relcache entry to get updated, too.
3899  */
3901 
3903 }
TransactionId MultiXactId
Definition: c.h:649
uint32 TransactionId
Definition: c.h:639
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
bool IsBinaryUpgrade
Definition: globals.c:118
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:82
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:85
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3918
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:198
void smgrclose(SMgrRelation reln)
Definition: smgr.c:320
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:462
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
void RelationDropStorage(Relation rel)
Definition: storage.c:206
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1611
void CommandCounterIncrement(void)
Definition: xact.c:1079
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:446

References Assert(), binary_upgrade_next_heap_pg_class_relfilenumber, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, GetCurrentTransactionId(), GetNewRelFileNumber(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidMultiXactId, InvalidOid, InvalidTransactionId, IsBinaryUpgrade, ObjectIdGetDatum(), OidIsValid, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, RelationAssumeNewRelfilelocator(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileLocator::relNumber, RowExclusiveLock, SearchSysCacheCopy1, smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), and table_relation_set_new_filelocator().

Referenced by AlterSequence(), ExecuteTruncateGuts(), reindex_index(), ResetSequence(), and SequenceChangePersistence().

◆ RememberToFreeTupleDescAtEOX()

static void RememberToFreeTupleDescAtEOX ( TupleDesc  td)
static

Definition at line 3065 of file relcache.c.

3066 {
3067  if (EOXactTupleDescArray == NULL)
3068  {
3069  MemoryContext oldcxt;
3070 
3072 
3073  EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3076  MemoryContextSwitchTo(oldcxt);
3077  }
3079  {
3080  int32 newlen = EOXactTupleDescArrayLen * 2;
3081 
3083 
3085  newlen * sizeof(TupleDesc));
3086  EOXactTupleDescArrayLen = newlen;
3087  }
3088 
3090 }
signed int int32
Definition: c.h:481

References Assert(), CacheMemoryContext, EOXactTupleDescArray, EOXactTupleDescArrayLen, MemoryContextSwitchTo(), NextEOXactTupleDescNum, palloc(), and repalloc().

Referenced by RelationDestroyRelation().

◆ ResourceOwnerForgetRelationRef()

static void ResourceOwnerForgetRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2139 of file relcache.c.

2140 {
2142 }
static const ResourceOwnerDesc relref_resowner_desc
Definition: relcache.c:2123
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerForget().

Referenced by RelationDecrementReferenceCount().

◆ ResourceOwnerRememberRelationRef()

static void ResourceOwnerRememberRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2134 of file relcache.c.

2135 {
2137 }
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerRemember().

Referenced by RelationIncrementReferenceCount().

◆ ResOwnerPrintRelCache()

static char * ResOwnerPrintRelCache ( Datum  res)
static

Definition at line 6849 of file relcache.c.

6850 {
6852 
6853  return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6854 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

References DatumGetPointer(), psprintf(), RelationGetRelationName, and res.

◆ ResOwnerReleaseRelation()

static void ResOwnerReleaseRelation ( Datum  res)
static

Definition at line 6857 of file relcache.c.

6858 {
6860 
6861  /*
6862  * This reference has already been removed from the resource owner, so
6863  * just decrement reference count without calling
6864  * ResourceOwnerForgetRelationRef.
6865  */
6866  Assert(rel->rd_refcnt > 0);
6867  rel->rd_refcnt -= 1;
6868 
6870 }

References Assert(), DatumGetPointer(), RelationData::rd_refcnt, RelationCloseCleanup(), and res.

◆ ScanPgRelation()

static HeapTuple ScanPgRelation ( Oid  targetRelId,
bool  indexOK,
bool  force_non_historic 
)
static

Definition at line 338 of file relcache.c.

339 {
340  HeapTuple pg_class_tuple;
341  Relation pg_class_desc;
342  SysScanDesc pg_class_scan;
343  ScanKeyData key[1];
344  Snapshot snapshot = NULL;
345 
346  /*
347  * If something goes wrong during backend startup, we might find ourselves
348  * trying to read pg_class before we've selected a database. That ain't
349  * gonna work, so bail out with a useful error message. If this happens,
350  * it probably means a relcache entry that needs to be nailed isn't.
351  */
352  if (!OidIsValid(MyDatabaseId))
353  elog(FATAL, "cannot read pg_class without having selected a database");
354 
355  /*
356  * form a scan key
357  */
358  ScanKeyInit(&key[0],
359  Anum_pg_class_oid,
360  BTEqualStrategyNumber, F_OIDEQ,
361  ObjectIdGetDatum(targetRelId));
362 
363  /*
364  * Open pg_class and fetch a tuple. Force heap scan if we haven't yet
365  * built the critical relcache entries (this includes initdb and startup
366  * without a pg_internal.init file). The caller can also force a heap
367  * scan by setting indexOK == false.
368  */
369  pg_class_desc = table_open(RelationRelationId, AccessShareLock);
370 
371  /*
372  * The caller might need a tuple that's newer than the one the historic
373  * snapshot; currently the only case requiring to do so is looking up the
374  * relfilenumber of non mapped system relations during decoding. That
375  * snapshot can't change in the midst of a relcache build, so there's no
376  * need to register the snapshot.
377  */
378  if (force_non_historic)
379  snapshot = GetNonHistoricCatalogSnapshot(RelationRelationId);
380 
381  pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
382  indexOK && criticalRelcachesBuilt,
383  snapshot,
384  1, key);
385 
386  pg_class_tuple = systable_getnext(pg_class_scan);
387 
388  /*
389  * Must copy tuple before releasing buffer.
390  */
391  if (HeapTupleIsValid(pg_class_tuple))
392  pg_class_tuple = heap_copytuple(pg_class_tuple);
393 
394  /* all done */
395  systable_endscan(pg_class_scan);
396  table_close(pg_class_desc, AccessShareLock);
397 
398  return pg_class_tuple;
399 }
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:374

References AccessShareLock, BTEqualStrategyNumber, criticalRelcachesBuilt, elog, FATAL, GetNonHistoricCatalogSnapshot(), heap_copytuple(), HeapTupleIsValid, sort-test::key, MyDatabaseId, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by RelationBuildDesc(), RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ unlink_initfile()

static void unlink_initfile ( const char *  initfilename,
int  elevel 
)
static

Definition at line 6832 of file relcache.c.

6833 {
6834  if (unlink(initfilename) < 0)
6835  {
6836  /* It might not be there, but log any error other than ENOENT */
6837  if (errno != ENOENT)
6838  ereport(elevel,
6840  errmsg("could not remove cache file \"%s\": %m",
6841  initfilename)));
6842  }
6843 }
int errcode_for_file_access(void)
Definition: elog.c:882

References ereport, errcode_for_file_access(), and errmsg().

Referenced by RelationCacheInitFilePreInvalidate(), RelationCacheInitFileRemove(), and RelationCacheInitFileRemoveInDir().

◆ write_item()

static void write_item ( const void *  data,
Size  len,
FILE *  fp 
)
static

Definition at line 6676 of file relcache.c.

6677 {
6678  if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6679  elog(FATAL, "could not write init file");
6680  if (len > 0 && fwrite(data, 1, len, fp) != len)
6681  elog(FATAL, "could not write init file");
6682 }
const void * data

References data, elog, FATAL, and len.

Referenced by write_relcache_init_file().

◆ write_relcache_init_file()

static void write_relcache_init_file ( bool  shared)
static

Definition at line 6468 of file relcache.c.

6469 {
6470  FILE *fp;
6471  char tempfilename[MAXPGPATH];
6472  char finalfilename[MAXPGPATH];
6473  int magic;
6474  HASH_SEQ_STATUS status;
6475  RelIdCacheEnt *idhentry;
6476  int i;
6477 
6478  /*
6479  * If we have already received any relcache inval events, there's no
6480  * chance of succeeding so we may as well skip the whole thing.
6481  */
6482  if (relcacheInvalsReceived != 0L)
6483  return;
6484 
6485  /*
6486  * We must write a temporary file and rename it into place. Otherwise,
6487  * another backend starting at about the same time might crash trying to
6488  * read the partially-complete file.
6489  */
6490  if (shared)
6491  {
6492  snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d",
6494  snprintf(finalfilename, sizeof(finalfilename), "global/%s",
6496  }
6497  else
6498  {
6499  snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
6501  snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
6503  }
6504 
6505  unlink(tempfilename); /* in case it exists w/wrong permissions */
6506 
6507  fp = AllocateFile(tempfilename, PG_BINARY_W);
6508  if (fp == NULL)
6509  {
6510  /*
6511  * We used to consider this a fatal error, but we might as well
6512  * continue with backend startup ...
6513  */
6514  ereport(WARNING,
6516  errmsg("could not create relation-cache initialization file \"%s\": %m",
6517  tempfilename),
6518  errdetail("Continuing anyway, but there's something wrong.")));
6519  return;
6520  }
6521 
6522  /*
6523  * Write a magic number to serve as a file version identifier. We can
6524  * change the magic number whenever the relcache layout changes.
6525  */
6526  magic = RELCACHE_INIT_FILEMAGIC;
6527  if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6528  elog(FATAL, "could not write init file");
6529 
6530  /*
6531  * Write all the appropriate reldescs (in no particular order).
6532  */
6533  hash_seq_init(&status, RelationIdCache);
6534 
6535  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
6536  {
6537  Relation rel = idhentry->reldesc;
6538  Form_pg_class relform = rel->rd_rel;
6539 
6540  /* ignore if not correct group */
6541  if (relform->relisshared != shared)
6542  continue;
6543 
6544  /*
6545  * Ignore if not supposed to be in init file. We can allow any shared
6546  * relation that's been loaded so far to be in the shared init file,
6547  * but unshared relations must be ones that should be in the local
6548  * file per RelationIdIsInInitFile. (Note: if you want to change the
6549  * criterion for rels to be kept in the init file, see also inval.c.
6550  * The reason for filtering here is to be sure that we don't put
6551  * anything into the local init file for which a relcache inval would
6552  * not cause invalidation of that init file.)
6553  */
6554  if (!shared && !RelationIdIsInInitFile(RelationGetRelid(rel)))
6555  {
6556  /* Nailed rels had better get stored. */
6557  Assert(!rel->rd_isnailed);
6558  continue;
6559  }
6560 
6561  /* first write the relcache entry proper */
6562  write_item(rel, sizeof(RelationData), fp);
6563 
6564  /* next write the relation tuple form */
6565  write_item(relform, CLASS_TUPLE_SIZE, fp);
6566 
6567  /* next, do all the attribute tuple form data entries */
6568  for (i = 0; i < relform->relnatts; i++)
6569  {
6572  }
6573 
6574  /* next, do the access method specific field */
6575  write_item(rel->rd_options,
6576  (rel->rd_options ? VARSIZE(rel->rd_options) : 0),
6577  fp);
6578 
6579  /*
6580  * If it's an index, there's more to do. Note we explicitly ignore
6581  * partitioned indexes here.
6582  */
6583  if (rel->rd_rel->relkind == RELKIND_INDEX)
6584  {
6585  /* write the pg_index tuple */
6586  /* we assume this was created by heap_copytuple! */
6589  fp);
6590 
6591  /* write the vector of opfamily OIDs */
6592  write_item(rel->rd_opfamily,
6593  relform->relnatts * sizeof(Oid),
6594  fp);
6595 
6596  /* write the vector of opcintype OIDs */
6597  write_item(rel->rd_opcintype,
6598  relform->relnatts * sizeof(Oid),
6599  fp);
6600 
6601  /* write the vector of support procedure OIDs */
6602  write_item(rel->rd_support,
6603  relform->relnatts * (rel->rd_indam->amsupport * sizeof(RegProcedure)),
6604  fp);
6605 
6606  /* write the vector of collation OIDs */
6608  relform->relnatts * sizeof(Oid),
6609  fp);
6610 
6611  /* write the vector of indoption values */
6612  write_item(rel->rd_indoption,
6613  relform->relnatts * sizeof(int16),
6614  fp);
6615 
6616  Assert(rel->rd_opcoptions);
6617 
6618  /* write the vector of opcoptions values */
6619  for (i = 0; i < relform->relnatts; i++)
6620  {
6621  bytea *opt = rel->rd_opcoptions[i];
6622 
6623  write_item(opt, opt ? VARSIZE(opt) : 0, fp);
6624  }
6625  }
6626  }
6627 
6628  if (FreeFile(fp))
6629  elog(FATAL, "could not write init file");
6630 
6631  /*
6632  * Now we have to check whether the data we've so painstakingly
6633  * accumulated is already obsolete due to someone else's just-committed
6634  * catalog changes. If so, we just delete the temp file and leave it to
6635  * the next backend to try again. (Our own relcache entries will be
6636  * updated by SI message processing, but we can't be sure whether what we
6637  * wrote out was up-to-date.)
6638  *
6639  * This mustn't run concurrently with the code that unlinks an init file
6640  * and sends SI messages, so grab a serialization lock for the duration.
6641  */
6642  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6643 
6644  /* Make sure we have seen all incoming SI messages */
6646 
6647  /*
6648  * If we have received any SI relcache invals since backend start, assume
6649  * we may have written out-of-date data.
6650  */
6651  if (relcacheInvalsReceived == 0L)
6652  {
6653  /*
6654  * OK, rename the temp file to its final name, deleting any
6655  * previously-existing init file.
6656  *
6657  * Note: a failure here is possible under Cygwin, if some other
6658  * backend is holding open an unlinked-but-not-yet-gone init file. So
6659  * treat this as a noncritical failure; just remove the useless temp
6660  * file on failure.
6661  */
6662  if (rename(tempfilename, finalfilename) < 0)
6663  unlink(tempfilename);
6664  }
6665  else
6666  {
6667  /* Delete the already-obsolete temp file */
6668  unlink(tempfilename);
6669  }
6670 
6671  LWLockRelease(RelCacheInitLock);
6672 }
#define PG_BINARY_W
Definition: c.h:1263
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int MyProcPid
Definition: globals.c:45
void AcceptInvalidationMessages(void)
Definition: inval.c:806
static void write_item(const void *data, Size len, FILE *fp)
Definition: relcache.c:6676
bool RelationIdIsInInitFile(Oid relationId)
Definition: relcache.c:6695
uint32 t_len
Definition: htup.h:64

References AcceptInvalidationMessages(), AllocateFile(), IndexAmRoutine::amsupport, Assert(), ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, DatabasePath, elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), FATAL, FreeFile(), hash_seq_init(), hash_seq_search(), HEAPTUPLESIZE, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, MyProcPid, PG_BINARY_W, RelationData::rd_att, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_isnailed, RelationData::rd_opcintype, RelationData::rd_opcoptions, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_support, RelationGetRelid, RelationIdCache, RelationIdIsInInitFile(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, relcacheInvalsReceived, relidcacheent::reldesc, snprintf, HeapTupleData::t_len, TupleDescAttr, VARSIZE, WARNING, and write_item().

Referenced by RelationCacheInitializePhase3().

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

◆ Desc_pg_attribute

const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}
static

Definition at line 112 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_auth_members

const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members}
static

Definition at line 117 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_authid

const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid}
static

Definition at line 116 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_class

const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}
static

Definition at line 111 of file relcache.c.

Referenced by GetPgClassDescriptor(), and RelationCacheInitializePhase3().

◆ Desc_pg_database

const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database}
static

Definition at line 115 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_index

const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}
static

Definition at line 118 of file relcache.c.

Referenced by GetPgIndexDescriptor().

◆ Desc_pg_proc

const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}
static

Definition at line 113 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_shseclabel

const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel] = {Schema_pg_shseclabel}
static

Definition at line 119 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_subscription

const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription] = {Schema_pg_subscription}
static

Definition at line 120 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_type

const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}
static

Definition at line 114 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ eoxact_list

Oid eoxact_list[MAX_EOXACT_LIST]
static

Definition at line 185 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_len

int eoxact_list_len = 0
static

Definition at line 186 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_overflowed

bool eoxact_list_overflowed = false
static

Definition at line 187 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ EOXactTupleDescArray

TupleDesc* EOXactTupleDescArray
static

Definition at line 202 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ EOXactTupleDescArrayLen

int EOXactTupleDescArrayLen = 0
static

Definition at line 204 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ in_progress_list

◆ in_progress_list_len

◆ in_progress_list_maxlen

int in_progress_list_maxlen
static

Definition at line 172 of file relcache.c.

Referenced by RelationBuildDesc(), and RelationCacheInitialize().

◆ NextEOXactTupleDescNum

int NextEOXactTupleDescNum = 0
static

Definition at line 203 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ OpClassCache

HTAB* OpClassCache = NULL
static

Definition at line 271 of file relcache.c.

Referenced by LookupOpclassInfo().

◆ RelationIdCache

◆ relcacheInvalsReceived

long relcacheInvalsReceived = 0L
static

◆ relref_resowner_desc

const ResourceOwnerDesc relref_resowner_desc
static
Initial value:
=
{
.name = "relcache reference",
.release_priority = RELEASE_PRIO_RELCACHE_REFS,
.ReleaseResource = ResOwnerReleaseRelation,
.DebugPrint = ResOwnerPrintRelCache
}
static void ResOwnerReleaseRelation(Datum res)
Definition: relcache.c:6857
static char * ResOwnerPrintRelCache(Datum res)
Definition: relcache.c:6849
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
#define RELEASE_PRIO_RELCACHE_REFS
Definition: resowner.h:64

Definition at line 2123 of file relcache.c.

Referenced by ResourceOwnerForgetRelationRef(), and ResourceOwnerRememberRelationRef().