]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Change SearchSysCache coding conventions so that a reference count is
[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.57 2000/11/16 22:30:33 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 "access/heapam.h"
24 #include "access/transam.h"
25 #include "utils/builtins.h"
26 #include "catalog/catname.h"
27 #include "catalog/indexing.h"
28 #include "catalog/pg_aggregate.h"
29 #include "catalog/pg_amop.h"
30 #include "catalog/pg_group.h"
31 #include "catalog/pg_index.h"
32 #include "catalog/pg_inherits.h"
33 #include "catalog/pg_language.h"
34 #include "catalog/pg_listener.h"
35 #include "catalog/pg_opclass.h"
36 #include "catalog/pg_operator.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_rewrite.h"
39 #include "catalog/pg_shadow.h"
40 #include "catalog/pg_statistic.h"
41 #include "catalog/pg_type.h"
42 #include "utils/catcache.h"
43 #include "utils/syscache.h"
44 #include "utils/temprel.h"
45 #include "miscadmin.h"
46
47
48 /*---------------------------------------------------------------------------
49
50         Adding system caches:
51
52         Add your new cache to the list in include/utils/syscache.h.  Keep
53         the list sorted alphabetically and adjust the cache numbers
54         accordingly.
55
56         Add your entry to the cacheinfo[] array below.  All cache lists are
57         alphabetical, so add it in the proper place.  Specify the relation
58         name, index name, number of keys, and key attribute numbers.
59
60         In include/catalog/indexing.h, add a define for the number of indexes
61         on the relation, add define(s) for the index name(s), add an extern
62         array to hold the index names, and use DECLARE_UNIQUE_INDEX to define
63         the index.  Cache lookups return only one row, so the index should be
64         unique in most cases.
65
66         In backend/catalog/indexing.c, initialize the relation array with
67         the index names for the relation.
68
69         Finally, any place your relation gets heap_insert() or
70         heap_update calls, include code to do a CatalogIndexInsert() to update
71         the system indexes.  The heap_* calls do not update indexes.
72
73         bjm 1999/11/22
74
75   ---------------------------------------------------------------------------
76 */
77
78 /* ----------------
79  *              struct cachedesc: information defining a single syscache
80  * ----------------
81  */
82 struct cachedesc
83 {
84         char       *name;                       /* name of the relation being cached */
85         char       *indname;            /* name of index relation for this cache */
86         int                     nkeys;                  /* # of keys needed for cache lookup */
87         int                     key[4];                 /* attribute numbers of key attrs */
88 };
89
90 static struct cachedesc cacheinfo[] = {
91         {AggregateRelationName,         /* AGGNAME */
92          AggregateNameTypeIndex,
93                 2,
94                 {
95                         Anum_pg_aggregate_aggname,
96                         Anum_pg_aggregate_aggbasetype,
97                         0,
98                         0
99                 }},
100         {AccessMethodRelationName,      /* AMNAME */
101          AmNameIndex,
102                 1,
103                 {
104                         Anum_pg_am_amname,
105                         0,
106                         0,
107                         0
108                 }},
109         {AccessMethodOperatorRelationName,      /* AMOPOPID */
110          AccessMethodOpidIndex,
111                 3,
112                 {
113                         Anum_pg_amop_amopclaid,
114                         Anum_pg_amop_amopopr,
115                         Anum_pg_amop_amopid,
116                         0
117                 }},
118         {AccessMethodOperatorRelationName,      /* AMOPSTRATEGY */
119          AccessMethodStrategyIndex,
120                 3,
121                 {
122                         Anum_pg_amop_amopid,
123                         Anum_pg_amop_amopclaid,
124                         Anum_pg_amop_amopstrategy,
125                         0
126                 }},
127         {AttributeRelationName,         /* ATTNAME */
128          AttributeRelidNameIndex,
129                 2,
130                 {
131                         Anum_pg_attribute_attrelid,
132                         Anum_pg_attribute_attname,
133                         0,
134                         0
135                 }},
136         {AttributeRelationName,         /* ATTNUM */
137          AttributeRelidNumIndex,
138                 2,
139                 {
140                         Anum_pg_attribute_attrelid,
141                         Anum_pg_attribute_attnum,
142                         0,
143                         0
144                 }},
145         {OperatorClassRelationName, /* CLADEFTYPE */
146          OpclassDeftypeIndex,
147                 1,
148                 {
149                         Anum_pg_opclass_opcdeftype,
150                         0,
151                         0,
152                         0
153                 }},
154         {OperatorClassRelationName, /* CLANAME */
155          OpclassNameIndex,
156                 1,
157                 {
158                         Anum_pg_opclass_opcname,
159                         0,
160                         0,
161                         0
162                 }},
163         {GroupRelationName,                     /* GRONAME */
164          GroupNameIndex,
165                 1,
166                 {
167                         Anum_pg_group_groname,
168                         0,
169                         0,
170                         0
171                 }},
172         {GroupRelationName,                     /* GROSYSID */
173          GroupSysidIndex,
174                 1,
175                 {
176                         Anum_pg_group_grosysid,
177                         0,
178                         0,
179                         0
180                 }},
181         {IndexRelationName,                     /* INDEXRELID */
182          IndexRelidIndex,
183                 1,
184                 {
185                         Anum_pg_index_indexrelid,
186                         0,
187                         0,
188                         0
189                 }},
190         {InheritsRelationName,          /* INHRELID */
191          InheritsRelidSeqnoIndex,
192                 2,
193                 {
194                         Anum_pg_inherits_inhrelid,
195                         Anum_pg_inherits_inhseqno,
196                         0,
197                         0
198                 }},
199         {LanguageRelationName,          /* LANGNAME */
200          LanguageNameIndex,
201                 1,
202                 {
203                         Anum_pg_language_lanname,
204                         0,
205                         0,
206                         0
207                 }},
208         {LanguageRelationName,          /* LANGOID */
209          LanguageOidIndex,
210                 1,
211                 {
212                         ObjectIdAttributeNumber,
213                         0,
214                         0,
215                         0
216                 }},
217         {ListenerRelationName,          /* LISTENREL */
218          ListenerPidRelnameIndex,
219                 2,
220                 {
221                         Anum_pg_listener_pid,
222                         Anum_pg_listener_relname,
223                         0,
224                         0
225                 }},
226         {OperatorRelationName,          /* OPERNAME */
227          OperatorNameIndex,
228                 4,
229                 {
230                         Anum_pg_operator_oprname,
231                         Anum_pg_operator_oprleft,
232                         Anum_pg_operator_oprright,
233                         Anum_pg_operator_oprkind
234                 }},
235         {OperatorRelationName,          /* OPEROID */
236          OperatorOidIndex,
237                 1,
238                 {
239                         ObjectIdAttributeNumber,
240                         0,
241                         0,
242                         0
243                 }},
244         {ProcedureRelationName,         /* PROCNAME */
245          ProcedureNameIndex,
246                 3,
247                 {
248                         Anum_pg_proc_proname,
249                         Anum_pg_proc_pronargs,
250                         Anum_pg_proc_proargtypes,
251                         0
252                 }},
253         {ProcedureRelationName,         /* PROCOID */
254          ProcedureOidIndex,
255                 1,
256                 {
257                         ObjectIdAttributeNumber,
258                         0,
259                         0,
260                         0
261                 }},
262         {RelationRelationName,          /* RELNAME */
263          ClassNameIndex,
264                 1,
265                 {
266                         Anum_pg_class_relname,
267                         0,
268                         0,
269                         0
270                 }},
271         {RelationRelationName,          /* RELOID */
272          ClassOidIndex,
273                 1,
274                 {
275                         ObjectIdAttributeNumber,
276                         0,
277                         0,
278                         0
279                 }},
280         {RewriteRelationName,           /* REWRITENAME */
281          RewriteRulenameIndex,
282                 1,
283                 {
284                         Anum_pg_rewrite_rulename,
285                         0,
286                         0,
287                         0
288                 }},
289         {RewriteRelationName,           /* RULEOID */
290          RewriteOidIndex,
291                 1,
292                 {
293                         ObjectIdAttributeNumber,
294                         0,
295                         0,
296                         0
297                 }},
298         {ShadowRelationName,            /* SHADOWNAME */
299          ShadowNameIndex,
300                 1,
301                 {
302                         Anum_pg_shadow_usename,
303                         0,
304                         0,
305                         0
306                 }},
307         {ShadowRelationName,            /* SHADOWSYSID */
308          ShadowSysidIndex,
309                 1,
310                 {
311                         Anum_pg_shadow_usesysid,
312                         0,
313                         0,
314                         0
315                 }},
316         {StatisticRelationName,         /* STATRELID */
317          StatisticRelidAttnumIndex,
318                 2,
319                 {
320                         Anum_pg_statistic_starelid,
321                         Anum_pg_statistic_staattnum,
322                         0,
323                         0
324                 }},
325         {TypeRelationName,                      /* TYPENAME */
326          TypeNameIndex,
327                 1,
328                 {
329                         Anum_pg_type_typname,
330                         0,
331                         0,
332                         0
333                 }},
334         {TypeRelationName,                      /* TYPEOID */
335          TypeOidIndex,
336                 1,
337                 {
338                         ObjectIdAttributeNumber,
339                         0,
340                         0,
341                         0
342                 }}
343 };
344
345 static CatCache *SysCache[lengthof(cacheinfo)];
346 static int SysCacheSize = lengthof(cacheinfo);
347 static bool CacheInitialized = false;
348
349
350 bool
351 IsCacheInitialized(void)
352 {
353         return CacheInitialized;
354 }
355
356
357 /*
358  * InitCatalogCache - initialize the caches
359  *
360  * Note that no database access is done here; we only allocate memory
361  * and initialize the cache structure.  Interrogation of the database
362  * to complete initialization of a cache happens only upon first use
363  * of that cache.
364  */
365 void
366 InitCatalogCache(void)
367 {
368         int                     cacheId;
369
370         Assert(!CacheInitialized);
371
372         MemSet((char *) SysCache, 0, sizeof(SysCache));
373
374         for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
375         {
376                 SysCache[cacheId] = InitCatCache(cacheId,
377                                                                                  cacheinfo[cacheId].name,
378                                                                                  cacheinfo[cacheId].indname,
379                                                                                  cacheinfo[cacheId].nkeys,
380                                                                                  cacheinfo[cacheId].key);
381                 if (!PointerIsValid(SysCache[cacheId]))
382                         elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)",
383                                  cacheinfo[cacheId].name, cacheId);
384         }
385         CacheInitialized = true;
386 }
387
388
389 /*
390  * SearchSysCache
391  *
392  *      A layer on top of SearchCatCache that does the initialization and
393  *      key-setting for you.
394  *
395  *      Returns the cache copy of the tuple if one is found, NULL if not.
396  *      The tuple is the 'cache' copy and must NOT be modified!
397  *
398  *      When the caller is done using the tuple, call ReleaseSysCache()
399  *      to release the reference count grabbed by SearchSysCache().  If this
400  *      is not done, the tuple will remain locked in cache until end of
401  *      transaction, which is tolerable but not desirable.
402  *
403  *      CAUTION: The tuple that is returned must NOT be freed by the caller!
404  */
405 HeapTuple
406 SearchSysCache(int cacheId,
407                            Datum key1,
408                            Datum key2,
409                            Datum key3,
410                            Datum key4)
411 {
412         if (cacheId < 0 || cacheId >= SysCacheSize)
413         {
414                 elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
415                 return (HeapTuple) NULL;
416         }
417
418         Assert(PointerIsValid(SysCache[cacheId]));
419
420         /*
421          * If someone tries to look up a relname, translate temp relation
422          * names to real names.  Less obviously, apply the same translation
423          * to type names, so that the type tuple of a temp table will be found
424          * when sought.  This is a kluge ... temp table substitution should be
425          * happening at a higher level ...
426          */
427         if (cacheId == RELNAME || cacheId == TYPENAME)
428         {
429                 char       *nontemp_relname;
430
431                 nontemp_relname = get_temp_rel_by_username(DatumGetCString(key1));
432                 if (nontemp_relname != NULL)
433                         key1 = CStringGetDatum(nontemp_relname);
434         }
435
436         return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
437 }
438
439 /*
440  * ReleaseSysCache
441  *              Release previously grabbed reference count on a tuple
442  */
443 void
444 ReleaseSysCache(HeapTuple tuple)
445 {
446         ReleaseCatCache(tuple);
447 }
448
449 /*
450  * SearchSysCacheCopy
451  *
452  * A convenience routine that does SearchSysCache and (if successful)
453  * returns a modifiable copy of the syscache entry.  The original
454  * syscache entry is released before returning.  The caller should
455  * heap_freetuple() the result when done with it.
456  */
457 HeapTuple
458 SearchSysCacheCopy(int cacheId,
459                                    Datum key1,
460                                    Datum key2,
461                                    Datum key3,
462                                    Datum key4)
463 {
464         HeapTuple       tuple,
465                                 newtuple;
466
467         tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
468         if (!HeapTupleIsValid(tuple))
469                 return tuple;
470         newtuple = heap_copytuple(tuple);
471         ReleaseSysCache(tuple);
472         return newtuple;
473 }
474
475 /*
476  * GetSysCacheOid
477  *
478  * A convenience routine that does SearchSysCache and returns the OID
479  * of the found tuple, or InvalidOid if no tuple could be found.
480  * No lock is retained on the syscache entry.
481  */
482 Oid
483 GetSysCacheOid(int cacheId,
484                            Datum key1,
485                            Datum key2,
486                            Datum key3,
487                            Datum key4)
488 {
489         HeapTuple       tuple;
490         Oid                     result;
491
492         tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
493         if (!HeapTupleIsValid(tuple))
494                 return InvalidOid;
495         result = tuple->t_data->t_oid;
496         ReleaseSysCache(tuple);
497         return result;
498 }
499
500 /*
501  * SysCacheGetAttr
502  *
503  *              Given a tuple previously fetched by SearchSysCache(),
504  *              extract a specific attribute.
505  *
506  * This is equivalent to using heap_getattr() on a tuple fetched
507  * from a non-cached relation.  Usually, this is only used for attributes
508  * that could be NULL or variable length; the fixed-size attributes in
509  * a system table are accessed just by mapping the tuple onto the C struct
510  * declarations from include/catalog/.
511  *
512  * As with heap_getattr(), if the attribute is of a pass-by-reference type
513  * then a pointer into the tuple data area is returned --- the caller must
514  * not modify or pfree the datum!
515  */
516 Datum
517 SysCacheGetAttr(int cacheId, HeapTuple tup,
518                                 AttrNumber attributeNumber,
519                                 bool *isNull)
520 {
521
522         /*
523          * We just need to get the TupleDesc out of the cache entry, and then
524          * we can apply heap_getattr().  We expect that the cache control data
525          * is currently valid --- if the caller recently fetched the tuple, then
526          * it should be.
527          */
528         if (cacheId < 0 || cacheId >= SysCacheSize)
529                 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
530         if (!PointerIsValid(SysCache[cacheId]) ||
531                 !PointerIsValid(SysCache[cacheId]->cc_tupdesc))
532                 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
533
534         return heap_getattr(tup, attributeNumber,
535                                                 SysCache[cacheId]->cc_tupdesc,
536                                                 isNull);
537 }