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

539 lines
12 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* syscache.c
* System cache management routines
*
* Portions Copyright (c) 1996-2001, 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.61 2001/05/07 00:43:24 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
2001-03-22 05:01:46 +01:00
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 */
2001-03-22 05:01:46 +01:00
AggregateNameTypeIndex,
2,
{
Anum_pg_aggregate_aggname,
Anum_pg_aggregate_aggbasetype,
0,
0
2001-03-22 05:01:46 +01:00
}},
{AccessMethodRelationName, /* AMNAME */
2001-03-22 05:01:46 +01:00
AmNameIndex,
1,
{
Anum_pg_am_amname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
2001-03-22 05:01:46 +01:00
AccessMethodOpidIndex,
3,
{
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopopr,
Anum_pg_amop_amopid,
0
2001-03-22 05:01:46 +01:00
}},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
2001-03-22 05:01:46 +01:00
AccessMethodStrategyIndex,
3,
{
Anum_pg_amop_amopid,
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopstrategy,
0
2001-03-22 05:01:46 +01:00
}},
{AttributeRelationName, /* ATTNAME */
2001-03-22 05:01:46 +01:00
AttributeRelidNameIndex,
2,
{
Anum_pg_attribute_attrelid,
Anum_pg_attribute_attname,
0,
0
2001-03-22 05:01:46 +01:00
}},
{AttributeRelationName, /* ATTNUM */
2001-03-22 05:01:46 +01:00
AttributeRelidNumIndex,
2,
{
Anum_pg_attribute_attrelid,
Anum_pg_attribute_attnum,
0,
0
2001-03-22 05:01:46 +01:00
}},
{OperatorClassRelationName, /* CLADEFTYPE */
2001-03-22 05:01:46 +01:00
OpclassDeftypeIndex,
1,
{
Anum_pg_opclass_opcdeftype,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{OperatorClassRelationName, /* CLANAME */
2001-03-22 05:01:46 +01:00
OpclassNameIndex,
1,
{
Anum_pg_opclass_opcname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{GroupRelationName, /* GRONAME */
2001-03-22 05:01:46 +01:00
GroupNameIndex,
1,
{
Anum_pg_group_groname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{GroupRelationName, /* GROSYSID */
2001-03-22 05:01:46 +01:00
GroupSysidIndex,
1,
{
Anum_pg_group_grosysid,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{IndexRelationName, /* INDEXRELID */
2001-03-22 05:01:46 +01:00
IndexRelidIndex,
1,
{
Anum_pg_index_indexrelid,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{InheritsRelationName, /* INHRELID */
2001-03-22 05:01:46 +01:00
InheritsRelidSeqnoIndex,
2,
{
Anum_pg_inherits_inhrelid,
Anum_pg_inherits_inhseqno,
0,
0
2001-03-22 05:01:46 +01:00
}},
{LanguageRelationName, /* LANGNAME */
2001-03-22 05:01:46 +01:00
LanguageNameIndex,
1,
{
Anum_pg_language_lanname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{LanguageRelationName, /* LANGOID */
2001-03-22 05:01:46 +01:00
LanguageOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{ListenerRelationName, /* LISTENREL */
2001-03-22 05:01:46 +01:00
ListenerPidRelnameIndex,
2,
{
Anum_pg_listener_pid,
Anum_pg_listener_relname,
0,
0
2001-03-22 05:01:46 +01:00
}},
{OperatorRelationName, /* OPERNAME */
2001-03-22 05:01:46 +01:00
OperatorNameIndex,
4,
{
Anum_pg_operator_oprname,
Anum_pg_operator_oprleft,
Anum_pg_operator_oprright,
Anum_pg_operator_oprkind
2001-03-22 05:01:46 +01:00
}},
{OperatorRelationName, /* OPEROID */
2001-03-22 05:01:46 +01:00
OperatorOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{ProcedureRelationName, /* PROCNAME */
2001-03-22 05:01:46 +01:00
ProcedureNameIndex,
3,
{
Anum_pg_proc_proname,
Anum_pg_proc_pronargs,
Anum_pg_proc_proargtypes,
0
2001-03-22 05:01:46 +01:00
}},
{ProcedureRelationName, /* PROCOID */
2001-03-22 05:01:46 +01:00
ProcedureOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{RelationRelationName, /* RELNAME */
2001-03-22 05:01:46 +01:00
ClassNameIndex,
1,
{
Anum_pg_class_relname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{RelationRelationName, /* RELOID */
2001-03-22 05:01:46 +01:00
ClassOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{RewriteRelationName, /* REWRITENAME */
2001-03-22 05:01:46 +01:00
RewriteRulenameIndex,
1,
{
Anum_pg_rewrite_rulename,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{RewriteRelationName, /* RULEOID */
2001-03-22 05:01:46 +01:00
RewriteOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{ShadowRelationName, /* SHADOWNAME */
2001-03-22 05:01:46 +01:00
ShadowNameIndex,
1,
{
Anum_pg_shadow_usename,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{ShadowRelationName, /* SHADOWSYSID */
2001-03-22 05:01:46 +01:00
ShadowSysidIndex,
1,
{
Anum_pg_shadow_usesysid,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{StatisticRelationName, /* STATRELATT */
2001-03-22 05:01:46 +01:00
StatisticRelidAttnumIndex,
2,
{
Anum_pg_statistic_starelid,
Anum_pg_statistic_staattnum,
0,
0
2001-03-22 05:01:46 +01:00
}},
{TypeRelationName, /* TYPENAME */
2001-03-22 05:01:46 +01:00
TypeNameIndex,
1,
{
Anum_pg_type_typname,
0,
0,
0
2001-03-22 05:01:46 +01:00
}},
{TypeRelationName, /* TYPEOID */
2001-03-22 05:01:46 +01:00
TypeOidIndex,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
2001-03-22 05:01:46 +01:00
}}
};
2001-03-22 05:01:46 +01:00
static CatCache *SysCache[
lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
bool
IsCacheInitialized(void)
2000-02-18 10:30:20 +01:00
{
return CacheInitialized;
}
/*
* InitCatalogCache - initialize the caches
*
* Note that no database access is done here; we only allocate memory
2001-03-22 05:01:46 +01:00
* and initialize the cache structure. Interrogation of the database
* to complete initialization of a cache happens only upon first use
* of that cache.
*/
void
InitCatalogCache(void)
{
int cacheId;
Assert(!CacheInitialized);
MemSet((char *) SysCache, 0, sizeof(SysCache));
for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
{
SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].name,
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;
}
/*
* 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.
*
* CAUTION: The tuple that is returned must NOT be freed by the caller!
*/
HeapTuple
SearchSysCache(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
if (cacheId < 0 || cacheId >= SysCacheSize)
{
elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
1998-09-01 05:29:17 +02:00
return (HeapTuple) NULL;
}
Assert(PointerIsValid(SysCache[cacheId]));
/*
* If someone tries to look up a relname, translate temp relation
2001-03-22 05:01:46 +01:00
* 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);
}
return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
}
/*
* ReleaseSysCache
* Release previously grabbed reference count on a tuple
*/
void
ReleaseSysCache(HeapTuple tuple)
{
ReleaseCatCache(tuple);
}
/*
* SearchSysCacheCopy
*
* 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;
}
/*
* 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 = tuple->t_data->t_oid;
ReleaseSysCache(tuple);
return result;
}
/*
* 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!
*/
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
2001-03-22 05:01:46 +01:00
* 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);
}