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.39 1999/11/16 04:13:59 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 "access/heapam.h"
23 #include "catalog/catname.h"
24 #include "catalog/pg_aggregate.h"
25 #include "catalog/pg_amop.h"
26 #include "catalog/pg_group.h"
27 #include "catalog/pg_index.h"
28 #include "catalog/pg_inherits.h"
29 #include "catalog/pg_language.h"
30 #include "catalog/pg_listener.h"
31 #include "catalog/pg_opclass.h"
32 #include "catalog/pg_operator.h"
33 #include "catalog/pg_proc.h"
34 #include "catalog/pg_rewrite.h"
35 #include "catalog/pg_shadow.h"
36 #include "catalog/pg_type.h"
37 #include "utils/catcache.h"
38 #include "utils/temprel.h"
40 extern bool AMI_OVERRIDE; /* XXX style */
42 #include "utils/syscache.h"
43 #include "catalog/indexing.h"
45 typedef HeapTuple (*ScanFunc) ();
48 * Warning: cacheinfo[] below is changed, then be sure and
49 * update the magic constants in syscache.h!
52 static struct cachedesc cacheinfo[] = {
53 {AccessMethodOperatorRelationName, /* AMOPOPID */
56 Anum_pg_amop_amopclaid,
61 sizeof(FormData_pg_amop),
62 AccessMethodOpidIndex,
63 (ScanFunc) AccessMethodOpidIndexScan},
64 {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
68 Anum_pg_amop_amopclaid,
69 Anum_pg_amop_amopstrategy,
72 sizeof(FormData_pg_amop),
73 AccessMethodStrategyIndex,
74 (ScanFunc) AccessMethodStrategyIndexScan},
75 {AttributeRelationName, /* ATTNAME */
78 Anum_pg_attribute_attrelid,
79 Anum_pg_attribute_attname,
85 (ScanFunc) AttributeNameIndexScan},
86 {AttributeRelationName, /* ATTNUM */
89 Anum_pg_attribute_attrelid,
90 Anum_pg_attribute_attnum,
96 (ScanFunc) AttributeNumIndexScan},
97 {IndexRelationName, /* INDEXRELID */
100 Anum_pg_index_indexrelid,
105 offsetof(FormData_pg_index, indpred),
107 (ScanFunc) IndexRelidIndexScan},
108 {LanguageRelationName, /* LANNAME */
111 Anum_pg_language_lanname,
116 offsetof(FormData_pg_language, lancompiler),
119 {OperatorRelationName, /* OPRNAME */
122 Anum_pg_operator_oprname,
123 Anum_pg_operator_oprleft,
124 Anum_pg_operator_oprright,
125 Anum_pg_operator_oprkind
127 sizeof(FormData_pg_operator),
130 {OperatorRelationName, /* OPROID */
133 ObjectIdAttributeNumber,
138 sizeof(FormData_pg_operator),
141 {ProcedureRelationName, /* PRONAME */
144 Anum_pg_proc_proname,
145 Anum_pg_proc_pronargs,
146 Anum_pg_proc_proargtypes,
149 offsetof(FormData_pg_proc, prosrc),
151 (ScanFunc) ProcedureNameIndexScan},
152 {ProcedureRelationName, /* PROOID */
155 ObjectIdAttributeNumber,
160 offsetof(FormData_pg_proc, prosrc),
162 (ScanFunc) ProcedureOidIndexScan},
163 {RelationRelationName, /* RELNAME */
166 Anum_pg_class_relname,
173 (ScanFunc) ClassNameIndexScan},
174 {RelationRelationName, /* RELOID */
177 ObjectIdAttributeNumber,
184 (ScanFunc) ClassOidIndexScan},
185 {TypeRelationName, /* TYPNAME */
188 Anum_pg_type_typname,
193 offsetof(FormData_pg_type, typalign) +sizeof(char),
196 {TypeRelationName, /* TYPOID */
199 ObjectIdAttributeNumber,
204 offsetof(FormData_pg_type, typalign) +sizeof(char),
207 {AccessMethodRelationName, /* AMNAME */
215 sizeof(FormData_pg_am),
218 {OperatorClassRelationName, /* CLANAME */
221 Anum_pg_opclass_opcname,
226 sizeof(FormData_pg_opclass),
229 {InheritsRelationName, /* INHRELID */
232 Anum_pg_inherits_inhrel,
233 Anum_pg_inherits_inhseqno,
237 sizeof(FormData_pg_inherits),
240 {RewriteRelationName, /* RULOID */
243 ObjectIdAttributeNumber,
248 offsetof(FormData_pg_rewrite, ev_qual),
251 {AggregateRelationName, /* AGGNAME */
254 Anum_pg_aggregate_aggname,
255 Anum_pg_aggregate_aggbasetype,
259 offsetof(FormData_pg_aggregate, agginitval1),
262 {ListenerRelationName, /* LISTENREL */
265 Anum_pg_listener_relname,
266 Anum_pg_listener_pid,
270 sizeof(FormData_pg_listener),
273 {ShadowRelationName, /* USENAME */
276 Anum_pg_shadow_usename,
281 sizeof(FormData_pg_shadow),
284 {ShadowRelationName, /* USESYSID */
287 Anum_pg_shadow_usesysid,
292 sizeof(FormData_pg_shadow),
295 {GroupRelationName, /* GRONAME */
298 Anum_pg_group_groname,
303 offsetof(FormData_pg_group, grolist[0]),
306 {GroupRelationName, /* GROSYSID */
309 Anum_pg_group_grosysid,
314 offsetof(FormData_pg_group, grolist[0]),
317 {RewriteRelationName, /* REWRITENAME */
320 Anum_pg_rewrite_rulename,
325 offsetof(FormData_pg_rewrite, ev_qual),
328 {OperatorClassRelationName, /* CLADEFTYPE */
331 Anum_pg_opclass_opcdeftype,
336 sizeof(FormData_pg_opclass),
339 {LanguageRelationName, /* LANOID */
342 ObjectIdAttributeNumber,
347 offsetof(FormData_pg_language, lancompiler),
352 static struct catcache *SysCache[lengthof(cacheinfo)];
353 static int32 SysCacheSize = lengthof(cacheinfo);
359 * Make sure the SysCache structure is zero'd.
364 MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
369 * This function was written because the initialized catalog caches
370 * are used to determine which caches may contain tuples which need
371 * to be invalidated in other backends.
376 int cacheId; /* XXX type */
380 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
383 Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
385 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
386 cacheinfo[cacheId].indname,
388 cacheinfo[cacheId].nkeys,
389 cacheinfo[cacheId].key,
390 cacheinfo[cacheId].iScanFunc);
391 if (!PointerIsValid((char *) SysCache[cacheId]))
394 "InitCatalogCache: Can't init cache %s(%d)",
395 cacheinfo[cacheId].name,
404 * SearchSysCacheTupleCopy
406 * This is like SearchSysCacheTuple, except it returns a copy of the tuple
407 * that the user is required to pfree().
410 SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
418 cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
419 if (PointerIsValid(cachetup))
420 return heap_copytuple(cachetup);
422 return cachetup; /* NULL */
427 * SearchSysCacheTuple
429 * A layer on top of SearchSysCache that does the initialization and
430 * key-setting for you.
432 * Returns the cache copy of the tuple if one is found, NULL if not.
433 * The tuple is the 'cache' copy.
435 * XXX The tuple that is returned is NOT supposed to be pfree'd!
438 SearchSysCacheTuple(int cacheId,/* cache selection code */
446 if (cacheId < 0 || cacheId >= SysCacheSize)
448 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
449 return (HeapTuple) NULL;
452 Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
454 if (!PointerIsValid(SysCache[cacheId]))
456 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
457 cacheinfo[cacheId].indname,
459 cacheinfo[cacheId].nkeys,
460 cacheinfo[cacheId].key,
461 cacheinfo[cacheId].iScanFunc);
462 if (!PointerIsValid(SysCache[cacheId]))
464 "InitCatalogCache: Can't init cache %s(%d)",
465 cacheinfo[cacheId].name,
469 /* temp table name remapping */
470 if (cacheId == RELNAME)
472 char *nontemp_relname;
474 if ((nontemp_relname =
475 get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
476 key1 = PointerGetDatum(nontemp_relname);
479 tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
480 if (!HeapTupleIsValid(tp))
484 "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
485 cacheinfo[cacheId].name,
486 cacheId, key1, key2, key3, key4);
488 return (HeapTuple) NULL;
494 * SearchSysCacheStruct
495 * Fills 's' with the information retrieved by calling SearchSysCache()
496 * with arguments key1...key4. Retrieves only the portion of the tuple
497 * which is not variable-length.
499 * NOTE: we are assuming that non-variable-length fields in the system
500 * catalogs will always be defined!
502 * Returns 1L if a tuple was found, 0L if not.
505 SearchSysCacheStruct(int cacheId, /* cache selection code */
506 char *returnStruct, /* (preallocated!) */
514 if (!PointerIsValid(returnStruct))
516 elog(ERROR, "SearchSysCacheStruct: No receiving struct");
519 tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
520 if (!HeapTupleIsValid(tp))
522 memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
528 * SearchSysCacheGetAttribute
529 * Returns the attribute corresponding to 'attributeNumber' for
530 * a given cached tuple. This routine usually needs to be used for
531 * attributes that might be NULL or might be at a variable offset
534 * XXX This re-opens the relation, so this is slower than just pulling
535 * fixed-location fields out of the struct returned by SearchSysCacheTuple.
537 * [callers all assume this returns a (struct varlena *). -ay 10/94]
540 SearchSysCacheGetAttribute(int cacheId,
541 AttrNumber attributeNumber,
550 int32 attributeLength,
553 Datum attributeValue;
557 * Open the relation first, to ensure we are in sync with SI inval
558 * events --- we don't want the tuple found in the cache to be
559 * invalidated out from under us.
561 cacheName = cacheinfo[cacheId].name;
562 relation = heap_openr(cacheName, AccessShareLock);
564 tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
566 if (!HeapTupleIsValid(tp))
568 heap_close(relation, AccessShareLock);
571 "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
573 #endif /* defined(CACHEDEBUG) */
577 if (attributeNumber < 0 &&
578 attributeNumber > FirstLowInvalidHeapAttributeNumber)
580 attributeLength = heap_sysattrlen(attributeNumber);
581 attributeByValue = heap_sysattrbyval(attributeNumber);
583 else if (attributeNumber > 0 &&
584 attributeNumber <= relation->rd_rel->relnatts)
586 attributeLength = relation->rd_att->attrs[attributeNumber - 1]->attlen;
587 attributeByValue = relation->rd_att->attrs[attributeNumber - 1]->attbyval;
591 heap_close(relation, AccessShareLock);
593 "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
594 attributeNumber, cacheName, cacheId);
598 attributeValue = heap_getattr(tp,
600 RelationGetDescr(relation),
606 * Used to be an elog(DEBUG, ...) here and a claim that it should
607 * be a FATAL error, I don't think either is warranted -mer 6/9/92
609 heap_close(relation, AccessShareLock);
613 if (attributeByValue)
614 returnValue = (void *) attributeValue;
618 int size = (attributeLength < 0)
619 ? VARSIZE((struct varlena *) attributeValue) /* variable length */
620 : attributeLength; /* fixed length */
622 tmp = (char *) palloc(size);
623 memcpy(tmp, (void *) attributeValue, size);
624 returnValue = (void *) tmp;
627 heap_close(relation, AccessShareLock);