]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/syscache.c
Implement reindex command
[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.49 2000/02/18 09:28:56 inoue 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[lengthof(cacheinfo)];
398 static int32 SysCacheSize = lengthof(cacheinfo);
399 static bool  CacheInitialized = false;
400 extern bool  IsCacheInitialized(void)
401 {
402         return CacheInitialized;
403 }
404
405
406 /*
407  * zerocaches
408  *
409  *        Make sure the SysCache structure is zero'd.
410  */
411 void
412 zerocaches()
413 {
414         MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
415 }
416
417 /*
418  * Note:
419  *              This function was written because the initialized catalog caches
420  *              are used to determine which caches may contain tuples which need
421  *              to be invalidated in other backends.
422  */
423 void
424 InitCatalogCache()
425 {
426         int                     cacheId;                /* XXX type */
427
428         if (!AMI_OVERRIDE)
429         {
430                 for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
431                 {
432
433                         Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
434
435                         SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
436                                                                                          cacheinfo[cacheId].indname,
437                                                                                          cacheId,
438                                                                                          cacheinfo[cacheId].nkeys,
439                                                                                          cacheinfo[cacheId].key,
440                                                                                    cacheinfo[cacheId].iScanFunc);
441                         if (!PointerIsValid((char *) SysCache[cacheId]))
442                         {
443                                 elog(ERROR,
444                                          "InitCatalogCache: Can't init cache %s(%d)",
445                                          cacheinfo[cacheId].name,
446                                          cacheId);
447                         }
448
449                 }
450         }
451         CacheInitialized = true;
452 }
453
454 /*
455  * SearchSysCacheTupleCopy
456  *
457  *      This is like SearchSysCacheTuple, except it returns a copy of the tuple
458  *      that the user is required to pfree().
459  */
460 HeapTuple
461 SearchSysCacheTupleCopy(int cacheId,    /* cache selection code */
462                                                 Datum key1,
463                                                 Datum key2,
464                                                 Datum key3,
465                                                 Datum key4)
466 {
467         HeapTuple       cachetup;
468
469         cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
470         if (PointerIsValid(cachetup))
471                 return heap_copytuple(cachetup);
472         else
473                 return cachetup;                /* NULL */
474 }
475
476
477 /*
478  * SearchSysCacheTuple
479  *
480  *      A layer on top of SearchSysCache that does the initialization and
481  *      key-setting for you.
482  *
483  *      Returns the cache copy of the tuple if one is found, NULL if not.
484  *      The tuple is the 'cache' copy.
485  *
486  *      XXX The tuple that is returned is NOT supposed to be pfree'd!
487  */
488 HeapTuple
489 SearchSysCacheTuple(int cacheId,/* cache selection code */
490                                         Datum key1,
491                                         Datum key2,
492                                         Datum key3,
493                                         Datum key4)
494 {
495         HeapTuple       tp;
496
497         if (cacheId < 0 || cacheId >= SysCacheSize)
498         {
499                 elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
500                 return (HeapTuple) NULL;
501         }
502
503         Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
504
505         if (!PointerIsValid(SysCache[cacheId]))
506         {
507                 SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
508                                                                                  cacheinfo[cacheId].indname,
509                                                                                  cacheId,
510                                                                                  cacheinfo[cacheId].nkeys,
511                                                                                  cacheinfo[cacheId].key,
512                                                                                  cacheinfo[cacheId].iScanFunc);
513                 if (!PointerIsValid(SysCache[cacheId]))
514                         elog(ERROR,
515                                  "InitCatalogCache: Can't init cache %s(%d)",
516                                  cacheinfo[cacheId].name,
517                                  cacheId);
518         }
519
520         /* temp table name remapping */
521         if (cacheId == RELNAME)
522         {
523                 char *nontemp_relname;
524
525                 if ((nontemp_relname =
526                          get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
527                         key1 = PointerGetDatum(nontemp_relname);
528         }
529
530         tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
531         if (!HeapTupleIsValid(tp))
532         {
533 #ifdef CACHEDEBUG
534                 elog(DEBUG,
535                          "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
536                          cacheinfo[cacheId].name,
537                          cacheId, key1, key2, key3, key4);
538 #endif
539                 return (HeapTuple) NULL;
540         }
541         return tp;
542 }
543
544
545 /*
546  * SysCacheGetAttr
547  *
548  *              Given a tuple previously fetched by SearchSysCacheTuple() or
549  *              SearchSysCacheTupleCopy(), extract a specific attribute.
550  *
551  * This is equivalent to using heap_getattr() on a tuple fetched
552  * from a non-cached relation.  Usually, this is only used for attributes
553  * that could be NULL or variable length; the fixed-size attributes in
554  * a system table are accessed just by mapping the tuple onto the C struct
555  * declarations from include/catalog/.
556  *
557  * As with heap_getattr(), if the attribute is of a pass-by-reference type
558  * then a pointer into the tuple data area is returned --- the caller must
559  * not modify or pfree the datum!
560  */
561 Datum
562 SysCacheGetAttr(int cacheId, HeapTuple tup,
563                                 AttrNumber attributeNumber,
564                                 bool *isnull)
565 {
566         /*
567          * We just need to get the TupleDesc out of the cache entry,
568          * and then we can apply heap_getattr().  We expect that the cache
569          * control data is currently valid --- if the caller just fetched
570          * the tuple, then it should be.
571          */
572         if (cacheId < 0 || cacheId >= SysCacheSize)
573                 elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
574         if (! PointerIsValid(SysCache[cacheId]) ||
575                 SysCache[cacheId]->relationId == InvalidOid ||
576                 ! PointerIsValid(SysCache[cacheId]->cc_tupdesc))
577                 elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);
578
579         return heap_getattr(tup, attributeNumber,
580                                                 SysCache[cacheId]->cc_tupdesc,
581                                                 isnull);
582 }