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.50 2000/04/12 17:15:54 momjian 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 "utils/builtins.h"
24 #include "access/heapam.h"
25 #include "catalog/catname.h"
26 #include "catalog/pg_aggregate.h"
27 #include "catalog/pg_amop.h"
28 #include "catalog/pg_group.h"
29 #include "catalog/pg_index.h"
30 #include "catalog/pg_inherits.h"
31 #include "catalog/pg_language.h"
32 #include "catalog/pg_listener.h"
33 #include "catalog/pg_opclass.h"
34 #include "catalog/pg_operator.h"
35 #include "catalog/pg_proc.h"
36 #include "catalog/pg_rewrite.h"
37 #include "catalog/pg_shadow.h"
38 #include "catalog/pg_statistic.h"
39 #include "catalog/pg_type.h"
40 #include "utils/catcache.h"
41 #include "utils/temprel.h"
42 #include "miscadmin.h"
44 extern bool AMI_OVERRIDE; /* XXX style */
46 #include "utils/syscache.h"
47 #include "catalog/indexing.h"
49 typedef HeapTuple (*ScanFunc) ();
52 /*---------------------------------------------------------------------------
56 Add your new cache to the list in include/utils/syscache.h. Keep
57 the list sorted alphabetically and adjust the cache numbers
60 Add your entry to the cacheinfo[] array below. All cache lists are
61 alphabetical, so add it in the proper place. Specify the relation
62 name, number of arguments, argument names, size of tuple, index lookup
63 function, and index name.
65 In include/catalog/indexing.h, add a define for the number of indexes
66 in the relation, add a define for the index name, add an extern
67 array to hold the index names, define the index lookup function
68 prototype, and use DECLARE_UNIQUE_INDEX to define the index. Cache
69 lookups return only one row, so the index should be unique.
71 In backend/catalog/indexing.c, initialize the relation array with
72 the index names for the relation, fixed size of relation (or marking
73 first non-fixed length field), and create the index lookup function.
74 Pick one that takes similar arguments and use that one, but keep the
75 function names in the same order as the cache list for clarity.
77 Finally, any place your relation gets heap_insert() or
78 heap_update calls, include code to do a CatalogIndexInsert() to update
79 the system indexes. The heap_* calls do not update indexes.
83 ---------------------------------------------------------------------------
86 static struct cachedesc cacheinfo[] = {
87 {AggregateRelationName, /* AGGNAME */
90 Anum_pg_aggregate_aggname,
91 Anum_pg_aggregate_aggbasetype,
95 offsetof(FormData_pg_aggregate, agginitval1),
96 AggregateNameTypeIndex,
97 AggregateNameTypeIndexScan},
98 {AccessMethodRelationName, /* AMNAME */
106 sizeof(FormData_pg_am),
109 {AccessMethodOperatorRelationName, /* AMOPOPID */
112 Anum_pg_amop_amopclaid,
113 Anum_pg_amop_amopopr,
117 sizeof(FormData_pg_amop),
118 AccessMethodOpidIndex,
119 AccessMethodOpidIndexScan},
120 {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
124 Anum_pg_amop_amopclaid,
125 Anum_pg_amop_amopstrategy,
128 sizeof(FormData_pg_amop),
129 AccessMethodStrategyIndex,
130 (ScanFunc) AccessMethodStrategyIndexScan},
131 {AttributeRelationName, /* ATTNAME */
134 Anum_pg_attribute_attrelid,
135 Anum_pg_attribute_attname,
139 ATTRIBUTE_TUPLE_SIZE,
140 AttributeRelidNameIndex,
141 AttributeRelidNameIndexScan},
142 {AttributeRelationName, /* ATTNUM */
145 Anum_pg_attribute_attrelid,
146 Anum_pg_attribute_attnum,
150 ATTRIBUTE_TUPLE_SIZE,
151 AttributeRelidNumIndex,
152 (ScanFunc) AttributeRelidNumIndexScan},
153 {OperatorClassRelationName, /* CLADEFTYPE */
156 Anum_pg_opclass_opcdeftype,
161 sizeof(FormData_pg_opclass),
163 OpclassDeftypeIndexScan},
164 {OperatorClassRelationName, /* CLANAME */
167 Anum_pg_opclass_opcname,
172 sizeof(FormData_pg_opclass),
174 OpclassNameIndexScan},
175 {GroupRelationName, /* GRONAME */
178 Anum_pg_group_groname,
183 offsetof(FormData_pg_group, grolist[0]),
186 {GroupRelationName, /* GROSYSID */
189 Anum_pg_group_grosysid,
194 offsetof(FormData_pg_group, grolist[0]),
196 GroupSysidIndexScan},
197 {IndexRelationName, /* INDEXRELID */
200 Anum_pg_index_indexrelid,
205 offsetof(FormData_pg_index, indpred),
207 IndexRelidIndexScan},
208 {InheritsRelationName, /* INHRELID */
211 Anum_pg_inherits_inhrelid,
212 Anum_pg_inherits_inhseqno,
216 sizeof(FormData_pg_inherits),
217 InheritsRelidSeqnoIndex,
218 InheritsRelidSeqnoIndexScan},
219 {LanguageRelationName, /* LANGNAME */
222 Anum_pg_language_lanname,
227 offsetof(FormData_pg_language, lancompiler),
229 LanguageNameIndexScan},
230 {LanguageRelationName, /* LANGOID */
233 ObjectIdAttributeNumber,
238 offsetof(FormData_pg_language, lancompiler),
240 LanguageOidIndexScan},
241 {ListenerRelationName, /* LISTENREL */
244 Anum_pg_listener_relname,
245 Anum_pg_listener_pid,
249 sizeof(FormData_pg_listener),
250 ListenerRelnamePidIndex,
251 ListenerRelnamePidIndexScan},
252 {OperatorRelationName, /* OPERNAME */
255 Anum_pg_operator_oprname,
256 Anum_pg_operator_oprleft,
257 Anum_pg_operator_oprright,
258 Anum_pg_operator_oprkind
260 sizeof(FormData_pg_operator),
262 (ScanFunc) OperatorNameIndexScan},
263 {OperatorRelationName, /* OPEROID */
266 ObjectIdAttributeNumber,
271 sizeof(FormData_pg_operator),
273 OperatorOidIndexScan},
274 {ProcedureRelationName, /* PROCNAME */
277 Anum_pg_proc_proname,
278 Anum_pg_proc_pronargs,
279 Anum_pg_proc_proargtypes,
282 offsetof(FormData_pg_proc, prosrc),
284 (ScanFunc) ProcedureNameIndexScan},
285 {ProcedureRelationName, /* PROCOID */
288 ObjectIdAttributeNumber,
293 offsetof(FormData_pg_proc, prosrc),
295 ProcedureOidIndexScan},
296 {RelationRelationName, /* RELNAME */
299 Anum_pg_class_relname,
307 {RelationRelationName, /* RELOID */
310 ObjectIdAttributeNumber,
318 {RewriteRelationName, /* REWRITENAME */
321 Anum_pg_rewrite_rulename,
326 offsetof(FormData_pg_rewrite, ev_qual),
327 RewriteRulenameIndex,
328 RewriteRulenameIndexScan},
329 {RewriteRelationName, /* RULEOID */
332 ObjectIdAttributeNumber,
337 offsetof(FormData_pg_rewrite, ev_qual),
339 RewriteOidIndexScan},
340 {ShadowRelationName, /* SHADOWNAME */
343 Anum_pg_shadow_usename,
348 sizeof(FormData_pg_shadow),
350 ShadowNameIndexScan},
351 {ShadowRelationName, /* SHADOWSYSID */
354 Anum_pg_shadow_usesysid,
359 sizeof(FormData_pg_shadow),
361 ShadowSysidIndexScan},
362 {StatisticRelationName, /* STATRELID */
365 Anum_pg_statistic_starelid,
366 Anum_pg_statistic_staattnum,
370 offsetof(FormData_pg_statistic, stacommonval),
371 StatisticRelidAttnumIndex,
372 (ScanFunc) StatisticRelidAttnumIndexScan},
373 {TypeRelationName, /* TYPENAME */
376 Anum_pg_type_typname,
381 offsetof(FormData_pg_type, typalign) +sizeof(char),
384 {TypeRelationName, /* TYPEOID */
387 ObjectIdAttributeNumber,
392 offsetof(FormData_pg_type, typalign) +sizeof(char),
397 static struct catcache *SysCache[
398 lengthof(cacheinfo)];
399 static int32 SysCacheSize = lengthof(cacheinfo);
400 static bool CacheInitialized = false;
402 IsCacheInitialized(void)
404 return CacheInitialized;
411 * Make sure the SysCache structure is zero'd.
416 MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
421 * This function was written because the initialized catalog caches
422 * are used to determine which caches may contain tuples which need
423 * to be invalidated in other backends.
428 int cacheId; /* XXX type */
432 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
435 Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
437 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
438 cacheinfo[cacheId].indname,
440 cacheinfo[cacheId].nkeys,
441 cacheinfo[cacheId].key,
442 cacheinfo[cacheId].iScanFunc);
443 if (!PointerIsValid((char *) SysCache[cacheId]))
446 "InitCatalogCache: Can't init cache %s(%d)",
447 cacheinfo[cacheId].name,
453 CacheInitialized = true;
457 * SearchSysCacheTupleCopy
459 * This is like SearchSysCacheTuple, except it returns a copy of the tuple
460 * that the user is required to pfree().
463 SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
471 cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
472 if (PointerIsValid(cachetup))
473 return heap_copytuple(cachetup);
475 return cachetup; /* NULL */
480 * SearchSysCacheTuple
482 * A layer on top of SearchSysCache that does the initialization and
483 * key-setting for you.
485 * Returns the cache copy of the tuple if one is found, NULL if not.
486 * The tuple is the 'cache' copy.
488 * XXX The tuple that is returned is NOT supposed to be pfree'd!
491 SearchSysCacheTuple(int cacheId,/* cache selection code */
499 if (cacheId < 0 || cacheId >= SysCacheSize)
501 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
502 return (HeapTuple) NULL;
505 Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
507 if (!PointerIsValid(SysCache[cacheId]))
509 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
510 cacheinfo[cacheId].indname,
512 cacheinfo[cacheId].nkeys,
513 cacheinfo[cacheId].key,
514 cacheinfo[cacheId].iScanFunc);
515 if (!PointerIsValid(SysCache[cacheId]))
517 "InitCatalogCache: Can't init cache %s(%d)",
518 cacheinfo[cacheId].name,
522 /* temp table name remapping */
523 if (cacheId == RELNAME)
525 char *nontemp_relname;
527 if ((nontemp_relname =
528 get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
529 key1 = PointerGetDatum(nontemp_relname);
532 tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
533 if (!HeapTupleIsValid(tp))
537 "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
538 cacheinfo[cacheId].name,
539 cacheId, key1, key2, key3, key4);
541 return (HeapTuple) NULL;
550 * Given a tuple previously fetched by SearchSysCacheTuple() or
551 * SearchSysCacheTupleCopy(), extract a specific attribute.
553 * This is equivalent to using heap_getattr() on a tuple fetched
554 * from a non-cached relation. Usually, this is only used for attributes
555 * that could be NULL or variable length; the fixed-size attributes in
556 * a system table are accessed just by mapping the tuple onto the C struct
557 * declarations from include/catalog/.
559 * As with heap_getattr(), if the attribute is of a pass-by-reference type
560 * then a pointer into the tuple data area is returned --- the caller must
561 * not modify or pfree the datum!
564 SysCacheGetAttr(int cacheId, HeapTuple tup,
565 AttrNumber attributeNumber,
570 * We just need to get the TupleDesc out of the cache entry, and then
571 * we can apply heap_getattr(). We expect that the cache control data
572 * is currently valid --- if the caller just fetched the tuple, then
575 if (cacheId < 0 || cacheId >= SysCacheSize)
576 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
577 if (!PointerIsValid(SysCache[cacheId]) ||
578 SysCache[cacheId]->relationId == InvalidOid ||
579 !PointerIsValid(SysCache[cacheId]->cc_tupdesc))
580 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
582 return heap_getattr(tup, attributeNumber,
583 SysCache[cacheId]->cc_tupdesc,