Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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 CheckNNConstraintFetch (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 3999 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:956
#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:476
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:500
#define RelationGetRelationName(relation)
Definition: rel.h:550

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

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

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

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

3380{
3381 HASH_SEQ_STATUS status;
3382 RelIdCacheEnt *idhentry;
3383 int i;
3384
3385 /*
3386 * Forget in_progress_list. This is relevant when we're aborting due to
3387 * an error during RelationBuildDesc(). We don't commit subtransactions
3388 * during RelationBuildDesc().
3389 */
3390 Assert(in_progress_list_len == 0 || !isCommit);
3392
3393 /*
3394 * Unless the eoxact_list[] overflowed, we only need to examine the rels
3395 * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3396 * logic as in AtEOXact_RelationCache.
3397 */
3399 {
3401 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3402 {
3403 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3404 mySubid, parentSubid);
3405 }
3406 }
3407 else
3408 {
3409 for (i = 0; i < eoxact_list_len; i++)
3410 {
3412 &eoxact_list[i],
3413 HASH_FIND,
3414 NULL);
3415 if (idhentry != NULL)
3416 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3417 mySubid, parentSubid);
3418 }
3419 }
3420
3421 /* Don't reset the list; we still need more cleanup later */
3422}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1421
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1386
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:77
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:3433
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 3296 of file relcache.c.

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

3227{
3228 HASH_SEQ_STATUS status;
3229 RelIdCacheEnt *idhentry;
3230 int i;
3231
3232 /*
3233 * Forget in_progress_list. This is relevant when we're aborting due to
3234 * an error during RelationBuildDesc().
3235 */
3236 Assert(in_progress_list_len == 0 || !isCommit);
3238
3239 /*
3240 * Unless the eoxact_list[] overflowed, we only need to examine the rels
3241 * listed in it. Otherwise fall back on a hash_seq_search scan.
3242 *
3243 * For simplicity, eoxact_list[] entries are not deleted till end of
3244 * top-level transaction, even though we could remove them at
3245 * subtransaction end in some cases, or remove relations from the list if
3246 * they are cleared for other reasons. Therefore we should expect the
3247 * case that list entries are not found in the hashtable; if not, there's
3248 * nothing to do for them.
3249 */
3251 {
3253 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3254 {
3255 AtEOXact_cleanup(idhentry->reldesc, isCommit);
3256 }
3257 }
3258 else
3259 {
3260 for (i = 0; i < eoxact_list_len; i++)
3261 {
3263 &eoxact_list[i],
3264 HASH_FIND,
3265 NULL);
3266 if (idhentry != NULL)
3267 AtEOXact_cleanup(idhentry->reldesc, isCommit);
3268 }
3269 }
3270
3272 {
3274 for (i = 0; i < NextEOXactTupleDescNum; i++)
3277 EOXactTupleDescArray = NULL;
3278 }
3279
3280 /* Now we're out of the transaction and can clear the lists */
3281 eoxact_list_len = 0;
3282 eoxact_list_overflowed = false;
3285}
void pfree(void *pointer)
Definition: mcxt.c:1528
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:3296
static TupleDesc * EOXactTupleDescArray
Definition: relcache.c:202
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495

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

4576{
4577 const AttrDefault *ada = (const AttrDefault *) a;
4578 const AttrDefault *adb = (const AttrDefault *) b;
4579
4580 return pg_cmp_s16(ada->adnum, adb->adnum);
4581}
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:634
int b
Definition: isn.c:74
int a
Definition: isn.c:73
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 4495 of file relcache.c.

4496{
4497 AttrDefault *attrdef;
4498 Relation adrel;
4499 SysScanDesc adscan;
4500 ScanKeyData skey;
4501 HeapTuple htup;
4502 int found = 0;
4503
4504 /* Allocate array with room for as many entries as expected */
4505 attrdef = (AttrDefault *)
4507 ndef * sizeof(AttrDefault));
4508
4509 /* Search pg_attrdef for relevant entries */
4510 ScanKeyInit(&skey,
4511 Anum_pg_attrdef_adrelid,
4512 BTEqualStrategyNumber, F_OIDEQ,
4514
4515 adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4516 adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4517 NULL, 1, &skey);
4518
4519 while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4520 {
4521 Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4522 Datum val;
4523 bool isnull;
4524
4525 /* protect limited size of array */
4526 if (found >= ndef)
4527 {
4528 elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4529 adform->adnum, RelationGetRelationName(relation));
4530 break;
4531 }
4532
4533 val = fastgetattr(htup,
4534 Anum_pg_attrdef_adbin,
4535 adrel->rd_att, &isnull);
4536 if (isnull)
4537 elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4538 adform->adnum, RelationGetRelationName(relation));
4539 else
4540 {
4541 /* detoast and convert to cstring in caller's context */
4542 char *s = TextDatumGetCString(val);
4543
4544 attrdef[found].adnum = adform->adnum;
4545 attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4546 pfree(s);
4547 found++;
4548 }
4549 }
4550
4551 systable_endscan(adscan);
4553
4554 if (found != ndef)
4555 elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4556 ndef - found, RelationGetRelationName(relation));
4557
4558 /*
4559 * Sort the AttrDefault entries by adnum, for the convenience of
4560 * equalTupleDescs(). (Usually, they already will be in order, but this
4561 * might not be so if systable_getnext isn't using an index.)
4562 */
4563 if (found > 1)
4564 qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4565
4566 /* Install array only after it's fully valid */
4567 relation->rd_att->constr->defval = attrdef;
4568 relation->rd_att->constr->num_defval = found;
4569}
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:861
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1690
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1219
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:479
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define RelationGetRelid(relation)
Definition: rel.h:516
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4575
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:40
uint16 num_defval
Definition: tupdesc.h:43
TupleConstr * constr
Definition: tupdesc.h:141
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 4430 of file relcache.c.

4431{
4432 TupleDesc result;
4433 MemoryContext oldcxt;
4434 int i;
4435
4437
4438 result = CreateTemplateTupleDesc(natts);
4439 result->tdtypeid = RECORDOID; /* not right, but we don't care */
4440 result->tdtypmod = -1;
4441
4442 for (i = 0; i < natts; i++)
4443 {
4444 memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4445
4447 }
4448
4449 /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4450 TupleDescCompactAttr(result, 0)->attcacheoff = 0;
4451
4452 /* Note: we don't bother to set up a TupleConstr entry */
4453
4454 MemoryContextSwitchTo(oldcxt);
4455
4456 return result;
4457}
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:194
int32 attcacheoff
Definition: tupdesc.h:70
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:117
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175

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

Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().

◆ CheckConstraintCmp()

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

Definition at line 4708 of file relcache.c.

4709{
4710 const ConstrCheck *ca = (const ConstrCheck *) a;
4711 const ConstrCheck *cb = (const ConstrCheck *) b;
4712
4713 return strcmp(ca->ccname, cb->ccname);
4714}
char * ccname
Definition: tupdesc.h:30

References a, b, and ConstrCheck::ccname.

Referenced by CheckNNConstraintFetch().

◆ CheckNNConstraintFetch()

static void CheckNNConstraintFetch ( Relation  relation)
static

Definition at line 4591 of file relcache.c.

4592{
4593 ConstrCheck *check;
4594 int ncheck = relation->rd_rel->relchecks;
4595 Relation conrel;
4596 SysScanDesc conscan;
4597 ScanKeyData skey[1];
4598 HeapTuple htup;
4599 int found = 0;
4600
4601 /* Allocate array with room for as many entries as expected, if needed */
4602 if (ncheck > 0)
4603 check = (ConstrCheck *)
4605 ncheck * sizeof(ConstrCheck));
4606 else
4607 check = NULL;
4608
4609 /* Search pg_constraint for relevant entries */
4610 ScanKeyInit(&skey[0],
4611 Anum_pg_constraint_conrelid,
4612 BTEqualStrategyNumber, F_OIDEQ,
4614
4615 conrel = table_open(ConstraintRelationId, AccessShareLock);
4616 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4617 NULL, 1, skey);
4618
4619 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4620 {
4622 Datum val;
4623 bool isnull;
4624
4625 /*
4626 * If this is a not-null constraint, then only look at it if it's
4627 * invalid, and if so, mark the TupleDesc entry as known invalid.
4628 * Otherwise move on. We'll mark any remaining columns that are still
4629 * in UNKNOWN state as known valid later. This allows us not to have
4630 * to extract the attnum from this constraint tuple in the vast
4631 * majority of cases.
4632 */
4633 if (conform->contype == CONSTRAINT_NOTNULL)
4634 {
4635 if (!conform->convalidated)
4636 {
4638
4642 relation->rd_att->compact_attrs[attnum - 1].attnullability =
4644 }
4645
4646 continue;
4647 }
4648
4649 /* For what follows, consider check constraints only */
4650 if (conform->contype != CONSTRAINT_CHECK)
4651 continue;
4652
4653 /* protect limited size of array */
4654 if (found >= ncheck)
4655 {
4656 elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4657 RelationGetRelationName(relation));
4658 break;
4659 }
4660
4661 check[found].ccenforced = conform->conenforced;
4662 check[found].ccvalid = conform->convalidated;
4663 check[found].ccnoinherit = conform->connoinherit;
4665 NameStr(conform->conname));
4666
4667 /* Grab and test conbin is actually set */
4668 val = fastgetattr(htup,
4669 Anum_pg_constraint_conbin,
4670 conrel->rd_att, &isnull);
4671 if (isnull)
4672 elog(WARNING, "null conbin for relation \"%s\"",
4673 RelationGetRelationName(relation));
4674 else
4675 {
4676 /* detoast and convert to cstring in caller's context */
4677 char *s = TextDatumGetCString(val);
4678
4679 check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4680 pfree(s);
4681 found++;
4682 }
4683 }
4684
4685 systable_endscan(conscan);
4687
4688 if (found != ncheck)
4689 elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4690 ncheck - found, RelationGetRelationName(relation));
4691
4692 /*
4693 * Sort the records by name. This ensures that CHECKs are applied in a
4694 * deterministic order, and it also makes equalTupleDescs() faster.
4695 */
4696 if (found > 1)
4697 qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4698
4699 /* Install array only after it's fully valid */
4700 relation->rd_att->constr->check = check;
4701 relation->rd_att->constr->num_check = found;
4702}
int16 AttrNumber
Definition: attnum.h:21
#define NameStr(name)
Definition: c.h:717
int16 attnum
Definition: pg_attribute.h:74
AttrNumber extractNotNullColumn(HeapTuple constrTup)
FormData_pg_constraint * Form_pg_constraint
static int CheckConstraintCmp(const void *a, const void *b)
Definition: relcache.c:4708
char attnullability
Definition: tupdesc.h:79
bool ccenforced
Definition: tupdesc.h:32
bool ccnoinherit
Definition: tupdesc.h:34
bool ccvalid
Definition: tupdesc.h:33
char * ccbin
Definition: tupdesc.h:31
ConstrCheck * check
Definition: tupdesc.h:41
uint16 num_check
Definition: tupdesc.h:44
CompactAttribute compact_attrs[FLEXIBLE_ARRAY_MEMBER]
Definition: tupdesc.h:143
#define ATTNULLABLE_UNKNOWN
Definition: tupdesc.h:85
#define ATTNULLABLE_INVALID
Definition: tupdesc.h:87

References AccessShareLock, Assert(), CompactAttribute::attnullability, ATTNULLABLE_INVALID, ATTNULLABLE_UNKNOWN, attnum, BTEqualStrategyNumber, CacheMemoryContext, ConstrCheck::ccbin, ConstrCheck::ccenforced, ConstrCheck::ccname, ConstrCheck::ccnoinherit, ConstrCheck::ccvalid, TupleConstr::check, CheckConstraintCmp(), TupleDescData::compact_attrs, TupleDescData::constr, elog, extractNotNullColumn(), 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 5968 of file relcache.c.

5969{
5970 bytea **opts = palloc(sizeof(*opts) * natts);
5971
5972 for (int i = 0; i < natts; i++)
5973 {
5974 bytea *opt = srcopts[i];
5975
5976 opts[i] = !opt ? NULL : (bytea *)
5977 DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5978 }
5979
5980 return opts;
5981}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
static AmcheckOptions opts
Definition: pg_amcheck.c:112
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
Definition: c.h:658

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 972 of file relcache.c.

973{
974 int i;
975 Oid *r1,
976 *r2;
977
978 if (policy1 != NULL)
979 {
980 if (policy2 == NULL)
981 return false;
982
983 if (policy1->polcmd != policy2->polcmd)
984 return false;
985 if (policy1->hassublinks != policy2->hassublinks)
986 return false;
987 if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
988 return false;
989 if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
990 return false;
991
992 r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
993 r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
994
995 for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
996 {
997 if (r1[i] != r2[i])
998 return false;
999 }
1000
1001 if (!equal(policy1->qual, policy2->qual))
1002 return false;
1003 if (!equal(policy1->with_check_qual, policy2->with_check_qual))
1004 return false;
1005 }
1006 else if (policy2 != NULL)
1007 return false;
1008
1009 return true;
1010}
#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:30
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 1018 of file relcache.c.

1019{
1020 ListCell *lc,
1021 *rc;
1022
1023 if (rsdesc1 == NULL && rsdesc2 == NULL)
1024 return true;
1025
1026 if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1027 (rsdesc1 == NULL && rsdesc2 != NULL))
1028 return false;
1029
1030 if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1031 return false;
1032
1033 /* RelationBuildRowSecurity should build policies in order */
1034 forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1035 {
1038
1039 if (!equalPolicy(l, r))
1040 return false;
1041 }
1042
1043 return true;
1044}
#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:972

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

Referenced by RelationRebuildRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 927 of file relcache.c.

928{
929 int i;
930
931 /*
932 * As of 7.3 we assume the rule ordering is repeatable, because
933 * RelationBuildRuleLock should read 'em in a consistent order. So just
934 * compare corresponding slots.
935 */
936 if (rlock1 != NULL)
937 {
938 if (rlock2 == NULL)
939 return false;
940 if (rlock1->numLocks != rlock2->numLocks)
941 return false;
942 for (i = 0; i < rlock1->numLocks; i++)
943 {
944 RewriteRule *rule1 = rlock1->rules[i];
945 RewriteRule *rule2 = rlock2->rules[i];
946
947 if (rule1->ruleId != rule2->ruleId)
948 return false;
949 if (rule1->event != rule2->event)
950 return false;
951 if (rule1->enabled != rule2->enabled)
952 return false;
953 if (rule1->isInstead != rule2->isInstead)
954 return false;
955 if (!equal(rule1->qual, rule2->qual))
956 return false;
957 if (!equal(rule1->actions, rule2->actions))
958 return false;
959 }
960 }
961 else if (rlock2 != NULL)
962 return false;
963 return true;
964}
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 6049 of file relcache.c.

6050{
6054
6055 return 0; /* return value does not matter */
6056}
int err_generic_string(int field, const char *str)
Definition: elog.c:1534
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3506
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:60
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:61
#define RelationGetNamespace(relation)
Definition: rel.h:557

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

6067{
6068 TupleDesc reldesc = RelationGetDescr(rel);
6069 const char *colname;
6070
6071 /* Use reldesc if it's a user attribute, else consult the catalogs */
6072 if (attnum > 0 && attnum <= reldesc->natts)
6073 colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
6074 else
6075 colname = get_attname(RelationGetRelid(rel), attnum, false);
6076
6077 return errtablecolname(rel, colname);
6078}
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:919
NameData attname
Definition: pg_attribute.h:41
#define RelationGetDescr(relation)
Definition: rel.h:542
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:6090

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 6090 of file relcache.c.

6091{
6092 errtable(rel);
6094
6095 return 0; /* return value does not matter */
6096}
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:62
int errtable(Relation rel)
Definition: relcache.c:6049

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

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

References CompactAttribute::attcacheoff, ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateTemplateTupleDesc(), GetHeapamTableAmRoutine(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidRelFileNumber, InvalidSubTransactionId, IsBootstrapProcessingMode, namestrcpy(), palloc0(), populate_compact_attribute(), 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, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().

◆ GetPgClassDescriptor()

static TupleDesc GetPgClassDescriptor ( void  )
static

Definition at line 4460 of file relcache.c.

4461{
4462 static TupleDesc pgclassdesc = NULL;
4463
4464 /* Already done? */
4465 if (pgclassdesc == NULL)
4466 pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4468
4469 return pgclassdesc;
4470}
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4430
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 4473 of file relcache.c.

4474{
4475 static TupleDesc pgindexdesc = NULL;
4476
4477 /* Already done? */
4478 if (pgindexdesc == NULL)
4479 pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4481
4482 return pgindexdesc;
4483}
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 1616 of file relcache.c.

1622{
1623 int attIndex;
1624
1625 for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1626 {
1627 OpClassCacheEnt *opcentry;
1628
1629 if (!OidIsValid(indclass->values[attIndex]))
1630 elog(ERROR, "bogus pg_index tuple");
1631
1632 /* look up the info for this opclass, using a cache */
1633 opcentry = LookupOpclassInfo(indclass->values[attIndex],
1634 maxSupportNumber);
1635
1636 /* copy cached data into relcache entry */
1637 opFamily[attIndex] = opcentry->opcfamily;
1638 opcInType[attIndex] = opcentry->opcintype;
1639 if (maxSupportNumber > 0)
1640 memcpy(&indexSupport[attIndex * maxSupportNumber],
1641 opcentry->supportProcs,
1642 maxSupportNumber * sizeof(RegProcedure));
1643 }
1644}
regproc RegProcedure
Definition: c.h:621
#define OidIsValid(objectId)
Definition: c.h:746
#define ERROR
Definition: elog.h:39
static OpClassCacheEnt * LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport)
Definition: relcache.c:1667
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:704
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 1421 of file relcache.c.

1422{
1423 IndexAmRoutine *cached,
1424 *tmp;
1425
1426 /*
1427 * Call the amhandler in current, short-lived memory context, just in case
1428 * it leaks anything (it probably won't, but let's be paranoid).
1429 */
1430 tmp = GetIndexAmRoutine(relation->rd_amhandler);
1431
1432 /* OK, now transfer the data into relation's rd_indexcxt. */
1433 cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
1434 sizeof(IndexAmRoutine));
1435 memcpy(cached, tmp, sizeof(IndexAmRoutine));
1436 relation->rd_indam = cached;
1437
1438 pfree(tmp);
1439}
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1185
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 1820 of file relcache.c.

1821{
1822 relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1823}
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 4392 of file relcache.c.

4393{
4394 Relation ird;
4395
4396 /*
4397 * We must lock the underlying catalog before locking the index to avoid
4398 * deadlock, since RelationBuildDesc might well need to read the catalog,
4399 * and if anyone else is exclusive-locking this catalog and index they'll
4400 * be doing it in that order.
4401 */
4404 ird = RelationBuildDesc(indexoid, true);
4405 if (ird == NULL)
4406 ereport(PANIC,
4408 errmsg_internal("could not open critical system index %u", indexoid));
4409 ird->rd_isnailed = true;
4410 ird->rd_refcnt = 1;
4413
4414 (void) RelationGetIndexAttOptions(ird, false);
4415}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1158
int errcode(int sqlerrcode)
Definition: elog.c:854
#define PANIC
Definition: elog.h:42
#define ereport(elevel,...)
Definition: elog.h:149
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:229
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:1059
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5988

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

6168{
6169 FILE *fp;
6170 char initfilename[MAXPGPATH];
6171 Relation *rels;
6172 int relno,
6173 num_rels,
6174 max_rels,
6175 nailed_rels,
6176 nailed_indexes,
6177 magic;
6178 int i;
6179
6180 if (shared)
6181 snprintf(initfilename, sizeof(initfilename), "global/%s",
6183 else
6184 snprintf(initfilename, sizeof(initfilename), "%s/%s",
6186
6187 fp = AllocateFile(initfilename, PG_BINARY_R);
6188 if (fp == NULL)
6189 return false;
6190
6191 /*
6192 * Read the index relcache entries from the file. Note we will not enter
6193 * any of them into the cache if the read fails partway through; this
6194 * helps to guard against broken init files.
6195 */
6196 max_rels = 100;
6197 rels = (Relation *) palloc(max_rels * sizeof(Relation));
6198 num_rels = 0;
6199 nailed_rels = nailed_indexes = 0;
6200
6201 /* check for correct magic number (compatible version) */
6202 if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6203 goto read_failed;
6204 if (magic != RELCACHE_INIT_FILEMAGIC)
6205 goto read_failed;
6206
6207 for (relno = 0;; relno++)
6208 {
6209 Size len;
6210 size_t nread;
6211 Relation rel;
6212 Form_pg_class relform;
6213 bool has_not_null;
6214
6215 /* first read the relation descriptor length */
6216 nread = fread(&len, 1, sizeof(len), fp);
6217 if (nread != sizeof(len))
6218 {
6219 if (nread == 0)
6220 break; /* end of file */
6221 goto read_failed;
6222 }
6223
6224 /* safety check for incompatible relcache layout */
6225 if (len != sizeof(RelationData))
6226 goto read_failed;
6227
6228 /* allocate another relcache header */
6229 if (num_rels >= max_rels)
6230 {
6231 max_rels *= 2;
6232 rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
6233 }
6234
6235 rel = rels[num_rels++] = (Relation) palloc(len);
6236
6237 /* then, read the Relation structure */
6238 if (fread(rel, 1, len, fp) != len)
6239 goto read_failed;
6240
6241 /* next read the relation tuple form */
6242 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6243 goto read_failed;
6244
6245 relform = (Form_pg_class) palloc(len);
6246 if (fread(relform, 1, len, fp) != len)
6247 goto read_failed;
6248
6249 rel->rd_rel = relform;
6250
6251 /* initialize attribute tuple forms */
6252 rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
6253 rel->rd_att->tdrefcount = 1; /* mark as refcounted */
6254
6255 rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
6256 rel->rd_att->tdtypmod = -1; /* just to be sure */
6257
6258 /* next read all the attribute tuple form data entries */
6259 has_not_null = false;
6260 for (i = 0; i < relform->relnatts; i++)
6261 {
6263
6264 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6265 goto read_failed;
6267 goto read_failed;
6268 if (fread(attr, 1, len, fp) != len)
6269 goto read_failed;
6270
6271 has_not_null |= attr->attnotnull;
6272
6274 }
6275
6276 /* next read the access method specific field */
6277 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6278 goto read_failed;
6279 if (len > 0)
6280 {
6281 rel->rd_options = palloc(len);
6282 if (fread(rel->rd_options, 1, len, fp) != len)
6283 goto read_failed;
6284 if (len != VARSIZE(rel->rd_options))
6285 goto read_failed; /* sanity check */
6286 }
6287 else
6288 {
6289 rel->rd_options = NULL;
6290 }
6291
6292 /* mark not-null status */
6293 if (has_not_null)
6294 {
6295 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
6296
6297 constr->has_not_null = true;
6298 rel->rd_att->constr = constr;
6299 }
6300
6301 /*
6302 * If it's an index, there's more to do. Note we explicitly ignore
6303 * partitioned indexes here.
6304 */
6305 if (rel->rd_rel->relkind == RELKIND_INDEX)
6306 {
6307 MemoryContext indexcxt;
6308 Oid *opfamily;
6309 Oid *opcintype;
6310 RegProcedure *support;
6311 int nsupport;
6312 int16 *indoption;
6313 Oid *indcollation;
6314
6315 /* Count nailed indexes to ensure we have 'em all */
6316 if (rel->rd_isnailed)
6317 nailed_indexes++;
6318
6319 /* read the pg_index tuple */
6320 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6321 goto read_failed;
6322
6324 if (fread(rel->rd_indextuple, 1, len, fp) != len)
6325 goto read_failed;
6326
6327 /* Fix up internal pointers in the tuple -- see heap_copytuple */
6330
6331 /*
6332 * prepare index info context --- parameters should match
6333 * RelationInitIndexAccessInfo
6334 */
6336 "index info",
6338 rel->rd_indexcxt = indexcxt;
6341
6342 /*
6343 * Now we can fetch the index AM's API struct. (We can't store
6344 * that in the init file, since it contains function pointers that
6345 * might vary across server executions. Fortunately, it should be
6346 * safe to call the amhandler even while bootstrapping indexes.)
6347 */
6348 InitIndexAmRoutine(rel);
6349
6350 /* read the vector of opfamily OIDs */
6351 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6352 goto read_failed;
6353
6354 opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
6355 if (fread(opfamily, 1, len, fp) != len)
6356 goto read_failed;
6357
6358 rel->rd_opfamily = opfamily;
6359
6360 /* read the vector of opcintype OIDs */
6361 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6362 goto read_failed;
6363
6364 opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
6365 if (fread(opcintype, 1, len, fp) != len)
6366 goto read_failed;
6367
6368 rel->rd_opcintype = opcintype;
6369
6370 /* read the vector of support procedure OIDs */
6371 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6372 goto read_failed;
6373 support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
6374 if (fread(support, 1, len, fp) != len)
6375 goto read_failed;
6376
6377 rel->rd_support = support;
6378
6379 /* read the vector of collation OIDs */
6380 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6381 goto read_failed;
6382
6383 indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
6384 if (fread(indcollation, 1, len, fp) != len)
6385 goto read_failed;
6386
6387 rel->rd_indcollation = indcollation;
6388
6389 /* read the vector of indoption values */
6390 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6391 goto read_failed;
6392
6393 indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
6394 if (fread(indoption, 1, len, fp) != len)
6395 goto read_failed;
6396
6397 rel->rd_indoption = indoption;
6398
6399 /* read the vector of opcoptions values */
6400 rel->rd_opcoptions = (bytea **)
6401 MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
6402
6403 for (i = 0; i < relform->relnatts; i++)
6404 {
6405 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6406 goto read_failed;
6407
6408 if (len > 0)
6409 {
6410 rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
6411 if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
6412 goto read_failed;
6413 }
6414 }
6415
6416 /* set up zeroed fmgr-info vector */
6417 nsupport = relform->relnatts * rel->rd_indam->amsupport;
6418 rel->rd_supportinfo = (FmgrInfo *)
6419 MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
6420 }
6421 else
6422 {
6423 /* Count nailed rels to ensure we have 'em all */
6424 if (rel->rd_isnailed)
6425 nailed_rels++;
6426
6427 /* Load table AM data */
6428 if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
6430
6431 Assert(rel->rd_index == NULL);
6432 Assert(rel->rd_indextuple == NULL);
6433 Assert(rel->rd_indexcxt == NULL);
6434 Assert(rel->rd_indam == NULL);
6435 Assert(rel->rd_opfamily == NULL);
6436 Assert(rel->rd_opcintype == NULL);
6437 Assert(rel->rd_support == NULL);
6438 Assert(rel->rd_supportinfo == NULL);
6439 Assert(rel->rd_indoption == NULL);
6440 Assert(rel->rd_indcollation == NULL);
6441 Assert(rel->rd_opcoptions == NULL);
6442 }
6443
6444 /*
6445 * Rules and triggers are not saved (mainly because the internal
6446 * format is complex and subject to change). They must be rebuilt if
6447 * needed by RelationCacheInitializePhase3. This is not expected to
6448 * be a big performance hit since few system catalogs have such. Ditto
6449 * for RLS policy data, partition info, index expressions, predicates,
6450 * exclusion info, and FDW info.
6451 */
6452 rel->rd_rules = NULL;
6453 rel->rd_rulescxt = NULL;
6454 rel->trigdesc = NULL;
6455 rel->rd_rsdesc = NULL;
6456 rel->rd_partkey = NULL;
6457 rel->rd_partkeycxt = NULL;
6458 rel->rd_partdesc = NULL;
6459 rel->rd_partdesc_nodetached = NULL;
6461 rel->rd_pdcxt = NULL;
6462 rel->rd_pddcxt = NULL;
6463 rel->rd_partcheck = NIL;
6464 rel->rd_partcheckvalid = false;
6465 rel->rd_partcheckcxt = NULL;
6466 rel->rd_indexprs = NIL;
6467 rel->rd_indpred = NIL;
6468 rel->rd_exclops = NULL;
6469 rel->rd_exclprocs = NULL;
6470 rel->rd_exclstrats = NULL;
6471 rel->rd_fdwroutine = NULL;
6472
6473 /*
6474 * Reset transient-state fields in the relcache entry
6475 */
6476 rel->rd_smgr = NULL;
6477 if (rel->rd_isnailed)
6478 rel->rd_refcnt = 1;
6479 else
6480 rel->rd_refcnt = 0;
6481 rel->rd_indexvalid = false;
6482 rel->rd_indexlist = NIL;
6483 rel->rd_pkindex = InvalidOid;
6485 rel->rd_attrsvalid = false;
6486 rel->rd_keyattr = NULL;
6487 rel->rd_pkattr = NULL;
6488 rel->rd_idattr = NULL;
6489 rel->rd_pubdesc = NULL;
6490 rel->rd_statvalid = false;
6491 rel->rd_statlist = NIL;
6492 rel->rd_fkeyvalid = false;
6493 rel->rd_fkeylist = NIL;
6498 rel->rd_amcache = NULL;
6499 rel->pgstat_info = NULL;
6500
6501 /*
6502 * Recompute lock and physical addressing info. This is needed in
6503 * case the pg_internal.init file was copied from some other database
6504 * by CREATE DATABASE.
6505 */
6508 }
6509
6510 /*
6511 * We reached the end of the init file without apparent problem. Did we
6512 * get the right number of nailed items? This is a useful crosscheck in
6513 * case the set of critical rels or indexes changes. However, that should
6514 * not happen in a normally-running system, so let's bleat if it does.
6515 *
6516 * For the shared init file, we're called before client authentication is
6517 * done, which means that elog(WARNING) will go only to the postmaster
6518 * log, where it's easily missed. To ensure that developers notice bad
6519 * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
6520 * an Assert(false) there.
6521 */
6522 if (shared)
6523 {
6524 if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
6525 nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
6526 {
6527 elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
6528 nailed_rels, nailed_indexes,
6530 /* Make sure we get developers' attention about this */
6531 Assert(false);
6532 /* In production builds, recover by bootstrapping the relcache */
6533 goto read_failed;
6534 }
6535 }
6536 else
6537 {
6538 if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
6539 nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
6540 {
6541 elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
6542 nailed_rels, nailed_indexes,
6544 /* We don't need an Assert() in this case */
6545 goto read_failed;
6546 }
6547 }
6548
6549 /*
6550 * OK, all appears well.
6551 *
6552 * Now insert all the new relcache entries into the cache.
6553 */
6554 for (relno = 0; relno < num_rels; relno++)
6555 {
6556 RelationCacheInsert(rels[relno], false);
6557 }
6558
6559 pfree(rels);
6560 FreeFile(fp);
6561
6562 if (shared)
6564 else
6566 return true;
6567
6568 /*
6569 * init file is broken, so do it the hard way. We don't bother trying to
6570 * free the clutter we just allocated; it's not in the relcache so it
6571 * won't hurt.
6572 */
6573read_failed:
6574 pfree(rels);
6575 FreeFile(fp);
6576
6577 return false;
6578}
#define PG_BINARY_R
Definition: c.h:1246
size_t Size
Definition: c.h:576
int FreeFile(FILE *file)
Definition: fd.c:2843
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2644
char * DatabasePath
Definition: globals.c:104
#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:1548
#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:202
#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:239
#define InvalidOid
Definition: postgres_ext.h:35
#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:1421
#define NUM_CRITICAL_SHARED_RELS
void RelationInitTableAccessMethod(Relation relation)
Definition: relcache.c:1829
#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:240
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, populate_compact_attribute(), 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 1667 of file relcache.c.

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

3977{
3981
3982 /* Flag relation as needing eoxact cleanup (to clear these fields) */
3983 EOXactListAdd(relation);
3984}
#define EOXactListAdd(rel)
Definition: relcache.c:189
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791

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

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

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

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

References Assert(), CompactAttribute::attnullability, 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(), populate_compact_attribute(), 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, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5794 of file relcache.c.

5795{
5796 List *puboids;
5797 ListCell *lc;
5798 MemoryContext oldcxt;
5799 Oid schemaid;
5800 List *ancestors = NIL;
5801 Oid relid = RelationGetRelid(relation);
5802
5803 /*
5804 * If not publishable, it publishes no actions. (pgoutput_change() will
5805 * ignore it.)
5806 */
5807 if (!is_publishable_relation(relation))
5808 {
5809 memset(pubdesc, 0, sizeof(PublicationDesc));
5810 pubdesc->rf_valid_for_update = true;
5811 pubdesc->rf_valid_for_delete = true;
5812 pubdesc->cols_valid_for_update = true;
5813 pubdesc->cols_valid_for_delete = true;
5814 pubdesc->gencols_valid_for_update = true;
5815 pubdesc->gencols_valid_for_delete = true;
5816 return;
5817 }
5818
5819 if (relation->rd_pubdesc)
5820 {
5821 memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5822 return;
5823 }
5824
5825 memset(pubdesc, 0, sizeof(PublicationDesc));
5826 pubdesc->rf_valid_for_update = true;
5827 pubdesc->rf_valid_for_delete = true;
5828 pubdesc->cols_valid_for_update = true;
5829 pubdesc->cols_valid_for_delete = true;
5830 pubdesc->gencols_valid_for_update = true;
5831 pubdesc->gencols_valid_for_delete = true;
5832
5833 /* Fetch the publication membership info. */
5834 puboids = GetRelationPublications(relid);
5835 schemaid = RelationGetNamespace(relation);
5836 puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5837
5838 if (relation->rd_rel->relispartition)
5839 {
5840 /* Add publications that the ancestors are in too. */
5841 ancestors = get_partition_ancestors(relid);
5842
5843 foreach(lc, ancestors)
5844 {
5845 Oid ancestor = lfirst_oid(lc);
5846
5847 puboids = list_concat_unique_oid(puboids,
5848 GetRelationPublications(ancestor));
5849 schemaid = get_rel_namespace(ancestor);
5850 puboids = list_concat_unique_oid(puboids,
5851 GetSchemaPublications(schemaid));
5852 }
5853 }
5855
5856 foreach(lc, puboids)
5857 {
5858 Oid pubid = lfirst_oid(lc);
5859 HeapTuple tup;
5860 Form_pg_publication pubform;
5861 bool invalid_column_list;
5862 bool invalid_gen_col;
5863
5864 tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5865
5866 if (!HeapTupleIsValid(tup))
5867 elog(ERROR, "cache lookup failed for publication %u", pubid);
5868
5869 pubform = (Form_pg_publication) GETSTRUCT(tup);
5870
5871 pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5872 pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5873 pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5874 pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5875
5876 /*
5877 * Check if all columns referenced in the filter expression are part
5878 * of the REPLICA IDENTITY index or not.
5879 *
5880 * If the publication is FOR ALL TABLES then it means the table has no
5881 * row filters and we can skip the validation.
5882 */
5883 if (!pubform->puballtables &&
5884 (pubform->pubupdate || pubform->pubdelete) &&
5885 pub_rf_contains_invalid_column(pubid, relation, ancestors,
5886 pubform->pubviaroot))
5887 {
5888 if (pubform->pubupdate)
5889 pubdesc->rf_valid_for_update = false;
5890 if (pubform->pubdelete)
5891 pubdesc->rf_valid_for_delete = false;
5892 }
5893
5894 /*
5895 * Check if all columns are part of the REPLICA IDENTITY index or not.
5896 *
5897 * Check if all generated columns included in the REPLICA IDENTITY are
5898 * published.
5899 */
5900 if ((pubform->pubupdate || pubform->pubdelete) &&
5901 pub_contains_invalid_column(pubid, relation, ancestors,
5902 pubform->pubviaroot,
5903 pubform->pubgencols,
5904 &invalid_column_list,
5905 &invalid_gen_col))
5906 {
5907 if (pubform->pubupdate)
5908 {
5909 pubdesc->cols_valid_for_update = !invalid_column_list;
5910 pubdesc->gencols_valid_for_update = !invalid_gen_col;
5911 }
5912
5913 if (pubform->pubdelete)
5914 {
5915 pubdesc->cols_valid_for_delete = !invalid_column_list;
5916 pubdesc->gencols_valid_for_delete = !invalid_gen_col;
5917 }
5918 }
5919
5920 ReleaseSysCache(tup);
5921
5922 /*
5923 * If we know everything is replicated and the row filter is invalid
5924 * for update and delete, there is no point to check for other
5925 * publications.
5926 */
5927 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5928 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5929 !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5930 break;
5931
5932 /*
5933 * If we know everything is replicated and the column list is invalid
5934 * for update and delete, there is no point to check for other
5935 * publications.
5936 */
5937 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5938 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5939 !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5940 break;
5941
5942 /*
5943 * If we know everything is replicated and replica identity has an
5944 * unpublished generated column, there is no point to check for other
5945 * publications.
5946 */
5947 if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5948 pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5949 !pubdesc->gencols_valid_for_update &&
5950 !pubdesc->gencols_valid_for_delete)
5951 break;
5952 }
5953
5954 if (relation->rd_pubdesc)
5955 {
5956 pfree(relation->rd_pubdesc);
5957 relation->rd_pubdesc = NULL;
5958 }
5959
5960 /* Now save copy of the descriptor in the relcache entry. */
5962 relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
5963 memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5964 MemoryContextSwitchTo(oldcxt);
5965}
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2092
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * GetRelationPublications(Oid relid)
List * GetAllTablesPublications(void)
List * GetSchemaPublications(Oid schemaid)
bool is_publishable_relation(Relation rel)
FormData_pg_publication * Form_pg_publication
bool pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot, char pubgencols_type, bool *invalid_column_list, bool *invalid_gen_col)
bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
Definition: pg_list.h:54
PublicationActions pubactions
bool gencols_valid_for_update
bool gencols_valid_for_delete
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, PublicationDesc::gencols_valid_for_delete, PublicationDesc::gencols_valid_for_update, 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_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 752 of file relcache.c.

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

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

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

Referenced by RelationBuildDesc().

◆ RelationCacheInitFilePostInvalidate()

void RelationCacheInitFilePostInvalidate ( void  )

Definition at line 6885 of file relcache.c.

6886{
6887 LWLockRelease(RelCacheInitLock);
6888}
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1900

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6860 of file relcache.c.

6861{
6862 char localinitfname[MAXPGPATH];
6863 char sharedinitfname[MAXPGPATH];
6864
6865 if (DatabasePath)
6866 snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6868 snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6870
6871 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6872
6873 /*
6874 * The files might not be there if no backend has been started since the
6875 * last removal. But complain about failures other than ENOENT with
6876 * ERROR. Fortunately, it's not too late to abort the transaction if we
6877 * can't get rid of the would-be-obsolete init file.
6878 */
6879 if (DatabasePath)
6880 unlink_initfile(localinitfname, ERROR);
6881 unlink_initfile(sharedinitfname, ERROR);
6882}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1180
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6957

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

6901{
6902 const char *tblspcdir = PG_TBLSPC_DIR;
6903 DIR *dir;
6904 struct dirent *de;
6905 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6906
6907 snprintf(path, sizeof(path), "global/%s",
6909 unlink_initfile(path, LOG);
6910
6911 /* Scan everything in the default tablespace */
6913
6914 /* Scan the tablespace link directory to find non-default tablespaces */
6915 dir = AllocateDir(tblspcdir);
6916
6917 while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6918 {
6919 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6920 {
6921 /* Scan the tablespace dir for per-database dirs */
6922 snprintf(path, sizeof(path), "%s/%s/%s",
6923 tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6925 }
6926 }
6927
6928 FreeDir(dir);
6929}
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:3025
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2988
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2907
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6933
#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 6933 of file relcache.c.

6934{
6935 DIR *dir;
6936 struct dirent *de;
6937 char initfilename[MAXPGPATH * 2];
6938
6939 /* Scan the tablespace directory to find per-database directories */
6940 dir = AllocateDir(tblspcpath);
6941
6942 while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6943 {
6944 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6945 {
6946 /* Try to remove the init file in each database */
6947 snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6948 tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6949 unlink_initfile(initfilename, LOG);
6950 }
6951 }
6952
6953 FreeDir(dir);
6954}

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

4003{
4004 HASHCTL ctl;
4005 int allocsize;
4006
4007 /*
4008 * make sure cache memory context exists
4009 */
4010 if (!CacheMemoryContext)
4012
4013 /*
4014 * create hashtable that indexes the relcache
4015 */
4016 ctl.keysize = sizeof(Oid);
4017 ctl.entrysize = sizeof(RelIdCacheEnt);
4018 RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4020
4021 /*
4022 * reserve enough in_progress_list slots for many cases
4023 */
4024 allocsize = 4;
4027 allocsize * sizeof(*in_progress_list));
4028 in_progress_list_maxlen = allocsize;
4029
4030 /*
4031 * relation mapper needs to be initialized too
4032 */
4034}
#define INITRELCACHESIZE
Definition: relcache.c:3999
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 4048 of file relcache.c.

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

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

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

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

2939{
2940 Relation relation;
2941
2942 RelationIdCacheLookup(relationId, relation);
2943
2944 if (PointerIsValid(relation))
2945 {
2947 RelationFlushRelation(relation);
2948 }
2949 else
2950 {
2951 int i;
2952
2953 for (i = 0; i < in_progress_list_len; i++)
2954 if (in_progress_list[i].reloid == relationId)
2956 }
2957}
#define PointerIsValid(pointer)
Definition: c.h:734
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2827

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

2547{
2549 Assert(!relation->rd_isnailed);
2550
2551 /*
2552 * Relations created in the same transaction must never be removed, see
2553 * RelationFlushRelation.
2554 */
2558
2559 /* first mark it as invalid */
2561
2562 /* Remove it from the hash table */
2563 RelationCacheDelete(relation);
2564
2565 /* And release storage */
2566 RelationDestroyRelation(relation, false);
2567}
#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 2220 of file relcache.c.

2221{
2222 /* Note: no locking manipulations needed */
2224
2225 RelationCloseCleanup(relation);
2226}
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2229

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

2230{
2231 /*
2232 * If the relation is no longer open in this session, we can clean up any
2233 * stale partition descriptors it has. This is unlikely, so check to see
2234 * if there are child contexts before expending a call to mcxt.c.
2235 */
2236 if (RelationHasReferenceCountZero(relation))
2237 {
2238 if (relation->rd_pdcxt != NULL &&
2239 relation->rd_pdcxt->firstchild != NULL)
2241
2242 if (relation->rd_pddcxt != NULL &&
2243 relation->rd_pddcxt->firstchild != NULL)
2245 }
2246
2247#ifdef RELCACHE_FORCE_RELEASE
2248 if (RelationHasReferenceCountZero(relation) &&
2251 RelationClearRelation(relation);
2252#endif
2253}
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 2200 of file relcache.c.

2201{
2202 Assert(rel->rd_refcnt > 0);
2203 rel->rd_refcnt -= 1;
2206}
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2173
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173

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

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

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

2828{
2829 if (relation->rd_createSubid != InvalidSubTransactionId ||
2831 {
2832 /*
2833 * New relcache entries are always rebuilt, not flushed; else we'd
2834 * forget the "new" status of the relation. Ditto for the
2835 * new-relfilenumber status.
2836 */
2838 {
2839 /*
2840 * The rel could have zero refcnt here, so temporarily increment
2841 * the refcnt to ensure it's safe to rebuild it. We can assume
2842 * that the current transaction has some lock on the rel already.
2843 */
2845 RelationRebuildRelation(relation);
2847 }
2848 else
2850 }
2851 else
2852 {
2853 /*
2854 * Pre-existing rels can be dropped from the relcache if not open.
2855 *
2856 * If the entry is in use, rebuild it if possible. If we're not
2857 * inside a valid transaction, we can't do any catalog access so it's
2858 * not possible to rebuild yet. Just mark it as invalid in that case,
2859 * so that the rebuild will occur when the entry is next opened.
2860 *
2861 * Note: it's possible that we come here during subtransaction abort,
2862 * and the reason for wanting to rebuild is that the rel is open in
2863 * the outer transaction. In that case it might seem unsafe to not
2864 * rebuild immediately, since whatever code has the rel already open
2865 * will keep on using the relcache entry as-is. However, in such a
2866 * case the outer transaction should be holding a lock that's
2867 * sufficient to prevent any significant change in the rel's schema,
2868 * so the existing entry contents should be good enough for its
2869 * purposes; at worst we might be behind on statistics updates or the
2870 * like. (See also CheckTableNotInUse() and its callers.)
2871 */
2872 if (RelationHasReferenceCountZero(relation))
2873 RelationClearRelation(relation);
2874 else if (!IsTransactionState())
2876 else if (relation->rd_isnailed && relation->rd_refcnt == 1)
2877 {
2878 /*
2879 * A nailed relation with refcnt == 1 is unused. We cannot clear
2880 * it, but there's also no need no need to rebuild it immediately.
2881 */
2883 }
2884 else
2885 RelationRebuildRelation(relation);
2886 }
2887}

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

2894{
2895 Relation relation;
2896
2897 RelationIdCacheLookup(rid, relation);
2898
2899 if (!PointerIsValid(relation))
2900 return; /* not in cache, nothing to do */
2901
2902 if (!RelationHasReferenceCountZero(relation))
2903 elog(ERROR, "relation %u is still open", rid);
2904
2906 if (relation->rd_createSubid != InvalidSubTransactionId ||
2908 {
2909 /*
2910 * In the event of subtransaction rollback, we must not forget
2911 * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2912 * destroying it right away. (If we're in a top transaction, we could
2913 * opt to destroy the entry.)
2914 */
2917 }
2918 else
2919 RelationClearRelation(relation);
2920}

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

5157{
5158 List *result;
5159 Datum exprsDatum;
5160 bool isnull;
5161 char *exprsString;
5162 List *rawExprs;
5163 ListCell *lc;
5164
5165 /* Quick exit if there is nothing to do. */
5166 if (relation->rd_indextuple == NULL ||
5167 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5168 return NIL;
5169
5170 /* Extract raw node tree(s) from index tuple. */
5171 exprsDatum = heap_getattr(relation->rd_indextuple,
5172 Anum_pg_index_indexprs,
5174 &isnull);
5175 Assert(!isnull);
5176 exprsString = TextDatumGetCString(exprsDatum);
5177 rawExprs = (List *) stringToNode(exprsString);
5178 pfree(exprsString);
5179
5180 /* Construct null Consts; the typlen and typbyval are arbitrary. */
5181 result = NIL;
5182 foreach(lc, rawExprs)
5183 {
5184 Node *rawExpr = (Node *) lfirst(lc);
5185
5186 result = lappend(result,
5187 makeConst(exprType(rawExpr),
5188 exprTypmod(rawExpr),
5189 exprCollation(rawExpr),
5190 1,
5191 (Datum) 0,
5192 true,
5193 true));
5194 }
5195
5196 return result;
5197}
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:350
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
static TupleDesc GetPgIndexDescriptor(void)
Definition: relcache.c:4473

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

5657{
5658 int indnkeyatts;
5659 Oid *ops;
5660 Oid *funcs;
5661 uint16 *strats;
5662 Relation conrel;
5663 SysScanDesc conscan;
5664 ScanKeyData skey[1];
5665 HeapTuple htup;
5666 bool found;
5667 MemoryContext oldcxt;
5668 int i;
5669
5670 indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5671
5672 /* Allocate result space in caller context */
5673 *operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5674 *procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5675 *strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5676
5677 /* Quick exit if we have the data cached already */
5678 if (indexRelation->rd_exclstrats != NULL)
5679 {
5680 memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5681 memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5682 memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5683 return;
5684 }
5685
5686 /*
5687 * Search pg_constraint for the constraint associated with the index. To
5688 * make this not too painfully slow, we use the index on conrelid; that
5689 * will hold the parent relation's OID not the index's own OID.
5690 *
5691 * Note: if we wanted to rely on the constraint name matching the index's
5692 * name, we could just do a direct lookup using pg_constraint's unique
5693 * index. For the moment it doesn't seem worth requiring that.
5694 */
5695 ScanKeyInit(&skey[0],
5696 Anum_pg_constraint_conrelid,
5697 BTEqualStrategyNumber, F_OIDEQ,
5698 ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5699
5700 conrel = table_open(ConstraintRelationId, AccessShareLock);
5701 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5702 NULL, 1, skey);
5703 found = false;
5704
5705 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5706 {
5708 Datum val;
5709 bool isnull;
5710 ArrayType *arr;
5711 int nelem;
5712
5713 /* We want the exclusion constraint owning the index */
5714 if ((conform->contype != CONSTRAINT_EXCLUSION &&
5715 !(conform->conperiod && (conform->contype == CONSTRAINT_PRIMARY
5716 || conform->contype == CONSTRAINT_UNIQUE))) ||
5717 conform->conindid != RelationGetRelid(indexRelation))
5718 continue;
5719
5720 /* There should be only one */
5721 if (found)
5722 elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5723 RelationGetRelationName(indexRelation));
5724 found = true;
5725
5726 /* Extract the operator OIDS from conexclop */
5727 val = fastgetattr(htup,
5728 Anum_pg_constraint_conexclop,
5729 conrel->rd_att, &isnull);
5730 if (isnull)
5731 elog(ERROR, "null conexclop for rel %s",
5732 RelationGetRelationName(indexRelation));
5733
5734 arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5735 nelem = ARR_DIMS(arr)[0];
5736 if (ARR_NDIM(arr) != 1 ||
5737 nelem != indnkeyatts ||
5738 ARR_HASNULL(arr) ||
5739 ARR_ELEMTYPE(arr) != OIDOID)
5740 elog(ERROR, "conexclop is not a 1-D Oid array");
5741
5742 memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5743 }
5744
5745 systable_endscan(conscan);
5747
5748 if (!found)
5749 elog(ERROR, "exclusion constraint record missing for rel %s",
5750 RelationGetRelationName(indexRelation));
5751
5752 /* We need the func OIDs and strategy numbers too */
5753 for (i = 0; i < indnkeyatts; i++)
5754 {
5755 funcs[i] = get_opcode(ops[i]);
5756 strats[i] = get_op_opfamily_strategy(ops[i],
5757 indexRelation->rd_opfamily[i]);
5758 /* shouldn't fail, since it was checked at index creation */
5759 if (strats[i] == InvalidStrategy)
5760 elog(ERROR, "could not find strategy for operator %u in family %u",
5761 ops[i], indexRelation->rd_opfamily[i]);
5762 }
5763
5764 /* Save a copy of the results in the relcache entry. */
5765 oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5766 indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5767 indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
5768 indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
5769 memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5770 memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5771 memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5772 MemoryContextSwitchTo(oldcxt);
5773}
#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
uint16_t uint16
Definition: c.h:501
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1425
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:84
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:535
#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 4731 of file relcache.c.

4732{
4733 List *result;
4734 Relation conrel;
4735 SysScanDesc conscan;
4736 ScanKeyData skey;
4737 HeapTuple htup;
4738 List *oldlist;
4739 MemoryContext oldcxt;
4740
4741 /* Quick exit if we already computed the list. */
4742 if (relation->rd_fkeyvalid)
4743 return relation->rd_fkeylist;
4744
4745 /*
4746 * We build the list we intend to return (in the caller's context) while
4747 * doing the scan. After successfully completing the scan, we copy that
4748 * list into the relcache entry. This avoids cache-context memory leakage
4749 * if we get some sort of error partway through.
4750 */
4751 result = NIL;
4752
4753 /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4754 ScanKeyInit(&skey,
4755 Anum_pg_constraint_conrelid,
4756 BTEqualStrategyNumber, F_OIDEQ,
4758
4759 conrel = table_open(ConstraintRelationId, AccessShareLock);
4760 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4761 NULL, 1, &skey);
4762
4763 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4764 {
4765 Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4766 ForeignKeyCacheInfo *info;
4767
4768 /* consider only foreign keys */
4769 if (constraint->contype != CONSTRAINT_FOREIGN)
4770 continue;
4771
4773 info->conoid = constraint->oid;
4774 info->conrelid = constraint->conrelid;
4775 info->confrelid = constraint->confrelid;
4776 info->conenforced = constraint->conenforced;
4777
4778 DeconstructFkConstraintRow(htup, &info->nkeys,
4779 info->conkey,
4780 info->confkey,
4781 info->conpfeqop,
4782 NULL, NULL, NULL, NULL);
4783
4784 /* Add FK's node to the result list */
4785 result = lappend(result, info);
4786 }
4787
4788 systable_endscan(conscan);
4790
4791 /* Now save a copy of the completed list in the relcache entry. */
4793 oldlist = relation->rd_fkeylist;
4794 relation->rd_fkeylist = copyObject(result);
4795 relation->rd_fkeyvalid = true;
4796 MemoryContextSwitchTo(oldcxt);
4797
4798 /* Don't leak the old list, if there is one */
4799 list_free_deep(oldlist);
4800
4801 return result;
4802}
#define copyObject(obj)
Definition: nodes.h:230
#define makeNode(_type_)
Definition: nodes.h:161
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)
bool conenforced
Definition: rel.h:288

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, ForeignKeyCacheInfo::conenforced, 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, 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 5576 of file relcache.c.

5577{
5578 Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5579 Relation indexDesc;
5580 int i;
5581 Oid replidindex;
5582 MemoryContext oldcxt;
5583
5584 /* Quick exit if we already computed the result */
5585 if (relation->rd_idattr != NULL)
5586 return bms_copy(relation->rd_idattr);
5587
5588 /* Fast path if definitely no indexes */
5589 if (!RelationGetForm(relation)->relhasindex)
5590 return NULL;
5591
5592 /* Historic snapshot must be set. */
5594
5595 replidindex = RelationGetReplicaIndex(relation);
5596
5597 /* Fall out if there is no replica identity index */
5598 if (!OidIsValid(replidindex))
5599 return NULL;
5600
5601 /* Look up the description for the replica identity index */
5602 indexDesc = RelationIdGetRelation(replidindex);
5603
5604 if (!RelationIsValid(indexDesc))
5605 elog(ERROR, "could not open relation with OID %u",
5606 relation->rd_replidindex);
5607
5608 /* Add referenced attributes to idindexattrs */
5609 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5610 {
5611 int attrnum = indexDesc->rd_index->indkey.values[i];
5612
5613 /*
5614 * We don't include non-key columns into idindexattrs bitmaps. See
5615 * RelationGetIndexAttrBitmap.
5616 */
5617 if (attrnum != 0)
5618 {
5619 if (i < indexDesc->rd_index->indnkeyatts)
5620 idindexattrs = bms_add_member(idindexattrs,
5622 }
5623 }
5624
5625 RelationClose(indexDesc);
5626
5627 /* Don't leak the old values of these bitmaps, if any */
5628 bms_free(relation->rd_idattr);
5629 relation->rd_idattr = NULL;
5630
5631 /* Now save copy of the bitmap in the relcache entry */
5633 relation->rd_idattr = bms_copy(idindexattrs);
5634 MemoryContextSwitchTo(oldcxt);
5635
5636 /* We return our original working copy for caller to play with */
5637 return idindexattrs;
5638}
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:510
#define RelationIsValid(relation)
Definition: rel.h:489
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:5072
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2099
void RelationClose(Relation relation)
Definition: relcache.c:2220
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1679
#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, RelationData::rd_replidindex, RelationClose(), RelationGetForm, RelationGetReplicaIndex(), RelationIdGetRelation(), and RelationIsValid.

Referenced by logicalrep_write_attrs().

◆ RelationGetIndexAttOptions()

bytea ** RelationGetIndexAttOptions ( Relation  relation,
bool  copy 
)

Definition at line 5988 of file relcache.c.

5989{
5990 MemoryContext oldcxt;
5991 bytea **opts = relation->rd_opcoptions;
5992 Oid relid = RelationGetRelid(relation);
5993 int natts = RelationGetNumberOfAttributes(relation); /* XXX
5994 * IndexRelationGetNumberOfKeyAttributes */
5995 int i;
5996
5997 /* Try to copy cached options. */
5998 if (opts)
5999 return copy ? CopyIndexAttOptions(opts, natts) : opts;
6000
6001 /* Get and parse opclass options. */
6002 opts = palloc0(sizeof(*opts) * natts);
6003
6004 for (i = 0; i < natts; i++)
6005 {
6006 if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
6007 {
6008 Datum attoptions = get_attoptions(relid, i + 1);
6009
6010 opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
6011
6012 if (attoptions != (Datum) 0)
6013 pfree(DatumGetPointer(attoptions));
6014 }
6015 }
6016
6017 /* Copy parsed options to the cache. */
6018 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
6019 relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
6020 MemoryContextSwitchTo(oldcxt);
6021
6022 if (copy)
6023 return opts;
6024
6025 for (i = 0; i < natts; i++)
6026 {
6027 if (opts[i])
6028 pfree(opts[i]);
6029 }
6030
6031 pfree(opts);
6032
6033 return relation->rd_opcoptions;
6034}
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:1043
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:1062
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5968

References CopyIndexAttOptions(), criticalRelcachesBuilt, DatumGetPointer(), get_attoptions(), i, index_opclass_options(), MemoryContextSwitchTo(), opts, palloc0(), pfree(), RelationData::rd_indexcxt, RelationData::rd_opcoptions, RelationGetNumberOfAttributes, and RelationGetRelid.

Referenced by get_relation_info(), index_getprocinfo(), load_critical_index(), and RelationInitIndexAccessInfo().

◆ RelationGetIndexAttrBitmap()

Bitmapset * RelationGetIndexAttrBitmap ( Relation  relation,
IndexAttrBitmapKind  attrKind 
)

Definition at line 5303 of file relcache.c.

5304{
5305 Bitmapset *uindexattrs; /* columns in unique indexes */
5306 Bitmapset *pkindexattrs; /* columns in the primary index */
5307 Bitmapset *idindexattrs; /* columns in the replica identity */
5308 Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5309 Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5310 List *indexoidlist;
5311 List *newindexoidlist;
5312 Oid relpkindex;
5313 Oid relreplindex;
5314 ListCell *l;
5315 MemoryContext oldcxt;
5316
5317 /* Quick exit if we already computed the result. */
5318 if (relation->rd_attrsvalid)
5319 {
5320 switch (attrKind)
5321 {
5323 return bms_copy(relation->rd_keyattr);
5325 return bms_copy(relation->rd_pkattr);
5327 return bms_copy(relation->rd_idattr);
5329 return bms_copy(relation->rd_hotblockingattr);
5331 return bms_copy(relation->rd_summarizedattr);
5332 default:
5333 elog(ERROR, "unknown attrKind %u", attrKind);
5334 }
5335 }
5336
5337 /* Fast path if definitely no indexes */
5338 if (!RelationGetForm(relation)->relhasindex)
5339 return NULL;
5340
5341 /*
5342 * Get cached list of index OIDs. If we have to start over, we do so here.
5343 */
5344restart:
5345 indexoidlist = RelationGetIndexList(relation);
5346
5347 /* Fall out if no indexes (but relhasindex was set) */
5348 if (indexoidlist == NIL)
5349 return NULL;
5350
5351 /*
5352 * Copy the rd_pkindex and rd_replidindex values computed by
5353 * RelationGetIndexList before proceeding. This is needed because a
5354 * relcache flush could occur inside index_open below, resetting the
5355 * fields managed by RelationGetIndexList. We need to do the work with
5356 * stable values of these fields.
5357 */
5358 relpkindex = relation->rd_pkindex;
5359 relreplindex = relation->rd_replidindex;
5360
5361 /*
5362 * For each index, add referenced attributes to indexattrs.
5363 *
5364 * Note: we consider all indexes returned by RelationGetIndexList, even if
5365 * they are not indisready or indisvalid. This is important because an
5366 * index for which CREATE INDEX CONCURRENTLY has just started must be
5367 * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5368 * CONCURRENTLY is far enough along that we should ignore the index, it
5369 * won't be returned at all by RelationGetIndexList.
5370 */
5371 uindexattrs = NULL;
5372 pkindexattrs = NULL;
5373 idindexattrs = NULL;
5374 hotblockingattrs = NULL;
5375 summarizedattrs = NULL;
5376 foreach(l, indexoidlist)
5377 {
5378 Oid indexOid = lfirst_oid(l);
5379 Relation indexDesc;
5380 Datum datum;
5381 bool isnull;
5382 Node *indexExpressions;
5383 Node *indexPredicate;
5384 int i;
5385 bool isKey; /* candidate key */
5386 bool isPK; /* primary key */
5387 bool isIDKey; /* replica identity index */
5388 Bitmapset **attrs;
5389
5390 indexDesc = index_open(indexOid, AccessShareLock);
5391
5392 /*
5393 * Extract index expressions and index predicate. Note: Don't use
5394 * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5395 * those might run constant expressions evaluation, which needs a
5396 * snapshot, which we might not have here. (Also, it's probably more
5397 * sound to collect the bitmaps before any transformations that might
5398 * eliminate columns, but the practical impact of this is limited.)
5399 */
5400
5401 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5402 GetPgIndexDescriptor(), &isnull);
5403 if (!isnull)
5404 indexExpressions = stringToNode(TextDatumGetCString(datum));
5405 else
5406 indexExpressions = NULL;
5407
5408 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5409 GetPgIndexDescriptor(), &isnull);
5410 if (!isnull)
5411 indexPredicate = stringToNode(TextDatumGetCString(datum));
5412 else
5413 indexPredicate = NULL;
5414
5415 /* Can this index be referenced by a foreign key? */
5416 isKey = indexDesc->rd_index->indisunique &&
5417 indexExpressions == NULL &&
5418 indexPredicate == NULL;
5419
5420 /* Is this a primary key? */
5421 isPK = (indexOid == relpkindex);
5422
5423 /* Is this index the configured (or default) replica identity? */
5424 isIDKey = (indexOid == relreplindex);
5425
5426 /*
5427 * If the index is summarizing, it doesn't block HOT updates, but we
5428 * may still need to update it (if the attributes were modified). So
5429 * decide which bitmap we'll update in the following loop.
5430 */
5431 if (indexDesc->rd_indam->amsummarizing)
5432 attrs = &summarizedattrs;
5433 else
5434 attrs = &hotblockingattrs;
5435
5436 /* Collect simple attribute references */
5437 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5438 {
5439 int attrnum = indexDesc->rd_index->indkey.values[i];
5440
5441 /*
5442 * Since we have covering indexes with non-key columns, we must
5443 * handle them accurately here. non-key columns must be added into
5444 * hotblockingattrs or summarizedattrs, since they are in index,
5445 * and update shouldn't miss them.
5446 *
5447 * Summarizing indexes do not block HOT, but do need to be updated
5448 * when the column value changes, thus require a separate
5449 * attribute bitmapset.
5450 *
5451 * Obviously, non-key columns couldn't be referenced by foreign
5452 * key or identity key. Hence we do not include them into
5453 * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5454 */
5455 if (attrnum != 0)
5456 {
5457 *attrs = bms_add_member(*attrs,
5459
5460 if (isKey && i < indexDesc->rd_index->indnkeyatts)
5461 uindexattrs = bms_add_member(uindexattrs,
5463
5464 if (isPK && i < indexDesc->rd_index->indnkeyatts)
5465 pkindexattrs = bms_add_member(pkindexattrs,
5467
5468 if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5469 idindexattrs = bms_add_member(idindexattrs,
5471 }
5472 }
5473
5474 /* Collect all attributes used in expressions, too */
5475 pull_varattnos(indexExpressions, 1, attrs);
5476
5477 /* Collect all attributes in the index predicate, too */
5478 pull_varattnos(indexPredicate, 1, attrs);
5479
5480 index_close(indexDesc, AccessShareLock);
5481 }
5482
5483 /*
5484 * During one of the index_opens in the above loop, we might have received
5485 * a relcache flush event on this relcache entry, which might have been
5486 * signaling a change in the rel's index list. If so, we'd better start
5487 * over to ensure we deliver up-to-date attribute bitmaps.
5488 */
5489 newindexoidlist = RelationGetIndexList(relation);
5490 if (equal(indexoidlist, newindexoidlist) &&
5491 relpkindex == relation->rd_pkindex &&
5492 relreplindex == relation->rd_replidindex)
5493 {
5494 /* Still the same index set, so proceed */
5495 list_free(newindexoidlist);
5496 list_free(indexoidlist);
5497 }
5498 else
5499 {
5500 /* Gotta do it over ... might as well not leak memory */
5501 list_free(newindexoidlist);
5502 list_free(indexoidlist);
5503 bms_free(uindexattrs);
5504 bms_free(pkindexattrs);
5505 bms_free(idindexattrs);
5506 bms_free(hotblockingattrs);
5507 bms_free(summarizedattrs);
5508
5509 goto restart;
5510 }
5511
5512 /* Don't leak the old values of these bitmaps, if any */
5513 relation->rd_attrsvalid = false;
5514 bms_free(relation->rd_keyattr);
5515 relation->rd_keyattr = NULL;
5516 bms_free(relation->rd_pkattr);
5517 relation->rd_pkattr = NULL;
5518 bms_free(relation->rd_idattr);
5519 relation->rd_idattr = NULL;
5520 bms_free(relation->rd_hotblockingattr);
5521 relation->rd_hotblockingattr = NULL;
5522 bms_free(relation->rd_summarizedattr);
5523 relation->rd_summarizedattr = NULL;
5524
5525 /*
5526 * Now save copies of the bitmaps in the relcache entry. We intentionally
5527 * set rd_attrsvalid last, because that's the one that signals validity of
5528 * the values; if we run out of memory before making that copy, we won't
5529 * leave the relcache entry looking like the other ones are valid but
5530 * empty.
5531 */
5533 relation->rd_keyattr = bms_copy(uindexattrs);
5534 relation->rd_pkattr = bms_copy(pkindexattrs);
5535 relation->rd_idattr = bms_copy(idindexattrs);
5536 relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5537 relation->rd_summarizedattr = bms_copy(summarizedattrs);
5538 relation->rd_attrsvalid = true;
5539 MemoryContextSwitchTo(oldcxt);
5540
5541 /* We return our original working copy for caller to play with */
5542 switch (attrKind)
5543 {
5545 return uindexattrs;
5547 return pkindexattrs;
5549 return idindexattrs;
5551 return hotblockingattrs;
5553 return summarizedattrs;
5554 default:
5555 elog(ERROR, "unknown attrKind %u", attrKind);
5556 return NULL;
5557 }
5558}
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4836
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:69
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:72
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:70
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:73
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:71
bool amsummarizing
Definition: amapi.h:280
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References AccessShareLock, IndexAmRoutine::amsummarizing, bms_add_member(), bms_copy(), bms_free(), CacheMemoryContext, elog, equal(), ERROR, FirstLowInvalidHeapAttributeNumber, GetPgIndexDescriptor(), heap_getattr(), i, INDEX_ATTR_BITMAP_HOT_BLOCKING, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_SUMMARIZED, index_close(), index_open(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, pull_varattnos(), RelationData::rd_attrsvalid, RelationData::rd_hotblockingattr, RelationData::rd_idattr, RelationData::rd_indam, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_keyattr, RelationData::rd_pkattr, RelationData::rd_pkindex, RelationData::rd_replidindex, RelationData::rd_summarizedattr, RelationGetForm, RelationGetIndexList(), stringToNode(), and TextDatumGetCString.

Referenced by dropconstraint_internal(), ExecUpdateLockMode(), ExtractReplicaIdentity(), GetParentedForeignKeyRefs(), heap_update(), logicalrep_rel_mark_updatable(), pub_contains_invalid_column(), and pub_rf_contains_invalid_column().

◆ RelationGetIndexExpressions()

List * RelationGetIndexExpressions ( Relation  relation)

Definition at line 5097 of file relcache.c.

5098{
5099 List *result;
5100 Datum exprsDatum;
5101 bool isnull;
5102 char *exprsString;
5103 MemoryContext oldcxt;
5104
5105 /* Quick exit if we already computed the result. */
5106 if (relation->rd_indexprs)
5107 return copyObject(relation->rd_indexprs);
5108
5109 /* Quick exit if there is nothing to do. */
5110 if (relation->rd_indextuple == NULL ||
5111 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5112 return NIL;
5113
5114 /*
5115 * We build the tree we intend to return in the caller's context. After
5116 * successfully completing the work, we copy it into the relcache entry.
5117 * This avoids problems if we get some sort of error partway through.
5118 */
5119 exprsDatum = heap_getattr(relation->rd_indextuple,
5120 Anum_pg_index_indexprs,
5122 &isnull);
5123 Assert(!isnull);
5124 exprsString = TextDatumGetCString(exprsDatum);
5125 result = (List *) stringToNode(exprsString);
5126 pfree(exprsString);
5127
5128 /*
5129 * Run the expressions through eval_const_expressions. This is not just an
5130 * optimization, but is necessary, because the planner will be comparing
5131 * them to similarly-processed qual clauses, and may fail to detect valid
5132 * matches without this. We must not use canonicalize_qual, however,
5133 * since these aren't qual expressions.
5134 */
5135 result = (List *) eval_const_expressions(NULL, (Node *) result);
5136
5137 /* May as well fix opfuncids too */
5138 fix_opfuncids((Node *) result);
5139
5140 /* Now save a copy of the completed tree in the relcache entry. */
5141 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5142 relation->rd_indexprs = copyObject(result);
5143 MemoryContextSwitchTo(oldcxt);
5144
5145 return result;
5146}
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2256
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1841

References Assert(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_attr_expr(), get_relation_info(), GetIndexInputType(), index_unchanged_by_update(), infer_arbiter_indexes(), plan_create_index_workers(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetIndexList()

List * RelationGetIndexList ( Relation  relation)

Definition at line 4836 of file relcache.c.

4837{
4838 Relation indrel;
4839 SysScanDesc indscan;
4840 ScanKeyData skey;
4841 HeapTuple htup;
4842 List *result;
4843 List *oldlist;
4844 char replident = relation->rd_rel->relreplident;
4845 Oid pkeyIndex = InvalidOid;
4846 Oid candidateIndex = InvalidOid;
4847 bool pkdeferrable = false;
4848 MemoryContext oldcxt;
4849
4850 /* Quick exit if we already computed the list. */
4851 if (relation->rd_indexvalid)
4852 return list_copy(relation->rd_indexlist);
4853
4854 /*
4855 * We build the list we intend to return (in the caller's context) while
4856 * doing the scan. After successfully completing the scan, we copy that
4857 * list into the relcache entry. This avoids cache-context memory leakage
4858 * if we get some sort of error partway through.
4859 */
4860 result = NIL;
4861
4862 /* Prepare to scan pg_index for entries having indrelid = this rel. */
4863 ScanKeyInit(&skey,
4864 Anum_pg_index_indrelid,
4865 BTEqualStrategyNumber, F_OIDEQ,
4867
4868 indrel = table_open(IndexRelationId, AccessShareLock);
4869 indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4870 NULL, 1, &skey);
4871
4872 while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4873 {
4875
4876 /*
4877 * Ignore any indexes that are currently being dropped. This will
4878 * prevent them from being searched, inserted into, or considered in
4879 * HOT-safety decisions. It's unsafe to touch such an index at all
4880 * since its catalog entries could disappear at any instant.
4881 */
4882 if (!index->indislive)
4883 continue;
4884
4885 /* add index's OID to result list */
4886 result = lappend_oid(result, index->indexrelid);
4887
4888 /*
4889 * Non-unique or predicate indexes aren't interesting for either oid
4890 * indexes or replication identity indexes, so don't check them.
4891 * Deferred ones are not useful for replication identity either; but
4892 * we do include them if they are PKs.
4893 */
4894 if (!index->indisunique ||
4895 !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4896 continue;
4897
4898 /*
4899 * Remember primary key index, if any. For regular tables we do this
4900 * only if the index is valid; but for partitioned tables, then we do
4901 * it even if it's invalid.
4902 *
4903 * The reason for returning invalid primary keys for partitioned
4904 * tables is that we need it to prevent drop of not-null constraints
4905 * that may underlie such a primary key, which is only a problem for
4906 * partitioned tables.
4907 */
4908 if (index->indisprimary &&
4909 (index->indisvalid ||
4910 relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4911 {
4912 pkeyIndex = index->indexrelid;
4913 pkdeferrable = !index->indimmediate;
4914 }
4915
4916 if (!index->indimmediate)
4917 continue;
4918
4919 if (!index->indisvalid)
4920 continue;
4921
4922 /* remember explicitly chosen replica index */
4923 if (index->indisreplident)
4924 candidateIndex = index->indexrelid;
4925 }
4926
4927 systable_endscan(indscan);
4928
4930
4931 /* Sort the result list into OID order, per API spec. */
4932 list_sort(result, list_oid_cmp);
4933
4934 /* Now save a copy of the completed list in the relcache entry. */
4936 oldlist = relation->rd_indexlist;
4937 relation->rd_indexlist = list_copy(result);
4938 relation->rd_pkindex = pkeyIndex;
4939 relation->rd_ispkdeferrable = pkdeferrable;
4940 if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4941 relation->rd_replidindex = pkeyIndex;
4942 else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4943 relation->rd_replidindex = candidateIndex;
4944 else
4945 relation->rd_replidindex = InvalidOid;
4946 relation->rd_indexvalid = true;
4947 MemoryContextSwitchTo(oldcxt);
4948
4949 /* Don't leak the old list, if there is one */
4950 list_free(oldlist);
4951
4952 return result;
4953}
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
bool rd_ispkdeferrable
Definition: rel.h:154
Definition: type.h:96

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT(), heap_attisnull(), HeapTupleIsValid, InvalidOid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), OidIsValid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, RelationData::rd_rel, RelationData::rd_replidindex, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterIndexNamespaces(), apply_handle_delete_internal(), apply_handle_insert_internal(), ATExecChangeOwner(), ATExecSetTableSpace(), AttachPartitionEnsureIndexes(), calculate_indexes_size(), calculate_toast_table_size(), cluster(), DefineIndex(), DefineRelation(), DetachPartitionFinalize(), do_analyze_rel(), ExecInitPartitionInfo(), ExecOpenIndices(), expandTableLikeClause(), FindUsableIndexForReplicaIdentityFull(), get_relation_info(), GetParentedForeignKeyRefs(), index_get_partition(), infer_arbiter_indexes(), mark_index_clustered(), refresh_by_match_merge(), RefreshMatViewByOid(), reindex_relation(), ReindexRelationConcurrently(), relation_mark_replica_identity(), RelationGetIndexAttrBitmap(), RelationGetPrimaryKeyIndex(), RelationGetReplicaIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), SetIndexStorageProperties(), toast_open_indexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), triggered_change_notification(), and vac_open_indexes().

◆ RelationGetIndexPredicate()

List * RelationGetIndexPredicate ( Relation  relation)

Definition at line 5210 of file relcache.c.

5211{
5212 List *result;
5213 Datum predDatum;
5214 bool isnull;
5215 char *predString;
5216 MemoryContext oldcxt;
5217
5218 /* Quick exit if we already computed the result. */
5219 if (relation->rd_indpred)
5220 return copyObject(relation->rd_indpred);
5221
5222 /* Quick exit if there is nothing to do. */
5223 if (relation->rd_indextuple == NULL ||
5224 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5225 return NIL;
5226
5227 /*
5228 * We build the tree we intend to return in the caller's context. After
5229 * successfully completing the work, we copy it into the relcache entry.
5230 * This avoids problems if we get some sort of error partway through.
5231 */
5232 predDatum = heap_getattr(relation->rd_indextuple,
5233 Anum_pg_index_indpred,
5235 &isnull);
5236 Assert(!isnull);
5237 predString = TextDatumGetCString(predDatum);
5238 result = (List *) stringToNode(predString);
5239 pfree(predString);
5240
5241 /*
5242 * Run the expression through const-simplification and canonicalization.
5243 * This is not just an optimization, but is necessary, because the planner
5244 * will be comparing it to similarly-processed qual clauses, and may fail
5245 * to detect valid matches without this. This must match the processing
5246 * done to qual clauses in preprocess_expression()! (We can skip the
5247 * stuff involving subqueries, however, since we don't allow any in index
5248 * predicates.)
5249 */
5250 result = (List *) eval_const_expressions(NULL, (Node *) result);
5251
5252 result = (List *) canonicalize_qual((Expr *) result, false);
5253
5254 /* Also convert to implicit-AND format */
5255 result = make_ands_implicit((Expr *) result);
5256
5257 /* May as well fix opfuncids too */
5258 fix_opfuncids((Node *) result);
5259
5260 /* Now save a copy of the completed tree in the relcache entry. */
5261 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5262 relation->rd_indpred = copyObject(result);
5263 MemoryContextSwitchTo(oldcxt);
5264
5265 return result;
5266}
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:810
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293

References Assert(), canonicalize_qual(), copyObject, eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr(), make_ands_implicit(), MemoryContextSwitchTo(), NIL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indextuple, RelationData::rd_indpred, stringToNode(), and TextDatumGetCString.

Referenced by ATExecReplicaIdentity(), BuildIndexInfo(), get_relation_info(), infer_arbiter_indexes(), is_usable_unique_index(), plan_create_index_workers(), ReindexRelationConcurrently(), and transformIndexConstraint().

◆ RelationGetPrimaryKeyIndex()

Oid RelationGetPrimaryKeyIndex ( Relation  relation,
bool  deferrable_ok 
)

Definition at line 5047 of file relcache.c.

5048{
5049 List *ilist;
5050
5051 if (!relation->rd_indexvalid)
5052 {
5053 /* RelationGetIndexList does the heavy lifting. */
5054 ilist = RelationGetIndexList(relation);
5055 list_free(ilist);
5056 Assert(relation->rd_indexvalid);
5057 }
5058
5059 if (deferrable_ok)
5060 return relation->rd_pkindex;
5061 else if (relation->rd_ispkdeferrable)
5062 return InvalidOid;
5063 return relation->rd_pkindex;
5064}

References Assert(), InvalidOid, list_free(), RelationData::rd_indexvalid, RelationData::rd_ispkdeferrable, RelationData::rd_pkindex, and RelationGetIndexList().

Referenced by dropconstraint_internal(), and GetRelationIdentityOrPK().

◆ RelationGetReplicaIndex()

Oid RelationGetReplicaIndex ( Relation  relation)

Definition at line 5072 of file relcache.c.

5073{
5074 List *ilist;
5075
5076 if (!relation->rd_indexvalid)
5077 {
5078 /* RelationGetIndexList does the heavy lifting. */
5079 ilist = RelationGetIndexList(relation);
5080 list_free(ilist);
5081 Assert(relation->rd_indexvalid);
5082 }
5083
5084 return relation->rd_replidindex;
5085}

References Assert(), list_free(), RelationData::rd_indexvalid, RelationData::rd_replidindex, and RelationGetIndexList().

Referenced by CheckCmdReplicaIdentity(), GetRelationIdentityOrPK(), pg_get_replica_identity_index(), and RelationGetIdentityKeyBitmap().

◆ RelationGetStatExtList()

List * RelationGetStatExtList ( Relation  relation)

Definition at line 4977 of file relcache.c.

4978{
4979 Relation indrel;
4980 SysScanDesc indscan;
4981 ScanKeyData skey;
4982 HeapTuple htup;
4983 List *result;
4984 List *oldlist;
4985 MemoryContext oldcxt;
4986
4987 /* Quick exit if we already computed the list. */
4988 if (relation->rd_statvalid != 0)
4989 return list_copy(relation->rd_statlist);
4990
4991 /*
4992 * We build the list we intend to return (in the caller's context) while
4993 * doing the scan. After successfully completing the scan, we copy that
4994 * list into the relcache entry. This avoids cache-context memory leakage
4995 * if we get some sort of error partway through.
4996 */
4997 result = NIL;
4998
4999 /*
5000 * Prepare to scan pg_statistic_ext for entries having stxrelid = this
5001 * rel.
5002 */
5003 ScanKeyInit(&skey,
5004 Anum_pg_statistic_ext_stxrelid,
5005 BTEqualStrategyNumber, F_OIDEQ,
5007
5008 indrel = table_open(StatisticExtRelationId, AccessShareLock);
5009 indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
5010 NULL, 1, &skey);
5011
5012 while (HeapTupleIsValid(htup = systable_getnext(indscan)))
5013 {
5014 Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
5015
5016 result = lappend_oid(result, oid);
5017 }
5018
5019 systable_endscan(indscan);
5020
5022
5023 /* Sort the result list into OID order, per API spec. */
5024 list_sort(result, list_oid_cmp);
5025
5026 /* Now save a copy of the completed list in the relcache entry. */
5028 oldlist = relation->rd_statlist;
5029 relation->rd_statlist = list_copy(result);
5030
5031 relation->rd_statvalid = true;
5032 MemoryContextSwitchTo(oldcxt);
5033
5034 /* Don't leak the old list, if there is one */
5035 list_free(oldlist);
5036
5037 return result;
5038}
FormData_pg_statistic_ext * Form_pg_statistic_ext

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, GETSTRUCT(), HeapTupleIsValid, lappend_oid(), list_copy(), list_free(), list_oid_cmp(), list_sort(), MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_statlist, RelationData::rd_statvalid, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by expandTableLikeClause(), and get_relation_statistics().

◆ RelationIdGetRelation()

Relation RelationIdGetRelation ( Oid  relationId)

Definition at line 2099 of file relcache.c.

2100{
2101 Relation rd;
2102
2104
2105 /*
2106 * first try to find reldesc in the cache
2107 */
2108 RelationIdCacheLookup(relationId, rd);
2109
2110 if (RelationIsValid(rd))
2111 {
2112 /* return NULL for dropped relations */
2114 {
2115 Assert(!rd->rd_isvalid);
2116 return NULL;
2117 }
2118
2120 /* revalidate cache entry if necessary */
2121 if (!rd->rd_isvalid)
2122 {
2124
2125 /*
2126 * Normally entries need to be valid here, but before the relcache
2127 * has been initialized, not enough infrastructure exists to
2128 * perform pg_class lookups. The structure of such entries doesn't
2129 * change, but we still want to update the rd_rel entry. So
2130 * rd_isvalid = false is left in place for a later lookup.
2131 */
2132 Assert(rd->rd_isvalid ||
2134 }
2135 return rd;
2136 }
2137
2138 /*
2139 * no reldesc in the cache, so have RelationBuildDesc() build one and add
2140 * it.
2141 */
2142 rd = RelationBuildDesc(relationId, true);
2143 if (RelationIsValid(rd))
2145 return rd;
2146}
static void AssertCouldGetRelation(void)
Definition: relcache.h:44

References Assert(), AssertCouldGetRelation(), criticalRelcachesBuilt, InvalidSubTransactionId, RelationData::rd_droppedSubid, RelationData::rd_isnailed, RelationData::rd_isvalid, RelationBuildDesc(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, and RelationRebuildRelation().

Referenced by check_and_init_gencol(), init_tuple_slot(), maybe_send_schema(), pgoutput_change(), pgoutput_column_list_init(), pgoutput_ensure_entry_cxt(), pgoutput_row_filter_init(), relation_open(), RelationGetIdentityKeyBitmap(), ReorderBufferProcessTXN(), ReorderBufferToastReplace(), and try_relation_open().

◆ RelationIdIsInInitFile()

bool RelationIdIsInInitFile ( Oid  relationId)

Definition at line 6820 of file relcache.c.

6821{
6822 if (relationId == SharedSecLabelRelationId ||
6823 relationId == TriggerRelidNameIndexId ||
6824 relationId == DatabaseNameIndexId ||
6825 relationId == SharedSecLabelObjectIndexId)
6826 {
6827 /*
6828 * If this Assert fails, we don't need the applicable special case
6829 * anymore.
6830 */
6831 Assert(!RelationSupportsSysCache(relationId));
6832 return true;
6833 }
6834 return RelationSupportsSysCache(relationId);
6835}
bool RelationSupportsSysCache(Oid relid)
Definition: syscache.c:770

References Assert(), and RelationSupportsSysCache().

Referenced by RegisterRelcacheInvalidation(), and write_relcache_init_file().

◆ RelationIncrementReferenceCount()

void RelationIncrementReferenceCount ( Relation  rel)

◆ RelationInitIndexAccessInfo()

void RelationInitIndexAccessInfo ( Relation  relation)

Definition at line 1445 of file relcache.c.

1446{
1447 HeapTuple tuple;
1448 Form_pg_am aform;
1449 Datum indcollDatum;
1450 Datum indclassDatum;
1451 Datum indoptionDatum;
1452 bool isnull;
1453 oidvector *indcoll;
1454 oidvector *indclass;
1455 int2vector *indoption;
1456 MemoryContext indexcxt;
1457 MemoryContext oldcontext;
1458 int indnatts;
1459 int indnkeyatts;
1460 uint16 amsupport;
1461
1462 /*
1463 * Make a copy of the pg_index entry for the index. Since pg_index
1464 * contains variable-length and possibly-null fields, we have to do this
1465 * honestly rather than just treating it as a Form_pg_index struct.
1466 */
1467 tuple = SearchSysCache1(INDEXRELID,
1469 if (!HeapTupleIsValid(tuple))
1470 elog(ERROR, "cache lookup failed for index %u",
1471 RelationGetRelid(relation));
1473 relation->rd_indextuple = heap_copytuple(tuple);
1474 relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1475 MemoryContextSwitchTo(oldcontext);
1476 ReleaseSysCache(tuple);
1477
1478 /*
1479 * Look up the index's access method, save the OID of its handler function
1480 */
1481 Assert(relation->rd_rel->relam != InvalidOid);
1482 tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1483 if (!HeapTupleIsValid(tuple))
1484 elog(ERROR, "cache lookup failed for access method %u",
1485 relation->rd_rel->relam);
1486 aform = (Form_pg_am) GETSTRUCT(tuple);
1487 relation->rd_amhandler = aform->amhandler;
1488 ReleaseSysCache(tuple);
1489
1490 indnatts = RelationGetNumberOfAttributes(relation);
1491 if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1492 elog(ERROR, "relnatts disagrees with indnatts for index %u",
1493 RelationGetRelid(relation));
1494 indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1495
1496 /*
1497 * Make the private context to hold index access info. The reason we need
1498 * a context, and not just a couple of pallocs, is so that we won't leak
1499 * any subsidiary info attached to fmgr lookup records.
1500 */
1502 "index info",
1504 relation->rd_indexcxt = indexcxt;
1506 RelationGetRelationName(relation));
1507
1508 /*
1509 * Now we can fetch the index AM's API struct
1510 */
1511 InitIndexAmRoutine(relation);
1512
1513 /*
1514 * Allocate arrays to hold data. Opclasses are not used for included
1515 * columns, so allocate them for indnkeyatts only.
1516 */
1517 relation->rd_opfamily = (Oid *)
1518 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1519 relation->rd_opcintype = (Oid *)
1520 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1521
1522 amsupport = relation->rd_indam->amsupport;
1523 if (amsupport > 0)
1524 {
1525 int nsupport = indnatts * amsupport;
1526
1527 relation->rd_support = (RegProcedure *)
1528 MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1529 relation->rd_supportinfo = (FmgrInfo *)
1530 MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1531 }
1532 else
1533 {
1534 relation->rd_support = NULL;
1535 relation->rd_supportinfo = NULL;
1536 }
1537
1538 relation->rd_indcollation = (Oid *)
1539 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1540
1541 relation->rd_indoption = (int16 *)
1542 MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1543
1544 /*
1545 * indcollation cannot be referenced directly through the C struct,
1546 * because it comes after the variable-width indkey field. Must extract
1547 * the datum the hard way...
1548 */
1549 indcollDatum = fastgetattr(relation->rd_indextuple,
1550 Anum_pg_index_indcollation,
1552 &isnull);
1553 Assert(!isnull);
1554 indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1555 memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1556
1557 /*
1558 * indclass cannot be referenced directly through the C struct, because it
1559 * comes after the variable-width indkey field. Must extract the datum
1560 * the hard way...
1561 */
1562 indclassDatum = fastgetattr(relation->rd_indextuple,
1563 Anum_pg_index_indclass,
1565 &isnull);
1566 Assert(!isnull);
1567 indclass = (oidvector *) DatumGetPointer(indclassDatum);
1568
1569 /*
1570 * Fill the support procedure OID array, as well as the info about
1571 * opfamilies and opclass input types. (aminfo and supportinfo are left
1572 * as zeroes, and are filled on-the-fly when used)
1573 */
1574 IndexSupportInitialize(indclass, relation->rd_support,
1575 relation->rd_opfamily, relation->rd_opcintype,
1576 amsupport, indnkeyatts);
1577
1578 /*
1579 * Similarly extract indoption and copy it to the cache entry
1580 */
1581 indoptionDatum = fastgetattr(relation->rd_indextuple,
1582 Anum_pg_index_indoption,
1584 &isnull);
1585 Assert(!isnull);
1586 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1587 memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1588
1589 (void) RelationGetIndexAttOptions(relation, false);
1590
1591 /*
1592 * expressions, predicate, exclusion caches will be filled later
1593 */
1594 relation->rd_indexprs = NIL;
1595 relation->rd_indpred = NIL;
1596 relation->rd_exclops = NULL;
1597 relation->rd_exclprocs = NULL;
1598 relation->rd_exclstrats = NULL;
1599 relation->rd_amcache = NULL;
1600}
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:528
static void IndexSupportInitialize(oidvector *indclass, RegProcedure *indexSupport, Oid *opFamily, Oid *opcInType, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber)
Definition: relcache.c:1616
Definition: c.h:686
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:693
Definition: c.h:697

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, IndexAmRoutine::amsupport, Assert(), CacheMemoryContext, DatumGetPointer(), elog, ERROR, fastgetattr(), GetPgIndexDescriptor(), GETSTRUCT(), heap_copytuple(), HeapTupleIsValid, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, IndexSupportInitialize(), InitIndexAmRoutine(), InvalidOid, MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, ObjectIdGetDatum(), RelationData::rd_amcache, RelationData::rd_amhandler, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_support, RelationData::rd_supportinfo, RelationGetIndexAttOptions(), RelationGetNumberOfAttributes, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1(), int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

◆ RelationInitPhysicalAddr()

static void RelationInitPhysicalAddr ( Relation  relation)
static

Definition at line 1339 of file relcache.c.

1340{
1341 RelFileNumber oldnumber = relation->rd_locator.relNumber;
1342
1343 /* these relations kinds never have storage */
1344 if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
1345 return;
1346
1347 if (relation->rd_rel->reltablespace)
1348 relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
1349 else
1351 if (relation->rd_locator.spcOid == GLOBALTABLESPACE_OID)
1352 relation->rd_locator.dbOid = InvalidOid;
1353 else
1354 relation->rd_locator.dbOid = MyDatabaseId;
1355
1356 if (relation->rd_rel->relfilenode)
1357 {
1358 /*
1359 * Even if we are using a decoding snapshot that doesn't represent the
1360 * current state of the catalog we need to make sure the filenode
1361 * points to the current file since the older file will be gone (or
1362 * truncated). The new file will still contain older rows so lookups
1363 * in them will work correctly. This wouldn't work correctly if
1364 * rewrites were allowed to change the schema in an incompatible way,
1365 * but those are prevented both on catalog tables and on user tables
1366 * declared as additional catalog tables.
1367 */
1370 && IsTransactionState())
1371 {
1372 HeapTuple phys_tuple;
1373 Form_pg_class physrel;
1374
1375 phys_tuple = ScanPgRelation(RelationGetRelid(relation),
1376 RelationGetRelid(relation) != ClassOidIndexId,
1377 true);
1378 if (!HeapTupleIsValid(phys_tuple))
1379 elog(ERROR, "could not find pg_class entry for %u",
1380 RelationGetRelid(relation));
1381 physrel = (Form_pg_class) GETSTRUCT(phys_tuple);
1382
1383 relation->rd_rel->reltablespace = physrel->reltablespace;
1384 relation->rd_rel->relfilenode = physrel->relfilenode;
1385 heap_freetuple(phys_tuple);
1386 }
1387
1388 relation->rd_locator.relNumber = relation->rd_rel->relfilenode;
1389 }
1390 else
1391 {
1392 /* Consult the relation mapper */
1393 relation->rd_locator.relNumber =
1395 relation->rd_rel->relisshared);
1397 elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1398 RelationGetRelationName(relation), relation->rd_id);
1399 }
1400
1401 /*
1402 * For RelationNeedsWAL() to answer correctly on parallel workers, restore
1403 * rd_firstRelfilelocatorSubid. No subtransactions start or end while in
1404 * parallel mode, so the specific SubTransactionId does not matter.
1405 */
1406 if (IsParallelWorker() && oldnumber != relation->rd_locator.relNumber)
1407 {
1410 else
1412 }
1413}
#define TopSubTransactionId
Definition: c.h:630
Oid MyDatabaseTableSpace
Definition: globals.c:96
Oid MyDatabaseId
Definition: globals.c:94
#define IsParallelWorker()
Definition: parallel.h:60
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:695
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool RelFileLocatorSkippingWAL(RelFileLocator rlocator)
Definition: storage.c:573
RelFileNumber relNumber
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

References RelFileLocator::dbOid, elog, ERROR, GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, HistoricSnapshotActive(), InvalidOid, InvalidSubTransactionId, IsParallelWorker, IsTransactionState(), MyDatabaseId, MyDatabaseTableSpace, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_id, RelationData::rd_locator, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationMapOidToFilenumber(), RelFileLocatorSkippingWAL(), RelFileNumberIsValid, RelFileLocator::relNumber, ScanPgRelation(), RelFileLocator::spcOid, and TopSubTransactionId.

Referenced by formrdesc(), load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), RelationCacheInvalidate(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ RelationInitTableAccessMethod()

void RelationInitTableAccessMethod ( Relation  relation)

Definition at line 1829 of file relcache.c.

1830{
1831 HeapTuple tuple;
1832 Form_pg_am aform;
1833
1834 if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1835 {
1836 /*
1837 * Sequences are currently accessed like heap tables, but it doesn't
1838 * seem prudent to show that in the catalog. So just overwrite it
1839 * here.
1840 */
1841 Assert(relation->rd_rel->relam == InvalidOid);
1842 relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1843 }
1844 else if (IsCatalogRelation(relation))
1845 {
1846 /*
1847 * Avoid doing a syscache lookup for catalog tables.
1848 */
1849 Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1850 relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1851 }
1852 else
1853 {
1854 /*
1855 * Look up the table access method, save the OID of its handler
1856 * function.
1857 */
1858 Assert(relation->rd_rel->relam != InvalidOid);
1859 tuple = SearchSysCache1(AMOID,
1860 ObjectIdGetDatum(relation->rd_rel->relam));
1861 if (!HeapTupleIsValid(tuple))
1862 elog(ERROR, "cache lookup failed for access method %u",
1863 relation->rd_rel->relam);
1864 aform = (Form_pg_am) GETSTRUCT(tuple);
1865 relation->rd_amhandler = aform->amhandler;
1866 ReleaseSysCache(tuple);
1867 }
1868
1869 /*
1870 * Now we can fetch the table AM's API struct
1871 */
1872 InitTableAmRoutine(relation);
1873}
static void InitTableAmRoutine(Relation relation)
Definition: relcache.c:1820

References Assert(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, InitTableAmRoutine(), InvalidOid, IsCatalogRelation(), ObjectIdGetDatum(), RelationData::rd_amhandler, RelationData::rd_rel, ReleaseSysCache(), and SearchSysCache1().

Referenced by load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), and RelationCacheInitializePhase3().

◆ RelationInvalidateRelation()

static void RelationInvalidateRelation ( Relation  relation)
static

Definition at line 2518 of file relcache.c.

2519{
2520 /*
2521 * Make sure smgr and lower levels close the relation's files, if they
2522 * weren't closed already. If the relation is not getting deleted, the
2523 * next smgr access should reopen the files automatically. This ensures
2524 * that the low-level file access state is updated after, say, a vacuum
2525 * truncation.
2526 */
2527 RelationCloseSmgr(relation);
2528
2529 /* Free AM cached data, if any */
2530 if (relation->rd_amcache)
2531 pfree(relation->rd_amcache);
2532 relation->rd_amcache = NULL;
2533
2534 relation->rd_isvalid = false;
2535}

References pfree(), RelationData::rd_amcache, RelationData::rd_isvalid, and RelationCloseSmgr().

Referenced by RelationCacheInvalidate(), RelationClearRelation(), RelationFlushRelation(), RelationForgetRelation(), and RelationRebuildRelation().

◆ RelationParseRelOptions()

static void RelationParseRelOptions ( Relation  relation,
HeapTuple  tuple 
)
static

Definition at line 468 of file relcache.c.

469{
470 bytea *options;
471 amoptions_function amoptsfn;
472
473 relation->rd_options = NULL;
474
475 /*
476 * Look up any AM-specific parse function; fall out if relkind should not
477 * have options.
478 */
479 switch (relation->rd_rel->relkind)
480 {
481 case RELKIND_RELATION:
482 case RELKIND_TOASTVALUE:
483 case RELKIND_VIEW:
484 case RELKIND_MATVIEW:
485 case RELKIND_PARTITIONED_TABLE:
486 amoptsfn = NULL;
487 break;
488 case RELKIND_INDEX:
489 case RELKIND_PARTITIONED_INDEX:
490 amoptsfn = relation->rd_indam->amoptions;
491 break;
492 default:
493 return;
494 }
495
496 /*
497 * Fetch reloptions from tuple; have to use a hardwired descriptor because
498 * we might not have any other for pg_class yet (consider executing this
499 * code for pg_class itself)
500 */
501 options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
502
503 /*
504 * Copy parsed data into CacheMemoryContext. To guard against the
505 * possibility of leaks in the reloptions code, we want to do the actual
506 * parsing in the caller's memory context and copy the results into
507 * CacheMemoryContext after the fact.
508 */
509 if (options)
510 {
513 memcpy(relation->rd_options, options, VARSIZE(options));
514 pfree(options);
515 }
516}
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:163
static char ** options
static TupleDesc GetPgClassDescriptor(void)
Definition: relcache.c:4460
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
Definition: reloptions.c:1390
amoptions_function amoptions
Definition: amapi.h:302

References IndexAmRoutine::amoptions, CacheMemoryContext, extractRelOptions(), GetPgClassDescriptor(), MemoryContextAlloc(), options, pfree(), RelationData::rd_indam, RelationData::rd_options, RelationData::rd_rel, and VARSIZE.

Referenced by RelationBuildDesc(), RelationCacheInitializePhase3(), and RelationReloadIndexInfo().

◆ RelationRebuildRelation()

static void RelationRebuildRelation ( Relation  relation)
static

Definition at line 2585 of file relcache.c.

2586{
2589 /* there is no reason to ever rebuild a dropped relation */
2591
2592 /* Close and mark it as invalid until we've finished the rebuild */
2594
2595 /*
2596 * Indexes only have a limited number of possible schema changes, and we
2597 * don't want to use the full-blown procedure because it's a headache for
2598 * indexes that reload itself depends on.
2599 *
2600 * As an exception, use the full procedure if the index access info hasn't
2601 * been initialized yet. Index creation relies on that: it first builds
2602 * the relcache entry with RelationBuildLocalRelation(), creates the
2603 * pg_index tuple only after that, and then relies on
2604 * CommandCounterIncrement to load the pg_index contents.
2605 */
2606 if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2607 relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2608 relation->rd_indexcxt != NULL)
2609 {
2610 RelationReloadIndexInfo(relation);
2611 return;
2612 }
2613 /* Nailed relations are handled separately. */
2614 else if (relation->rd_isnailed)
2615 {
2616 RelationReloadNailed(relation);
2617 return;
2618 }
2619 else
2620 {
2621 /*
2622 * Our strategy for rebuilding an open relcache entry is to build a
2623 * new entry from scratch, swap its contents with the old entry, and
2624 * finally delete the new entry (along with any infrastructure swapped
2625 * over from the old entry). This is to avoid trouble in case an
2626 * error causes us to lose control partway through. The old entry
2627 * will still be marked !rd_isvalid, so we'll try to rebuild it again
2628 * on next access. Meanwhile it's not any less valid than it was
2629 * before, so any code that might expect to continue accessing it
2630 * isn't hurt by the rebuild failure. (Consider for example a
2631 * subtransaction that ALTERs a table and then gets canceled partway
2632 * through the cache entry rebuild. The outer transaction should
2633 * still see the not-modified cache entry as valid.) The worst
2634 * consequence of an error is leaking the necessarily-unreferenced new
2635 * entry, and this shouldn't happen often enough for that to be a big
2636 * problem.
2637 *
2638 * When rebuilding an open relcache entry, we must preserve ref count,
2639 * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2640 * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2641 * and partition descriptor substructures in place, because various
2642 * places assume that these structures won't move while they are
2643 * working with an open relcache entry. (Note: the refcount
2644 * mechanism for tupledescs might someday allow us to remove this hack
2645 * for the tupledesc.)
2646 *
2647 * Note that this process does not touch CurrentResourceOwner; which
2648 * is good because whatever ref counts the entry may have do not
2649 * necessarily belong to that resource owner.
2650 */
2651 Relation newrel;
2652 Oid save_relid = RelationGetRelid(relation);
2653 bool keep_tupdesc;
2654 bool keep_rules;
2655 bool keep_policies;
2656 bool keep_partkey;
2657
2658 /* Build temporary entry, but don't link it into hashtable */
2659 newrel = RelationBuildDesc(save_relid, false);
2660
2661 /*
2662 * Between here and the end of the swap, don't add code that does or
2663 * reasonably could read system catalogs. That range must be free
2664 * from invalidation processing. See RelationBuildDesc() manipulation
2665 * of in_progress_list.
2666 */
2667
2668 if (newrel == NULL)
2669 {
2670 /*
2671 * We can validly get here, if we're using a historic snapshot in
2672 * which a relation, accessed from outside logical decoding, is
2673 * still invisible. In that case it's fine to just mark the
2674 * relation as invalid and return - it'll fully get reloaded by
2675 * the cache reset at the end of logical decoding (or at the next
2676 * access). During normal processing we don't want to ignore this
2677 * case as it shouldn't happen there, as explained below.
2678 */
2680 return;
2681
2682 /*
2683 * This shouldn't happen as dropping a relation is intended to be
2684 * impossible if still referenced (cf. CheckTableNotInUse()). But
2685 * if we get here anyway, we can't just delete the relcache entry,
2686 * as it possibly could get accessed later (as e.g. the error
2687 * might get trapped and handled via a subtransaction rollback).
2688 */
2689 elog(ERROR, "relation %u deleted while still in use", save_relid);
2690 }
2691
2692 /*
2693 * If we were to, again, have cases of the relkind of a relcache entry
2694 * changing, we would need to ensure that pgstats does not get
2695 * confused.
2696 */
2697 Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind);
2698
2699 keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2700 keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2701 keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2702 /* partkey is immutable once set up, so we can always keep it */
2703 keep_partkey = (relation->rd_partkey != NULL);
2704
2705 /*
2706 * Perform swapping of the relcache entry contents. Within this
2707 * process the old entry is momentarily invalid, so there *must* be no
2708 * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2709 * all-in-line code for safety.
2710 *
2711 * Since the vast majority of fields should be swapped, our method is
2712 * to swap the whole structures and then re-swap those few fields we
2713 * didn't want swapped.
2714 */
2715#define SWAPFIELD(fldtype, fldname) \
2716 do { \
2717 fldtype _tmp = newrel->fldname; \
2718 newrel->fldname = relation->fldname; \
2719 relation->fldname = _tmp; \
2720 } while (0)
2721
2722 /* swap all Relation struct fields */
2723 {
2724 RelationData tmpstruct;
2725
2726 memcpy(&tmpstruct, newrel, sizeof(RelationData));
2727 memcpy(newrel, relation, sizeof(RelationData));
2728 memcpy(relation, &tmpstruct, sizeof(RelationData));
2729 }
2730
2731 /* rd_smgr must not be swapped, due to back-links from smgr level */
2732 SWAPFIELD(SMgrRelation, rd_smgr);
2733 /* rd_refcnt must be preserved */
2734 SWAPFIELD(int, rd_refcnt);
2735 /* isnailed shouldn't change */
2736 Assert(newrel->rd_isnailed == relation->rd_isnailed);
2737 /* creation sub-XIDs must be preserved */
2738 SWAPFIELD(SubTransactionId, rd_createSubid);
2739 SWAPFIELD(SubTransactionId, rd_newRelfilelocatorSubid);
2740 SWAPFIELD(SubTransactionId, rd_firstRelfilelocatorSubid);
2741 SWAPFIELD(SubTransactionId, rd_droppedSubid);
2742 /* un-swap rd_rel pointers, swap contents instead */
2743 SWAPFIELD(Form_pg_class, rd_rel);
2744 /* ... but actually, we don't have to update newrel->rd_rel */
2745 memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2746 /* preserve old tupledesc, rules, policies if no logical change */
2747 if (keep_tupdesc)
2748 SWAPFIELD(TupleDesc, rd_att);
2749 if (keep_rules)
2750 {
2751 SWAPFIELD(RuleLock *, rd_rules);
2752 SWAPFIELD(MemoryContext, rd_rulescxt);
2753 }
2754 if (keep_policies)
2755 SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2756 /* toast OID override must be preserved */
2757 SWAPFIELD(Oid, rd_toastoid);
2758 /* pgstat_info / enabled must be preserved */
2759 SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2760 SWAPFIELD(bool, pgstat_enabled);
2761 /* preserve old partition key if we have one */
2762 if (keep_partkey)
2763 {
2764 SWAPFIELD(PartitionKey, rd_partkey);
2765 SWAPFIELD(MemoryContext, rd_partkeycxt);
2766 }
2767 if (newrel->rd_pdcxt != NULL || newrel->rd_pddcxt != NULL)
2768 {
2769 /*
2770 * We are rebuilding a partitioned relation with a non-zero
2771 * reference count, so we must keep the old partition descriptor
2772 * around, in case there's a PartitionDirectory with a pointer to
2773 * it. This means we can't free the old rd_pdcxt yet. (This is
2774 * necessary because RelationGetPartitionDesc hands out direct
2775 * pointers to the relcache's data structure, unlike our usual
2776 * practice which is to hand out copies. We'd have the same
2777 * problem with rd_partkey, except that we always preserve that
2778 * once created.)
2779 *
2780 * To ensure that it's not leaked completely, re-attach it to the
2781 * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2782 * in the unlikely event that there is one already. (Compare hack
2783 * in RelationBuildPartitionDesc.) RelationClose will clean up
2784 * any such contexts once the reference count reaches zero.
2785 *
2786 * In the case where the reference count is zero, this code is not
2787 * reached, which should be OK because in that case there should
2788 * be no PartitionDirectory with a pointer to the old entry.
2789 *
2790 * Note that newrel and relation have already been swapped, so the
2791 * "old" partition descriptor is actually the one hanging off of
2792 * newrel.
2793 */
2794 relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2795 relation->rd_partdesc_nodetached = NULL;
2797 if (relation->rd_pdcxt != NULL) /* probably never happens */
2798 MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2799 else
2800 relation->rd_pdcxt = newrel->rd_pdcxt;
2801 if (relation->rd_pddcxt != NULL)
2802 MemoryContextSetParent(newrel->rd_pddcxt, relation->rd_pddcxt);
2803 else
2804 relation->rd_pddcxt = newrel->rd_pddcxt;
2805 /* drop newrel's pointers so we don't destroy it below */
2806 newrel->rd_partdesc = NULL;
2807 newrel->rd_partdesc_nodetached = NULL;
2809 newrel->rd_pdcxt = NULL;
2810 newrel->rd_pddcxt = NULL;
2811 }
2812
2813#undef SWAPFIELD
2814
2815 /* And now we can throw away the temporary entry */
2816 RelationDestroyRelation(newrel, !keep_tupdesc);
2817 }
2818}
uint32 SubTransactionId
Definition: c.h:627
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
Definition: relcache.c:927
static void RelationReloadNailed(Relation relation)
Definition: relcache.c:2385
static bool equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
Definition: relcache.c:1018
static void RelationReloadIndexInfo(Relation relation)
Definition: relcache.c:2276
#define SWAPFIELD(fldtype, fldname)
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:583

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

Referenced by RelationCacheInvalidate(), RelationFlushRelation(), and RelationIdGetRelation().

◆ RelationReloadIndexInfo()

static void RelationReloadIndexInfo ( Relation  relation)
static

Definition at line 2276 of file relcache.c.

2277{
2278 bool indexOK;
2279 HeapTuple pg_class_tuple;
2280 Form_pg_class relp;
2281
2282 /* Should be called only for invalidated, live indexes */
2283 Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
2284 relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2285 !relation->rd_isvalid &&
2287
2288 /*
2289 * If it's a shared index, we might be called before backend startup has
2290 * finished selecting a database, in which case we have no way to read
2291 * pg_class yet. However, a shared index can never have any significant
2292 * schema updates, so it's okay to mostly ignore the invalidation signal.
2293 * Its physical relfilenumber might've changed, but that's all. Update
2294 * the physical relfilenumber, mark it valid and return without doing
2295 * anything more.
2296 */
2297 if (relation->rd_rel->relisshared && !criticalRelcachesBuilt)
2298 {
2299 RelationInitPhysicalAddr(relation);
2300 relation->rd_isvalid = true;
2301 return;
2302 }
2303
2304 /*
2305 * Read the pg_class row
2306 *
2307 * Don't try to use an indexscan of pg_class_oid_index to reload the info
2308 * for pg_class_oid_index ...
2309 */
2310 indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
2311 pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK, false);
2312 if (!HeapTupleIsValid(pg_class_tuple))
2313 elog(ERROR, "could not find pg_class tuple for index %u",
2314 RelationGetRelid(relation));
2315 relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2316 memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2317 /* Reload reloptions in case they changed */
2318 if (relation->rd_options)
2319 pfree(relation->rd_options);
2320 RelationParseRelOptions(relation, pg_class_tuple);
2321 /* done with pg_class tuple */
2322 heap_freetuple(pg_class_tuple);
2323 /* We must recalculate physical address in case it changed */
2324 RelationInitPhysicalAddr(relation);
2325
2326 /*
2327 * For a non-system index, there are fields of the pg_index row that are
2328 * allowed to change, so re-read that row and update the relcache entry.
2329 * Most of the info derived from pg_index (such as support function lookup
2330 * info) cannot change, and indeed the whole point of this routine is to
2331 * update the relcache entry without clobbering that data; so wholesale
2332 * replacement is not appropriate.
2333 */
2334 if (!IsSystemRelation(relation))
2335 {
2336 HeapTuple tuple;
2338
2339 tuple = SearchSysCache1(INDEXRELID,
2341 if (!HeapTupleIsValid(tuple))
2342 elog(ERROR, "cache lookup failed for index %u",
2343 RelationGetRelid(relation));
2344 index = (Form_pg_index) GETSTRUCT(tuple);
2345
2346 /*
2347 * Basically, let's just copy all the bool fields. There are one or
2348 * two of these that can't actually change in the current code, but
2349 * it's not worth it to track exactly which ones they are. None of
2350 * the array fields are allowed to change, though.
2351 */
2352 relation->rd_index->indisunique = index->indisunique;
2353 relation->rd_index->indnullsnotdistinct = index->indnullsnotdistinct;
2354 relation->rd_index->indisprimary = index->indisprimary;
2355 relation->rd_index->indisexclusion = index->indisexclusion;
2356 relation->rd_index->indimmediate = index->indimmediate;
2357 relation->rd_index->indisclustered = index->indisclustered;
2358 relation->rd_index->indisvalid = index->indisvalid;
2359 relation->rd_index->indcheckxmin = index->indcheckxmin;
2360 relation->rd_index->indisready = index->indisready;
2361 relation->rd_index->indislive = index->indislive;
2362 relation->rd_index->indisreplident = index->indisreplident;
2363
2364 /* Copy xmin too, as that is needed to make sense of indcheckxmin */
2367
2368 ReleaseSysCache(tuple);
2369 }
2370
2371 /* Okay, now it's valid again */
2372 relation->rd_isvalid = true;
2373}
bool IsSystemRelation(Relation relation)
Definition: catalog.c:74
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:324
static void HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
Definition: htup_details.h:331

References Assert(), CLASS_TUPLE_SIZE, criticalRelcachesBuilt, elog, ERROR, GETSTRUCT(), heap_freetuple(), HeapTupleHeaderGetXmin(), HeapTupleHeaderSetXmin(), HeapTupleIsValid, InvalidSubTransactionId, IsSystemRelation(), ObjectIdGetDatum(), pfree(), RelationData::rd_droppedSubid, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_isvalid, RelationData::rd_options, RelationData::rd_rel, RelationGetRelid, RelationInitPhysicalAddr(), RelationParseRelOptions(), ReleaseSysCache(), ScanPgRelation(), SearchSysCache1(), and HeapTupleData::t_data.

Referenced by RelationRebuildRelation().

◆ RelationReloadNailed()

static void RelationReloadNailed ( Relation  relation)
static

Definition at line 2385 of file relcache.c.

2386{
2387 /* Should be called only for invalidated, nailed relations */
2388 Assert(!relation->rd_isvalid);
2389 Assert(relation->rd_isnailed);
2390 /* nailed indexes are handled by RelationReloadIndexInfo() */
2391 Assert(relation->rd_rel->relkind == RELKIND_RELATION);
2393
2394 /*
2395 * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2396 * mapping changed.
2397 */
2398 RelationInitPhysicalAddr(relation);
2399
2400 /*
2401 * Reload a non-index entry. We can't easily do so if relcaches aren't
2402 * yet built, but that's fine because at that stage the attributes that
2403 * need to be current (like relfrozenxid) aren't yet accessed. To ensure
2404 * the entry will later be revalidated, we leave it in invalid state, but
2405 * allow use (cf. RelationIdGetRelation()).
2406 */
2408 {
2409 HeapTuple pg_class_tuple;
2410 Form_pg_class relp;
2411
2412 /*
2413 * NB: Mark the entry as valid before starting to scan, to avoid
2414 * self-recursion when re-building pg_class.
2415 */
2416 relation->rd_isvalid = true;
2417
2418 pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
2419 true, false);
2420 relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2421 memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2422 heap_freetuple(pg_class_tuple);
2423
2424 /*
2425 * Again mark as valid, to protect against concurrently arriving
2426 * invalidations.
2427 */
2428 relation->rd_isvalid = true;
2429 }
2430}

References Assert(), AssertCouldGetRelation(), CLASS_TUPLE_SIZE, criticalRelcachesBuilt, GETSTRUCT(), heap_freetuple(), RelationData::rd_isnailed, RelationData::rd_isvalid, RelationData::rd_rel, RelationGetRelid, RelationInitPhysicalAddr(), and ScanPgRelation().

Referenced by RelationRebuildRelation().

◆ RelationSetNewRelfilenumber()

void RelationSetNewRelfilenumber ( Relation  relation,
char  persistence 
)

Definition at line 3773 of file relcache.c.

3774{
3775 RelFileNumber newrelfilenumber;
3776 Relation pg_class;
3777 ItemPointerData otid;
3778 HeapTuple tuple;
3779 Form_pg_class classform;
3782 RelFileLocator newrlocator;
3783
3784 if (!IsBinaryUpgrade)
3785 {
3786 /* Allocate a new relfilenumber */
3787 newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3788 NULL, persistence);
3789 }
3790 else if (relation->rd_rel->relkind == RELKIND_INDEX)
3791 {
3793 ereport(ERROR,
3794 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3795 errmsg("index relfilenumber value not set when in binary upgrade mode")));
3796
3799 }
3800 else if (relation->rd_rel->relkind == RELKIND_RELATION)
3801 {
3803 ereport(ERROR,
3804 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3805 errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3806
3809 }
3810 else
3811 ereport(ERROR,
3812 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3813 errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3814
3815 /*
3816 * Get a writable copy of the pg_class tuple for the given relation.
3817 */
3818 pg_class = table_open(RelationRelationId, RowExclusiveLock);
3819
3820 tuple = SearchSysCacheLockedCopy1(RELOID,
3822 if (!HeapTupleIsValid(tuple))
3823 elog(ERROR, "could not find tuple for relation %u",
3824 RelationGetRelid(relation));
3825 otid = tuple->t_self;
3826 classform = (Form_pg_class) GETSTRUCT(tuple);
3827
3828 /*
3829 * Schedule unlinking of the old storage at transaction commit, except
3830 * when performing a binary upgrade, when we must do it immediately.
3831 */
3832 if (IsBinaryUpgrade)
3833 {
3834 SMgrRelation srel;
3835
3836 /*
3837 * During a binary upgrade, we use this code path to ensure that
3838 * pg_largeobject and its index have the same relfilenumbers as in the
3839 * old cluster. This is necessary because pg_upgrade treats
3840 * pg_largeobject like a user table, not a system table. It is however
3841 * possible that a table or index may need to end up with the same
3842 * relfilenumber in the new cluster as what it had in the old cluster.
3843 * Hence, we can't wait until commit time to remove the old storage.
3844 *
3845 * In general, this function needs to have transactional semantics,
3846 * and removing the old storage before commit time surely isn't.
3847 * However, it doesn't really matter, because if a binary upgrade
3848 * fails at this stage, the new cluster will need to be recreated
3849 * anyway.
3850 */
3851 srel = smgropen(relation->rd_locator, relation->rd_backend);
3852 smgrdounlinkall(&srel, 1, false);
3853 smgrclose(srel);
3854 }
3855 else
3856 {
3857 /* Not a binary upgrade, so just schedule it to happen later. */
3858 RelationDropStorage(relation);
3859 }
3860
3861 /*
3862 * Create storage for the main fork of the new relfilenumber. If it's a
3863 * table-like object, call into the table AM to do so, which'll also
3864 * create the table's init fork if needed.
3865 *
3866 * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3867 * be caught here, if GetNewRelFileNumber messes up for any reason.
3868 */
3869 newrlocator = relation->rd_locator;
3870 newrlocator.relNumber = newrelfilenumber;
3871
3872 if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3873 {
3874 table_relation_set_new_filelocator(relation, &newrlocator,
3875 persistence,
3876 &freezeXid, &minmulti);
3877 }
3878 else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3879 {
3880 /* handle these directly, at least for now */
3881 SMgrRelation srel;
3882
3883 srel = RelationCreateStorage(newrlocator, persistence, true);
3884 smgrclose(srel);
3885 }
3886 else
3887 {
3888 /* we shouldn't be called for anything else */
3889 elog(ERROR, "relation \"%s\" does not have storage",
3890 RelationGetRelationName(relation));
3891 }
3892
3893 /*
3894 * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3895 * change; instead we have to send the update to the relation mapper.
3896 *
3897 * For mapped indexes, we don't actually change the pg_class entry at all;
3898 * this is essential when reindexing pg_class itself. That leaves us with
3899 * possibly-inaccurate values of relpages etc, but those will be fixed up
3900 * later.
3901 */
3902 if (RelationIsMapped(relation))
3903 {
3904 /* This case is only supported for indexes */
3905 Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3906
3907 /* Since we're not updating pg_class, these had better not change */
3908 Assert(classform->relfrozenxid == freezeXid);
3909 Assert(classform->relminmxid == minmulti);
3910 Assert(classform->relpersistence == persistence);
3911
3912 /*
3913 * In some code paths it's possible that the tuple update we'd
3914 * otherwise do here is the only thing that would assign an XID for
3915 * the current transaction. However, we must have an XID to delete
3916 * files, so make sure one is assigned.
3917 */
3918 (void) GetCurrentTransactionId();
3919
3920 /* Do the deed */
3922 newrelfilenumber,
3923 relation->rd_rel->relisshared,
3924 false);
3925
3926 /* Since we're not updating pg_class, must trigger inval manually */
3927 CacheInvalidateRelcache(relation);
3928 }
3929 else
3930 {
3931 /* Normal case, update the pg_class entry */
3932 classform->relfilenode = newrelfilenumber;
3933
3934 /* relpages etc. never change for sequences */
3935 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3936 {
3937 classform->relpages = 0; /* it's empty until further notice */
3938 classform->reltuples = -1;
3939 classform->relallvisible = 0;
3940 classform->relallfrozen = 0;
3941 }
3942 classform->relfrozenxid = freezeXid;
3943 classform->relminmxid = minmulti;
3944 classform->relpersistence = persistence;
3945
3946 CatalogTupleUpdate(pg_class, &otid, tuple);
3947 }
3948
3949 UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3950 heap_freetuple(tuple);
3951
3952 table_close(pg_class, RowExclusiveLock);
3953
3954 /*
3955 * Make the pg_class row change or relation map change visible. This will
3956 * cause the relcache entry to get updated, too.
3957 */
3959
3961}
TransactionId MultiXactId
Definition: c.h:633
uint32 TransactionId
Definition: c.h:623
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:557
int errmsg(const char *fmt,...)
Definition: elog.c:1071
bool IsBinaryUpgrade
Definition: globals.c:121
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:83
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber
Definition: index.c:86
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1631
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:601
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3976
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:240
void smgrclose(SMgrRelation reln)
Definition: smgr.c:374
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:538
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:122
void RelationDropStorage(Relation rel)
Definition: storage.c:207
ItemPointerData t_self
Definition: htup.h:65
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:404
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1581
void CommandCounterIncrement(void)
Definition: xact.c:1100
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:454

References Assert(), binary_upgrade_next_heap_pg_class_relfilenumber, binary_upgrade_next_index_pg_class_relfilenumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, GetCurrentTransactionId(), GetNewRelFileNumber(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidMultiXactId, InvalidOid, InvalidTransactionId, IsBinaryUpgrade, ObjectIdGetDatum(), OidIsValid, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, RelationAssumeNewRelfilelocator(), RelationCreateStorage(), RelationDropStorage(), RelationGetRelationName, RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelFileLocator::relNumber, RowExclusiveLock, SearchSysCacheLockedCopy1(), smgrclose(), smgrdounlinkall(), smgropen(), HeapTupleData::t_self, table_close(), table_open(), table_relation_set_new_filelocator(), and UnlockTuple().

Referenced by AlterSequence(), ExecuteTruncateGuts(), reindex_index(), ResetSequence(), and SequenceChangePersistence().

◆ RememberToFreeTupleDescAtEOX()

static void RememberToFreeTupleDescAtEOX ( TupleDesc  td)
static

Definition at line 3104 of file relcache.c.

3105{
3106 if (EOXactTupleDescArray == NULL)
3107 {
3108 MemoryContext oldcxt;
3109
3111
3112 EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3115 MemoryContextSwitchTo(oldcxt);
3116 }
3118 {
3119 int32 newlen = EOXactTupleDescArrayLen * 2;
3120
3122
3124 newlen * sizeof(TupleDesc));
3125 EOXactTupleDescArrayLen = newlen;
3126 }
3127
3129}
int32_t int32
Definition: c.h:498

References Assert(), CacheMemoryContext, EOXactTupleDescArray, EOXactTupleDescArrayLen, MemoryContextSwitchTo(), NextEOXactTupleDescNum, palloc(), and repalloc().

Referenced by RelationDestroyRelation().

◆ ResourceOwnerForgetRelationRef()

static void ResourceOwnerForgetRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2173 of file relcache.c.

2174{
2176}
static const ResourceOwnerDesc relref_resowner_desc
Definition: relcache.c:2157
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:564

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerForget().

Referenced by RelationDecrementReferenceCount().

◆ ResourceOwnerRememberRelationRef()

static void ResourceOwnerRememberRelationRef ( ResourceOwner  owner,
Relation  rel 
)
inlinestatic

Definition at line 2168 of file relcache.c.

2169{
2171}
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:524

References PointerGetDatum(), relref_resowner_desc, and ResourceOwnerRemember().

Referenced by RelationIncrementReferenceCount().

◆ ResOwnerPrintRelCache()

static char * ResOwnerPrintRelCache ( Datum  res)
static

Definition at line 6974 of file relcache.c.

6975{
6976 Relation rel = (Relation) DatumGetPointer(res);
6977
6978 return psprintf("relation \"%s\"", RelationGetRelationName(rel));
6979}
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

References DatumGetPointer(), psprintf(), and RelationGetRelationName.

◆ ResOwnerReleaseRelation()

static void ResOwnerReleaseRelation ( Datum  res)
static

Definition at line 6982 of file relcache.c.

6983{
6984 Relation rel = (Relation) DatumGetPointer(res);
6985
6986 /*
6987 * This reference has already been removed from the resource owner, so
6988 * just decrement reference count without calling
6989 * ResourceOwnerForgetRelationRef.
6990 */
6991 Assert(rel->rd_refcnt > 0);
6992 rel->rd_refcnt -= 1;
6993
6995}

References Assert(), DatumGetPointer(), RelationData::rd_refcnt, and RelationCloseCleanup().

◆ ScanPgRelation()

static HeapTuple ScanPgRelation ( Oid  targetRelId,
bool  indexOK,
bool  force_non_historic 
)
static

Definition at line 340 of file relcache.c.

341{
342 HeapTuple pg_class_tuple;
343 Relation pg_class_desc;
344 SysScanDesc pg_class_scan;
345 ScanKeyData key[1];
346 Snapshot snapshot = NULL;
347
348 /*
349 * If something goes wrong during backend startup, we might find ourselves
350 * trying to read pg_class before we've selected a database. That ain't
351 * gonna work, so bail out with a useful error message. If this happens,
352 * it probably means a relcache entry that needs to be nailed isn't.
353 */
355 elog(FATAL, "cannot read pg_class without having selected a database");
356
357 /*
358 * form a scan key
359 */
360 ScanKeyInit(&key[0],
361 Anum_pg_class_oid,
362 BTEqualStrategyNumber, F_OIDEQ,
363 ObjectIdGetDatum(targetRelId));
364
365 /*
366 * Open pg_class and fetch a tuple. Force heap scan if we haven't yet
367 * built the critical relcache entries (this includes initdb and startup
368 * without a pg_internal.init file). The caller can also force a heap
369 * scan by setting indexOK == false.
370 */
371 pg_class_desc = table_open(RelationRelationId, AccessShareLock);
372
373 /*
374 * The caller might need a tuple that's newer than what's visible to the
375 * historic snapshot; currently the only case requiring to do so is
376 * looking up the relfilenumber of non mapped system relations during
377 * decoding.
378 */
379 if (force_non_historic)
380 snapshot = RegisterSnapshot(GetNonHistoricCatalogSnapshot(RelationRelationId));
381
382 pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
383 indexOK && criticalRelcachesBuilt,
384 snapshot,
385 1, key);
386
387 pg_class_tuple = systable_getnext(pg_class_scan);
388
389 /*
390 * Must copy tuple before releasing buffer.
391 */
392 if (HeapTupleIsValid(pg_class_tuple))
393 pg_class_tuple = heap_copytuple(pg_class_tuple);
394
395 /* all done */
396 systable_endscan(pg_class_scan);
397
398 if (snapshot)
399 UnregisterSnapshot(snapshot);
400
401 table_close(pg_class_desc, AccessShareLock);
402
403 return pg_class_tuple;
404}
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:853
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:811
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:395

References AccessShareLock, BTEqualStrategyNumber, criticalRelcachesBuilt, elog, FATAL, GetNonHistoricCatalogSnapshot(), heap_copytuple(), HeapTupleIsValid, sort-test::key, MyDatabaseId, ObjectIdGetDatum(), OidIsValid, RegisterSnapshot(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and UnregisterSnapshot().

Referenced by RelationBuildDesc(), RelationInitPhysicalAddr(), RelationReloadIndexInfo(), and RelationReloadNailed().

◆ unlink_initfile()

static void unlink_initfile ( const char *  initfilename,
int  elevel 
)
static

Definition at line 6957 of file relcache.c.

6958{
6959 if (unlink(initfilename) < 0)
6960 {
6961 /* It might not be there, but log any error other than ENOENT */
6962 if (errno != ENOENT)
6963 ereport(elevel,
6965 errmsg("could not remove cache file \"%s\": %m",
6966 initfilename)));
6967 }
6968}
int errcode_for_file_access(void)
Definition: elog.c:877

References ereport, errcode_for_file_access(), and errmsg().

Referenced by RelationCacheInitFilePreInvalidate(), RelationCacheInitFileRemove(), and RelationCacheInitFileRemoveInDir().

◆ write_item()

static void write_item ( const void *  data,
Size  len,
FILE *  fp 
)
static

Definition at line 6797 of file relcache.c.

6798{
6799 if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6800 ereport(FATAL,
6802 errmsg_internal("could not write init file: %m"));
6803 if (len > 0 && fwrite(data, 1, len, fp) != len)
6804 ereport(FATAL,
6806 errmsg_internal("could not write init file: %m"));
6807}
const void * data

References data, ereport, errcode_for_file_access(), errmsg_internal(), FATAL, and len.

Referenced by write_relcache_init_file().

◆ write_relcache_init_file()

static void write_relcache_init_file ( bool  shared)
static

Definition at line 6585 of file relcache.c.

6586{
6587 FILE *fp;
6588 char tempfilename[MAXPGPATH];
6589 char finalfilename[MAXPGPATH];
6590 int magic;
6591 HASH_SEQ_STATUS status;
6592 RelIdCacheEnt *idhentry;
6593 int i;
6594
6595 /*
6596 * If we have already received any relcache inval events, there's no
6597 * chance of succeeding so we may as well skip the whole thing.
6598 */
6599 if (relcacheInvalsReceived != 0L)
6600 return;
6601
6602 /*
6603 * We must write a temporary file and rename it into place. Otherwise,
6604 * another backend starting at about the same time might crash trying to
6605 * read the partially-complete file.
6606 */
6607 if (shared)
6608 {
6609 snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d",
6611 snprintf(finalfilename, sizeof(finalfilename), "global/%s",
6613 }
6614 else
6615 {
6616 snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
6618 snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
6620 }
6621
6622 unlink(tempfilename); /* in case it exists w/wrong permissions */
6623
6624 fp = AllocateFile(tempfilename, PG_BINARY_W);
6625 if (fp == NULL)
6626 {
6627 /*
6628 * We used to consider this a fatal error, but we might as well
6629 * continue with backend startup ...
6630 */
6633 errmsg("could not create relation-cache initialization file \"%s\": %m",
6634 tempfilename),
6635 errdetail("Continuing anyway, but there's something wrong.")));
6636 return;
6637 }
6638
6639 /*
6640 * Write a magic number to serve as a file version identifier. We can
6641 * change the magic number whenever the relcache layout changes.
6642 */
6644 if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6645 ereport(FATAL,
6647 errmsg_internal("could not write init file: %m"));
6648
6649 /*
6650 * Write all the appropriate reldescs (in no particular order).
6651 */
6653
6654 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
6655 {
6656 Relation rel = idhentry->reldesc;
6657 Form_pg_class relform = rel->rd_rel;
6658
6659 /* ignore if not correct group */
6660 if (relform->relisshared != shared)
6661 continue;
6662
6663 /*
6664 * Ignore if not supposed to be in init file. We can allow any shared
6665 * relation that's been loaded so far to be in the shared init file,
6666 * but unshared relations must be ones that should be in the local
6667 * file per RelationIdIsInInitFile. (Note: if you want to change the
6668 * criterion for rels to be kept in the init file, see also inval.c.
6669 * The reason for filtering here is to be sure that we don't put
6670 * anything into the local init file for which a relcache inval would
6671 * not cause invalidation of that init file.)
6672 */
6673 if (!shared && !RelationIdIsInInitFile(RelationGetRelid(rel)))
6674 {
6675 /* Nailed rels had better get stored. */
6676 Assert(!rel->rd_isnailed);
6677 continue;
6678 }
6679
6680 /* first write the relcache entry proper */
6681 write_item(rel, sizeof(RelationData), fp);
6682
6683 /* next write the relation tuple form */
6684 write_item(relform, CLASS_TUPLE_SIZE, fp);
6685
6686 /* next, do all the attribute tuple form data entries */
6687 for (i = 0; i < relform->relnatts; i++)
6688 {
6691 }
6692
6693 /* next, do the access method specific field */
6695 (rel->rd_options ? VARSIZE(rel->rd_options) : 0),
6696 fp);
6697
6698 /*
6699 * If it's an index, there's more to do. Note we explicitly ignore
6700 * partitioned indexes here.
6701 */
6702 if (rel->rd_rel->relkind == RELKIND_INDEX)
6703 {
6704 /* write the pg_index tuple */
6705 /* we assume this was created by heap_copytuple! */
6708 fp);
6709
6710 /* write the vector of opfamily OIDs */
6712 relform->relnatts * sizeof(Oid),
6713 fp);
6714
6715 /* write the vector of opcintype OIDs */
6717 relform->relnatts * sizeof(Oid),
6718 fp);
6719
6720 /* write the vector of support procedure OIDs */
6722 relform->relnatts * (rel->rd_indam->amsupport * sizeof(RegProcedure)),
6723 fp);
6724
6725 /* write the vector of collation OIDs */
6727 relform->relnatts * sizeof(Oid),
6728 fp);
6729
6730 /* write the vector of indoption values */
6732 relform->relnatts * sizeof(int16),
6733 fp);
6734
6735 Assert(rel->rd_opcoptions);
6736
6737 /* write the vector of opcoptions values */
6738 for (i = 0; i < relform->relnatts; i++)
6739 {
6740 bytea *opt = rel->rd_opcoptions[i];
6741
6742 write_item(opt, opt ? VARSIZE(opt) : 0, fp);
6743 }
6744 }
6745 }
6746
6747 if (FreeFile(fp))
6748 ereport(FATAL,
6750 errmsg_internal("could not write init file: %m"));
6751
6752 /*
6753 * Now we have to check whether the data we've so painstakingly
6754 * accumulated is already obsolete due to someone else's just-committed
6755 * catalog changes. If so, we just delete the temp file and leave it to
6756 * the next backend to try again. (Our own relcache entries will be
6757 * updated by SI message processing, but we can't be sure whether what we
6758 * wrote out was up-to-date.)
6759 *
6760 * This mustn't run concurrently with the code that unlinks an init file
6761 * and sends SI messages, so grab a serialization lock for the duration.
6762 */
6763 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6764
6765 /* Make sure we have seen all incoming SI messages */
6767
6768 /*
6769 * If we have received any SI relcache invals since backend start, assume
6770 * we may have written out-of-date data.
6771 */
6772 if (relcacheInvalsReceived == 0L)
6773 {
6774 /*
6775 * OK, rename the temp file to its final name, deleting any
6776 * previously-existing init file.
6777 *
6778 * Note: a failure here is possible under Cygwin, if some other
6779 * backend is holding open an unlinked-but-not-yet-gone init file. So
6780 * treat this as a noncritical failure; just remove the useless temp
6781 * file on failure.
6782 */
6783 if (rename(tempfilename, finalfilename) < 0)
6784 unlink(tempfilename);
6785 }
6786 else
6787 {
6788 /* Delete the already-obsolete temp file */
6789 unlink(tempfilename);
6790 }
6791
6792 LWLockRelease(RelCacheInitLock);
6793}
#define PG_BINARY_W
Definition: c.h:1247
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int MyProcPid
Definition: globals.c:47
void AcceptInvalidationMessages(void)
Definition: inval.c:930
static void write_item(const void *data, Size len, FILE *fp)
Definition: relcache.c:6797
bool RelationIdIsInInitFile(Oid relationId)
Definition: relcache.c:6820
uint32 t_len
Definition: htup.h:64

References AcceptInvalidationMessages(), AllocateFile(), IndexAmRoutine::amsupport, Assert(), ATTRIBUTE_FIXED_PART_SIZE, CLASS_TUPLE_SIZE, DatabasePath, ereport, errcode_for_file_access(), errdetail(), errmsg(), errmsg_internal(), FATAL, FreeFile(), hash_seq_init(), hash_seq_search(), HEAPTUPLESIZE, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, MyProcPid, PG_BINARY_W, RelationData::rd_att, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_isnailed, RelationData::rd_opcintype, RelationData::rd_opcoptions, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_support, RelationGetRelid, RelationIdCache, RelationIdIsInInitFile(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, relcacheInvalsReceived, relidcacheent::reldesc, snprintf, HeapTupleData::t_len, TupleDescAttr(), VARSIZE, WARNING, and write_item().

Referenced by RelationCacheInitializePhase3().

Variable Documentation

◆ criticalRelcachesBuilt

◆ criticalSharedRelcachesBuilt

◆ Desc_pg_attribute

const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}
static

Definition at line 112 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_auth_members

const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members}
static

Definition at line 117 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_authid

const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid}
static

Definition at line 116 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_class

const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}
static

Definition at line 111 of file relcache.c.

Referenced by GetPgClassDescriptor(), and RelationCacheInitializePhase3().

◆ Desc_pg_database

const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database}
static

Definition at line 115 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_index

const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}
static

Definition at line 118 of file relcache.c.

Referenced by GetPgIndexDescriptor().

◆ Desc_pg_proc

const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}
static

Definition at line 113 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ Desc_pg_shseclabel

const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel] = {Schema_pg_shseclabel}
static

Definition at line 119 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_subscription

const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription] = {Schema_pg_subscription}
static

Definition at line 120 of file relcache.c.

Referenced by RelationCacheInitializePhase2().

◆ Desc_pg_type

const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}
static

Definition at line 114 of file relcache.c.

Referenced by RelationCacheInitializePhase3().

◆ eoxact_list

Oid eoxact_list[MAX_EOXACT_LIST]
static

Definition at line 185 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_len

int eoxact_list_len = 0
static

Definition at line 186 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ eoxact_list_overflowed

bool eoxact_list_overflowed = false
static

Definition at line 187 of file relcache.c.

Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().

◆ EOXactTupleDescArray

TupleDesc* EOXactTupleDescArray
static

Definition at line 202 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ EOXactTupleDescArrayLen

int EOXactTupleDescArrayLen = 0
static

Definition at line 204 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ in_progress_list

◆ in_progress_list_len

◆ in_progress_list_maxlen

int in_progress_list_maxlen
static

Definition at line 172 of file relcache.c.

Referenced by RelationBuildDesc(), and RelationCacheInitialize().

◆ NextEOXactTupleDescNum

int NextEOXactTupleDescNum = 0
static

Definition at line 203 of file relcache.c.

Referenced by AtEOXact_RelationCache(), and RememberToFreeTupleDescAtEOX().

◆ OpClassCache

HTAB* OpClassCache = NULL
static

Definition at line 271 of file relcache.c.

Referenced by LookupOpclassInfo().

◆ RelationIdCache

◆ relcacheInvalsReceived

long relcacheInvalsReceived = 0L
static

◆ relref_resowner_desc

const ResourceOwnerDesc relref_resowner_desc
static
Initial value:
=
{
.name = "relcache reference",
.release_priority = RELEASE_PRIO_RELCACHE_REFS,
.ReleaseResource = ResOwnerReleaseRelation,
.DebugPrint = ResOwnerPrintRelCache
}
static void ResOwnerReleaseRelation(Datum res)
Definition: relcache.c:6982
static char * ResOwnerPrintRelCache(Datum res)
Definition: relcache.c:6974
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
#define RELEASE_PRIO_RELCACHE_REFS
Definition: resowner.h:64

Definition at line 2157 of file relcache.c.

Referenced by ResourceOwnerForgetRelationRef(), and ResourceOwnerRememberRelationRef().