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.49 2000/02/18 09:28:56 inoue 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[lengthof(cacheinfo)];
398 static int32 SysCacheSize = lengthof(cacheinfo);
399 static bool CacheInitialized = false;
400 extern bool IsCacheInitialized(void)
402 return CacheInitialized;
409 * Make sure the SysCache structure is zero'd.
414 MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
419 * This function was written because the initialized catalog caches
420 * are used to determine which caches may contain tuples which need
421 * to be invalidated in other backends.
426 int cacheId; /* XXX type */
430 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
433 Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
435 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
436 cacheinfo[cacheId].indname,
438 cacheinfo[cacheId].nkeys,
439 cacheinfo[cacheId].key,
440 cacheinfo[cacheId].iScanFunc);
441 if (!PointerIsValid((char *) SysCache[cacheId]))
444 "InitCatalogCache: Can't init cache %s(%d)",
445 cacheinfo[cacheId].name,
451 CacheInitialized = true;
455 * SearchSysCacheTupleCopy
457 * This is like SearchSysCacheTuple, except it returns a copy of the tuple
458 * that the user is required to pfree().
461 SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
469 cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
470 if (PointerIsValid(cachetup))
471 return heap_copytuple(cachetup);
473 return cachetup; /* NULL */
478 * SearchSysCacheTuple
480 * A layer on top of SearchSysCache that does the initialization and
481 * key-setting for you.
483 * Returns the cache copy of the tuple if one is found, NULL if not.
484 * The tuple is the 'cache' copy.
486 * XXX The tuple that is returned is NOT supposed to be pfree'd!
489 SearchSysCacheTuple(int cacheId,/* cache selection code */
497 if (cacheId < 0 || cacheId >= SysCacheSize)
499 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
500 return (HeapTuple) NULL;
503 Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
505 if (!PointerIsValid(SysCache[cacheId]))
507 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
508 cacheinfo[cacheId].indname,
510 cacheinfo[cacheId].nkeys,
511 cacheinfo[cacheId].key,
512 cacheinfo[cacheId].iScanFunc);
513 if (!PointerIsValid(SysCache[cacheId]))
515 "InitCatalogCache: Can't init cache %s(%d)",
516 cacheinfo[cacheId].name,
520 /* temp table name remapping */
521 if (cacheId == RELNAME)
523 char *nontemp_relname;
525 if ((nontemp_relname =
526 get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
527 key1 = PointerGetDatum(nontemp_relname);
530 tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
531 if (!HeapTupleIsValid(tp))
535 "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
536 cacheinfo[cacheId].name,
537 cacheId, key1, key2, key3, key4);
539 return (HeapTuple) NULL;
548 * Given a tuple previously fetched by SearchSysCacheTuple() or
549 * SearchSysCacheTupleCopy(), extract a specific attribute.
551 * This is equivalent to using heap_getattr() on a tuple fetched
552 * from a non-cached relation. Usually, this is only used for attributes
553 * that could be NULL or variable length; the fixed-size attributes in
554 * a system table are accessed just by mapping the tuple onto the C struct
555 * declarations from include/catalog/.
557 * As with heap_getattr(), if the attribute is of a pass-by-reference type
558 * then a pointer into the tuple data area is returned --- the caller must
559 * not modify or pfree the datum!
562 SysCacheGetAttr(int cacheId, HeapTuple tup,
563 AttrNumber attributeNumber,
567 * We just need to get the TupleDesc out of the cache entry,
568 * and then we can apply heap_getattr(). We expect that the cache
569 * control data is currently valid --- if the caller just fetched
570 * the tuple, then it should be.
572 if (cacheId < 0 || cacheId >= SysCacheSize)
573 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
574 if (! PointerIsValid(SysCache[cacheId]) ||
575 SysCache[cacheId]->relationId == InvalidOid ||
576 ! PointerIsValid(SysCache[cacheId]->cc_tupdesc))
577 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
579 return heap_getattr(tup, attributeNumber,
580 SysCache[cacheId]->cc_tupdesc,