]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Rename heap_replace to heap_update.
[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.42 1999/11/24 00:58:48 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 "utils/builtins.h"
23 #include "access/heapam.h"
24 #include "catalog/catname.h"
25 #include "catalog/pg_aggregate.h"
26 #include "catalog/pg_amop.h"
27 #include "catalog/pg_group.h"
28 #include "catalog/pg_index.h"
29 #include "catalog/pg_inherits.h"
30 #include "catalog/pg_language.h"
31 #include "catalog/pg_listener.h"
32 #include "catalog/pg_opclass.h"
33 #include "catalog/pg_operator.h"
34 #include "catalog/pg_proc.h"
35 #include "catalog/pg_rewrite.h"
36 #include "catalog/pg_shadow.h"
37 #include "catalog/pg_type.h"
38 #include "utils/catcache.h"
39 #include "utils/temprel.h"
40
41 extern bool AMI_OVERRIDE;               /* XXX style */
42
43 #include "utils/syscache.h"
44 #include "catalog/indexing.h"
45
46 typedef HeapTuple (*ScanFunc) ();
47
48
49 /*---------------------------------------------------------------------------
50
51         Adding system caches:
52
53         Add your new cache to the list in include/utils/syscache.h.  Keep
54         the list sorted alphabetically and adjust the cache numbers
55         accordingly.
56         
57         Add your entry to the cacheinfo[] array below.  All cache lists are
58         alphabetical, so add it in the proper place.  Specify the relation
59     name, number of arguments, argument names, size of tuple, index lookup
60         function, and index name.
61
62     In include/catalog/indexing.h, add a define for the number of indexes
63     in the relation, add a define for the index name, add an extern
64     array to hold the index names, define the index lookup function
65     prototype, and use DECLARE_UNIQUE_INDEX to define the index.  Cache
66     lookups return only one row, so the index should be unique.
67
68     In backend/catalog/indexing.c, initialize the relation array with
69     the index names for the relation, and create the index lookup function.
70     Pick one that takes similar arguments and use that one, but keep the
71     function names in the same order as the cache list for clarity.
72
73     Finally, any place your relation gets heap_insert() or
74         heap_update calls, include code to do a CatalogIndexInsert() to update
75         the system indexes.  The heap_* calls do not update indexes.
76         
77     bjm 1999/11/22
78
79   ---------------------------------------------------------------------------
80 */
81
82 static struct cachedesc cacheinfo[] = {
83         {AggregateRelationName,         /* AGGNAME */
84                 2,
85                 {
86                         Anum_pg_aggregate_aggname,
87                         Anum_pg_aggregate_aggbasetype,
88                         0,
89                         0
90                 },
91                 offsetof(FormData_pg_aggregate, agginitval1),
92                 AggregateNameTypeIndex,
93         AggregateNameTypeIndexScan},
94         {AccessMethodRelationName,      /* AMNAME */
95                 1,
96                 {
97                         Anum_pg_am_amname,
98                         0,
99                         0,
100                         0
101                 },
102                 sizeof(FormData_pg_am),
103                 AmNameIndex,
104         AmNameIndexScan},
105         {AccessMethodOperatorRelationName,      /* AMOPOPID */
106                 3,
107                 {
108                         Anum_pg_amop_amopclaid,
109                         Anum_pg_amop_amopopr,
110                         Anum_pg_amop_amopid,
111                         0
112                 },
113                 sizeof(FormData_pg_amop),
114                 AccessMethodOpidIndex,
115         AccessMethodOpidIndexScan},
116         {AccessMethodOperatorRelationName,      /* AMOPSTRATEGY */
117                 3,
118                 {
119                         Anum_pg_amop_amopid,
120                         Anum_pg_amop_amopclaid,
121                         Anum_pg_amop_amopstrategy,
122                         0
123                 },
124                 sizeof(FormData_pg_amop),
125                 AccessMethodStrategyIndex,
126         (ScanFunc) AccessMethodStrategyIndexScan},
127         {AttributeRelationName,         /* ATTNAME */
128                 2,
129                 {
130                         Anum_pg_attribute_attrelid,
131                         Anum_pg_attribute_attname,
132                         0,
133                         0
134                 },
135                 ATTRIBUTE_TUPLE_SIZE,
136                 AttributeRelidNameIndex,
137         AttributeRelidNameIndexScan},
138         {AttributeRelationName,         /* ATTNUM */
139                 2,
140                 {
141                         Anum_pg_attribute_attrelid,
142                         Anum_pg_attribute_attnum,
143                         0,
144                         0
145                 },
146                 ATTRIBUTE_TUPLE_SIZE,
147                 AttributeRelidNumIndex,
148         (ScanFunc) AttributeRelidNumIndexScan},
149         {OperatorClassRelationName, /* CLADEFTYPE */
150                 1,
151                 {
152                         Anum_pg_opclass_opcdeftype,
153                         0,
154                         0,
155                         0
156                 },
157                 sizeof(FormData_pg_opclass),
158                 OpclassDeftypeIndex,
159         OpclassDeftypeIndexScan},
160         {OperatorClassRelationName, /* CLANAME */
161                 1,
162                 {
163                         Anum_pg_opclass_opcname,
164                         0,
165                         0,
166                         0
167                 },
168                 sizeof(FormData_pg_opclass),
169                 OpclassNameIndex,
170         OpclassNameIndexScan},
171         {GroupRelationName,                     /* GRONAME */
172                 1,
173                 {
174                         Anum_pg_group_groname,
175                         0,
176                         0,
177                         0
178                 },
179                 offsetof(FormData_pg_group, grolist[0]),
180                 GroupNameIndex,
181         GroupNameIndexScan},
182         {GroupRelationName,                     /* GROSYSID */
183                 1,
184                 {
185                         Anum_pg_group_grosysid,
186                         0,
187                         0,
188                         0
189                 },
190                 offsetof(FormData_pg_group, grolist[0]),
191                 GroupSysidIndex,
192         GroupSysidIndexScan},
193         {IndexRelationName,                     /* INDEXRELID */
194                 1,
195                 {
196                         Anum_pg_index_indexrelid,
197                         0,
198                         0,
199                         0
200                 },
201                 offsetof(FormData_pg_index, indpred),
202                 IndexRelidIndex,
203         IndexRelidIndexScan},
204         {InheritsRelationName,          /* INHRELID */
205                 2,
206                 {
207                         Anum_pg_inherits_inhrelid,
208                         Anum_pg_inherits_inhseqno,
209                         0,
210                         0
211                 },
212                 sizeof(FormData_pg_inherits),
213                 InheritsRelidSeqnoIndex,
214         InheritsRelidSeqnoIndexScan},
215         {LanguageRelationName,          /* LANGNAME */
216                 1,
217                 {
218                         Anum_pg_language_lanname,
219                         0,
220                         0,
221                         0
222                 },
223                 offsetof(FormData_pg_language, lancompiler),
224                 LanguageNameIndex,
225         LanguageNameIndexScan},
226         {LanguageRelationName,          /* LANGOID */
227                 1,
228                 {
229                         ObjectIdAttributeNumber,
230                         0,
231                         0,
232                         0
233                 },
234                 offsetof(FormData_pg_language, lancompiler),
235                 LanguageOidIndex,
236         LanguageOidIndexScan},
237         {ListenerRelationName,          /* LISTENREL */
238                 2,
239                 {
240                         Anum_pg_listener_relname,
241                         Anum_pg_listener_pid,
242                         0,
243                         0
244                 },
245                 sizeof(FormData_pg_listener),
246                 ListenerRelnamePidIndex,
247         ListenerRelnamePidIndexScan},
248         {OperatorRelationName,          /* OPERNAME */
249                 4,
250                 {
251                         Anum_pg_operator_oprname,
252                         Anum_pg_operator_oprleft,
253                         Anum_pg_operator_oprright,
254                         Anum_pg_operator_oprkind
255                 },
256                 sizeof(FormData_pg_operator),
257                 OperatorNameIndex,
258         (ScanFunc) OperatorNameIndexScan},
259         {OperatorRelationName,          /* OPEROID */
260                 1,
261                 {
262                         ObjectIdAttributeNumber,
263                         0,
264                         0,
265                         0
266                 },
267                 sizeof(FormData_pg_operator),
268                 OperatorOidIndex,
269         OperatorOidIndexScan},
270         {ProcedureRelationName,         /* PROCNAME */
271                 3,
272                 {
273                         Anum_pg_proc_proname,
274                         Anum_pg_proc_pronargs,
275                         Anum_pg_proc_proargtypes,
276                         0
277                 },
278                 offsetof(FormData_pg_proc, prosrc),
279                 ProcedureNameIndex,
280         (ScanFunc) ProcedureNameIndexScan},
281         {ProcedureRelationName,         /* PROCOID */
282                 1,
283                 {
284                         ObjectIdAttributeNumber,
285                         0,
286                         0,
287                         0
288                 },
289                 offsetof(FormData_pg_proc, prosrc),
290                 ProcedureOidIndex,
291         ProcedureOidIndexScan},
292         {RelationRelationName,          /* RELNAME */
293                 1,
294                 {
295                         Anum_pg_class_relname,
296                         0,
297                         0,
298                         0
299                 },
300                 CLASS_TUPLE_SIZE,
301                 ClassNameIndex,
302         ClassNameIndexScan},
303         {RelationRelationName,          /* RELOID */
304                 1,
305                 {
306                         ObjectIdAttributeNumber,
307                         0,
308                         0,
309                         0
310                 },
311                 CLASS_TUPLE_SIZE,
312                 ClassOidIndex,
313         ClassOidIndexScan},
314         {RewriteRelationName,           /* REWRITENAME */
315                 1,
316                 {
317                         Anum_pg_rewrite_rulename,
318                         0,
319                         0,
320                         0
321                 },
322                 offsetof(FormData_pg_rewrite, ev_qual),
323                 RewriteRulenameIndex,
324         RewriteRulenameIndexScan},
325         {RewriteRelationName,           /* RULEOID */
326                 1,
327                 {
328                         ObjectIdAttributeNumber,
329                         0,
330                         0,
331                         0
332                 },
333                 offsetof(FormData_pg_rewrite, ev_qual),
334                 RewriteOidIndex,
335         RewriteOidIndexScan},
336         {TypeRelationName,                      /* TYPENAME */
337                 1,
338                 {
339                         Anum_pg_type_typname,
340                         0,
341                         0,
342                         0
343                 },
344                 offsetof(FormData_pg_type, typalign) +sizeof(char),
345                 TypeNameIndex,
346         TypeNameIndexScan},
347         {TypeRelationName,                      /* TYPEOID */
348                 1,
349                 {
350                         ObjectIdAttributeNumber,
351                         0,
352                         0,
353                         0
354                 },
355                 offsetof(FormData_pg_type, typalign) +sizeof(char),
356                 TypeOidIndex,
357         TypeOidIndexScan},
358         {ShadowRelationName,            /* USERNAME */
359                 1,
360                 {
361                         Anum_pg_shadow_usename,
362                         0,
363                         0,
364                         0
365                 },
366                 sizeof(FormData_pg_shadow),
367 NULL,NULL
368 /*              ShadowNameIndex,
369         ShadowNameIndexScan*/},
370         {ShadowRelationName,            /* USERSYSID */
371                 1,
372                 {
373                         Anum_pg_shadow_usesysid,
374                         0,
375                         0,
376                         0
377                 },
378                 sizeof(FormData_pg_shadow),
379 NULL,NULL
380 /*              ShadowSysidIndex,
381         ShadowSysidIndexScan*/}
382 };
383
384 static struct catcache *SysCache[lengthof(cacheinfo)];
385 static int32 SysCacheSize = lengthof(cacheinfo);
386
387
388 /*
389  * zerocaches
390  *
391  *        Make sure the SysCache structure is zero'd.
392  */
393 void
394 zerocaches()
395 {
396         MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
397 }
398
399 /*
400  * Note:
401  *              This function was written because the initialized catalog caches
402  *              are used to determine which caches may contain tuples which need
403  *              to be invalidated in other backends.
404  */
405 void
406 InitCatalogCache()
407 {
408         int                     cacheId;                /* XXX type */
409
410         if (!AMI_OVERRIDE)
411         {
412                 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
413                 {
414
415                         Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
416
417                         SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
418                                                                                          cacheinfo[cacheId].indname,
419                                                                                          cacheId,
420                                                                                          cacheinfo[cacheId].nkeys,
421                                                                                          cacheinfo[cacheId].key,
422                                                                                    cacheinfo[cacheId].iScanFunc);
423                         if (!PointerIsValid((char *) SysCache[cacheId]))
424                         {
425                                 elog(ERROR,
426                                          "InitCatalogCache: Can't init cache %s(%d)",
427                                          cacheinfo[cacheId].name,
428                                          cacheId);
429                         }
430
431                 }
432         }
433 }
434
435 /*
436  * SearchSysCacheTupleCopy
437  *
438  *      This is like SearchSysCacheTuple, except it returns a copy of the tuple
439  *      that the user is required to pfree().
440  */
441 HeapTuple
442 SearchSysCacheTupleCopy(int cacheId,    /* cache selection code */
443                                                 Datum key1,
444                                                 Datum key2,
445                                                 Datum key3,
446                                                 Datum key4)
447 {
448         HeapTuple       cachetup;
449
450         cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
451         if (PointerIsValid(cachetup))
452                 return heap_copytuple(cachetup);
453         else
454                 return cachetup;                /* NULL */
455 }
456
457
458 /*
459  * SearchSysCacheTuple
460  *
461  *      A layer on top of SearchSysCache that does the initialization and
462  *      key-setting for you.
463  *
464  *      Returns the cache copy of the tuple if one is found, NULL if not.
465  *      The tuple is the 'cache' copy.
466  *
467  *      XXX The tuple that is returned is NOT supposed to be pfree'd!
468  */
469 HeapTuple
470 SearchSysCacheTuple(int cacheId,/* cache selection code */
471                                         Datum key1,
472                                         Datum key2,
473                                         Datum key3,
474                                         Datum key4)
475 {
476         HeapTuple       tp;
477
478         if (cacheId < 0 || cacheId >= SysCacheSize)
479         {
480                 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
481                 return (HeapTuple) NULL;
482         }
483
484         Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
485
486         if (!PointerIsValid(SysCache[cacheId]))
487         {
488                 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
489                                                                                  cacheinfo[cacheId].indname,
490                                                                                  cacheId,
491                                                                                  cacheinfo[cacheId].nkeys,
492                                                                                  cacheinfo[cacheId].key,
493                                                                                  cacheinfo[cacheId].iScanFunc);
494                 if (!PointerIsValid(SysCache[cacheId]))
495                         elog(ERROR,
496                                  "InitCatalogCache: Can't init cache %s(%d)",
497                                  cacheinfo[cacheId].name,
498                                  cacheId);
499         }
500
501         /* temp table name remapping */
502         if (cacheId == RELNAME)
503         {
504                 char *nontemp_relname;
505
506                 if ((nontemp_relname =
507                          get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
508                         key1 = PointerGetDatum(nontemp_relname);
509         }
510         
511         tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
512         if (!HeapTupleIsValid(tp))
513         {
514 #ifdef CACHEDEBUG
515                 elog(DEBUG,
516                          "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
517                          cacheinfo[cacheId].name,
518                          cacheId, key1, key2, key3, key4);
519 #endif
520                 return (HeapTuple) NULL;
521         }
522         return tp;
523 }
524
525 /*
526  * SearchSysCacheStruct
527  *        Fills 's' with the information retrieved by calling SearchSysCache()
528  *        with arguments key1...key4.  Retrieves only the portion of the tuple
529  *        which is not variable-length.
530  *
531  * NOTE: we are assuming that non-variable-length fields in the system
532  *               catalogs will always be defined!
533  *
534  * Returns 1L if a tuple was found, 0L if not.
535  */
536 int32
537 SearchSysCacheStruct(int cacheId,               /* cache selection code */
538                                          char *returnStruct,            /* (preallocated!) */
539                                          Datum key1,
540                                          Datum key2,
541                                          Datum key3,
542                                          Datum key4)
543 {
544         HeapTuple       tp;
545
546         if (!PointerIsValid(returnStruct))
547         {
548                 elog(ERROR, "SearchSysCacheStruct: No receiving struct");
549                 return 0;
550         }
551         tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
552         if (!HeapTupleIsValid(tp))
553                 return 0;
554         memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
555         return 1;
556 }
557
558
559 /*
560  * SearchSysCacheGetAttribute
561  *        Returns the attribute corresponding to 'attributeNumber' for
562  *        a given cached tuple.  This routine usually needs to be used for
563  *        attributes that might be NULL or might be at a variable offset
564  *        in the tuple.
565  *
566  * XXX This re-opens the relation, so this is slower than just pulling
567  * fixed-location fields out of the struct returned by SearchSysCacheTuple.
568  *
569  * [callers all assume this returns a (struct varlena *). -ay 10/94]
570  */
571 void *
572 SearchSysCacheGetAttribute(int cacheId,
573                                                    AttrNumber attributeNumber,
574                                                    Datum key1,
575                                                    Datum key2,
576                                                    Datum key3,
577                                                    Datum key4)
578 {
579         HeapTuple       tp;
580         char       *cacheName;
581         Relation        relation;
582         int32           attributeLength,
583                                 attributeByValue;
584         bool            isNull;
585         Datum           attributeValue;
586         void       *returnValue;
587
588         /*
589          * Open the relation first, to ensure we are in sync with SI inval
590          * events --- we don't want the tuple found in the cache to be
591          * invalidated out from under us.
592          */
593         cacheName = cacheinfo[cacheId].name;
594         relation = heap_openr(cacheName, AccessShareLock);
595
596         tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
597
598         if (!HeapTupleIsValid(tp))
599         {
600                 heap_close(relation, AccessShareLock);
601 #ifdef  CACHEDEBUG
602                 elog(DEBUG,
603                          "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
604                          cacheName, cacheId);
605 #endif   /* defined(CACHEDEBUG) */
606                 return NULL;
607         }
608
609         if (attributeNumber < 0 &&
610                 attributeNumber > FirstLowInvalidHeapAttributeNumber)
611         {
612                 attributeLength = heap_sysattrlen(attributeNumber);
613                 attributeByValue = heap_sysattrbyval(attributeNumber);
614         }
615         else if (attributeNumber > 0 &&
616                          attributeNumber <= relation->rd_rel->relnatts)
617         {
618                 attributeLength = relation->rd_att->attrs[attributeNumber - 1]->attlen;
619                 attributeByValue = relation->rd_att->attrs[attributeNumber - 1]->attbyval;
620         }
621         else
622         {
623                 heap_close(relation, AccessShareLock);
624                 elog(ERROR,
625                          "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
626                          attributeNumber, cacheName, cacheId);
627                 return NULL;
628         }
629
630         attributeValue = heap_getattr(tp,
631                                                                   attributeNumber,
632                                                                   RelationGetDescr(relation),
633                                                                   &isNull);
634
635         if (isNull)
636         {
637                 /*
638                  * Used to be an elog(DEBUG, ...) here and a claim that it should
639                  * be a FATAL error, I don't think either is warranted -mer 6/9/92
640                  */
641                 heap_close(relation, AccessShareLock);
642                 return NULL;
643         }
644
645         if (attributeByValue)
646                 returnValue = (void *) attributeValue;
647         else
648         {
649                 char       *tmp;
650                 int                     size = (attributeLength < 0)
651                 ? VARSIZE((struct varlena *) attributeValue)    /* variable length */
652                 : attributeLength;              /* fixed length */
653
654                 tmp = (char *) palloc(size);
655                 memcpy(tmp, (void *) attributeValue, size);
656                 returnValue = (void *) tmp;
657         }
658
659         heap_close(relation, AccessShareLock);
660         return returnValue;
661 }