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/nbtree.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 "access/xlog.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 "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/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_private.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 RelationDestroyRelation (Relation relation, bool remember_tupdesc)
 
static void RelationClearRelation (Relation relation, bool rebuild)
 
static void RelationReloadIndexInfo (Relation relation)
 
static void RelationReloadNailed (Relation relation)
 
static void RelationFlushRelation (Relation relation)
 
static void RememberToFreeTupleDescAtEOX (TupleDesc td)
 
static void AtEOXact_cleanup (Relation relation, bool isCommit)
 
static void AtEOSubXact_cleanup (Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
static bool load_relcache_init_file (bool shared)
 
static void write_relcache_init_file (bool shared)
 
static void write_item (const void *data, Size len, FILE *fp)
 
static void formrdesc (const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
 
static HeapTuple ScanPgRelation (Oid targetRelId, bool indexOK, bool force_non_historic)
 
static Relation AllocateRelationDesc (Form_pg_class relp)
 
static void RelationParseRelOptions (Relation relation, HeapTuple tuple)
 
static void RelationBuildTupleDesc (Relation relation)
 
static Relation RelationBuildDesc (Oid targetRelId, bool insertIt)
 
static void RelationInitPhysicalAddr (Relation relation)
 
static void load_critical_index (Oid indexoid, Oid heapoid)
 
static TupleDesc GetPgClassDescriptor (void)
 
static TupleDesc GetPgIndexDescriptor (void)
 
static void AttrDefaultFetch (Relation relation, int ndef)
 
static int AttrDefaultCmp (const void *a, const void *b)
 
static void CheckConstraintFetch (Relation relation)
 
static int CheckConstraintCmp (const void *a, const void *b)
 
static void InitIndexAmRoutine (Relation relation)
 
static void IndexSupportInitialize (oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
 
static OpClassCacheEntLookupOpclassInfo (Oid operatorClassOid, StrategyNumber numSupport)
 
static void RelationCacheInitFileRemoveInDir (const char *tblspcpath)
 
static void unlink_initfile (const char *initfilename, int elevel)
 
static void RelationBuildRuleLock (Relation relation)
 
static bool equalRuleLocks (RuleLock *rlock1, RuleLock *rlock2)
 
static bool equalPolicy (RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
 
static bool equalRSDesc (RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
 
void RelationInitIndexAccessInfo (Relation relation)
 
static void InitTableAmRoutine (Relation relation)
 
void RelationInitTableAccessMethod (Relation relation)
 
Relation RelationIdGetRelation (Oid relationId)
 
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 RelationCloseSmgrByOid (Oid relationId)
 
void AtEOXact_RelationCache (bool isCommit)
 
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
Relation RelationBuildLocalRelation (const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid 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)
 
DatumRelationGetIndexRawAttOptions (Relation indexrel)
 
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
 

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 3932 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:953
#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:414
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:488
#define RelationGetRelationName(relation)
Definition: rel.h:538

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

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

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

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

3332 {
3333  HASH_SEQ_STATUS status;
3334  RelIdCacheEnt *idhentry;
3335  int i;
3336 
3337  /*
3338  * Forget in_progress_list. This is relevant when we're aborting due to
3339  * an error during RelationBuildDesc(). We don't commit subtransactions
3340  * during RelationBuildDesc().
3341  */
3342  Assert(in_progress_list_len == 0 || !isCommit);
3344 
3345  /*
3346  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3347  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3348  * logic as in AtEOXact_RelationCache.
3349  */
3351  {
3352  hash_seq_init(&status, RelationIdCache);
3353  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3354  {
3355  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3356  mySubid, parentSubid);
3357  }
3358  }
3359  else
3360  {
3361  for (i = 0; i < eoxact_list_len; i++)
3362  {
3363  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3364  &eoxact_list[i],
3365  HASH_FIND,
3366  NULL);
3367  if (idhentry != NULL)
3368  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3369  mySubid, parentSubid);
3370  }
3371  }
3372 
3373  /* Don't reset the list; we still need more cleanup later */
3374 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
@ 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:3385
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 3248 of file relcache.c.

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

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

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

4505 {
4506  const AttrDefault *ada = (const AttrDefault *) a;
4507  const AttrDefault *adb = (const AttrDefault *) b;
4508 
4509  return ada->adnum - adb->adnum;
4510 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69
AttrNumber adnum
Definition: tupdesc.h:24

References a, AttrDefault::adnum, and b.

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4424 of file relcache.c.

4425 {
4426  AttrDefault *attrdef;
4427  Relation adrel;
4428  SysScanDesc adscan;
4429  ScanKeyData skey;
4430  HeapTuple htup;
4431  int found = 0;
4432 
4433  /* Allocate array with room for as many entries as expected */
4434  attrdef = (AttrDefault *)
4436  ndef * sizeof(AttrDefault));
4437 
4438  /* Search pg_attrdef for relevant entries */
4439  ScanKeyInit(&skey,
4440  Anum_pg_attrdef_adrelid,
4441  BTEqualStrategyNumber, F_OIDEQ,
4442  ObjectIdGetDatum(RelationGetRelid(relation)));
4443 
4444  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4445  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4446  NULL, 1, &skey);
4447 
4448  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4449  {
4450  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4451  Datum val;
4452  bool isnull;
4453 
4454  /* protect limited size of array */
4455  if (found >= ndef)
4456  {
4457  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4458  adform->adnum, RelationGetRelationName(relation));
4459  break;
4460  }
4461 
4462  val = fastgetattr(htup,
4463  Anum_pg_attrdef_adbin,
4464  adrel->rd_att, &isnull);
4465  if (isnull)
4466  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4467  adform->adnum, RelationGetRelationName(relation));
4468  else
4469  {
4470  /* detoast and convert to cstring in caller's context */
4471  char *s = TextDatumGetCString(val);
4472 
4473  attrdef[found].adnum = adform->adnum;
4474  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4475  pfree(s);
4476  found++;
4477  }
4478  }
4479 
4480  systable_endscan(adscan);
4481  table_close(adrel, AccessShareLock);
4482 
4483  if (found != ndef)
4484  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4485  ndef - found, RelationGetRelationName(relation));
4486 
4487  /*
4488  * Sort the AttrDefault entries by adnum, for the convenience of
4489  * equalTupleDescs(). (Usually, they already will be in order, but this
4490  * might not be so if systable_getnext isn't using an index.)
4491  */
4492  if (found > 1)
4493  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4494 
4495  /* Install array only after it's fully valid */
4496  relation->rd_att->constr->defval = attrdef;
4497  relation->rd_att->constr->num_defval = found;
4498 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1064
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1631
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:445
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetRelid(relation)
Definition: rel.h:504
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4504
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 4359 of file relcache.c.

4360 {
4361  TupleDesc result;
4362  MemoryContext oldcxt;
4363  int i;
4364 
4366 
4367  result = CreateTemplateTupleDesc(natts);
4368  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4369  result->tdtypmod = -1;
4370 
4371  for (i = 0; i < natts; i++)
4372  {
4373  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4374  /* make sure attcacheoff is valid */
4375  TupleDescAttr(result, i)->attcacheoff = -1;
4376  }
4377 
4378  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4379  TupleDescAttr(result, 0)->attcacheoff = 0;
4380 
4381  /* Note: we don't bother to set up a TupleConstr entry */
4382 
4383  MemoryContextSwitchTo(oldcxt);
4384 
4385  return result;
4386 }
#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 4608 of file relcache.c.

4609 {
4610  const ConstrCheck *ca = (const ConstrCheck *) a;
4611  const ConstrCheck *cb = (const ConstrCheck *) b;
4612 
4613  return strcmp(ca->ccname, cb->ccname);
4614 }
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 4519 of file relcache.c.

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

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

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:315
#define ARR_DIMS(a)
Definition: array.h:287
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:467
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 5935 of file relcache.c.

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

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5952 of file relcache.c.

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

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5976 of file relcache.c.

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

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

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

4390 {
4391  static TupleDesc pgclassdesc = NULL;
4392 
4393  /* Already done? */
4394  if (pgclassdesc == NULL)
4395  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4396  Desc_pg_class);
4397 
4398  return pgclassdesc;
4399 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4359
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 4402 of file relcache.c.

4403 {
4404  static TupleDesc pgindexdesc = NULL;
4405 
4406  /* Already done? */
4407  if (pgindexdesc == NULL)
4408  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4409  Desc_pg_index);
4410 
4411  return pgindexdesc;
4412 }
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 1588 of file relcache.c.

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

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

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

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

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

4324 {
4325  Relation ird;
4326 
4327  /*
4328  * We must lock the underlying catalog before locking the index to avoid
4329  * deadlock, since RelationBuildDesc might well need to read the catalog,
4330  * and if anyone else is exclusive-locking this catalog and index they'll
4331  * be doing it in that order.
4332  */
4333  LockRelationOid(heapoid, AccessShareLock);
4334  LockRelationOid(indexoid, AccessShareLock);
4335  ird = RelationBuildDesc(indexoid, true);
4336  if (ird == NULL)
4337  elog(PANIC, "could not open critical system index %u", indexoid);
4338  ird->rd_isnailed = true;
4339  ird->rd_refcnt = 1;
4342 
4343  (void) RelationGetIndexAttOptions(ird, false);
4344 }
#define PANIC
Definition: elog.h:42
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt)
Definition: relcache.c:1038
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5874

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

Referenced by RelationCacheInitializePhase3().

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 6053 of file relcache.c.

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

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

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

Referenced by IndexSupportInitialize().

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3909 of file relcache.c.

3910 {
3914 
3915  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3916  EOXactListAdd(relation);
3917 }
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780

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 = InvalidBackendId;
1145  relation->rd_islocaltemp = false;
1146  break;
1147  case RELPERSISTENCE_TEMP:
1148  if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1149  {
1150  relation->rd_backend = BackendIdForTempRelations();
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 MyBackendId
1160  * here, in case we are looking at a pg_class entry left over
1161  * from a crashed backend that coincidentally had the same
1162  * BackendId we're using. We should *not* consider such a
1163  * table to be "ours"; this is why we need the separate
1164  * rd_islocaltemp flag. The pg_class entry will get flushed
1165  * if/when we clean out the corresponding temp table namespace
1166  * in preparation for using it.
1167  */
1168  relation->rd_backend =
1169  GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
1170  Assert(relation->rd_backend != InvalidBackendId);
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
1211  Assert(relation->rd_rel->relam == InvalidOid);
1212 
1213  /* extract reloptions if any */
1214  RelationParseRelOptions(relation, pg_class_tuple);
1215 
1216  /*
1217  * Fetch rules and triggers that affect this relation.
1218  *
1219  * Note that RelationBuildRuleLock() relies on this being done after
1220  * extracting the relation's reloptions.
1221  */
1222  if (relation->rd_rel->relhasrules)
1223  RelationBuildRuleLock(relation);
1224  else
1225  {
1226  relation->rd_rules = NULL;
1227  relation->rd_rulescxt = NULL;
1228  }
1229 
1230  if (relation->rd_rel->relhastriggers)
1231  RelationBuildTriggers(relation);
1232  else
1233  relation->trigdesc = NULL;
1234 
1235  if (relation->rd_rel->relrowsecurity)
1236  RelationBuildRowSecurity(relation);
1237  else
1238  relation->rd_rsdesc = NULL;
1239 
1240  /*
1241  * initialize the relation lock manager information
1242  */
1243  RelationInitLockInfo(relation); /* see lmgr.c */
1244 
1245  /*
1246  * initialize physical addressing information for the relation
1247  */
1248  RelationInitPhysicalAddr(relation);
1249 
1250  /* make sure relation is marked as having no open file yet */
1251  relation->rd_smgr = NULL;
1252 
1253  /*
1254  * now we can free the memory allocated for pg_class_tuple
1255  */
1256  heap_freetuple(pg_class_tuple);
1257 
1258  /*
1259  * If an invalidation arrived mid-build, start over. Between here and the
1260  * end of this function, don't add code that does or reasonably could read
1261  * system catalogs. That range must be free from invalidation processing
1262  * for the !insertIt case. For the insertIt case, RelationCacheInsert()
1263  * will enroll this relation in ordinary relcache invalidation processing,
1264  */
1265  if (in_progress_list[in_progress_offset].invalidated)
1266  {
1267  RelationDestroyRelation(relation, false);
1268  goto retry;
1269  }
1270  Assert(in_progress_offset + 1 == in_progress_list_len);
1272 
1273  /*
1274  * Insert newly created relation into relcache hash table, if requested.
1275  *
1276  * There is one scenario in which we might find a hashtable entry already
1277  * present, even though our caller failed to find it: if the relation is a
1278  * system catalog or index that's used during relcache load, we might have
1279  * recursively created the same relcache entry during the preceding steps.
1280  * So allow RelationCacheInsert to delete any already-present relcache
1281  * entry for the same OID. The already-present entry should have refcount
1282  * zero (else somebody forgot to close it); in the event that it doesn't,
1283  * we'll elog a WARNING and leak the already-present entry.
1284  */
1285  if (insertIt)
1286  RelationCacheInsert(relation, true);
1287 
1288  /* It's fully valid */
1289  relation->rd_isvalid = true;
1290 
1291 #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1292  if (tmpcxt)
1293  {
1294  /* Return to caller's context, and blow away the temporary context */
1295  MemoryContextSwitchTo(oldcxt);
1296  MemoryContextDelete(tmpcxt);
1297  }
1298 #endif
1299 
1300  return relation;
1301 }
#define BackendIdForTempRelations()
Definition: backendid.h:34
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3206
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3299
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:196
#define RECOVER_RELATION_BUILD_MEMORY
Definition: relcache.c:102
static void RelationParseRelOptions(Relation relation, HeapTuple tuple)
Definition: relcache.c:462
static Relation AllocateRelationDesc(Form_pg_class relp)
Definition: relcache.c:407
void RelationInitIndexAccessInfo(Relation relation)
Definition: relcache.c:1417
static int in_progress_list_maxlen
Definition: relcache.c:172
static void RelationDestroyRelation(Relation relation, bool remember_tupdesc)
Definition: relcache.c:2403
static void RelationBuildRuleLock(Relation relation)
Definition: relcache.c:731
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
Definition: relcache.c:337
static void RelationBuildTupleDesc(Relation relation)
Definition: relcache.c:519
static InProgressEnt * in_progress_list
Definition: relcache.c:170
bool invalidated
Definition: relcache.c:167
void RelationBuildTriggers(Relation relation)
Definition: trigger.c:1862

References AllocateRelationDesc(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), BackendIdForTempRelations, CurrentMemoryContext, debug_discard_caches, elog(), ERROR, GETSTRUCT, GetTempNamespaceBackendId(), heap_freetuple(), HeapTupleIsValid, in_progress_list, in_progress_list_len, in_progress_list_maxlen, inprogressent::invalidated, InvalidBackendId, InvalidOid, InvalidSubTransactionId, InvalidTransactionId, isTempOrTempToastNamespace(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, 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 3467 of file relcache.c.

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

References Assert(), BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog(), EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, 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, 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 5677 of file relcache.c.

5678 {
5679  List *puboids;
5680  ListCell *lc;
5681  MemoryContext oldcxt;
5682  Oid schemaid;
5683  List *ancestors = NIL;
5684  Oid relid = RelationGetRelid(relation);
5685 
5686  /*
5687  * If not publishable, it publishes no actions. (pgoutput_change() will
5688  * ignore it.)
5689  */
5690  if (!is_publishable_relation(relation))
5691  {
5692  memset(pubdesc, 0, sizeof(PublicationDesc));
5693  pubdesc->rf_valid_for_update = true;
5694  pubdesc->rf_valid_for_delete = true;
5695  pubdesc->cols_valid_for_update = true;
5696  pubdesc->cols_valid_for_delete = true;
5697  return;
5698  }
5699 
5700  if (relation->rd_pubdesc)
5701  {
5702  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5703  return;
5704  }
5705 
5706  memset(pubdesc, 0, sizeof(PublicationDesc));
5707  pubdesc->rf_valid_for_update = true;
5708  pubdesc->rf_valid_for_delete = true;
5709  pubdesc->cols_valid_for_update = true;
5710  pubdesc->cols_valid_for_delete = true;
5711 
5712  /* Fetch the publication membership info. */
5713  puboids = GetRelationPublications(relid);
5714  schemaid = RelationGetNamespace(relation);
5715  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5716 
5717  if (relation->rd_rel->relispartition)
5718  {
5719  /* Add publications that the ancestors are in too. */
5720  ancestors = get_partition_ancestors(relid);
5721 
5722  foreach(lc, ancestors)
5723  {
5724  Oid ancestor = lfirst_oid(lc);
5725 
5726  puboids = list_concat_unique_oid(puboids,
5727  GetRelationPublications(ancestor));
5728  schemaid = get_rel_namespace(ancestor);
5729  puboids = list_concat_unique_oid(puboids,
5730  GetSchemaPublications(schemaid));
5731  }
5732  }
5733  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5734 
5735  foreach(lc, puboids)
5736  {
5737  Oid pubid = lfirst_oid(lc);
5738  HeapTuple tup;
5739  Form_pg_publication pubform;
5740 
5742 
5743  if (!HeapTupleIsValid(tup))
5744  elog(ERROR, "cache lookup failed for publication %u", pubid);
5745 
5746  pubform = (Form_pg_publication) GETSTRUCT(tup);
5747 
5748  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5749  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5750  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5751  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5752 
5753  /*
5754  * Check if all columns referenced in the filter expression are part
5755  * of the REPLICA IDENTITY index or not.
5756  *
5757  * If the publication is FOR ALL TABLES then it means the table has no
5758  * row filters and we can skip the validation.
5759  */
5760  if (!pubform->puballtables &&
5761  (pubform->pubupdate || pubform->pubdelete) &&
5762  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5763  pubform->pubviaroot))
5764  {
5765  if (pubform->pubupdate)
5766  pubdesc->rf_valid_for_update = false;
5767  if (pubform->pubdelete)
5768  pubdesc->rf_valid_for_delete = false;
5769  }
5770 
5771  /*
5772  * Check if all columns are part of the REPLICA IDENTITY index or not.
5773  *
5774  * If the publication is FOR ALL TABLES then it means the table has no
5775  * column list and we can skip the validation.
5776  */
5777  if (!pubform->puballtables &&
5778  (pubform->pubupdate || pubform->pubdelete) &&
5779  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5780  pubform->pubviaroot))
5781  {
5782  if (pubform->pubupdate)
5783  pubdesc->cols_valid_for_update = false;
5784  if (pubform->pubdelete)
5785  pubdesc->cols_valid_for_delete = false;
5786  }
5787 
5788  ReleaseSysCache(tup);
5789 
5790  /*
5791  * If we know everything is replicated and the row filter is invalid
5792  * for update and delete, there is no point to check for other
5793  * publications.
5794  */
5795  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5796  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5797  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5798  break;
5799 
5800  /*
5801  * If we know everything is replicated and the column list is invalid
5802  * for update and delete, there is no point to check for other
5803  * publications.
5804  */
5805  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5806  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5807  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5808  break;
5809  }
5810 
5811  if (relation->rd_pubdesc)
5812  {
5813  pfree(relation->rd_pubdesc);
5814  relation->rd_pubdesc = NULL;
5815  }
5816 
5817  /* Now save copy of the descriptor in the relcache entry. */
5819  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5820  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5821  MemoryContextSwitchTo(oldcxt);
5822 }
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1468
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1956
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#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:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ PUBLICATIONOID
Definition: syscache.h:83

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, PUBLICATIONOID, 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:276
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:435
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 519 of file relcache.c.

520 {
521  HeapTuple pg_attribute_tuple;
522  Relation pg_attribute_desc;
523  SysScanDesc pg_attribute_scan;
524  ScanKeyData skey[2];
525  int need;
526  TupleConstr *constr;
527  AttrMissing *attrmiss = NULL;
528  int ndef = 0;
529 
530  /* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */
531  relation->rd_att->tdtypeid =
532  relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
533  relation->rd_att->tdtypmod = -1; /* just to be sure */
534 
536  sizeof(TupleConstr));
537  constr->has_not_null = false;
538  constr->has_generated_stored = false;
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:1834
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:510
static void AttrDefaultFetch(Relation relation, int ndef)
Definition: relcache.c:4424
static void CheckConstraintFetch(Relation relation)
Definition: relcache.c:4519
#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 6761 of file relcache.c.

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

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6736 of file relcache.c.

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

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

6777 {
6778  const char *tblspcdir = "pg_tblspc";
6779  DIR *dir;
6780  struct dirent *de;
6781  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6782 
6783  snprintf(path, sizeof(path), "global/%s",
6785  unlink_initfile(path, LOG);
6786 
6787  /* Scan everything in the default tablespace */
6789 
6790  /* Scan the tablespace link directory to find non-default tablespaces */
6791  dir = AllocateDir(tblspcdir);
6792 
6793  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6794  {
6795  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6796  {
6797  /* Scan the tablespace dir for per-database dirs */
6798  snprintf(path, sizeof(path), "%s/%s/%s",
6799  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6801  }
6802  }
6803 
6804  FreeDir(dir);
6805 }
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2906
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2869
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2788
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6809
#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 6809 of file relcache.c.

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

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

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

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3981 of file relcache.c.

3982 {
3983  MemoryContext oldcxt;
3984 
3985  /*
3986  * relation mapper needs initialized too
3987  */
3989 
3990  /*
3991  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3992  * nothing.
3993  */
3995  return;
3996 
3997  /*
3998  * switch to cache memory context
3999  */
4001 
4002  /*
4003  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4004  * the cache with pre-made descriptors for the critical shared catalogs.
4005  */
4006  if (!load_relcache_init_file(true))
4007  {
4008  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4009  Natts_pg_database, Desc_pg_database);
4010  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4011  Natts_pg_authid, Desc_pg_authid);
4012  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4013  Natts_pg_auth_members, Desc_pg_auth_members);
4014  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4015  Natts_pg_shseclabel, Desc_pg_shseclabel);
4016  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4017  Natts_pg_subscription, Desc_pg_subscription);
4018 
4019 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4020  }
4021 
4022  MemoryContextSwitchTo(oldcxt);
4023 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6053
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:1866
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:669

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

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

References Assert(), CacheMemoryContext, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog(), ERROR, FATAL, formrdesc(), GETSTRUCT, hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), ObjectIdGetDatum(), pfree(), RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rsdesc, RelationData::rd_rules, RelationData::rd_tableam, RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIdCache, RelationIncrementReferenceCount(), RelationInitTableAccessMethod(), RelationMapInitializePhase3(), RelationParseRelOptions(), relidcacheent::reldesc, ReleaseSysCache(), RELOID, SearchSysCache1(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2934 of file relcache.c.

2935 {
2936  HASH_SEQ_STATUS status;
2937  RelIdCacheEnt *idhentry;
2938  Relation relation;
2939  List *rebuildFirstList = NIL;
2940  List *rebuildList = NIL;
2941  ListCell *l;
2942  int i;
2943 
2944  /*
2945  * Reload relation mapping data before starting to reconstruct cache.
2946  */
2948 
2949  /* Phase 1 */
2950  hash_seq_init(&status, RelationIdCache);
2951 
2952  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
2953  {
2954  relation = idhentry->reldesc;
2955 
2956  /* Must close all smgr references to avoid leaving dangling ptrs */
2957  RelationCloseSmgr(relation);
2958 
2959  /*
2960  * Ignore new relations; no other backend will manipulate them before
2961  * we commit. Likewise, before replacing a relation's relfilelocator,
2962  * we shall have acquired AccessExclusiveLock and drained any
2963  * applicable pending invalidations.
2964  */
2965  if (relation->rd_createSubid != InvalidSubTransactionId ||
2967  continue;
2968 
2970 
2971  if (RelationHasReferenceCountZero(relation))
2972  {
2973  /* Delete this entry immediately */
2974  Assert(!relation->rd_isnailed);
2975  RelationClearRelation(relation, false);
2976  }
2977  else
2978  {
2979  /*
2980  * If it's a mapped relation, immediately update its rd_locator in
2981  * case its relfilenumber changed. We must do this during phase 1
2982  * in case the relation is consulted during rebuild of other
2983  * relcache entries in phase 2. It's safe since consulting the
2984  * map doesn't involve any access to relcache entries.
2985  */
2986  if (RelationIsMapped(relation))
2987  RelationInitPhysicalAddr(relation);
2988 
2989  /*
2990  * Add this entry to list of stuff to rebuild in second pass.
2991  * pg_class goes to the front of rebuildFirstList while
2992  * pg_class_oid_index goes to the back of rebuildFirstList, so
2993  * they are done first and second respectively. Other nailed
2994  * relations go to the front of rebuildList, so they'll be done
2995  * next in no particular order; and everything else goes to the
2996  * back of rebuildList.
2997  */
2998  if (RelationGetRelid(relation) == RelationRelationId)
2999  rebuildFirstList = lcons(relation, rebuildFirstList);
3000  else if (RelationGetRelid(relation) == ClassOidIndexId)
3001  rebuildFirstList = lappend(rebuildFirstList, relation);
3002  else if (relation->rd_isnailed)
3003  rebuildList = lcons(relation, rebuildList);
3004  else
3005  rebuildList = lappend(rebuildList, relation);
3006  }
3007  }
3008 
3009  /*
3010  * Now zap any remaining smgr cache entries. This must happen before we
3011  * start to rebuild entries, since that may involve catalog fetches which
3012  * will re-open catalog files.
3013  */
3014  smgrcloseall();
3015 
3016  /* Phase 2: rebuild the items found to need rebuild in phase 1 */
3017  foreach(l, rebuildFirstList)
3018  {
3019  relation = (Relation) lfirst(l);
3020  RelationClearRelation(relation, true);
3021  }
3022  list_free(rebuildFirstList);
3023  foreach(l, rebuildList)
3024  {
3025  relation = (Relation) lfirst(l);
3026  RelationClearRelation(relation, true);
3027  }
3028  list_free(rebuildList);
3029 
3030  if (!debug_discard)
3031  /* Any RelationBuildDesc() on the stack must start over. */
3032  for (i = 0; i < in_progress_list_len; i++)
3033  in_progress_list[i].invalidated = true;
3034 }
List * lappend(List *list, void *datum)
Definition: list.c:338
void list_free(List *list)
Definition: list.c:1545
List * lcons(void *datum, List *list)
Definition: list.c:494
#define RelationIsMapped(relation)
Definition: rel.h:553
static void RelationCloseSmgr(Relation relation)
Definition: rel.h:584
static long relcacheInvalsReceived
Definition: relcache.c:154
void RelationMapInvalidateAll(void)
Definition: relmapper.c:490
void smgrcloseall(void)
Definition: smgr.c:327

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2878 of file relcache.c.

2879 {
2880  Relation relation;
2881 
2882  RelationIdCacheLookup(relationId, relation);
2883 
2884  if (PointerIsValid(relation))
2885  {
2887  RelationFlushRelation(relation);
2888  }
2889  else
2890  {
2891  int i;
2892 
2893  for (i = 0; i < in_progress_list_len; i++)
2894  if (in_progress_list[i].reloid == relationId)
2895  in_progress_list[i].invalidated = true;
2896  }
2897 }
#define PointerIsValid(pointer)
Definition: c.h:752
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2801

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

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

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(), RelationClose(), RelationFlushRelation(), RelationForgetRelation(), and RelationIdGetRelation().

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2160 of file relcache.c.

2161 {
2162  /* Note: no locking manipulations needed */
2164 
2165  /*
2166  * If the relation is no longer open in this session, we can clean up any
2167  * stale partition descriptors it has. This is unlikely, so check to see
2168  * if there are child contexts before expending a call to mcxt.c.
2169  */
2170  if (RelationHasReferenceCountZero(relation))
2171  {
2172  if (relation->rd_pdcxt != NULL &&
2173  relation->rd_pdcxt->firstchild != NULL)
2175 
2176  if (relation->rd_pddcxt != NULL &&
2177  relation->rd_pddcxt->firstchild != NULL)
2179  }
2180 
2181 #ifdef RELCACHE_FORCE_RELEASE
2182  if (RelationHasReferenceCountZero(relation) &&
2183  relation->rd_createSubid == InvalidSubTransactionId &&
2185  RelationClearRelation(relation, false);
2186 #endif
2187 }
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:448
MemoryContext firstchild
Definition: memnodes.h:90

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

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

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 3043 of file relcache.c.

3044 {
3045  Relation relation;
3046 
3047  RelationIdCacheLookup(relationId, relation);
3048 
3049  if (!PointerIsValid(relation))
3050  return; /* not in cache, nothing to do */
3051 
3052  RelationCloseSmgr(relation);
3053 }

References PointerIsValid, RelationCloseSmgr(), and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2140 of file relcache.c.

2141 {
2142  Assert(rel->rd_refcnt > 0);
2143  rel->rd_refcnt -= 1;
2146 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:147
void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1189

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

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

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

2802 {
2803  if (relation->rd_createSubid != InvalidSubTransactionId ||
2805  {
2806  /*
2807  * New relcache entries are always rebuilt, not flushed; else we'd
2808  * forget the "new" status of the relation. Ditto for the
2809  * new-relfilenumber status.
2810  *
2811  * The rel could have zero refcnt here, so temporarily increment the
2812  * refcnt to ensure it's safe to rebuild it. We can assume that the
2813  * current transaction has some lock on the rel already.
2814  */
2816  RelationClearRelation(relation, true);
2818  }
2819  else
2820  {
2821  /*
2822  * Pre-existing rels can be dropped from the relcache if not open.
2823  */
2824  bool rebuild = !RelationHasReferenceCountZero(relation);
2825 
2826  RelationClearRelation(relation, rebuild);
2827  }
2828 }

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2834 of file relcache.c.

2835 {
2836  Relation relation;
2837 
2838  RelationIdCacheLookup(rid, relation);
2839 
2840  if (!PointerIsValid(relation))
2841  return; /* not in cache, nothing to do */
2842 
2843  if (!RelationHasReferenceCountZero(relation))
2844  elog(ERROR, "relation %u is still open", rid);
2845 
2847  if (relation->rd_createSubid != InvalidSubTransactionId ||
2849  {
2850  /*
2851  * In the event of subtransaction rollback, we must not forget
2852  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2853  * invalidates it in lieu of destroying it. (If we're in a top
2854  * transaction, we could opt to destroy the entry.)
2855  */
2857  }
2858 
2859  RelationClearRelation(relation, false);
2860 }

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

5056 {
5057  List *result;
5058  Datum exprsDatum;
5059  bool isnull;
5060  char *exprsString;
5061  List *rawExprs;
5062  ListCell *lc;
5063 
5064  /* Quick exit if there is nothing to do. */
5065  if (relation->rd_indextuple == NULL ||
5066  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5067  return NIL;
5068 
5069  /* Extract raw node tree(s) from index tuple. */
5070  exprsDatum = heap_getattr(relation->rd_indextuple,
5071  Anum_pg_index_indexprs,
5073  &isnull);
5074  Assert(!isnull);
5075  exprsString = TextDatumGetCString(exprsDatum);
5076  rawExprs = (List *) stringToNode(exprsString);
5077  pfree(exprsString);
5078 
5079  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5080  result = NIL;
5081  foreach(lc, rawExprs)
5082  {
5083  Node *rawExpr = (Node *) lfirst(lc);
5084 
5085  result = lappend(result,
5086  makeConst(exprType(rawExpr),
5087  exprTypmod(rawExpr),
5088  exprCollation(rawExpr),
5089  1,
5090  (Datum) 0,
5091  true,
5092  true));
5093  }
5094 
5095  return result;
5096 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:447
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:302
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:282
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:786
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4402

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

5549 {
5550  int indnkeyatts;
5551  Oid *ops;
5552  Oid *funcs;
5553  uint16 *strats;
5554  Relation conrel;
5555  SysScanDesc conscan;
5556  ScanKeyData skey[1];
5557  HeapTuple htup;
5558  bool found;
5559  MemoryContext oldcxt;
5560  int i;
5561 
5562  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5563 
5564  /* Allocate result space in caller context */
5565  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5566  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5567  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5568 
5569  /* Quick exit if we have the data cached already */
5570  if (indexRelation->rd_exclstrats != NULL)
5571  {
5572  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5573  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5574  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5575  return;
5576  }
5577 
5578  /*
5579  * Search pg_constraint for the constraint associated with the index. To
5580  * make this not too painfully slow, we use the index on conrelid; that
5581  * will hold the parent relation's OID not the index's own OID.
5582  *
5583  * Note: if we wanted to rely on the constraint name matching the index's
5584  * name, we could just do a direct lookup using pg_constraint's unique
5585  * index. For the moment it doesn't seem worth requiring that.
5586  */
5587  ScanKeyInit(&skey[0],
5588  Anum_pg_constraint_conrelid,
5589  BTEqualStrategyNumber, F_OIDEQ,
5590  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5591 
5592  conrel = table_open(ConstraintRelationId, AccessShareLock);
5593  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5594  NULL, 1, skey);
5595  found = false;
5596 
5597  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5598  {
5600  Datum val;
5601  bool isnull;
5602  ArrayType *arr;
5603  int nelem;
5604 
5605  /* We want the exclusion constraint owning the index */
5606  if (conform->contype != CONSTRAINT_EXCLUSION ||
5607  conform->conindid != RelationGetRelid(indexRelation))
5608  continue;
5609 
5610  /* There should be only one */
5611  if (found)
5612  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5613  RelationGetRelationName(indexRelation));
5614  found = true;
5615 
5616  /* Extract the operator OIDS from conexclop */
5617  val = fastgetattr(htup,
5618  Anum_pg_constraint_conexclop,
5619  conrel->rd_att, &isnull);
5620  if (isnull)
5621  elog(ERROR, "null conexclop for rel %s",
5622  RelationGetRelationName(indexRelation));
5623 
5624  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5625  nelem = ARR_DIMS(arr)[0];
5626  if (ARR_NDIM(arr) != 1 ||
5627  nelem != indnkeyatts ||
5628  ARR_HASNULL(arr) ||
5629  ARR_ELEMTYPE(arr) != OIDOID)
5630  elog(ERROR, "conexclop is not a 1-D Oid array");
5631 
5632  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5633  }
5634 
5635  systable_endscan(conscan);
5636  table_close(conrel, AccessShareLock);
5637 
5638  if (!found)
5639  elog(ERROR, "exclusion constraint record missing for rel %s",
5640  RelationGetRelationName(indexRelation));
5641 
5642  /* We need the func OIDs and strategy numbers too */
5643  for (i = 0; i < indnkeyatts; i++)
5644  {
5645  funcs[i] = get_opcode(ops[i]);
5646  strats[i] = get_op_opfamily_strategy(ops[i],
5647  indexRelation->rd_opfamily[i]);
5648  /* shouldn't fail, since it was checked at index creation */
5649  if (strats[i] == InvalidStrategy)
5650  elog(ERROR, "could not find strategy for operator %u in family %u",
5651  ops[i], indexRelation->rd_opfamily[i]);
5652  }
5653 
5654  /* Save a copy of the results in the relcache entry. */
5655  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5656  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5657  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5658  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5659  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5660  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5661  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5662  MemoryContextSwitchTo(oldcxt);
5663 }
#define ARR_NDIM(a)
Definition: array.h:283
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_HASNULL(a)
Definition: array.h:284