* syscache.c
* System cache management routines
*
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.44 1999/11/24 17:09:27 momjian Exp $
+ * src/backend/utils/cache/syscache.c
*
* NOTES
* These routines allow the parser/planner/executor to perform
* rapid lookups on the contents of the system catalogs.
*
- * see catalog/syscache.h for a list of the cache id's
+ * see utils/syscache.h for a list of the cache IDs
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "utils/builtins.h"
-#include "access/heapam.h"
-#include "catalog/catname.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
-#include "catalog/pg_group.h"
-#include "catalog/pg_index.h"
-#include "catalog/pg_inherits.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_auth_members.h"
+#include "catalog/pg_authid.h"
+#include "catalog/pg_cast.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_conversion.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
+#include "catalog/pg_default_acl.h"
+#include "catalog/pg_depend.h"
+#include "catalog/pg_description.h"
+#include "catalog/pg_enum.h"
+#include "catalog/pg_event_trigger.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_foreign_table.h"
#include "catalog/pg_language.h"
-#include "catalog/pg_listener.h"
+#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
+#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
+#include "catalog/pg_publication.h"
+#include "catalog/pg_publication_rel.h"
+#include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_seclabel.h"
+#include "catalog/pg_sequence.h"
+#include "catalog/pg_shdepend.h"
+#include "catalog/pg_shdescription.h"
+#include "catalog/pg_shseclabel.h"
+#include "catalog/pg_replication_origin.h"
#include "catalog/pg_statistic.h"
+#include "catalog/pg_statistic_ext.h"
+#include "catalog/pg_subscription.h"
+#include "catalog/pg_subscription_rel.h"
+#include "catalog/pg_tablespace.h"
+#include "catalog/pg_transform.h"
+#include "catalog/pg_ts_config.h"
+#include "catalog/pg_ts_config_map.h"
+#include "catalog/pg_ts_dict.h"
+#include "catalog/pg_ts_parser.h"
+#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
+#include "utils/rel.h"
#include "utils/catcache.h"
-#include "utils/temprel.h"
-
-extern bool AMI_OVERRIDE; /* XXX style */
-
#include "utils/syscache.h"
-#include "catalog/indexing.h"
-
-typedef HeapTuple (*ScanFunc) ();
/*---------------------------------------------------------------------------
Adding system caches:
- Add your new cache to the list in include/utils/syscache.h. Keep
- the list sorted alphabetically and adjust the cache numbers
- accordingly.
-
- Add your entry to the cacheinfo[] array below. All cache lists are
- alphabetical, so add it in the proper place. Specify the relation
- name, number of arguments, argument names, size of tuple, index lookup
- function, and index name.
-
- In include/catalog/indexing.h, add a define for the number of indexes
- in the relation, add a define for the index name, add an extern
- array to hold the index names, define the index lookup function
- prototype, and use DECLARE_UNIQUE_INDEX to define the index. Cache
- lookups return only one row, so the index should be unique.
-
- In backend/catalog/indexing.c, initialize the relation array with
- the index names for the relation, fixed size of relation (or marking
- first non-fixed length field), and create the index lookup function.
- Pick one that takes similar arguments and use that one, but keep the
- function names in the same order as the cache list for clarity.
-
- Finally, any place your relation gets heap_insert() or
- heap_update calls, include code to do a CatalogIndexInsert() to update
- the system indexes. The heap_* calls do not update indexes.
-
- bjm 1999/11/22
-
- ---------------------------------------------------------------------------
+ Add your new cache to the list in include/utils/syscache.h.
+ Keep the list sorted alphabetically.
+
+ Add your entry to the cacheinfo[] array below. All cache lists are
+ alphabetical, so add it in the proper place. Specify the relation OID,
+ index OID, number of keys, key attribute numbers, and initial number of
+ hash buckets.
+
+ The number of hash buckets must be a power of 2. It's reasonable to
+ set this to the number of entries that might be in the particular cache
+ in a medium-size database.
+
+ There must be a unique index underlying each syscache (ie, an index
+ whose key is the same as that of the cache). If there is not one
+ already, add definitions for it to include/catalog/indexing.h: you need
+ to add a DECLARE_UNIQUE_INDEX macro and a #define for the index OID.
+ (Adding an index requires a catversion.h update, while simply
+ adding/deleting caches only requires a recompile.)
+
+ Finally, any place your relation gets heap_insert() or
+ heap_update() calls, use CatalogTupleInsert() or CatalogTupleUpdate()
+ instead, which also update indexes. The heap_* calls do not do that.
+
+*---------------------------------------------------------------------------
*/
-static struct cachedesc cacheinfo[] = {
- {AggregateRelationName, /* AGGNAME */
- 2,
+/*
+ * struct cachedesc: information defining a single syscache
+ */
+struct cachedesc
+{
+ Oid reloid; /* OID of the relation being cached */
+ Oid indoid; /* OID of index relation for this cache */
+ int nkeys; /* # of keys needed for cache lookup */
+ int key[4]; /* attribute numbers of key attrs */
+ int nbuckets; /* number of hash buckets for this cache */
+};
+
+static const struct cachedesc cacheinfo[] = {
+ {AggregateRelationId, /* AGGFNOID */
+ AggregateFnoidIndexId,
+ 1,
{
- Anum_pg_aggregate_aggname,
- Anum_pg_aggregate_aggbasetype,
+ Anum_pg_aggregate_aggfnoid,
+ 0,
0,
0
},
- offsetof(FormData_pg_aggregate, agginitval1),
- AggregateNameTypeIndex,
- AggregateNameTypeIndexScan},
- {AccessMethodRelationName, /* AMNAME */
+ 16
+ },
+ {AccessMethodRelationId, /* AMNAME */
+ AmNameIndexId,
1,
{
Anum_pg_am_amname,
0,
0
},
- sizeof(FormData_pg_am),
- AmNameIndex,
- AmNameIndexScan},
- {AccessMethodOperatorRelationName, /* AMOPOPID */
- 3,
+ 4
+ },
+ {AccessMethodRelationId, /* AMOID */
+ AmOidIndexId,
+ 1,
{
- Anum_pg_amop_amopclaid,
- Anum_pg_amop_amopopr,
- Anum_pg_amop_amopid,
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
0
},
- sizeof(FormData_pg_amop),
- AccessMethodOpidIndex,
- AccessMethodOpidIndexScan},
- {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
+ 4
+ },
+ {AccessMethodOperatorRelationId, /* AMOPOPID */
+ AccessMethodOperatorIndexId,
3,
{
- Anum_pg_amop_amopid,
- Anum_pg_amop_amopclaid,
- Anum_pg_amop_amopstrategy,
+ Anum_pg_amop_amopopr,
+ Anum_pg_amop_amoppurpose,
+ Anum_pg_amop_amopfamily,
0
},
- sizeof(FormData_pg_amop),
- AccessMethodStrategyIndex,
- (ScanFunc) AccessMethodStrategyIndexScan},
- {AttributeRelationName, /* ATTNAME */
+ 64
+ },
+ {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
+ AccessMethodStrategyIndexId,
+ 4,
+ {
+ Anum_pg_amop_amopfamily,
+ Anum_pg_amop_amoplefttype,
+ Anum_pg_amop_amoprighttype,
+ Anum_pg_amop_amopstrategy
+ },
+ 64
+ },
+ {AccessMethodProcedureRelationId, /* AMPROCNUM */
+ AccessMethodProcedureIndexId,
+ 4,
+ {
+ Anum_pg_amproc_amprocfamily,
+ Anum_pg_amproc_amproclefttype,
+ Anum_pg_amproc_amprocrighttype,
+ Anum_pg_amproc_amprocnum
+ },
+ 16
+ },
+ {AttributeRelationId, /* ATTNAME */
+ AttributeRelidNameIndexId,
2,
{
Anum_pg_attribute_attrelid,
0,
0
},
- ATTRIBUTE_TUPLE_SIZE,
- AttributeRelidNameIndex,
- AttributeRelidNameIndexScan},
- {AttributeRelationName, /* ATTNUM */
+ 32
+ },
+ {AttributeRelationId, /* ATTNUM */
+ AttributeRelidNumIndexId,
2,
{
Anum_pg_attribute_attrelid,
0,
0
},
- ATTRIBUTE_TUPLE_SIZE,
- AttributeRelidNumIndex,
- (ScanFunc) AttributeRelidNumIndexScan},
- {OperatorClassRelationName, /* CLADEFTYPE */
+ 128
+ },
+ {AuthMemRelationId, /* AUTHMEMMEMROLE */
+ AuthMemMemRoleIndexId,
+ 2,
+ {
+ Anum_pg_auth_members_member,
+ Anum_pg_auth_members_roleid,
+ 0,
+ 0
+ },
+ 8
+ },
+ {AuthMemRelationId, /* AUTHMEMROLEMEM */
+ AuthMemRoleMemIndexId,
+ 2,
+ {
+ Anum_pg_auth_members_roleid,
+ Anum_pg_auth_members_member,
+ 0,
+ 0
+ },
+ 8
+ },
+ {AuthIdRelationId, /* AUTHNAME */
+ AuthIdRolnameIndexId,
1,
{
- Anum_pg_opclass_opcdeftype,
+ Anum_pg_authid_rolname,
0,
0,
0
},
- sizeof(FormData_pg_opclass),
- OpclassDeftypeIndex,
- OpclassDeftypeIndexScan},
- {OperatorClassRelationName, /* CLANAME */
+ 8
+ },
+ {AuthIdRelationId, /* AUTHOID */
+ AuthIdOidIndexId,
1,
{
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {
+ CastRelationId, /* CASTSOURCETARGET */
+ CastSourceTargetIndexId,
+ 2,
+ {
+ Anum_pg_cast_castsource,
+ Anum_pg_cast_casttarget,
+ 0,
+ 0
+ },
+ 256
+ },
+ {OperatorClassRelationId, /* CLAAMNAMENSP */
+ OpclassAmNameNspIndexId,
+ 3,
+ {
+ Anum_pg_opclass_opcmethod,
Anum_pg_opclass_opcname,
+ Anum_pg_opclass_opcnamespace,
+ 0
+ },
+ 8
+ },
+ {OperatorClassRelationId, /* CLAOID */
+ OpclassOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
0,
0,
0
},
- sizeof(FormData_pg_opclass),
- OpclassNameIndex,
- OpclassNameIndexScan},
- {GroupRelationName, /* GRONAME */
+ 8
+ },
+ {CollationRelationId, /* COLLNAMEENCNSP */
+ CollationNameEncNspIndexId,
+ 3,
+ {
+ Anum_pg_collation_collname,
+ Anum_pg_collation_collencoding,
+ Anum_pg_collation_collnamespace,
+ 0
+ },
+ 8
+ },
+ {CollationRelationId, /* COLLOID */
+ CollationOidIndexId,
1,
{
- Anum_pg_group_groname,
+ ObjectIdAttributeNumber,
0,
0,
0
},
- offsetof(FormData_pg_group, grolist[0]),
- GroupNameIndex,
- GroupNameIndexScan},
- {GroupRelationName, /* GROSYSID */
+ 8
+ },
+ {ConversionRelationId, /* CONDEFAULT */
+ ConversionDefaultIndexId,
+ 4,
+ {
+ Anum_pg_conversion_connamespace,
+ Anum_pg_conversion_conforencoding,
+ Anum_pg_conversion_contoencoding,
+ ObjectIdAttributeNumber,
+ },
+ 8
+ },
+ {ConversionRelationId, /* CONNAMENSP */
+ ConversionNameNspIndexId,
+ 2,
+ {
+ Anum_pg_conversion_conname,
+ Anum_pg_conversion_connamespace,
+ 0,
+ 0
+ },
+ 8
+ },
+ {ConstraintRelationId, /* CONSTROID */
+ ConstraintOidIndexId,
1,
{
- Anum_pg_group_grosysid,
+ ObjectIdAttributeNumber,
0,
0,
0
},
- offsetof(FormData_pg_group, grolist[0]),
- GroupSysidIndex,
- GroupSysidIndexScan},
- {IndexRelationName, /* INDEXRELID */
+ 16
+ },
+ {ConversionRelationId, /* CONVOID */
+ ConversionOidIndexId,
1,
{
- Anum_pg_index_indexrelid,
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {DatabaseRelationId, /* DATABASEOID */
+ DatabaseOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {DefaultAclRelationId, /* DEFACLROLENSPOBJ */
+ DefaultAclRoleNspObjIndexId,
+ 3,
+ {
+ Anum_pg_default_acl_defaclrole,
+ Anum_pg_default_acl_defaclnamespace,
+ Anum_pg_default_acl_defaclobjtype,
+ 0
+ },
+ 8
+ },
+ {EnumRelationId, /* ENUMOID */
+ EnumOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
0,
0,
0
},
- offsetof(FormData_pg_index, indpred),
- IndexRelidIndex,
- IndexRelidIndexScan},
- {InheritsRelationName, /* INHRELID */
+ 8
+ },
+ {EnumRelationId, /* ENUMTYPOIDNAME */
+ EnumTypIdLabelIndexId,
2,
{
- Anum_pg_inherits_inhrelid,
- Anum_pg_inherits_inhseqno,
+ Anum_pg_enum_enumtypid,
+ Anum_pg_enum_enumlabel,
0,
0
},
- sizeof(FormData_pg_inherits),
- InheritsRelidSeqnoIndex,
- InheritsRelidSeqnoIndexScan},
- {LanguageRelationName, /* LANGNAME */
+ 8
+ },
+ {EventTriggerRelationId, /* EVENTTRIGGERNAME */
+ EventTriggerNameIndexId,
+ 1,
+ {
+ Anum_pg_event_trigger_evtname,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {EventTriggerRelationId, /* EVENTTRIGGEROID */
+ EventTriggerOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */
+ ForeignDataWrapperNameIndexId,
+ 1,
+ {
+ Anum_pg_foreign_data_wrapper_fdwname,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */
+ ForeignDataWrapperOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVERNAME */
+ ForeignServerNameIndexId,
+ 1,
+ {
+ Anum_pg_foreign_server_srvname,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVEROID */
+ ForeignServerOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignTableRelationId, /* FOREIGNTABLEREL */
+ ForeignTableRelidIndexId,
+ 1,
+ {
+ Anum_pg_foreign_table_ftrelid,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {IndexRelationId, /* INDEXRELID */
+ IndexRelidIndexId,
+ 1,
+ {
+ Anum_pg_index_indexrelid,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
+ {LanguageRelationId, /* LANGNAME */
+ LanguageNameIndexId,
1,
{
Anum_pg_language_lanname,
0,
0
},
- offsetof(FormData_pg_language, lancompiler),
- LanguageNameIndex,
- LanguageNameIndexScan},
- {LanguageRelationName, /* LANGOID */
+ 4
+ },
+ {LanguageRelationId, /* LANGOID */
+ LanguageOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- offsetof(FormData_pg_language, lancompiler),
- LanguageOidIndex,
- LanguageOidIndexScan},
- {ListenerRelationName, /* LISTENREL */
- 2,
+ 4
+ },
+ {NamespaceRelationId, /* NAMESPACENAME */
+ NamespaceNameIndexId,
+ 1,
{
- Anum_pg_listener_relname,
- Anum_pg_listener_pid,
+ Anum_pg_namespace_nspname,
+ 0,
0,
0
},
- sizeof(FormData_pg_listener),
- ListenerRelnamePidIndex,
- ListenerRelnamePidIndexScan},
- {OperatorRelationName, /* OPERNAME */
+ 4
+ },
+ {NamespaceRelationId, /* NAMESPACEOID */
+ NamespaceOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 16
+ },
+ {OperatorRelationId, /* OPERNAMENSP */
+ OperatorNameNspIndexId,
4,
{
Anum_pg_operator_oprname,
Anum_pg_operator_oprleft,
Anum_pg_operator_oprright,
- Anum_pg_operator_oprkind
+ Anum_pg_operator_oprnamespace
},
- sizeof(FormData_pg_operator),
- OperatorNameIndex,
- (ScanFunc) OperatorNameIndexScan},
- {OperatorRelationName, /* OPEROID */
+ 256
+ },
+ {OperatorRelationId, /* OPEROID */
+ OperatorOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- sizeof(FormData_pg_operator),
- OperatorOidIndex,
- OperatorOidIndexScan},
- {ProcedureRelationName, /* PROCNAME */
+ 32
+ },
+ {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */
+ OpfamilyAmNameNspIndexId,
+ 3,
+ {
+ Anum_pg_opfamily_opfmethod,
+ Anum_pg_opfamily_opfname,
+ Anum_pg_opfamily_opfnamespace,
+ 0
+ },
+ 8
+ },
+ {OperatorFamilyRelationId, /* OPFAMILYOID */
+ OpfamilyOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {PartitionedRelationId, /* PARTRELID */
+ PartitionedRelidIndexId,
+ 1,
+ {
+ Anum_pg_partitioned_table_partrelid,
+ 0,
+ 0,
+ 0
+ },
+ 32
+ },
+ {ProcedureRelationId, /* PROCNAMEARGSNSP */
+ ProcedureNameArgsNspIndexId,
3,
{
Anum_pg_proc_proname,
- Anum_pg_proc_pronargs,
Anum_pg_proc_proargtypes,
+ Anum_pg_proc_pronamespace,
0
},
- offsetof(FormData_pg_proc, prosrc),
- ProcedureNameIndex,
- (ScanFunc) ProcedureNameIndexScan},
- {ProcedureRelationName, /* PROCOID */
+ 128
+ },
+ {ProcedureRelationId, /* PROCOID */
+ ProcedureOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- offsetof(FormData_pg_proc, prosrc),
- ProcedureOidIndex,
- ProcedureOidIndexScan},
- {RelationRelationName, /* RELNAME */
+ 128
+ },
+ {RangeRelationId, /* RANGETYPE */
+ RangeTypidIndexId,
1,
+ {
+ Anum_pg_range_rngtypid,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {RelationRelationId, /* RELNAMENSP */
+ ClassNameNspIndexId,
+ 2,
{
Anum_pg_class_relname,
+ Anum_pg_class_relnamespace,
+ 0,
+ 0
+ },
+ 128
+ },
+ {RelationRelationId, /* RELOID */
+ ClassOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
0,
0,
0
},
- CLASS_TUPLE_SIZE,
- ClassNameIndex,
- ClassNameIndexScan},
- {RelationRelationName, /* RELOID */
+ 128
+ },
+ {ReplicationOriginRelationId, /* REPLORIGIDENT */
+ ReplicationOriginIdentIndex,
+ 1,
+ {
+ Anum_pg_replication_origin_roident,
+ 0,
+ 0,
+ 0
+ },
+ 16
+ },
+ {ReplicationOriginRelationId, /* REPLORIGNAME */
+ ReplicationOriginNameIndex,
+ 1,
+ {
+ Anum_pg_replication_origin_roname,
+ 0,
+ 0,
+ 0
+ },
+ 16
+ },
+ {PublicationRelationId, /* PUBLICATIONOID */
+ PublicationObjectIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- CLASS_TUPLE_SIZE,
- ClassOidIndex,
- ClassOidIndexScan},
- {RewriteRelationName, /* REWRITENAME */
+ 8
+ },
+ {PublicationRelationId, /* PUBLICATIONNAME */
+ PublicationNameIndexId,
1,
{
- Anum_pg_rewrite_rulename,
+ Anum_pg_publication_pubname,
0,
0,
0
},
- offsetof(FormData_pg_rewrite, ev_qual),
- RewriteRulenameIndex,
- RewriteRulenameIndexScan},
- {RewriteRelationName, /* RULEOID */
+ 8
+ },
+ {PublicationRelRelationId, /* PUBLICATIONREL */
+ PublicationRelObjectIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- offsetof(FormData_pg_rewrite, ev_qual),
- RewriteOidIndex,
- RewriteOidIndexScan},
- {ShadowRelationName, /* SHADOWNAME */
+ 64
+ },
+ {PublicationRelRelationId, /* PUBLICATIONRELMAP */
+ PublicationRelPrrelidPrpubidIndexId,
+ 2,
+ {
+ Anum_pg_publication_rel_prrelid,
+ Anum_pg_publication_rel_prpubid,
+ 0,
+ 0
+ },
+ 64
+ },
+ {RewriteRelationId, /* RULERELNAME */
+ RewriteRelRulenameIndexId,
+ 2,
+ {
+ Anum_pg_rewrite_ev_class,
+ Anum_pg_rewrite_rulename,
+ 0,
+ 0
+ },
+ 8
+ },
+ {SequenceRelationId, /* SEQRELID */
+ SequenceRelidIndexId,
1,
{
- Anum_pg_shadow_usename,
+ Anum_pg_sequence_seqrelid,
+ 0,
0,
+ 0
+ },
+ 32
+ },
+ {StatisticExtRelationId, /* STATEXTNAMENSP */
+ StatisticExtNameIndexId,
+ 2,
+ {
+ Anum_pg_statistic_ext_stxname,
+ Anum_pg_statistic_ext_stxnamespace,
0,
0
},
- sizeof(FormData_pg_shadow),
-NULL,NULL
-/* ShadowNameIndex,
- ShadowNameIndexScan*/},
- {ShadowRelationName, /* SHADOWSYSID */
+ 4
+ },
+ {StatisticExtRelationId, /* STATEXTOID */
+ StatisticExtOidIndexId,
1,
{
- Anum_pg_shadow_usesysid,
+ ObjectIdAttributeNumber,
0,
0,
0
},
- sizeof(FormData_pg_shadow),
-NULL,NULL
-/* ShadowSysidIndex,
- ShadowSysidIndexScan*/},
- {StatisticRelationName, /* STATRELID */
+ 4
+ },
+ {StatisticRelationId, /* STATRELATTINH */
+ StatisticRelidAttnumInhIndexId,
3,
{
Anum_pg_statistic_starelid,
Anum_pg_statistic_staattnum,
- Anum_pg_statistic_staop,
+ Anum_pg_statistic_stainherit,
+ 0
+ },
+ 128
+ },
+ {SubscriptionRelationId, /* SUBSCRIPTIONOID */
+ SubscriptionObjectIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {SubscriptionRelationId, /* SUBSCRIPTIONNAME */
+ SubscriptionNameIndexId,
+ 2,
+ {
+ Anum_pg_subscription_subdbid,
+ Anum_pg_subscription_subname,
+ 0,
+ 0
+ },
+ 4
+ },
+ {SubscriptionRelRelationId, /* SUBSCRIPTIONRELMAP */
+ SubscriptionRelSrrelidSrsubidIndexId,
+ 2,
+ {
+ Anum_pg_subscription_rel_srrelid,
+ Anum_pg_subscription_rel_srsubid,
+ 0,
+ 0
+ },
+ 64
+ },
+ {TableSpaceRelationId, /* TABLESPACEOID */
+ TablespaceOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0,
+ },
+ 4
+ },
+ {TransformRelationId, /* TRFOID */
+ TransformOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0,
+ },
+ 16
+ },
+ {TransformRelationId, /* TRFTYPELANG */
+ TransformTypeLangIndexId,
+ 2,
+ {
+ Anum_pg_transform_trftype,
+ Anum_pg_transform_trflang,
+ 0,
+ 0,
+ },
+ 16
+ },
+ {TSConfigMapRelationId, /* TSCONFIGMAP */
+ TSConfigMapIndexId,
+ 3,
+ {
+ Anum_pg_ts_config_map_mapcfg,
+ Anum_pg_ts_config_map_maptokentype,
+ Anum_pg_ts_config_map_mapseqno,
+ 0
+ },
+ 2
+ },
+ {TSConfigRelationId, /* TSCONFIGNAMENSP */
+ TSConfigNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_config_cfgname,
+ Anum_pg_ts_config_cfgnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSConfigRelationId, /* TSCONFIGOID */
+ TSConfigOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSDictionaryRelationId, /* TSDICTNAMENSP */
+ TSDictionaryNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_dict_dictname,
+ Anum_pg_ts_dict_dictnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSDictionaryRelationId, /* TSDICTOID */
+ TSDictionaryOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSParserRelationId, /* TSPARSERNAMENSP */
+ TSParserNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_parser_prsname,
+ Anum_pg_ts_parser_prsnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSParserRelationId, /* TSPARSEROID */
+ TSParserOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSTemplateRelationId, /* TSTEMPLATENAMENSP */
+ TSTemplateNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_template_tmplname,
+ Anum_pg_ts_template_tmplnamespace,
+ 0,
0
},
- offsetof(FormData_pg_statistic, stacommonval),
- StatisticRelidAttnumOpIndex,
- (ScanFunc) StatisticRelidAttnumOpIndexScan},
- {TypeRelationName, /* TYPENAME */
+ 2
+ },
+ {TSTemplateRelationId, /* TSTEMPLATEOID */
+ TSTemplateOidIndexId,
1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TypeRelationId, /* TYPENAMENSP */
+ TypeNameNspIndexId,
+ 2,
{
Anum_pg_type_typname,
+ Anum_pg_type_typnamespace,
+ 0,
+ 0
+ },
+ 64
+ },
+ {TypeRelationId, /* TYPEOID */
+ TypeOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
0,
0,
0
},
- offsetof(FormData_pg_type, typalign) +sizeof(char),
- TypeNameIndex,
- TypeNameIndexScan},
- {TypeRelationName, /* TYPEOID */
+ 64
+ },
+ {UserMappingRelationId, /* USERMAPPINGOID */
+ UserMappingOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- offsetof(FormData_pg_type, typalign) +sizeof(char),
- TypeOidIndex,
- TypeOidIndexScan}
+ 2
+ },
+ {UserMappingRelationId, /* USERMAPPINGUSERSERVER */
+ UserMappingUserServerIndexId,
+ 2,
+ {
+ Anum_pg_user_mapping_umuser,
+ Anum_pg_user_mapping_umserver,
+ 0,
+ 0
+ },
+ 2
+ }
};
-static struct catcache *SysCache[lengthof(cacheinfo)];
-static int32 SysCacheSize = lengthof(cacheinfo);
+static CatCache *SysCache[SysCacheSize];
+
+static bool CacheInitialized = false;
+
+/* Sorted array of OIDs of tables that have caches on them */
+static Oid SysCacheRelationOid[SysCacheSize];
+static int SysCacheRelationOidSize;
+
+/* Sorted array of OIDs of tables and indexes used by caches */
+static Oid SysCacheSupportingRelOid[SysCacheSize * 2];
+static int SysCacheSupportingRelOidSize;
+
+static int oid_compare(const void *a, const void *b);
/*
- * zerocaches
+ * InitCatalogCache - initialize the caches
*
- * Make sure the SysCache structure is zero'd.
+ * Note that no database access is done here; we only allocate memory
+ * and initialize the cache structure. Interrogation of the database
+ * to complete initialization of a cache happens upon first use
+ * of that cache.
*/
void
-zerocaches()
+InitCatalogCache(void)
{
- MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
+ int cacheId;
+ int i,
+ j;
+
+ StaticAssertStmt(SysCacheSize == (int) lengthof(cacheinfo),
+ "SysCacheSize does not match syscache.c's array");
+
+ Assert(!CacheInitialized);
+
+ SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
+
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
+ {
+ SysCache[cacheId] = InitCatCache(cacheId,
+ cacheinfo[cacheId].reloid,
+ cacheinfo[cacheId].indoid,
+ cacheinfo[cacheId].nkeys,
+ cacheinfo[cacheId].key,
+ cacheinfo[cacheId].nbuckets);
+ if (!PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "could not initialize cache %u (%d)",
+ cacheinfo[cacheId].reloid, cacheId);
+ /* Accumulate data for OID lists, too */
+ SysCacheRelationOid[SysCacheRelationOidSize++] =
+ cacheinfo[cacheId].reloid;
+ SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
+ cacheinfo[cacheId].reloid;
+ SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
+ cacheinfo[cacheId].indoid;
+ /* see comments for RelationInvalidatesSnapshotsOnly */
+ Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
+ }
+
+ Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid));
+ Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid));
+
+ /* Sort and de-dup OID arrays, so we can use binary search. */
+ pg_qsort(SysCacheRelationOid, SysCacheRelationOidSize,
+ sizeof(Oid), oid_compare);
+ for (i = 1, j = 0; i < SysCacheRelationOidSize; i++)
+ {
+ if (SysCacheRelationOid[i] != SysCacheRelationOid[j])
+ SysCacheRelationOid[++j] = SysCacheRelationOid[i];
+ }
+ SysCacheRelationOidSize = j + 1;
+
+ pg_qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
+ sizeof(Oid), oid_compare);
+ for (i = 1, j = 0; i < SysCacheSupportingRelOidSize; i++)
+ {
+ if (SysCacheSupportingRelOid[i] != SysCacheSupportingRelOid[j])
+ SysCacheSupportingRelOid[++j] = SysCacheSupportingRelOid[i];
+ }
+ SysCacheSupportingRelOidSize = j + 1;
+
+ CacheInitialized = true;
}
/*
- * Note:
- * This function was written because the initialized catalog caches
- * are used to determine which caches may contain tuples which need
- * to be invalidated in other backends.
+ * InitCatalogCachePhase2 - finish initializing the caches
+ *
+ * Finish initializing all the caches, including necessary database
+ * access.
+ *
+ * This is *not* essential; normally we allow syscaches to be initialized
+ * on first use. However, it is useful as a mechanism to preload the
+ * relcache with entries for the most-commonly-used system catalogs.
+ * Therefore, we invoke this routine when we need to write a new relcache
+ * init file.
*/
void
-InitCatalogCache()
+InitCatalogCachePhase2(void)
{
- int cacheId; /* XXX type */
+ int cacheId;
- if (!AMI_OVERRIDE)
- {
- for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
- {
-
- Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
-
- SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheId,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key,
- cacheinfo[cacheId].iScanFunc);
- if (!PointerIsValid((char *) SysCache[cacheId]))
- {
- elog(ERROR,
- "InitCatalogCache: Can't init cache %s(%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
-
- }
- }
+ Assert(CacheInitialized);
+
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
+ InitCatCachePhase2(SysCache[cacheId], true);
}
+
/*
- * SearchSysCacheTupleCopy
+ * SearchSysCache
+ *
+ * A layer on top of SearchCatCache that does the initialization and
+ * key-setting for you.
+ *
+ * Returns the cache copy of the tuple if one is found, NULL if not.
+ * The tuple is the 'cache' copy and must NOT be modified!
+ *
+ * When the caller is done using the tuple, call ReleaseSysCache()
+ * to release the reference count grabbed by SearchSysCache(). If this
+ * is not done, the tuple will remain locked in cache until end of
+ * transaction, which is tolerable but not desirable.
*
- * This is like SearchSysCacheTuple, except it returns a copy of the tuple
- * that the user is required to pfree().
+ * CAUTION: The tuple that is returned must NOT be freed by the caller!
*/
HeapTuple
-SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+SearchSysCache(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- HeapTuple cachetup;
+ if (cacheId < 0 || cacheId >= SysCacheSize ||
+ !PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "invalid cache ID: %d", cacheId);
- cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
- if (PointerIsValid(cachetup))
- return heap_copytuple(cachetup);
- else
- return cachetup; /* NULL */
+ return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
}
+/*
+ * ReleaseSysCache
+ * Release previously grabbed reference count on a tuple
+ */
+void
+ReleaseSysCache(HeapTuple tuple)
+{
+ ReleaseCatCache(tuple);
+}
/*
- * SearchSysCacheTuple
+ * SearchSysCacheCopy
*
- * A layer on top of SearchSysCache that does the initialization and
- * key-setting for you.
+ * A convenience routine that does SearchSysCache and (if successful)
+ * returns a modifiable copy of the syscache entry. The original
+ * syscache entry is released before returning. The caller should
+ * heap_freetuple() the result when done with it.
+ */
+HeapTuple
+SearchSysCacheCopy(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tuple,
+ newtuple;
+
+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tuple))
+ return tuple;
+ newtuple = heap_copytuple(tuple);
+ ReleaseSysCache(tuple);
+ return newtuple;
+}
+
+/*
+ * SearchSysCacheExists
*
- * Returns the cache copy of the tuple if one is found, NULL if not.
- * The tuple is the 'cache' copy.
+ * A convenience routine that just probes to see if a tuple can be found.
+ * No lock is retained on the syscache entry.
+ */
+bool
+SearchSysCacheExists(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tuple;
+
+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tuple))
+ return false;
+ ReleaseSysCache(tuple);
+ return true;
+}
+
+/*
+ * GetSysCacheOid
+ *
+ * A convenience routine that does SearchSysCache and returns the OID
+ * of the found tuple, or InvalidOid if no tuple could be found.
+ * No lock is retained on the syscache entry.
+ */
+Oid
+GetSysCacheOid(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tuple;
+ Oid result;
+
+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tuple))
+ return InvalidOid;
+ result = HeapTupleGetOid(tuple);
+ ReleaseSysCache(tuple);
+ return result;
+}
+
+
+/*
+ * SearchSysCacheAttName
*
- * XXX The tuple that is returned is NOT supposed to be pfree'd!
+ * This routine is equivalent to SearchSysCache on the ATTNAME cache,
+ * except that it will return NULL if the found attribute is marked
+ * attisdropped. This is convenient for callers that want to act as
+ * though dropped attributes don't exist.
*/
HeapTuple
-SearchSysCacheTuple(int cacheId,/* cache selection code */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+SearchSysCacheAttName(Oid relid, const char *attname)
{
- HeapTuple tp;
+ HeapTuple tuple;
- if (cacheId < 0 || cacheId >= SysCacheSize)
+ tuple = SearchSysCache2(ATTNAME,
+ ObjectIdGetDatum(relid),
+ CStringGetDatum(attname));
+ if (!HeapTupleIsValid(tuple))
+ return NULL;
+ if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
{
- elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
- return (HeapTuple) NULL;
+ ReleaseSysCache(tuple);
+ return NULL;
}
+ return tuple;
+}
- Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
+/*
+ * SearchSysCacheCopyAttName
+ *
+ * As above, an attisdropped-aware version of SearchSysCacheCopy.
+ */
+HeapTuple
+SearchSysCacheCopyAttName(Oid relid, const char *attname)
+{
+ HeapTuple tuple,
+ newtuple;
- if (!PointerIsValid(SysCache[cacheId]))
- {
- SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheId,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key,
- cacheinfo[cacheId].iScanFunc);
- if (!PointerIsValid(SysCache[cacheId]))
- elog(ERROR,
- "InitCatalogCache: Can't init cache %s(%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
+ tuple = SearchSysCacheAttName(relid, attname);
+ if (!HeapTupleIsValid(tuple))
+ return tuple;
+ newtuple = heap_copytuple(tuple);
+ ReleaseSysCache(tuple);
+ return newtuple;
+}
- /* temp table name remapping */
- if (cacheId == RELNAME)
- {
- char *nontemp_relname;
+/*
+ * SearchSysCacheExistsAttName
+ *
+ * As above, an attisdropped-aware version of SearchSysCacheExists.
+ */
+bool
+SearchSysCacheExistsAttName(Oid relid, const char *attname)
+{
+ HeapTuple tuple;
- if ((nontemp_relname =
- get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
- key1 = PointerGetDatum(nontemp_relname);
- }
-
- tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
- if (!HeapTupleIsValid(tp))
+ tuple = SearchSysCacheAttName(relid, attname);
+ if (!HeapTupleIsValid(tuple))
+ return false;
+ ReleaseSysCache(tuple);
+ return true;
+}
+
+
+/*
+ * SysCacheGetAttr
+ *
+ * Given a tuple previously fetched by SearchSysCache(),
+ * extract a specific attribute.
+ *
+ * This is equivalent to using heap_getattr() on a tuple fetched
+ * from a non-cached relation. Usually, this is only used for attributes
+ * that could be NULL or variable length; the fixed-size attributes in
+ * a system table are accessed just by mapping the tuple onto the C struct
+ * declarations from include/catalog/.
+ *
+ * As with heap_getattr(), if the attribute is of a pass-by-reference type
+ * then a pointer into the tuple data area is returned --- the caller must
+ * not modify or pfree the datum!
+ *
+ * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
+ * a different cache for the same catalog the tuple was fetched from.
+ */
+Datum
+SysCacheGetAttr(int cacheId, HeapTuple tup,
+ AttrNumber attributeNumber,
+ bool *isNull)
+{
+ /*
+ * We just need to get the TupleDesc out of the cache entry, and then we
+ * can apply heap_getattr(). Normally the cache control data is already
+ * valid (because the caller recently fetched the tuple via this same
+ * cache), but there are cases where we have to initialize the cache here.
+ */
+ if (cacheId < 0 || cacheId >= SysCacheSize ||
+ !PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "invalid cache ID: %d", cacheId);
+ if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
{
-#ifdef CACHEDEBUG
- elog(DEBUG,
- "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
- cacheinfo[cacheId].name,
- cacheId, key1, key2, key3, key4);
-#endif
- return (HeapTuple) NULL;
+ InitCatCachePhase2(SysCache[cacheId], false);
+ Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
}
- return tp;
+
+ return heap_getattr(tup, attributeNumber,
+ SysCache[cacheId]->cc_tupdesc,
+ isNull);
}
/*
- * SearchSysCacheStruct
- * Fills 's' with the information retrieved by calling SearchSysCache()
- * with arguments key1...key4. Retrieves only the portion of the tuple
- * which is not variable-length.
+ * GetSysCacheHashValue
*
- * NOTE: we are assuming that non-variable-length fields in the system
- * catalogs will always be defined!
+ * Get the hash value that would be used for a tuple in the specified cache
+ * with the given search keys.
*
- * Returns 1L if a tuple was found, 0L if not.
+ * The reason for exposing this as part of the API is that the hash value is
+ * exposed in cache invalidation operations, so there are places outside the
+ * catcache code that need to be able to compute the hash values.
*/
-int32
-SearchSysCacheStruct(int cacheId, /* cache selection code */
- char *returnStruct, /* (preallocated!) */
+uint32
+GetSysCacheHashValue(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
- HeapTuple tp;
+ if (cacheId < 0 || cacheId >= SysCacheSize ||
+ !PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "invalid cache ID: %d", cacheId);
- if (!PointerIsValid(returnStruct))
- {
- elog(ERROR, "SearchSysCacheStruct: No receiving struct");
- return 0;
- }
- tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
- if (!HeapTupleIsValid(tp))
- return 0;
- memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
- return 1;
+ return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
}
+/*
+ * List-search interface
+ */
+struct catclist *
+SearchSysCacheList(int cacheId, int nkeys,
+ Datum key1, Datum key2, Datum key3, Datum key4)
+{
+ if (cacheId < 0 || cacheId >= SysCacheSize ||
+ !PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "invalid cache ID: %d", cacheId);
+
+ return SearchCatCacheList(SysCache[cacheId], nkeys,
+ key1, key2, key3, key4);
+}
/*
- * SearchSysCacheGetAttribute
- * Returns the attribute corresponding to 'attributeNumber' for
- * a given cached tuple. This routine usually needs to be used for
- * attributes that might be NULL or might be at a variable offset
- * in the tuple.
+ * SysCacheInvalidate
*
- * XXX This re-opens the relation, so this is slower than just pulling
- * fixed-location fields out of the struct returned by SearchSysCacheTuple.
+ * Invalidate entries in the specified cache, given a hash value.
+ * See CatCacheInvalidate() for more info.
*
- * [callers all assume this returns a (struct varlena *). -ay 10/94]
+ * This routine is only quasi-public: it should only be used by inval.c.
*/
-void *
-SearchSysCacheGetAttribute(int cacheId,
- AttrNumber attributeNumber,
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+void
+SysCacheInvalidate(int cacheId, uint32 hashValue)
{
- HeapTuple tp;
- char *cacheName;
- Relation relation;
- int32 attributeLength,
- attributeByValue;
- bool isNull;
- Datum attributeValue;
- void *returnValue;
+ if (cacheId < 0 || cacheId >= SysCacheSize)
+ elog(ERROR, "invalid cache ID: %d", cacheId);
- /*
- * Open the relation first, to ensure we are in sync with SI inval
- * events --- we don't want the tuple found in the cache to be
- * invalidated out from under us.
- */
- cacheName = cacheinfo[cacheId].name;
- relation = heap_openr(cacheName, AccessShareLock);
+ /* if this cache isn't initialized yet, no need to do anything */
+ if (!PointerIsValid(SysCache[cacheId]))
+ return;
- tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+ CatCacheInvalidate(SysCache[cacheId], hashValue);
+}
- if (!HeapTupleIsValid(tp))
+/*
+ * Certain relations that do not have system caches send snapshot invalidation
+ * messages in lieu of catcache messages. This is for the benefit of
+ * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
+ * for scanning one of those catalogs, rather than taking a new one, if no
+ * invalidation has been received.
+ *
+ * Relations that have syscaches need not (and must not) be listed here. The
+ * catcache invalidation messages will also flush the snapshot. If you add a
+ * syscache for one of these relations, remove it from this list.
+ */
+bool
+RelationInvalidatesSnapshotsOnly(Oid relid)
+{
+ switch (relid)
{
- heap_close(relation, AccessShareLock);
-#ifdef CACHEDEBUG
- elog(DEBUG,
- "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
- cacheName, cacheId);
-#endif /* defined(CACHEDEBUG) */
- return NULL;
+ case DbRoleSettingRelationId:
+ case DependRelationId:
+ case SharedDependRelationId:
+ case DescriptionRelationId:
+ case SharedDescriptionRelationId:
+ case SecLabelRelationId:
+ case SharedSecLabelRelationId:
+ return true;
+ default:
+ break;
}
- if (attributeNumber < 0 &&
- attributeNumber > FirstLowInvalidHeapAttributeNumber)
- {
- attributeLength = heap_sysattrlen(attributeNumber);
- attributeByValue = heap_sysattrbyval(attributeNumber);
- }
- else if (attributeNumber > 0 &&
- attributeNumber <= relation->rd_rel->relnatts)
- {
- attributeLength = relation->rd_att->attrs[attributeNumber - 1]->attlen;
- attributeByValue = relation->rd_att->attrs[attributeNumber - 1]->attbyval;
- }
- else
- {
- heap_close(relation, AccessShareLock);
- elog(ERROR,
- "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
- attributeNumber, cacheName, cacheId);
- return NULL;
- }
+ return false;
+}
- attributeValue = heap_getattr(tp,
- attributeNumber,
- RelationGetDescr(relation),
- &isNull);
+/*
+ * Test whether a relation has a system cache.
+ */
+bool
+RelationHasSysCache(Oid relid)
+{
+ int low = 0,
+ high = SysCacheRelationOidSize - 1;
- if (isNull)
+ while (low <= high)
{
- /*
- * Used to be an elog(DEBUG, ...) here and a claim that it should
- * be a FATAL error, I don't think either is warranted -mer 6/9/92
- */
- heap_close(relation, AccessShareLock);
- return NULL;
+ int middle = low + (high - low) / 2;
+
+ if (SysCacheRelationOid[middle] == relid)
+ return true;
+ if (SysCacheRelationOid[middle] < relid)
+ low = middle + 1;
+ else
+ high = middle - 1;
}
- if (attributeByValue)
- returnValue = (void *) attributeValue;
- else
+ return false;
+}
+
+/*
+ * Test whether a relation supports a system cache, ie it is either a
+ * cached table or the index used for a cache.
+ */
+bool
+RelationSupportsSysCache(Oid relid)
+{
+ int low = 0,
+ high = SysCacheSupportingRelOidSize - 1;
+
+ while (low <= high)
{
- char *tmp;
- int size = (attributeLength < 0)
- ? VARSIZE((struct varlena *) attributeValue) /* variable length */
- : attributeLength; /* fixed length */
-
- tmp = (char *) palloc(size);
- memcpy(tmp, (void *) attributeValue, size);
- returnValue = (void *) tmp;
+ int middle = low + (high - low) / 2;
+
+ if (SysCacheSupportingRelOid[middle] == relid)
+ return true;
+ if (SysCacheSupportingRelOid[middle] < relid)
+ low = middle + 1;
+ else
+ high = middle - 1;
}
- heap_close(relation, AccessShareLock);
- return returnValue;
+ return false;
+}
+
+
+/*
+ * OID comparator for pg_qsort
+ */
+static int
+oid_compare(const void *a, const void *b)
+{
+ Oid oa = *((const Oid *) a);
+ Oid ob = *((const Oid *) b);
+
+ if (oa == ob)
+ return 0;
+ return (oa > ob) ? 1 : -1;
}