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

545 lines
12 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* syscache.c
* System cache management routines
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.56 2000/11/10 00:33:10 tgl 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 "access/transam.h"
#include "utils/builtins.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
1999-07-16 07:23:30 +02:00
#include "catalog/pg_aggregate.h"
#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"
1999-07-16 07:23:30 +02:00
#include "catalog/pg_listener.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shadow.h"
1999-11-24 18:09:28 +01:00
#include "catalog/pg_statistic.h"
1999-07-16 07:23:30 +02:00
#include "catalog/pg_type.h"
#include "utils/catcache.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
2000-02-18 10:30:20 +01:00
#include "miscadmin.h"
/*---------------------------------------------------------------------------
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, index name, number of keys, and key attribute numbers.
In include/catalog/indexing.h, add a define for the number of indexes
on the relation, add define(s) for the index name(s), add an extern
array to hold the index names, and use DECLARE_UNIQUE_INDEX to define
the index. Cache lookups return only one row, so the index should be
unique in most cases.
In backend/catalog/indexing.c, initialize the relation array with
the index names for the relation.
Finally, any place your relation gets heap_insert() or
1999-11-24 01:58:48 +01:00
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
---------------------------------------------------------------------------
*/
/* ----------------
* struct cachedesc: information defining a single syscache
* ----------------
*/
struct cachedesc
{
char *name; /* name of the relation being cached */
char *indname; /* name of index relation for this cache */
int nkeys; /* # of keys needed for cache lookup */
int key[4]; /* attribute numbers of key attrs */
};
static struct cachedesc cacheinfo[] = {
{AggregateRelationName, /* AGGNAME */
AggregateNameTypeIndex,
2,
{
Anum_pg_aggregate_aggname,
Anum_pg_aggregate_aggbasetype,
0,
0
}},
{AccessMethodRelationName, /* AMNAME */
AmNameIndex,
1,
{
Anum_pg_am_amname,
0,
0,
0
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOpidIndex,
3,
{
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopopr,
Anum_pg_amop_amopid,
0
}},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
AccessMethodStrategyIndex,
3,
{
Anum_pg_amop_amopid,
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopstrategy,
0
}},
{AttributeRelationName, /* ATTNAME */
AttributeRelidNameIndex,
2,
{
Anum_pg_attribute_attrelid,
Anum_pg_attribute_attname,
0,
0
}},
{AttributeRelationName, /* ATTNUM */
AttributeRelidNumIndex,
2,
{
Anum_pg_attribute_attrelid,
Anum_pg_attribute_attnum,
0,
0
}},
{OperatorClassRelationName, /* CLADEFTYPE */
OpclassDeftypeIndex,
1,
{
Anum_pg_opclass_opcdeftype,
0,
0,
0
}},
{OperatorClassRelationName, /* CLANAME */
OpclassNameIndex,
1,
{
Anum_pg_opclass_opcname,
0,
0,
0
}},
{GroupRelationName, /* GRONAME */
GroupNameIndex,
1,
{
Anum_pg_group_groname,
0,
0,
0
}},
{GroupRelationName, /* GROSYSID */
GroupSysidIndex,
1,
{
Anum_pg_group_grosysid,
0,
0,
0
}},
{IndexRelationName, /* INDEXRELID */
IndexRelidIndex,
1,
{
Anum_pg_index_indexrelid,
0,
0,
0
}},
{InheritsRelationName, /* INHRELID */
InheritsRelidSeqnoIndex,
2,
{
Anum_pg_inherits_inhrelid,
Anum_pg_inherits_inhseqno,
0,
0
}},
{LanguageRelationName, /* LANGNAME */
LanguageNameIndex,
1,
{
Anum_pg_language_lanname,
0,
0,
0
}},
{LanguageRelationName, /* LANGOID */
LanguageOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{ListenerRelationName, /* LISTENREL */
ListenerPidRelnameIndex,
2,
{
Anum_pg_listener_pid,
Anum_pg_listener_relname,
0,
0
}},
{OperatorRelationName, /* OPERNAME */
OperatorNameIndex,
4,
{
Anum_pg_operator_oprname,
Anum_pg_operator_oprleft,
Anum_pg_operator_oprright,
Anum_pg_operator_oprkind
}},
{OperatorRelationName, /* OPEROID */
OperatorOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{ProcedureRelationName, /* PROCNAME */
ProcedureNameIndex,
3,
{
Anum_pg_proc_proname,
Anum_pg_proc_pronargs,
Anum_pg_proc_proargtypes,
0
}},
{ProcedureRelationName, /* PROCOID */
ProcedureOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{RelationRelationName, /* RELNAME */
ClassNameIndex,
1,
{
Anum_pg_class_relname,
0,
0,
0
}},
{RelationRelationName, /* RELOID */
ClassOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{RewriteRelationName, /* REWRITENAME */
RewriteRulenameIndex,
1,
{
Anum_pg_rewrite_rulename,
0,
0,
0
}},
{RewriteRelationName, /* RULEOID */
RewriteOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{ShadowRelationName, /* SHADOWNAME */
ShadowNameIndex,
1,
{
Anum_pg_shadow_usename,
0,
0,
0
}},
{ShadowRelationName, /* SHADOWSYSID */
ShadowSysidIndex,
1,
{
Anum_pg_shadow_usesysid,
0,
0,
0
}},
{StatisticRelationName, /* STATRELID */
StatisticRelidAttnumIndex,
2,
{
Anum_pg_statistic_starelid,
Anum_pg_statistic_staattnum,
0,
0
}},
{TypeRelationName, /* TYPENAME */
TypeNameIndex,
1,
{
Anum_pg_type_typname,
0,
0,
0
}},
{TypeRelationName, /* TYPEOID */
TypeOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}}
};
static CatCache *SysCache[lengthof(cacheinfo)];
static int32 SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
bool
IsCacheInitialized(void)
2000-02-18 10:30:20 +01:00
{
return CacheInitialized;
}
/*
* zerocaches
*
* Make sure the SysCache structure is zero'd.
*/
void
zerocaches()
{
MemSet((char *) SysCache, 0, SysCacheSize * sizeof(CatCache *));
}
/*
* InitCatalogCache - initialize the caches
*/
void
InitCatalogCache()
{
int cacheId; /* XXX type */
if (!AMI_OVERRIDE)
{
for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
{
Assert(!PointerIsValid(SysCache[cacheId]));
SysCache[cacheId] = InitSysCache(cacheId,
cacheinfo[cacheId].name,
1999-05-25 18:15:34 +02:00
cacheinfo[cacheId].indname,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
{
elog(ERROR,
"InitCatalogCache: Can't init cache %s (%d)",
cacheinfo[cacheId].name,
cacheId);
}
}
}
2000-02-18 10:30:20 +01:00
CacheInitialized = true;
}
/*
* 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.
*
* CAUTION: The tuple that is returned must NOT be freed by the caller!
*
* CAUTION: The returned tuple may be flushed from the cache during
* subsequent cache lookup operations, or by shared cache invalidation.
* Callers should not expect the pointer to remain valid for long.
*
* XXX we ought to have some kind of referencecount mechanism for
* cache entries, to ensure entries aren't deleted while in use.
*/
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(cacheId,
cacheinfo[cacheId].name,
1999-05-25 18:15:34 +02:00
cacheinfo[cacheId].indname,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
elog(ERROR,
"InitCatalogCache: Can't init cache %s(%d)",
cacheinfo[cacheId].name,
cacheId);
}
/*
* If someone tries to look up a relname, translate temp relation
* names to real names. Less obviously, apply the same translation
* to type names, so that the type tuple of a temp table will be found
* when sought. This is a kluge ... temp table substitution should be
* happening at a higher level ...
*/
if (cacheId == RELNAME || cacheId == TYPENAME)
{
char *nontemp_relname;
nontemp_relname = get_temp_rel_by_username(DatumGetCString(key1));
if (nontemp_relname != NULL)
key1 = CStringGetDatum(nontemp_relname);
}
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;
}
/*
* SearchSysCacheTupleCopy
*
* This is like SearchSysCacheTuple, except it returns a palloc'd copy of
* the tuple. The caller should heap_freetuple() the returned copy when
* done with it. This routine should be used when the caller intends to
* continue to access the tuple for more than a very short period of time.
*/
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 */
}
/*
* SysCacheGetAttr
*
* Given a tuple previously fetched by SearchSysCacheTuple() or
* SearchSysCacheTupleCopy(), 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!
*/
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(). We expect that the cache control data
* is currently valid --- if the caller recently fetched the tuple, then
* it should be.
*/
if (cacheId < 0 || cacheId >= SysCacheSize)
elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
if (!PointerIsValid(SysCache[cacheId]) ||
!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
return heap_getattr(tup, attributeNumber,
SysCache[cacheId]->cc_tupdesc,
isNull);
}