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

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

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

Typedefs

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

Functions

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

Variables

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

Macro Definition Documentation

◆ EOXactListAdd

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

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3948 of file relcache.c.

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 184 of file relcache.c.

◆ NUM_CRITICAL_LOCAL_INDEXES

#define NUM_CRITICAL_LOCAL_INDEXES   7 /* fix if you change list above */

◆ NUM_CRITICAL_LOCAL_RELS

#define NUM_CRITICAL_LOCAL_RELS   4 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_INDEXES

#define NUM_CRITICAL_SHARED_INDEXES   6 /* fix if you change list above */

◆ NUM_CRITICAL_SHARED_RELS

#define NUM_CRITICAL_SHARED_RELS   5 /* fix if you change list above */

◆ RECOVER_RELATION_BUILD_MEMORY

#define RECOVER_RELATION_BUILD_MEMORY   0

Definition at line 102 of file relcache.c.

◆ RelationCacheDelete

#define RelationCacheDelete (   RELATION)
Value:
do { \
RelIdCacheEnt *hentry; \
&((RELATION)->rd_id), \
HASH_REMOVE, NULL); \
if (hentry == NULL) \
elog(WARNING, "failed to delete relcache entry for OID %u", \
(RELATION)->rd_id); \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
#define WARNING
Definition: elog.h:36
static HTAB * RelationIdCache
Definition: relcache.c:134

Definition at line 243 of file relcache.c.

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
&((RELATION)->rd_id), \
HASH_ENTER, &found); \
if (found) \
{ \
/* see comments in RelationBuildDesc and RelationBuildLocalRelation */ \
Relation _old_rel = hentry->reldesc; \
Assert(replace_allowed); \
hentry->reldesc = (RELATION); \
RelationDestroyRelation(_old_rel, false); \
elog(WARNING, "leaking still-referenced relcache entry for \"%s\"", \
} \
else \
hentry->reldesc = (RELATION); \
} while(0)
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:489
#define RelationGetRelationName(relation)
Definition: rel.h:539

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

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

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

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

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

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

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 408 of file relcache.c.

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

References CacheMemoryContext, CLASS_TUPLE_SIZE, CreateTemplateTupleDesc(), MemoryContextSwitchTo(), palloc(), palloc0(), RelationData::rd_att, RelationData::rd_rel, RelationData::rd_smgr, and TupleDescData::tdrefcount.

Referenced by RelationBuildDesc().

◆ AtEOSubXact_cleanup()

static void AtEOSubXact_cleanup ( Relation  relation,
bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)
static

Definition at line 3401 of file relcache.c.

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

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

Referenced by AtEOSubXact_RelationCache().

◆ AtEOSubXact_RelationCache()

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

Definition at line 3346 of file relcache.c.

3348 {
3349  HASH_SEQ_STATUS status;
3350  RelIdCacheEnt *idhentry;
3351  int i;
3352 
3353  /*
3354  * Forget in_progress_list. This is relevant when we're aborting due to
3355  * an error during RelationBuildDesc(). We don't commit subtransactions
3356  * during RelationBuildDesc().
3357  */
3358  Assert(in_progress_list_len == 0 || !isCommit);
3360 
3361  /*
3362  * Unless the eoxact_list[] overflowed, we only need to examine the rels
3363  * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3364  * logic as in AtEOXact_RelationCache.
3365  */
3367  {
3368  hash_seq_init(&status, RelationIdCache);
3369  while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3370  {
3371  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3372  mySubid, parentSubid);
3373  }
3374  }
3375  else
3376  {
3377  for (i = 0; i < eoxact_list_len; i++)
3378  {
3379  idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3380  &eoxact_list[i],
3381  HASH_FIND,
3382  NULL);
3383  if (idhentry != NULL)
3384  AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3385  mySubid, parentSubid);
3386  }
3387  }
3388 
3389  /* Don't reset the list; we still need more cleanup later */
3390 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:73
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3401
static bool eoxact_list_overflowed
Definition: relcache.c:187
Relation reldesc
Definition: relcache.c:131

References Assert, AtEOSubXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, RelationIdCache, and relidcacheent::reldesc.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3264 of file relcache.c.

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

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

Referenced by AtEOXact_RelationCache().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3194 of file relcache.c.

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

References Assert, AtEOXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, EOXactTupleDescArray, EOXactTupleDescArrayLen, FreeTupleDesc(), HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), i, in_progress_list_len, NextEOXactTupleDescNum, pfree(), RelationIdCache, and relidcacheent::reldesc.

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

◆ AttrDefaultCmp()

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

Definition at line 4524 of file relcache.c.

4525 {
4526  const AttrDefault *ada = (const AttrDefault *) a;
4527  const AttrDefault *adb = (const AttrDefault *) b;
4528 
4529  return pg_cmp_s16(ada->adnum, adb->adnum);
4530 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:471
int b
Definition: isn.c:70
int a
Definition: isn.c:69
AttrNumber adnum
Definition: tupdesc.h:24

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

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4444 of file relcache.c.

4445 {
4446  AttrDefault *attrdef;
4447  Relation adrel;
4448  SysScanDesc adscan;
4449  ScanKeyData skey;
4450  HeapTuple htup;
4451  int found = 0;
4452 
4453  /* Allocate array with room for as many entries as expected */
4454  attrdef = (AttrDefault *)
4456  ndef * sizeof(AttrDefault));
4457 
4458  /* Search pg_attrdef for relevant entries */
4459  ScanKeyInit(&skey,
4460  Anum_pg_attrdef_adrelid,
4461  BTEqualStrategyNumber, F_OIDEQ,
4462  ObjectIdGetDatum(RelationGetRelid(relation)));
4463 
4464  adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4465  adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4466  NULL, 1, &skey);
4467 
4468  while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4469  {
4470  Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4471  Datum val;
4472  bool isnull;
4473 
4474  /* protect limited size of array */
4475  if (found >= ndef)
4476  {
4477  elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4478  adform->adnum, RelationGetRelationName(relation));
4479  break;
4480  }
4481 
4482  val = fastgetattr(htup,
4483  Anum_pg_attrdef_adbin,
4484  adrel->rd_att, &isnull);
4485  if (isnull)
4486  elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4487  adform->adnum, RelationGetRelationName(relation));
4488  else
4489  {
4490  /* detoast and convert to cstring in caller's context */
4491  char *s = TextDatumGetCString(val);
4492 
4493  attrdef[found].adnum = adform->adnum;
4494  attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4495  pfree(s);
4496  found++;
4497  }
4498  }
4499 
4500  systable_endscan(adscan);
4501  table_close(adrel, AccessShareLock);
4502 
4503  if (found != ndef)
4504  elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4505  ndef - found, RelationGetRelationName(relation));
4506 
4507  /*
4508  * Sort the AttrDefault entries by adnum, for the convenience of
4509  * equalTupleDescs(). (Usually, they already will be in order, but this
4510  * might not be so if systable_getnext isn't using an index.)
4511  */
4512  if (found > 1)
4513  qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4514 
4515  /* Install array only after it's fully valid */
4516  relation->rd_att->constr->defval = attrdef;
4517  relation->rd_att->constr->num_defval = found;
4518 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:670
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1682
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:449
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define RelationGetRelid(relation)
Definition: rel.h:505
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4524
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char * adbin
Definition: tupdesc.h:25
AttrDefault * defval
Definition: tupdesc.h:39
uint16 num_defval
Definition: tupdesc.h:42
TupleConstr * constr
Definition: tupdesc.h:85
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, AttrDefault::adbin, AttrDefault::adnum, AttrDefaultCmp(), BTEqualStrategyNumber, CacheMemoryContext, TupleDescData::constr, TupleConstr::defval, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), TupleConstr::num_defval, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ BuildHardcodedDescriptor()

static TupleDesc BuildHardcodedDescriptor ( int  natts,
const FormData_pg_attribute attrs 
)
static

Definition at line 4379 of file relcache.c.

4380 {
4381  TupleDesc result;
4382  MemoryContext oldcxt;
4383  int i;
4384 
4386 
4387  result = CreateTemplateTupleDesc(natts);
4388  result->tdtypeid = RECORDOID; /* not right, but we don't care */
4389  result->tdtypmod = -1;
4390 
4391  for (i = 0; i < natts; i++)
4392  {
4393  memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4394  /* make sure attcacheoff is valid */
4395  TupleDescAttr(result, i)->attcacheoff = -1;
4396  }
4397 
4398  /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4399  TupleDescAttr(result, 0)->attcacheoff = 0;
4400 
4401  /* Note: we don't bother to set up a TupleConstr entry */
4402 
4403  MemoryContextSwitchTo(oldcxt);
4404 
4405  return result;
4406 }
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:201
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References ATTRIBUTE_FIXED_PART_SIZE, CacheMemoryContext, CreateTemplateTupleDesc(), i, MemoryContextSwitchTo(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

◆ CheckConstraintCmp()

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

Definition at line 4628 of file relcache.c.

4629 {
4630  const ConstrCheck *ca = (const ConstrCheck *) a;
4631  const ConstrCheck *cb = (const ConstrCheck *) b;
4632 
4633  return strcmp(ca->ccname, cb->ccname);
4634 }
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 4539 of file relcache.c.

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

5865 {
5866  bytea **opts = palloc(sizeof(*opts) * natts);
5867 
5868  for (int i = 0; i < natts; i++)
5869  {
5870  bytea *opt = srcopts[i];
5871 
5872  opts[i] = !opt ? NULL : (bytea *)
5873  DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5874  }
5875 
5876  return opts;
5877 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
static AmcheckOptions opts
Definition: pg_amcheck.c:111
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
Definition: c.h:687

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 952 of file relcache.c.

953 {
954  int i;
955  Oid *r1,
956  *r2;
957 
958  if (policy1 != NULL)
959  {
960  if (policy2 == NULL)
961  return false;
962 
963  if (policy1->polcmd != policy2->polcmd)
964  return false;
965  if (policy1->hassublinks != policy2->hassublinks)
966  return false;
967  if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
968  return false;
969  if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
970  return false;
971 
972  r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
973  r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
974 
975  for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
976  {
977  if (r1[i] != r2[i])
978  return false;
979  }
980 
981  if (!equal(policy1->qual, policy2->qual))
982  return false;
983  if (!equal(policy1->with_check_qual, policy2->with_check_qual))
984  return false;
985  }
986  else if (policy2 != NULL)
987  return false;
988 
989  return true;
990 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_DIMS(a)
Definition: array.h:294
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
unsigned int Oid
Definition: postgres_ext.h:31
ArrayType * roles
Definition: rowsecurity.h:24
Expr * with_check_qual
Definition: rowsecurity.h:27

References ARR_DATA_PTR, ARR_DIMS, equal(), RowSecurityPolicy::hassublinks, i, RowSecurityPolicy::polcmd, RowSecurityPolicy::policy_name, RowSecurityPolicy::qual, RowSecurityPolicy::roles, and RowSecurityPolicy::with_check_qual.

Referenced by equalRSDesc().

◆ equalRSDesc()

static bool equalRSDesc ( RowSecurityDesc rsdesc1,
RowSecurityDesc rsdesc2 
)
static

Definition at line 998 of file relcache.c.

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

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

Referenced by RelationClearRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 907 of file relcache.c.

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

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

Referenced by RelationClearRelation().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5945 of file relcache.c.

5946 {
5950 
5951  return 0; /* return value does not matter */
5952 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1514
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3344
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define RelationGetNamespace(relation)
Definition: rel.h:546

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5962 of file relcache.c.

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

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5986 of file relcache.c.

5987 {
5988  errtable(rel);
5990 
5991  return 0; /* return value does not matter */
5992 }
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
int errtable(Relation rel)
Definition: relcache.c:5945

References err_generic_string(), errtable(), and PG_DIAG_COLUMN_NAME.

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ formrdesc()

static void formrdesc ( const char *  relationName,
Oid  relationReltype,
bool  isshared,
int  natts,
const FormData_pg_attribute attrs 
)
static

Definition at line 1874 of file relcache.c.

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

References ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateTemplateTupleDesc(), GetHeapamTableAmRoutine(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidRelFileNumber, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), palloc0(), RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationData::rd_tableam, RelationCacheInsert, RelationGetRelid, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4409 of file relcache.c.

4410 {
4411  static TupleDesc pgclassdesc = NULL;
4412 
4413  /* Already done? */
4414  if (pgclassdesc == NULL)
4415  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4416  Desc_pg_class);
4417 
4418  return pgclassdesc;
4419 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4379
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4422 of file relcache.c.

4423 {
4424  static TupleDesc pgindexdesc = NULL;
4425 
4426  /* Already done? */
4427  if (pgindexdesc == NULL)
4428  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4429  Desc_pg_index);
4430 
4431  return pgindexdesc;
4432 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:118

References BuildHardcodedDescriptor(), and Desc_pg_index.

Referenced by RelationGetDummyIndexExpressions(), RelationGetIndexAttrBitmap(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), and RelationInitIndexAccessInfo().

◆ IndexSupportInitialize()

static void IndexSupportInitialize ( oidvector indclass,
RegProcedure indexSupport,
Oid opFamily,
Oid opcInType,
StrategyNumber  maxSupportNumber,
AttrNumber  maxAttributeNumber 
)
static

Definition at line 1596 of file relcache.c.

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

References elog, ERROR, LookupOpclassInfo(), OidIsValid, opclasscacheent::opcfamily, opclasscacheent::opcintype, opclasscacheent::supportProcs, and oidvector::values.

Referenced by RelationInitIndexAccessInfo().

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1401 of file relcache.c.

1402 {
1403  IndexAmRoutine *cached,
1404  *tmp;
1405 
1406  /*
1407  * Call the amhandler in current, short-lived memory context, just in case
1408  * it leaks anything (it probably won't, but let's be paranoid).
1409  */
1410  tmp = GetIndexAmRoutine(relation->rd_amhandler);
1411 
1412  /* OK, now transfer the data into relation's rd_indexcxt. */
1413  cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1414  sizeof(IndexAmRoutine));
1415  memcpy(cached, tmp, sizeof(IndexAmRoutine));
1416  relation->rd_indam = cached;
1417 
1418  pfree(tmp);
1419 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
Oid rd_amhandler
Definition: rel.h:184
MemoryContext rd_indexcxt
Definition: rel.h:204

References GetIndexAmRoutine(), MemoryContextAlloc(), pfree(), RelationData::rd_amhandler, RelationData::rd_indam, and RelationData::rd_indexcxt.

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1800 of file relcache.c.

1801 {
1802  relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1803 }
const TableAmRoutine * GetTableAmRoutine(Oid amhandler)
Definition: tableamapi.c:28

References GetTableAmRoutine(), RelationData::rd_amhandler, and RelationData::rd_tableam.

Referenced by RelationInitTableAccessMethod().

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 4341 of file relcache.c.

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

References AccessShareLock, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), LockRelationOid(), PANIC, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationBuildDesc(), RelationGetIndexAttOptions(), and UnlockRelationOid().

Referenced by RelationCacheInitializePhase3().

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 6063 of file relcache.c.

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

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

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ LookupOpclassInfo()

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

Definition at line 1647 of file relcache.c.

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

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

Referenced by IndexSupportInitialize().

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3925 of file relcache.c.

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

References EOXactListAdd, GetCurrentSubTransactionId(), InvalidSubTransactionId, RelationData::rd_firstRelfilelocatorSubid, and RelationData::rd_newRelfilelocatorSubid.

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1039 of file relcache.c.

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

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

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

◆ RelationBuildLocalRelation()

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

Definition at line 3483 of file relcache.c.

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

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), ProcNumberForTempRelations, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_droppedSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationInitTableAccessMethod(), RelationMapUpdateMap(), relname, TupleDescData::tdrefcount, and TupleDescAttr.

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5716 of file relcache.c.

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

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 732 of file relcache.c.

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

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 520 of file relcache.c.

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

6780 {
6781  LWLockRelease(RelCacheInitLock);
6782 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6754 of file relcache.c.

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

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

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

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6827 of file relcache.c.

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

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

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

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 3997 of file relcache.c.

3998 {
3999  MemoryContext oldcxt;
4000 
4001  /*
4002  * relation mapper needs initialized too
4003  */
4005 
4006  /*
4007  * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4008  * nothing.
4009  */
4011  return;
4012 
4013  /*
4014  * switch to cache memory context
4015  */
4017 
4018  /*
4019  * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4020  * the cache with pre-made descriptors for the critical shared catalogs.
4021  */
4022  if (!load_relcache_init_file(true))
4023  {
4024  formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4025  Natts_pg_database, Desc_pg_database);
4026  formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4027  Natts_pg_authid, Desc_pg_authid);
4028  formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4029  Natts_pg_auth_members, Desc_pg_auth_members);
4030  formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4031  Natts_pg_shseclabel, Desc_pg_shseclabel);
4032  formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4033  Natts_pg_subscription, Desc_pg_subscription);
4034 
4035 #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4036  }
4037 
4038  MemoryContextSwitchTo(oldcxt);
4039 }
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6063
static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel]
Definition: relcache.c:119
static void formrdesc(const char *relationName, Oid relationReltype, bool isshared, int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:1874
static const FormData_pg_attribute Desc_pg_database[Natts_pg_database]
Definition: relcache.c:115
static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid]
Definition: relcache.c:116
static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription]
Definition: relcache.c:120
static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members]
Definition: relcache.c:117
void RelationMapInitializePhase2(void)
Definition: relmapper.c:671

References CacheMemoryContext, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, Desc_pg_shseclabel, Desc_pg_subscription, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), and RelationMapInitializePhase2().

Referenced by InitPostgres().

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 4056 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2973 of file relcache.c.

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2917 of file relcache.c.

2918 {
2919  Relation relation;
2920 
2921  RelationIdCacheLookup(relationId, relation);
2922 
2923  if (PointerIsValid(relation))
2924  {
2926  RelationFlushRelation(relation);
2927  }
2928  else
2929  {
2930  int i;
2931 
2932  for (i = 0; i < in_progress_list_len; i++)
2933  if (in_progress_list[i].reloid == relationId)
2934  in_progress_list[i].invalidated = true;
2935  }
2936 }
#define PointerIsValid(pointer)
Definition: c.h:763
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2840

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

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

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

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2193 of file relcache.c.

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

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

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

◆ RelationCloseCleanup()

static void RelationCloseCleanup ( Relation  relation)
static

Definition at line 2202 of file relcache.c.

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

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

Referenced by RelationClose(), and ResOwnerReleaseRelation().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2173 of file relcache.c.

2174 {
2175  Assert(rel->rd_refcnt > 0);
2176  rel->rd_refcnt -= 1;
2179 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2146
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References Assert, CurrentResourceOwner, IsBootstrapProcessingMode, RelationData::rd_refcnt, and ResourceOwnerForgetRelationRef().

Referenced by DestroyPartitionDirectory(), heap_endscan(), index_endscan(), RelationCacheInitializePhase3(), RelationClose(), and RelationFlushRelation().

◆ RelationDestroyRelation()

static void RelationDestroyRelation ( Relation  relation,
bool  remember_tupdesc 
)
static

Definition at line 2442 of file relcache.c.

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

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

Referenced by RelationBuildDesc(), and RelationClearRelation().

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2840 of file relcache.c.

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

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2873 of file relcache.c.

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

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5084 of file relcache.c.

5085 {
5086  List *result;
5087  Datum exprsDatum;
5088  bool isnull;
5089  char *exprsString;
5090  List *rawExprs;
5091  ListCell *lc;
5092 
5093  /* Quick exit if there is nothing to do. */
5094  if (relation->rd_indextuple == NULL ||
5095  heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5096  return NIL;
5097 
5098  /* Extract raw node tree(s) from index tuple. */
5099  exprsDatum = heap_getattr(relation->rd_indextuple,
5100  Anum_pg_index_indexprs,
5102  &isnull);
5103  Assert(!isnull);
5104  exprsString = TextDatumGetCString(exprsDatum);
5105  rawExprs = (List *) stringToNode(exprsString);
5106  pfree(exprsString);
5107 
5108  /* Construct null Consts; the typlen and typbyval are arbitrary. */
5109  result = NIL;
5110  foreach(lc, rawExprs)
5111  {
5112  Node *rawExpr = (Node *) lfirst(lc);
5113 
5114  result = lappend(result,
5115  makeConst(exprType(rawExpr),
5116  exprTypmod(rawExpr),
5117  exprCollation(rawExpr),
5118  1,
5119  (Datum) 0,
5120  true,
5121  true));
5122  }
5123 
5124  return result;
5125 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4422

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

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