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 3943 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:454
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:491
#define RelationGetRelationName(relation)
Definition: rel.h:541

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
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define CLASS_TUPLE_SIZE
Definition: pg_class.h:145
MemoryContextSwitchTo(old_ctx)
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 3396 of file relcache.c.

3398 {
3399  /*
3400  * Is it a relation created in the current subtransaction?
3401  *
3402  * During subcommit, mark it as belonging to the parent, instead, as long
3403  * as it has not been dropped. Otherwise simply delete the relcache entry.
3404  * --- it isn't interesting any longer.
3405  */
3406  if (relation->rd_createSubid == mySubid)
3407  {
3408  /*
3409  * Valid rd_droppedSubid means the corresponding relation is dropped
3410  * but the relcache entry is preserved for at-commit pending sync. We
3411  * need to drop it explicitly here not to make the entry orphan.
3412  */
3413  Assert(relation->rd_droppedSubid == mySubid ||
3415  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3416  relation->rd_createSubid = parentSubid;
3417  else if (RelationHasReferenceCountZero(relation))
3418  {
3419  /* allow the entry to be removed */
3424  RelationClearRelation(relation, false);
3425  return;
3426  }
3427  else
3428  {
3429  /*
3430  * Hmm, somewhere there's a (leaked?) reference to the relation.
3431  * We daren't remove the entry for fear of dereferencing a
3432  * dangling pointer later. Bleat, and transfer it to the parent
3433  * subtransaction so we can try again later. This must be just a
3434  * WARNING to avoid error-during-error-recovery loops.
3435  */
3436  relation->rd_createSubid = parentSubid;
3437  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3438  RelationGetRelationName(relation));
3439  }
3440  }
3441 
3442  /*
3443  * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3444  * or drop record.
3445  */
3446  if (relation->rd_newRelfilelocatorSubid == mySubid)
3447  {
3448  if (isCommit)
3449  relation->rd_newRelfilelocatorSubid = parentSubid;
3450  else
3452  }
3453 
3454  if (relation->rd_firstRelfilelocatorSubid == mySubid)
3455  {
3456  if (isCommit)
3457  relation->rd_firstRelfilelocatorSubid = parentSubid;
3458  else
3460  }
3461 
3462  if (relation->rd_droppedSubid == mySubid)
3463  {
3464  if (isCommit)
3465  relation->rd_droppedSubid = parentSubid;
3466  else
3468  }
3469 }
#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:2532
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 3341 of file relcache.c.

3343 {
3344  HASH_SEQ_STATUS status;
3345  RelIdCacheEnt *idhentry;
3346  int i;
3347 
3348  /*
3349  * Forget in_progress_list. This is relevant when we're aborting due to
3350  * an error during RelationBuildDesc(). We don't commit subtransactions
3351  * during RelationBuildDesc().
3352  */
3353  Assert(in_progress_list_len == 0 || !isCommit);
3355 
3356  /*
3357  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3358  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3359  * logic as in AtEOXact_RelationCache.
3360  */
3362  {
3363  hash_seq_init(&status, RelationIdCache);
3364  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3365  {
3366  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3367  mySubid, parentSubid);
3368  }
3369  }
3370  else
3371  {
3372  for (i = 0; i < eoxact_list_len; i++)
3373  {
3374  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3375  &eoxact_list[i],
3376  HASH_FIND,
3377  NULL);
3378  if (idhentry != NULL)
3379  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3380  mySubid, parentSubid);
3381  }
3382  }
3383 
3384  /* Don't reset the list; we still need more cleanup later */
3385 }
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:3396
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 3259 of file relcache.c.

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

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

4516 {
4517  const AttrDefault *ada = (const AttrDefault *) a;
4518  const AttrDefault *adb = (const AttrDefault *) b;
4519 
4520  return pg_cmp_s16(ada->adnum, adb->adnum);
4521 }
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 4435 of file relcache.c.

4436 {
4437  AttrDefault *attrdef;
4438  Relation adrel;
4439  SysScanDesc adscan;
4440  ScanKeyData skey;
4441  HeapTuple htup;
4442  int found = 0;
4443 
4444  /* Allocate array with room for as many entries as expected */
4445  attrdef = (AttrDefault *)
4447  ndef * sizeof(AttrDefault));
4448 
4449  /* Search pg_attrdef for relevant entries */
4450  ScanKeyInit(&skey,
4451  Anum_pg_attrdef_adrelid,
4452  BTEqualStrategyNumber, F_OIDEQ,
4453  ObjectIdGetDatum(RelationGetRelid(relation)));
4454 
4455  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4456  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4457  NULL, 1, &skey);
4458 
4459  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4460  {
4461  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4462  Datum val;
4463  bool isnull;
4464 
4465  /* protect limited size of array */
4466  if (found >= ndef)
4467  {
4468  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4469  adform->adnum, RelationGetRelationName(relation));
4470  break;
4471  }
4472 
4473  val = fastgetattr(htup,
4474  Anum_pg_attrdef_adbin,
4475  adrel->rd_att, &isnull);
4476  if (isnull)
4477  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4478  adform->adnum, RelationGetRelationName(relation));
4479  else
4480  {
4481  /* detoast and convert to cstring in caller's context */
4482  char *s = TextDatumGetCString(val);
4483 
4484  attrdef[found].adnum = adform->adnum;
4485  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4486  pfree(s);
4487  found++;
4488  }
4489  }
4490 
4491  systable_endscan(adscan);
4492  table_close(adrel, AccessShareLock);
4493 
4494  if (found != ndef)
4495  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4496  ndef - found, RelationGetRelationName(relation));
4497 
4498  /*
4499  * Sort the AttrDefault entries by adnum, for the convenience of
4500  * equalTupleDescs(). (Usually, they already will be in order, but this
4501  * might not be so if systable_getnext isn't using an index.)
4502  */
4503  if (found > 1)
4504  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4505 
4506  /* Install array only after it's fully valid */
4507  relation->rd_att->constr->defval = attrdef;
4508  relation->rd_att->constr->num_defval = found;
4509 }
#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:670
#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:507
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4515
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 4370 of file relcache.c.

4371 {
4372  TupleDesc result;
4373  MemoryContext oldcxt;
4374  int i;
4375 
4377 
4378  result = CreateTemplateTupleDesc(natts);
4379  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4380  result->tdtypmod = -1;
4381 
4382  for (i = 0; i < natts; i++)
4383  {
4384  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4385  /* make sure attcacheoff is valid */
4386  TupleDescAttr(result, i)->attcacheoff = -1;
4387  }
4388 
4389  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4390  TupleDescAttr(result, 0)->attcacheoff = 0;
4391 
4392  /* Note: we don't bother to set up a TupleConstr entry */
4393 
4394  MemoryContextSwitchTo(oldcxt);
4395 
4396  return result;
4397 }
#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 4619 of file relcache.c.

4620 {
4621  const ConstrCheck *ca = (const ConstrCheck *) a;
4622  const ConstrCheck *cb = (const ConstrCheck *) b;
4623 
4624  return strcmp(ca->ccname, cb->ccname);
4625 }
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 4530 of file relcache.c.

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

5856 {
5857  bytea **opts = palloc(sizeof(*opts) * natts);
5858 
5859  for (int i = 0; i < natts; i++)
5860  {
5861  bytea *opt = srcopts[i];
5862 
5863  opts[i] = !opt ? NULL : (bytea *)
5864  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5865  }
5866 
5867  return opts;
5868 }
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 5936 of file relcache.c.

5937 {
5941 
5942  return 0; /* return value does not matter */
5943 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3344
#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:548

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

5954 {
5955  TupleDesc reldesc = RelationGetDescr(rel);
5956  const char *colname;
5957 
5958  /* Use reldesc if it's a user attribute, else consult the catalogs */
5959  if (attnum > 0 && attnum <= reldesc->natts)
5960  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5961  else
5962  colname = get_attname(RelationGetRelid(rel), attnum, false);
5963 
5964  return errtablecolname(rel, colname);
5965 }
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:533
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5977

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

Referenced by ATRewriteTable(), ExecConstraints(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5977 of file relcache.c.

5978 {
5979  errtable(rel);
5981 
5982  return 0; /* return value does not matter */
5983 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5936

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

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

4401 {
4402  static TupleDesc pgclassdesc = NULL;
4403 
4404  /* Already done? */
4405  if (pgclassdesc == NULL)
4406  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4407  Desc_pg_class);
4408 
4409  return pgclassdesc;
4410 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4370
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 4413 of file relcache.c.

4414 {
4415  static TupleDesc pgindexdesc = NULL;
4416 
4417  /* Already done? */
4418  if (pgindexdesc == NULL)
4419  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4420  Desc_pg_index);
4421 
4422  return pgindexdesc;
4423 }
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 1596 of file relcache.c.

1602 {
1603  int attIndex;
1604 
1605  for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1606  {
1607  OpClassCacheEnt *opcentry;
1608 
1609  if (!OidIsValid(indclass->values[attIndex]))
1610  elog(ERROR, "bogus pg_index tuple");
1611 
1612  /* look up the info for this opclass, using a cache */
1613  opcentry = LookupOpclassInfo(indclass->values[attIndex],
1614  maxSupportNumber);
1615 
1616  /* copy cached data into relcache entry */
1617  opFamily[attIndex] = opcentry->opcfamily;
1618  opcInType[attIndex] = opcentry->opcintype;
1619  if (maxSupportNumber > 0)
1620  memcpy(&indexSupport[attIndex * maxSupportNumber],
1621  opcentry->supportProcs,
1622  maxSupportNumber * sizeof(RegProcedure));
1623  }
1624 }
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:1647
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 1401 of file relcache.c.

1402 {
1403  IndexAmRoutine *cached,
1404  *tmp;
1405 
1406  /*
1407  * Call the amhandler in current, short-lived memory context, just in case
1408  * it leaks anything (it probably won't, but let's be paranoid).
1409  */
1410  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1411 
1412  /* OK, now transfer the data into relation's rd_indexcxt. */
1413  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1414  sizeof(IndexAmRoutine));
1415  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1416  relation->rd_indam = cached;
1417 
1418  pfree(tmp);
1419 }
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 1800 of file relcache.c.

1801 {
1802  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1803 }
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 4334 of file relcache.c.

4335 {
4336  Relation ird;
4337 
4338  /*
4339  * We must lock the underlying catalog before locking the index to avoid
4340  * deadlock, since RelationBuildDesc might well need to read the catalog,
4341  * and if anyone else is exclusive-locking this catalog and index they'll
4342  * be doing it in that order.
4343  */
4344  LockRelationOid(heapoid, AccessShareLock);
4345  LockRelationOid(indexoid, AccessShareLock);
4346  ird = RelationBuildDesc(indexoid, true);
4347  if (ird == NULL)
4348  elog(PANIC, "could not open critical system index %u", indexoid);
4349  ird->rd_isnailed = true;
4350  ird->rd_refcnt = 1;
4353 
4354  (void) RelationGetIndexAttOptions(ird, false);
4355 }
#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:5875

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

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

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

References AccessShareLock, Assert(), BTEqualStrategyNumber, CacheMemoryContext, CreateCacheMemoryContext(), criticalRelcachesBuilt, ctl, debug_discard_caches, elog, ERROR, GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HeapTupleIsValid, 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 3920 of file relcache.c.

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

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 if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1212  {
1213  /*
1214  * Do nothing: access methods are a setting that partitions can
1215  * inherit.
1216  */
1217  }
1218  else
1219  Assert(relation->rd_rel->relam == InvalidOid);
1220 
1221  /* extract reloptions if any */
1222  RelationParseRelOptions(relation, pg_class_tuple);
1223 
1224  /*
1225  * Fetch rules and triggers that affect this relation.
1226  *
1227  * Note that RelationBuildRuleLock() relies on this being done after
1228  * extracting the relation's reloptions.
1229  */
1230  if (relation->rd_rel->relhasrules)
1231  RelationBuildRuleLock(relation);
1232  else
1233  {
1234  relation->rd_rules = NULL;
1235  relation->rd_rulescxt = NULL;
1236  }
1237 
1238  if (relation->rd_rel->relhastriggers)
1239  RelationBuildTriggers(relation);
1240  else
1241  relation->trigdesc = NULL;
1242 
1243  if (relation->rd_rel->relrowsecurity)
1244  RelationBuildRowSecurity(relation);
1245  else
1246  relation->rd_rsdesc = NULL;
1247 
1248  /*
1249  * initialize the relation lock manager information
1250  */
1251  RelationInitLockInfo(relation); /* see lmgr.c */
1252 
1253  /*
1254  * initialize physical addressing information for the relation
1255  */
1256  RelationInitPhysicalAddr(relation);
1257 
1258  /* make sure relation is marked as having no open file yet */
1259  relation->rd_smgr = NULL;
1260 
1261  /*
1262  * now we can free the memory allocated for pg_class_tuple
1263  */
1264  heap_freetuple(pg_class_tuple);
1265 
1266  /*
1267  * If an invalidation arrived mid-build, start over. Between here and the
1268  * end of this function, don't add code that does or reasonably could read
1269  * system catalogs. That range must be free from invalidation processing
1270  * for the !insertIt case. For the insertIt case, RelationCacheInsert()
1271  * will enroll this relation in ordinary relcache invalidation processing,
1272  */
1273  if (in_progress_list[in_progress_offset].invalidated)
1274  {
1275  RelationDestroyRelation(relation, false);
1276  goto retry;
1277  }
1278  Assert(in_progress_offset + 1 == in_progress_list_len);
1280 
1281  /*
1282  * Insert newly created relation into relcache hash table, if requested.
1283  *
1284  * There is one scenario in which we might find a hashtable entry already
1285  * present, even though our caller failed to find it: if the relation is a
1286  * system catalog or index that's used during relcache load, we might have
1287  * recursively created the same relcache entry during the preceding steps.
1288  * So allow RelationCacheInsert to delete any already-present relcache
1289  * entry for the same OID. The already-present entry should have refcount
1290  * zero (else somebody forgot to close it); in the event that it doesn't,
1291  * we'll elog a WARNING and leak the already-present entry.
1292  */
1293  if (insertIt)
1294  RelationCacheInsert(relation, true);
1295 
1296  /* It's fully valid */
1297  relation->rd_isvalid = true;
1298 
1299 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1300  if (tmpcxt)
1301  {
1302  /* Return to caller's context, and blow away the temporary context */
1303  MemoryContextSwitchTo(oldcxt);
1304  MemoryContextDelete(tmpcxt);
1305  }
1306 #endif
1307 
1308  return relation;
1309 }
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:1425
static int in_progress_list_maxlen
Definition: relcache.c:172
static void RelationDestroyRelation(Relation relation, bool remember_tupdesc)
Definition: relcache.c:2440
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 3478 of file relcache.c.

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

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

6763 {
6764  LWLockRelease(RelCacheInitLock);
6765 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1782

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6737 of file relcache.c.

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

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

6778 {
6779  const char *tblspcdir = "pg_tblspc";
6780  DIR *dir;
6781  struct dirent *de;
6782  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6783 
6784  snprintf(path, sizeof(path), "global/%s",
6786  unlink_initfile(path, LOG);
6787 
6788  /* Scan everything in the default tablespace */
6790 
6791  /* Scan the tablespace link directory to find non-default tablespaces */
6792  dir = AllocateDir(tblspcdir);
6793 
6794  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6795  {
6796  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6797  {
6798  /* Scan the tablespace dir for per-database dirs */
6799  snprintf(path, sizeof(path), "%s/%s/%s",
6800  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6802  }
6803  }
6804 
6805  FreeDir(dir);
6806 }
#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:6810
#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 6810 of file relcache.c.

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

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

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

References CacheMemoryContext, CreateCacheMemoryContext(), ctl, HASH_BLOBS, hash_create(), HASH_ELEM, in_progress_list, in_progress_list_maxlen, INITRELCACHESIZE, MemoryContextAlloc(), RelationIdCache, and RelationMapInitialize().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3992 of file relcache.c.

3993 {
3994  MemoryContext oldcxt;
3995 
3996  /*
3997  * relation mapper needs initialized too
3998  */
4000 
4001  /*
4002  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4003  * nothing.
4004  */
4006  return;
4007 
4008  /*
4009  * switch to cache memory context
4010  */
4012 
4013  /*
4014  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4015  * the cache with pre-made descriptors for the critical shared catalogs.
4016  */
4017  if (!load_relcache_init_file(true))
4018  {
4019  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4020  Natts_pg_database, Desc_pg_database);
4021  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4022  Natts_pg_authid, Desc_pg_authid);
4023  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4024  Natts_pg_auth_members, Desc_pg_auth_members);
4025  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4026  Natts_pg_shseclabel, Desc_pg_shseclabel);
4027  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4028  Natts_pg_subscription, Desc_pg_subscription);
4029 
4030 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4031  }
4032 
4033  MemoryContextSwitchTo(oldcxt);
4034 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6054
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:1874
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 4051 of file relcache.c.

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

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

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

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

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

References Assert(), CLASS_TUPLE_SIZE, elog, equalRSDesc(), equalRuleLocks(), equalTupleDescs(), ERROR, HistoricSnapshotActive(), InvalidSubTransactionId, InvalidTransactionId, IsTransactionState(), MemoryContextSetParent(), 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(), SWAPFIELD, and table_free_rd_amcache().

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2193 of file relcache.c.

2194 {
2195  /* Note: no locking manipulations needed */
2197 
2198  RelationCloseCleanup(relation);
2199 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2202

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

2203 {
2204  /*
2205  * If the relation is no longer open in this session, we can clean up any
2206  * stale partition descriptors it has. This is unlikely, so check to see
2207  * if there are child contexts before expending a call to mcxt.c.
2208  */
2209  if (RelationHasReferenceCountZero(relation))
2210  {
2211  if (relation->rd_pdcxt != NULL &&
2212  relation->rd_pdcxt->firstchild != NULL)
2214 
2215  if (relation->rd_pddcxt != NULL &&
2216  relation->rd_pddcxt->firstchild != NULL)
2218  }
2219 
2220 #ifdef RELCACHE_FORCE_RELEASE
2221  if (RelationHasReferenceCountZero(relation) &&
2222  relation->rd_createSubid == InvalidSubTransactionId &&
2224  RelationClearRelation(relation, false);
2225 #endif
2226 }
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 2173 of file relcache.c.

2174 {
2175  Assert(rel->rd_refcnt > 0);
2176  rel->rd_refcnt -= 1;
2179 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2146
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 2440 of file relcache.c.

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

Referenced by RelationBuildDesc(), and RelationClearRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2835 of file relcache.c.

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

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2868 of file relcache.c.

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

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

5076 {
5077  List *result;
5078  Datum exprsDatum;
5079  bool isnull;
5080  char *exprsString;
5081  List *rawExprs;
5082  ListCell *lc;
5083 
5084  /* Quick exit if there is nothing to do. */
5085  if (relation->rd_indextuple == NULL ||
5086  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5087  return NIL;
5088 
5089  /* Extract raw node tree(s) from index tuple. */
5090  exprsDatum = heap_getattr(relation->rd_indextuple,
5091  Anum_pg_index_indexprs,
5093  &isnull);
5094  Assert(!isnull);
5095  exprsString = TextDatumGetCString(exprsDatum);
5096  rawExprs = (List *) stringToNode(exprsString);
5097  pfree(exprsString);
5098 
5099  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5100  result = NIL;
5101  foreach(lc, rawExprs)
5102  {
5103  Node *rawExpr = (Node *) lfirst(lc);
5104 
5105  result = lappend(result,
5106  makeConst(exprType(rawExpr),
5107  exprTypmod(rawExpr),
5108  exprCollation(rawExpr),
5109  1,
5110  (Datum) 0,
5111  true,
5112  true));
5113  }
5114 
5115  return result;
5116 }
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:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4413

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

6698 {
6699  if (relationId == SharedSecLabelRelationId ||
6700  relationId == TriggerRelidNameIndexId ||
6701  relationId == DatabaseNameIndexId ||
6702  relationId == SharedSecLabelObjectIndexId)
6703  {
6704  /*
6705  * If this Assert fails, we don't need the applicable special case
6706  * anymore.
6707  */
6708  Assert(!RelationSupportsSysCache(relationId));
6709  return true;
6710  }
6711  return RelationSupportsSysCache(relationId);
6712 }
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 1425 of file relcache.c.

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

1320 {
1321  RelFileNumber oldnumber = relation->rd_locator.relNumber;
1322 
1323  /* these relations kinds never have storage */
1324  if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
1325  return;
1326 
1327  if (relation->rd_rel->reltablespace)
1328  relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
1329  else
1331  if (relation->rd_locator.spcOid == GLOBALTABLESPACE_OID)
1332  relation->rd_locator.dbOid = InvalidOid;
1333  else
1334  relation->rd_locator.dbOid = MyDatabaseId;
1335 
1336  if (relation->rd_rel->relfilenode)
1337  {
1338  /*
1339  * Even if we are using a decoding snapshot that doesn't represent the
1340  * current state of the catalog we need to make sure the filenode
1341  * points to the current file since the older file will be gone (or
1342  * truncated). The new file will still contain older rows so lookups
1343  * in them will work correctly. This wouldn't work correctly if
1344  * rewrites were allowed to change the schema in an incompatible way,
1345  * but those are prevented both on catalog tables and on user tables
1346  * declared as additional catalog tables.
1347  */
1350  && IsTransactionState())
1351  {
1352  HeapTuple phys_tuple;
1353  Form_pg_class physrel;
1354 
1355  phys_tuple = ScanPgRelation(RelationGetRelid(relation),
1356  RelationGetRelid(relation) != ClassOidIndexId,
1357  true);
1358  if (!HeapTupleIsValid(phys_tuple))
1359  elog(ERROR, "could not find pg_class entry for %u",
1360  RelationGetRelid(relation));
1361  physrel = (Form_pg_class) GETSTRUCT(phys_tuple);
1362 
1363  relation->rd_rel->reltablespace = physrel->reltablespace;
1364  relation->rd_rel->relfilenode = physrel->relfilenode;
1365  heap_freetuple(phys_tuple);
1366  }
1367 
1368  relation->rd_locator.relNumber = relation->rd_rel->relfilenode;
1369  }
1370  else
1371  {
1372  /* Consult the relation mapper */
1373  relation->rd_locator.relNumber =
1375  relation->rd_rel->relisshared);
1376  if (!RelFileNumberIsValid(relation->rd_locator.relNumber))
1377  elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1378  RelationGetRelationName(relation), relation->rd_id);
1379  }
1380 
1381  /*
1382  * For RelationNeedsWAL() to answer correctly on parallel workers, restore
1383  * rd_firstRelfilelocatorSubid. No subtransactions start or end while in
1384  * parallel mode, so the specific SubTransactionId does not matter.
1385  */
1386  if (IsParallelWorker() && oldnumber != relation->rd_locator.relNumber)
1387  {
1388  if (RelFileLocatorSkippingWAL(relation->rd_locator))
1390  else
1392  }
1393 }
#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:686
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 1809 of file relcache.c.

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

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:4400
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 2256 of file relcache.c.

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

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

◆ RelationReloadNailed()

static void RelationReloadNailed ( Relation  relation)
static

Definition at line 2368 of file relcache.c.

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

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

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

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

3068 {
3069  if (EOXactTupleDescArray == NULL)
3070  {
3071  MemoryContext oldcxt;
3072 
3074 
3075  EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3078  MemoryContextSwitchTo(oldcxt);
3079  }
3081  {
3082  int32 newlen = EOXactTupleDescArrayLen * 2;
3083 
3085 
3087  newlen * sizeof(TupleDesc));
3088  EOXactTupleDescArrayLen = newlen;
3089  }
3090 
3092 }
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 2146 of file relcache.c.

2147 {
2149 }
static const ResourceOwnerDesc relref_resowner_desc
Definition: relcache.c:2130
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 2141 of file relcache.c.

2142 {
2144 }
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 6851 of file relcache.c.

6852 {
6854 
6855  return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6856 }
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 6859 of file relcache.c.

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

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

6835 {
6836  if (unlink(initfilename) < 0)
6837  {
6838  /* It might not be there, but log any error other than ENOENT */
6839  if (errno != ENOENT)
6840  ereport(elevel,
6842  errmsg("could not remove cache file \"%s\": %m",
6843  initfilename)));
6844  }
6845 }
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 6678 of file relcache.c.

6679 {
6680  if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6681  elog(FATAL, "could not write init file");
6682  if (len > 0 && fwrite(data, 1, len, fp) != len)
6683  elog(FATAL, "could not write init file");
6684 }
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 6470 of file relcache.c.

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

Definition at line 2130 of file relcache.c.

Referenced by ResourceOwnerForgetRelationRef(), and ResourceOwnerRememberRelationRef().