PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 RelationInvalidateRelation (Relation relation)
 
static void RelationClearRelation (Relation relation)
 
static void RelationRebuildRelation (Relation relation)
 
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, bool deferrable_ok)
 
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 3955 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:489
#define RelationGetRelationName(relation)
Definition: rel.h:539

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

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

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

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

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

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

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 410 of file relcache.c.

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

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

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

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

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

4532 {
4533  const AttrDefault *ada = (const AttrDefault *) a;
4534  const AttrDefault *adb = (const AttrDefault *) b;
4535 
4536  return pg_cmp_s16(ada->adnum, adb->adnum);
4537 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:586
int b
Definition: isn.c:69
int a
Definition: isn.c:68
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 4451 of file relcache.c.

4452 {
4453  AttrDefault *attrdef;
4454  Relation adrel;
4455  SysScanDesc adscan;
4456  ScanKeyData skey;
4457  HeapTuple htup;
4458  int found = 0;
4459 
4460  /* Allocate array with room for as many entries as expected */
4461  attrdef = (AttrDefault *)
4463  ndef * sizeof(AttrDefault));
4464 
4465  /* Search pg_attrdef for relevant entries */
4466  ScanKeyInit(&skey,
4467  Anum_pg_attrdef_adrelid,
4468  BTEqualStrategyNumber, F_OIDEQ,
4469  ObjectIdGetDatum(RelationGetRelid(relation)));
4470 
4471  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4472  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4473  NULL, 1, &skey);
4474 
4475  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4476  {
4477  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4478  Datum val;
4479  bool isnull;
4480 
4481  /* protect limited size of array */
4482  if (found >= ndef)
4483  {
4484  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4485  adform->adnum, RelationGetRelationName(relation));
4486  break;
4487  }
4488 
4489  val = fastgetattr(htup,
4490  Anum_pg_attrdef_adbin,
4491  adrel->rd_att, &isnull);
4492  if (isnull)
4493  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4494  adform->adnum, RelationGetRelationName(relation));
4495  else
4496  {
4497  /* detoast and convert to cstring in caller's context */
4498  char *s = TextDatumGetCString(val);
4499 
4500  attrdef[found].adnum = adform->adnum;
4501  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4502  pfree(s);
4503  found++;
4504  }
4505  }
4506 
4507  systable_endscan(adscan);
4508  table_close(adrel, AccessShareLock);
4509 
4510  if (found != ndef)
4511  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4512  ndef - found, RelationGetRelationName(relation));
4513 
4514  /*
4515  * Sort the AttrDefault entries by adnum, for the convenience of
4516  * equalTupleDescs(). (Usually, they already will be in order, but this
4517  * might not be so if systable_getnext isn't using an index.)
4518  */
4519  if (found > 1)
4520  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4521 
4522  /* Install array only after it's fully valid */
4523  relation->rd_att->constr->defval = attrdef;
4524  relation->rd_att->constr->num_defval = found;
4525 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#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:689
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:447
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetRelid(relation)
Definition: rel.h:505
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4531
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 4386 of file relcache.c.

4387 {
4388  TupleDesc result;
4389  MemoryContext oldcxt;
4390  int i;
4391 
4393 
4394  result = CreateTemplateTupleDesc(natts);
4395  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4396  result->tdtypmod = -1;
4397 
4398  for (i = 0; i < natts; i++)
4399  {
4400  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4401  /* make sure attcacheoff is valid */
4402  TupleDescAttr(result, i)->attcacheoff = -1;
4403  }
4404 
4405  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4406  TupleDescAttr(result, 0)->attcacheoff = 0;
4407 
4408  /* Note: we don't bother to set up a TupleConstr entry */
4409 
4410  MemoryContextSwitchTo(oldcxt);
4411 
4412  return result;
4413 }
#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 4635 of file relcache.c.

4636 {
4637  const ConstrCheck *ca = (const ConstrCheck *) a;
4638  const ConstrCheck *cb = (const ConstrCheck *) b;
4639 
4640  return strcmp(ca->ccname, cb->ccname);
4641 }
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 4546 of file relcache.c.

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

5868 {
5869  bytea **opts = palloc(sizeof(*opts) * natts);
5870 
5871  for (int i = 0; i < natts; i++)
5872  {
5873  bytea *opt = srcopts[i];
5874 
5875  opts[i] = !opt ? NULL : (bytea *)
5876  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5877  }
5878 
5879  return opts;
5880 }
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:692

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

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

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5948 of file relcache.c.

5949 {
5953 
5954  return 0; /* return value does not matter */
5955 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define RelationGetNamespace(relation)
Definition: rel.h:546

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5965 of file relcache.c.

5966 {
5967  TupleDesc reldesc = RelationGetDescr(rel);
5968  const char *colname;
5969 
5970  /* Use reldesc if it's a user attribute, else consult the catalogs */
5971  if (attnum > 0 && attnum <= reldesc->natts)
5972  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5973  else
5974  colname = get_attname(RelationGetRelid(rel), attnum, false);
5975 
5976  return errtablecolname(rel, colname);
5977 }
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetDescr(relation)
Definition: rel.h:531
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5989

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

5990 {
5991  errtable(rel);
5993 
5994  return 0; /* return value does not matter */
5995 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5948

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:507
const TableAmRoutine * GetHeapamTableAmRoutine(void)
void RelationInitLockInfo(Relation relation)
Definition: lmgr.c:70
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 4416 of file relcache.c.

4417 {
4418  static TupleDesc pgclassdesc = NULL;
4419 
4420  /* Already done? */
4421  if (pgclassdesc == NULL)
4422  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4423  Desc_pg_class);
4424 
4425  return pgclassdesc;
4426 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4386
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 4429 of file relcache.c.

4430 {
4431  static TupleDesc pgindexdesc = NULL;
4432 
4433  /* Already done? */
4434  if (pgindexdesc == NULL)
4435  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4436  Desc_pg_index);
4437 
4438  return pgindexdesc;
4439 }
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:655
#define OidIsValid(objectId)
Definition: c.h:780
#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:738
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:1181
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 4348 of file relcache.c.

4349 {
4350  Relation ird;
4351 
4352  /*
4353  * We must lock the underlying catalog before locking the index to avoid
4354  * deadlock, since RelationBuildDesc might well need to read the catalog,
4355  * and if anyone else is exclusive-locking this catalog and index they'll
4356  * be doing it in that order.
4357  */
4358  LockRelationOid(heapoid, AccessShareLock);
4359  LockRelationOid(indexoid, AccessShareLock);
4360  ird = RelationBuildDesc(indexoid, true);
4361  if (ird == NULL)
4362  ereport(PANIC,
4364  errmsg_internal("could not open critical system index %u", indexoid));
4365  ird->rd_isnailed = true;
4366  ird->rd_refcnt = 1;
4369 
4370  (void) RelationGetIndexAttOptions(ird, false);
4371 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode(int sqlerrcode)
Definition: elog.c:853
#define PANIC
Definition: elog.h:42
#define ereport(elevel,...)
Definition: elog.h:149
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:226
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1039
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5887

References AccessShareLock, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), 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 6066 of file relcache.c.

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

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

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ LookupOpclassInfo()

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

Definition at line 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:680
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:258
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:1853
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 3932 of file relcache.c.

3933 {
3937 
3938  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3939  EOXactListAdd(relation);
3940 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790

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:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3766
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:193
#define ProcNumberForTempRelations()
Definition: proc.h:324
#define RECOVER_RELATION_BUILD_MEMORY
Definition: relcache.c:102
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:465
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:410
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:2404
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:732
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:340
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:522
static InProgressEnt * in_progress_list
Definition: relcache.c:170
bool invalidated
Definition: relcache.c:167
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1857

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(), RelationIdGetRelation(), and RelationRebuildRelation().

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

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

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

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:436
void setRuleCheckAsUser(Node *node, Oid userid)
Definition: nodes.h:129
Definition: localtime.c:73
static struct rule * rules
Definition: zic.c:283

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 522 of file relcache.c.

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

6783 {
6784  LWLockRelease(RelCacheInitLock);
6785 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6757 of file relcache.c.

6758 {
6759  char localinitfname[MAXPGPATH];
6760  char sharedinitfname[MAXPGPATH];
6761 
6762  if (DatabasePath)
6763  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6765  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6767 
6768  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6769 
6770  /*
6771  * The files might not be there if no backend has been started since the
6772  * last removal. But complain about failures other than ENOENT with
6773  * ERROR. Fortunately, it's not too late to abort the transaction if we
6774  * can't get rid of the would-be-obsolete init file.
6775  */
6776  if (DatabasePath)
6777  unlink_initfile(localinitfname, ERROR);
6778  unlink_initfile(sharedinitfname, ERROR);
6779 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6854

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

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6797 of file relcache.c.

6798 {
6799  const char *tblspcdir = PG_TBLSPC_DIR;
6800  DIR *dir;
6801  struct dirent *de;
6802  char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6803 
6804  snprintf(path, sizeof(path), "global/%s",
6806  unlink_initfile(path, LOG);
6807 
6808  /* Scan everything in the default tablespace */
6810 
6811  /* Scan the tablespace link directory to find non-default tablespaces */
6812  dir = AllocateDir(tblspcdir);
6813 
6814  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6815  {
6816  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6817  {
6818  /* Scan the tablespace dir for per-database dirs */
6819  snprintf(path, sizeof(path), "%s/%s/%s",
6820  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6822  }
6823  }
6824 
6825  FreeDir(dir);
6826 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2983
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2946
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6830
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#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, PG_TBLSPC_DIR, 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 6830 of file relcache.c.

6831 {
6832  DIR *dir;
6833  struct dirent *de;
6834  char initfilename[MAXPGPATH * 2];
6835 
6836  /* Scan the tablespace directory to find per-database directories */
6837  dir = AllocateDir(tblspcpath);
6838 
6839  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6840  {
6841  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6842  {
6843  /* Try to remove the init file in each database */
6844  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6845  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6846  unlink_initfile(initfilename, LOG);
6847  }
6848  }
6849 
6850  FreeDir(dir);
6851 }

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

3959 {
3960  HASHCTL ctl;
3961  int allocsize;
3962 
3963  /*
3964  * make sure cache memory context exists
3965  */
3966  if (!CacheMemoryContext)
3968 
3969  /*
3970  * create hashtable that indexes the relcache
3971  */
3972  ctl.keysize = sizeof(Oid);
3973  ctl.entrysize = sizeof(RelIdCacheEnt);
3974  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3975  &ctl, HASH_ELEM | HASH_BLOBS);
3976 
3977  /*
3978  * reserve enough in_progress_list slots for many cases
3979  */
3980  allocsize = 4;
3983  allocsize * sizeof(*in_progress_list));
3984  in_progress_list_maxlen = allocsize;
3985 
3986  /*
3987  * relation mapper needs to be initialized too
3988  */
3990 }
#define INITRELCACHESIZE
Definition: relcache.c:3955
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 4004 of file relcache.c.

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

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

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ereport, errcode(), errmsg_internal(), 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 2960 of file relcache.c.

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2904 of file relcache.c.

2905 {
2906  Relation relation;
2907 
2908  RelationIdCacheLookup(relationId, relation);
2909 
2910  if (PointerIsValid(relation))
2911  {
2913  RelationFlushRelation(relation);
2914  }
2915  else
2916  {
2917  int i;
2918 
2919  for (i = 0; i < in_progress_list_len; i++)
2920  if (in_progress_list[i].reloid == relationId)
2921  in_progress_list[i].invalidated = true;
2922  }
2923 }
#define PointerIsValid(pointer)
Definition: c.h:768
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2793

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)
static

Definition at line 2511 of file relcache.c.

2512 {
2514  Assert(!relation->rd_isnailed);
2515 
2516  /*
2517  * Relations created in the same transaction must never be removed, see
2518  * RelationFlushRelation.
2519  */
2523 
2524  /* first mark it as invalid */
2525  RelationInvalidateRelation(relation);
2526 
2527  /* Remove it from the hash table */
2528  RelationCacheDelete(relation);
2529 
2530  /* And release storage */
2531  RelationDestroyRelation(relation, false);
2532 }
#define RelationCacheDelete(RELATION)
Definition: relcache.c:243

References Assert, InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationCacheDelete, RelationDestroyRelation(), RelationHasReferenceCountZero, and RelationInvalidateRelation().

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2184 of file relcache.c.

2185 {
2186  /* Note: no locking manipulations needed */
2188 
2189  RelationCloseCleanup(relation);
2190 }
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2193

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

2194 {
2195  /*
2196  * If the relation is no longer open in this session, we can clean up any
2197  * stale partition descriptors it has. This is unlikely, so check to see
2198  * if there are child contexts before expending a call to mcxt.c.
2199  */
2200  if (RelationHasReferenceCountZero(relation))
2201  {
2202  if (relation->rd_pdcxt != NULL &&
2203  relation->rd_pdcxt->firstchild != NULL)
2205 
2206  if (relation->rd_pddcxt != NULL &&
2207  relation->rd_pddcxt->firstchild != NULL)
2209  }
2210 
2211 #ifdef RELCACHE_FORCE_RELEASE
2212  if (RelationHasReferenceCountZero(relation) &&
2213  relation->rd_createSubid == InvalidSubTransactionId &&
2215  RelationClearRelation(relation);
2216 #endif
2217 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:539
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 2164 of file relcache.c.

2165 {
2166  Assert(rel->rd_refcnt > 0);
2167  rel->rd_refcnt -= 1;
2170 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2137
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 2404 of file relcache.c.

2405 {
2407 
2408  /*
2409  * Make sure smgr and lower levels close the relation's files, if they
2410  * weren't closed already. (This was probably done by caller, but let's
2411  * just be real sure.)
2412  */
2413  RelationCloseSmgr(relation);
2414 
2415  /* break mutual link with stats entry */
2416  pgstat_unlink_relation(relation);
2417 
2418  /*
2419  * Free all the subsidiary data structures of the relcache entry, then the
2420  * entry itself.
2421  */
2422  if (relation->rd_rel)
2423  pfree(relation->rd_rel);
2424  /* can't use DecrTupleDescRefCount here */
2425  Assert(relation->rd_att->tdrefcount > 0);
2426  if (--relation->rd_att->tdrefcount == 0)
2427  {
2428  /*
2429  * If we Rebuilt a relcache entry during a transaction then its
2430  * possible we did that because the TupDesc changed as the result of
2431  * an ALTER TABLE that ran at less than AccessExclusiveLock. It's
2432  * possible someone copied that TupDesc, in which case the copy would
2433  * point to free'd memory. So if we rebuild an entry we keep the
2434  * TupDesc around until end of transaction, to be safe.
2435  */
2436  if (remember_tupdesc)
2438  else
2439  FreeTupleDesc(relation->rd_att);
2440  }
2441  FreeTriggerDesc(relation->trigdesc);
2442  list_free_deep(relation->rd_fkeylist);
2443  list_free(relation->rd_indexlist);
2444  list_free(relation->rd_statlist);
2445  bms_free(relation->rd_keyattr);
2446  bms_free(relation->rd_pkattr);
2447  bms_free(relation->rd_idattr);
2448  bms_free(relation->rd_hotblockingattr);
2449  bms_free(relation->rd_summarizedattr);
2450  if (relation->rd_pubdesc)
2451  pfree(relation->rd_pubdesc);
2452  if (relation->rd_options)
2453  pfree(relation->rd_options);
2454  if (relation->rd_indextuple)
2455  pfree(relation->rd_indextuple);
2456  if (relation->rd_amcache)
2457  pfree(relation->rd_amcache);
2458  if (relation->rd_fdwroutine)
2459  pfree(relation->rd_fdwroutine);
2460  if (relation->rd_indexcxt)
2461  MemoryContextDelete(relation->rd_indexcxt);
2462  if (relation->rd_rulescxt)
2463  MemoryContextDelete(relation->rd_rulescxt);
2464  if (relation->rd_rsdesc)
2465  MemoryContextDelete(relation->rd_rsdesc->rscxt);
2466  if (relation->rd_partkeycxt)
2468  if (relation->rd_pdcxt)
2469  MemoryContextDelete(relation->rd_pdcxt);
2470  if (relation->rd_pddcxt)
2471  MemoryContextDelete(relation->rd_pddcxt);
2472  if (relation->rd_partcheckcxt)
2474  pfree(relation);
2475 }
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:3070
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:2141

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

Referenced by RelationBuildDesc(), RelationClearRelation(), and RelationRebuildRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2793 of file relcache.c.

2794 {
2795  if (relation->rd_createSubid != InvalidSubTransactionId ||
2797  {
2798  /*
2799  * New relcache entries are always rebuilt, not flushed; else we'd
2800  * forget the "new" status of the relation. Ditto for the
2801  * new-relfilenumber status.
2802  */
2804  {
2805  /*
2806  * The rel could have zero refcnt here, so temporarily increment
2807  * the refcnt to ensure it's safe to rebuild it. We can assume
2808  * that the current transaction has some lock on the rel already.
2809  */
2811  RelationRebuildRelation(relation);
2813  }
2814  else
2815  RelationInvalidateRelation(relation);
2816  }
2817  else
2818  {
2819  /*
2820  * Pre-existing rels can be dropped from the relcache if not open.
2821  *
2822  * If the entry is in use, rebuild it if possible. If we're not
2823  * inside a valid transaction, we can't do any catalog access so it's
2824  * not possible to rebuild yet. Just mark it as invalid in that case,
2825  * so that the rebuild will occur when the entry is next opened.
2826  *
2827  * Note: it's possible that we come here during subtransaction abort,
2828  * and the reason for wanting to rebuild is that the rel is open in
2829  * the outer transaction. In that case it might seem unsafe to not
2830  * rebuild immediately, since whatever code has the rel already open
2831  * will keep on using the relcache entry as-is. However, in such a
2832  * case the outer transaction should be holding a lock that's
2833  * sufficient to prevent any significant change in the rel's schema,
2834  * so the existing entry contents should be good enough for its
2835  * purposes; at worst we might be behind on statistics updates or the
2836  * like. (See also CheckTableNotInUse() and its callers.)
2837  */
2838  if (RelationHasReferenceCountZero(relation))
2839  RelationClearRelation(relation);
2840  else if (!IsTransactionState())
2841  RelationInvalidateRelation(relation);
2842  else if (relation->rd_isnailed && relation->rd_refcnt == 1)
2843  {
2844  /*
2845  * A nailed relation with refcnt == 1 is unused. We cannot clear
2846  * it, but there's also no need no need to rebuild it immediately.
2847  */
2848  RelationInvalidateRelation(relation);
2849  }
2850  else
2851  RelationRebuildRelation(relation);
2852  }
2853 }

References InvalidSubTransactionId, IsTransactionState(), RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationClearRelation(), RelationDecrementReferenceCount(), RelationHasReferenceCountZero, RelationIncrementReferenceCount(), RelationInvalidateRelation(), and RelationRebuildRelation().

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2859 of file relcache.c.

2860 {
2861  Relation relation;
2862 
2863  RelationIdCacheLookup(rid, relation);
2864 
2865  if (!PointerIsValid(relation))
2866  return; /* not in cache, nothing to do */
2867 
2868  if (!RelationHasReferenceCountZero(relation))
2869  elog(ERROR, "relation %u is still open", rid);
2870 
2872  if (relation->rd_createSubid != InvalidSubTransactionId ||
2874  {
2875  /*
2876  * In the event of subtransaction rollback, we must not forget
2877  * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2878  * destroying it right away. (If we're in a top transaction, we could
2879  * opt to destroy the entry.)
2880  */
2882  RelationInvalidateRelation(relation);
2883  }
2884  else
2885  RelationClearRelation(relation);
2886 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5087 of file relcache.c.

5088 {
5089  List *result;
5090  Datum exprsDatum;
5091  bool isnull;
5092  char *exprsString;
5093  List *rawExprs;
5094  ListCell *lc;
5095 
5096  /* Quick exit if there is nothing to do. */
5097  if (relation->rd_indextuple == NULL ||
5098  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5099  return NIL;
5100 
5101  /* Extract raw node tree(s) from index tuple. */
5102  exprsDatum = heap_getattr(relation->rd_indextuple,
5103  Anum_pg_index_indexprs,
5105  &isnull);
5106  Assert(!isnull);
5107  exprsString = TextDatumGetCString(exprsDatum);
5108  rawExprs = (List *) stringToNode(exprsString);
5109  pfree(exprsString);
5110 
5111  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5112  result = NIL;
5113  foreach(lc, rawExprs)
5114  {
5115  Node *rawExpr = (Node *) lfirst(lc);
5116 
5117  result = lappend(result,
5118  makeConst(exprType(rawExpr),
5119  exprTypmod(rawExpr),
5120  exprCollation(rawExpr),
5121  1,
5122  (Datum) 0,
5123  true,
5124  true));
5125  }
5126 
5127  return result;
5128 }
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:4429

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

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

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

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4658 of file relcache.c.

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

5508 {
5509  Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5510  Relation indexDesc;
5511  int i;
5512  Oid replidindex;
5513  MemoryContext oldcxt;
5514 
5515  /* Quick exit if we already computed the result */
5516  if (relation->rd_idattr != NULL)
5517  return bms_copy(relation->rd_idattr);
5518 
5519  /* Fast path if definitely no indexes */
5520  if (!RelationGetForm(relation)->relhasindex)
5521  return NULL;
5522 
5523  /* Historic snapshot must be set. */
5525 
5526  replidindex = RelationGetReplicaIndex(relation);
5527 
5528  /* Fall out if there is no replica identity index */
5529  if (!OidIsValid(replidindex))
5530  return NULL;
5531 
5532  /* Look up the description for the replica identity index */
5533  indexDesc = RelationIdGetRelation(replidindex);
5534 
5535  if (!RelationIsValid(indexDesc))
5536  elog(ERROR, "could not open relation with OID %u",
5537  relation->rd_replidindex);
5538 
5539  /* Add referenced attributes to idindexattrs */
5540  for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5541  {
5542  int attrnum = indexDesc->rd_index->indkey.values[i];
5543 
5544  /*
5545  * We don't include non-key columns into idindexattrs bitmaps. See
5546  * RelationGetIndexAttrBitmap.
5547  */
5548  if (attrnum != 0)
5549  {
5550  if (i < indexDesc->rd_index->indnkeyatts)
5551  idindexattrs = bms_add_member(idindexattrs,
5553  }
5554  }
5555 
5556  RelationClose(indexDesc);
5557 
5558  /* Don't leak the old values of these bitmaps, if any */
5559  bms_free(relation->rd_idattr);
5560  relation->rd_idattr = NULL;
5561 
5562  /* Now save copy of the bitmap in the relcache entry */
5564  relation->rd_idattr = bms_copy(idindexattrs);
5565  MemoryContextSwitchTo(oldcxt);
5566 
5567  /* We return our original working copy for caller to play with */
5568  return idindexattrs;
5569 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationIsValid(relation)
Definition: rel.h:478
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:5003
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2062
void RelationClose(Relation relation)
Definition: relcache.c:2184
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
#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 5887 of file relcache.c.

5888 {
5889  MemoryContext oldcxt;
5890  bytea **opts = relation->rd_opcoptions;
5891  Oid relid = RelationGetRelid(relation);
5892  int natts = RelationGetNumberOfAttributes(relation); /* XXX
5893  * IndexRelationGetNumberOfKeyAttributes */
5894  int i;
5895 
5896  /* Try to copy cached options. */
5897  if (opts)
5898  return copy ? CopyIndexAttOptions(opts, natts) : opts;
5899 
5900  /* Get and parse opclass options. */
5901  opts = palloc0(sizeof(*opts) * natts);
5902 
5903  for (i = 0; i < natts; i++)
5904  {
5905  if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5906  {
5907  Datum attoptions = get_attoptions(relid, i + 1);
5908 
5909  opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5910 
5911  if (attoptions != (Datum) 0)
5912  pfree(DatumGetPointer(attoptions));
5913  }
5914  }
5915 
5916  /* Copy parsed options to the cache. */
5917  oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5918  relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5919  MemoryContextSwitchTo(oldcxt);
5920 
5921  if (copy)
5922  return opts;
5923 
5924  for (i = 0; i < natts; i++)
5925  {
5926  if (opts[i])
5927  pfree(opts[i]);
5928  }
5929 
5930  pfree(opts);
5931 
5932  return relation->rd_opcoptions;
5933 }
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:998
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5867

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

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

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 dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), pub_collist_contains_invalid_column(), and pub_rf_contains_invalid_column().

◆ RelationGetIndexExpressions()

List* RelationGetIndexExpressions ( Relation  relation)

Definition at line 5028 of file relcache.c.

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

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(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetIndexList()

List* RelationGetIndexList ( Relation  relation)

Definition at line 4767 of file relcache.c.

4768 {
4769  Relation indrel;
4770  SysScanDesc indscan;
4771  ScanKeyData skey;
4772  HeapTuple htup;
4773  List *result;
4774  List *oldlist;
4775  char replident = relation->rd_rel->relreplident;
4776  Oid pkeyIndex = InvalidOid;
4777  Oid candidateIndex = InvalidOid;
4778  bool pkdeferrable = false;
4779  MemoryContext oldcxt;
4780 
4781  /* Quick exit if we already computed the list. */
4782  if (relation->rd_indexvalid)
4783  return list_copy(relation->rd_indexlist);
4784 
4785  /*
4786  * We build the list we intend to return (in the caller's context) while
4787  * doing the scan. After successfully completing the scan, we copy that
4788  * list into the relcache entry. This avoids cache-context memory leakage
4789  * if we get some sort of error partway through.
4790  */
4791  result = NIL;
4792 
4793  /* Prepare to scan pg_index for entries having indrelid = this rel. */
4794  ScanKeyInit(&skey,
4795  Anum_pg_index_indrelid,
4796  BTEqualStrategyNumber, F_OIDEQ,
4797  ObjectIdGetDatum(RelationGetRelid(relation)));
4798 
4799  indrel = table_open(IndexRelationId, AccessShareLock);
4800  indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4801  NULL, 1, &skey);
4802 
4803  while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4804  {
4806 
4807  /*
4808  * Ignore any indexes that are currently being dropped. This will
4809  * prevent them from being searched, inserted into, or considered in
4810  * HOT-safety decisions. It's unsafe to touch such an index at all
4811  * since its catalog entries could disappear at any instant.
4812  */
4813  if (!index->indislive)
4814  continue;
4815 
4816  /* add index's OID to result list */
4817  result = lappend_oid(result, index->indexrelid);
4818 
4819  /*
4820  * Non-unique or predicate indexes aren't interesting for either oid
4821  * indexes or replication identity indexes, so don't check them.
4822  * Deferred ones are not useful for replication identity either; but
4823  * we do include them if they are PKs.
4824  */
4825  if (!index->indisunique ||
4826  !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4827  continue;
4828 
4829  /*
4830  * Remember primary key index, if any. For regular tables we do this
4831  * only if the index is valid; but for partitioned tables, then we do
4832  * it even if it's invalid.
4833  *
4834  * The reason for returning invalid primary keys for partitioned
4835  * tables is that we need it to prevent drop of not-null constraints
4836  * that may underlie such a primary key, which is only a problem for
4837  * partitioned tables.
4838  */
4839  if (index->indisprimary &&
4840  (index->indisvalid ||
4841  relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4842  {
4843  pkeyIndex = index->indexrelid;
4844  pkdeferrable = !index->indimmediate;
4845  }
4846 
4847  if (!index->indimmediate)
4848  continue;
4849 
4850  if (!index->indisvalid)
4851  continue;
4852 
4853  /* remember explicitly chosen replica index */
4854  if (index->indisreplident)
4855  candidateIndex = index->indexrelid;
4856  }
4857 
4858  systable_endscan(indscan);
4859 
4860  table_close(indrel, AccessShareLock);
4861 
4862  /* Sort the result list into OID order, per API spec. */
4863  list_sort(result, list_oid_cmp);
4864 
4865  /* Now save a copy of the completed list in the relcache entry. */
4867  oldlist = relation->rd_indexlist;
4868  relation->rd_indexlist = list_copy(result);
4869  relation->rd_pkindex = pkeyIndex;
4870  relation->rd_ispkdeferrable = pkdeferrable;
4871  if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4872  relation->rd_replidindex = pkeyIndex;
4873  else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4874  relation->rd_replidindex = candidateIndex;
4875  else
4876  relation->rd_replidindex = InvalidOid;
4877  relation->rd_indexvalid = true;
4878  MemoryContextSwitchTo(oldcxt);
4879 
4880  /* Don't leak the old list, if there is one */
4881  list_free(oldlist);
4882 
4883  return result;
4884 }
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(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), RefreshMatViewByOid(), 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 5141 of file relcache.c.

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

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation,
bool  deferrable_ok 
)

Definition at line 4978 of file relcache.c.

4979 {
4980  List *ilist;
4981 
4982  if (!relation->rd_indexvalid)
4983  {
4984  /* RelationGetIndexList does the heavy lifting. */
4985  ilist = RelationGetIndexList(relation);
4986  list_free(ilist);
4987  Assert(relation->rd_indexvalid);
4988  }
4989 
4990  if (deferrable_ok)
4991  return relation->rd_pkindex;
4992  else if (relation->rd_ispkdeferrable)
4993  return InvalidOid;
4994  return relation->rd_pkindex;
4995 }

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

Referenced by dropconstraint_internal(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5003 of file relcache.c.

5004 {
5005  List *ilist;
5006 
5007  if (!relation->rd_indexvalid)
5008  {
5009  /* RelationGetIndexList does the heavy lifting. */
5010  ilist = RelationGetIndexList(relation);
5011  list_free(ilist);
5012  Assert(relation->rd_indexvalid);
5013  }
5014 
5015  return relation->rd_replidindex;
5016 }

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

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

◆ 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  {
2088 
2089  /*
2090  * Normally entries need to be valid here, but before the relcache
2091  * has been initialized, not enough infrastructure exists to
2092  * perform pg_class lookups. The structure of such entries doesn't
2093  * change, but we still want to update the rd_rel entry. So
2094  * rd_isvalid = false is left in place for a later lookup.
2095  */
2096  Assert(rd->rd_isvalid ||
2098  }
2099  return rd;
2100  }
2101 
2102  /*
2103  * no reldesc in the cache, so have RelationBuildDesc() build one and add
2104  * it.
2105  */
2106  rd = RelationBuildDesc(relationId, true);
2107  if (RelationIsValid(rd))
2109  return rd;
2110 }

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

Referenced by check_and_init_gencol(), 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 6717 of file relcache.c.

6718 {
6719  if (relationId == SharedSecLabelRelationId ||
6720  relationId == TriggerRelidNameIndexId ||
6721  relationId == DatabaseNameIndexId ||
6722  relationId == SharedSecLabelObjectIndexId)
6723  {
6724  /*
6725  * If this Assert fails, we don't need the applicable special case
6726  * anymore.
6727  */
6728  Assert(!RelationSupportsSysCache(relationId));
6729  return true;
6730  }
6731  return RelationSupportsSysCache(relationId);
6732 }
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:765

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:517
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1596
Definition: c.h:720
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:727
Definition: c.h:731

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:664
Oid MyDatabaseTableSpace
Definition: globals.c:95
Oid MyDatabaseId
Definition: globals.c:93
#define IsParallelWorker()
Definition: parallel.h:60
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool RelFileLocatorSkippingWAL(RelFileLocator rlocator)
Definition: storage.c:532
RelFileNumber relNumber
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

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

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

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

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

◆ RelationInvalidateRelation()

static void RelationInvalidateRelation ( Relation  relation)
static

Definition at line 2483 of file relcache.c.

2484 {
2485  /*
2486  * Make sure smgr and lower levels close the relation's files, if they
2487  * weren't closed already. If the relation is not getting deleted, the
2488  * next smgr access should reopen the files automatically. This ensures
2489  * that the low-level file access state is updated after, say, a vacuum
2490  * truncation.
2491  */
2492  RelationCloseSmgr(relation);
2493 
2494  /* Free AM cached data, if any */
2495  if (relation->rd_amcache)
2496  pfree(relation->rd_amcache);
2497  relation->rd_amcache = NULL;
2498 
2499  relation->rd_isvalid = false;
2500 }

References pfree(), RelationData::rd_amcache, RelationData::rd_isvalid, and RelationCloseSmgr().

Referenced by RelationCacheInvalidate(), RelationClearRelation(), RelationFlushRelation(), RelationForgetRelation(), and RelationRebuildRelation().

◆ RelationParseRelOptions()

static void RelationParseRelOptions ( Relation  relation,
HeapTuple  tuple 
)
static

Definition at line 465 of file relcache.c.

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

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

◆ RelationRebuildRelation()

static void RelationRebuildRelation ( Relation  relation)
static

Definition at line 2550 of file relcache.c.

2551 {
2553  /* rebuilding requires access to the catalogs */
2555  /* there is no reason to ever rebuild a dropped relation */
2557 
2558  /* Close and mark it as invalid until we've finished the rebuild */
2559  RelationInvalidateRelation(relation);
2560 
2561  /*
2562  * Indexes only have a limited number of possible schema changes, and we
2563  * don't want to use the full-blown procedure because it's a headache for
2564  * indexes that reload itself depends on.
2565  *
2566  * As an exception, use the full procedure if the index access info hasn't
2567  * been initialized yet. Index creation relies on that: it first builds
2568  * the relcache entry with RelationBuildLocalRelation(), creates the
2569  * pg_index tuple only after that, and then relies on
2570  * CommandCounterIncrement to load the pg_index contents.
2571  */
2572  if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2573  relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2574  relation->rd_indexcxt != NULL)
2575  {
2576  RelationReloadIndexInfo(relation);
2577  return;
2578  }
2579  /* Nailed relations are handled separately. */
2580  else if (relation->rd_isnailed)
2581  {
2582  RelationReloadNailed(relation);
2583  return;
2584  }
2585  else
2586  {
2587  /*
2588  * Our strategy for rebuilding an open relcache entry is to build a
2589  * new entry from scratch, swap its contents with the old entry, and
2590  * finally delete the new entry (along with any infrastructure swapped
2591  * over from the old entry). This is to avoid trouble in case an
2592  * error causes us to lose control partway through. The old entry
2593  * will still be marked !rd_isvalid, so we'll try to rebuild it again
2594  * on next access. Meanwhile it's not any less valid than it was
2595  * before, so any code that might expect to continue accessing it
2596  * isn't hurt by the rebuild failure. (Consider for example a
2597  * subtransaction that ALTERs a table and then gets canceled partway
2598  * through the cache entry rebuild. The outer transaction should
2599  * still see the not-modified cache entry as valid.) The worst
2600  * consequence of an error is leaking the necessarily-unreferenced new
2601  * entry, and this shouldn't happen often enough for that to be a big
2602  * problem.
2603  *
2604  * When rebuilding an open relcache entry, we must preserve ref count,
2605  * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2606  * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2607  * and partition descriptor substructures in place, because various
2608  * places assume that these structures won't move while they are
2609  * working with an open relcache entry. (Note: the refcount
2610  * mechanism for tupledescs might someday allow us to remove this hack
2611  * for the tupledesc.)
2612  *
2613  * Note that this process does not touch CurrentResourceOwner; which
2614  * is good because whatever ref counts the entry may have do not
2615  * necessarily belong to that resource owner.
2616  */
2617  Relation newrel;
2618  Oid save_relid = RelationGetRelid(relation);
2619  bool keep_tupdesc;
2620  bool keep_rules;
2621  bool keep_policies;
2622  bool keep_partkey;
2623 
2624  /* Build temporary entry, but don't link it into hashtable */
2625  newrel = RelationBuildDesc(save_relid, false);
2626 
2627  /*
2628  * Between here and the end of the swap, don't add code that does or
2629  * reasonably could read system catalogs. That range must be free
2630  * from invalidation processing. See RelationBuildDesc() manipulation
2631  * of in_progress_list.
2632  */
2633 
2634  if (newrel == NULL)
2635  {
2636  /*
2637  * We can validly get here, if we're using a historic snapshot in
2638  * which a relation, accessed from outside logical decoding, is
2639  * still invisible. In that case it's fine to just mark the
2640  * relation as invalid and return - it'll fully get reloaded by
2641  * the cache reset at the end of logical decoding (or at the next
2642  * access). During normal processing we don't want to ignore this
2643  * case as it shouldn't happen there, as explained below.
2644  */
2645  if (HistoricSnapshotActive())
2646  return;
2647 
2648  /*
2649  * This shouldn't happen as dropping a relation is intended to be
2650  * impossible if still referenced (cf. CheckTableNotInUse()). But
2651  * if we get here anyway, we can't just delete the relcache entry,
2652  * as it possibly could get accessed later (as e.g. the error
2653  * might get trapped and handled via a subtransaction rollback).
2654  */
2655  elog(ERROR, "relation %u deleted while still in use", save_relid);
2656  }
2657 
2658  /*
2659  * If we were to, again, have cases of the relkind of a relcache entry
2660  * changing, we would need to ensure that pgstats does not get
2661  * confused.
2662  */
2663  Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind);
2664 
2665  keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2666  keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2667  keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2668  /* partkey is immutable once set up, so we can always keep it */
2669  keep_partkey = (relation->rd_partkey != NULL);
2670 
2671  /*
2672  * Perform swapping of the relcache entry contents. Within this
2673  * process the old entry is momentarily invalid, so there *must* be no
2674  * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2675  * all-in-line code for safety.
2676  *
2677  * Since the vast majority of fields should be swapped, our method is
2678  * to swap the whole structures and then re-swap those few fields we
2679  * didn't want swapped.
2680  */
2681 #define SWAPFIELD(fldtype, fldname) \
2682  do { \
2683  fldtype _tmp = newrel->fldname; \
2684  newrel->fldname = relation->fldname; \
2685  relation->fldname = _tmp; \
2686  } while (0)
2687 
2688  /* swap all Relation struct fields */
2689  {
2690  RelationData tmpstruct;
2691 
2692  memcpy(&tmpstruct, newrel, sizeof(RelationData));
2693  memcpy(newrel, relation, sizeof(RelationData));
2694  memcpy(relation, &tmpstruct, sizeof(RelationData));
2695  }
2696 
2697  /* rd_smgr must not be swapped, due to back-links from smgr level */
2698  SWAPFIELD(SMgrRelation, rd_smgr);
2699  /* rd_refcnt must be preserved */
2700  SWAPFIELD(int, rd_refcnt);
2701  /* isnailed shouldn't change */
2702  Assert(newrel->rd_isnailed == relation->rd_isnailed);
2703  /* creation sub-XIDs must be preserved */
2704  SWAPFIELD(SubTransactionId, rd_createSubid);
2705  SWAPFIELD(SubTransactionId, rd_newRelfilelocatorSubid);
2706  SWAPFIELD(SubTransactionId, rd_firstRelfilelocatorSubid);
2707  SWAPFIELD(SubTransactionId, rd_droppedSubid);
2708  /* un-swap rd_rel pointers, swap contents instead */
2709  SWAPFIELD(Form_pg_class, rd_rel);
2710  /* ... but actually, we don't have to update newrel->rd_rel */
2711  memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2712  /* preserve old tupledesc, rules, policies if no logical change */
2713  if (keep_tupdesc)
2714  SWAPFIELD(TupleDesc, rd_att);
2715  if (keep_rules)
2716  {
2717  SWAPFIELD(RuleLock *, rd_rules);
2718  SWAPFIELD(MemoryContext, rd_rulescxt);
2719  }
2720  if (keep_policies)
2721  SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2722  /* toast OID override must be preserved */
2723  SWAPFIELD(Oid, rd_toastoid);
2724  /* pgstat_info / enabled must be preserved */
2725  SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2726  SWAPFIELD(bool, pgstat_enabled);
2727  /* preserve old partition key if we have one */
2728  if (keep_partkey)
2729  {
2730  SWAPFIELD(PartitionKey, rd_partkey);
2731  SWAPFIELD(MemoryContext, rd_partkeycxt);
2732  }
2733  if (newrel->rd_pdcxt != NULL || newrel->rd_pddcxt != NULL)
2734  {
2735  /*
2736  * We are rebuilding a partitioned relation with a non-zero
2737  * reference count, so we must keep the old partition descriptor
2738  * around, in case there's a PartitionDirectory with a pointer to
2739  * it. This means we can't free the old rd_pdcxt yet. (This is
2740  * necessary because RelationGetPartitionDesc hands out direct
2741  * pointers to the relcache's data structure, unlike our usual
2742  * practice which is to hand out copies. We'd have the same
2743  * problem with rd_partkey, except that we always preserve that
2744  * once created.)
2745  *
2746  * To ensure that it's not leaked completely, re-attach it to the
2747  * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2748  * in the unlikely event that there is one already. (Compare hack
2749  * in RelationBuildPartitionDesc.) RelationClose will clean up
2750  * any such contexts once the reference count reaches zero.
2751  *
2752  * In the case where the reference count is zero, this code is not
2753  * reached, which should be OK because in that case there should
2754  * be no PartitionDirectory with a pointer to the old entry.
2755  *
2756  * Note that newrel and relation have already been swapped, so the
2757  * "old" partition descriptor is actually the one hanging off of
2758  * newrel.
2759  */
2760  relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2761  relation->rd_partdesc_nodetached = NULL;
2763  if (relation->rd_pdcxt != NULL) /* probably never happens */
2764  MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2765  else
2766  relation->rd_pdcxt = newrel->rd_pdcxt;
2767  if (relation->rd_pddcxt != NULL)
2768  MemoryContextSetParent(newrel->rd_pddcxt, relation->rd_pddcxt);
2769  else
2770  relation->rd_pddcxt = newrel->rd_pddcxt;
2771  /* drop newrel's pointers so we don't destroy it below */
2772  newrel->rd_partdesc = NULL;
2773  newrel->rd_partdesc_nodetached = NULL;
2775  newrel->rd_pdcxt = NULL;
2776  newrel->rd_pddcxt = NULL;
2777  }
2778 
2779 #undef SWAPFIELD
2780 
2781  /* And now we can throw away the temporary entry */
2782  RelationDestroyRelation(newrel, !keep_tupdesc);
2783  }
2784 }
uint32 SubTransactionId
Definition: c.h:661
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
Definition: relcache.c:907
static void RelationReloadNailed(Relation relation)
Definition: relcache.c:2349
static bool equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
Definition: relcache.c:998
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2240
#define SWAPFIELD(fldtype, fldname)
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:419

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_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_partkey, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationBuildDesc(), RelationDestroyRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationInvalidateRelation(), RelationReloadIndexInfo(), RelationReloadNailed(), and SWAPFIELD.

Referenced by RelationCacheInvalidate(), RelationFlushRelation(), and RelationIdGetRelation().

◆ RelationReloadIndexInfo()

static void RelationReloadIndexInfo ( Relation  relation)
static

Definition at line 2240 of file relcache.c.

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

Referenced by RelationRebuildRelation().

◆ RelationReloadNailed()

static void RelationReloadNailed ( Relation  relation)
static

Definition at line 2349 of file relcache.c.

2350 {
2351  /* Should be called only for invalidated, nailed relations */
2352  Assert(!relation->rd_isvalid);
2353  Assert(relation->rd_isnailed);
2354  /* nailed indexes are handled by RelationReloadIndexInfo() */
2355  Assert(relation->rd_rel->relkind == RELKIND_RELATION);
2356  /* can only reread catalog contents in a transaction */
2358 
2359  /*
2360  * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2361  * mapping changed.
2362  */
2363  RelationInitPhysicalAddr(relation);
2364 
2365  /*
2366  * Reload a non-index entry. We can't easily do so if relcaches aren't
2367  * yet built, but that's fine because at that stage the attributes that
2368  * need to be current (like relfrozenxid) aren't yet accessed. To ensure
2369  * the entry will later be revalidated, we leave it in invalid state, but
2370  * allow use (cf. RelationIdGetRelation()).
2371  */
2373  {
2374  HeapTuple pg_class_tuple;
2375  Form_pg_class relp;
2376 
2377  /*
2378  * NB: Mark the entry as valid before starting to scan, to avoid
2379  * self-recursion when re-building pg_class.
2380  */
2381  relation->rd_isvalid = true;
2382 
2383  pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
2384  true, false);
2385  relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2386  memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2387  heap_freetuple(pg_class_tuple);
2388 
2389  /*
2390  * Again mark as valid, to protect against concurrently arriving
2391  * invalidations.
2392  */
2393  relation->rd_isvalid = true;
2394  }
2395 }

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

Referenced by RelationRebuildRelation().

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3730 of file relcache.c.

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

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, InplaceUpdateTupleLock, 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, SearchSysCacheLockedCopy1(), smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), table_relation_set_new_filelocator(), and UnlockTuple().

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

◆ RememberToFreeTupleDescAtEOX()

static void RememberToFreeTupleDescAtEOX ( TupleDesc  td)
static

Definition at line 3070 of file relcache.c.

3071 {
3072  if (EOXactTupleDescArray == NULL)
3073  {
3074  MemoryContext oldcxt;
3075 
3077 
3078  EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3081  MemoryContextSwitchTo(oldcxt);
3082  }
3084  {
3085  int32 newlen = EOXactTupleDescArrayLen * 2;
3086 
3088 
3090  newlen * sizeof(TupleDesc));
3091  EOXactTupleDescArrayLen = newlen;
3092  }
3093 
3095 }
signed int int32
Definition: c.h:508

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

2138 {
2140 }
static const ResourceOwnerDesc relref_resowner_desc
Definition: relcache.c:2121
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 2132 of file relcache.c.

2133 {
2135 }
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 6871 of file relcache.c.

6872 {
6874 
6875  return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6876 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

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

◆ ResOwnerReleaseRelation()

static void ResOwnerReleaseRelation ( Datum  res)
static

Definition at line 6879 of file relcache.c.

6880 {
6882 
6883  /*
6884  * This reference has already been removed from the resource owner, so
6885  * just decrement reference count without calling
6886  * ResourceOwnerForgetRelationRef.
6887  */
6888  Assert(rel->rd_refcnt > 0);
6889  rel->rd_refcnt -= 1;
6890 
6892 }

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

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

6855 {
6856  if (unlink(initfilename) < 0)
6857  {
6858  /* It might not be there, but log any error other than ENOENT */
6859  if (errno != ENOENT)
6860  ereport(elevel,
6862  errmsg("could not remove cache file \"%s\": %m",
6863  initfilename)));
6864  }
6865 }
int errcode_for_file_access(void)
Definition: elog.c:876

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

6695 {
6696  if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6697  ereport(FATAL,
6699  errmsg_internal("could not write init file: %m"));
6700  if (len > 0 && fwrite(data, 1, len, fp) != len)
6701  ereport(FATAL,
6703  errmsg_internal("could not write init file: %m"));
6704 }
const void * data

References data, ereport, errcode_for_file_access(), errmsg_internal(), 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 6482 of file relcache.c.

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

References AcceptInvalidationMessages(), AllocateFile(), IndexAmRoutine::amsupport, Assert, ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, DatabasePath, ereport, errcode_for_file_access(), errdetail(), errmsg(), errmsg_internal(), 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:6879
static char * ResOwnerPrintRelCache(Datum res)
Definition: relcache.c:6871
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
#define RELEASE_PRIO_RELCACHE_REFS
Definition: resowner.h:64

Definition at line 2121 of file relcache.c.

Referenced by ResourceOwnerForgetRelationRef(), and ResourceOwnerRememberRelationRef().