1 /*-------------------------------------------------------------------------
4 * System cache management routines
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.42 1999/11/24 00:58:48 momjian Exp $
13 * These routines allow the parser/planner/executor to perform
14 * rapid lookups on the contents of the system catalogs.
16 * see catalog/syscache.h for a list of the cache id's
18 *-------------------------------------------------------------------------
22 #include "utils/builtins.h"
23 #include "access/heapam.h"
24 #include "catalog/catname.h"
25 #include "catalog/pg_aggregate.h"
26 #include "catalog/pg_amop.h"
27 #include "catalog/pg_group.h"
28 #include "catalog/pg_index.h"
29 #include "catalog/pg_inherits.h"
30 #include "catalog/pg_language.h"
31 #include "catalog/pg_listener.h"
32 #include "catalog/pg_opclass.h"
33 #include "catalog/pg_operator.h"
34 #include "catalog/pg_proc.h"
35 #include "catalog/pg_rewrite.h"
36 #include "catalog/pg_shadow.h"
37 #include "catalog/pg_type.h"
38 #include "utils/catcache.h"
39 #include "utils/temprel.h"
41 extern bool AMI_OVERRIDE; /* XXX style */
43 #include "utils/syscache.h"
44 #include "catalog/indexing.h"
46 typedef HeapTuple (*ScanFunc) ();
49 /*---------------------------------------------------------------------------
53 Add your new cache to the list in include/utils/syscache.h. Keep
54 the list sorted alphabetically and adjust the cache numbers
57 Add your entry to the cacheinfo[] array below. All cache lists are
58 alphabetical, so add it in the proper place. Specify the relation
59 name, number of arguments, argument names, size of tuple, index lookup
60 function, and index name.
62 In include/catalog/indexing.h, add a define for the number of indexes
63 in the relation, add a define for the index name, add an extern
64 array to hold the index names, define the index lookup function
65 prototype, and use DECLARE_UNIQUE_INDEX to define the index. Cache
66 lookups return only one row, so the index should be unique.
68 In backend/catalog/indexing.c, initialize the relation array with
69 the index names for the relation, and create the index lookup function.
70 Pick one that takes similar arguments and use that one, but keep the
71 function names in the same order as the cache list for clarity.
73 Finally, any place your relation gets heap_insert() or
74 heap_update calls, include code to do a CatalogIndexInsert() to update
75 the system indexes. The heap_* calls do not update indexes.
79 ---------------------------------------------------------------------------
82 static struct cachedesc cacheinfo[] = {
83 {AggregateRelationName, /* AGGNAME */
86 Anum_pg_aggregate_aggname,
87 Anum_pg_aggregate_aggbasetype,
91 offsetof(FormData_pg_aggregate, agginitval1),
92 AggregateNameTypeIndex,
93 AggregateNameTypeIndexScan},
94 {AccessMethodRelationName, /* AMNAME */
102 sizeof(FormData_pg_am),
105 {AccessMethodOperatorRelationName, /* AMOPOPID */
108 Anum_pg_amop_amopclaid,
109 Anum_pg_amop_amopopr,
113 sizeof(FormData_pg_amop),
114 AccessMethodOpidIndex,
115 AccessMethodOpidIndexScan},
116 {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
120 Anum_pg_amop_amopclaid,
121 Anum_pg_amop_amopstrategy,
124 sizeof(FormData_pg_amop),
125 AccessMethodStrategyIndex,
126 (ScanFunc) AccessMethodStrategyIndexScan},
127 {AttributeRelationName, /* ATTNAME */
130 Anum_pg_attribute_attrelid,
131 Anum_pg_attribute_attname,
135 ATTRIBUTE_TUPLE_SIZE,
136 AttributeRelidNameIndex,
137 AttributeRelidNameIndexScan},
138 {AttributeRelationName, /* ATTNUM */
141 Anum_pg_attribute_attrelid,
142 Anum_pg_attribute_attnum,
146 ATTRIBUTE_TUPLE_SIZE,
147 AttributeRelidNumIndex,
148 (ScanFunc) AttributeRelidNumIndexScan},
149 {OperatorClassRelationName, /* CLADEFTYPE */
152 Anum_pg_opclass_opcdeftype,
157 sizeof(FormData_pg_opclass),
159 OpclassDeftypeIndexScan},
160 {OperatorClassRelationName, /* CLANAME */
163 Anum_pg_opclass_opcname,
168 sizeof(FormData_pg_opclass),
170 OpclassNameIndexScan},
171 {GroupRelationName, /* GRONAME */
174 Anum_pg_group_groname,
179 offsetof(FormData_pg_group, grolist[0]),
182 {GroupRelationName, /* GROSYSID */
185 Anum_pg_group_grosysid,
190 offsetof(FormData_pg_group, grolist[0]),
192 GroupSysidIndexScan},
193 {IndexRelationName, /* INDEXRELID */
196 Anum_pg_index_indexrelid,
201 offsetof(FormData_pg_index, indpred),
203 IndexRelidIndexScan},
204 {InheritsRelationName, /* INHRELID */
207 Anum_pg_inherits_inhrelid,
208 Anum_pg_inherits_inhseqno,
212 sizeof(FormData_pg_inherits),
213 InheritsRelidSeqnoIndex,
214 InheritsRelidSeqnoIndexScan},
215 {LanguageRelationName, /* LANGNAME */
218 Anum_pg_language_lanname,
223 offsetof(FormData_pg_language, lancompiler),
225 LanguageNameIndexScan},
226 {LanguageRelationName, /* LANGOID */
229 ObjectIdAttributeNumber,
234 offsetof(FormData_pg_language, lancompiler),
236 LanguageOidIndexScan},
237 {ListenerRelationName, /* LISTENREL */
240 Anum_pg_listener_relname,
241 Anum_pg_listener_pid,
245 sizeof(FormData_pg_listener),
246 ListenerRelnamePidIndex,
247 ListenerRelnamePidIndexScan},
248 {OperatorRelationName, /* OPERNAME */
251 Anum_pg_operator_oprname,
252 Anum_pg_operator_oprleft,
253 Anum_pg_operator_oprright,
254 Anum_pg_operator_oprkind
256 sizeof(FormData_pg_operator),
258 (ScanFunc) OperatorNameIndexScan},
259 {OperatorRelationName, /* OPEROID */
262 ObjectIdAttributeNumber,
267 sizeof(FormData_pg_operator),
269 OperatorOidIndexScan},
270 {ProcedureRelationName, /* PROCNAME */
273 Anum_pg_proc_proname,
274 Anum_pg_proc_pronargs,
275 Anum_pg_proc_proargtypes,
278 offsetof(FormData_pg_proc, prosrc),
280 (ScanFunc) ProcedureNameIndexScan},
281 {ProcedureRelationName, /* PROCOID */
284 ObjectIdAttributeNumber,
289 offsetof(FormData_pg_proc, prosrc),
291 ProcedureOidIndexScan},
292 {RelationRelationName, /* RELNAME */
295 Anum_pg_class_relname,
303 {RelationRelationName, /* RELOID */
306 ObjectIdAttributeNumber,
314 {RewriteRelationName, /* REWRITENAME */
317 Anum_pg_rewrite_rulename,
322 offsetof(FormData_pg_rewrite, ev_qual),
323 RewriteRulenameIndex,
324 RewriteRulenameIndexScan},
325 {RewriteRelationName, /* RULEOID */
328 ObjectIdAttributeNumber,
333 offsetof(FormData_pg_rewrite, ev_qual),
335 RewriteOidIndexScan},
336 {TypeRelationName, /* TYPENAME */
339 Anum_pg_type_typname,
344 offsetof(FormData_pg_type, typalign) +sizeof(char),
347 {TypeRelationName, /* TYPEOID */
350 ObjectIdAttributeNumber,
355 offsetof(FormData_pg_type, typalign) +sizeof(char),
358 {ShadowRelationName, /* USERNAME */
361 Anum_pg_shadow_usename,
366 sizeof(FormData_pg_shadow),
369 ShadowNameIndexScan*/},
370 {ShadowRelationName, /* USERSYSID */
373 Anum_pg_shadow_usesysid,
378 sizeof(FormData_pg_shadow),
381 ShadowSysidIndexScan*/}
384 static struct catcache *SysCache[lengthof(cacheinfo)];
385 static int32 SysCacheSize = lengthof(cacheinfo);
391 * Make sure the SysCache structure is zero'd.
396 MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
401 * This function was written because the initialized catalog caches
402 * are used to determine which caches may contain tuples which need
403 * to be invalidated in other backends.
408 int cacheId; /* XXX type */
412 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
415 Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
417 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
418 cacheinfo[cacheId].indname,
420 cacheinfo[cacheId].nkeys,
421 cacheinfo[cacheId].key,
422 cacheinfo[cacheId].iScanFunc);
423 if (!PointerIsValid((char *) SysCache[cacheId]))
426 "InitCatalogCache: Can't init cache %s(%d)",
427 cacheinfo[cacheId].name,
436 * SearchSysCacheTupleCopy
438 * This is like SearchSysCacheTuple, except it returns a copy of the tuple
439 * that the user is required to pfree().
442 SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
450 cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
451 if (PointerIsValid(cachetup))
452 return heap_copytuple(cachetup);
454 return cachetup; /* NULL */
459 * SearchSysCacheTuple
461 * A layer on top of SearchSysCache that does the initialization and
462 * key-setting for you.
464 * Returns the cache copy of the tuple if one is found, NULL if not.
465 * The tuple is the 'cache' copy.
467 * XXX The tuple that is returned is NOT supposed to be pfree'd!
470 SearchSysCacheTuple(int cacheId,/* cache selection code */
478 if (cacheId < 0 || cacheId >= SysCacheSize)
480 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
481 return (HeapTuple) NULL;
484 Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
486 if (!PointerIsValid(SysCache[cacheId]))
488 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
489 cacheinfo[cacheId].indname,
491 cacheinfo[cacheId].nkeys,
492 cacheinfo[cacheId].key,
493 cacheinfo[cacheId].iScanFunc);
494 if (!PointerIsValid(SysCache[cacheId]))
496 "InitCatalogCache: Can't init cache %s(%d)",
497 cacheinfo[cacheId].name,
501 /* temp table name remapping */
502 if (cacheId == RELNAME)
504 char *nontemp_relname;
506 if ((nontemp_relname =
507 get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
508 key1 = PointerGetDatum(nontemp_relname);
511 tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
512 if (!HeapTupleIsValid(tp))
516 "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
517 cacheinfo[cacheId].name,
518 cacheId, key1, key2, key3, key4);
520 return (HeapTuple) NULL;
526 * SearchSysCacheStruct
527 * Fills 's' with the information retrieved by calling SearchSysCache()
528 * with arguments key1...key4. Retrieves only the portion of the tuple
529 * which is not variable-length.
531 * NOTE: we are assuming that non-variable-length fields in the system
532 * catalogs will always be defined!
534 * Returns 1L if a tuple was found, 0L if not.
537 SearchSysCacheStruct(int cacheId, /* cache selection code */
538 char *returnStruct, /* (preallocated!) */
546 if (!PointerIsValid(returnStruct))
548 elog(ERROR, "SearchSysCacheStruct: No receiving struct");
551 tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
552 if (!HeapTupleIsValid(tp))
554 memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
560 * SearchSysCacheGetAttribute
561 * Returns the attribute corresponding to 'attributeNumber' for
562 * a given cached tuple. This routine usually needs to be used for
563 * attributes that might be NULL or might be at a variable offset
566 * XXX This re-opens the relation, so this is slower than just pulling
567 * fixed-location fields out of the struct returned by SearchSysCacheTuple.
569 * [callers all assume this returns a (struct varlena *). -ay 10/94]
572 SearchSysCacheGetAttribute(int cacheId,
573 AttrNumber attributeNumber,
582 int32 attributeLength,
585 Datum attributeValue;
589 * Open the relation first, to ensure we are in sync with SI inval
590 * events --- we don't want the tuple found in the cache to be
591 * invalidated out from under us.
593 cacheName = cacheinfo[cacheId].name;
594 relation = heap_openr(cacheName, AccessShareLock);
596 tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
598 if (!HeapTupleIsValid(tp))
600 heap_close(relation, AccessShareLock);
603 "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
605 #endif /* defined(CACHEDEBUG) */
609 if (attributeNumber < 0 &&
610 attributeNumber > FirstLowInvalidHeapAttributeNumber)
612 attributeLength = heap_sysattrlen(attributeNumber);
613 attributeByValue = heap_sysattrbyval(attributeNumber);
615 else if (attributeNumber > 0 &&
616 attributeNumber <= relation->rd_rel->relnatts)
618 attributeLength = relation->rd_att->attrs[attributeNumber - 1]->attlen;
619 attributeByValue = relation->rd_att->attrs[attributeNumber - 1]->attbyval;
623 heap_close(relation, AccessShareLock);
625 "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
626 attributeNumber, cacheName, cacheId);
630 attributeValue = heap_getattr(tp,
632 RelationGetDescr(relation),
638 * Used to be an elog(DEBUG, ...) here and a claim that it should
639 * be a FATAL error, I don't think either is warranted -mer 6/9/92
641 heap_close(relation, AccessShareLock);
645 if (attributeByValue)
646 returnValue = (void *) attributeValue;
650 int size = (attributeLength < 0)
651 ? VARSIZE((struct varlena *) attributeValue) /* variable length */
652 : attributeLength; /* fixed length */
654 tmp = (char *) palloc(size);
655 memcpy(tmp, (void *) attributeValue, size);
656 returnValue = (void *) tmp;
659 heap_close(relation, AccessShareLock);