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

Go to the source code of this file.

Data Structures

struct  relidcacheent
 
struct  inprogressent
 
struct  opclasscacheent
 

Macros

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

Typedefs

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

Functions

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

Variables

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

Macro Definition Documentation

◆ EOXactListAdd

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

Definition at line 189 of file relcache.c.

◆ INITRELCACHESIZE

#define INITRELCACHESIZE   400

Definition at line 3946 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:466
#define RelationHasReferenceCountZero(relation)
Definition: rel.h:496
#define RelationGetRelationName(relation)
Definition: rel.h:546

Definition at line 209 of file relcache.c.

◆ RelationIdCacheLookup

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

Definition at line 231 of file relcache.c.

◆ RELCACHE_INIT_FILEMAGIC

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

Definition at line 93 of file relcache.c.

◆ SWAPFIELD

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

Typedef Documentation

◆ InProgressEnt

typedef struct inprogressent InProgressEnt

◆ OpClassCacheEnt

◆ RelIdCacheEnt

typedef struct relidcacheent RelIdCacheEnt

Function Documentation

◆ AllocateRelationDesc()

static Relation AllocateRelationDesc ( Form_pg_class  relp)
static

Definition at line 410 of file relcache.c.

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

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

3391{
3392 /*
3393 * Is it a relation created in the current subtransaction?
3394 *
3395 * During subcommit, mark it as belonging to the parent, instead, as long
3396 * as it has not been dropped. Otherwise simply delete the relcache entry.
3397 * --- it isn't interesting any longer.
3398 */
3399 if (relation->rd_createSubid == mySubid)
3400 {
3401 /*
3402 * Valid rd_droppedSubid means the corresponding relation is dropped
3403 * but the relcache entry is preserved for at-commit pending sync. We
3404 * need to drop it explicitly here not to make the entry orphan.
3405 */
3406 Assert(relation->rd_droppedSubid == mySubid ||
3408 if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3409 relation->rd_createSubid = parentSubid;
3410 else if (RelationHasReferenceCountZero(relation))
3411 {
3412 /* allow the entry to be removed */
3417 RelationClearRelation(relation);
3418 return;
3419 }
3420 else
3421 {
3422 /*
3423 * Hmm, somewhere there's a (leaked?) reference to the relation.
3424 * We daren't remove the entry for fear of dereferencing a
3425 * dangling pointer later. Bleat, and transfer it to the parent
3426 * subtransaction so we can try again later. This must be just a
3427 * WARNING to avoid error-during-error-recovery loops.
3428 */
3429 relation->rd_createSubid = parentSubid;
3430 elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3431 RelationGetRelationName(relation));
3432 }
3433 }
3434
3435 /*
3436 * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3437 * or drop record.
3438 */
3439 if (relation->rd_newRelfilelocatorSubid == mySubid)
3440 {
3441 if (isCommit)
3442 relation->rd_newRelfilelocatorSubid = parentSubid;
3443 else
3445 }
3446
3447 if (relation->rd_firstRelfilelocatorSubid == mySubid)
3448 {
3449 if (isCommit)
3450 relation->rd_firstRelfilelocatorSubid = parentSubid;
3451 else
3453 }
3454
3455 if (relation->rd_droppedSubid == mySubid)
3456 {
3457 if (isCommit)
3458 relation->rd_droppedSubid = parentSubid;
3459 else
3461 }
3462}
#define InvalidSubTransactionId
Definition: c.h:615
#define Assert(condition)
Definition: c.h:815
#define elog(elevel,...)
Definition: elog.h:225
static void RelationClearRelation(Relation relation)
Definition: relcache.c:2501
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 3334 of file relcache.c.

3336{
3337 HASH_SEQ_STATUS status;
3338 RelIdCacheEnt *idhentry;
3339 int i;
3340
3341 /*
3342 * Forget in_progress_list. This is relevant when we're aborting due to
3343 * an error during RelationBuildDesc(). We don't commit subtransactions
3344 * during RelationBuildDesc().
3345 */
3346 Assert(in_progress_list_len == 0 || !isCommit);
3348
3349 /*
3350 * Unless the eoxact_list[] overflowed, we only need to examine the rels
3351 * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3352 * logic as in AtEOXact_RelationCache.
3353 */
3355 {
3357 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3358 {
3359 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3360 mySubid, parentSubid);
3361 }
3362 }
3363 else
3364 {
3365 for (i = 0; i < eoxact_list_len; i++)
3366 {
3368 &eoxact_list[i],
3369 HASH_FIND,
3370 NULL);
3371 if (idhentry != NULL)
3372 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3373 mySubid, parentSubid);
3374 }
3375 }
3376
3377 /* Don't reset the list; we still need more cleanup later */
3378}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
@ HASH_FIND
Definition: hsearch.h:113
int i
Definition: isn.c:72
static Oid eoxact_list[MAX_EOXACT_LIST]
Definition: relcache.c:185
static int in_progress_list_len
Definition: relcache.c:171
static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: relcache.c:3389
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 3252 of file relcache.c.

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

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

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

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

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

Referenced by AttrDefaultFetch().

◆ AttrDefaultFetch()

static void AttrDefaultFetch ( Relation  relation,
int  ndef 
)
static

Definition at line 4442 of file relcache.c.

4443{
4444 AttrDefault *attrdef;
4445 Relation adrel;
4446 SysScanDesc adscan;
4447 ScanKeyData skey;
4448 HeapTuple htup;
4449 int found = 0;
4450
4451 /* Allocate array with room for as many entries as expected */
4452 attrdef = (AttrDefault *)
4454 ndef * sizeof(AttrDefault));
4455
4456 /* Search pg_attrdef for relevant entries */
4457 ScanKeyInit(&skey,
4458 Anum_pg_attrdef_adrelid,
4459 BTEqualStrategyNumber, F_OIDEQ,
4461
4462 adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4463 adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4464 NULL, 1, &skey);
4465
4466 while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4467 {
4468 Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4469 Datum val;
4470 bool isnull;
4471
4472 /* protect limited size of array */
4473 if (found >= ndef)
4474 {
4475 elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4476 adform->adnum, RelationGetRelationName(relation));
4477 break;
4478 }
4479
4480 val = fastgetattr(htup,
4481 Anum_pg_attrdef_adbin,
4482 adrel->rd_att, &isnull);
4483 if (isnull)
4484 elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4485 adform->adnum, RelationGetRelationName(relation));
4486 else
4487 {
4488 /* detoast and convert to cstring in caller's context */
4489 char *s = TextDatumGetCString(val);
4490
4491 attrdef[found].adnum = adform->adnum;
4492 attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4493 pfree(s);
4494 found++;
4495 }
4496 }
4497
4498 systable_endscan(adscan);
4500
4501 if (found != ndef)
4502 elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4503 ndef - found, RelationGetRelationName(relation));
4504
4505 /*
4506 * Sort the AttrDefault entries by adnum, for the convenience of
4507 * equalTupleDescs(). (Usually, they already will be in order, but this
4508 * might not be so if systable_getnext isn't using an index.)
4509 */
4510 if (found > 1)
4511 qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4512
4513 /* Install array only after it's fully valid */
4514 relation->rd_att->constr->defval = attrdef;
4515 relation->rd_att->constr->num_defval = found;
4516}
#define TextDatumGetCString(d)
Definition: builtins.h:98
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
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:860
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define qsort(a, b, c, d)
Definition: port.h:475
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define RelationGetRelid(relation)
Definition: rel.h:512
static int AttrDefaultCmp(const void *a, const void *b)
Definition: relcache.c:4522
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:135
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 4377 of file relcache.c.

4378{
4379 TupleDesc result;
4380 MemoryContext oldcxt;
4381 int i;
4382
4384
4385 result = CreateTemplateTupleDesc(natts);
4386 result->tdtypeid = RECORDOID; /* not right, but we don't care */
4387 result->tdtypmod = -1;
4388
4389 for (i = 0; i < natts; i++)
4390 {
4391 memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4392
4394 }
4395
4396 /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
4397 TupleDescCompactAttr(result, 0)->attcacheoff = 0;
4398
4399 /* Note: we don't bother to set up a TupleConstr entry */
4400
4401 MemoryContextSwitchTo(oldcxt);
4402
4403 return result;
4404}
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:192
int32 attcacheoff
Definition: tupdesc.h:70
int32 tdtypmod
Definition: tupdesc.h:133
Oid tdtypeid
Definition: tupdesc.h:132
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:107
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:169

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

4628{
4629 const ConstrCheck *ca = (const ConstrCheck *) a;
4630 const ConstrCheck *cb = (const ConstrCheck *) b;
4631
4632 return strcmp(ca->ccname, cb->ccname);
4633}
char * ccname
Definition: tupdesc.h:30

References a, b, and ConstrCheck::ccname.

Referenced by CheckConstraintFetch().

◆ CheckConstraintFetch()

static void CheckConstraintFetch ( Relation  relation)
static

Definition at line 4537 of file relcache.c.

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

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

Referenced by RelationBuildTupleDesc().

◆ CopyIndexAttOptions()

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

Definition at line 5891 of file relcache.c.

5892{
5893 bytea **opts = palloc(sizeof(*opts) * natts);
5894
5895 for (int i = 0; i < natts; i++)
5896 {
5897 bytea *opt = srcopts[i];
5898
5899 opts[i] = !opt ? NULL : (bytea *)
5900 DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
5901 }
5902
5903 return opts;
5904}
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:644

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

Referenced by RelationGetIndexAttOptions().

◆ equalPolicy()

static bool equalPolicy ( RowSecurityPolicy policy1,
RowSecurityPolicy policy2 
)
static

Definition at line 943 of file relcache.c.

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

990{
991 ListCell *lc,
992 *rc;
993
994 if (rsdesc1 == NULL && rsdesc2 == NULL)
995 return true;
996
997 if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
998 (rsdesc1 == NULL && rsdesc2 != NULL))
999 return false;
1000
1001 if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1002 return false;
1003
1004 /* RelationBuildRowSecurity should build policies in order */
1005 forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1006 {
1009
1010 if (!equalPolicy(l, r))
1011 return false;
1012 }
1013
1014 return true;
1015}
#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:943

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

Referenced by RelationRebuildRelation().

◆ equalRuleLocks()

static bool equalRuleLocks ( RuleLock rlock1,
RuleLock rlock2 
)
static

Definition at line 898 of file relcache.c.

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

5973{
5977
5978 return 0; /* return value does not matter */
5979}
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3393
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define RelationGetNamespace(relation)
Definition: rel.h:553

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

5990{
5991 TupleDesc reldesc = RelationGetDescr(rel);
5992 const char *colname;
5993
5994 /* Use reldesc if it's a user attribute, else consult the catalogs */
5995 if (attnum > 0 && attnum <= reldesc->natts)
5996 colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
5997 else
5998 colname = get_attname(RelationGetRelid(rel), attnum, false);
5999
6000 return errtablecolname(rel, colname);
6001}
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:828
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetDescr(relation)
Definition: rel.h:538
int errtablecolname(Relation rel, const char *colname)
Definition: relcache.c:6013

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

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

◆ errtablecolname()

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 6013 of file relcache.c.

6014{
6015 errtable(rel);
6017
6018 return 0; /* return value does not matter */
6019}
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
int errtable(Relation rel)
Definition: relcache.c:5972

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

Referenced by errtablecol().

◆ errtableconstraint()

int errtableconstraint ( Relation  rel,
const char *  conname 
)

◆ formrdesc()

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

Definition at line 1865 of file relcache.c.

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

4408{
4409 static TupleDesc pgclassdesc = NULL;
4410
4411 /* Already done? */
4412 if (pgclassdesc == NULL)
4413 pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4415
4416 return pgclassdesc;
4417}
static TupleDesc BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
Definition: relcache.c:4377
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 4420 of file relcache.c.

4421{
4422 static TupleDesc pgindexdesc = NULL;
4423
4424 /* Already done? */
4425 if (pgindexdesc == NULL)
4426 pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4428
4429 return pgindexdesc;
4430}
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 1587 of file relcache.c.

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

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

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

Referenced by load_relcache_init_file(), and RelationInitIndexAccessInfo().

◆ InitTableAmRoutine()

static void InitTableAmRoutine ( Relation  relation)
static

Definition at line 1791 of file relcache.c.

1792{
1793 relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1794}
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 4339 of file relcache.c.

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

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

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

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

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

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

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

◆ RelationBuildDesc()

static Relation RelationBuildDesc ( Oid  targetRelId,
bool  insertIt 
)
static

Definition at line 1030 of file relcache.c.

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

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

References Assert, CacheMemoryContext, CLASS_TUPLE_SIZE, TupleDescData::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), TupleConstr::has_not_null, i, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, IsCatalogNamespace(), IsSharedRelation(), isTempOrTempToastNamespace(), MemoryContextSwitchTo(), namestrcpy(), TupleDescData::natts, palloc0(), 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, and TupleDescAttr().

Referenced by heap_create().

◆ RelationBuildPublicationDesc()

void RelationBuildPublicationDesc ( Relation  relation,
PublicationDesc pubdesc 
)

Definition at line 5717 of file relcache.c.

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

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

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RelationBuildTupleDesc()

static void RelationBuildTupleDesc ( Relation  relation)
static

Definition at line 522 of file relcache.c.

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

References AccessShareLock, AttrMissing::am_present, AttrMissing::am_value, array_get_element(), Assert, CompactAttribute::attcacheoff, attnum, AttrDefaultFetch(), ATTRIBUTE_FIXED_PART_SIZE, BTEqualStrategyNumber, BTGreaterStrategyNumber, CacheMemoryContext, CheckConstraintFetch(), TupleDescData::constr, criticalRelcachesBuilt, datumCopy(), elog, ERROR, GETSTRUCT(), TupleConstr::has_generated_stored, TupleConstr::has_generated_virtual, TupleConstr::has_not_null, heap_getattr(), HeapTupleIsValid, Int16GetDatum(), 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 6808 of file relcache.c.

6809{
6810 LWLockRelease(RelCacheInitLock);
6811}
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781

References LWLockRelease().

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

◆ RelationCacheInitFilePreInvalidate()

void RelationCacheInitFilePreInvalidate ( void  )

Definition at line 6783 of file relcache.c.

6784{
6785 char localinitfname[MAXPGPATH];
6786 char sharedinitfname[MAXPGPATH];
6787
6788 if (DatabasePath)
6789 snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6791 snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6793
6794 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6795
6796 /*
6797 * The files might not be there if no backend has been started since the
6798 * last removal. But complain about failures other than ENOENT with
6799 * ERROR. Fortunately, it's not too late to abort the transaction if we
6800 * can't get rid of the would-be-obsolete init file.
6801 */
6802 if (DatabasePath)
6803 unlink_initfile(localinitfname, ERROR);
6804 unlink_initfile(sharedinitfname, ERROR);
6805}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static void unlink_initfile(const char *initfilename, int elevel)
Definition: relcache.c:6880

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

6824{
6825 const char *tblspcdir = PG_TBLSPC_DIR;
6826 DIR *dir;
6827 struct dirent *de;
6828 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6829
6830 snprintf(path, sizeof(path), "global/%s",
6832 unlink_initfile(path, LOG);
6833
6834 /* Scan everything in the default tablespace */
6836
6837 /* Scan the tablespace link directory to find non-default tablespaces */
6838 dir = AllocateDir(tblspcdir);
6839
6840 while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6841 {
6842 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6843 {
6844 /* Scan the tablespace dir for per-database dirs */
6845 snprintf(path, sizeof(path), "%s/%s/%s",
6846 tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6848 }
6849 }
6850
6851 FreeDir(dir);
6852}
#define LOG
Definition: elog.h:31
int FreeDir(DIR *dir)
Definition: fd.c:2983
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2946
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath)
Definition: relcache.c:6856
#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 6856 of file relcache.c.

6857{
6858 DIR *dir;
6859 struct dirent *de;
6860 char initfilename[MAXPGPATH * 2];
6861
6862 /* Scan the tablespace directory to find per-database directories */
6863 dir = AllocateDir(tblspcpath);
6864
6865 while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6866 {
6867 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6868 {
6869 /* Try to remove the init file in each database */
6870 snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6871 tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6872 unlink_initfile(initfilename, LOG);
6873 }
6874 }
6875
6876 FreeDir(dir);
6877}

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

3950{
3951 HASHCTL ctl;
3952 int allocsize;
3953
3954 /*
3955 * make sure cache memory context exists
3956 */
3957 if (!CacheMemoryContext)
3959
3960 /*
3961 * create hashtable that indexes the relcache
3962 */
3963 ctl.keysize = sizeof(Oid);
3964 ctl.entrysize = sizeof(RelIdCacheEnt);
3965 RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
3967
3968 /*
3969 * reserve enough in_progress_list slots for many cases
3970 */
3971 allocsize = 4;
3974 allocsize * sizeof(*in_progress_list));
3975 in_progress_list_maxlen = allocsize;
3976
3977 /*
3978 * relation mapper needs to be initialized too
3979 */
3981}
#define INITRELCACHESIZE
Definition: relcache.c:3946
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 3995 of file relcache.c.

3996{
3997 MemoryContext oldcxt;
3998
3999 /*
4000 * relation mapper needs initialized too
4001 */
4003
4004 /*
4005 * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4006 * nothing.
4007 */
4009 return;
4010
4011 /*
4012 * switch to cache memory context
4013 */
4015
4016 /*
4017 * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4018 * the cache with pre-made descriptors for the critical shared catalogs.
4019 */
4020 if (!load_relcache_init_file(true))
4021 {
4022 formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4023 Natts_pg_database, Desc_pg_database);
4024 formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4025 Natts_pg_authid, Desc_pg_authid);
4026 formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4027 Natts_pg_auth_members, Desc_pg_auth_members);
4028 formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4029 Natts_pg_shseclabel, Desc_pg_shseclabel);
4030 formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4031 Natts_pg_subscription, Desc_pg_subscription);
4032
4033#define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4034 }
4035
4036 MemoryContextSwitchTo(oldcxt);
4037}
static bool load_relcache_init_file(bool shared)
Definition: relcache.c:6090
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:1865
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 4054 of file relcache.c.

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

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

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

Referenced by InvalidateSystemCachesExtended(), and LocalExecuteInvalidationMessage().

◆ RelationCacheInvalidateEntry()

void RelationCacheInvalidateEntry ( Oid  relationId)

Definition at line 2894 of file relcache.c.

2895{
2896 Relation relation;
2897
2898 RelationIdCacheLookup(relationId, relation);
2899
2900 if (PointerIsValid(relation))
2901 {
2903 RelationFlushRelation(relation);
2904 }
2905 else
2906 {
2907 int i;
2908
2909 for (i = 0; i < in_progress_list_len; i++)
2910 if (in_progress_list[i].reloid == relationId)
2912 }
2913}
#define PointerIsValid(pointer)
Definition: c.h:720
#define RelationIdCacheLookup(ID, RELATION)
Definition: relcache.c:231
static void RelationFlushRelation(Relation relation)
Definition: relcache.c:2783

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

2502{
2504 Assert(!relation->rd_isnailed);
2505
2506 /*
2507 * Relations created in the same transaction must never be removed, see
2508 * RelationFlushRelation.
2509 */
2513
2514 /* first mark it as invalid */
2516
2517 /* Remove it from the hash table */
2518 RelationCacheDelete(relation);
2519
2520 /* And release storage */
2521 RelationDestroyRelation(relation, false);
2522}
#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 2174 of file relcache.c.

2175{
2176 /* Note: no locking manipulations needed */
2178
2179 RelationCloseCleanup(relation);
2180}
static void RelationCloseCleanup(Relation relation)
Definition: relcache.c:2183

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

2184{
2185 /*
2186 * If the relation is no longer open in this session, we can clean up any
2187 * stale partition descriptors it has. This is unlikely, so check to see
2188 * if there are child contexts before expending a call to mcxt.c.
2189 */
2190 if (RelationHasReferenceCountZero(relation))
2191 {
2192 if (relation->rd_pdcxt != NULL &&
2193 relation->rd_pdcxt->firstchild != NULL)
2195
2196 if (relation->rd_pddcxt != NULL &&
2197 relation->rd_pddcxt->firstchild != NULL)
2199 }
2200
2201#ifdef RELCACHE_FORCE_RELEASE
2202 if (RelationHasReferenceCountZero(relation) &&
2205 RelationClearRelation(relation);
2206#endif
2207}
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:539
MemoryContext firstchild
Definition: memnodes.h:128

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

Referenced by RelationClose(), and ResOwnerReleaseRelation().

◆ RelationDecrementReferenceCount()

void RelationDecrementReferenceCount ( Relation  rel)

Definition at line 2154 of file relcache.c.

2155{
2156 Assert(rel->rd_refcnt > 0);
2157 rel->rd_refcnt -= 1;
2160}
static void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: relcache.c:2127
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

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

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

◆ RelationDestroyRelation()

static void RelationDestroyRelation ( Relation  relation,
bool  remember_tupdesc 
)
static

Definition at line 2394 of file relcache.c.

2395{
2397
2398 /*
2399 * Make sure smgr and lower levels close the relation's files, if they
2400 * weren't closed already. (This was probably done by caller, but let's
2401 * just be real sure.)
2402 */
2403 RelationCloseSmgr(relation);
2404
2405 /* break mutual link with stats entry */
2406 pgstat_unlink_relation(relation);
2407
2408 /*
2409 * Free all the subsidiary data structures of the relcache entry, then the
2410 * entry itself.
2411 */
2412 if (relation->rd_rel)
2413 pfree(relation->rd_rel);
2414 /* can't use DecrTupleDescRefCount here */
2415 Assert(relation->rd_att->tdrefcount > 0);
2416 if (--relation->rd_att->tdrefcount == 0)
2417 {
2418 /*
2419 * If we Rebuilt a relcache entry during a transaction then its
2420 * possible we did that because the TupDesc changed as the result of
2421 * an ALTER TABLE that ran at less than AccessExclusiveLock. It's
2422 * possible someone copied that TupDesc, in which case the copy would
2423 * point to free'd memory. So if we rebuild an entry we keep the
2424 * TupDesc around until end of transaction, to be safe.
2425 */
2426 if (remember_tupdesc)
2428 else
2429 FreeTupleDesc(relation->rd_att);
2430 }
2431 FreeTriggerDesc(relation->trigdesc);
2432 list_free_deep(relation->rd_fkeylist);
2433 list_free(relation->rd_indexlist);
2434 list_free(relation->rd_statlist);
2435 bms_free(relation->rd_keyattr);
2436 bms_free(relation->rd_pkattr);
2437 bms_free(relation->rd_idattr);
2438 bms_free(relation->rd_hotblockingattr);
2439 bms_free(relation->rd_summarizedattr);
2440 if (relation->rd_pubdesc)
2441 pfree(relation->rd_pubdesc);
2442 if (relation->rd_options)
2443 pfree(relation->rd_options);
2444 if (relation->rd_indextuple)
2445 pfree(relation->rd_indextuple);
2446 if (relation->rd_amcache)
2447 pfree(relation->rd_amcache);
2448 if (relation->rd_fdwroutine)
2449 pfree(relation->rd_fdwroutine);
2450 if (relation->rd_indexcxt)
2452 if (relation->rd_rulescxt)
2454 if (relation->rd_rsdesc)
2456 if (relation->rd_partkeycxt)
2458 if (relation->rd_pdcxt)
2459 MemoryContextDelete(relation->rd_pdcxt);
2460 if (relation->rd_pddcxt)
2461 MemoryContextDelete(relation->rd_pddcxt);
2462 if (relation->rd_partcheckcxt)
2464 pfree(relation);
2465}
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:3060
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 2783 of file relcache.c.

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

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

2850{
2851 Relation relation;
2852
2853 RelationIdCacheLookup(rid, relation);
2854
2855 if (!PointerIsValid(relation))
2856 return; /* not in cache, nothing to do */
2857
2858 if (!RelationHasReferenceCountZero(relation))
2859 elog(ERROR, "relation %u is still open", rid);
2860
2862 if (relation->rd_createSubid != InvalidSubTransactionId ||
2864 {
2865 /*
2866 * In the event of subtransaction rollback, we must not forget
2867 * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2868 * destroying it right away. (If we're in a top transaction, we could
2869 * opt to destroy the entry.)
2870 */
2873 }
2874 else
2875 RelationClearRelation(relation);
2876}

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

5080{
5081 List *result;
5082 Datum exprsDatum;
5083 bool isnull;
5084 char *exprsString;
5085 List *rawExprs;
5086 ListCell *lc;
5087
5088 /* Quick exit if there is nothing to do. */
5089 if (relation->rd_indextuple == NULL ||
5090 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5091 return NIL;
5092
5093 /* Extract raw node tree(s) from index tuple. */
5094 exprsDatum = heap_getattr(relation->rd_indextuple,
5095 Anum_pg_index_indexprs,
5097 &isnull);
5098 Assert(!isnull);
5099 exprsString = TextDatumGetCString(exprsDatum);
5100 rawExprs = (List *) stringToNode(exprsString);
5101 pfree(exprsString);
5102
5103 /* Construct null Consts; the typlen and typbyval are arbitrary. */
5104 result = NIL;
5105 foreach(lc, rawExprs)
5106 {
5107 Node *rawExpr = (Node *) lfirst(lc);
5108
5109 result = lappend(result,
5110 makeConst(exprType(rawExpr),
5111 exprTypmod(rawExpr),
5112 exprCollation(rawExpr),
5113 1,
5114 (Datum) 0,
5115 true,
5116 true));
5117 }
5118
5119 return result;
5120}
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:303
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:4420

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

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

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

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

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

◆ RelationGetIdentityKeyBitmap()

Bitmapset * RelationGetIdentityKeyBitmap ( Relation  relation)

Definition at line 5499 of file relcache.c.

5500{
5501 Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5502 Relation indexDesc;
5503 int i;
5504 Oid replidindex;
5505 MemoryContext oldcxt;
5506
5507 /* Quick exit if we already computed the result */
5508 if (relation->rd_idattr != NULL)
5509 return bms_copy(relation->rd_idattr);
5510
5511 /* Fast path if definitely no indexes */
5512 if (!RelationGetForm(relation)->relhasindex)
5513 return NULL;
5514
5515 /* Historic snapshot must be set. */
5517
5518 replidindex = RelationGetReplicaIndex(relation);
5519
5520 /* Fall out if there is no replica identity index */
5521 if (!OidIsValid(replidindex))
5522 return NULL;
5523
5524 /* Look up the description for the replica identity index */
5525 indexDesc = RelationIdGetRelation(replidindex);
5526
5527 if (!RelationIsValid(indexDesc))
5528 elog(ERROR, "could not open relation with OID %u",
5529 relation->rd_replidindex);
5530
5531 /* Add referenced attributes to idindexattrs */
5532 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5533 {
5534 int attrnum = indexDesc->rd_index->indkey.values[i];
5535
5536 /*
5537 * We don't include non-key columns into idindexattrs bitmaps. See
5538 * RelationGetIndexAttrBitmap.
5539 */
5540 if (attrnum != 0)
5541 {
5542 if (i < indexDesc->rd_index->indnkeyatts)
5543 idindexattrs = bms_add_member(idindexattrs,
5545 }
5546 }
5547
5548 RelationClose(indexDesc);
5549
5550 /* Don't leak the old values of these bitmaps, if any */
5551 bms_free(relation->rd_idattr);
5552 relation->rd_idattr = NULL;
5553
5554 /* Now save copy of the bitmap in the relcache entry */
5556 relation->rd_idattr = bms_copy(idindexattrs);
5557 MemoryContextSwitchTo(oldcxt);
5558
5559 /* We return our original working copy for caller to play with */
5560 return idindexattrs;
5561}
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:506
#define RelationIsValid(relation)
Definition: rel.h:485
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4995
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2052
void RelationClose(Relation relation)
Definition: relcache.c:2174
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1620
#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 5911 of file relcache.c.

5912{
5913 MemoryContext oldcxt;
5914 bytea **opts = relation->rd_opcoptions;
5915 Oid relid = RelationGetRelid(relation);
5916 int natts = RelationGetNumberOfAttributes(relation); /* XXX
5917 * IndexRelationGetNumberOfKeyAttributes */
5918 int i;
5919
5920 /* Try to copy cached options. */
5921 if (opts)
5922 return copy ? CopyIndexAttOptions(opts, natts) : opts;
5923
5924 /* Get and parse opclass options. */
5925 opts = palloc0(sizeof(*opts) * natts);
5926
5927 for (i = 0; i < natts; i++)
5928 {
5929 if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
5930 {
5931 Datum attoptions = get_attoptions(relid, i + 1);
5932
5933 opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
5934
5935 if (attoptions != (Datum) 0)
5936 pfree(DatumGetPointer(attoptions));
5937 }
5938 }
5939
5940 /* Copy parsed options to the cache. */
5941 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5942 relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
5943 MemoryContextSwitchTo(oldcxt);
5944
5945 if (copy)
5946 return opts;
5947
5948 for (i = 0; i < natts; i++)
5949 {
5950 if (opts[i])
5951 pfree(opts[i]);
5952 }
5953
5954 pfree(opts);
5955
5956 return relation->rd_opcoptions;
5957}
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:998
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:971
static bytea ** CopyIndexAttOptions(bytea **srcopts, int natts)
Definition: relcache.c:5891

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

5227{
5228 Bitmapset *uindexattrs; /* columns in unique indexes */
5229 Bitmapset *pkindexattrs; /* columns in the primary index */
5230 Bitmapset *idindexattrs; /* columns in the replica identity */
5231 Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5232 Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5233 List *indexoidlist;
5234 List *newindexoidlist;
5235 Oid relpkindex;
5236 Oid relreplindex;
5237 ListCell *l;
5238 MemoryContext oldcxt;
5239
5240 /* Quick exit if we already computed the result. */
5241 if (relation->rd_attrsvalid)
5242 {
5243 switch (attrKind)
5244 {
5246 return bms_copy(relation->rd_keyattr);
5248 return bms_copy(relation->rd_pkattr);
5250 return bms_copy(relation->rd_idattr);
5252 return bms_copy(relation->rd_hotblockingattr);
5254 return bms_copy(relation->rd_summarizedattr);
5255 default:
5256 elog(ERROR, "unknown attrKind %u", attrKind);
5257 }
5258 }
5259
5260 /* Fast path if definitely no indexes */
5261 if (!RelationGetForm(relation)->relhasindex)
5262 return NULL;
5263
5264 /*
5265 * Get cached list of index OIDs. If we have to start over, we do so here.
5266 */
5267restart:
5268 indexoidlist = RelationGetIndexList(relation);
5269
5270 /* Fall out if no indexes (but relhasindex was set) */
5271 if (indexoidlist == NIL)
5272 return NULL;
5273
5274 /*
5275 * Copy the rd_pkindex and rd_replidindex values computed by
5276 * RelationGetIndexList before proceeding. This is needed because a
5277 * relcache flush could occur inside index_open below, resetting the
5278 * fields managed by RelationGetIndexList. We need to do the work with
5279 * stable values of these fields.
5280 */
5281 relpkindex = relation->rd_pkindex;
5282 relreplindex = relation->rd_replidindex;
5283
5284 /*
5285 * For each index, add referenced attributes to indexattrs.
5286 *
5287 * Note: we consider all indexes returned by RelationGetIndexList, even if
5288 * they are not indisready or indisvalid. This is important because an
5289 * index for which CREATE INDEX CONCURRENTLY has just started must be
5290 * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5291 * CONCURRENTLY is far enough along that we should ignore the index, it
5292 * won't be returned at all by RelationGetIndexList.
5293 */
5294 uindexattrs = NULL;
5295 pkindexattrs = NULL;
5296 idindexattrs = NULL;
5297 hotblockingattrs = NULL;
5298 summarizedattrs = NULL;
5299 foreach(l, indexoidlist)
5300 {
5301 Oid indexOid = lfirst_oid(l);
5302 Relation indexDesc;
5303 Datum datum;
5304 bool isnull;
5305 Node *indexExpressions;
5306 Node *indexPredicate;
5307 int i;
5308 bool isKey; /* candidate key */
5309 bool isPK; /* primary key */
5310 bool isIDKey; /* replica identity index */
5311 Bitmapset **attrs;
5312
5313 indexDesc = index_open(indexOid, AccessShareLock);
5314
5315 /*
5316 * Extract index expressions and index predicate. Note: Don't use
5317 * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5318 * those might run constant expressions evaluation, which needs a
5319 * snapshot, which we might not have here. (Also, it's probably more
5320 * sound to collect the bitmaps before any transformations that might
5321 * eliminate columns, but the practical impact of this is limited.)
5322 */
5323
5324 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5325 GetPgIndexDescriptor(), &isnull);
5326 if (!isnull)
5327 indexExpressions = stringToNode(TextDatumGetCString(datum));
5328 else
5329 indexExpressions = NULL;
5330
5331 datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5332 GetPgIndexDescriptor(), &isnull);
5333 if (!isnull)
5334 indexPredicate = stringToNode(TextDatumGetCString(datum));
5335 else
5336 indexPredicate = NULL;
5337
5338 /* Can this index be referenced by a foreign key? */
5339 isKey = indexDesc->rd_index->indisunique &&
5340 indexExpressions == NULL &&
5341 indexPredicate == NULL;
5342
5343 /* Is this a primary key? */
5344 isPK = (indexOid == relpkindex);
5345
5346 /* Is this index the configured (or default) replica identity? */
5347 isIDKey = (indexOid == relreplindex);
5348
5349 /*
5350 * If the index is summarizing, it doesn't block HOT updates, but we
5351 * may still need to update it (if the attributes were modified). So
5352 * decide which bitmap we'll update in the following loop.
5353 */
5354 if (indexDesc->rd_indam->amsummarizing)
5355 attrs = &summarizedattrs;
5356 else
5357 attrs = &hotblockingattrs;
5358
5359 /* Collect simple attribute references */
5360 for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5361 {
5362 int attrnum = indexDesc->rd_index->indkey.values[i];
5363
5364 /*
5365 * Since we have covering indexes with non-key columns, we must
5366 * handle them accurately here. non-key columns must be added into
5367 * hotblockingattrs or summarizedattrs, since they are in index,
5368 * and update shouldn't miss them.
5369 *
5370 * Summarizing indexes do not block HOT, but do need to be updated
5371 * when the column value changes, thus require a separate
5372 * attribute bitmapset.
5373 *
5374 * Obviously, non-key columns couldn't be referenced by foreign
5375 * key or identity key. Hence we do not include them into
5376 * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5377 */
5378 if (attrnum != 0)
5379 {
5380 *attrs = bms_add_member(*attrs,
5382
5383 if (isKey && i < indexDesc->rd_index->indnkeyatts)
5384 uindexattrs = bms_add_member(uindexattrs,
5386
5387 if (isPK && i < indexDesc->rd_index->indnkeyatts)
5388 pkindexattrs = bms_add_member(pkindexattrs,
5390
5391 if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5392 idindexattrs = bms_add_member(idindexattrs,
5394 }
5395 }
5396
5397 /* Collect all attributes used in expressions, too */
5398 pull_varattnos(indexExpressions, 1, attrs);
5399
5400 /* Collect all attributes in the index predicate, too */
5401 pull_varattnos(indexPredicate, 1, attrs);
5402
5403 index_close(indexDesc, AccessShareLock);
5404 }
5405
5406 /*
5407 * During one of the index_opens in the above loop, we might have received
5408 * a relcache flush event on this relcache entry, which might have been
5409 * signaling a change in the rel's index list. If so, we'd better start
5410 * over to ensure we deliver up-to-date attribute bitmaps.
5411 */
5412 newindexoidlist = RelationGetIndexList(relation);
5413 if (equal(indexoidlist, newindexoidlist) &&
5414 relpkindex == relation->rd_pkindex &&
5415 relreplindex == relation->rd_replidindex)
5416 {
5417 /* Still the same index set, so proceed */
5418 list_free(newindexoidlist);
5419 list_free(indexoidlist);
5420 }
5421 else
5422 {
5423 /* Gotta do it over ... might as well not leak memory */
5424 list_free(newindexoidlist);
5425 list_free(indexoidlist);
5426 bms_free(uindexattrs);
5427 bms_free(pkindexattrs);
5428 bms_free(idindexattrs);
5429 bms_free(hotblockingattrs);
5430 bms_free(summarizedattrs);
5431
5432 goto restart;
5433 }
5434
5435 /* Don't leak the old values of these bitmaps, if any */
5436 relation->rd_attrsvalid = false;
5437 bms_free(relation->rd_keyattr);
5438 relation->rd_keyattr = NULL;
5439 bms_free(relation->rd_pkattr);
5440 relation->rd_pkattr = NULL;
5441 bms_free(relation->rd_idattr);
5442 relation->rd_idattr = NULL;
5443 bms_free(relation->rd_hotblockingattr);
5444 relation->rd_hotblockingattr = NULL;
5445 bms_free(relation->rd_summarizedattr);
5446 relation->rd_summarizedattr = NULL;
5447
5448 /*
5449 * Now save copies of the bitmaps in the relcache entry. We intentionally
5450 * set rd_attrsvalid last, because that's the one that signals validity of
5451 * the values; if we run out of memory before making that copy, we won't
5452 * leave the relcache entry looking like the other ones are valid but
5453 * empty.
5454 */
5456 relation->rd_keyattr = bms_copy(uindexattrs);
5457 relation->rd_pkattr = bms_copy(pkindexattrs);
5458 relation->rd_idattr = bms_copy(idindexattrs);
5459 relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5460 relation->rd_summarizedattr = bms_copy(summarizedattrs);
5461 relation->rd_attrsvalid = true;
5462 MemoryContextSwitchTo(oldcxt);
5463
5464 /* We return our original working copy for caller to play with */
5465 switch (attrKind)
5466 {
5468 return uindexattrs;
5470 return pkindexattrs;
5472 return idindexattrs;
5474 return hotblockingattrs;
5476 return summarizedattrs;
5477 default:
5478 elog(ERROR, "unknown attrKind %u", attrKind);
5479 return NULL;
5480 }
5481}
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:4759
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition: relcache.h:64
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition: relcache.h:65
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
bool amsummarizing
Definition: amapi.h:273
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(),