1 /*-------------------------------------------------------------------------
4 * System cache management routines
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.57 2000/11/16 22:30:33 tgl Exp $
14 * These routines allow the parser/planner/executor to perform
15 * rapid lookups on the contents of the system catalogs.
17 * see catalog/syscache.h for a list of the cache id's
19 *-------------------------------------------------------------------------
23 #include "access/heapam.h"
24 #include "access/transam.h"
25 #include "utils/builtins.h"
26 #include "catalog/catname.h"
27 #include "catalog/indexing.h"
28 #include "catalog/pg_aggregate.h"
29 #include "catalog/pg_amop.h"
30 #include "catalog/pg_group.h"
31 #include "catalog/pg_index.h"
32 #include "catalog/pg_inherits.h"
33 #include "catalog/pg_language.h"
34 #include "catalog/pg_listener.h"
35 #include "catalog/pg_opclass.h"
36 #include "catalog/pg_operator.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_rewrite.h"
39 #include "catalog/pg_shadow.h"
40 #include "catalog/pg_statistic.h"
41 #include "catalog/pg_type.h"
42 #include "utils/catcache.h"
43 #include "utils/syscache.h"
44 #include "utils/temprel.h"
45 #include "miscadmin.h"
48 /*---------------------------------------------------------------------------
52 Add your new cache to the list in include/utils/syscache.h. Keep
53 the list sorted alphabetically and adjust the cache numbers
56 Add your entry to the cacheinfo[] array below. All cache lists are
57 alphabetical, so add it in the proper place. Specify the relation
58 name, index name, number of keys, and key attribute numbers.
60 In include/catalog/indexing.h, add a define for the number of indexes
61 on the relation, add define(s) for the index name(s), add an extern
62 array to hold the index names, and use DECLARE_UNIQUE_INDEX to define
63 the index. Cache lookups return only one row, so the index should be
66 In backend/catalog/indexing.c, initialize the relation array with
67 the index names for the relation.
69 Finally, any place your relation gets heap_insert() or
70 heap_update calls, include code to do a CatalogIndexInsert() to update
71 the system indexes. The heap_* calls do not update indexes.
75 ---------------------------------------------------------------------------
79 * struct cachedesc: information defining a single syscache
84 char *name; /* name of the relation being cached */
85 char *indname; /* name of index relation for this cache */
86 int nkeys; /* # of keys needed for cache lookup */
87 int key[4]; /* attribute numbers of key attrs */
90 static struct cachedesc cacheinfo[] = {
91 {AggregateRelationName, /* AGGNAME */
92 AggregateNameTypeIndex,
95 Anum_pg_aggregate_aggname,
96 Anum_pg_aggregate_aggbasetype,
100 {AccessMethodRelationName, /* AMNAME */
109 {AccessMethodOperatorRelationName, /* AMOPOPID */
110 AccessMethodOpidIndex,
113 Anum_pg_amop_amopclaid,
114 Anum_pg_amop_amopopr,
118 {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
119 AccessMethodStrategyIndex,
123 Anum_pg_amop_amopclaid,
124 Anum_pg_amop_amopstrategy,
127 {AttributeRelationName, /* ATTNAME */
128 AttributeRelidNameIndex,
131 Anum_pg_attribute_attrelid,
132 Anum_pg_attribute_attname,
136 {AttributeRelationName, /* ATTNUM */
137 AttributeRelidNumIndex,
140 Anum_pg_attribute_attrelid,
141 Anum_pg_attribute_attnum,
145 {OperatorClassRelationName, /* CLADEFTYPE */
149 Anum_pg_opclass_opcdeftype,
154 {OperatorClassRelationName, /* CLANAME */
158 Anum_pg_opclass_opcname,
163 {GroupRelationName, /* GRONAME */
167 Anum_pg_group_groname,
172 {GroupRelationName, /* GROSYSID */
176 Anum_pg_group_grosysid,
181 {IndexRelationName, /* INDEXRELID */
185 Anum_pg_index_indexrelid,
190 {InheritsRelationName, /* INHRELID */
191 InheritsRelidSeqnoIndex,
194 Anum_pg_inherits_inhrelid,
195 Anum_pg_inherits_inhseqno,
199 {LanguageRelationName, /* LANGNAME */
203 Anum_pg_language_lanname,
208 {LanguageRelationName, /* LANGOID */
212 ObjectIdAttributeNumber,
217 {ListenerRelationName, /* LISTENREL */
218 ListenerPidRelnameIndex,
221 Anum_pg_listener_pid,
222 Anum_pg_listener_relname,
226 {OperatorRelationName, /* OPERNAME */
230 Anum_pg_operator_oprname,
231 Anum_pg_operator_oprleft,
232 Anum_pg_operator_oprright,
233 Anum_pg_operator_oprkind
235 {OperatorRelationName, /* OPEROID */
239 ObjectIdAttributeNumber,
244 {ProcedureRelationName, /* PROCNAME */
248 Anum_pg_proc_proname,
249 Anum_pg_proc_pronargs,
250 Anum_pg_proc_proargtypes,
253 {ProcedureRelationName, /* PROCOID */
257 ObjectIdAttributeNumber,
262 {RelationRelationName, /* RELNAME */
266 Anum_pg_class_relname,
271 {RelationRelationName, /* RELOID */
275 ObjectIdAttributeNumber,
280 {RewriteRelationName, /* REWRITENAME */
281 RewriteRulenameIndex,
284 Anum_pg_rewrite_rulename,
289 {RewriteRelationName, /* RULEOID */
293 ObjectIdAttributeNumber,
298 {ShadowRelationName, /* SHADOWNAME */
302 Anum_pg_shadow_usename,
307 {ShadowRelationName, /* SHADOWSYSID */
311 Anum_pg_shadow_usesysid,
316 {StatisticRelationName, /* STATRELID */
317 StatisticRelidAttnumIndex,
320 Anum_pg_statistic_starelid,
321 Anum_pg_statistic_staattnum,
325 {TypeRelationName, /* TYPENAME */
329 Anum_pg_type_typname,
334 {TypeRelationName, /* TYPEOID */
338 ObjectIdAttributeNumber,
345 static CatCache *SysCache[lengthof(cacheinfo)];
346 static int SysCacheSize = lengthof(cacheinfo);
347 static bool CacheInitialized = false;
351 IsCacheInitialized(void)
353 return CacheInitialized;
358 * InitCatalogCache - initialize the caches
360 * Note that no database access is done here; we only allocate memory
361 * and initialize the cache structure. Interrogation of the database
362 * to complete initialization of a cache happens only upon first use
366 InitCatalogCache(void)
370 Assert(!CacheInitialized);
372 MemSet((char *) SysCache, 0, sizeof(SysCache));
374 for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
376 SysCache[cacheId] = InitCatCache(cacheId,
377 cacheinfo[cacheId].name,
378 cacheinfo[cacheId].indname,
379 cacheinfo[cacheId].nkeys,
380 cacheinfo[cacheId].key);
381 if (!PointerIsValid(SysCache[cacheId]))
382 elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)",
383 cacheinfo[cacheId].name, cacheId);
385 CacheInitialized = true;
392 * A layer on top of SearchCatCache that does the initialization and
393 * key-setting for you.
395 * Returns the cache copy of the tuple if one is found, NULL if not.
396 * The tuple is the 'cache' copy and must NOT be modified!
398 * When the caller is done using the tuple, call ReleaseSysCache()
399 * to release the reference count grabbed by SearchSysCache(). If this
400 * is not done, the tuple will remain locked in cache until end of
401 * transaction, which is tolerable but not desirable.
403 * CAUTION: The tuple that is returned must NOT be freed by the caller!
406 SearchSysCache(int cacheId,
412 if (cacheId < 0 || cacheId >= SysCacheSize)
414 elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
415 return (HeapTuple) NULL;
418 Assert(PointerIsValid(SysCache[cacheId]));
421 * If someone tries to look up a relname, translate temp relation
422 * names to real names. Less obviously, apply the same translation
423 * to type names, so that the type tuple of a temp table will be found
424 * when sought. This is a kluge ... temp table substitution should be
425 * happening at a higher level ...
427 if (cacheId == RELNAME || cacheId == TYPENAME)
429 char *nontemp_relname;
431 nontemp_relname = get_temp_rel_by_username(DatumGetCString(key1));
432 if (nontemp_relname != NULL)
433 key1 = CStringGetDatum(nontemp_relname);
436 return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
441 * Release previously grabbed reference count on a tuple
444 ReleaseSysCache(HeapTuple tuple)
446 ReleaseCatCache(tuple);
452 * A convenience routine that does SearchSysCache and (if successful)
453 * returns a modifiable copy of the syscache entry. The original
454 * syscache entry is released before returning. The caller should
455 * heap_freetuple() the result when done with it.
458 SearchSysCacheCopy(int cacheId,
467 tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
468 if (!HeapTupleIsValid(tuple))
470 newtuple = heap_copytuple(tuple);
471 ReleaseSysCache(tuple);
478 * A convenience routine that does SearchSysCache and returns the OID
479 * of the found tuple, or InvalidOid if no tuple could be found.
480 * No lock is retained on the syscache entry.
483 GetSysCacheOid(int cacheId,
492 tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
493 if (!HeapTupleIsValid(tuple))
495 result = tuple->t_data->t_oid;
496 ReleaseSysCache(tuple);
503 * Given a tuple previously fetched by SearchSysCache(),
504 * extract a specific attribute.
506 * This is equivalent to using heap_getattr() on a tuple fetched
507 * from a non-cached relation. Usually, this is only used for attributes
508 * that could be NULL or variable length; the fixed-size attributes in
509 * a system table are accessed just by mapping the tuple onto the C struct
510 * declarations from include/catalog/.
512 * As with heap_getattr(), if the attribute is of a pass-by-reference type
513 * then a pointer into the tuple data area is returned --- the caller must
514 * not modify or pfree the datum!
517 SysCacheGetAttr(int cacheId, HeapTuple tup,
518 AttrNumber attributeNumber,
523 * We just need to get the TupleDesc out of the cache entry, and then
524 * we can apply heap_getattr(). We expect that the cache control data
525 * is currently valid --- if the caller recently fetched the tuple, then
528 if (cacheId < 0 || cacheId >= SysCacheSize)
529 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
530 if (!PointerIsValid(SysCache[cacheId]) ||
531 !PointerIsValid(SysCache[cacheId]->cc_tupdesc))
532 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
534 return heap_getattr(tup, attributeNumber,
535 SysCache[cacheId]->cc_tupdesc,