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

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

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

Typedefs

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

Functions

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

Variables

static const FormData_pg_attribute Desc_pg_class [Natts_pg_class] = {Schema_pg_class}
 
static const FormData_pg_attribute Desc_pg_attribute [Natts_pg_attribute] = {Schema_pg_attribute}
 
static const FormData_pg_attribute Desc_pg_proc [Natts_pg_proc] = {Schema_pg_proc}
 
static const FormData_pg_attribute Desc_pg_type [Natts_pg_type] = {Schema_pg_type}
 
static const FormData_pg_attribute Desc_pg_database [Natts_pg_database] = {Schema_pg_database}
 
static const FormData_pg_attribute Desc_pg_authid [Natts_pg_authid] = {Schema_pg_authid}
 
static const FormData_pg_attribute Desc_pg_auth_members [Natts_pg_auth_members] = {Schema_pg_auth_members}
 
static const FormData_pg_attribute Desc_pg_index [Natts_pg_index] = {Schema_pg_index}
 
static const FormData_pg_attribute Desc_pg_shseclabel [Natts_pg_shseclabel] = {Schema_pg_shseclabel}
 
static const FormData_pg_attribute Desc_pg_subscription [Natts_pg_subscription] = {Schema_pg_subscription}
 
static HTABRelationIdCache
 
bool criticalRelcachesBuilt = false
 
bool criticalSharedRelcachesBuilt = false
 
static long relcacheInvalsReceived = 0L
 
static InProgressEntin_progress_list
 
static int in_progress_list_len
 
static int in_progress_list_maxlen
 
static Oid eoxact_list [MAX_EOXACT_LIST]
 
static int eoxact_list_len = 0
 
static bool eoxact_list_overflowed = false
 
static TupleDescEOXactTupleDescArray
 
static int NextEOXactTupleDescNum = 0
 
static int EOXactTupleDescArrayLen = 0
 
static HTABOpClassCache = NULL
 
static const ResourceOwnerDesc relref_resowner_desc
 

Macro Definition Documentation

◆ EOXactListAdd

#define EOXactListAdd (   rel)
Value:
do { \
eoxact_list[eoxact_list_len++] = (rel)->rd_id; \
else \
eoxact_list_overflowed = true; \
} while (0)
#define MAX_EOXACT_LIST
Definition: relcache.c:184
static int eoxact_list_len
Definition: relcache.c:186

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3989 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 409 of file relcache.c.

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

3444 {
3445  /*
3446  * Is it a relation created in the current subtransaction?
3447  *
3448  * During subcommit, mark it as belonging to the parent, instead, as long
3449  * as it has not been dropped. Otherwise simply delete the relcache entry.
3450  * --- it isn't interesting any longer.
3451  */
3452  if (relation->rd_createSubid == mySubid)
3453  {
3454  /*
3455  * Valid rd_droppedSubid means the corresponding relation is dropped
3456  * but the relcache entry is preserved for at-commit pending sync. We
3457  * need to drop it explicitly here not to make the entry orphan.
3458  */
3459  Assert(relation->rd_droppedSubid == mySubid ||
3461  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3462  relation->rd_createSubid = parentSubid;
3463  else if (RelationHasReferenceCountZero(relation))
3464  {
3465  /* allow the entry to be removed */
3470  RelationClearRelation(relation, false);
3471  return;
3472  }
3473  else
3474  {
3475  /*
3476  * Hmm, somewhere there's a (leaked?) reference to the relation.
3477  * We daren't remove the entry for fear of dereferencing a
3478  * dangling pointer later. Bleat, and transfer it to the parent
3479  * subtransaction so we can try again later. This must be just a
3480  * WARNING to avoid error-during-error-recovery loops.
3481  */
3482  relation->rd_createSubid = parentSubid;
3483  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3484  RelationGetRelationName(relation));
3485  }
3486  }
3487 
3488  /*
3489  * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3490  * or drop record.
3491  */
3492  if (relation->rd_newRelfilelocatorSubid == mySubid)
3493  {
3494  if (isCommit)
3495  relation->rd_newRelfilelocatorSubid = parentSubid;
3496  else
3498  }
3499 
3500  if (relation->rd_firstRelfilelocatorSubid == mySubid)
3501  {
3502  if (isCommit)
3503  relation->rd_firstRelfilelocatorSubid = parentSubid;
3504  else
3506  }
3507 
3508  if (relation->rd_droppedSubid == mySubid)
3509  {
3510  if (isCommit)
3511  relation->rd_droppedSubid = parentSubid;
3512  else
3514  }
3515 }
#define InvalidSubTransactionId
Definition: c.h:658
#define Assert(condition)
Definition: c.h:858
#define elog(elevel,...)
Definition: elog.h:224
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2559
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 3387 of file relcache.c.

3389 {
3390  HASH_SEQ_STATUS status;
3391  RelIdCacheEnt *idhentry;
3392  int i;
3393 
3394  /*
3395  * Forget in_progress_list. This is relevant when we're aborting due to
3396  * an error during RelationBuildDesc(). We don't commit subtransactions
3397  * during RelationBuildDesc().
3398  */
3399  Assert(in_progress_list_len == 0 || !isCommit);
3401 
3402  /*
3403  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3404  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3405  * logic as in AtEOXact_RelationCache.
3406  */
3408  {
3409  hash_seq_init(&status, RelationIdCache);
3410  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3411  {
3412  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3413  mySubid, parentSubid);
3414  }
3415  }
3416  else
3417  {
3418  for (i = 0; i < eoxact_list_len; i++)
3419  {
3420  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3421  &eoxact_list[i],
3422  HASH_FIND,
3423  NULL);
3424  if (idhentry != NULL)
3425  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3426  mySubid, parentSubid);
3427  }
3428  }
3429 
3430  /* Don't reset the list; we still need more cleanup later */
3431 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3442
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 3305 of file relcache.c.

3306 {
3307  bool clear_relcache = false;
3308 
3309  /*
3310  * The relcache entry's ref count should be back to its normal
3311  * not-in-a-transaction state: 0 unless it's nailed in cache.
3312  *
3313  * In bootstrap mode, this is NOT true, so don't check it --- the
3314  * bootstrap code expects relations to stay open across start/commit
3315  * transaction calls. (That seems bogus, but it's not worth fixing.)
3316  *
3317  * Note: ideally this check would be applied to every relcache entry, not
3318  * just those that have eoxact work to do. But it's not worth forcing a
3319  * scan of the whole relcache just for this. (Moreover, doing so would
3320  * mean that assert-enabled testing never tests the hash_search code path
3321  * above, which seems a bad idea.)
3322  */
3323 #ifdef USE_ASSERT_CHECKING
3325  {
3326  int expected_refcnt;
3327 
3328  expected_refcnt = relation->rd_isnailed ? 1 : 0;
3329  Assert(relation->rd_refcnt == expected_refcnt);
3330  }
3331 #endif
3332 
3333  /*
3334  * Is the relation live after this transaction ends?
3335  *
3336  * During commit, clear the relcache entry if it is preserved after
3337  * relation drop, in order not to orphan the entry. During rollback,
3338  * clear the relcache entry if the relation is created in the current
3339  * transaction since it isn't interesting any longer once we are out of
3340  * the transaction.
3341  */
3342  clear_relcache =
3343  (isCommit ?
3346 
3347  /*
3348  * Since we are now out of the transaction, reset the subids to zero. That
3349  * also lets RelationClearRelation() drop the relcache entry.
3350  */
3355 
3356  if (clear_relcache)
3357  {
3358  if (RelationHasReferenceCountZero(relation))
3359  {
3360  RelationClearRelation(relation, false);
3361  return;
3362  }
3363  else
3364  {
3365  /*
3366  * Hmm, somewhere there's a (leaked?) reference to the relation.
3367  * We daren't remove the entry for fear of dereferencing a
3368  * dangling pointer later. Bleat, and mark it as not belonging to
3369  * the current transaction. Hopefully it'll get cleaned up
3370  * eventually. This must be just a WARNING to avoid
3371  * error-during-error-recovery loops.
3372  */
3373  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3374  RelationGetRelationName(relation));
3375  }
3376  }
3377 }
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 3235 of file relcache.c.

3236 {
3237  HASH_SEQ_STATUS status;
3238  RelIdCacheEnt *idhentry;
3239  int i;
3240 
3241  /*
3242  * Forget in_progress_list. This is relevant when we're aborting due to
3243  * an error during RelationBuildDesc().
3244  */
3245  Assert(in_progress_list_len == 0 || !isCommit);
3247 
3248  /*
3249  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3250  * listed in it. Otherwise fall back on a hash_seq_search scan.
3251  *
3252  * For simplicity, eoxact_list[] entries are not deleted till end of
3253  * top-level transaction, even though we could remove them at
3254  * subtransaction end in some cases, or remove relations from the list if
3255  * they are cleared for other reasons. Therefore we should expect the
3256  * case that list entries are not found in the hashtable; if not, there's
3257  * nothing to do for them.
3258  */
3260  {
3261  hash_seq_init(&status, RelationIdCache);
3262  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3263  {
3264  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3265  }
3266  }
3267  else
3268  {
3269  for (i = 0; i < eoxact_list_len; i++)
3270  {
3271  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3272  &eoxact_list[i],
3273  HASH_FIND,
3274  NULL);
3275  if (idhentry != NULL)
3276  AtEOXact_cleanup(idhentry->reldesc, isCommit);
3277  }
3278  }
3279 
3280  if (EOXactTupleDescArrayLen > 0)
3281  {
3282  Assert(EOXactTupleDescArray != NULL);
3283  for (i = 0; i < NextEOXactTupleDescNum; i++)
3286  EOXactTupleDescArray = NULL;
3287  }
3288 
3289  /* Now we're out of the transaction and can clear the lists */
3290  eoxact_list_len = 0;
3291  eoxact_list_overflowed = false;
3294 }
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:3305
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 4565 of file relcache.c.

4566 {
4567  const AttrDefault *ada = (const AttrDefault *) a;
4568  const AttrDefault *adb = (const AttrDefault *) b;
4569 
4570  return pg_cmp_s16(ada->adnum, adb->adnum);
4571 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:471
int b
Definition: isn.c:70
int a
Definition: isn.c:69
AttrNumber adnum
Definition: tupdesc.h:24

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

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4485 of file relcache.c.

4486 {
4487  AttrDefault *attrdef;
4488  Relation adrel;
4489  SysScanDesc adscan;
4490  ScanKeyData skey;
4491  HeapTuple htup;
4492  int found = 0;
4493 
4494  /* Allocate array with room for as many entries as expected */
4495  attrdef = (AttrDefault *)
4497  ndef * sizeof(AttrDefault));
4498 
4499  /* Search pg_attrdef for relevant entries */
4500  ScanKeyInit(&skey,
4501  Anum_pg_attrdef_adrelid,
4502  BTEqualStrategyNumber, F_OIDEQ,
4503  ObjectIdGetDatum(RelationGetRelid(relation)));
4504 
4505  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4506  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4507  NULL, 1, &skey);
4508 
4509  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4510  {
4511  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4512  Datum val;
4513  bool isnull;
4514 
4515  /* protect limited size of array */
4516  if (found >= ndef)
4517  {
4518  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4519  adform->adnum, RelationGetRelationName(relation));
4520  break;
4521  }
4522 
4523  val = fastgetattr(htup,
4524  Anum_pg_attrdef_adbin,
4525  adrel->rd_att, &isnull);
4526  if (isnull)
4527  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4528  adform->adnum, RelationGetRelationName(relation));
4529  else
4530  {
4531  /* detoast and convert to cstring in caller's context */
4532  char *s = TextDatumGetCString(val);
4533 
4534  attrdef[found].adnum = adform->adnum;
4535  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4536  pfree(s);
4537  found++;
4538  }
4539  }
4540 
4541  systable_endscan(adscan);
4542  table_close(adrel, AccessShareLock);
4543 
4544  if (found != ndef)
4545  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4546  ndef - found, RelationGetRelationName(relation));
4547 
4548  /*
4549  * Sort the AttrDefault entries by adnum, for the convenience of
4550  * equalTupleDescs(). (Usually, they already will be in order, but this
4551  * might not be so if systable_getnext isn't using an index.)
4552  */
4553  if (found > 1)
4554  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4555 
4556  /* Install array only after it's fully valid */
4557  relation->rd_att->constr->defval = attrdef;
4558  relation->rd_att->constr->num_defval = found;
4559 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:670
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c: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:453
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:4565
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 4420 of file relcache.c.

4421 {
4422  TupleDesc result;
4423  MemoryContext oldcxt;
4424  int i;
4425 
4427 
4428  result = CreateTemplateTupleDesc(natts);
4429  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4430  result->tdtypmod = -1;
4431 
4432  for (i = 0; i < natts; i++)
4433  {
4434  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4435  /* make sure attcacheoff is valid */
4436  TupleDescAttr(result, i)->attcacheoff = -1;
4437  }
4438 
4439  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4440  TupleDescAttr(result, 0)->attcacheoff = 0;
4441 
4442  /* Note: we don't bother to set up a TupleConstr entry */
4443 
4444  MemoryContextSwitchTo(oldcxt);
4445 
4446  return result;
4447 }
#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 4669 of file relcache.c.

4670 {
4671  const ConstrCheck *ca = (const ConstrCheck *) a;
4672  const ConstrCheck *cb = (const ConstrCheck *) b;
4673 
4674  return strcmp(ca->ccname, cb->ccname);
4675 }
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 4580 of file relcache.c.

4581 {
4582  ConstrCheck *check;
4583  int ncheck = relation->rd_rel->relchecks;
4584  Relation conrel;
4585  SysScanDesc conscan;
4586  ScanKeyData skey[1];
4587  HeapTuple htup;
4588  int found = 0;
4589 
4590  /* Allocate array with room for as many entries as expected */
4591  check = (ConstrCheck *)
4593  ncheck * sizeof(ConstrCheck));
4594 
4595  /* Search pg_constraint for relevant entries */
4596  ScanKeyInit(&skey[0],
4597  Anum_pg_constraint_conrelid,
4598  BTEqualStrategyNumber, F_OIDEQ,
4599  ObjectIdGetDatum(RelationGetRelid(relation)));
4600 
4601  conrel = table_open(ConstraintRelationId, AccessShareLock);
4602  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4603  NULL, 1, skey);
4604 
4605  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4606  {
4608  Datum val;
4609  bool isnull;
4610 
4611  /* We want check constraints only */
4612  if (conform->contype != CONSTRAINT_CHECK)
4613  continue;
4614 
4615  /* protect limited size of array */
4616  if (found >= ncheck)
4617  {
4618  elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4619  RelationGetRelationName(relation));
4620  break;
4621  }
4622 
4623  check[found].ccvalid = conform->convalidated;
4624  check[found].ccnoinherit = conform->connoinherit;
4626  NameStr(conform->conname));
4627 
4628  /* Grab and test conbin is actually set */
4629  val = fastgetattr(htup,
4630  Anum_pg_constraint_conbin,
4631  conrel->rd_att, &isnull);
4632  if (isnull)
4633  elog(WARNING, "null conbin for relation \"%s\"",
4634  RelationGetRelationName(relation));
4635  else
4636  {
4637  /* detoast and convert to cstring in caller's context */
4638  char *s = TextDatumGetCString(val);
4639 
4640  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4641  pfree(s);
4642  found++;
4643  }
4644  }
4645 
4646  systable_endscan(conscan);
4647  table_close(conrel, AccessShareLock);
4648 
4649  if (found != ncheck)
4650  elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4651  ncheck - found, RelationGetRelationName(relation));
4652 
4653  /*
4654  * Sort the records by name. This ensures that CHECKs are applied in a
4655  * deterministic order, and it also makes equalTupleDescs() faster.
4656  */
4657  if (found > 1)
4658  qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4659 
4660  /* Install array only after it's fully valid */
4661  relation->rd_att->constr->check = check;
4662  relation->rd_att->constr->num_check = found;
4663 }
#define NameStr(name)
Definition: c.h:746
FormData_pg_constraint * Form_pg_constraint
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4669
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 5871 of file relcache.c.

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

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 951 of file relcache.c.

952 {
953  int i;
954  Oid *r1,
955  *r2;
956 
957  if (policy1 != NULL)
958  {
959  if (policy2 == NULL)
960  return false;
961 
962  if (policy1->polcmd != policy2->polcmd)
963  return false;
964  if (policy1->hassublinks != policy2->hassublinks)
965  return false;
966  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
967  return false;
968  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
969  return false;
970 
971  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
972  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
973 
974  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
975  {
976  if (r1[i] != r2[i])
977  return false;
978  }
979 
980  if (!equal(policy1->qual, policy2->qual))
981  return false;
982  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
983  return false;
984  }
985  else if (policy2 != NULL)
986  return false;
987 
988  return true;
989 }
#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 997 of file relcache.c.

998 {
999  ListCell *lc,
1000  *rc;
1001 
1002  if (rsdesc1 == NULL && rsdesc2 == NULL)
1003  return true;
1004 
1005  if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1006  (rsdesc1 == NULL && rsdesc2 != NULL))
1007  return false;
1008 
1009  if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1010  return false;
1011 
1012  /* RelationBuildRowSecurity should build policies in order */
1013  forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1014  {
1017 
1018  if (!equalPolicy(l, r))
1019  return false;
1020  }
1021 
1022  return true;
1023 }
#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:951

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

Referenced by RelationClearRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 906 of file relcache.c.

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

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

Referenced by RelationClearRelation().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5952 of file relcache.c.

5953 {
5957 
5958  return 0; /* return value does not matter */
5959 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
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(), ExecPartitionCheckEmitError(), and moveSplitTableRows().

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5969 of file relcache.c.

5970 {
5971  TupleDesc reldesc = RelationGetDescr(rel);
5972  const char *colname;
5973 
5974  /* Use reldesc if it's a user attribute, else consult the catalogs */
5975  if (attnum > 0 && attnum <= reldesc->natts)
5976  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5977  else
5978  colname = get_attname(RelationGetRelid(rel), attnum, false);
5979 
5980  return errtablecolname(rel, colname);
5981 }
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:5993

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

5994 {
5995  errtable(rel);
5997 
5998  return 0; /* return value does not matter */
5999 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5952

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

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

4451 {
4452  static TupleDesc pgclassdesc = NULL;
4453 
4454  /* Already done? */
4455  if (pgclassdesc == NULL)
4456  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4457  Desc_pg_class);
4458 
4459  return pgclassdesc;
4460 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4420
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 4463 of file relcache.c.

4464 {
4465  static TupleDesc pgindexdesc = NULL;
4466 
4467  /* Already done? */
4468  if (pgindexdesc == NULL)
4469  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4470  Desc_pg_index);
4471 
4472  return pgindexdesc;
4473 }
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 1595 of file relcache.c.

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

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

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

4383 {
4384  Relation ird;
4385 
4386  /*
4387  * We must lock the underlying catalog before locking the index to avoid
4388  * deadlock, since RelationBuildDesc might well need to read the catalog,
4389  * and if anyone else is exclusive-locking this catalog and index they'll
4390  * be doing it in that order.
4391  */
4392  LockRelationOid(heapoid, AccessShareLock);
4393  LockRelationOid(indexoid, AccessShareLock);
4394  ird = RelationBuildDesc(indexoid, true);
4395  if (ird == NULL)
4396  ereport(PANIC,
4398  errmsg_internal("could not open critical system index %u", indexoid));
4399  ird->rd_isnailed = true;
4400  ird->rd_refcnt = 1;
4403 
4404  (void) RelationGetIndexAttOptions(ird, false);
4405 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
int errcode(int sqlerrcode)
Definition: elog.c:855
#define PANIC
Definition: elog.h:42
#define ereport(elevel,...)
Definition: elog.h:149
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1038
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5891

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

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

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

3967 {
3971 
3972  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3973  EOXactListAdd(relation);
3974 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:789

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

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

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

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

◆ RelationBuildLocalRelation()

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

Definition at line 3524 of file relcache.c.

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

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

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 731 of file relcache.c.

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

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

6787 {
6788  LWLockRelease(RelCacheInitLock);
6789 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6761 of file relcache.c.

6762 {
6763  char localinitfname[MAXPGPATH];
6764  char sharedinitfname[MAXPGPATH];
6765 
6766  if (DatabasePath)
6767  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6769  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6771 
6772  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6773 
6774  /*
6775  * The files might not be there if no backend has been started since the
6776  * last removal. But complain about failures other than ENOENT with
6777  * ERROR. Fortunately, it's not too late to abort the transaction if we
6778  * can't get rid of the would-be-obsolete init file.
6779  */
6780  if (DatabasePath)
6781  unlink_initfile(localinitfname, ERROR);
6782  unlink_initfile(sharedinitfname, ERROR);
6783 }
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:6858

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

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6801 of file relcache.c.

6802 {
6803  const char *tblspcdir = "pg_tblspc";
6804  DIR *dir;
6805  struct dirent *de;
6806  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6807 
6808  snprintf(path, sizeof(path), "global/%s",
6810  unlink_initfile(path, LOG);
6811 
6812  /* Scan everything in the default tablespace */
6814 
6815  /* Scan the tablespace link directory to find non-default tablespaces */
6816  dir = AllocateDir(tblspcdir);
6817 
6818  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6819  {
6820  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6821  {
6822  /* Scan the tablespace dir for per-database dirs */
6823  snprintf(path, sizeof(path), "%s/%s/%s",
6824  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6826  }
6827  }
6828 
6829  FreeDir(dir);
6830 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2961
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2924
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6834
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6834 of file relcache.c.

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

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

3993 {
3994  HASHCTL ctl;
3995  int allocsize;
3996 
3997  /*
3998  * make sure cache memory context exists
3999  */
4000  if (!CacheMemoryContext)
4002 
4003  /*
4004  * create hashtable that indexes the relcache
4005  */
4006  ctl.keysize = sizeof(Oid);
4007  ctl.entrysize = sizeof(RelIdCacheEnt);
4008  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4009  &ctl, HASH_ELEM | HASH_BLOBS);
4010 
4011  /*
4012  * reserve enough in_progress_list slots for many cases
4013  */
4014  allocsize = 4;
4017  allocsize * sizeof(*in_progress_list));
4018  in_progress_list_maxlen = allocsize;
4019 
4020  /*
4021  * relation mapper needs to be initialized too
4022  */
4024 }
#define INITRELCACHESIZE
Definition: relcache.c:3989
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 4038 of file relcache.c.

4039 {
4040  MemoryContext oldcxt;
4041 
4042  /*
4043  * relation mapper needs initialized too
4044  */
4046 
4047  /*
4048  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4049  * nothing.
4050  */
4052  return;
4053 
4054  /*
4055  * switch to cache memory context
4056  */
4058 
4059  /*
4060  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4061  * the cache with pre-made descriptors for the critical shared catalogs.
4062  */
4063  if (!load_relcache_init_file(true))
4064  {
4065  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4066  Natts_pg_database, Desc_pg_database);
4067  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4068  Natts_pg_authid, Desc_pg_authid);
4069  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4070  Natts_pg_auth_members, Desc_pg_auth_members);
4071  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4072  Natts_pg_shseclabel, Desc_pg_shseclabel);
4073  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4074  Natts_pg_subscription, Desc_pg_subscription);
4075 
4076 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4077  }
4078 
4079  MemoryContextSwitchTo(oldcxt);
4080 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6070
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:1873
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 4097 of file relcache.c.

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

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, 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 3011 of file relcache.c.

3012 {
3013  HASH_SEQ_STATUS status;
3014  RelIdCacheEnt *idhentry;
3015  Relation relation;
3016  List *rebuildFirstList = NIL;
3017  List *rebuildList = NIL;
3018  ListCell *l;
3019  int i;
3020 
3021  /*
3022  * Reload relation mapping data before starting to reconstruct cache.
3023  */
3025 
3026  /* Phase 1 */
3027  hash_seq_init(&status, RelationIdCache);
3028 
3029  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3030  {
3031  relation = idhentry->reldesc;
3032 
3033  /*
3034  * Ignore new relations; no other backend will manipulate them before
3035  * we commit. Likewise, before replacing a relation's relfilelocator,
3036  * we shall have acquired AccessExclusiveLock and drained any
3037  * applicable pending invalidations.
3038  */
3039  if (relation->rd_createSubid != InvalidSubTransactionId ||
3041  continue;
3042 
3044 
3045  if (RelationHasReferenceCountZero(relation))
3046  {
3047  /* Delete this entry immediately */
3048  Assert(!relation->rd_isnailed);
3049  RelationClearRelation(relation, false);
3050  }
3051  else
3052  {
3053  /*
3054  * If it's a mapped relation, immediately update its rd_locator in
3055  * case its relfilenumber changed. We must do this during phase 1
3056  * in case the relation is consulted during rebuild of other
3057  * relcache entries in phase 2. It's safe since consulting the
3058  * map doesn't involve any access to relcache entries.
3059  */
3060  if (RelationIsMapped(relation))
3061  {
3062  RelationCloseSmgr(relation);
3063  RelationInitPhysicalAddr(relation);
3064  }
3065 
3066  /*
3067  * Add this entry to list of stuff to rebuild in second pass.
3068  * pg_class goes to the front of rebuildFirstList while
3069  * pg_class_oid_index goes to the back of rebuildFirstList, so
3070  * they are done first and second respectively. Other nailed
3071  * relations go to the front of rebuildList, so they'll be done
3072  * next in no particular order; and everything else goes to the
3073  * back of rebuildList.
3074  */
3075  if (RelationGetRelid(relation) == RelationRelationId)
3076  rebuildFirstList = lcons(relation, rebuildFirstList);
3077  else if (RelationGetRelid(relation) == ClassOidIndexId)
3078  rebuildFirstList = lappend(rebuildFirstList, relation);
3079  else if (relation->rd_isnailed)
3080  rebuildList = lcons(relation, rebuildList);
3081  else
3082  rebuildList = lappend(rebuildList, relation);
3083  }
3084  }
3085 
3086  /*
3087  * We cannot destroy the SMgrRelations as there might still be references
3088  * to them, but close the underlying file descriptors.
3089  */
3090  smgrreleaseall();
3091 
3092  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3093  foreach(l, rebuildFirstList)
3094  {
3095  relation = (Relation) lfirst(l);
3096  RelationClearRelation(relation, true);
3097  }
3098  list_free(rebuildFirstList);
3099  foreach(l, rebuildList)
3100  {
3101  relation = (Relation) lfirst(l);
3102  RelationClearRelation(relation, true);
3103  }
3104  list_free(rebuildList);
3105 
3106  if (!debug_discard)
3107  /* Any RelationBuildDesc() on the stack must start over. */
3108  for (i = 0; i < in_progress_list_len; i++)
3109  in_progress_list[i].invalidated = true;
3110 }
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 long relcacheInvalsReceived
Definition: relcache.c:154
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrreleaseall(void)
Definition: smgr.c:353

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2955 of file relcache.c.

2956 {
2957  Relation relation;
2958 
2959  RelationIdCacheLookup(relationId, relation);
2960 
2961  if (PointerIsValid(relation))
2962  {
2964  RelationFlushRelation(relation);
2965  }
2966  else
2967  {
2968  int i;
2969 
2970  for (i = 0; i < in_progress_list_len; i++)
2971  if (in_progress_list[i].reloid == relationId)
2972  in_progress_list[i].invalidated = true;
2973  }
2974 }
#define PointerIsValid(pointer)
Definition: c.h:763
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2864

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

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation,
bool  rebuild 
)
static

Definition at line 2559 of file relcache.c.

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

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

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2192 of file relcache.c.

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

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

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

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

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

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

Referenced by RelationBuildDesc(), and RelationClearRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2864 of file relcache.c.

2865 {
2866  if (relation->rd_createSubid != InvalidSubTransactionId ||
2868  {
2869  /*
2870  * New relcache entries are always rebuilt, not flushed; else we'd
2871  * forget the "new" status of the relation. Ditto for the
2872  * new-relfilenumber status.
2873  */
2875  {
2876  /*
2877  * The rel could have zero refcnt here, so temporarily increment
2878  * the refcnt to ensure it's safe to rebuild it. We can assume
2879  * that the current transaction has some lock on the rel already.
2880  */
2882  RelationClearRelation(relation, true);
2884  }
2885  else
2886  {
2887  /*
2888  * During abort processing, the current resource owner is not
2889  * valid and we cannot hold a refcnt. Without a valid
2890  * transaction, RelationClearRelation() would just mark the rel as
2891  * invalid anyway, so we can do the same directly.
2892  */
2893  RelationInvalidateRelation(relation);
2894  }
2895  }
2896  else
2897  {
2898  /*
2899  * Pre-existing rels can be dropped from the relcache if not open.
2900  */
2901  bool rebuild = !RelationHasReferenceCountZero(relation);
2902 
2903  RelationClearRelation(relation, rebuild);
2904  }
2905 }
static void RelationInvalidateRelation(Relation relation)
Definition: relcache.c:2520

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2911 of file relcache.c.

2912 {
2913  Relation relation;
2914 
2915  RelationIdCacheLookup(rid, relation);
2916 
2917  if (!PointerIsValid(relation))
2918  return; /* not in cache, nothing to do */
2919 
2920  if (!RelationHasReferenceCountZero(relation))
2921  elog(ERROR, "relation %u is still open", rid);
2922 
2924  if (relation->rd_createSubid != InvalidSubTransactionId ||
2926  {
2927  /*
2928  * In the event of subtransaction rollback, we must not forget
2929  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2930  * invalidates it in lieu of destroying it. (If we're in a top
2931  * transaction, we could opt to destroy the entry.)
2932  */
2934  }
2935 
2936  RelationClearRelation(relation, false);
2937 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5097 of file relcache.c.

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

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

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