Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * syscache.c
4 : : * System cache management routines
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/cache/syscache.c
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 utils/syscache.h for a list of the cache IDs
18 : : *
19 : : *-------------------------------------------------------------------------
20 : : */
21 : : #include "postgres.h"
22 : :
23 : : #include "access/htup_details.h"
24 : : #include "catalog/pg_db_role_setting_d.h"
25 : : #include "catalog/pg_depend_d.h"
26 : : #include "catalog/pg_description_d.h"
27 : : #include "catalog/pg_seclabel_d.h"
28 : : #include "catalog/pg_shdepend_d.h"
29 : : #include "catalog/pg_shdescription_d.h"
30 : : #include "catalog/pg_shseclabel_d.h"
31 : : #include "common/int.h"
32 : : #include "lib/qunique.h"
33 : : #include "utils/catcache.h"
34 : : #include "utils/lsyscache.h"
35 : : #include "utils/rel.h"
36 : : #include "utils/syscache.h"
37 : :
38 : : /*---------------------------------------------------------------------------
39 : :
40 : : Adding system caches:
41 : :
42 : : There must be a unique index underlying each syscache (ie, an index
43 : : whose key is the same as that of the cache). If there is not one
44 : : already, add the definition for it to include/catalog/pg_*.h using
45 : : DECLARE_UNIQUE_INDEX.
46 : : (Adding an index requires a catversion.h update, while simply
47 : : adding/deleting caches only requires a recompile.)
48 : :
49 : : Add a MAKE_SYSCACHE call to the same pg_*.h file specifying the name of
50 : : your cache, the underlying index, and the initial number of hash buckets.
51 : :
52 : : The number of hash buckets must be a power of 2. It's reasonable to
53 : : set this to the number of entries that might be in the particular cache
54 : : in a medium-size database.
55 : :
56 : : Finally, any place your relation gets heap_insert() or
57 : : heap_update() calls, use CatalogTupleInsert() or CatalogTupleUpdate()
58 : : instead, which also update indexes. The heap_* calls do not do that.
59 : :
60 : : *---------------------------------------------------------------------------
61 : : */
62 : :
63 : : /*
64 : : * struct cachedesc: information defining a single syscache
65 : : */
66 : : struct cachedesc
67 : : {
68 : : Oid reloid; /* OID of the relation being cached */
69 : : Oid indoid; /* OID of index relation for this cache */
70 : : int nkeys; /* # of keys needed for cache lookup */
71 : : int key[4]; /* attribute numbers of key attrs */
72 : : int nbuckets; /* number of hash buckets for this cache */
73 : : };
74 : :
75 : : /* Macro to provide nkeys and key array with convenient syntax. */
76 : : #define KEY(...) VA_ARGS_NARGS(__VA_ARGS__), { __VA_ARGS__ }
77 : :
78 : : #include "catalog/syscache_info.h"
79 : :
80 : : StaticAssertDecl(lengthof(cacheinfo) == SysCacheSize,
81 : : "SysCacheSize does not match syscache.c's array");
82 : :
83 : : static CatCache *SysCache[SysCacheSize];
84 : :
85 : : static bool CacheInitialized = false;
86 : :
87 : : /* Sorted array of OIDs of tables that have caches on them */
88 : : static Oid SysCacheRelationOid[SysCacheSize];
89 : : static int SysCacheRelationOidSize;
90 : :
91 : : /* Sorted array of OIDs of tables and indexes used by caches */
92 : : static Oid SysCacheSupportingRelOid[SysCacheSize * 2];
93 : : static int SysCacheSupportingRelOidSize;
94 : :
95 : : static int oid_compare(const void *a, const void *b);
96 : :
97 : :
98 : : /*
99 : : * InitCatalogCache - initialize the caches
100 : : *
101 : : * Note that no database access is done here; we only allocate memory
102 : : * and initialize the cache structure. Interrogation of the database
103 : : * to complete initialization of a cache happens upon first use
104 : : * of that cache.
105 : : */
106 : : void
8550 tgl@sss.pgh.pa.us 107 :CBC 16411 : InitCatalogCache(void)
108 : : {
109 : : int cacheId;
110 : :
111 [ - + ]: 16411 : Assert(!CacheInitialized);
112 : :
3234 113 : 16411 : SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
114 : :
8550 115 [ + + ]: 1378524 : for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
116 : : {
117 : : /*
118 : : * Assert that every enumeration value defined in syscache.h has been
119 : : * populated in the cacheinfo array.
120 : : */
262 michael@paquier.xyz 121 [ - + ]:GNC 1362113 : Assert(OidIsValid(cacheinfo[cacheId].reloid));
122 [ - + ]: 1362113 : Assert(OidIsValid(cacheinfo[cacheId].indoid));
123 : : /* .nbuckets and .key[] are checked by InitCatCache() */
124 : :
8550 tgl@sss.pgh.pa.us 125 :CBC 2724226 : SysCache[cacheId] = InitCatCache(cacheId,
6940 126 : 1362113 : cacheinfo[cacheId].reloid,
127 : 1362113 : cacheinfo[cacheId].indoid,
8550 128 : 1362113 : cacheinfo[cacheId].nkeys,
6513 129 : 1362113 : cacheinfo[cacheId].key,
130 : 1362113 : cacheinfo[cacheId].nbuckets);
8550 131 [ - + ]: 1362113 : if (!PointerIsValid(SysCache[cacheId]))
6940 tgl@sss.pgh.pa.us 132 [ # # ]:UBC 0 : elog(ERROR, "could not initialize cache %u (%d)",
133 : : cacheinfo[cacheId].reloid, cacheId);
134 : : /* Accumulate data for OID lists, too */
3939 rhaas@postgresql.org 135 :CBC 1362113 : SysCacheRelationOid[SysCacheRelationOidSize++] =
136 : 1362113 : cacheinfo[cacheId].reloid;
3234 tgl@sss.pgh.pa.us 137 : 1362113 : SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
138 : 1362113 : cacheinfo[cacheId].reloid;
139 : 1362113 : SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
140 : 1362113 : cacheinfo[cacheId].indoid;
141 : : /* see comments for RelationInvalidatesSnapshotsOnly */
3939 rhaas@postgresql.org 142 [ - + ]: 1362113 : Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
143 : : }
144 : :
3234 tgl@sss.pgh.pa.us 145 [ - + ]: 16411 : Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid));
146 [ - + ]: 16411 : Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid));
147 : :
148 : : /* Sort and de-dup OID arrays, so we can use binary search. */
58 nathan@postgresql.or 149 :GNC 16411 : qsort(SysCacheRelationOid, SysCacheRelationOidSize,
150 : : sizeof(Oid), oid_compare);
1620 tmunro@postgresql.or 151 :CBC 16411 : SysCacheRelationOidSize =
152 : 16411 : qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
153 : : oid_compare);
154 : :
58 nathan@postgresql.or 155 :GNC 16411 : qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
156 : : sizeof(Oid), oid_compare);
1620 tmunro@postgresql.or 157 :CBC 16411 : SysCacheSupportingRelOidSize =
158 : 16411 : qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
159 : : sizeof(Oid), oid_compare);
160 : :
8822 inoue@tpf.co.jp 161 : 16411 : CacheInitialized = true;
10141 scrappy@hub.org 162 : 16411 : }
163 : :
164 : : /*
165 : : * InitCatalogCachePhase2 - finish initializing the caches
166 : : *
167 : : * Finish initializing all the caches, including necessary database
168 : : * access.
169 : : *
170 : : * This is *not* essential; normally we allow syscaches to be initialized
171 : : * on first use. However, it is useful as a mechanism to preload the
172 : : * relcache with entries for the most-commonly-used system catalogs.
173 : : * Therefore, we invoke this routine when we need to write a new relcache
174 : : * init file.
175 : : */
176 : : void
8090 tgl@sss.pgh.pa.us 177 : 1445 : InitCatalogCachePhase2(void)
178 : : {
179 : : int cacheId;
180 : :
181 [ - + ]: 1445 : Assert(CacheInitialized);
182 : :
183 [ + + ]: 121380 : for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
6400 184 : 119935 : InitCatCachePhase2(SysCache[cacheId], true);
8090 185 : 1445 : }
186 : :
187 : :
188 : : /*
189 : : * SearchSysCache
190 : : *
191 : : * A layer on top of SearchCatCache that does the initialization and
192 : : * key-setting for you.
193 : : *
194 : : * Returns the cache copy of the tuple if one is found, NULL if not.
195 : : * The tuple is the 'cache' copy and must NOT be modified!
196 : : *
197 : : * When the caller is done using the tuple, call ReleaseSysCache()
198 : : * to release the reference count grabbed by SearchSysCache(). If this
199 : : * is not done, the tuple will remain locked in cache until end of
200 : : * transaction, which is tolerable but not desirable.
201 : : *
202 : : * CAUTION: The tuple that is returned must NOT be freed by the caller!
203 : : */
204 : : HeapTuple
8550 205 : 2644607 : SearchSysCache(int cacheId,
206 : : Datum key1,
207 : : Datum key2,
208 : : Datum key3,
209 : : Datum key4)
210 : : {
2375 andres@anarazel.de 211 [ + - + - : 2644607 : Assert(cacheId >= 0 && cacheId < SysCacheSize &&
- + ]
212 : : PointerIsValid(SysCache[cacheId]));
213 : :
8550 tgl@sss.pgh.pa.us 214 : 2644607 : return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
215 : : }
216 : :
217 : : HeapTuple
2375 andres@anarazel.de 218 : 29697531 : SearchSysCache1(int cacheId,
219 : : Datum key1)
220 : : {
221 [ + - + - : 29697531 : Assert(cacheId >= 0 && cacheId < SysCacheSize &&
- + ]
222 : : PointerIsValid(SysCache[cacheId]));
223 [ - + ]: 29697531 : Assert(SysCache[cacheId]->cc_nkeys == 1);
224 : :
225 : 29697531 : return SearchCatCache1(SysCache[cacheId], key1);
226 : : }
227 : :
228 : : HeapTuple
229 : 2428165 : SearchSysCache2(int cacheId,
230 : : Datum key1, Datum key2)
231 : : {
232 [ + - + - : 2428165 : Assert(cacheId >= 0 && cacheId < SysCacheSize &&
- + ]
233 : : PointerIsValid(SysCache[cacheId]));
234 [ - + ]: 2428165 : Assert(SysCache[cacheId]->cc_nkeys == 2);
235 : :
236 : 2428165 : return SearchCatCache2(SysCache[cacheId], key1, key2);
237 : : }
238 : :
239 : : HeapTuple
240 : 2233030 : SearchSysCache3(int cacheId,
241 : : Datum key1, Datum key2, Datum key3)
242 : : {
243 [ + - + - : 2233030 : Assert(cacheId >= 0 && cacheId < SysCacheSize &&
- + ]
244 : : PointerIsValid(SysCache[cacheId]));
245 [ - + ]: 2233030 : Assert(SysCache[cacheId]->cc_nkeys == 3);
246 : :
247 : 2233030 : return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
248 : : }
249 : :
250 : : HeapTuple
251 : 1756003 : SearchSysCache4(int cacheId,
252 : : Datum key1, Datum key2, Datum key3, Datum key4)
253 : : {
254 [ + - + - : 1756003 : Assert(cacheId >= 0 && cacheId < SysCacheSize &&
- + ]
255 : : PointerIsValid(SysCache[cacheId]));
256 [ - + ]: 1756003 : Assert(SysCache[cacheId]->cc_nkeys == 4);
257 : :
258 : 1756003 : return SearchCatCache4(SysCache[cacheId], key1, key2, key3, key4);
259 : : }
260 : :
261 : : /*
262 : : * ReleaseSysCache
263 : : * Release previously grabbed reference count on a tuple
264 : : */
265 : : void
8550 tgl@sss.pgh.pa.us 266 : 36218766 : ReleaseSysCache(HeapTuple tuple)
267 : : {
268 : 36218766 : ReleaseCatCache(tuple);
269 : 36218766 : }
270 : :
271 : : /*
272 : : * SearchSysCacheCopy
273 : : *
274 : : * A convenience routine that does SearchSysCache and (if successful)
275 : : * returns a modifiable copy of the syscache entry. The original
276 : : * syscache entry is released before returning. The caller should
277 : : * heap_freetuple() the result when done with it.
278 : : */
279 : : HeapTuple
280 : 388382 : SearchSysCacheCopy(int cacheId,
281 : : Datum key1,
282 : : Datum key2,
283 : : Datum key3,
284 : : Datum key4)
285 : : {
286 : : HeapTuple tuple,
287 : : newtuple;
288 : :
289 : 388382 : tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
290 [ + + ]: 388382 : if (!HeapTupleIsValid(tuple))
291 : 59244 : return tuple;
292 : 329138 : newtuple = heap_copytuple(tuple);
293 : 329138 : ReleaseSysCache(tuple);
294 : 329138 : return newtuple;
295 : : }
296 : :
297 : : /*
298 : : * SearchSysCacheExists
299 : : *
300 : : * A convenience routine that just probes to see if a tuple can be found.
301 : : * No lock is retained on the syscache entry.
302 : : */
303 : : bool
8283 304 : 623707 : SearchSysCacheExists(int cacheId,
305 : : Datum key1,
306 : : Datum key2,
307 : : Datum key3,
308 : : Datum key4)
309 : : {
310 : : HeapTuple tuple;
311 : :
312 : 623707 : tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
313 [ + + ]: 623707 : if (!HeapTupleIsValid(tuple))
314 : 110172 : return false;
315 : 513535 : ReleaseSysCache(tuple);
316 : 513535 : return true;
317 : : }
318 : :
319 : : /*
320 : : * GetSysCacheOid
321 : : *
322 : : * A convenience routine that does SearchSysCache and returns the OID in the
323 : : * oidcol column of the found tuple, or InvalidOid if no tuple could be found.
324 : : * No lock is retained on the syscache entry.
325 : : */
326 : : Oid
8550 327 : 1632518 : GetSysCacheOid(int cacheId,
328 : : AttrNumber oidcol,
329 : : Datum key1,
330 : : Datum key2,
331 : : Datum key3,
332 : : Datum key4)
333 : : {
334 : : HeapTuple tuple;
335 : : bool isNull;
336 : : Oid result;
337 : :
338 : 1632518 : tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
339 [ + + ]: 1632518 : if (!HeapTupleIsValid(tuple))
340 : 684534 : return InvalidOid;
1972 andres@anarazel.de 341 : 1895968 : result = heap_getattr(tuple, oidcol,
342 : 947984 : SysCache[cacheId]->cc_tupdesc,
343 : : &isNull);
1789 tgl@sss.pgh.pa.us 344 [ - + ]: 947984 : Assert(!isNull); /* columns used as oids should never be NULL */
8550 345 : 947984 : ReleaseSysCache(tuple);
346 : 947984 : return result;
347 : : }
348 : :
349 : :
350 : : /*
351 : : * SearchSysCacheAttName
352 : : *
353 : : * This routine is equivalent to SearchSysCache on the ATTNAME cache,
354 : : * except that it will return NULL if the found attribute is marked
355 : : * attisdropped. This is convenient for callers that want to act as
356 : : * though dropped attributes don't exist.
357 : : */
358 : : HeapTuple
7926 359 : 50305 : SearchSysCacheAttName(Oid relid, const char *attname)
360 : : {
361 : : HeapTuple tuple;
362 : :
5173 rhaas@postgresql.org 363 : 50305 : tuple = SearchSysCache2(ATTNAME,
364 : : ObjectIdGetDatum(relid),
365 : : CStringGetDatum(attname));
7926 tgl@sss.pgh.pa.us 366 [ + + ]: 50305 : if (!HeapTupleIsValid(tuple))
367 : 429 : return NULL;
368 [ + + ]: 49876 : if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
369 : : {
370 : 39 : ReleaseSysCache(tuple);
371 : 39 : return NULL;
372 : : }
373 : 49837 : return tuple;
374 : : }
375 : :
376 : : /*
377 : : * SearchSysCacheCopyAttName
378 : : *
379 : : * As above, an attisdropped-aware version of SearchSysCacheCopy.
380 : : */
381 : : HeapTuple
382 : 4959 : SearchSysCacheCopyAttName(Oid relid, const char *attname)
383 : : {
384 : : HeapTuple tuple,
385 : : newtuple;
386 : :
387 : 4959 : tuple = SearchSysCacheAttName(relid, attname);
388 [ + + ]: 4959 : if (!HeapTupleIsValid(tuple))
389 : 327 : return tuple;
390 : 4632 : newtuple = heap_copytuple(tuple);
391 : 4632 : ReleaseSysCache(tuple);
392 : 4632 : return newtuple;
393 : : }
394 : :
395 : : /*
396 : : * SearchSysCacheExistsAttName
397 : : *
398 : : * As above, an attisdropped-aware version of SearchSysCacheExists.
399 : : */
400 : : bool
401 : 909 : SearchSysCacheExistsAttName(Oid relid, const char *attname)
402 : : {
403 : : HeapTuple tuple;
404 : :
405 : 909 : tuple = SearchSysCacheAttName(relid, attname);
406 [ + + ]: 909 : if (!HeapTupleIsValid(tuple))
407 : 6 : return false;
408 : 903 : ReleaseSysCache(tuple);
409 : 903 : return true;
410 : : }
411 : :
412 : :
413 : : /*
414 : : * SearchSysCacheAttNum
415 : : *
416 : : * This routine is equivalent to SearchSysCache on the ATTNUM cache,
417 : : * except that it will return NULL if the found attribute is marked
418 : : * attisdropped. This is convenient for callers that want to act as
419 : : * though dropped attributes don't exist.
420 : : */
421 : : HeapTuple
2412 simon@2ndQuadrant.co 422 : 11894 : SearchSysCacheAttNum(Oid relid, int16 attnum)
423 : : {
424 : : HeapTuple tuple;
425 : :
426 : 11894 : tuple = SearchSysCache2(ATTNUM,
427 : : ObjectIdGetDatum(relid),
428 : : Int16GetDatum(attnum));
429 [ + + ]: 11894 : if (!HeapTupleIsValid(tuple))
430 : 6 : return NULL;
431 [ - + ]: 11888 : if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
432 : : {
2412 simon@2ndQuadrant.co 433 :UBC 0 : ReleaseSysCache(tuple);
434 : 0 : return NULL;
435 : : }
2412 simon@2ndQuadrant.co 436 :CBC 11888 : return tuple;
437 : : }
438 : :
439 : : /*
440 : : * SearchSysCacheCopyAttNum
441 : : *
442 : : * As above, an attisdropped-aware version of SearchSysCacheCopy.
443 : : */
444 : : HeapTuple
445 : 11862 : SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
446 : : {
447 : : HeapTuple tuple,
448 : : newtuple;
449 : :
450 : 11862 : tuple = SearchSysCacheAttNum(relid, attnum);
451 [ - + ]: 11862 : if (!HeapTupleIsValid(tuple))
2412 simon@2ndQuadrant.co 452 :LBC (6) : return NULL;
2412 simon@2ndQuadrant.co 453 :CBC 11862 : newtuple = heap_copytuple(tuple);
454 : 11862 : ReleaseSysCache(tuple);
455 : 11862 : return newtuple;
456 : : }
457 : :
458 : :
459 : : /*
460 : : * SysCacheGetAttr
461 : : *
462 : : * Given a tuple previously fetched by SearchSysCache(),
463 : : * extract a specific attribute.
464 : : *
465 : : * This is equivalent to using heap_getattr() on a tuple fetched
466 : : * from a non-cached relation. Usually, this is only used for attributes
467 : : * that could be NULL or variable length; the fixed-size attributes in
468 : : * a system table are accessed just by mapping the tuple onto the C struct
469 : : * declarations from include/catalog/.
470 : : *
471 : : * As with heap_getattr(), if the attribute is of a pass-by-reference type
472 : : * then a pointer into the tuple data area is returned --- the caller must
473 : : * not modify or pfree the datum!
474 : : *
475 : : * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
476 : : * a different cache for the same catalog the tuple was fetched from.
477 : : */
478 : : Datum
8848 tgl@sss.pgh.pa.us 479 : 2490115 : SysCacheGetAttr(int cacheId, HeapTuple tup,
480 : : AttrNumber attributeNumber,
481 : : bool *isNull)
482 : : {
483 : : /*
484 : : * We just need to get the TupleDesc out of the cache entry, and then we
485 : : * can apply heap_getattr(). Normally the cache control data is already
486 : : * valid (because the caller recently fetched the tuple via this same
487 : : * cache), but there are cases where we have to initialize the cache here.
488 : : */
6400 489 [ + - + - ]: 2490115 : if (cacheId < 0 || cacheId >= SysCacheSize ||
490 [ - + ]: 2490115 : !PointerIsValid(SysCache[cacheId]))
4683 peter_e@gmx.net 491 [ # # ]:UBC 0 : elog(ERROR, "invalid cache ID: %d", cacheId);
6400 tgl@sss.pgh.pa.us 492 [ + + ]:CBC 2490115 : if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
493 : : {
494 : 13729 : InitCatCachePhase2(SysCache[cacheId], false);
495 [ - + ]: 13729 : Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
496 : : }
497 : :
8848 498 : 4980230 : return heap_getattr(tup, attributeNumber,
499 : 2490115 : SysCache[cacheId]->cc_tupdesc,
500 : : isNull);
501 : : }
502 : :
503 : : /*
504 : : * SysCacheGetAttrNotNull
505 : : *
506 : : * As above, a version of SysCacheGetAttr which knows that the attr cannot
507 : : * be NULL.
508 : : */
509 : : Datum
386 dgustafsson@postgres 510 : 1380979 : SysCacheGetAttrNotNull(int cacheId, HeapTuple tup,
511 : : AttrNumber attributeNumber)
512 : : {
513 : : bool isnull;
514 : : Datum attr;
515 : :
516 : 1380979 : attr = SysCacheGetAttr(cacheId, tup, attributeNumber, &isnull);
517 : :
518 [ - + ]: 1380979 : if (isnull)
519 : : {
386 dgustafsson@postgres 520 [ # # ]:UBC 0 : elog(ERROR,
521 : : "unexpected null value in cached tuple for catalog %s column %s",
522 : : get_rel_name(cacheinfo[cacheId].reloid),
523 : : NameStr(TupleDescAttr(SysCache[cacheId]->cc_tupdesc, attributeNumber - 1)->attname));
524 : : }
525 : :
386 dgustafsson@postgres 526 :CBC 1380979 : return attr;
527 : : }
528 : :
529 : : /*
530 : : * GetSysCacheHashValue
531 : : *
532 : : * Get the hash value that would be used for a tuple in the specified cache
533 : : * with the given search keys.
534 : : *
535 : : * The reason for exposing this as part of the API is that the hash value is
536 : : * exposed in cache invalidation operations, so there are places outside the
537 : : * catcache code that need to be able to compute the hash values.
538 : : */
539 : : uint32
4421 tgl@sss.pgh.pa.us 540 : 72105 : GetSysCacheHashValue(int cacheId,
541 : : Datum key1,
542 : : Datum key2,
543 : : Datum key3,
544 : : Datum key4)
545 : : {
546 [ + - + - ]: 72105 : if (cacheId < 0 || cacheId >= SysCacheSize ||
547 [ - + ]: 72105 : !PointerIsValid(SysCache[cacheId]))
4421 tgl@sss.pgh.pa.us 548 [ # # ]:UBC 0 : elog(ERROR, "invalid cache ID: %d", cacheId);
549 : :
4421 tgl@sss.pgh.pa.us 550 :CBC 72105 : return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
551 : : }
552 : :
553 : : /*
554 : : * List-search interface
555 : : */
556 : : struct catclist *
8044 557 : 1525452 : SearchSysCacheList(int cacheId, int nkeys,
558 : : Datum key1, Datum key2, Datum key3)
559 : : {
560 [ + - + - ]: 1525452 : if (cacheId < 0 || cacheId >= SysCacheSize ||
7893 bruce@momjian.us 561 [ - + ]: 1525452 : !PointerIsValid(SysCache[cacheId]))
4683 peter_e@gmx.net 562 [ # # ]:UBC 0 : elog(ERROR, "invalid cache ID: %d", cacheId);
563 : :
8044 tgl@sss.pgh.pa.us 564 :CBC 1525452 : return SearchCatCacheList(SysCache[cacheId], nkeys,
565 : : key1, key2, key3);
566 : : }
567 : :
568 : : /*
569 : : * SysCacheInvalidate
570 : : *
571 : : * Invalidate entries in the specified cache, given a hash value.
572 : : * See CatCacheInvalidate() for more info.
573 : : *
574 : : * This routine is only quasi-public: it should only be used by inval.c.
575 : : */
576 : : void
2529 577 : 10524998 : SysCacheInvalidate(int cacheId, uint32 hashValue)
578 : : {
579 [ + - - + ]: 10524998 : if (cacheId < 0 || cacheId >= SysCacheSize)
2529 tgl@sss.pgh.pa.us 580 [ # # ]:UBC 0 : elog(ERROR, "invalid cache ID: %d", cacheId);
581 : :
582 : : /* if this cache isn't initialized yet, no need to do anything */
2529 tgl@sss.pgh.pa.us 583 [ - + ]:CBC 10524998 : if (!PointerIsValid(SysCache[cacheId]))
2529 tgl@sss.pgh.pa.us 584 :UBC 0 : return;
585 : :
2529 tgl@sss.pgh.pa.us 586 :CBC 10524998 : CatCacheInvalidate(SysCache[cacheId], hashValue);
587 : : }
588 : :
589 : : /*
590 : : * Certain relations that do not have system caches send snapshot invalidation
591 : : * messages in lieu of catcache messages. This is for the benefit of
592 : : * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
593 : : * for scanning one of those catalogs, rather than taking a new one, if no
594 : : * invalidation has been received.
595 : : *
596 : : * Relations that have syscaches need not (and must not) be listed here. The
597 : : * catcache invalidation messages will also flush the snapshot. If you add a
598 : : * syscache for one of these relations, remove it from this list.
599 : : */
600 : : bool
3939 rhaas@postgresql.org 601 : 8159713 : RelationInvalidatesSnapshotsOnly(Oid relid)
602 : : {
603 [ + + ]: 8159713 : switch (relid)
604 : : {
605 : 1110075 : case DbRoleSettingRelationId:
606 : : case DependRelationId:
607 : : case SharedDependRelationId:
608 : : case DescriptionRelationId:
609 : : case SharedDescriptionRelationId:
610 : : case SecLabelRelationId:
611 : : case SharedSecLabelRelationId:
612 : 1110075 : return true;
613 : 7049638 : default:
614 : 7049638 : break;
615 : : }
616 : :
617 : 7049638 : return false;
618 : : }
619 : :
620 : : /*
621 : : * Test whether a relation has a system cache.
622 : : */
623 : : bool
624 : 4374304 : RelationHasSysCache(Oid relid)
625 : : {
3631 bruce@momjian.us 626 : 4374304 : int low = 0,
627 : 4374304 : high = SysCacheRelationOidSize - 1;
628 : :
3939 rhaas@postgresql.org 629 [ + + ]: 19334031 : while (low <= high)
630 : : {
3631 bruce@momjian.us 631 : 19125192 : int middle = low + (high - low) / 2;
632 : :
3939 rhaas@postgresql.org 633 [ + + ]: 19125192 : if (SysCacheRelationOid[middle] == relid)
634 : 4165465 : return true;
635 [ + + ]: 14959727 : if (SysCacheRelationOid[middle] < relid)
636 : 5194996 : low = middle + 1;
637 : : else
638 : 9764731 : high = middle - 1;
639 : : }
640 : :
641 : 208839 : return false;
642 : : }
643 : :
644 : : /*
645 : : * Test whether a relation supports a system cache, ie it is either a
646 : : * cached table or the index used for a cache.
647 : : */
648 : : bool
3234 tgl@sss.pgh.pa.us 649 : 989122 : RelationSupportsSysCache(Oid relid)
650 : : {
651 : 989122 : int low = 0,
652 : 989122 : high = SysCacheSupportingRelOidSize - 1;
653 : :
654 [ + + ]: 8345073 : while (low <= high)
655 : : {
656 : 7543981 : int middle = low + (high - low) / 2;
657 : :
658 [ + + ]: 7543981 : if (SysCacheSupportingRelOid[middle] == relid)
659 : 188030 : return true;
660 [ + + ]: 7355951 : if (SysCacheSupportingRelOid[middle] < relid)
661 : 6795918 : low = middle + 1;
662 : : else
663 : 560033 : high = middle - 1;
664 : : }
665 : :
666 : 801092 : return false;
667 : : }
668 : :
669 : :
670 : : /*
671 : : * OID comparator for qsort
672 : : */
673 : : static int
3939 rhaas@postgresql.org 674 : 31148078 : oid_compare(const void *a, const void *b)
675 : : {
3234 tgl@sss.pgh.pa.us 676 : 31148078 : Oid oa = *((const Oid *) a);
677 : 31148078 : Oid ob = *((const Oid *) b);
678 : :
58 nathan@postgresql.or 679 :GNC 31148078 : return pg_cmp_u32(oa, ob);
680 : : }
|