PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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:955
#define WARNING
Definition: elog.h:36
static HTAB * RelationIdCache
Definition: relcache.c:134

Definition at line 243 of file relcache.c.

◆ RelationCacheInsert

#define RelationCacheInsert (   RELATION,
  replace_allowed 
)
Value:
do { \
RelIdCacheEnt *hentry; bool found; \
&((RELATION)->rd_id), \
HASH_ENTER, &found); \
if (found) \
{ \
/* see comments in RelationBuildDesc and RelationBuildLocalRelation */ \
Relation _old_rel = hentry->reldesc; \
Assert(replace_allowed); \
hentry->reldesc = (RELATION); \
RelationDestroyRelation(_old_rel, false); \
elog(WARNING, "leaking still-referenced relcache entry for \"%s\"", \
} \
else \
hentry->reldesc = (RELATION); \
} while(0)
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:477
#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:1969
void * palloc(Size size)
Definition: mcxt.c:1939
MemoryContext CacheMemoryContext
Definition: mcxt.c:168
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:226
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:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c: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:2146
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:2308
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
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 4705 of file relcache.c.

4706{
4707 const ConstrCheck *ca = (const ConstrCheck *) a;
4708 const ConstrCheck *cb = (const ConstrCheck *) b;
4709
4710 return strcmp(ca->ccname, cb->ccname);
4711}
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 */
4602 check = (ConstrCheck *)
4604 ncheck * sizeof(ConstrCheck));
4605
4606 /* Search pg_constraint for relevant entries */
4607 ScanKeyInit(&skey[0],
4608 Anum_pg_constraint_conrelid,
4609 BTEqualStrategyNumber, F_OIDEQ,
4611
4612 conrel = table_open(ConstraintRelationId, AccessShareLock);
4613 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4614 NULL, 1, skey);
4615
4616 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4617 {
4619 Datum val;
4620 bool isnull;
4621
4622 /*
4623 * If this is a not-null constraint, then only look at it if it's
4624 * invalid, and if so, mark the TupleDesc entry as known invalid.
4625 * Otherwise move on. We'll mark any remaining columns that are still
4626 * in UNKNOWN state as known valid later. This allows us not to have
4627 * to extract the attnum from this constraint tuple in the vast
4628 * majority of cases.
4629 */
4630 if (conform->contype == CONSTRAINT_NOTNULL)
4631 {
4632 if (!conform->convalidated)
4633 {
4635
4639 relation->rd_att->compact_attrs[attnum - 1].attnullability =
4641 }
4642
4643 continue;
4644 }
4645
4646 /* For what follows, consider check constraints only */
4647 if (conform->contype != CONSTRAINT_CHECK)
4648 continue;
4649
4650 /* protect limited size of array */
4651 if (found >= ncheck)
4652 {
4653 elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4654 RelationGetRelationName(relation));
4655 break;
4656 }
4657
4658 check[found].ccenforced = conform->conenforced;
4659 check[found].ccvalid = conform->convalidated;
4660 check[found].ccnoinherit = conform->connoinherit;
4662 NameStr(conform->conname));
4663
4664 /* Grab and test conbin is actually set */
4665 val = fastgetattr(htup,
4666 Anum_pg_constraint_conbin,
4667 conrel->rd_att, &isnull);
4668 if (isnull)
4669 elog(WARNING, "null conbin for relation \"%s\"",
4670 RelationGetRelationName(relation));
4671 else
4672 {
4673 /* detoast and convert to cstring in caller's context */
4674 char *s = TextDatumGetCString(val);
4675
4676 check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4677 pfree(s);
4678 found++;
4679 }
4680 }
4681
4682 systable_endscan(conscan);
4684
4685 if (found != ncheck)
4686 elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4687 ncheck - found, RelationGetRelationName(relation));
4688
4689 /*
4690 * Sort the records by name. This ensures that CHECKs are applied in a
4691 * deterministic order, and it also makes equalTupleDescs() faster.
4692 */
4693 if (found > 1)
4694 qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4695
4696 /* Install array only after it's fully valid */
4697 relation->rd_att->constr->check = check;
4698 relation->rd_att->constr->num_check = found;
4699}
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:4705
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 5965 of file relcache.c.

5966{
5967 bytea **opts = palloc(sizeof(*opts) * natts);
5968
5969 for (int i = 0; i < natts; i++)
5970 {
5971 bytea *opt = srcopts[i];
5972
5973 opts[i] = !opt ? NULL : (bytea *)
5974 DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5975 }
5976
5977 return opts;
5978}
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 6046 of file relcache.c.

6047{
6051
6052 return 0; /* return value does not matter */
6053}
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 6063 of file relcache.c.

6064{
6065 TupleDesc reldesc = RelationGetDescr(rel);
6066 const char *colname;
6067
6068 /* Use reldesc if it's a user attribute, else consult the catalogs */
6069 if (attnum > 0 && attnum <= reldesc->natts)
6070 colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
6071 else
6072 colname = get_attname(RelationGetRelid(rel), attnum, false);
6073
6074 return errtablecolname(rel, colname);
6075}
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:6087

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

6088{
6089 errtable(rel);
6091
6092 return 0; /* return value does not matter */
6093}
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:62
int errtable(Relation rel)
Definition: relcache.c:6046

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:1256
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:5985

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

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

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

6883{
6884 LWLockRelease(RelCacheInitLock);
6885}
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1902

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6857 of file relcache.c.

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

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

6898{
6899 const char *tblspcdir = PG_TBLSPC_DIR;
6900 DIR *dir;
6901 struct dirent *de;
6902 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6903
6904 snprintf(path, sizeof(path), "global/%s",
6906 unlink_initfile(path, LOG);
6907
6908 /* Scan everything in the default tablespace */
6910
6911 /* Scan the tablespace link directory to find non-default tablespaces */
6912 dir = AllocateDir(tblspcdir);
6913
6914 while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6915 {
6916 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6917 {
6918 /* Scan the tablespace dir for per-database dirs */
6919 snprintf(path, sizeof(path), "%s/%s/%s",
6920 tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6922 }
6923 }
6924
6925 FreeDir(dir);
6926}
#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:6930
#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 6930 of file relcache.c.

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

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:6164
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:1514
#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:6582
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:570
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 5153 of file relcache.c.

5154{
5155 List *result;
5156 Datum exprsDatum;
5157 bool isnull;
5158 char *exprsString;
5159 List *rawExprs;
5160 ListCell *lc;
5161
5162 /* Quick exit if there is nothing to do. */
5163 if (relation->rd_indextuple == NULL ||
5164 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5165 return NIL;
5166
5167 /* Extract raw node tree(s) from index tuple. */
5168 exprsDatum = heap_getattr(relation->rd_indextuple,
5169 Anum_pg_index_indexprs,
5171 &isnull);
5172 Assert(!isnull);
5173 exprsString = TextDatumGetCString(exprsDatum);
5174 rawExprs = (List *) stringToNode(exprsString);
5175 pfree(exprsString);
5176
5177 /* Construct null Consts; the typlen and typbyval are arbitrary. */
5178 result = NIL;
5179 foreach(lc, rawExprs)
5180 {
5181 Node *rawExpr = (Node *) lfirst(lc);
5182
5183 result = lappend(result,
5184 makeConst(exprType(rawExpr),
5185 exprTypmod(rawExpr),
5186 exprCollation(rawExpr),
5187 1,
5188 (Datum) 0,
5189 true,
5190 true));
5191 }
5192
5193 return result;
5194}
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 5650 of file relcache.c.

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

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

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

5986{
5987 MemoryContext oldcxt;
5988 bytea **opts = relation->rd_opcoptions;
5989 Oid relid = RelationGetRelid(relation);
5990 int natts = RelationGetNumberOfAttributes(relation); /* XXX
5991 * IndexRelationGetNumberOfKeyAttributes */
5992 int i;
5993
5994 /* Try to copy cached options. */
5995 if (opts)
5996 return copy ? CopyIndexAttOptions(opts, natts) : opts;
5997
5998 /* Get and parse opclass options. */
5999 opts = palloc0(sizeof(*opts) * natts);
6000
6001 for (i = 0; i < natts; i++)
6002 {
6003 if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
6004 {
6005 Datum attoptions = get_attoptions(relid, i + 1);
6006
6007 opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
6008
6009 if (attoptions != (Datum) 0)
6010 pfree(DatumGetPointer(attoptions));
6011 }
6012 }
6013
6014 /* Copy parsed options to the cache. */
6015 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
6016 relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
6017 MemoryContextSwitchTo(oldcxt);
6018
6019 if (copy)
6020 return opts;
6021
6022 for (i = 0; i < natts; i++)
6023 {
6024 if (opts[i])
6025 pfree(opts[i]);
6026 }
6027
6028 pfree(opts);
6029
6030 return relation->rd_opcoptions;
6031}
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:5965

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

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

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

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

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

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

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

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

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

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

6818{
6819 if (relationId == SharedSecLabelRelationId ||
6820 relationId == TriggerRelidNameIndexId ||
6821 relationId == DatabaseNameIndexId ||
6822 relationId == SharedSecLabelObjectIndexId)
6823 {
6824 /*
6825 * If this Assert fails, we don't need the applicable special case
6826 * anymore.
6827 */
6828 Assert(!RelationSupportsSysCache(relationId));
6829 return true;
6830 }
6831 return RelationSupportsSysCache(relationId);
6832}
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:97
Oid MyDatabaseId
Definition: globals.c:95
#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:668
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:559
int errmsg(const char *fmt,...)
Definition: elog.c:1071
bool IsBinaryUpgrade
Definition: globals.c:122
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 6971 of file relcache.c.

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

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

◆ ResOwnerReleaseRelation()

static void ResOwnerReleaseRelation ( Datum  res)
static

Definition at line 6979 of file relcache.c.

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

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

6955{
6956 if (unlink(initfilename) < 0)
6957 {
6958 /* It might not be there, but log any error other than ENOENT */
6959 if (errno != ENOENT)
6960 ereport(elevel,
6962 errmsg("could not remove cache file \"%s\": %m",
6963 initfilename)));
6964 }
6965}
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 6794 of file relcache.c.

6795{
6796 if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6797 ereport(FATAL,
6799 errmsg_internal("could not write init file: %m"));
6800 if (len > 0 && fwrite(data, 1, len, fp) != len)
6801 ereport(FATAL,
6803 errmsg_internal("could not write init file: %m"));
6804}
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 6582 of file relcache.c.

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