]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/cache/syscache.c
Post-PG 10 beta1 pgindent run
[postgresql] / src / backend / utils / cache / syscache.c
index 9c94c1e05a14380ca35d56f6d11746af8ba80eb8..922718c9d17378d4fb230c775a5c7bf1c86e27c4 100644 (file)
  * 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,
@@ -101,32 +141,54 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -134,10 +196,10 @@ static struct cachedesc cacheinfo[] = {
                        0,
                        0
                },
-               ATTRIBUTE_TUPLE_SIZE,
-               AttributeRelidNameIndex,
-       AttributeRelidNameIndexScan},
-       {AttributeRelationName,         /* ATTNUM */
+               32
+       },
+       {AttributeRelationId,           /* ATTNUM */
+               AttributeRelidNumIndexId,
                2,
                {
                        Anum_pg_attribute_attrelid,
@@ -145,76 +207,286 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -222,10 +494,10 @@ static struct cachedesc cacheinfo[] = {
                        0,
                        0
                },
-               offsetof(FormData_pg_language, lancompiler),
-               LanguageNameIndex,
-       LanguageNameIndexScan},
-       {LanguageRelationName,          /* LANGOID */
+               4
+       },
+       {LanguageRelationId,            /* LANGOID */
+               LanguageOidIndexId,
                1,
                {
                        ObjectIdAttributeNumber,
@@ -233,32 +505,43 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -266,21 +549,54 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -288,21 +604,65 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -310,21 +670,21 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -332,56 +692,263 @@ static struct cachedesc cacheinfo[] = {
                        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,
@@ -389,286 +956,501 @@ NULL,NULL
                        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;
 }