]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Improve comments for SearchSysCacheTuple and SearchSysCacheTupleCopy.
[postgresql] / src / backend / utils / cache / syscache.c
1 /*-------------------------------------------------------------------------
2  *
3  * syscache.c
4  *        System cache management routines
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.51 2000/06/06 17:02:38 tgl Exp $
12  *
13  * NOTES
14  *        These routines allow the parser/planner/executor to perform
15  *        rapid lookups on the contents of the system catalogs.
16  *
17  *        see catalog/syscache.h for a list of the cache id's
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22
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"
43
44 extern bool AMI_OVERRIDE;               /* XXX style */
45
46 #include "utils/syscache.h"
47 #include "catalog/indexing.h"
48
49 typedef HeapTuple (*ScanFunc) ();
50
51
52 /*---------------------------------------------------------------------------
53
54         Adding system caches:
55
56         Add your new cache to the list in include/utils/syscache.h.  Keep
57         the list sorted alphabetically and adjust the cache numbers
58         accordingly.
59
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.
64
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.
70
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.
76
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.
80
81         bjm 1999/11/22
82
83   ---------------------------------------------------------------------------
84 */
85
86 static struct cachedesc cacheinfo[] = {
87         {AggregateRelationName,         /* AGGNAME */
88                 2,
89                 {
90                         Anum_pg_aggregate_aggname,
91                         Anum_pg_aggregate_aggbasetype,
92                         0,
93                         0
94                 },
95                 offsetof(FormData_pg_aggregate, agginitval1),
96                 AggregateNameTypeIndex,
97         AggregateNameTypeIndexScan},
98         {AccessMethodRelationName,      /* AMNAME */
99                 1,
100                 {
101                         Anum_pg_am_amname,
102                         0,
103                         0,
104                         0
105                 },
106                 sizeof(FormData_pg_am),
107                 AmNameIndex,
108         AmNameIndexScan},
109         {AccessMethodOperatorRelationName,      /* AMOPOPID */
110                 3,
111                 {
112                         Anum_pg_amop_amopclaid,
113                         Anum_pg_amop_amopopr,
114                         Anum_pg_amop_amopid,
115                         0
116                 },
117                 sizeof(FormData_pg_amop),
118                 AccessMethodOpidIndex,
119         AccessMethodOpidIndexScan},
120         {AccessMethodOperatorRelationName,      /* AMOPSTRATEGY */
121                 3,
122                 {
123                         Anum_pg_amop_amopid,
124                         Anum_pg_amop_amopclaid,
125                         Anum_pg_amop_amopstrategy,
126                         0
127                 },
128                 sizeof(FormData_pg_amop),
129                 AccessMethodStrategyIndex,
130         (ScanFunc) AccessMethodStrategyIndexScan},
131         {AttributeRelationName,         /* ATTNAME */
132                 2,
133                 {
134                         Anum_pg_attribute_attrelid,
135                         Anum_pg_attribute_attname,
136                         0,
137                         0
138                 },
139                 ATTRIBUTE_TUPLE_SIZE,
140                 AttributeRelidNameIndex,
141         AttributeRelidNameIndexScan},
142         {AttributeRelationName,         /* ATTNUM */
143                 2,
144                 {
145                         Anum_pg_attribute_attrelid,
146                         Anum_pg_attribute_attnum,
147                         0,
148                         0
149                 },
150                 ATTRIBUTE_TUPLE_SIZE,
151                 AttributeRelidNumIndex,
152         (ScanFunc) AttributeRelidNumIndexScan},
153         {OperatorClassRelationName, /* CLADEFTYPE */
154                 1,
155                 {
156                         Anum_pg_opclass_opcdeftype,
157                         0,
158                         0,
159                         0
160                 },
161                 sizeof(FormData_pg_opclass),
162                 OpclassDeftypeIndex,
163         OpclassDeftypeIndexScan},
164         {OperatorClassRelationName, /* CLANAME */
165                 1,
166                 {
167                         Anum_pg_opclass_opcname,
168                         0,
169                         0,
170                         0
171                 },
172                 sizeof(FormData_pg_opclass),
173                 OpclassNameIndex,
174         OpclassNameIndexScan},
175         {GroupRelationName,                     /* GRONAME */
176                 1,
177                 {
178                         Anum_pg_group_groname,
179                         0,
180                         0,
181                         0
182                 },
183                 offsetof(FormData_pg_group, grolist[0]),
184                 GroupNameIndex,
185         GroupNameIndexScan},
186         {GroupRelationName,                     /* GROSYSID */
187                 1,
188                 {
189                         Anum_pg_group_grosysid,
190                         0,
191                         0,
192                         0
193                 },
194                 offsetof(FormData_pg_group, grolist[0]),
195                 GroupSysidIndex,
196         GroupSysidIndexScan},
197         {IndexRelationName,                     /* INDEXRELID */
198                 1,
199                 {
200                         Anum_pg_index_indexrelid,
201                         0,
202                         0,
203                         0
204                 },
205                 offsetof(FormData_pg_index, indpred),
206                 IndexRelidIndex,
207         IndexRelidIndexScan},
208         {InheritsRelationName,          /* INHRELID */
209                 2,
210                 {
211                         Anum_pg_inherits_inhrelid,
212                         Anum_pg_inherits_inhseqno,
213                         0,
214                         0
215                 },
216                 sizeof(FormData_pg_inherits),
217                 InheritsRelidSeqnoIndex,
218         InheritsRelidSeqnoIndexScan},
219         {LanguageRelationName,          /* LANGNAME */
220                 1,
221                 {
222                         Anum_pg_language_lanname,
223                         0,
224                         0,
225                         0
226                 },
227                 offsetof(FormData_pg_language, lancompiler),
228                 LanguageNameIndex,
229         LanguageNameIndexScan},
230         {LanguageRelationName,          /* LANGOID */
231                 1,
232                 {
233                         ObjectIdAttributeNumber,
234                         0,
235                         0,
236                         0
237                 },
238                 offsetof(FormData_pg_language, lancompiler),
239                 LanguageOidIndex,
240         LanguageOidIndexScan},
241         {ListenerRelationName,          /* LISTENREL */
242                 2,
243                 {
244                         Anum_pg_listener_relname,
245                         Anum_pg_listener_pid,
246                         0,
247                         0
248                 },
249                 sizeof(FormData_pg_listener),
250                 ListenerRelnamePidIndex,
251         ListenerRelnamePidIndexScan},
252         {OperatorRelationName,          /* OPERNAME */
253                 4,
254                 {
255                         Anum_pg_operator_oprname,
256                         Anum_pg_operator_oprleft,
257                         Anum_pg_operator_oprright,
258                         Anum_pg_operator_oprkind
259                 },
260                 sizeof(FormData_pg_operator),
261                 OperatorNameIndex,
262         (ScanFunc) OperatorNameIndexScan},
263         {OperatorRelationName,          /* OPEROID */
264                 1,
265                 {
266                         ObjectIdAttributeNumber,
267                         0,
268                         0,
269                         0
270                 },
271                 sizeof(FormData_pg_operator),
272                 OperatorOidIndex,
273         OperatorOidIndexScan},
274         {ProcedureRelationName,         /* PROCNAME */
275                 3,
276                 {
277                         Anum_pg_proc_proname,
278                         Anum_pg_proc_pronargs,
279                         Anum_pg_proc_proargtypes,
280                         0
281                 },
282                 offsetof(FormData_pg_proc, prosrc),
283                 ProcedureNameIndex,
284         (ScanFunc) ProcedureNameIndexScan},
285         {ProcedureRelationName,         /* PROCOID */
286                 1,
287                 {
288                         ObjectIdAttributeNumber,
289                         0,
290                         0,
291                         0
292                 },
293                 offsetof(FormData_pg_proc, prosrc),
294                 ProcedureOidIndex,
295         ProcedureOidIndexScan},
296         {RelationRelationName,          /* RELNAME */
297                 1,
298                 {
299                         Anum_pg_class_relname,
300                         0,
301                         0,
302                         0
303                 },
304                 CLASS_TUPLE_SIZE,
305                 ClassNameIndex,
306         ClassNameIndexScan},
307         {RelationRelationName,          /* RELOID */
308                 1,
309                 {
310                         ObjectIdAttributeNumber,
311                         0,
312                         0,
313                         0
314                 },
315                 CLASS_TUPLE_SIZE,
316                 ClassOidIndex,
317         ClassOidIndexScan},
318         {RewriteRelationName,           /* REWRITENAME */
319                 1,
320                 {
321                         Anum_pg_rewrite_rulename,
322                         0,
323                         0,
324                         0
325                 },
326                 offsetof(FormData_pg_rewrite, ev_qual),
327                 RewriteRulenameIndex,
328         RewriteRulenameIndexScan},
329         {RewriteRelationName,           /* RULEOID */
330                 1,
331                 {
332                         ObjectIdAttributeNumber,
333                         0,
334                         0,
335                         0
336                 },
337                 offsetof(FormData_pg_rewrite, ev_qual),
338                 RewriteOidIndex,
339         RewriteOidIndexScan},
340         {ShadowRelationName,            /* SHADOWNAME */
341                 1,
342                 {
343                         Anum_pg_shadow_usename,
344                         0,
345                         0,
346                         0
347                 },
348                 sizeof(FormData_pg_shadow),
349                 ShadowNameIndex,
350         ShadowNameIndexScan},
351         {ShadowRelationName,            /* SHADOWSYSID */
352                 1,
353                 {
354                         Anum_pg_shadow_usesysid,
355                         0,
356                         0,
357                         0
358                 },
359                 sizeof(FormData_pg_shadow),
360                 ShadowSysidIndex,
361         ShadowSysidIndexScan},
362         {StatisticRelationName,         /* STATRELID */
363                 2,
364                 {
365                         Anum_pg_statistic_starelid,
366                         Anum_pg_statistic_staattnum,
367                         0,
368                         0
369                 },
370                 offsetof(FormData_pg_statistic, stacommonval),
371                 StatisticRelidAttnumIndex,
372         (ScanFunc) StatisticRelidAttnumIndexScan},
373         {TypeRelationName,                      /* TYPENAME */
374                 1,
375                 {
376                         Anum_pg_type_typname,
377                         0,
378                         0,
379                         0
380                 },
381                 offsetof(FormData_pg_type, typalign) +sizeof(char),
382                 TypeNameIndex,
383         TypeNameIndexScan},
384         {TypeRelationName,                      /* TYPEOID */
385                 1,
386                 {
387                         ObjectIdAttributeNumber,
388                         0,
389                         0,
390                         0
391                 },
392                 offsetof(FormData_pg_type, typalign) +sizeof(char),
393                 TypeOidIndex,
394         TypeOidIndexScan}
395 };
396
397 static struct catcache *SysCache[
398                                                                  lengthof(cacheinfo)];
399 static int32 SysCacheSize = lengthof(cacheinfo);
400 static bool CacheInitialized = false;
401 extern bool
402 IsCacheInitialized(void)
403 {
404         return CacheInitialized;
405 }
406
407
408 /*
409  * zerocaches
410  *
411  *        Make sure the SysCache structure is zero'd.
412  */
413 void
414 zerocaches()
415 {
416         MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
417 }
418
419 /*
420  * Note:
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.
424  */
425 void
426 InitCatalogCache()
427 {
428         int                     cacheId;                /* XXX type */
429
430         if (!AMI_OVERRIDE)
431         {
432                 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
433                 {
434
435                         Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
436
437                         SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
438                                                                                          cacheinfo[cacheId].indname,
439                                                                                          cacheId,
440                                                                                          cacheinfo[cacheId].nkeys,
441                                                                                          cacheinfo[cacheId].key,
442                                                                                    cacheinfo[cacheId].iScanFunc);
443                         if (!PointerIsValid((char *) SysCache[cacheId]))
444                         {
445                                 elog(ERROR,
446                                          "InitCatalogCache: Can't init cache %s(%d)",
447                                          cacheinfo[cacheId].name,
448                                          cacheId);
449                         }
450
451                 }
452         }
453         CacheInitialized = true;
454 }
455
456 /*
457  * SearchSysCacheTupleCopy
458  *
459  *      This is like SearchSysCacheTuple, except it returns a palloc'd copy of
460  *      the tuple.  The caller should heap_freetuple() the returned copy when
461  *      done with it.  This routine should be used when the caller intends to
462  *      continue to access the tuple for more than a very short period of time.
463  */
464 HeapTuple
465 SearchSysCacheTupleCopy(int cacheId,    /* cache selection code */
466                                                 Datum key1,
467                                                 Datum key2,
468                                                 Datum key3,
469                                                 Datum key4)
470 {
471         HeapTuple       cachetup;
472
473         cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
474         if (PointerIsValid(cachetup))
475                 return heap_copytuple(cachetup);
476         else
477                 return cachetup;                /* NULL */
478 }
479
480
481 /*
482  * SearchSysCacheTuple
483  *
484  *      A layer on top of SearchSysCache that does the initialization and
485  *      key-setting for you.
486  *
487  *      Returns the cache copy of the tuple if one is found, NULL if not.
488  *      The tuple is the 'cache' copy.
489  *
490  *      CAUTION: The tuple that is returned must NOT be freed by the caller!
491  *
492  *      CAUTION: The returned tuple may be flushed from the cache during
493  *      subsequent cache lookup operations, or by shared cache invalidation.
494  *      Callers should not expect the pointer to remain valid for long.
495  */
496 HeapTuple
497 SearchSysCacheTuple(int cacheId,/* cache selection code */
498                                         Datum key1,
499                                         Datum key2,
500                                         Datum key3,
501                                         Datum key4)
502 {
503         HeapTuple       tp;
504
505         if (cacheId < 0 || cacheId >= SysCacheSize)
506         {
507                 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
508                 return (HeapTuple) NULL;
509         }
510
511         Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
512
513         if (!PointerIsValid(SysCache[cacheId]))
514         {
515                 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
516                                                                                  cacheinfo[cacheId].indname,
517                                                                                  cacheId,
518                                                                                  cacheinfo[cacheId].nkeys,
519                                                                                  cacheinfo[cacheId].key,
520                                                                                  cacheinfo[cacheId].iScanFunc);
521                 if (!PointerIsValid(SysCache[cacheId]))
522                         elog(ERROR,
523                                  "InitCatalogCache: Can't init cache %s(%d)",
524                                  cacheinfo[cacheId].name,
525                                  cacheId);
526         }
527
528         /* temp table name remapping */
529         if (cacheId == RELNAME)
530         {
531                 char       *nontemp_relname;
532
533                 if ((nontemp_relname =
534                          get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
535                         key1 = PointerGetDatum(nontemp_relname);
536         }
537
538         tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
539         if (!HeapTupleIsValid(tp))
540         {
541 #ifdef CACHEDEBUG
542                 elog(DEBUG,
543                          "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
544                          cacheinfo[cacheId].name,
545                          cacheId, key1, key2, key3, key4);
546 #endif
547                 return (HeapTuple) NULL;
548         }
549         return tp;
550 }
551
552
553 /*
554  * SysCacheGetAttr
555  *
556  *              Given a tuple previously fetched by SearchSysCacheTuple() or
557  *              SearchSysCacheTupleCopy(), extract a specific attribute.
558  *
559  * This is equivalent to using heap_getattr() on a tuple fetched
560  * from a non-cached relation.  Usually, this is only used for attributes
561  * that could be NULL or variable length; the fixed-size attributes in
562  * a system table are accessed just by mapping the tuple onto the C struct
563  * declarations from include/catalog/.
564  *
565  * As with heap_getattr(), if the attribute is of a pass-by-reference type
566  * then a pointer into the tuple data area is returned --- the caller must
567  * not modify or pfree the datum!
568  */
569 Datum
570 SysCacheGetAttr(int cacheId, HeapTuple tup,
571                                 AttrNumber attributeNumber,
572                                 bool *isnull)
573 {
574
575         /*
576          * We just need to get the TupleDesc out of the cache entry, and then
577          * we can apply heap_getattr().  We expect that the cache control data
578          * is currently valid --- if the caller just fetched the tuple, then
579          * it should be.
580          */
581         if (cacheId < 0 || cacheId >= SysCacheSize)
582                 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
583         if (!PointerIsValid(SysCache[cacheId]) ||
584                 SysCache[cacheId]->relationId == InvalidOid ||
585                 !PointerIsValid(SysCache[cacheId]->cc_tupdesc))
586                 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
587
588         return heap_getattr(tup, attributeNumber,
589                                                 SysCache[cacheId]->cc_tupdesc,
590                                                 isnull);
591 }