syscache.c 13.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * syscache.c
4
 *	  System cache management routines
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
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.81 2002/07/11 07:39:27 ishii Exp $
12 13
 *
 * NOTES
14 15
 *	  These routines allow the parser/planner/executor to perform
 *	  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 "access/heapam.h"
24 25
#include "access/transam.h"
#include "utils/builtins.h"
26
#include "catalog/catname.h"
27
#include "catalog/indexing.h"
Bruce Momjian's avatar
Bruce Momjian committed
28
#include "catalog/pg_aggregate.h"
29
#include "catalog/pg_amop.h"
30
#include "catalog/pg_amproc.h"
31
#include "catalog/pg_conversion.h"
32 33 34 35
#include "catalog/pg_group.h"
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h"
36
#include "catalog/pg_namespace.h"
37 38 39 40
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
41
#include "catalog/pg_shadow.h"
42
#include "catalog/pg_statistic.h"
Bruce Momjian's avatar
Bruce Momjian committed
43 44
#include "catalog/pg_type.h"
#include "utils/catcache.h"
45
#include "utils/syscache.h"
Hiroshi Inoue's avatar
Hiroshi Inoue committed
46
#include "miscadmin.h"
47

48 49 50 51 52 53 54 55

/*---------------------------------------------------------------------------

	Adding system caches:

	Add your new cache to the list in include/utils/syscache.h.  Keep
	the list sorted alphabetically and adjust the cache numbers
	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 60 61 62 63 64
	name, index name, number of keys, and key attribute numbers.  If the
	relation contains tuples that are associated with a particular relation
	(for example, its attributes, rules, triggers, etc) then specify the
	attribute number that contains the OID of the associated relation.
	This is used by CatalogCacheFlushRelation() to remove the correct
	tuples during a table drop or relcache invalidation event.
65

66
	In include/catalog/indexing.h, add a define for the number of indexes
67
	on the relation, add define(s) for the index name(s), add an extern
68
	array to hold the index names, and use DECLARE_UNIQUE_INDEX to define
69
	the index.	Cache lookups return only one row, so the index should be
70
	unique in most cases.
71

72
	In backend/catalog/indexing.c, initialize the relation array with
73
	the index names for the relation.
74

75
	Finally, any place your relation gets heap_insert() or
76
	heap_update calls, include code to do a CatalogIndexInsert() to update
77
	the system indexes.  The heap_* calls do not update indexes.
78

79
	bjm 1999/11/22
80 81 82 83

  ---------------------------------------------------------------------------
*/

84
/*
85 86 87 88
 *		struct cachedesc: information defining a single syscache
 */
struct cachedesc
{
89 90
	const char *name;			/* name of the relation being cached */
	const char *indname;		/* name of index relation for this cache */
91
	int			reloidattr;		/* attr number of rel OID reference, or 0 */
92 93 94 95
	int			nkeys;			/* # of keys needed for cache lookup */
	int			key[4];			/* attribute numbers of key attrs */
};

96
static const struct cachedesc cacheinfo[] = {
97 98
	{AggregateRelationName,		/* AGGFNOID */
		AggregateFnoidIndex,
99 100 101
		0,
		1,
		{
102
			Anum_pg_aggregate_aggfnoid,
103 104 105 106
			0,
			0,
			0
	}},
107
	{AccessMethodRelationName,	/* AMNAME */
108
		AmNameIndex,
109
		0,
110 111 112 113 114 115
		1,
		{
			Anum_pg_am_amname,
			0,
			0,
			0
116
	}},
117 118 119 120 121 122 123 124 125 126
	{AccessMethodRelationName,	/* AMOID */
		AmOidIndex,
		0,
		1,
		{
			ObjectIdAttributeNumber,
			0,
			0,
			0
	}},
127
	{AccessMethodOperatorRelationName,	/* AMOPOPID */
128
		AccessMethodOperatorIndex,
129
		0,
130
		2,
131 132
		{
			Anum_pg_amop_amopclaid,
133
			Anum_pg_amop_amopopr,
134
			0,
135
			0
136
	}},
137
	{AccessMethodOperatorRelationName,	/* AMOPSTRATEGY */
138
		AccessMethodStrategyIndex,
139
		0,
140
		2,
141
		{
142 143
			Anum_pg_amop_amopclaid,
			Anum_pg_amop_amopstrategy,
144 145 146
			0,
			0
	}},
147
	{AccessMethodProcedureRelationName, /* AMPROCNUM */
148 149 150 151 152 153 154
		AccessMethodProcedureIndex,
		0,
		2,
		{
			Anum_pg_amproc_amopclaid,
			Anum_pg_amproc_amprocnum,
			0,
155
			0
156
	}},
157
	{AttributeRelationName,		/* ATTNAME */
158
		AttributeRelidNameIndex,
159
		Anum_pg_attribute_attrelid,
160
		2,
161 162
		{
			Anum_pg_attribute_attrelid,
163 164
			Anum_pg_attribute_attname,
			0,
165
			0
166
	}},
167
	{AttributeRelationName,		/* ATTNUM */
168
		AttributeRelidNumIndex,
169
		Anum_pg_attribute_attrelid,
170
		2,
171 172
		{
			Anum_pg_attribute_attrelid,
173 174
			Anum_pg_attribute_attnum,
			0,
175
			0
176
	}},
177 178
	{OperatorClassRelationName, /* CLAAMNAMENSP */
		OpclassAmNameNspIndex,
179
		0,
180
		3,
181
		{
182 183
			Anum_pg_opclass_opcamid,
			Anum_pg_opclass_opcname,
184
			Anum_pg_opclass_opcnamespace,
185
			0
186
	}},
187 188
	{OperatorClassRelationName, /* CLAOID */
		OpclassOidIndex,
189
		0,
190 191
		1,
		{
192
			ObjectIdAttributeNumber,
193 194 195
			0,
			0,
			0
196
	}},
197 198 199 200 201 202 203 204 205 206
	{ConversionRelationName, /* CONNAMENSP */
		ConversionNameNspIndex,
		0,
		2,
		{
			Anum_pg_conversion_conname,
			Anum_pg_conversion_connamespace,
			0,
			0
	}},
207
	{GroupRelationName,			/* GRONAME */
208
		GroupNameIndex,
209
		0,
210 211 212 213 214 215
		1,
		{
			Anum_pg_group_groname,
			0,
			0,
			0
216
	}},
217
	{GroupRelationName,			/* GROSYSID */
218
		GroupSysidIndex,
219
		0,
220 221 222 223 224 225
		1,
		{
			Anum_pg_group_grosysid,
			0,
			0,
			0
226
	}},
227
	{IndexRelationName,			/* INDEXRELID */
228
		IndexRelidIndex,
229
		Anum_pg_index_indrelid,
230
		1,
231 232
		{
			Anum_pg_index_indexrelid,
233 234
			0,
			0,
235
			0
236
	}},
237
	{InheritsRelationName,		/* INHRELID */
238
		InheritsRelidSeqnoIndex,
239
		Anum_pg_inherits_inhrelid,
240 241 242 243 244 245
		2,
		{
			Anum_pg_inherits_inhrelid,
			Anum_pg_inherits_inhseqno,
			0,
			0
246
	}},
247
	{LanguageRelationName,		/* LANGNAME */
248
		LanguageNameIndex,
249
		0,
250
		1,
251 252
		{
			Anum_pg_language_lanname,
253 254
			0,
			0,
255
			0
256
	}},
257
	{LanguageRelationName,		/* LANGOID */
258
		LanguageOidIndex,
259
		0,
260 261 262 263 264 265
		1,
		{
			ObjectIdAttributeNumber,
			0,
			0,
			0
266
	}},
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	{NamespaceRelationName,		/* NAMESPACENAME */
		NamespaceNameIndex,
		0,
		1,
		{
			Anum_pg_namespace_nspname,
			0,
			0,
			0
	}},
	{NamespaceRelationName,		/* NAMESPACEOID */
		NamespaceOidIndex,
		0,
		1,
		{
			ObjectIdAttributeNumber,
			0,
			0,
			0
	}},
287 288
	{OperatorRelationName,		/* OPERNAMENSP */
		OperatorNameNspIndex,
289
		0,
290
		4,
291 292
		{
			Anum_pg_operator_oprname,
293 294
			Anum_pg_operator_oprleft,
			Anum_pg_operator_oprright,
295
			Anum_pg_operator_oprnamespace
296
	}},
297
	{OperatorRelationName,		/* OPEROID */
298
		OperatorOidIndex,
299
		0,
300
		1,
301 302
		{
			ObjectIdAttributeNumber,
303 304
			0,
			0,
305
			0
306
	}},
307 308
	{ProcedureRelationName,		/* PROCNAMENSP */
		ProcedureNameNspIndex,
309
		0,
310
		4,
311 312
		{
			Anum_pg_proc_proname,
313 314
			Anum_pg_proc_pronargs,
			Anum_pg_proc_proargtypes,
315
			Anum_pg_proc_pronamespace
316
	}},
317
	{ProcedureRelationName,		/* PROCOID */
318
		ProcedureOidIndex,
319
		0,
320
		1,
321 322
		{
			ObjectIdAttributeNumber,
323 324
			0,
			0,
325
			0
326
	}},
327 328
	{RelationRelationName,		/* RELNAMENSP */
		ClassNameNspIndex,
329
		ObjectIdAttributeNumber,
330
		2,
331 332
		{
			Anum_pg_class_relname,
333
			Anum_pg_class_relnamespace,
334
			0,
335
			0
336
	}},
337
	{RelationRelationName,		/* RELOID */
338
		ClassOidIndex,
339
		ObjectIdAttributeNumber,
340
		1,
341 342
		{
			ObjectIdAttributeNumber,
343 344
			0,
			0,
345
			0
346
	}},
347 348
	{RewriteRelationName,		/* RULERELNAME */
		RewriteRelRulenameIndex,
349
		Anum_pg_rewrite_ev_class,
350
		2,
351
		{
352
			Anum_pg_rewrite_ev_class,
353
			Anum_pg_rewrite_rulename,
354
			0,
355
			0
356
	}},
357
	{ShadowRelationName,		/* SHADOWNAME */
358
		ShadowNameIndex,
359
		0,
360
		1,
361
		{
362
			Anum_pg_shadow_usename,
363 364
			0,
			0,
365
			0
366
	}},
367
	{ShadowRelationName,		/* SHADOWSYSID */
368
		ShadowSysidIndex,
369
		0,
370
		1,
371
		{
372
			Anum_pg_shadow_usesysid,
373 374
			0,
			0,
375
			0
376
	}},
377
	{StatisticRelationName,		/* STATRELATT */
378
		StatisticRelidAttnumIndex,
379
		Anum_pg_statistic_starelid,
380
		2,
381 382 383
		{
			Anum_pg_statistic_starelid,
			Anum_pg_statistic_staattnum,
384
			0,
385
			0
386
	}},
387 388
	{TypeRelationName,			/* TYPENAMENSP */
		TypeNameNspIndex,
389
		Anum_pg_type_typrelid,
390
		2,
391
		{
392
			Anum_pg_type_typname,
393
			Anum_pg_type_typnamespace,
394
			0,
395
			0
396
	}},
397
	{TypeRelationName,			/* TYPEOID */
398
		TypeOidIndex,
399
		Anum_pg_type_typrelid,
400
		1,
401
		{
402
			ObjectIdAttributeNumber,
403 404
			0,
			0,
405
			0
406
	}}
407
};
408

409
static CatCache *SysCache[lengthof(cacheinfo)];
410
static int	SysCacheSize = lengthof(cacheinfo);
411
static bool CacheInitialized = false;
412 413 414


bool
415
IsCacheInitialized(void)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
416 417 418
{
	return CacheInitialized;
}
419 420


421
/*
422
 * InitCatalogCache - initialize the caches
423
 *
424
 * Note that no database access is done here; we only allocate memory
425
 * and initialize the cache structure.	Interrogation of the database
426
 * to complete initialization of a cache happens upon first use
427
 * of that cache.
428 429
 */
void
430
InitCatalogCache(void)
431
{
432
	int			cacheId;
433

434
	Assert(!CacheInitialized);
435

436
	MemSet((char *) SysCache, 0, sizeof(SysCache));
437

438
	for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
439
	{
440 441 442
		SysCache[cacheId] = InitCatCache(cacheId,
										 cacheinfo[cacheId].name,
										 cacheinfo[cacheId].indname,
443
										 cacheinfo[cacheId].reloidattr,
444 445 446 447 448
										 cacheinfo[cacheId].nkeys,
										 cacheinfo[cacheId].key);
		if (!PointerIsValid(SysCache[cacheId]))
			elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)",
				 cacheinfo[cacheId].name, cacheId);
449
	}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
450
	CacheInitialized = true;
451
}
452

453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
/*
 * InitCatalogCachePhase2 - finish initializing the caches
 *
 * Finish initializing all the caches, including necessary database
 * access.
 *
 * This is *not* essential; normally we allow syscaches to be initialized
 * on first use.  However, it is useful as a mechanism to preload the
 * relcache with entries for the most-commonly-used system catalogs.
 * Therefore, we invoke this routine when we need to write a new relcache
 * init file.
 */
void
InitCatalogCachePhase2(void)
{
	int			cacheId;

	Assert(CacheInitialized);

	for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
	{
		InitCatCachePhase2(SysCache[cacheId]);
	}
}


480
/*
481
 * SearchSysCache
482
 *
483
 *	A layer on top of SearchCatCache that does the initialization and
484
 *	key-setting for you.
485
 *
486
 *	Returns the cache copy of the tuple if one is found, NULL if not.
487
 *	The tuple is the 'cache' copy and must NOT be modified!
488
 *
489 490 491 492
 *	When the caller is done using the tuple, call ReleaseSysCache()
 *	to release the reference count grabbed by SearchSysCache().  If this
 *	is not done, the tuple will remain locked in cache until end of
 *	transaction, which is tolerable but not desirable.
493
 *
494
 *	CAUTION: The tuple that is returned must NOT be freed by the caller!
495 496
 */
HeapTuple
497 498 499 500 501
SearchSysCache(int cacheId,
			   Datum key1,
			   Datum key2,
			   Datum key3,
			   Datum key4)
502
{
503 504
	if (cacheId < 0 || cacheId >= SysCacheSize ||
		! PointerIsValid(SysCache[cacheId]))
505
		elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
506

507
	return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
508 509
}

510 511 512 513 514 515 516 517 518
/*
 * ReleaseSysCache
 *		Release previously grabbed reference count on a tuple
 */
void
ReleaseSysCache(HeapTuple tuple)
{
	ReleaseCatCache(tuple);
}
519

520
/*
521
 * SearchSysCacheCopy
522
 *
523 524 525 526
 * A convenience routine that does SearchSysCache and (if successful)
 * returns a modifiable copy of the syscache entry.  The original
 * syscache entry is released before returning.  The caller should
 * heap_freetuple() the result when done with it.
527 528
 */
HeapTuple
529 530 531 532 533
SearchSysCacheCopy(int cacheId,
				   Datum key1,
				   Datum key2,
				   Datum key3,
				   Datum key4)
534
{
535 536 537 538 539 540 541 542 543
	HeapTuple	tuple,
				newtuple;

	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
	if (!HeapTupleIsValid(tuple))
		return tuple;
	newtuple = heap_copytuple(tuple);
	ReleaseSysCache(tuple);
	return newtuple;
544 545
}

546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
/*
 * SearchSysCacheExists
 *
 * A convenience routine that just probes to see if a tuple can be found.
 * No lock is retained on the syscache entry.
 */
bool
SearchSysCacheExists(int cacheId,
					 Datum key1,
					 Datum key2,
					 Datum key3,
					 Datum key4)
{
	HeapTuple	tuple;

	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
	if (!HeapTupleIsValid(tuple))
		return false;
	ReleaseSysCache(tuple);
	return true;
}

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
/*
 * GetSysCacheOid
 *
 * A convenience routine that does SearchSysCache and returns the OID
 * of the found tuple, or InvalidOid if no tuple could be found.
 * No lock is retained on the syscache entry.
 */
Oid
GetSysCacheOid(int cacheId,
			   Datum key1,
			   Datum key2,
			   Datum key3,
			   Datum key4)
{
	HeapTuple	tuple;
	Oid			result;

	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
	if (!HeapTupleIsValid(tuple))
		return InvalidOid;
	result = tuple->t_data->t_oid;
	ReleaseSysCache(tuple);
	return result;
}
592

593
/*
594 595
 * SysCacheGetAttr
 *
596 597
 *		Given a tuple previously fetched by SearchSysCache(),
 *		extract a specific attribute.
598
 *
599
 * This is equivalent to using heap_getattr() on a tuple fetched
600
 * from a non-cached relation.	Usually, this is only used for attributes
601 602 603
 * that could be NULL or variable length; the fixed-size attributes in
 * a system table are accessed just by mapping the tuple onto the C struct
 * declarations from include/catalog/.
604
 *
605 606 607
 * As with heap_getattr(), if the attribute is of a pass-by-reference type
 * then a pointer into the tuple data area is returned --- the caller must
 * not modify or pfree the datum!
608
 */
609 610 611
Datum
SysCacheGetAttr(int cacheId, HeapTuple tup,
				AttrNumber attributeNumber,
612
				bool *isNull)
613
{
614
	/*
615 616
	 * We just need to get the TupleDesc out of the cache entry, and then
	 * we can apply heap_getattr().  We expect that the cache control data
617 618
	 * is currently valid --- if the caller recently fetched the tuple,
	 * then it should be.
619
	 */
620 621
	if (cacheId < 0 || cacheId >= SysCacheSize)
		elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
622 623
	if (!PointerIsValid(SysCache[cacheId]) ||
		!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
624 625 626 627
		elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);

	return heap_getattr(tup, attributeNumber,
						SysCache[cacheId]->cc_tupdesc,
628
						isNull);
629
}
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

/*
 * List-search interface
 */
struct catclist *
SearchSysCacheList(int cacheId, int nkeys,
				   Datum key1, Datum key2, Datum key3, Datum key4)
{
	if (cacheId < 0 || cacheId >= SysCacheSize ||
		! PointerIsValid(SysCache[cacheId]))
		elog(ERROR, "SearchSysCacheList: Bad cache id %d", cacheId);

	return SearchCatCacheList(SysCache[cacheId], nkeys,
							  key1, key2, key3, key4);
}