From a0a6c14f8c649114667c4ee4a4ce6a9ae6465ca5 Mon Sep 17 00:00:00 2001 From: David Geier Date: Thu, 3 Sep 2026 09:46:30 +0200 Subject: [PATCH v4 4/7] Overlay relation-kind-specific relcache fields Table-like relations and indexes use disjoint sets of cached metadata. Put those fields in an anonymous union so each relcache entry pays only for the larger set instead of both sets. sizeof(RelationData): 368 bytes --- src/backend/access/spgist/spgutils.c | 2 +- src/backend/commands/repack.c | 2 +- src/backend/commands/tablecmds.c | 2 +- src/backend/storage/lmgr/predicate.c | 6 +- src/backend/utils/cache/relcache.c | 212 ++++++++++++----------- src/include/utils/rel.h | 8 + src/include/utils/rel_internal.h | 245 ++++++++++++++------------- 7 files changed, 257 insertions(+), 220 deletions(-) diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index f2ee333f60d..a33dcfe8ecf 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -126,7 +126,7 @@ GetIndexInputType(Relation index, AttrNumber indexcol) List *indexprs; ListCell *indexpr_item; - Assert(index->rd_index != NULL); + Assert(RelationIsIndex(index)); Assert(indexcol > 0 && indexcol <= index->rd_index->indnkeyatts); opcintype = index->rd_opcintype[indexcol - 1]; if (!IsPolymorphicType(opcintype)) diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index 596c1abaf78..6f14de97a2f 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -790,7 +790,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode) /* * Check that index is in fact an index on the given relation */ - if (OldIndex->rd_index == NULL || + if (!RelationIsIndex(OldIndex) || OldIndex->rd_index->indrelid != RelationGetRelid(OldHeap)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0274d892f2e..642bb46ecc7 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -19194,7 +19194,7 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode indexRel = index_open(indexOid, ShareLock); /* Check that the index is on the relation we're altering. */ - if (indexRel->rd_index == NULL || + if (!RelationIsIndex(indexRel) || indexRel->rd_index->indrelid != RelationGetRelid(rel)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index 0ae85b7d5b4..5c539306e77 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -2558,7 +2558,7 @@ PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapsho /* * Return if this xact wrote it. */ - if (relation->rd_index == NULL) + if (!RelationIsIndex(relation)) { /* If we wrote it; we already have a write lock. */ if (TransactionIdIsCurrentTransactionId(tuple_xid)) @@ -2890,7 +2890,7 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer) dbId = relation->rd_locator.dbOid; relId = relation->rd_id; - if (relation->rd_index == NULL) + if (!RelationIsIndex(relation)) { isIndex = false; heapId = relId; @@ -4371,7 +4371,7 @@ CheckTableForSerializableConflictIn(Relation relation) */ MyXactDidWrite = true; - Assert(relation->rd_index == NULL); /* not an index relation */ + Assert(!RelationIsIndex(relation)); dbId = relation->rd_locator.dbOid; heapId = relation->rd_id; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 78794a2fb60..fb03140df99 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -93,7 +93,7 @@ #include "utils/snapmgr.h" #include "utils/syscache.h" -#define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */ +#define RELCACHE_INIT_FILEMAGIC 0x573267 /* version ID value */ /* * Whether to bother checking if relation cache memory needs to be freed @@ -1261,23 +1261,26 @@ retry: * Note that RelationBuildRuleLock() relies on this being done after * extracting the relation's reloptions. */ - if (relation->rd_rel->relhasrules) - RelationBuildRuleLock(relation); - else + if (!RelationIsIndex(relation)) { - relation->rd_rules = NULL; - relation->rd_rulescxt = NULL; - } + if (relation->rd_rel->relhasrules) + RelationBuildRuleLock(relation); + else + { + relation->rd_rules = NULL; + relation->rd_rulescxt = NULL; + } - if (relation->rd_rel->relhastriggers) - RelationBuildTriggers(relation); - else - relation->trigdesc = NULL; + if (relation->rd_rel->relhastriggers) + RelationBuildTriggers(relation); + else + relation->trigdesc = NULL; - if (relation->rd_rel->relrowsecurity) - RelationBuildRowSecurity(relation); - else - relation->rd_rsdesc = NULL; + if (relation->rd_rel->relrowsecurity) + RelationBuildRowSecurity(relation); + else + relation->rd_rsdesc = NULL; + } /* * initialize the relation lock manager information @@ -2240,7 +2243,7 @@ RelationCloseCleanup(Relation relation) * stale partition descriptors it has. This is unlikely, so check to see * if there are child contexts before expending a call to mcxt.c. */ - if (RelationHasReferenceCountZero(relation)) + if (RelationHasReferenceCountZero(relation) && !RelationIsIndex(relation)) { if (relation->rd_pdcxt != NULL && relation->rd_pdcxt->firstchild != NULL) @@ -2445,6 +2448,8 @@ RelationReloadNailed(Relation relation) static void RelationDestroyRelation(Relation relation, bool remember_tupdesc) { + const bool is_index = relation->rd_rel && RelationIsIndex(relation); + Assert(RelationHasReferenceCountZero(relation)); /* @@ -2480,39 +2485,45 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) else FreeTupleDesc(relation->rd_att); } - FreeTriggerDesc(relation->trigdesc); - list_free_deep(relation->rd_fkeylist); - list_free(relation->rd_indexlist); - list_free(relation->rd_statlist); - bms_free(relation->rd_keyattr); - bms_free(relation->rd_pkattr); - bms_free(relation->rd_idattr); - bms_free(relation->rd_hotblockingattr); - bms_free(relation->rd_summarizedattr); - if (relation->rd_pubdesc) - pfree(relation->rd_pubdesc); if (relation->rd_options) pfree(relation->rd_options); - if (relation->rd_indextuple) - pfree(relation->rd_indextuple); if (relation->rd_amcache) pfree(relation->rd_amcache); - if (relation->rd_fdwroutine) - pfree(relation->rd_fdwroutine); - if (relation->rd_indexcxt) - MemoryContextDelete(relation->rd_indexcxt); - if (relation->rd_rulescxt) - MemoryContextDelete(relation->rd_rulescxt); - if (relation->rd_rsdesc) - MemoryContextDelete(relation->rd_rsdesc->rscxt); - if (relation->rd_partkeycxt) - MemoryContextDelete(relation->rd_partkeycxt); - if (relation->rd_pdcxt) - MemoryContextDelete(relation->rd_pdcxt); - if (relation->rd_pddcxt) - MemoryContextDelete(relation->rd_pddcxt); if (relation->rd_partcheckcxt) MemoryContextDelete(relation->rd_partcheckcxt); + if (!is_index) + { + list_free(relation->rd_indexlist); + list_free(relation->rd_statlist); + FreeTriggerDesc(relation->trigdesc); + list_free_deep(relation->rd_fkeylist); + bms_free(relation->rd_keyattr); + bms_free(relation->rd_pkattr); + bms_free(relation->rd_idattr); + bms_free(relation->rd_hotblockingattr); + bms_free(relation->rd_summarizedattr); + if (relation->rd_pubdesc) + pfree(relation->rd_pubdesc); + if (relation->rd_fdwroutine) + pfree(relation->rd_fdwroutine); + if (relation->rd_rulescxt) + MemoryContextDelete(relation->rd_rulescxt); + if (relation->rd_rsdesc) + MemoryContextDelete(relation->rd_rsdesc->rscxt); + if (relation->rd_partkeycxt) + MemoryContextDelete(relation->rd_partkeycxt); + if (relation->rd_pdcxt) + MemoryContextDelete(relation->rd_pdcxt); + if (relation->rd_pddcxt) + MemoryContextDelete(relation->rd_pddcxt); + } + else + { + if (relation->rd_indextuple) + pfree(relation->rd_indextuple); + if (relation->rd_indexcxt) + MemoryContextDelete(relation->rd_indexcxt); + } pfree(relation); } @@ -2658,9 +2669,9 @@ RelationRebuildRelation(Relation relation) Relation newrel; Oid save_relid = RelationGetRelid(relation); bool keep_tupdesc; - bool keep_rules; - bool keep_policies; - bool keep_partkey; + bool keep_rules = false; + bool keep_policies = false; + bool keep_partkey = false; /* Build temporary entry, but don't link it into hashtable */ newrel = RelationBuildDesc(save_relid, false); @@ -2704,10 +2715,14 @@ RelationRebuildRelation(Relation relation) Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind); keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att); - keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules); - keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc); - /* partkey is immutable once set up, so we can always keep it */ - keep_partkey = (relation->rd_partkey != NULL); + + if (!RelationIsIndex(relation)) + { + keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules); + keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc); + /* partkey is immutable once set up, so we can always keep it */ + keep_partkey = (relation->rd_partkey != NULL); + } /* * Perform swapping of the relcache entry contents. Within this @@ -2761,7 +2776,8 @@ RelationRebuildRelation(Relation relation) if (keep_policies) SWAPFIELD(RowSecurityDesc *, rd_rsdesc); /* toast OID override must be preserved */ - SWAPFIELD(Oid, rd_toastoid); + if (!RelationIsIndex(relation)) + SWAPFIELD(Oid, rd_toastoid); /* pgstat_info / enabled must be preserved */ SWAPFIELD(struct PgStat_RelationStatus *, pgstat_info); SWAPFIELD(bool, pgstat_enabled); @@ -6522,18 +6538,6 @@ load_relcache_init_file(bool shared) /* Load table AM data */ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE) RelationInitTableAccessMethod(rel); - - Assert(rel->rd_index == NULL); - Assert(rel->rd_indextuple == NULL); - Assert(rel->rd_indexcxt == NULL); - Assert(rel->rd_indam == NULL); - Assert(rel->rd_opfamily == NULL); - Assert(rel->rd_opcintype == NULL); - Assert(rel->rd_support == NULL); - Assert(rel->rd_supportinfo == NULL); - Assert(rel->rd_indoption == NULL); - Assert(rel->rd_indcollation == NULL); - Assert(rel->rd_opcoptions == NULL); } /* @@ -6543,55 +6547,69 @@ load_relcache_init_file(bool shared) * be a big performance hit since few system catalogs have such. Ditto * for RLS policy data, partition info, index expressions, predicates, * exclusion info, and FDW info. + * + * These fields are overlaid in a union with the index-only fields + * that were just set up above (see RelationData in rel_internal.h), + * so this must be skipped for index relations to avoid clobbering + * that data. */ - rel->rd_rules = NULL; - rel->rd_rulescxt = NULL; - rel->trigdesc = NULL; - rel->rd_rsdesc = NULL; - rel->rd_partkey = NULL; - rel->rd_partkeycxt = NULL; - rel->rd_partdesc = NULL; - rel->rd_partdesc_nodetached = NULL; - rel->rd_partdesc_nodetached_xmin = InvalidTransactionId; - rel->rd_pdcxt = NULL; - rel->rd_pddcxt = NULL; - rel->rd_partcheck = NIL; - rel->rd_partcheckvalid = false; - rel->rd_partcheckcxt = NULL; - rel->rd_indexprs = NIL; - rel->rd_indpred = NIL; - rel->rd_exclops = NULL; - rel->rd_exclprocs = NULL; - rel->rd_exclstrats = NULL; - rel->rd_fdwroutine = NULL; + if (!RelationIsIndex(rel)) + { + rel->rd_rules = NULL; + rel->rd_rulescxt = NULL; + rel->trigdesc = NULL; + rel->rd_rsdesc = NULL; + rel->rd_partkey = NULL; + rel->rd_partkeycxt = NULL; + rel->rd_partdesc = NULL; + rel->rd_partdesc_nodetached = NULL; + rel->rd_partdesc_nodetached_xmin = InvalidTransactionId; + rel->rd_pdcxt = NULL; + rel->rd_pddcxt = NULL; + rel->rd_keyattr = NULL; + rel->rd_pkattr = NULL; + rel->rd_idattr = NULL; + rel->rd_hotblockingattr = NULL; + rel->rd_summarizedattr = NULL; + rel->rd_pubdesc = NULL; + rel->rd_fdwroutine = NULL; + rel->rd_fkeyvalid = false; + rel->rd_fkeylist = NIL; + rel->rd_indexvalid = false; + rel->rd_indexlist = NIL; + rel->rd_pkindex = InvalidOid; + rel->rd_replidindex = InvalidOid; + rel->rd_attrsvalid = false; + rel->rd_statvalid = false; + rel->rd_statlist = NIL; + rel->rd_toastchunkidtype = InvalidOid; + } + else + { + /* These lazily built fields are not stored in the init file. */ + rel->rd_indexprs = NIL; + rel->rd_indpred = NIL; + rel->rd_exclops = NULL; + rel->rd_exclprocs = NULL; + rel->rd_exclstrats = NULL; + } /* * Reset transient-state fields in the relcache entry */ rel->rd_smgr = NULL; + rel->rd_partcheck = NIL; + rel->rd_partcheckvalid = false; + rel->rd_partcheckcxt = NULL; if (rel->rd_isnailed) rel->rd_refcnt = 1; else rel->rd_refcnt = 0; - rel->rd_indexvalid = false; - rel->rd_indexlist = NIL; - rel->rd_pkindex = InvalidOid; - rel->rd_replidindex = InvalidOid; - rel->rd_attrsvalid = false; - rel->rd_keyattr = NULL; - rel->rd_pkattr = NULL; - rel->rd_idattr = NULL; - rel->rd_pubdesc = NULL; - rel->rd_statvalid = false; - rel->rd_statlist = NIL; - rel->rd_fkeyvalid = false; - rel->rd_fkeylist = NIL; rel->rd_createSubid = InvalidSubTransactionId; rel->rd_newRelfilelocatorSubid = InvalidSubTransactionId; rel->rd_firstRelfilelocatorSubid = InvalidSubTransactionId; rel->rd_droppedSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; - rel->rd_toastchunkidtype = InvalidOid; rel->pgstat_info = NULL; /* diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index fc7b5f6d800..d1a8408932f 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -308,6 +308,14 @@ typedef struct ViewOptions */ #define RelationGetRelid(relation) ((relation)->rd_id) +/* + * RelationIsIndex + * True for both, ordinary and partitioned index relations. + */ +#define RelationIsIndex(relation) \ + ((relation)->rd_rel->relkind == RELKIND_INDEX || \ + (relation)->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) + /* * RelationGetNumberOfAttributes * Returns the total number of attributes in a relation. diff --git a/src/include/utils/rel_internal.h b/src/include/utils/rel_internal.h index adee58a6c5a..f2ec9196f3c 100644 --- a/src/include/utils/rel_internal.h +++ b/src/include/utils/rel_internal.h @@ -40,6 +40,134 @@ typedef LockInfoData *LockInfo; typedef struct RelationData { + union + { + /* fields used only for a non-index (table-like) relation */ + struct + { + RuleLock *rd_rules; /* rewrite rules */ + MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ + TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ + /* use "struct" here to avoid needing to include rowsecurity.h: */ + struct RowSecurityDesc *rd_rsdesc; /* row security policies, or NULL */ + + /* data managed by RelationGetFKeyList: */ + List *rd_fkeylist; /* list of ForeignKeyCacheInfo (see below) */ + bool rd_fkeyvalid; /* true if rd_fkeylist has been computed */ + + /* data managed by RelationGetPartitionKey: */ + PartitionKey rd_partkey; /* partition key, or NULL */ + MemoryContext rd_partkeycxt; /* private context for rd_partkey, if any */ + + /* data managed by RelationGetPartitionDesc: */ + PartitionDesc rd_partdesc; /* partition descriptor, or NULL */ + MemoryContext rd_pdcxt; /* private context for rd_partdesc, if any */ + + /* Same as above, for partdescs that omit detached partitions */ + PartitionDesc rd_partdesc_nodetached; /* partdesc w/o detached parts */ + MemoryContext rd_pddcxt; /* for rd_partdesc_nodetached, if any */ + + /* + * pg_inherits.xmin of the partition that was excluded in + * rd_partdesc_nodetached. This informs a future user of that partdesc: + * if this value is not in progress for the active snapshot, then the + * partdesc can be used, otherwise they have to build a new one. (This + * matches what find_inheritance_children_extended would do). + */ + TransactionId rd_partdesc_nodetached_xmin; + + /* data managed by RelationGetIndexList: */ + List *rd_indexlist; /* list of OIDs of indexes on relation */ + Oid rd_pkindex; /* OID of (deferrable?) primary key, if any */ + bool rd_ispkdeferrable; /* is rd_pkindex a deferrable PK? */ + bool rd_indexvalid; /* is rd_indexlist valid? (also rd_pkindex and + * rd_replidindex) */ + Oid rd_replidindex; /* OID of replica identity index, if any */ + + /* data managed by RelationGetIndexAttrBitmap: */ + bool rd_attrsvalid; /* are bitmaps of attrs valid? (see + * RelationGetIndexAttrBitmap) */ + Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ + Bitmapset *rd_pkattr; /* cols included in primary key */ + Bitmapset *rd_idattr; /* included in replica identity index */ + Bitmapset *rd_hotblockingattr; /* cols blocking HOT update */ + Bitmapset *rd_summarizedattr; /* cols indexed by summarizing indexes */ + + /* data managed by RelationGetStatExtList: */ + List *rd_statlist; /* list of OIDs of extended stats */ + bool rd_statvalid; /* is rd_statlist valid? */ + + /* + * Table access method. + */ + const struct TableAmRoutine *rd_tableam; + + /* + * Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new + * version of a table, we need to make any toast pointers inserted into it + * have the existing toast table's OID, not the OID of the transient toast + * table. If rd_toastoid isn't InvalidOid, it is the OID to place in + * toast pointers inserted into this rel. (Note it's set on the new + * version of the main heap, not the toast table itself.) This also + * causes toast_save_datum() to try to preserve toast value OIDs. + */ + Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */ + + /* + * Type OID of the "chunk_id" column of this relation's TOAST table, i.e. + * OIDOID or OID8OID. + * + * This data is filled on demand by RelationGetToastChunkIdType(), not at + * relcache build time, so as to save in syscache lookups. + */ + Oid rd_toastchunkidtype; + + PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */ + + /* + * foreign-table support + * + * rd_fdwroutine must point to a single memory chunk palloc'd in + * CacheMemoryContext. It will be freed and reset to NULL on a + * relcache reset. + */ + /* use "struct" here to avoid needing to include fdwapi.h: */ + struct FdwRoutine *rd_fdwroutine; /* cached function pointers, or NULL */ + }; + + /* fields used only for an index relation */ + struct + { + Form_pg_index rd_index; /* pg_index tuple describing this index */ + /* use "struct" here to avoid needing to include htup.h: */ + struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ + + /* + * index access support info (used only for an index relation) + * + * Note: only default support procs for each opclass are cached, namely + * those with lefttype and righttype equal to the opclass's opcintype. The + * arrays are indexed by support function number, which is a sufficient + * identifier given that restriction. + */ + MemoryContext rd_indexcxt; /* private memory cxt for this stuff */ + /* use "struct" here to avoid needing to include amapi.h: */ + const struct IndexAmRoutine *rd_indam; /* index AM's API struct */ + Oid *rd_opfamily; /* OIDs of op families for each index col */ + Oid *rd_opcintype; /* OIDs of opclass declared input data types */ + RegProcedure *rd_support; /* OIDs of support procedures */ + struct FmgrInfo *rd_supportinfo; /* lookup info for support procedures */ + int16 *rd_indoption; /* per-column AM-specific flags */ + List *rd_indexprs; /* index expression trees, if any */ + List *rd_indpred; /* index predicate tree, if any */ + Oid *rd_exclops; /* OIDs of exclusion operators, if any */ + Oid *rd_exclprocs; /* OIDs of exclusion ops' procs, if any */ + uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */ + Oid *rd_indcollation; /* OIDs of index collations */ + bytea **rd_opcoptions; /* parsed opclass-specific options */ + }; + }; + RelFileLocator rd_locator; /* relation physical identifier */ SMgrRelation rd_smgr; /* cached file handle, or NULL */ int rd_refcnt; /* reference count */ @@ -47,9 +175,6 @@ typedef struct RelationData bool rd_islocaltemp; /* rel is a temp rel of this session */ bool rd_isnailed; /* rel is nailed in cache */ bool rd_isvalid; /* relcache entry is valid */ - bool rd_indexvalid; /* is rd_indexlist valid? (also rd_pkindex and - * rd_replidindex) */ - bool rd_statvalid; /* is rd_statlist valid? */ /*---------- * rd_createSubid is the ID of the highest subtransaction the rel has @@ -98,61 +223,12 @@ typedef struct RelationData TupleDesc rd_att; /* tuple descriptor */ Oid rd_id; /* relation's object id */ LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */ - RuleLock *rd_rules; /* rewrite rules */ - MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ - TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ - /* use "struct" here to avoid needing to include rowsecurity.h: */ - struct RowSecurityDesc *rd_rsdesc; /* row security policies, or NULL */ - - /* data managed by RelationGetFKeyList: */ - List *rd_fkeylist; /* list of ForeignKeyCacheInfo (see below) */ - bool rd_fkeyvalid; /* true if list has been computed */ - - /* data managed by RelationGetPartitionKey: */ - PartitionKey rd_partkey; /* partition key, or NULL */ - MemoryContext rd_partkeycxt; /* private context for rd_partkey, if any */ - - /* data managed by RelationGetPartitionDesc: */ - PartitionDesc rd_partdesc; /* partition descriptor, or NULL */ - MemoryContext rd_pdcxt; /* private context for rd_partdesc, if any */ - - /* Same as above, for partdescs that omit detached partitions */ - PartitionDesc rd_partdesc_nodetached; /* partdesc w/o detached parts */ - MemoryContext rd_pddcxt; /* for rd_partdesc_nodetached, if any */ - - /* - * pg_inherits.xmin of the partition that was excluded in - * rd_partdesc_nodetached. This informs a future user of that partdesc: - * if this value is not in progress for the active snapshot, then the - * partdesc can be used, otherwise they have to build a new one. (This - * matches what find_inheritance_children_extended would do). - */ - TransactionId rd_partdesc_nodetached_xmin; /* data managed by RelationGetPartitionQual: */ List *rd_partcheck; /* partition CHECK quals */ bool rd_partcheckvalid; /* true if list has been computed */ MemoryContext rd_partcheckcxt; /* private cxt for rd_partcheck, if any */ - /* data managed by RelationGetIndexList: */ - List *rd_indexlist; /* list of OIDs of indexes on relation */ - Oid rd_pkindex; /* OID of (deferrable?) primary key, if any */ - bool rd_ispkdeferrable; /* is rd_pkindex a deferrable PK? */ - Oid rd_replidindex; /* OID of replica identity index, if any */ - - /* data managed by RelationGetStatExtList: */ - List *rd_statlist; /* list of OIDs of extended stats */ - - /* data managed by RelationGetIndexAttrBitmap: */ - bool rd_attrsvalid; /* are bitmaps of attrs valid? */ - Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ - Bitmapset *rd_pkattr; /* cols included in primary key */ - Bitmapset *rd_idattr; /* included in replica identity index */ - Bitmapset *rd_hotblockingattr; /* cols blocking HOT update */ - Bitmapset *rd_summarizedattr; /* cols indexed by summarizing indexes */ - - PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */ - /* * rd_options is set whenever rd_rel is loaded into the relcache entry. * Note that you can NOT look into rd_rel for this data. NULL means "use @@ -169,40 +245,6 @@ typedef struct RelationData */ Oid rd_amhandler; /* OID of index AM's handler function */ - /* - * Table access method. - */ - const struct TableAmRoutine *rd_tableam; - - /* These are non-NULL only for an index relation: */ - Form_pg_index rd_index; /* pg_index tuple describing this index */ - /* use "struct" here to avoid needing to include htup.h: */ - struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ - - /* - * index access support info (used only for an index relation) - * - * Note: only default support procs for each opclass are cached, namely - * those with lefttype and righttype equal to the opclass's opcintype. The - * arrays are indexed by support function number, which is a sufficient - * identifier given that restriction. - */ - MemoryContext rd_indexcxt; /* private memory cxt for this stuff */ - /* use "struct" here to avoid needing to include amapi.h: */ - const struct IndexAmRoutine *rd_indam; /* index AM's API struct */ - Oid *rd_opfamily; /* OIDs of op families for each index col */ - Oid *rd_opcintype; /* OIDs of opclass declared input data types */ - RegProcedure *rd_support; /* OIDs of support procedures */ - struct FmgrInfo *rd_supportinfo; /* lookup info for support procedures */ - int16 *rd_indoption; /* per-column AM-specific flags */ - List *rd_indexprs; /* index expression trees, if any */ - List *rd_indpred; /* index predicate tree, if any */ - Oid *rd_exclops; /* OIDs of exclusion operators, if any */ - Oid *rd_exclprocs; /* OIDs of exclusion ops' procs, if any */ - uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */ - Oid *rd_indcollation; /* OIDs of index collations */ - bytea **rd_opcoptions; /* parsed opclass-specific options */ - /* * rd_amcache is available for index and table AMs to cache private data * about the relation. This must be just a cache since it may get reset @@ -214,37 +256,6 @@ typedef struct RelationData */ void *rd_amcache; /* available for use by index/table AM */ - /* - * foreign-table support - * - * rd_fdwroutine must point to a single memory chunk palloc'd in - * CacheMemoryContext. It will be freed and reset to NULL on a relcache - * reset. - */ - - /* use "struct" here to avoid needing to include fdwapi.h: */ - struct FdwRoutine *rd_fdwroutine; /* cached function pointers, or NULL */ - - /* - * Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new - * version of a table, we need to make any toast pointers inserted into it - * have the existing toast table's OID, not the OID of the transient toast - * table. If rd_toastoid isn't InvalidOid, it is the OID to place in - * toast pointers inserted into this rel. (Note it's set on the new - * version of the main heap, not the toast table itself.) This also - * causes toast_save_datum() to try to preserve toast value OIDs. - */ - Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */ - - /* - * Type OID of the "chunk_id" column of this relation's TOAST table, i.e. - * OIDOID or OID8OID. - * - * This data is filled on demand by RelationGetToastChunkIdType(), not at - * relcache build time, so as to save in syscache lookups. - */ - Oid rd_toastchunkidtype; - bool pgstat_enabled; /* should relation stats be counted */ /* use "struct" here to avoid needing to include pgstat.h: */ struct PgStat_RelationStatus *pgstat_info; /* statistics collection area */ -- 2.55.0