aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/syscache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/syscache.c')
-rw-r--r--src/backend/utils/cache/syscache.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
new file mode 100644
index 00000000000..36b46d9b99e
--- /dev/null
+++ b/src/backend/utils/cache/syscache.c
@@ -0,0 +1,630 @@
+/*-------------------------------------------------------------------------
+ *
+ * syscache.c--
+ * System cache management routines
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.1.1.1 1996/07/09 06:22:07 scrappy Exp $
+ *
+ * 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
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "catalog/catname.h"
+#include "utils/catcache.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "nodes/pg_list.h"
+
+/* ----------------
+ * hardwired attribute information comes from system catalog files.
+ * ----------------
+ */
+#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_attribute.h"
+#include "catalog/pg_group.h"
+#include "catalog/pg_index.h"
+#include "catalog/pg_inherits.h"
+#include "catalog/pg_language.h"
+#include "catalog/pg_opclass.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_rewrite.h"
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_user.h"
+#include "storage/large_object.h"
+#include "catalog/pg_listener.h"
+
+extern bool AMI_OVERRIDE; /* XXX style */
+
+#include "utils/syscache.h"
+#include "catalog/indexing.h"
+
+typedef HeapTuple (*ScanFunc)();
+
+/* ----------------
+ * Warning: cacheinfo[] below is changed, then be sure and
+ * update the magic constants in syscache.h!
+ * ----------------
+ */
+static struct cachedesc cacheinfo[] = {
+ { AccessMethodOperatorRelationName, /* AMOPOPID */
+ 3,
+ { Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopopr,
+ Anum_pg_amop_amopid,
+ 0 },
+ sizeof(FormData_pg_amop),
+ NULL,
+ (ScanFunc) NULL },
+ { AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
+ 3,
+ { Anum_pg_amop_amopid,
+ Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopstrategy,
+ 0 },
+ sizeof(FormData_pg_amop),
+ NULL,
+ (ScanFunc) NULL },
+ { AttributeRelationName, /* ATTNAME */
+ 2,
+ { Anum_pg_attribute_attrelid,
+ Anum_pg_attribute_attname,
+ 0,
+ 0 },
+ ATTRIBUTE_TUPLE_SIZE,
+ AttributeNameIndex,
+ (ScanFunc) AttributeNameIndexScan },
+ { AttributeRelationName, /* ATTNUM */
+ 2,
+ { Anum_pg_attribute_attrelid,
+ Anum_pg_attribute_attnum,
+ 0,
+ 0 },
+ ATTRIBUTE_TUPLE_SIZE,
+ AttributeNumIndex,
+ (ScanFunc) AttributeNumIndexScan },
+ { IndexRelationName, /* INDEXRELID */
+ 1,
+ { Anum_pg_index_indexrelid,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_index, indpred),
+ NULL,
+ NULL },
+ { LanguageRelationName, /* LANNAME */
+ 1,
+ { Anum_pg_language_lanname,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_language, lancompiler),
+ NULL,
+ NULL },
+ { OperatorRelationName, /* OPRNAME */
+ 4,
+ { Anum_pg_operator_oprname,
+ Anum_pg_operator_oprleft,
+ Anum_pg_operator_oprright,
+ Anum_pg_operator_oprkind },
+ sizeof(FormData_pg_operator),
+ NULL,
+ NULL },
+ { OperatorRelationName, /* OPROID */
+ 1,
+ { ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0 },
+ sizeof(FormData_pg_operator),
+ NULL,
+ (ScanFunc) NULL },
+ { ProcedureRelationName, /* PRONAME */
+ 3,
+ { Anum_pg_proc_proname,
+ Anum_pg_proc_pronargs,
+ Anum_pg_proc_proargtypes,
+ 0 },
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureNameIndex,
+ (ScanFunc) ProcedureNameIndexScan },
+ { ProcedureRelationName, /* PROOID */
+ 1,
+ { ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureOidIndex,
+ (ScanFunc) ProcedureOidIndexScan },
+ { RelationRelationName, /* RELNAME */
+ 1,
+ { Anum_pg_class_relname,
+ 0,
+ 0,
+ 0 },
+ CLASS_TUPLE_SIZE,
+ ClassNameIndex,
+ (ScanFunc) ClassNameIndexScan },
+ { RelationRelationName, /* RELOID */
+ 1,
+ { ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0 },
+ CLASS_TUPLE_SIZE,
+ ClassOidIndex,
+ (ScanFunc) ClassOidIndexScan },
+ { TypeRelationName, /* TYPNAME */
+ 1,
+ { Anum_pg_type_typname,
+ 0,
+ 0,
+ 0 },
+ offsetof(TypeTupleFormData,typalign)+sizeof(char),
+ TypeNameIndex,
+ TypeNameIndexScan },
+ { TypeRelationName, /* TYPOID */
+ 1,
+ { ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ offsetof(TypeTupleFormData,typalign)+sizeof(char),
+ TypeOidIndex,
+ TypeOidIndexScan },
+ { AccessMethodRelationName, /* AMNAME */
+ 1,
+ { Anum_pg_am_amname,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_am),
+ NULL,
+ NULL },
+ { OperatorClassRelationName, /* CLANAME */
+ 1,
+ { Anum_pg_opclass_opcname,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_opclass),
+ NULL,
+ NULL },
+ { IndexRelationName, /* INDRELIDKEY */
+ 2,
+ { Anum_pg_index_indrelid,
+ Anum_pg_index_indkey,
+ 0,
+ 0},
+ offsetof(FormData_pg_index, indpred),
+ NULL,
+ (ScanFunc) NULL },
+ { InheritsRelationName, /* INHRELID */
+ 2,
+ { Anum_pg_inherits_inhrel,
+ Anum_pg_inherits_inhseqno,
+ 0,
+ 0},
+ sizeof(FormData_pg_inherits),
+ NULL,
+ (ScanFunc) NULL },
+ { RewriteRelationName, /* RULOID */
+ 1,
+ { ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_rewrite, ev_qual),
+ NULL,
+ (ScanFunc) NULL },
+ { AggregateRelationName, /*AGGNAME*/
+ 2,
+ { Anum_pg_aggregate_aggname,
+ Anum_pg_aggregate_aggbasetype,
+ 0,
+ 0 },
+ offsetof(FormData_pg_aggregate, agginitval1),
+ NULL,
+ (ScanFunc) NULL },
+ { ListenerRelationName, /* LISTENREL */
+ 2,
+ { Anum_pg_listener_relname,
+ Anum_pg_listener_pid,
+ 0,
+ 0 },
+ sizeof(FormData_pg_listener),
+ NULL,
+ (ScanFunc) NULL },
+ { UserRelationName, /* USENAME */
+ 1,
+ { Anum_pg_user_usename,
+ 0,
+ 0,
+ 0 },
+ sizeof(FormData_pg_user),
+ NULL,
+ (ScanFunc) NULL },
+ { UserRelationName, /* USESYSID */
+ 1,
+ { Anum_pg_user_usesysid,
+ 0,
+ 0,
+ 0 },
+ sizeof(FormData_pg_user),
+ NULL,
+ (ScanFunc) NULL },
+ { GroupRelationName, /* GRONAME */
+ 1,
+ { Anum_pg_group_groname,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_group, grolist[0]),
+ NULL,
+ (ScanFunc) NULL },
+ { GroupRelationName, /* GROSYSID */
+ 1,
+ { Anum_pg_group_grosysid,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_group, grolist[0]),
+ NULL,
+ (ScanFunc) NULL },
+ { RewriteRelationName, /* REWRITENAME */
+ 1,
+ { Anum_pg_rewrite_rulename,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_rewrite, ev_qual),
+ NULL,
+ (ScanFunc) NULL },
+ { ProcedureRelationName, /* PROSRC */
+ 1,
+ { Anum_pg_proc_prosrc,
+ 0,
+ 0,
+ 0 },
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureSrcIndex,
+ (ScanFunc) ProcedureSrcIndexScan }
+};
+
+static struct catcache *SysCache[lengthof(cacheinfo)];
+static int32 SysCacheSize = lengthof(cacheinfo);
+
+
+/*
+ * zerocaches--
+ *
+ * Make sure the SysCache structure is zero'd.
+ */
+void
+zerocaches()
+{
+ memset((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
+}
+
+/*
+ * 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.
+ */
+void
+InitCatalogCache()
+{
+ int cacheId; /* XXX type */
+
+ 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(WARN,
+ "InitCatalogCache: Can't init cache %.16s(%d)",
+ cacheinfo[cacheId].name,
+ cacheId);
+ }
+
+ }
+ }
+}
+
+/*
+ * SearchSysCacheTuple--
+ *
+ * A layer on top of SearchSysCache that does the initialization and
+ * key-setting for you.
+ *
+ * Returns the tuple if one is found, NULL if not.
+ *
+ * XXX The tuple that is returned is NOT supposed to be pfree'd!
+ */
+HeapTuple
+SearchSysCacheTuple(int cacheId, /* cache selection code */
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ register HeapTuple tp;
+
+ if (cacheId < 0 || cacheId >= SysCacheSize) {
+ elog(WARN, "SearchSysCacheTuple: Bad cache id %d", cacheId);
+ return((HeapTuple) NULL);
+ }
+
+ if (!AMI_OVERRIDE) {
+ Assert(PointerIsValid(SysCache[cacheId]));
+ } else {
+ 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(WARN,
+ "InitCatalogCache: Can't init cache %.16s(%d)",
+ cacheinfo[cacheId].name,
+ cacheId);
+ }
+
+ }
+ }
+
+ tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tp)) {
+#ifdef CACHEDEBUG
+ elog(DEBUG,
+ "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
+ (*cacheinfo[cacheId].name)->data,
+ cacheId, key1, key2, key3, key4);
+#endif
+ return((HeapTuple) NULL);
+ }
+ return(tp);
+}
+
+/*
+ * 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.
+ *
+ * NOTE: we are assuming that non-variable-length fields in the system
+ * catalogs will always be defined!
+ *
+ * Returns 1L if a tuple was found, 0L if not.
+ */
+int32
+SearchSysCacheStruct(int cacheId, /* cache selection code */
+ char *returnStruct, /* (preallocated!) */
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tp;
+
+ if (!PointerIsValid(returnStruct)) {
+ elog(WARN, "SearchSysCacheStruct: No receiving struct");
+ return(0);
+ }
+ tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tp))
+ return(0);
+ memmove(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
+ return(1);
+}
+
+
+/*
+ * SearchSysCacheGetAttribute--
+ * Returns the attribute corresponding to 'attributeNumber' for
+ * a given cached tuple.
+ *
+ * XXX This re-opens a relation, so this is slower.
+ *
+ * [callers all assume this returns a (struct varlena *). -ay 10/94]
+ */
+void *
+SearchSysCacheGetAttribute(int cacheId,
+ AttrNumber attributeNumber,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tp;
+ char *cacheName;
+ Relation relation;
+ int32 attributeLength, attributeByValue;
+ bool isNull;
+ char *attributeValue;
+ void *returnValue;
+
+ tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+ cacheName = cacheinfo[cacheId].name;
+
+ if (!HeapTupleIsValid(tp)) {
+#ifdef CACHEDEBUG
+ elog(DEBUG,
+ "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
+ cacheName, cacheId);
+#endif /* defined(CACHEDEBUG) */
+ return(NULL);
+ }
+
+ relation = heap_openr(cacheName);
+
+ 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 {
+ elog(WARN,
+ "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
+ attributeNumber, cacheName, cacheId);
+ return(NULL);
+ }
+
+ attributeValue = heap_getattr(tp,
+ (Buffer) 0,
+ attributeNumber,
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+
+ if (isNull) {
+ /*
+ * 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
+ */
+ return(NULL);
+ }
+
+ if (attributeByValue) {
+ returnValue = (void *)attributeValue;
+ } else {
+ char *tmp;
+ int size = (attributeLength < 0)
+ ? VARSIZE((struct varlena *) attributeValue) /* variable length */
+ : attributeLength; /* fixed length */
+
+ tmp = (char *) palloc(size);
+ memmove(tmp, attributeValue, size);
+ returnValue = (void *)tmp;
+ }
+
+ heap_close(relation);
+ return(returnValue);
+}
+
+/*
+ * TypeDefaultRetrieve--
+ *
+ * Given a type OID, return the typdefault field associated with that
+ * type. The typdefault is returned as the car of a dotted pair which
+ * is passed to TypeDefaultRetrieve by the calling routine.
+ *
+ * Returns a fixnum for types which are passed by value and a ppreserve'd
+ * vectori for types which are not.
+ *
+ * [identical to get_typdefault, expecting a (struct varlena *) as ret val.
+ * some day, either of the functions should be removed -ay 10/94]
+ */
+void *
+TypeDefaultRetrieve(Oid typId)
+{
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+ int32 typByVal, typLen;
+ struct varlena *typDefault;
+ int32 dataSize;
+ void *returnValue;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typId),
+ 0,0,0);
+
+ if (!HeapTupleIsValid(typeTuple)) {
+#ifdef CACHEDEBUG
+ elog(DEBUG, "TypeDefaultRetrieve: Lookup in %s(%d) failed",
+ (*cacheinfo[TYPOID].name)->data, TYPOID);
+#endif /* defined(CACHEDEBUG) */
+ return(NULL);
+ }
+
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+ typByVal = type->typbyval;
+ typLen = type->typlen;
+
+ typDefault = (struct varlena *)
+ SearchSysCacheGetAttribute(TYPOID,
+ Anum_pg_type_typdefault,
+ ObjectIdGetDatum(typId),
+ 0,0,0);
+
+ if (typDefault == (struct varlena *)NULL) {
+#ifdef CACHEDEBUG
+ elog(DEBUG, "TypeDefaultRetrieve: No extractable typdefault",
+ (*cacheinfo[TYPOID].name)->data, TYPOID);
+#endif /* defined(CACHEDEBUG) */
+ return (NULL);
+
+ }
+
+ dataSize = VARSIZE(typDefault) - VARHDRSZ;
+
+ if (typByVal) {
+ int8 i8;
+ int16 i16;
+ int32 i32;
+
+ if (dataSize == typLen) {
+ switch (typLen) {
+ case sizeof(int8):
+ memmove((char *) &i8, VARDATA(typDefault), sizeof(int8));
+ i32 = i8;
+ break;
+ case sizeof(int16):
+ memmove((char *) &i16, VARDATA(typDefault), sizeof(int16));
+ i32 = i16;
+ break;
+ case sizeof(int32):
+ memmove((char *) &i32, VARDATA(typDefault), sizeof(int32));
+ break;
+ }
+ returnValue = (void *)i32;
+ } else {
+ returnValue = NULL;
+ }
+ } else {
+ if ((typLen < 0 && dataSize < 0) || dataSize != typLen)
+ returnValue = NULL;
+ else {
+ returnValue = (void *)palloc(VARSIZE(typDefault));
+ memmove((char *) returnValue,
+ (char *) typDefault,
+ (int) VARSIZE(typDefault));
+ }
+ }
+
+ return(returnValue);
+}
+
+