]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Ye-old pgindent run. Same 4-space tabs.
[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.50 2000/04/12 17:15:54 momjian 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 copy of the tuple
460  *      that the user is required to pfree().
461  */
462 HeapTuple
463 SearchSysCacheTupleCopy(int cacheId,    /* cache selection code */
464                                                 Datum key1,
465                                                 Datum key2,
466                                                 Datum key3,
467                                                 Datum key4)
468 {
469         HeapTuple       cachetup;
470
471         cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
472         if (PointerIsValid(cachetup))
473                 return heap_copytuple(cachetup);
474         else
475                 return cachetup;                /* NULL */
476 }
477
478
479 /*
480  * SearchSysCacheTuple
481  *
482  *      A layer on top of SearchSysCache that does the initialization and
483  *      key-setting for you.
484  *
485  *      Returns the cache copy of the tuple if one is found, NULL if not.
486  *      The tuple is the 'cache' copy.
487  *
488  *      XXX The tuple that is returned is NOT supposed to be pfree'd!
489  */
490 HeapTuple
491 SearchSysCacheTuple(int cacheId,/* cache selection code */
492                                         Datum key1,
493                                         Datum key2,
494                                         Datum key3,
495                                         Datum key4)
496 {
497         HeapTuple       tp;
498
499         if (cacheId < 0 || cacheId >= SysCacheSize)
500         {
501                 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
502                 return (HeapTuple) NULL;
503         }
504
505         Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
506
507         if (!PointerIsValid(SysCache[cacheId]))
508         {
509                 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
510                                                                                  cacheinfo[cacheId].indname,
511                                                                                  cacheId,
512                                                                                  cacheinfo[cacheId].nkeys,
513                                                                                  cacheinfo[cacheId].key,
514                                                                                  cacheinfo[cacheId].iScanFunc);
515                 if (!PointerIsValid(SysCache[cacheId]))
516                         elog(ERROR,
517                                  "InitCatalogCache: Can't init cache %s(%d)",
518                                  cacheinfo[cacheId].name,
519                                  cacheId);
520         }
521
522         /* temp table name remapping */
523         if (cacheId == RELNAME)
524         {
525                 char       *nontemp_relname;
526
527                 if ((nontemp_relname =
528                          get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
529                         key1 = PointerGetDatum(nontemp_relname);
530         }
531
532         tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
533         if (!HeapTupleIsValid(tp))
534         {
535 #ifdef CACHEDEBUG
536                 elog(DEBUG,
537                          "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
538                          cacheinfo[cacheId].name,
539                          cacheId, key1, key2, key3, key4);
540 #endif
541                 return (HeapTuple) NULL;
542         }
543         return tp;
544 }
545
546
547 /*
548  * SysCacheGetAttr
549  *
550  *              Given a tuple previously fetched by SearchSysCacheTuple() or
551  *              SearchSysCacheTupleCopy(), extract a specific attribute.
552  *
553  * This is equivalent to using heap_getattr() on a tuple fetched
554  * from a non-cached relation.  Usually, this is only used for attributes
555  * that could be NULL or variable length; the fixed-size attributes in
556  * a system table are accessed just by mapping the tuple onto the C struct
557  * declarations from include/catalog/.
558  *
559  * As with heap_getattr(), if the attribute is of a pass-by-reference type
560  * then a pointer into the tuple data area is returned --- the caller must
561  * not modify or pfree the datum!
562  */
563 Datum
564 SysCacheGetAttr(int cacheId, HeapTuple tup,
565                                 AttrNumber attributeNumber,
566                                 bool *isnull)
567 {
568
569         /*
570          * We just need to get the TupleDesc out of the cache entry, and then
571          * we can apply heap_getattr().  We expect that the cache control data
572          * is currently valid --- if the caller just fetched the tuple, then
573          * it should be.
574          */
575         if (cacheId < 0 || cacheId >= SysCacheSize)
576                 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
577         if (!PointerIsValid(SysCache[cacheId]) ||
578                 SysCache[cacheId]->relationId == InvalidOid ||
579                 !PointerIsValid(SysCache[cacheId]->cc_tupdesc))
580                 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
581
582         return heap_getattr(tup, attributeNumber,
583                                                 SysCache[cacheId]->cc_tupdesc,
584                                                 isnull);
585 }