]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Allow indexes on system catalogs for use in cache code.
[postgresql] / src / backend / utils / cache / syscache.c
1 /*-------------------------------------------------------------------------
2  *
3  * syscache.c
4  *        System cache management routines
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.38 1999/11/01 02:29:25 momjian Exp $
11  *
12  * NOTES
13  *        These routines allow the parser/planner/executor to perform
14  *        rapid lookups on the contents of the system catalogs.
15  *
16  *        see catalog/syscache.h for a list of the cache id's
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21
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"
39
40 extern bool AMI_OVERRIDE;               /* XXX style */
41
42 #include "utils/syscache.h"
43 #include "catalog/indexing.h"
44
45 typedef HeapTuple (*ScanFunc) ();
46
47 /* ----------------
48  *              Warning:  cacheinfo[] below is changed, then be sure and
49  *              update the magic constants in syscache.h!
50  * ----------------
51  */
52 static struct cachedesc cacheinfo[] = {
53         {AccessMethodOperatorRelationName,      /* AMOPOPID */
54                 3,
55                 {
56                         Anum_pg_amop_amopclaid,
57                         Anum_pg_amop_amopopr,
58                         Anum_pg_amop_amopid,
59                         0
60                 },
61                 sizeof(FormData_pg_amop),
62                 AccessMethodOpidIndex,
63         (ScanFunc) AccessMethodOpidIndexScan},
64         {AccessMethodOperatorRelationName,      /* AMOPSTRATEGY */
65                 3,
66                 {
67                         Anum_pg_amop_amopid,
68                         Anum_pg_amop_amopclaid,
69                         Anum_pg_amop_amopstrategy,
70                         0
71                 },
72                 sizeof(FormData_pg_amop),
73                 AccessMethodStrategyIndex,
74         (ScanFunc) AccessMethodStrategyIndexScan},
75         {AttributeRelationName,         /* ATTNAME */
76                 2,
77                 {
78                         Anum_pg_attribute_attrelid,
79                         Anum_pg_attribute_attname,
80                         0,
81                         0
82                 },
83                 ATTRIBUTE_TUPLE_SIZE,
84                 AttributeNameIndex,
85         (ScanFunc) AttributeNameIndexScan},
86         {AttributeRelationName,         /* ATTNUM */
87                 2,
88                 {
89                         Anum_pg_attribute_attrelid,
90                         Anum_pg_attribute_attnum,
91                         0,
92                         0
93                 },
94                 ATTRIBUTE_TUPLE_SIZE,
95                 AttributeNumIndex,
96         (ScanFunc) AttributeNumIndexScan},
97         {IndexRelationName,                     /* INDEXRELID */
98                 1,
99                 {
100                         Anum_pg_index_indexrelid,
101                         0,
102                         0,
103                         0
104                 },
105                 offsetof(FormData_pg_index, indpred),
106                 IndexRelidIndex,
107         (ScanFunc) IndexRelidIndexScan},
108         {LanguageRelationName,          /* LANNAME */
109                 1,
110                 {
111                         Anum_pg_language_lanname,
112                         0,
113                         0,
114                         0
115                 },
116                 offsetof(FormData_pg_language, lancompiler),
117                 NULL,
118         NULL},
119         {OperatorRelationName,          /* OPRNAME */
120                 4,
121                 {
122                         Anum_pg_operator_oprname,
123                         Anum_pg_operator_oprleft,
124                         Anum_pg_operator_oprright,
125                         Anum_pg_operator_oprkind
126                 },
127                 sizeof(FormData_pg_operator),
128                 NULL,
129         NULL},
130         {OperatorRelationName,          /* OPROID */
131                 1,
132                 {
133                         ObjectIdAttributeNumber,
134                         0,
135                         0,
136                         0
137                 },
138                 sizeof(FormData_pg_operator),
139                 NULL,
140         (ScanFunc) NULL},
141         {ProcedureRelationName,         /* PRONAME */
142                 3,
143                 {
144                         Anum_pg_proc_proname,
145                         Anum_pg_proc_pronargs,
146                         Anum_pg_proc_proargtypes,
147                         0
148                 },
149                 offsetof(FormData_pg_proc, prosrc),
150                 ProcedureNameIndex,
151         (ScanFunc) ProcedureNameIndexScan},
152         {ProcedureRelationName,         /* PROOID */
153                 1,
154                 {
155                         ObjectIdAttributeNumber,
156                         0,
157                         0,
158                         0
159                 },
160                 offsetof(FormData_pg_proc, prosrc),
161                 ProcedureOidIndex,
162         (ScanFunc) ProcedureOidIndexScan},
163         {RelationRelationName,          /* RELNAME */
164                 1,
165                 {
166                         Anum_pg_class_relname,
167                         0,
168                         0,
169                         0
170                 },
171                 CLASS_TUPLE_SIZE,
172                 ClassNameIndex,
173         (ScanFunc) ClassNameIndexScan},
174         {RelationRelationName,          /* RELOID */
175                 1,
176                 {
177                         ObjectIdAttributeNumber,
178                         0,
179                         0,
180                         0
181                 },
182                 CLASS_TUPLE_SIZE,
183                 ClassOidIndex,
184         (ScanFunc) ClassOidIndexScan},
185         {TypeRelationName,                      /* TYPNAME */
186                 1,
187                 {
188                         Anum_pg_type_typname,
189                         0,
190                         0,
191                         0
192                 },
193                 offsetof(FormData_pg_type, typalign) +sizeof(char),
194                 TypeNameIndex,
195         TypeNameIndexScan},
196         {TypeRelationName,                      /* TYPOID */
197                 1,
198                 {
199                         ObjectIdAttributeNumber,
200                         0,
201                         0,
202                         0
203                 },
204                 offsetof(FormData_pg_type, typalign) +sizeof(char),
205                 TypeOidIndex,
206         TypeOidIndexScan},
207         {AccessMethodRelationName,      /* AMNAME */
208                 1,
209                 {
210                         Anum_pg_am_amname,
211                         0,
212                         0,
213                         0
214                 },
215                 sizeof(FormData_pg_am),
216                 NULL,
217         NULL},
218         {OperatorClassRelationName, /* CLANAME */
219                 1,
220                 {
221                         Anum_pg_opclass_opcname,
222                         0,
223                         0,
224                         0
225                 },
226                 sizeof(FormData_pg_opclass),
227                 NULL,
228         NULL},
229         {InheritsRelationName,          /* INHRELID */
230                 2,
231                 {
232                         Anum_pg_inherits_inhrel,
233                         Anum_pg_inherits_inhseqno,
234                         0,
235                         0
236                 },
237                 sizeof(FormData_pg_inherits),
238                 NULL,
239         (ScanFunc) NULL},
240         {RewriteRelationName,           /* RULOID */
241                 1,
242                 {
243                         ObjectIdAttributeNumber,
244                         0,
245                         0,
246                         0
247                 },
248                 offsetof(FormData_pg_rewrite, ev_qual),
249                 NULL,
250         (ScanFunc) NULL},
251         {AggregateRelationName,         /* AGGNAME */
252                 2,
253                 {
254                         Anum_pg_aggregate_aggname,
255                         Anum_pg_aggregate_aggbasetype,
256                         0,
257                         0
258                 },
259                 offsetof(FormData_pg_aggregate, agginitval1),
260                 NULL,
261         (ScanFunc) NULL},
262         {ListenerRelationName,          /* LISTENREL */
263                 2,
264                 {
265                         Anum_pg_listener_relname,
266                         Anum_pg_listener_pid,
267                         0,
268                         0
269                 },
270                 sizeof(FormData_pg_listener),
271                 NULL,
272         (ScanFunc) NULL},
273         {ShadowRelationName,            /* USENAME */
274                 1,
275                 {
276                         Anum_pg_shadow_usename,
277                         0,
278                         0,
279                         0
280                 },
281                 sizeof(FormData_pg_shadow),
282                 NULL,
283         (ScanFunc) NULL},
284         {ShadowRelationName,            /* USESYSID */
285                 1,
286                 {
287                         Anum_pg_shadow_usesysid,
288                         0,
289                         0,
290                         0
291                 },
292                 sizeof(FormData_pg_shadow),
293                 NULL,
294         (ScanFunc) NULL},
295         {GroupRelationName,                     /* GRONAME */
296                 1,
297                 {
298                         Anum_pg_group_groname,
299                         0,
300                         0,
301                         0
302                 },
303                 offsetof(FormData_pg_group, grolist[0]),
304                 NULL,
305         (ScanFunc) NULL},
306         {GroupRelationName,                     /* GROSYSID */
307                 1,
308                 {
309                         Anum_pg_group_grosysid,
310                         0,
311                         0,
312                         0
313                 },
314                 offsetof(FormData_pg_group, grolist[0]),
315                 NULL,
316         (ScanFunc) NULL},
317         {RewriteRelationName,           /* REWRITENAME */
318                 1,
319                 {
320                         Anum_pg_rewrite_rulename,
321                         0,
322                         0,
323                         0
324                 },
325                 offsetof(FormData_pg_rewrite, ev_qual),
326                 NULL,
327         (ScanFunc) NULL},
328         {OperatorClassRelationName, /* CLADEFTYPE */
329                 1,
330                 {
331                         Anum_pg_opclass_opcdeftype,
332                         0,
333                         0,
334                         0
335                 },
336                 sizeof(FormData_pg_opclass),
337                 NULL,
338         (ScanFunc) NULL},
339         {LanguageRelationName,          /* LANOID */
340                 1,
341                 {
342                         ObjectIdAttributeNumber,
343                         0,
344                         0,
345                         0
346                 },
347                 offsetof(FormData_pg_language, lancompiler),
348                 NULL,
349         NULL}
350 };
351
352 static struct catcache *SysCache[lengthof(cacheinfo)];
353 static int32 SysCacheSize = lengthof(cacheinfo);
354
355
356 /*
357  * zerocaches
358  *
359  *        Make sure the SysCache structure is zero'd.
360  */
361 void
362 zerocaches()
363 {
364         MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
365 }
366
367 /*
368  * Note:
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.
372  */
373 void
374 InitCatalogCache()
375 {
376         int                     cacheId;                /* XXX type */
377
378         if (!AMI_OVERRIDE)
379         {
380                 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
381                 {
382
383                         Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
384
385                         SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
386                                                                                          cacheinfo[cacheId].indname,
387                                                                                          cacheId,
388                                                                                          cacheinfo[cacheId].nkeys,
389                                                                                          cacheinfo[cacheId].key,
390                                                                                    cacheinfo[cacheId].iScanFunc);
391                         if (!PointerIsValid((char *) SysCache[cacheId]))
392                         {
393                                 elog(ERROR,
394                                          "InitCatalogCache: Can't init cache %s(%d)",
395                                          cacheinfo[cacheId].name,
396                                          cacheId);
397                         }
398
399                 }
400         }
401 }
402
403 /*
404  * SearchSysCacheTupleCopy
405  *
406  *      This is like SearchSysCacheTuple, except it returns a copy of the tuple
407  *      that the user is required to pfree().
408  */
409 HeapTuple
410 SearchSysCacheTupleCopy(int cacheId,    /* cache selection code */
411                                                 Datum key1,
412                                                 Datum key2,
413                                                 Datum key3,
414                                                 Datum key4)
415 {
416         HeapTuple       cachetup;
417
418         cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
419         if (PointerIsValid(cachetup))
420                 return heap_copytuple(cachetup);
421         else
422                 return cachetup;                /* NULL */
423 }
424
425
426 /*
427  * SearchSysCacheTuple
428  *
429  *      A layer on top of SearchSysCache that does the initialization and
430  *      key-setting for you.
431  *
432  *      Returns the cache copy of the tuple if one is found, NULL if not.
433  *      The tuple is the 'cache' copy.
434  *
435  *      XXX The tuple that is returned is NOT supposed to be pfree'd!
436  */
437 HeapTuple
438 SearchSysCacheTuple(int cacheId,/* cache selection code */
439                                         Datum key1,
440                                         Datum key2,
441                                         Datum key3,
442                                         Datum key4)
443 {
444         HeapTuple       tp;
445
446         if (cacheId < 0 || cacheId >= SysCacheSize)
447         {
448                 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
449                 return (HeapTuple) NULL;
450         }
451
452         Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
453
454         if (!PointerIsValid(SysCache[cacheId]))
455         {
456                 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
457                                                                                  cacheinfo[cacheId].indname,
458                                                                                  cacheId,
459                                                                                  cacheinfo[cacheId].nkeys,
460                                                                                  cacheinfo[cacheId].key,
461                                                                                  cacheinfo[cacheId].iScanFunc);
462                 if (!PointerIsValid(SysCache[cacheId]))
463                         elog(ERROR,
464                                  "InitCatalogCache: Can't init cache %s(%d)",
465                                  cacheinfo[cacheId].name,
466                                  cacheId);
467         }
468
469         /* temp table name remapping */
470         if (cacheId == RELNAME)
471         {
472                 char *nontemp_relname;
473
474                 if ((nontemp_relname =
475                          get_temp_rel_by_name(DatumGetPointer(key1))) != NULL)
476                         key1 = PointerGetDatum(nontemp_relname);
477         }
478         
479         tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
480         if (!HeapTupleIsValid(tp))
481         {
482 #ifdef CACHEDEBUG
483                 elog(DEBUG,
484                          "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
485                          cacheinfo[cacheId].name,
486                          cacheId, key1, key2, key3, key4);
487 #endif
488                 return (HeapTuple) NULL;
489         }
490         return tp;
491 }
492
493 /*
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.
498  *
499  * NOTE: we are assuming that non-variable-length fields in the system
500  *               catalogs will always be defined!
501  *
502  * Returns 1L if a tuple was found, 0L if not.
503  */
504 int32
505 SearchSysCacheStruct(int cacheId,               /* cache selection code */
506                                          char *returnStruct,            /* (preallocated!) */
507                                          Datum key1,
508                                          Datum key2,
509                                          Datum key3,
510                                          Datum key4)
511 {
512         HeapTuple       tp;
513
514         if (!PointerIsValid(returnStruct))
515         {
516                 elog(ERROR, "SearchSysCacheStruct: No receiving struct");
517                 return 0;
518         }
519         tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
520         if (!HeapTupleIsValid(tp))
521                 return 0;
522         memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
523         return 1;
524 }
525
526
527 /*
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
532  *        in the tuple.
533  *
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.
536  *
537  * [callers all assume this returns a (struct varlena *). -ay 10/94]
538  */
539 void *
540 SearchSysCacheGetAttribute(int cacheId,
541                                                    AttrNumber attributeNumber,
542                                                    Datum key1,
543                                                    Datum key2,
544                                                    Datum key3,
545                                                    Datum key4)
546 {
547         HeapTuple       tp;
548         char       *cacheName;
549         Relation        relation;
550         int32           attributeLength,
551                                 attributeByValue;
552         bool            isNull;
553         Datum           attributeValue;
554         void       *returnValue;
555
556         /*
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.
560          */
561         cacheName = cacheinfo[cacheId].name;
562         relation = heap_openr(cacheName, AccessShareLock);
563
564         tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
565
566         if (!HeapTupleIsValid(tp))
567         {
568                 heap_close(relation, AccessShareLock);
569 #ifdef  CACHEDEBUG
570                 elog(DEBUG,
571                          "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
572                          cacheName, cacheId);
573 #endif   /* defined(CACHEDEBUG) */
574                 return NULL;
575         }
576
577         if (attributeNumber < 0 &&
578                 attributeNumber > FirstLowInvalidHeapAttributeNumber)
579         {
580                 attributeLength = heap_sysattrlen(attributeNumber);
581                 attributeByValue = heap_sysattrbyval(attributeNumber);
582         }
583         else if (attributeNumber > 0 &&
584                          attributeNumber <= relation->rd_rel->relnatts)
585         {
586                 attributeLength = relation->rd_att->attrs[attributeNumber - 1]->attlen;
587                 attributeByValue = relation->rd_att->attrs[attributeNumber - 1]->attbyval;
588         }
589         else
590         {
591                 heap_close(relation, AccessShareLock);
592                 elog(ERROR,
593                          "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
594                          attributeNumber, cacheName, cacheId);
595                 return NULL;
596         }
597
598         attributeValue = heap_getattr(tp,
599                                                                   attributeNumber,
600                                                                   RelationGetDescr(relation),
601                                                                   &isNull);
602
603         if (isNull)
604         {
605                 /*
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
608                  */
609                 heap_close(relation, AccessShareLock);
610                 return NULL;
611         }
612
613         if (attributeByValue)
614                 returnValue = (void *) attributeValue;
615         else
616         {
617                 char       *tmp;
618                 int                     size = (attributeLength < 0)
619                 ? VARSIZE((struct varlena *) attributeValue)    /* variable length */
620                 : attributeLength;              /* fixed length */
621
622                 tmp = (char *) palloc(size);
623                 memcpy(tmp, (void *) attributeValue, size);
624                 returnValue = (void *) tmp;
625         }
626
627         heap_close(relation, AccessShareLock);
628         return returnValue;
629 }