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/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, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
 
void RelationSetNewRelfilenode (Relation relation, char persistence)
 
void RelationAssumeNewRelfilenode (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:183
static int eoxact_list_len
Definition: relcache.c:185

Definition at line 188 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3867 of file relcache.c.

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

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

◆ RelationCacheDelete

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

Definition at line 242 of file relcache.c.

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
(void *) &((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:406
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:473
#define RelationGetRelationName(relation)
Definition: rel.h:523

Definition at line 208 of file relcache.c.

◆ RelationIdCacheLookup

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

Definition at line 230 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

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

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

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

3377 {
3378  /*
3379  * Is it a relation created in the current subtransaction?
3380  *
3381  * During subcommit, mark it as belonging to the parent, instead, as long
3382  * as it has not been dropped. Otherwise simply delete the relcache entry.
3383  * --- it isn't interesting any longer.
3384  */
3385  if (relation->rd_createSubid == mySubid)
3386  {
3387  /*
3388  * Valid rd_droppedSubid means the corresponding relation is dropped
3389  * but the relcache entry is preserved for at-commit pending sync. We
3390  * need to drop it explicitly here not to make the entry orphan.
3391  */
3392  Assert(relation->rd_droppedSubid == mySubid ||
3394  if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3395  relation->rd_createSubid = parentSubid;
3396  else if (RelationHasReferenceCountZero(relation))
3397  {
3398  /* allow the entry to be removed */
3403  RelationClearRelation(relation, false);
3404  return;
3405  }
3406  else
3407  {
3408  /*
3409  * Hmm, somewhere there's a (leaked?) reference to the relation.
3410  * We daren't remove the entry for fear of dereferencing a
3411  * dangling pointer later. Bleat, and transfer it to the parent
3412  * subtransaction so we can try again later. This must be just a
3413  * WARNING to avoid error-during-error-recovery loops.
3414  */
3415  relation->rd_createSubid = parentSubid;
3416  elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3417  RelationGetRelationName(relation));
3418  }
3419  }
3420 
3421  /*
3422  * Likewise, update or drop any new-relfilenode-in-subtransaction record
3423  * or drop record.
3424  */
3425  if (relation->rd_newRelfilenodeSubid == mySubid)
3426  {
3427  if (isCommit)
3428  relation->rd_newRelfilenodeSubid = parentSubid;
3429  else
3431  }
3432 
3433  if (relation->rd_firstRelfilenodeSubid == mySubid)
3434  {
3435  if (isCommit)
3436  relation->rd_firstRelfilenodeSubid = parentSubid;
3437  else
3439  }
3440 
3441  if (relation->rd_droppedSubid == mySubid)
3442  {
3443  if (isCommit)
3444  relation->rd_droppedSubid = parentSubid;
3445  else
3447  }
3448 }
#define InvalidSubTransactionId
Definition: c.h:593
#define elog(elevel,...)
Definition: elog.h:218
Assert(fmt[strlen(fmt) - 1] !='\n')
static void RelationClearRelation(Relation relation, bool rebuild)
Definition: relcache.c:2493
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_droppedSubid
Definition: rel.h:107

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

Referenced by AtEOSubXact_RelationCache().

◆ AtEOSubXact_RelationCache()

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

Definition at line 3320 of file relcache.c.

3322 {
3324  RelIdCacheEnt *idhentry;
3325  int i;
3326 
3327  /*
3328  * Forget in_progress_list. This is relevant when we're aborting due to
3329  * an error during RelationBuildDesc(). We don't commit subtransactions
3330  * during RelationBuildDesc().
3331  */
3332  Assert(in_progress_list_len == 0 || !isCommit);
3334 
3335  /*
3336  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3337  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3338  * logic as in AtEOXact_RelationCache.
3339  */
3341  {
3343  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3344  {
3345  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3346  mySubid, parentSubid);
3347  }
3348  }
3349  else
3350  {
3351  for (i = 0; i < eoxact_list_len; i++)
3352  {
3353  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3354  (void *) &eoxact_list[i],
3355  HASH_FIND,
3356  NULL);
3357  if (idhentry != NULL)
3358  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3359  mySubid, parentSubid);
3360  }
3361  }
3362 
3363  /* Don't reset the list; we still need more cleanup later */
3364 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
int i
Definition: isn.c:73
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:184
static int in_progress_list_len
Definition: relcache.c:170
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3375
static bool eoxact_list_overflowed
Definition: relcache.c:186
Relation reldesc
Definition: relcache.c:130

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, relidcacheent::reldesc, and status().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3238 of file relcache.c.

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

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

Referenced by AtEOXact_RelationCache().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3168 of file relcache.c.

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

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

◆ AttrDefaultCmp()

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

Definition at line 4439 of file relcache.c.

4440 {
4441  const AttrDefault *ada = (const AttrDefault *) a;
4442  const AttrDefault *adb = (const AttrDefault *) b;
4443 
4444  return ada->adnum - adb->adnum;
4445 }
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 4359 of file relcache.c.

4360 {
4361  AttrDefault *attrdef;
4362  Relation adrel;
4363  SysScanDesc adscan;
4364  ScanKeyData skey;
4365  HeapTuple htup;
4366  int found = 0;
4367 
4368  /* Allocate array with room for as many entries as expected */
4369  attrdef = (AttrDefault *)
4371  ndef * sizeof(AttrDefault));
4372 
4373  /* Search pg_attrdef for relevant entries */
4374  ScanKeyInit(&skey,
4375  Anum_pg_attrdef_adrelid,
4376  BTEqualStrategyNumber, F_OIDEQ,
4377  ObjectIdGetDatum(RelationGetRelid(relation)));
4378 
4379  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4380  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4381  NULL, 1, &skey);
4382 
4383  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4384  {
4385  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4386  Datum val;
4387  bool isnull;
4388 
4389  /* protect limited size of array */
4390  if (found >= ndef)
4391  {
4392  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4393  adform->adnum, RelationGetRelationName(relation));
4394  break;
4395  }
4396 
4397  val = fastgetattr(htup,
4398  Anum_pg_attrdef_adbin,
4399  adrel->rd_att, &isnull);
4400  if (isnull)
4401  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4402  adform->adnum, RelationGetRelationName(relation));
4403  else
4404  {
4405  /* detoast and convert to cstring in caller's context */
4406  char *s = TextDatumGetCString(val);
4407 
4408  attrdef[found].adnum = adform->adnum;
4409  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4410  pfree(s);
4411  found++;
4412  }
4413  }
4414 
4415  systable_endscan(adscan);
4416  table_close(adrel, AccessShareLock);
4417 
4418  if (found != ndef)
4419  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4420  ndef - found, RelationGetRelationName(relation));
4421 
4422  /*
4423  * Sort the AttrDefault entries by adnum, for the convenience of
4424  * equalTupleDescs(). (Usually, they already will be in order, but this
4425  * might not be so if systable_getnext isn't using an index.)
4426  */
4427  if (found > 1)
4428  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4429 
4430  /* Install array only after it's fully valid */
4431  relation->rd_att->constr->defval = attrdef;
4432  relation->rd_att->constr->num_defval = found;
4433 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:745
long val
Definition: informix.c:664
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1292
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:495
uintptr_t Datum
Definition: postgres.h:411
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define RelationGetRelid(relation)
Definition: rel.h:489
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4439
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:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

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

4295 {
4296  TupleDesc result;
4297  MemoryContext oldcxt;
4298  int i;
4299 
4301 
4302  result = CreateTemplateTupleDesc(natts);
4303  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4304  result->tdtypmod = -1;
4305 
4306  for (i = 0; i < natts; i++)
4307  {
4308  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4309  /* make sure attcacheoff is valid */
4310  TupleDescAttr(result, i)->attcacheoff = -1;
4311  }
4312 
4313  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4314  TupleDescAttr(result, 0)->attcacheoff = 0;
4315 
4316  /* Note: we don't bother to set up a TupleConstr entry */
4317 
4318  MemoryContextSwitchTo(oldcxt);
4319 
4320  return result;
4321 }
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:199
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 4543 of file relcache.c.

4544 {
4545  const ConstrCheck *ca = (const ConstrCheck *) a;
4546  const ConstrCheck *cb = (const ConstrCheck *) b;
4547 
4548  return strcmp(ca->ccname, cb->ccname);
4549 }
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 4454 of file relcache.c.

4455 {
4456  ConstrCheck *check;
4457  int ncheck = relation->rd_rel->relchecks;
4458  Relation conrel;
4459  SysScanDesc conscan;
4460  ScanKeyData skey[1];
4461  HeapTuple htup;
4462  int found = 0;
4463 
4464  /* Allocate array with room for as many entries as expected */
4465  check = (ConstrCheck *)
4467  ncheck * sizeof(ConstrCheck));
4468 
4469  /* Search pg_constraint for relevant entries */
4470  ScanKeyInit(&skey[0],
4471  Anum_pg_constraint_conrelid,
4472  BTEqualStrategyNumber, F_OIDEQ,
4473  ObjectIdGetDatum(RelationGetRelid(relation)));
4474 
4475  conrel = table_open(ConstraintRelationId, AccessShareLock);
4476  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4477  NULL, 1, skey);
4478 
4479  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4480  {
4482  Datum val;
4483  bool isnull;
4484 
4485  /* We want check constraints only */
4486  if (conform->contype != CONSTRAINT_CHECK)
4487  continue;
4488 
4489  /* protect limited size of array */
4490  if (found >= ncheck)
4491  {
4492  elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4493  RelationGetRelationName(relation));
4494  break;
4495  }
4496 
4497  check[found].ccvalid = conform->convalidated;
4498  check[found].ccnoinherit = conform->connoinherit;
4500  NameStr(conform->conname));
4501 
4502  /* Grab and test conbin is actually set */
4503  val = fastgetattr(htup,
4504  Anum_pg_constraint_conbin,
4505  conrel->rd_att, &isnull);
4506  if (isnull)
4507  elog(WARNING, "null conbin for relation \"%s\"",
4508  RelationGetRelationName(relation));
4509  else
4510  {
4511  /* detoast and convert to cstring in caller's context */
4512  char *s = TextDatumGetCString(val);
4513 
4514  check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4515  pfree(s);
4516  found++;
4517  }
4518  }
4519 
4520  systable_endscan(conscan);
4521  table_close(conrel, AccessShareLock);
4522 
4523  if (found != ncheck)
4524  elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4525  ncheck - found, RelationGetRelationName(relation));
4526 
4527  /*
4528  * Sort the records by name. This ensures that CHECKs are applied in a
4529  * deterministic order, and it also makes equalTupleDescs() faster.
4530  */
4531  if (found > 1)
4532  qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4533 
4534  /* Install array only after it's fully valid */
4535  relation->rd_att->constr->check = check;
4536  relation->rd_att->constr->num_check = found;
4537 }
#define NameStr(name)
Definition: c.h:681
FormData_pg_constraint * Form_pg_constraint
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4543
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 5738 of file relcache.c.

5739 {
5740  bytea **opts = palloc(sizeof(*opts) * natts);
5741 
5742  for (int i = 0; i < natts; i++)
5743  {
5744  bytea *opt = srcopts[i];
5745 
5746  opts[i] = !opt ? NULL : (bytea *)
5747  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5748  }
5749 
5750  return opts;
5751 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
static AmcheckOptions opts
Definition: pg_amcheck.c:110
#define DatumGetPointer(X)
Definition: postgres.h:593
#define PointerGetDatum(X)
Definition: postgres.h:600
Definition: c.h:622

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 950 of file relcache.c.

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

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

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

Referenced by RelationClearRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 905 of file relcache.c.

906 {
907  int i;
908 
909  /*
910  * As of 7.3 we assume the rule ordering is repeatable, because
911  * RelationBuildRuleLock should read 'em in a consistent order. So just
912  * compare corresponding slots.
913  */
914  if (rlock1 != NULL)
915  {
916  if (rlock2 == NULL)
917  return false;
918  if (rlock1->numLocks != rlock2->numLocks)
919  return false;
920  for (i = 0; i < rlock1->numLocks; i++)
921  {
922  RewriteRule *rule1 = rlock1->rules[i];
923  RewriteRule *rule2 = rlock2->rules[i];
924 
925  if (rule1->ruleId != rule2->ruleId)
926  return false;
927  if (rule1->event != rule2->event)
928  return false;
929  if (rule1->enabled != rule2->enabled)
930  return false;
931  if (rule1->isInstead != rule2->isInstead)
932  return false;
933  if (!equal(rule1->qual, rule2->qual))
934  return false;
935  if (!equal(rule1->actions, rule2->actions))
936  return false;
937  }
938  }
939  else if (rlock2 != NULL)
940  return false;
941  return true;
942 }
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 5819 of file relcache.c.

5820 {
5824 
5825  return 0; /* return value does not matter */
5826 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1346
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define RelationGetNamespace(relation)
Definition: rel.h:530

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

5837 {
5838  TupleDesc reldesc = RelationGetDescr(rel);
5839  const char *colname;
5840 
5841  /* Use reldesc if it's a user attribute, else consult the catalogs */
5842  if (attnum > 0 && attnum <= reldesc->natts)
5843  colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5844  else
5845  colname = get_attname(RelationGetRelid(rel), attnum, false);
5846 
5847  return errtablecolname(rel, colname);
5848 }
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:83
#define RelationGetDescr(relation)
Definition: rel.h:515
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:5860

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

5861 {
5862  errtable(rel);
5864 
5865  return 0; /* return value does not matter */
5866 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int errtable(Relation rel)
Definition: relcache.c:5819

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

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

4325 {
4326  static TupleDesc pgclassdesc = NULL;
4327 
4328  /* Already done? */
4329  if (pgclassdesc == NULL)
4330  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4331  Desc_pg_class);
4332 
4333  return pgclassdesc;
4334 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4294
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:110

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4337 of file relcache.c.

4338 {
4339  static TupleDesc pgindexdesc = NULL;
4340 
4341  /* Already done? */
4342  if (pgindexdesc == NULL)
4343  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4344  Desc_pg_index);
4345 
4346  return pgindexdesc;
4347 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:117

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

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

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

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

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

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

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

4259 {
4260  Relation ird;
4261 
4262  /*
4263  * We must lock the underlying catalog before locking the index to avoid
4264  * deadlock, since RelationBuildDesc might well need to read the catalog,
4265  * and if anyone else is exclusive-locking this catalog and index they'll
4266  * be doing it in that order.
4267  */
4268  LockRelationOid(heapoid, AccessShareLock);
4269  LockRelationOid(indexoid, AccessShareLock);
4270  ird = RelationBuildDesc(indexoid, true);
4271  if (ird == NULL)
4272  elog(PANIC, "could not open critical system index %u", indexoid);
4273  ird->rd_isnailed = true;
4274  ird->rd_refcnt = 1;
4277 
4278  (void) RelationGetIndexAttOptions(ird, false);
4279 }
#define PANIC
Definition: elog.h:36
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:1037
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5758

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

5938 {
5939  FILE *fp;
5940  char initfilename[MAXPGPATH];
5941  Relation *rels;
5942  int relno,
5943  num_rels,
5944  max_rels,
5945  nailed_rels,
5946  nailed_indexes,
5947  magic;
5948  int i;
5949 
5950  if (shared)
5951  snprintf(initfilename, sizeof(initfilename), "global/%s",
5953  else
5954  snprintf(initfilename, sizeof(initfilename), "%s/%s",
5956 
5957  fp = AllocateFile(initfilename, PG_BINARY_R);
5958  if (fp == NULL)
5959  return false;
5960 
5961  /*
5962  * Read the index relcache entries from the file. Note we will not enter
5963  * any of them into the cache if the read fails partway through; this
5964  * helps to guard against broken init files.
5965  */
5966  max_rels = 100;
5967  rels = (Relation *) palloc(max_rels * sizeof(Relation));
5968  num_rels = 0;
5969  nailed_rels = nailed_indexes = 0;
5970 
5971  /* check for correct magic number (compatible version) */
5972  if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
5973  goto read_failed;
5974  if (magic != RELCACHE_INIT_FILEMAGIC)
5975  goto read_failed;
5976 
5977  for (relno = 0;; relno++)
5978  {
5979  Size len;
5980  size_t nread;
5981  Relation rel;
5982  Form_pg_class relform;
5983  bool has_not_null;
5984 
5985  /* first read the relation descriptor length */
5986  nread = fread(&len, 1, sizeof(len), fp);
5987  if (nread != sizeof(len))
5988  {
5989  if (nread == 0)
5990  break; /* end of file */
5991  goto read_failed;
5992  }
5993 
5994  /* safety check for incompatible relcache layout */
5995  if (len != sizeof(RelationData))
5996  goto read_failed;
5997 
5998  /* allocate another relcache header */
5999  if (num_rels >= max_rels)
6000  {
6001  max_rels *= 2;
6002  rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
6003  }
6004 
6005  rel = rels[num_rels++] = (Relation) palloc(len);
6006 
6007  /* then, read the Relation structure */
6008  if (fread(rel, 1, len, fp) != len)
6009  goto read_failed;
6010 
6011  /* next read the relation tuple form */
6012  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6013  goto read_failed;
6014 
6015  relform = (Form_pg_class) palloc(len);
6016  if (fread(relform, 1, len, fp) != len)
6017  goto read_failed;
6018 
6019  rel->rd_rel = relform;
6020 
6021  /* initialize attribute tuple forms */
6022  rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
6023  rel->rd_att->tdrefcount = 1; /* mark as refcounted */
6024 
6025  rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
6026  rel->rd_att->tdtypmod = -1; /* just to be sure */
6027 
6028  /* next read all the attribute tuple form data entries */
6029  has_not_null = false;
6030  for (i = 0; i < relform->relnatts; i++)
6031  {
6032  Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
6033 
6034  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6035  goto read_failed;
6037  goto read_failed;
6038  if (fread(attr, 1, len, fp) != len)
6039  goto read_failed;
6040 
6041  has_not_null |= attr->attnotnull;
6042  }
6043 
6044  /* next read the access method specific field */
6045  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6046  goto read_failed;
6047  if (len > 0)
6048  {
6049  rel->rd_options = palloc(len);
6050  if (fread(rel->rd_options, 1, len, fp) != len)
6051  goto read_failed;
6052  if (len != VARSIZE(rel->rd_options))
6053  goto read_failed; /* sanity check */
6054  }
6055  else
6056  {
6057  rel->rd_options = NULL;
6058  }
6059 
6060  /* mark not-null status */
6061  if (has_not_null)
6062  {
6063  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
6064 
6065  constr->has_not_null = true;
6066  rel->rd_att->constr = constr;
6067  }
6068 
6069  /*
6070  * If it's an index, there's more to do. Note we explicitly ignore
6071  * partitioned indexes here.
6072  */
6073  if (rel->rd_rel->relkind == RELKIND_INDEX)
6074  {
6075  MemoryContext indexcxt;
6076  Oid *opfamily;
6077  Oid *opcintype;
6078  RegProcedure *support;
6079  int nsupport;
6080  int16 *indoption;
6081  Oid *indcollation;
6082 
6083  /* Count nailed indexes to ensure we have 'em all */
6084  if (rel->rd_isnailed)
6085  nailed_indexes++;
6086 
6087  /* next, read the pg_index tuple */
6088  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6089  goto read_failed;
6090 
6091  rel->rd_indextuple = (HeapTuple) palloc(len);
6092  if (fread(rel->rd_indextuple, 1, len, fp) != len)
6093  goto read_failed;
6094 
6095  /* Fix up internal pointers in the tuple -- see heap_copytuple */
6096  rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
6098 
6099  /*
6100  * prepare index info context --- parameters should match
6101  * RelationInitIndexAccessInfo
6102  */
6104  "index info",
6106  rel->rd_indexcxt = indexcxt;
6109 
6110  /*
6111  * Now we can fetch the index AM's API struct. (We can't store
6112  * that in the init file, since it contains function pointers that
6113  * might vary across server executions. Fortunately, it should be
6114  * safe to call the amhandler even while bootstrapping indexes.)
6115  */
6116  InitIndexAmRoutine(rel);
6117 
6118  /* next, read the vector of opfamily OIDs */
6119  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6120  goto read_failed;
6121 
6122  opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
6123  if (fread(opfamily, 1, len, fp) != len)
6124  goto read_failed;
6125 
6126  rel->rd_opfamily = opfamily;
6127 
6128  /* next, read the vector of opcintype OIDs */
6129  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6130  goto read_failed;
6131 
6132  opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
6133  if (fread(opcintype, 1, len, fp) != len)
6134  goto read_failed;
6135 
6136  rel->rd_opcintype = opcintype;
6137 
6138  /* next, read the vector of support procedure OIDs */
6139  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6140  goto read_failed;
6141  support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
6142  if (fread(support, 1, len, fp) != len)
6143  goto read_failed;
6144 
6145  rel->rd_support = support;
6146 
6147  /* next, read the vector of collation OIDs */
6148  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6149  goto read_failed;
6150 
6151  indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
6152  if (fread(indcollation, 1, len, fp) != len)
6153  goto read_failed;
6154 
6155  rel->rd_indcollation = indcollation;
6156 
6157  /* finally, read the vector of indoption values */
6158  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6159  goto read_failed;
6160 
6161  indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
6162  if (fread(indoption, 1, len, fp) != len)
6163  goto read_failed;
6164 
6165  rel->rd_indoption = indoption;
6166 
6167  /* finally, read the vector of opcoptions values */
6168  rel->rd_opcoptions = (bytea **)
6169  MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
6170 
6171  for (i = 0; i < relform->relnatts; i++)
6172  {
6173  if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6174  goto read_failed;
6175 
6176  if (len > 0)
6177  {
6178  rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
6179  if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
6180  goto read_failed;
6181  }
6182  }
6183 
6184  /* set up zeroed fmgr-info vector */
6185  nsupport = relform->relnatts * rel->rd_indam->amsupport;
6186  rel->rd_supportinfo = (FmgrInfo *)
6187  MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
6188  }
6189  else
6190  {
6191  /* Count nailed rels to ensure we have 'em all */
6192  if (rel->rd_isnailed)
6193  nailed_rels++;
6194 
6195  /* Load table AM data */
6196  if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
6198 
6199  Assert(rel->rd_index == NULL);
6200  Assert(rel->rd_indextuple == NULL);
6201  Assert(rel->rd_indexcxt == NULL);
6202  Assert(rel->rd_indam == NULL);
6203  Assert(rel->rd_opfamily == NULL);
6204  Assert(rel->rd_opcintype == NULL);
6205  Assert(rel->rd_support == NULL);
6206  Assert(rel->rd_supportinfo == NULL);
6207  Assert(rel->rd_indoption == NULL);
6208  Assert(rel->rd_indcollation == NULL);
6209  Assert(rel->rd_opcoptions == NULL);
6210  }
6211 
6212  /*
6213  * Rules and triggers are not saved (mainly because the internal
6214  * format is complex and subject to change). They must be rebuilt if
6215  * needed by RelationCacheInitializePhase3. This is not expected to
6216  * be a big performance hit since few system catalogs have such. Ditto
6217  * for RLS policy data, partition info, index expressions, predicates,
6218  * exclusion info, and FDW info.
6219  */
6220  rel->rd_rules = NULL;
6221  rel->rd_rulescxt = NULL;
6222  rel->trigdesc = NULL;
6223  rel->rd_rsdesc = NULL;
6224  rel->rd_partkey = NULL;
6225  rel->rd_partkeycxt = NULL;
6226  rel->rd_partdesc = NULL;
6227  rel->rd_partdesc_nodetached = NULL;
6229  rel->rd_pdcxt = NULL;
6230  rel->rd_pddcxt = NULL;
6231  rel->rd_partcheck = NIL;
6232  rel->rd_partcheckvalid = false;
6233  rel->rd_partcheckcxt = NULL;
6234  rel->rd_indexprs = NIL;
6235  rel->rd_indpred = NIL;
6236  rel->rd_exclops = NULL;
6237  rel->rd_exclprocs = NULL;
6238  rel->rd_exclstrats = NULL;
6239  rel->rd_fdwroutine = NULL;
6240 
6241  /*
6242  * Reset transient-state fields in the relcache entry
6243  */
6244  rel->rd_smgr = NULL;
6245  if (rel->rd_isnailed)
6246  rel->rd_refcnt = 1;
6247  else
6248  rel->rd_refcnt = 0;
6249  rel->rd_indexvalid = false;
6250  rel->rd_indexlist = NIL;
6251  rel->rd_pkindex = InvalidOid;
6252  rel->rd_replidindex = InvalidOid;
6253  rel->rd_attrsvalid = false;
6254  rel->rd_keyattr = NULL;
6255  rel->rd_pkattr = NULL;
6256  rel->rd_idattr = NULL;
6257  rel->rd_hotblockingattr = NULL;
6258  rel->rd_pubdesc = NULL;
6259  rel->rd_statvalid = false;
6260  rel->rd_statlist = NIL;
6261  rel->rd_fkeyvalid = false;
6262  rel->rd_fkeylist = NIL;
6267  rel->rd_amcache = NULL;
6268  MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
6269 
6270  /*
6271  * Recompute lock and physical addressing info. This is needed in
6272  * case the pg_internal.init file was copied from some other database
6273  * by CREATE DATABASE.
6274  */
6275  RelationInitLockInfo(rel);
6277  }
6278 
6279  /*
6280  * We reached the end of the init file without apparent problem. Did we
6281  * get the right number of nailed items? This is a useful crosscheck in
6282  * case the set of critical rels or indexes changes. However, that should
6283  * not happen in a normally-running system, so let's bleat if it does.
6284  *
6285  * For the shared init file, we're called before client authentication is
6286  * done, which means that elog(WARNING) will go only to the postmaster
6287  * log, where it's easily missed. To ensure that developers notice bad
6288  * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
6289  * an Assert(false) there.
6290  */
6291  if (shared)
6292  {
6293  if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
6294  nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
6295  {
6296  elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
6297  nailed_rels, nailed_indexes,
6299  /* Make sure we get developers' attention about this */
6300  Assert(false);
6301  /* In production builds, recover by bootstrapping the relcache */
6302  goto read_failed;
6303  }
6304  }
6305  else
6306  {
6307  if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
6308  nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
6309  {
6310  elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
6311  nailed_rels, nailed_indexes,
6313  /* We don't need an Assert() in this case */
6314  goto read_failed;
6315  }
6316  }
6317 
6318  /*
6319  * OK, all appears well.
6320  *
6321  * Now insert all the new relcache entries into the cache.
6322  */
6323  for (relno = 0; relno < num_rels; relno++)
6324  {
6325  RelationCacheInsert(rels[relno], false);
6326  }
6327 
6328  pfree(rels);
6329  FreeFile(fp);
6330 
6331  if (shared)
6333  else
6334  criticalRelcachesBuilt = true;
6335  return true;
6336 
6337  /*
6338  * init file is broken, so do it the hard way. We don't bother trying to
6339  * free the clutter we just allocated; it's not in the relcache so it
6340  * won't hurt.
6341  */
6342 read_failed:
6343  pfree(rels);
6344  FreeFile(fp);
6345 
6346  return false;
6347 }
#define PG_BINARY_R
Definition: c.h:1270
#define MemSet(start, val, len)
Definition: c.h:1008
size_t Size
Definition: c.h:540
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2461
int FreeFile(FILE *file)
Definition: fd.c:2660
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:1188
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:207
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:98
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define MAXPGPATH
const void size_t len
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define NIL
Definition: pg_list.h:65
#define snprintf
Definition: port.h:225
#define VARSIZE(PTR)
Definition: postgres.h:316
#define NUM_CRITICAL_LOCAL_RELS
#define NUM_CRITICAL_SHARED_INDEXES
bool criticalRelcachesBuilt
Definition: relcache.c:139
bool criticalSharedRelcachesBuilt
Definition: relcache.c:145
static void InitIndexAmRoutine(Relation relation)
Definition: relcache.c:1392
#define NUM_CRITICAL_SHARED_RELS
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1800
#define NUM_CRITICAL_LOCAL_INDEXES
#define RELCACHE_INIT_FILEMAGIC
Definition: relcache.c:92
#define RELCACHE_INIT_FILENAME
Definition: relcache.h:24
Definition: fmgr.h:57
HeapTupleHeader t_data
Definition: htup.h:68
uint16 amsupport
Definition: amapi.h:216
List * rd_partcheck
Definition: rel.h:145
Bitmapset * rd_keyattr
Definition: rel.h:159
bool rd_partcheckvalid
Definition: rel.h:146
MemoryContext rd_pdcxt
Definition: rel.h:129
MemoryContext rd_partkeycxt
Definition: rel.h:125
TransactionId rd_partdesc_nodetached_xmin
Definition: rel.h:142
bool rd_indexvalid
Definition: rel.h:63
List * rd_indpred
Definition: rel.h:209
List * rd_fkeylist
Definition: rel.h:120
Oid * rd_exclprocs
Definition: rel.h:211
uint16 * rd_exclstrats
Definition: rel.h:212
List * rd_indexlist
Definition: rel.h:150
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:117
PartitionDesc rd_partdesc
Definition: rel.h:128
Oid rd_replidindex
Definition: rel.h:152
RegProcedure * rd_support
Definition: rel.h:205
PartitionDesc rd_partdesc_nodetached
Definition: rel.h:132
bytea ** rd_opcoptions
Definition: rel.h:214
PublicationDesc * rd_pubdesc
Definition: rel.h:164
struct FdwRoutine * rd_fdwroutine
Definition: rel.h:236
TriggerDesc * trigdesc
Definition: rel.h:115
Bitmapset * rd_idattr
Definition: rel.h:161
List * rd_indexprs
Definition: rel.h:208
bool rd_attrsvalid
Definition: rel.h:158
Oid * rd_exclops
Definition: rel.h:210
Oid * rd_opcintype
Definition: rel.h:204
struct HeapTupleData * rd_indextuple
Definition: rel.h:190
MemoryContext rd_partcheckcxt
Definition: rel.h:147
int16 * rd_indoption
Definition: rel.h:207
Form_pg_index rd_index
Definition: rel.h:188
Bitmapset * rd_hotblockingattr
Definition: rel.h:162
void * rd_amcache
Definition: rel.h:225
Oid rd_pkindex
Definition: rel.h:151
bool rd_fkeyvalid
Definition: rel.h:121
bool rd_statvalid
Definition: rel.h:65
List * rd_statlist
Definition: rel.h:155
MemoryContext rd_pddcxt
Definition: rel.h:133
RuleLock * rd_rules
Definition: rel.h:113
struct FmgrInfo * rd_supportinfo
Definition: rel.h:206
Oid * rd_opfamily
Definition: rel.h:203
MemoryContext rd_rulescxt
Definition: rel.h:114
Bitmapset * rd_pkattr
Definition: rel.h:160
PartitionKey rd_partkey
Definition: rel.h:124
bytea * rd_options
Definition: rel.h:171
Oid * rd_indcollation
Definition: rel.h:213
struct PgStat_TableStatus * pgstat_info
Definition: rel.h:251
#define InvalidTransactionId
Definition: transam.h:31

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, MemSet, 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_firstRelfilenodeSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_hotblockingattr, 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_newRelfilenodeSubid, 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 1638 of file relcache.c.

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

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

◆ RelationAssumeNewRelfilenode()

void RelationAssumeNewRelfilenode ( Relation  relation)

Definition at line 3844 of file relcache.c.

3845 {
3848  relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
3849 
3850  /* Flag relation as needing eoxact cleanup (to clear these fields) */
3851  EOXactListAdd(relation);
3852 }
#define EOXactListAdd(rel)
Definition: relcache.c:188
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:776

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilenodeSubid, and RelationData::rd_newRelfilenodeSubid.

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1037 of file relcache.c.

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

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_firstRelfilenodeSubid, RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, 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,
Oid  relfilenode,
Oid  reltablespace,
bool  shared_relation,
bool  mapped_relation,
char  relpersistence,
char  relkind 
)

Definition at line 3457 of file relcache.c.

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

References Assert(), AssertArg, BackendIdForTempRelations, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, InvalidBackendId, InvalidOid, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, 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 5561 of file relcache.c.

5562 {
5563  List *puboids;
5564  ListCell *lc;
5565  MemoryContext oldcxt;
5566  Oid schemaid;
5567  List *ancestors = NIL;
5568  Oid relid = RelationGetRelid(relation);
5569 
5570  /*
5571  * If not publishable, it publishes no actions. (pgoutput_change() will
5572  * ignore it.)
5573  */
5574  if (!is_publishable_relation(relation))
5575  {
5576  memset(pubdesc, 0, sizeof(PublicationDesc));
5577  pubdesc->rf_valid_for_update = true;
5578  pubdesc->rf_valid_for_delete = true;
5579  pubdesc->cols_valid_for_update = true;
5580  pubdesc->cols_valid_for_delete = true;
5581  return;
5582  }
5583 
5584  if (relation->rd_pubdesc)
5585  {
5586  memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5587  return;
5588  }
5589 
5590  memset(pubdesc, 0, sizeof(PublicationDesc));
5591  pubdesc->rf_valid_for_update = true;
5592  pubdesc->rf_valid_for_delete = true;
5593  pubdesc->cols_valid_for_update = true;
5594  pubdesc->cols_valid_for_delete = true;
5595 
5596  /* Fetch the publication membership info. */
5597  puboids = GetRelationPublications(relid);
5598  schemaid = RelationGetNamespace(relation);
5599  puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5600 
5601  if (relation->rd_rel->relispartition)
5602  {
5603  /* Add publications that the ancestors are in too. */
5604  ancestors = get_partition_ancestors(relid);
5605 
5606  foreach(lc, ancestors)
5607  {
5608  Oid ancestor = lfirst_oid(lc);
5609 
5610  puboids = list_concat_unique_oid(puboids,
5611  GetRelationPublications(ancestor));
5612  schemaid = get_rel_namespace(ancestor);
5613  puboids = list_concat_unique_oid(puboids,
5614  GetSchemaPublications(schemaid));
5615  }
5616  }
5617  puboids = list_concat_unique_oid(puboids, GetAllTablesPublications());
5618 
5619  foreach(lc, puboids)
5620  {
5621  Oid pubid = lfirst_oid(lc);
5622  HeapTuple tup;
5623  Form_pg_publication pubform;
5624 
5626 
5627  if (!HeapTupleIsValid(tup))
5628  elog(ERROR, "cache lookup failed for publication %u", pubid);
5629 
5630  pubform = (Form_pg_publication) GETSTRUCT(tup);
5631 
5632  pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5633  pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5634  pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5635  pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5636 
5637  /*
5638  * Check if all columns referenced in the filter expression are part
5639  * of the REPLICA IDENTITY index or not.
5640  *
5641  * If the publication is FOR ALL TABLES then it means the table has no
5642  * row filters and we can skip the validation.
5643  */
5644  if (!pubform->puballtables &&
5645  (pubform->pubupdate || pubform->pubdelete) &&
5646  pub_rf_contains_invalid_column(pubid, relation, ancestors,
5647  pubform->pubviaroot))
5648  {
5649  if (pubform->pubupdate)
5650  pubdesc->rf_valid_for_update = false;
5651  if (pubform->pubdelete)
5652  pubdesc->rf_valid_for_delete = false;
5653  }
5654 
5655  /*
5656  * Check if all columns are part of the REPLICA IDENTITY index or not.
5657  *
5658  * If the publication is FOR ALL TABLES then it means the table has no
5659  * column list and we can skip the validation.
5660  */
5661  if (!pubform->puballtables &&
5662  (pubform->pubupdate || pubform->pubdelete) &&
5663  pub_collist_contains_invalid_column(pubid, relation, ancestors,
5664  pubform->pubviaroot))
5665  {
5666  if (pubform->pubupdate)
5667  pubdesc->cols_valid_for_update = false;
5668  if (pubform->pubdelete)
5669  pubdesc->cols_valid_for_delete = false;
5670  }
5671 
5672  ReleaseSysCache(tup);
5673 
5674  /*
5675  * If we know everything is replicated and the row filter is invalid
5676  * for update and delete, there is no point to check for other
5677  * publications.
5678  */
5679  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5680  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5681  !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5682  break;
5683 
5684  /*
5685  * If we know everything is replicated and the column list is invalid
5686  * for update and delete, there is no point to check for other
5687  * publications.
5688  */
5689  if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5690  pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5691  !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5692  break;
5693  }
5694 
5695  if (relation->rd_pubdesc)
5696  {
5697  pfree(relation->rd_pubdesc);
5698  relation->rd_pubdesc = NULL;
5699  }
5700 
5701  /* Now save copy of the descriptor in the relcache entry. */
5703  relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5704  memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5705  MemoryContextSwitchTo(oldcxt);
5706 }
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1428
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1933
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
#define lfirst_oid(lc)
Definition: pg_list.h:171
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:51
PublicationActions pubactions
bool cols_valid_for_delete
bool cols_valid_for_update
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ 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 730 of file relcache.c.

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

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

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

6647 {
6648  LWLockRelease(RelCacheInitLock);
6649 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6621 of file relcache.c.

6622 {
6623  char localinitfname[MAXPGPATH];
6624  char sharedinitfname[MAXPGPATH];
6625 
6626  if (DatabasePath)
6627  snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6629  snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6631 
6632  LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6633 
6634  /*
6635  * The files might not be there if no backend has been started since the
6636  * last removal. But complain about failures other than ENOENT with
6637  * ERROR. Fortunately, it's not too late to abort the transaction if we
6638  * can't get rid of the would-be-obsolete init file.
6639  */
6640  if (DatabasePath)
6641  unlink_initfile(localinitfname, ERROR);
6642  unlink_initfile(sharedinitfname, ERROR);
6643 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
@ LW_EXCLUSIVE
Definition: lwlock.h:104
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6718

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

6662 {
6663  const char *tblspcdir = "pg_tblspc";
6664  DIR *dir;
6665  struct dirent *de;
6666  char path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6667 
6668  snprintf(path, sizeof(path), "global/%s",
6670  unlink_initfile(path, LOG);
6671 
6672  /* Scan everything in the default tablespace */
6674 
6675  /* Scan the tablespace link directory to find non-default tablespaces */
6676  dir = AllocateDir(tblspcdir);
6677 
6678  while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6679  {
6680  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6681  {
6682  /* Scan the tablespace dir for per-database dirs */
6683  snprintf(path, sizeof(path), "%s/%s/%s",
6684  tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6686  }
6687  }
6688 
6689  FreeDir(dir);
6690 }
#define LOG
Definition: elog.h:25
int FreeDir(DIR *dir)
Definition: fd.c:2840
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2803
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6694
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
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 6694 of file relcache.c.

6695 {
6696  DIR *dir;
6697  struct dirent *de;
6698  char initfilename[MAXPGPATH * 2];
6699 
6700  /* Scan the tablespace directory to find per-database directories */
6701  dir = AllocateDir(tblspcpath);
6702 
6703  while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6704  {
6705  if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6706  {
6707  /* Try to remove the init file in each database */
6708  snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6709  tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6710  unlink_initfile(initfilename, LOG);
6711  }
6712  }
6713 
6714  FreeDir(dir);
6715 }

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

3871 {
3872  HASHCTL ctl;
3873  int allocsize;
3874 
3875  /*
3876  * make sure cache memory context exists
3877  */
3878  if (!CacheMemoryContext)
3880 
3881  /*
3882  * create hashtable that indexes the relcache
3883  */
3884  ctl.keysize = sizeof(Oid);
3885  ctl.entrysize = sizeof(RelIdCacheEnt);
3886  RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3887  &ctl, HASH_ELEM | HASH_BLOBS);
3888 
3889  /*
3890  * reserve enough in_progress_list slots for many cases
3891  */
3892  allocsize = 4;
3895  allocsize * sizeof(*in_progress_list));
3896  in_progress_list_maxlen = allocsize;
3897 
3898  /*
3899  * relation mapper needs to be initialized too
3900  */
3902 }
#define INITRELCACHESIZE
Definition: relcache.c:3867
struct relidcacheent RelIdCacheEnt
void RelationMapInitialize(void)
Definition: relmapper.c:643

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

3917 {
3918  MemoryContext oldcxt;
3919 
3920  /*
3921  * relation mapper needs initialized too
3922  */
3924 
3925  /*
3926  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
3927  * nothing.
3928  */
3930  return;
3931 
3932  /*
3933  * switch to cache memory context
3934  */
3936 
3937  /*
3938  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
3939  * the cache with pre-made descriptors for the critical shared catalogs.
3940  */
3941  if (!load_relcache_init_file(true))
3942  {
3943  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
3944  Natts_pg_database, Desc_pg_database);
3945  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
3946  Natts_pg_authid, Desc_pg_authid);
3947  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
3948  Natts_pg_auth_members, Desc_pg_auth_members);
3949  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
3950  Natts_pg_shseclabel, Desc_pg_shseclabel);
3951  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
3952  Natts_pg_subscription, Desc_pg_subscription);
3953 
3954 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
3955  }
3956 
3957  MemoryContextSwitchTo(oldcxt);
3958 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:5937
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:118
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1865
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:114
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:119
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:116
void RelationMapInitializePhase2(void)
Definition: relmapper.c:663

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

3976 {
3978  RelIdCacheEnt *idhentry;
3979  MemoryContext oldcxt;
3980  bool needNewCacheFile = !criticalSharedRelcachesBuilt;
3981 
3982  /*
3983  * relation mapper needs initialized too
3984  */
3986 
3987  /*
3988  * switch to cache memory context
3989  */
3991 
3992  /*
3993  * Try to load the local relcache cache file. If unsuccessful, bootstrap
3994  * the cache with pre-made descriptors for the critical "nailed-in" system
3995  * catalogs.
3996  */
3997  if (IsBootstrapProcessingMode() ||
3998  !load_relcache_init_file(false))
3999  {
4000  needNewCacheFile = true;
4001 
4002  formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4003  Natts_pg_class, Desc_pg_class);
4004  formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4005  Natts_pg_attribute, Desc_pg_attribute);
4006  formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4007  Natts_pg_proc, Desc_pg_proc);
4008  formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4009  Natts_pg_type, Desc_pg_type);
4010 
4011 #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4012  }
4013 
4014  MemoryContextSwitchTo(oldcxt);
4015 
4016  /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4018  return;
4019 
4020  /*
4021  * If we didn't get the critical system indexes loaded into relcache, do
4022  * so now. These are critical because the catcache and/or opclass cache
4023  * depend on them for fetches done during relcache load. Thus, we have an
4024  * infinite-recursion problem. We can break the recursion by doing
4025  * heapscans instead of indexscans at certain key spots. To avoid hobbling
4026  * performance, we only want to do that until we have the critical indexes
4027  * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4028  * decide whether to do heapscan or indexscan at the key spots, and we set
4029  * it true after we've loaded the critical indexes.
4030  *
4031  * The critical indexes are marked as "nailed in cache", partly to make it
4032  * easy for load_relcache_init_file to count them, but mainly because we
4033  * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4034  * true. (NOTE: perhaps it would be possible to reload them by
4035  * temporarily setting criticalRelcachesBuilt to false again. For now,
4036  * though, we just nail 'em in.)
4037  *
4038  * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4039  * in the same way as the others, because the critical catalogs don't
4040  * (currently) have any rules or triggers, and so these indexes can be
4041  * rebuilt without inducing recursion. However they are used during
4042  * relcache load when a rel does have rules or triggers, so we choose to
4043  * nail them for performance reasons.
4044  */
4046  {
4047  load_critical_index(ClassOidIndexId,
4048  RelationRelationId);
4049  load_critical_index(AttributeRelidNumIndexId,
4050  AttributeRelationId);
4051  load_critical_index(IndexRelidIndexId,
4052  IndexRelationId);
4053  load_critical_index(OpclassOidIndexId,
4054  OperatorClassRelationId);
4055  load_critical_index(AccessMethodProcedureIndexId,
4056  AccessMethodProcedureRelationId);
4057  load_critical_index(RewriteRelRulenameIndexId,
4058  RewriteRelationId);
4059  load_critical_index(TriggerRelidNameIndexId,
4060  TriggerRelationId);
4061 
4062 #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4063 
4064  criticalRelcachesBuilt = true;
4065  }
4066 
4067  /*
4068  * Process critical shared indexes too.
4069  *
4070  * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4071  * initial lookup of MyDatabaseId, without which we'll never find any
4072  * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4073  * database OID, so it instead depends on DatabaseOidIndexId. We also
4074  * need to nail up some indexes on pg_authid and pg_auth_members for use
4075  * during client authentication. SharedSecLabelObjectIndexId isn't
4076  * critical for the core system, but authentication hooks might be
4077  * interested in it.
4078  */
4080  {
4081  load_critical_index(DatabaseNameIndexId,
4082  DatabaseRelationId);
4083  load_critical_index(DatabaseOidIndexId,
4084  DatabaseRelationId);
4085  load_critical_index(AuthIdRolnameIndexId,
4086  AuthIdRelationId);
4087  load_critical_index(AuthIdOidIndexId,
4088  AuthIdRelationId);
4089  load_critical_index(AuthMemMemRoleIndexId,
4090  AuthMemRelationId);
4091  load_critical_index(SharedSecLabelObjectIndexId,
4092  SharedSecLabelRelationId);
4093 
4094 #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4095 
4097  }
4098 
4099  /*
4100  * Now, scan all the relcache entries and update anything that might be
4101  * wrong in the results from formrdesc or the relcache cache file. If we
4102  * faked up relcache entries using formrdesc, then read the real pg_class
4103  * rows and replace the fake entries with them. Also, if any of the
4104  * relcache entries have rules, triggers, or security policies, load that
4105  * info the hard way since it isn't recorded in the cache file.
4106  *
4107  * Whenever we access the catalogs to read data, there is a possibility of
4108  * a shared-inval cache flush causing relcache entries to be removed.
4109  * Since hash_seq_search only guarantees to still work after the *current*
4110  * entry is removed, it's unsafe to continue the hashtable scan afterward.
4111  * We handle this by restarting the scan from scratch after each access.
4112  * This is theoretically O(N^2), but the number of entries that actually
4113  * need to be fixed is small enough that it doesn't matter.
4114  */
4116 
4117  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4118  {
4119  Relation relation = idhentry->reldesc;
4120  bool restart = false;
4121 
4122  /*
4123  * Make sure *this* entry doesn't get flushed while we work with it.
4124  */
4126 
4127  /*
4128  * If it's a faked-up entry, read the real pg_class tuple.
4129  */
4130  if (relation->rd_rel->relowner == InvalidOid)
4131  {
4132  HeapTuple htup;
4133  Form_pg_class relp;
4134 
4135  htup = SearchSysCache1(RELOID,
4136  ObjectIdGetDatum(RelationGetRelid(relation)));
4137  if (!HeapTupleIsValid(htup))
4138  elog(FATAL, "cache lookup failed for relation %u",
4139  RelationGetRelid(relation));
4140  relp = (Form_pg_class) GETSTRUCT(htup);
4141 
4142  /*
4143  * Copy tuple to relation->rd_rel. (See notes in
4144  * AllocateRelationDesc())
4145  */
4146  memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4147 
4148  /* Update rd_options while we have the tuple */
4149  if (relation->rd_options)
4150  pfree(relation->rd_options);
4151  RelationParseRelOptions(relation, htup);
4152 
4153  /*
4154  * Check the values in rd_att were set up correctly. (We cannot
4155  * just copy them over now: formrdesc must have set up the rd_att
4156  * data correctly to start with, because it may already have been
4157  * copied into one or more catcache entries.)
4158  */
4159  Assert(relation->rd_att->tdtypeid == relp->reltype);
4160  Assert(relation->rd_att->tdtypmod == -1);
4161 
4162  ReleaseSysCache(htup);
4163 
4164  /* relowner had better be OK now, else we'll loop forever */
4165  if (relation->rd_rel->relowner == InvalidOid)
4166  elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4167  RelationGetRelationName(relation));
4168 
4169  restart = true;
4170  }
4171 
4172  /*
4173  * Fix data that isn't saved in relcache cache file.
4174  *
4175  * relhasrules or relhastriggers could possibly be wrong or out of
4176  * date. If we don't actually find any rules or triggers, clear the
4177  * local copy of the flag so that we don't get into an infinite loop
4178  * here. We don't make any attempt to fix the pg_class entry, though.
4179  */
4180  if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4181  {
4182  RelationBuildRuleLock(relation);
4183  if (relation->rd_rules == NULL)
4184  relation->rd_rel->relhasrules = false;
4185  restart = true;
4186  }
4187  if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4188  {
4189  RelationBuildTriggers(relation);
4190  if (relation->trigdesc == NULL)
4191  relation->rd_rel->relhastriggers = false;
4192  restart = true;
4193  }
4194 
4195  /*
4196  * Re-load the row security policies if the relation has them, since
4197  * they are not preserved in the cache. Note that we can never NOT
4198  * have a policy while relrowsecurity is true,
4199  * RelationBuildRowSecurity will create a single default-deny policy
4200  * if there is no policy defined in pg_policy.
4201  */
4202  if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4203  {
4204  RelationBuildRowSecurity(relation);
4205 
4206  Assert(relation->rd_rsdesc != NULL);
4207  restart = true;
4208  }
4209 
4210  /* Reload tableam data if needed */
4211  if (relation->rd_tableam == NULL &&
4212  (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4213  {
4215  Assert(relation->rd_tableam != NULL);
4216 
4217  restart = true;
4218  }
4219 
4220  /* Release hold on the relation */
4222 
4223  /* Now, restart the hashtable scan if needed */
4224  if (restart)
4225  {
4228  }
4229  }
4230 
4231  /*
4232  * Lastly, write out new relcache cache files if needed. We don't bother
4233  * to distinguish cases where only one of the two needs an update.
4234  */
4235  if (needNewCacheFile)
4236  {
4237  /*
4238  * Force all the catcaches to finish initializing and thereby open the
4239  * catalogs and indexes they use. This will preload the relcache with
4240  * entries for all the most important system catalogs and indexes, so
4241  * that the init files will be most useful for future backends.
4242  */
4244 
4245  /* now write the files */
4247  write_relcache_init_file(false);
4248  }
4249 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512
#define FATAL
Definition: elog.h:35
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2139
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute]
Definition: relcache.c:111
static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc]
Definition: relcache.c:112
static void write_relcache_init_file(bool shared)
Definition: relcache.c:6354
static const FormData_pg_attribute Desc_pg_type[Natts_pg_type]
Definition: relcache.c:113
static void load_critical_index(Oid indexoid, Oid heapoid)
Definition: relcache.c:4258
void RelationMapInitializePhase3(void)
Definition: relmapper.c:684
void InitCatalogCachePhase2(void)
Definition: syscache.c:1132
@ 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(), status(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, RelationData::trigdesc, and write_relcache_init_file().

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2924 of file relcache.c.

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

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_firstRelfilenodeSubid, RelationData::rd_isnailed, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationIdCache, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), relcacheInvalsReceived, relidcacheent::reldesc, smgrcloseall(), and status().

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2868 of file relcache.c.

2869 {
2870  Relation relation;
2871 
2872  RelationIdCacheLookup(relationId, relation);
2873 
2874  if (PointerIsValid(relation))
2875  {
2877  RelationFlushRelation(relation);
2878  }
2879  else
2880  {
2881  int i;
2882 
2883  for (i = 0; i < in_progress_list_len; i++)
2884  if (in_progress_list[i].reloid == relationId)
2885  in_progress_list[i].invalidated = true;
2886  }
2887 }
#define PointerIsValid(pointer)
Definition: c.h:698
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:230
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2791

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

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

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

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

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

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

◆ RelationCloseSmgrByOid()

void RelationCloseSmgrByOid ( Oid  relationId)

Definition at line 3033 of file relcache.c.

3034 {
3035  Relation relation;
3036 
3037  RelationIdCacheLookup(relationId, relation);
3038 
3039  if (!PointerIsValid(relation))
3040  return; /* not in cache, nothing to do */
3041 
3042  RelationCloseSmgr(relation);
3043 }

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2139 of file relcache.c.

2140 {
2141  Assert(rel->rd_refcnt > 0);
2142  rel->rd_refcnt -= 1;
2145 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1124

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

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

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

2792 {
2793  if (relation->rd_createSubid != InvalidSubTransactionId ||
2795  {
2796  /*
2797  * New relcache entries are always rebuilt, not flushed; else we'd
2798  * forget the "new" status of the relation. Ditto for the
2799  * new-relfilenode status.
2800  *
2801  * The rel could have zero refcnt here, so temporarily increment the
2802  * refcnt to ensure it's safe to rebuild it. We can assume that the
2803  * current transaction has some lock on the rel already.
2804  */
2806  RelationClearRelation(relation, true);
2808  }
2809  else
2810  {
2811  /*
2812  * Pre-existing rels can be dropped from the relcache if not open.
2813  */
2814  bool rebuild = !RelationHasReferenceCountZero(relation);
2815 
2816  RelationClearRelation(relation, rebuild);
2817  }
2818 }

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2824 of file relcache.c.

2825 {
2826  Relation relation;
2827 
2828  RelationIdCacheLookup(rid, relation);
2829 
2830  if (!PointerIsValid(relation))
2831  return; /* not in cache, nothing to do */
2832 
2833  if (!RelationHasReferenceCountZero(relation))
2834  elog(ERROR, "relation %u is still open", rid);
2835 
2837  if (relation->rd_createSubid != InvalidSubTransactionId ||
2839  {
2840  /*
2841  * In the event of subtransaction rollback, we must not forget
2842  * rd_*Subid. Mark the entry "dropped" so RelationClearRelation()
2843  * invalidates it in lieu of destroying it. (If we're in a top
2844  * transaction, we could opt to destroy the entry.)
2845  */
2847  }
2848 
2849  RelationClearRelation(relation, false);
2850 }

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 4968 of file relcache.c.

4969 {
4970  List *result;
4971  Datum exprsDatum;
4972  bool isnull;
4973  char *exprsString;
4974  List *rawExprs;
4975  ListCell *lc;
4976 
4977  /* Quick exit if there is nothing to do. */
4978  if (relation->rd_indextuple == NULL ||
4979  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
4980  return NIL;
4981 
4982  /* Extract raw node tree(s) from index tuple. */
4983  exprsDatum = heap_getattr(relation->rd_indextuple,
4984  Anum_pg_index_indexprs,
4986  &isnull);
4987  Assert(!isnull);
4988  exprsString = TextDatumGetCString(exprsDatum);
4989  rawExprs = (List *) stringToNode(exprsString);
4990  pfree(exprsString);
4991 
4992  /* Construct null Consts; the typlen and typbyval are arbitrary. */
4993  result = NIL;
4994  foreach(lc, rawExprs)
4995  {
4996  Node *rawExpr = (Node *) lfirst(lc);
4997 
4998  result = lappend(result,
4999  makeConst(exprType(rawExpr),
5000  exprTypmod(rawExpr),
5001  exprCollation(rawExpr),
5002  1,
5003  (Datum) 0,
5004  true,
5005  true));
5006  }
5007 
5008  return result;
5009 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:300
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:286
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4337

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

5433 {
5434  int indnkeyatts;
5435  Oid *ops;
5436  Oid *funcs;
5437  uint16 *strats;
5438  Relation conrel;
5439  SysScanDesc conscan;
5440  ScanKeyData skey[1];
5441  HeapTuple htup;
5442  bool found;
5443  MemoryContext oldcxt;
5444  int i;
5445 
5446  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5447 
5448  /* Allocate result space in caller context */
5449  *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5450  *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5451  *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5452 
5453  /* Quick exit if we have the data cached already */
5454  if (indexRelation->rd_exclstrats != NULL)
5455  {
5456  memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5457  memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5458  memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5459  return;
5460  }
5461 
5462  /*
5463  * Search pg_constraint for the constraint associated with the index. To
5464  * make this not too painfully slow, we use the index on conrelid; that
5465  * will hold the parent relation's OID not the index's own OID.
5466  *
5467  * Note: if we wanted to rely on the constraint name matching the index's
5468  * name, we could just do a direct lookup using pg_constraint's unique
5469  * index. For the moment it doesn't seem worth requiring that.
5470  */
5471  ScanKeyInit(&skey[0],
5472  Anum_pg_constraint_conrelid,
5473  BTEqualStrategyNumber, F_OIDEQ,
5474  ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5475 
5476  conrel = table_open(ConstraintRelationId, AccessShareLock);
5477  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5478  NULL, 1, skey);
5479  found = false;
5480 
5481  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5482  {
5484  Datum val;
5485  bool isnull;
5486  ArrayType *arr;
5487  int nelem;
5488 
5489  /* We want the exclusion constraint owning the index */
5490  if (conform->contype != CONSTRAINT_EXCLUSION ||
5491  conform->conindid != RelationGetRelid(indexRelation))
5492  continue;
5493 
5494  /* There should be only one */
5495  if (found)
5496  elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5497  RelationGetRelationName(indexRelation));
5498  found = true;
5499 
5500  /* Extract the operator OIDS from conexclop */
5501  val = fastgetattr(htup,
5502  Anum_pg_constraint_conexclop,
5503  conrel->rd_att, &isnull);
5504  if (isnull)
5505  elog(ERROR, "null conexclop for rel %s",
5506  RelationGetRelationName(indexRelation));
5507 
5508  arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5509  nelem = ARR_DIMS(arr)[0];
5510  if (ARR_NDIM(arr) != 1 ||
5511  nelem != indnkeyatts ||
5512  ARR_HASNULL(arr) ||
5513  ARR_ELEMTYPE(arr) != OIDOID)
5514  elog(ERROR, "conexclop is not a 1-D Oid array");
5515 
5516  memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5517  }
5518 
5519  systable_endscan(conscan);
5520  table_close(conrel, AccessShareLock);
5521 
5522  if (!found)
5523  elog(ERROR, "exclusion constraint record missing for rel %s",
5524  RelationGetRelationName(indexRelation));
5525 
5526  /* We need the func OIDs and strategy numbers too */
5527  for (i = 0; i < indnkeyatts; i++)
5528  {
5529  funcs[i] = get_opcode(ops[i]);
5530  strats[i] = get_op_opfamily_strategy(ops[i],
5531  indexRelation->rd_opfamily[i]);
5532  /* shouldn't fail, since it was checked at index creation */
5533  if (strats[i] == InvalidStrategy)
5534  elog(ERROR, "could not find strategy for operator %u in family %u",
5535  ops[i], indexRelation->rd_opfamily[i]);
5536  }
5537 
5538  /* Save a copy of the results in the relcache entry. */
5539  oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5540  indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5541  indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5542  indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5543  memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5544  memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5545  memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5546  MemoryContextSwitchTo(oldcxt);
5547 }
#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
unsigned short uint16
Definition: c.h:440