postgresql/src/backend/utils/cache/syscache.c

750 lines
15 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* syscache.c
* System cache management routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
1999-07-16 00:40:16 +02:00
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.29 1999/07/15 22:40:04 momjian 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
*
*-------------------------------------------------------------------------
*/
1996-11-03 07:54:38 +01:00
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "utils/catcache.h"
#include <string.h>
/* ----------------
* hardwired attribute information comes from system catalog files.
* ----------------
*/
#include "catalog/pg_amop.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_type.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_shadow.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
},
1999-05-26 00:43:53 +02:00
offsetof(FormData_pg_type, typalign) +sizeof(char),
TypeNameIndex,
TypeNameIndexScan},
{TypeRelationName, /* TYPOID */
1,
{
ObjectIdAttributeNumber,
0,
0,
0
},
1998-09-01 05:29:17 +02:00
offsetof(FormData_pg_type, 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 *//* never used */
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},
{ShadowRelationName, /* USENAME */
1,
{
Anum_pg_shadow_usename,
0,
0,
0
},
sizeof(FormData_pg_shadow),
NULL,
(ScanFunc) NULL},
{ShadowRelationName, /* USESYSID */
1,
{
Anum_pg_shadow_usesysid,
0,
0,
0
},
sizeof(FormData_pg_shadow),
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},
{OperatorClassRelationName, /* CLADEFTYPE */
1,
{
Anum_pg_opclass_opcdeftype,
0,
0,
0
},
sizeof(FormData_pg_opclass),
NULL,
(ScanFunc) NULL},
{LanguageRelationName, /* LANOID */
1,
{
ObjectIdAttributeNumber,
0,
0,
0
},
offsetof(FormData_pg_language, lancompiler),
NULL,
NULL}
};
static struct catcache *SysCache[lengthof(cacheinfo)];
static int32 SysCacheSize = lengthof(cacheinfo);
/*
* zerocaches
*
* Make sure the SysCache structure is zero'd.
*/
void
zerocaches()
{
1997-09-18 22:22:58 +02:00
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,
1999-05-25 18:15:34 +02:00
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);
}
}
}
}
/*
* SearchSysCacheTupleCopy
*
1999-07-07 18:09:33 +02:00
* This is like SearchSysCacheTuple, except it returns a copy of the tuple
* that the user is required to pfree().
*/
HeapTuple
SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
HeapTuple cachetup;
cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
if (PointerIsValid(cachetup))
return heap_copytuple(cachetup);
else
return cachetup; /* NULL */
}
/*
* SearchSysCacheTuple
*
* A layer on top of SearchSysCache 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.
*
* 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)
{
HeapTuple tp;
if (cacheId < 0 || cacheId >= SysCacheSize)
{
elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
1998-09-01 05:29:17 +02:00
return (HeapTuple) NULL;
}
Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
if (!PointerIsValid(SysCache[cacheId]))
{
SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
1999-05-25 18:15:34 +02:00
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);
}
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,
cacheId, key1, key2, key3, key4);
#endif
1998-09-01 05:29:17 +02:00
return (HeapTuple) NULL;
}
1998-09-01 05:29:17 +02:00
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(ERROR, "SearchSysCacheStruct: No receiving struct");
1998-09-01 05:29:17 +02:00
return 0;
}
tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
if (!HeapTupleIsValid(tp))
1998-09-01 05:29:17 +02:00
return 0;
memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
1998-09-01 05:29:17 +02:00
return 1;
}
/*
* 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.
*
* XXX This re-opens the relation, so this is slower than just pulling
* fixed-location fields out of the struct returned by SearchSysCacheTuple.
*
* [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;
Datum 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) */
1998-09-01 05:29:17 +02:00
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(ERROR,
"SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
attributeNumber, cacheName, cacheId);
1998-09-01 05:29:17 +02:00
return NULL;
}
attributeValue = heap_getattr(tp,
attributeNumber,
1998-09-01 05:29:17 +02:00
RelationGetDescr(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
*/
1998-09-01 05:29:17 +02:00
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);
memcpy(tmp, (void *) attributeValue, size);
returnValue = (void *) tmp;
}
heap_close(relation);
1998-09-01 05:29:17 +02:00
return returnValue;
}
/*
* TypeDefaultRetrieve
*
* Given a type OID, return the typdefault field associated with that
* type. The result is a Datum, and points to palloc'd storage for
* non-pass-by-value types.
*
* [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)
{
struct varlena *typDefault;
int32 dataSize;
HeapTuple typeTuple;
1998-09-01 05:29:17 +02:00
Form_pg_type type;
int32 typByVal,
typLen;
void *returnValue;
/*
* First, see if there is a non-null typdefault field (usually there isn't)
*/
typDefault = (struct varlena *)
SearchSysCacheGetAttribute(TYPOID,
Anum_pg_type_typdefault,
ObjectIdGetDatum(typId),
0, 0, 0);
if (typDefault == NULL)
{
#ifdef CACHEDEBUG
elog(DEBUG, "TypeDefaultRetrieve: No extractable typdefault in %s(%d)",
cacheinfo[TYPOID].name, TYPOID);
#endif /* defined(CACHEDEBUG) */
1998-09-01 05:29:17 +02:00
return NULL;
}
dataSize = VARSIZE(typDefault) - VARHDRSZ;
/*
* Need the type's length and byVal fields.
*
* XXX silly to repeat the syscache search that SearchSysCacheGetAttribute
* just did --- but at present this path isn't taken often enough to
* make it worth fixing.
*/
typeTuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(typId),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
{
/* should never get here, really... */
#ifdef CACHEDEBUG
elog(DEBUG, "TypeDefaultRetrieve: Lookup in %s(%d) failed",
cacheinfo[TYPOID].name, TYPOID);
#endif /* defined(CACHEDEBUG) */
1998-09-01 05:29:17 +02:00
return NULL;
}
type = (Form_pg_type) GETSTRUCT(typeTuple);
typLen = type->typlen;
typByVal = type->typbyval;
if (typByVal)
{
int8 i8;
int16 i16;
int32 i32 = 0;
if (dataSize == typLen)
{
switch (typLen)
{
case sizeof(int8):
memcpy((char *) &i8, VARDATA(typDefault), sizeof(int8));
i32 = i8;
break;
case sizeof(int16):
memcpy((char *) &i16, VARDATA(typDefault), sizeof(int16));
i32 = i16;
break;
case sizeof(int32):
memcpy((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));
memcpy((char *) returnValue,
(char *) typDefault,
(int) VARSIZE(typDefault));
}
}
1998-09-01 05:29:17 +02:00
return returnValue;
}