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

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

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

Typedefs

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

Functions

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

Variables

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

Macro Definition Documentation

◆ EOXactListAdd

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

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3955 of file relcache.c.

◆ MAX_EOXACT_LIST

#define MAX_EOXACT_LIST   32

Definition at line 184 of file relcache.c.

◆ NUM_CRITICAL_LOCAL_INDEXES

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

◆ NUM_CRITICAL_LOCAL_RELS

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

◆ NUM_CRITICAL_SHARED_INDEXES

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

◆ NUM_CRITICAL_SHARED_RELS

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

◆ RECOVER_RELATION_BUILD_MEMORY

#define RECOVER_RELATION_BUILD_MEMORY   0

Definition at line 102 of file relcache.c.

◆ RelationCacheDelete

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

Definition at line 243 of file relcache.c.

◆ RelationCacheInsert

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

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

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

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

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

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

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

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 410 of file relcache.c.

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

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

Referenced by RelationBuildDesc().

◆ AtEOSubXact_cleanup()

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

Definition at line 3399 of file relcache.c.

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

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

Referenced by AtEOSubXact_RelationCache().

◆ AtEOSubXact_RelationCache()

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

Definition at line 3344 of file relcache.c.

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

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_cleanup()

static void AtEOXact_cleanup ( Relation  relation,
bool  isCommit 
)
static

Definition at line 3262 of file relcache.c.

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

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

Referenced by AtEOXact_RelationCache().

◆ AtEOXact_RelationCache()

void AtEOXact_RelationCache ( bool  isCommit)

Definition at line 3192 of file relcache.c.

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

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

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

◆ AttrDefaultCmp()

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

Definition at line 4531 of file relcache.c.

4532 {
4533  const AttrDefault *ada = (const AttrDefault *) a;
4534  const AttrDefault *adb = (const AttrDefault *) b;
4535 
4536  return pg_cmp_s16(ada->adnum, adb->adnum);
4537 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:586
int b
Definition: isn.c:69
int a
Definition: isn.c:68
AttrNumber adnum
Definition: tupdesc.h:24

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

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4451 of file relcache.c.

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

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

Referenced by RelationBuildTupleDesc().

◆ BuildHardcodedDescriptor()

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

Definition at line 4386 of file relcache.c.

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

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

◆ CheckConstraintCmp()

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

Definition at line 4635 of file relcache.c.

4636 {
4637  const ConstrCheck *ca = (const ConstrCheck *) a;
4638  const ConstrCheck *cb = (const ConstrCheck *) b;
4639 
4640  return strcmp(ca->ccname, cb->ccname);
4641 }
char * ccname
Definition: tupdesc.h:30

References a, b, and ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4546 of file relcache.c.

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

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ConstrCheck::ccbin, ConstrCheck::ccname, ConstrCheck::ccnoinherit, ConstrCheck::ccvalid, TupleConstr::check, CheckConstraintCmp(), TupleDescData::constr, elog, fastgetattr(), GETSTRUCT, HeapTupleIsValid, MemoryContextAllocZero(), MemoryContextStrdup(), NameStr, TupleConstr::num_check, ObjectIdGetDatum(), pfree(), qsort, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, val, and WARNING.

Referenced by RelationBuildTupleDesc().

◆ CopyIndexAttOptions()

static bytea** CopyIndexAttOptions ( bytea **  srcopts,
int  natts 
)
static

Definition at line 5867 of file relcache.c.

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

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 952 of file relcache.c.

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

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

Referenced by equalRSDesc().

◆ equalRSDesc()

static bool equalRSDesc ( RowSecurityDesc rsdesc1,
RowSecurityDesc rsdesc2 
)
static

Definition at line 998 of file relcache.c.

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

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

Referenced by RelationRebuildRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 907 of file relcache.c.

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

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

Referenced by RelationRebuildRelation().

◆ errtable()

int errtable ( Relation  rel)

Definition at line 5948 of file relcache.c.

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

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

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

◆ errtablecol()

int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 5965 of file relcache.c.

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

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 5989 of file relcache.c.

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

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ formrdesc()

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

Definition at line 1874 of file relcache.c.

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

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

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4416 of file relcache.c.

4417 {
4418  static TupleDesc pgclassdesc = NULL;
4419 
4420  /* Already done? */
4421  if (pgclassdesc == NULL)
4422  pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4423  Desc_pg_class);
4424 
4425  return pgclassdesc;
4426 }
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4386
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class]
Definition: relcache.c:111

References BuildHardcodedDescriptor(), and Desc_pg_class.

Referenced by RelationParseRelOptions().

◆ GetPgIndexDescriptor()

static TupleDesc GetPgIndexDescriptor ( void  )
static

Definition at line 4429 of file relcache.c.

4430 {
4431  static TupleDesc pgindexdesc = NULL;
4432 
4433  /* Already done? */
4434  if (pgindexdesc == NULL)
4435  pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4436  Desc_pg_index);
4437 
4438  return pgindexdesc;
4439 }
static const FormData_pg_attribute Desc_pg_index[Natts_pg_index]
Definition: relcache.c:118

References BuildHardcodedDescriptor(), and Desc_pg_index.

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

◆ IndexSupportInitialize()

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

Definition at line 1596 of file relcache.c.

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

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

Referenced by RelationInitIndexAccessInfo().

◆ InitIndexAmRoutine()

static void InitIndexAmRoutine ( Relation  relation)
static

Definition at line 1401 of file relcache.c.

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

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

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1800 of file relcache.c.

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

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

Referenced by RelationInitTableAccessMethod().

◆ load_critical_index()

static void load_critical_index ( Oid  indexoid,
Oid  heapoid 
)
static

Definition at line 4348 of file relcache.c.

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

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

Referenced by RelationCacheInitializePhase3().

◆ load_relcache_init_file()

static bool load_relcache_init_file ( bool  shared)
static

Definition at line 6066 of file relcache.c.

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

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

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ LookupOpclassInfo()

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

Definition at line 1647 of file relcache.c.

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

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

Referenced by IndexSupportInitialize().

◆ RelationAssumeNewRelfilelocator()

void RelationAssumeNewRelfilelocator ( Relation  relation)

Definition at line 3932 of file relcache.c.

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

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

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1039 of file relcache.c.

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

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

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

◆ RelationBuildLocalRelation()

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

Definition at line 3481 of file relcache.c.

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

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

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5719 of file relcache.c.

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

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

Referenced by CheckCmdReplicaIdentity().

◆ RelationBuildRuleLock()

static void RelationBuildRuleLock ( Relation  relation)
static

Definition at line 732 of file relcache.c.

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

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 522 of file relcache.c.

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

References AccessShareLock, AttrMissing::am_present, AttrMissing::am_value, array_get_element(), Assert, attnum, AttrDefaultFetch(), ATTRIBUTE_FIXED_PART_SIZE, BTEqualStrategyNumber, BTGreaterStrategyNumber, CacheMemoryContext, CheckConstraintFetch(), TupleDescData::constr, criticalRelcachesBuilt, datumCopy(), elog, ERROR, GETSTRUCT, TupleConstr::has_generated_stored, TupleConstr::has_not_null, heap_getattr(), HeapTupleIsValid, i, Int16GetDatum(), MemoryContextAllocZero(), MemoryContextSwitchTo(), TupleConstr::missing, TupleConstr::num_check, TupleConstr::num_defval, ObjectIdGetDatum(), pfree(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, and TupleDescAttr.

Referenced by RelationBuildDesc().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6782 of file relcache.c.

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

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6757 of file relcache.c.

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

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

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

◆ RelationCacheInitFileRemove()

void RelationCacheInitFileRemove ( void  )

Definition at line 6797 of file relcache.c.

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

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

Referenced by StartupXLOG().

◆ RelationCacheInitFileRemoveInDir()

static void RelationCacheInitFileRemoveInDir ( const char *  tblspcpath)
static

Definition at line 6830 of file relcache.c.

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

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

Referenced by RelationCacheInitFileRemove().

◆ RelationCacheInitialize()

void RelationCacheInitialize ( void  )

Definition at line 3958 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase2()

void RelationCacheInitializePhase2 ( void  )

Definition at line 4004 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInitializePhase3()

void RelationCacheInitializePhase3 ( void  )

Definition at line 4063 of file relcache.c.

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

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

Referenced by InitPostgres().

◆ RelationCacheInvalidate()

void RelationCacheInvalidate ( bool  debug_discard)

Definition at line 2960 of file relcache.c.

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2904 of file relcache.c.

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

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

Referenced by LocalExecuteInvalidationMessage().

◆ RelationClearRelation()

static void RelationClearRelation ( Relation  relation)
static

Definition at line 2511 of file relcache.c.

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

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

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

◆ RelationClose()

void RelationClose ( Relation  relation)

Definition at line 2184 of file relcache.c.

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

References RelationCloseCleanup(), and RelationDecrementReferenceCount().

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

◆ RelationCloseCleanup()

static void RelationCloseCleanup ( Relation  relation)
static

Definition at line 2193 of file relcache.c.

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

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

Referenced by RelationClose(), and ResOwnerReleaseRelation().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2164 of file relcache.c.

2165 {
2166  Assert(rel->rd_refcnt > 0);
2167  rel->rd_refcnt -= 1;
2170 }
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2137
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

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

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

◆ RelationDestroyRelation()

static void RelationDestroyRelation ( Relation  relation,
bool  remember_tupdesc 
)
static

Definition at line 2404 of file relcache.c.

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

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

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

◆ RelationFlushRelation()

static void RelationFlushRelation ( Relation  relation)
static

Definition at line 2793 of file relcache.c.

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

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

Referenced by RelationCacheInvalidateEntry().

◆ RelationForgetRelation()

void RelationForgetRelation ( Oid  rid)

Definition at line 2859 of file relcache.c.

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

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ RelationGetDummyIndexExpressions()

List* RelationGetDummyIndexExpressions ( Relation  relation)

Definition at line 5087 of file relcache.c.

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

References Assert, exprCollation(), exprType(), exprTypmod(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), lappend(), lfirst, makeConst(), NIL, pfree(), RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by BuildDummyIndexInfo().

◆ RelationGetExclusionInfo()

void RelationGetExclusionInfo ( Relation  indexRelation,
Oid **  operators,
Oid **  procs,
uint16 **  strategies 
)

Definition at line 5584 of file relcache.c.

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

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

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

◆ RelationGetFKeyList()

List* RelationGetFKeyList ( Relation  relation)

Definition at line 4658 of file relcache.c.

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

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conoid, ForeignKeyCacheInfo::conrelid, copyObject, DeconstructFkConstraintRow(), GETSTRUCT, HeapTupleIsValid, lappend(), list_free_deep(), makeNode, MemoryContextSwitchTo(), NIL, ForeignKeyCacheInfo::nkeys, ObjectIdGetDatum(), RelationData::rd_fkeylist, RelationData::rd_fkeyvalid, RelationData::rd_rel, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferencing(), CloneFkReferencing(), DetachPartitionFinalize(), and get_relation_foreign_keys().

◆ RelationGetIdentityKeyBitmap()

Bitmapset* RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5507 of file relcache.c.

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

References Assert, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, ERROR, FirstLowInvalidHeapAttributeNumber, HistoricSnapshotActive(), i, MemoryContextSwitchTo(), OidIsValid, RelationData::rd_idattr, RelationData::rd_index, RelationDa