syscache.c 12.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * syscache.c
4
 *	  System cache management routines
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.45 2000/01/23 03:43:24 tgl Exp $
11 12
 *
 * NOTES
13 14
 *	  These routines allow the parser/planner/executor to perform
 *	  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 24
#include "access/heapam.h"
#include "catalog/catname.h"
Bruce Momjian's avatar
Bruce Momjian committed
25
#include "catalog/pg_aggregate.h"
26 27 28 29 30
#include "catalog/pg_amop.h"
#include "catalog/pg_group.h"
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h"
Bruce Momjian's avatar
Bruce Momjian committed
31
#include "catalog/pg_listener.h"
32 33 34 35
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
36
#include "catalog/pg_shadow.h"
37
#include "catalog/pg_statistic.h"
Bruce Momjian's avatar
Bruce Momjian committed
38 39
#include "catalog/pg_type.h"
#include "utils/catcache.h"
40
#include "utils/temprel.h"
41

42
extern bool AMI_OVERRIDE;		/* XXX style */
43

44 45
#include "utils/syscache.h"
#include "catalog/indexing.h"
46

47
typedef HeapTuple (*ScanFunc) ();
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

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

	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.
	
	Add your entry to the cacheinfo[] array below.  All cache lists are
	alphabetical, so add it in the proper place.  Specify the relation
    name, number of arguments, argument names, size of tuple, index lookup
	function, and index name.

    In include/catalog/indexing.h, add a define for the number of indexes
    in the relation, add a define for the index name, add an extern
    array to hold the index names, define the index lookup function
    prototype, and use DECLARE_UNIQUE_INDEX to define the index.  Cache
    lookups return only one row, so the index should be unique.

    In backend/catalog/indexing.c, initialize the relation array with
70 71
    the index names for the relation, fixed size of relation (or marking
    first non-fixed length field), and create the index lookup function.
72 73 74 75
    Pick one that takes similar arguments and use that one, but keep the
    function names in the same order as the cache list for clarity.

    Finally, any place your relation gets heap_insert() or
76
	heap_update calls, include code to do a CatalogIndexInsert() to update
77 78 79 80 81 82 83
	the system indexes.  The heap_* calls do not update indexes.
	
    bjm 1999/11/22

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

84
static struct cachedesc cacheinfo[] = {
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
	{AggregateRelationName,		/* AGGNAME */
		2,
		{
			Anum_pg_aggregate_aggname,
			Anum_pg_aggregate_aggbasetype,
			0,
			0
		},
		offsetof(FormData_pg_aggregate, agginitval1),
		AggregateNameTypeIndex,
	AggregateNameTypeIndexScan},
	{AccessMethodRelationName,	/* AMNAME */
		1,
		{
			Anum_pg_am_amname,
			0,
			0,
			0
		},
		sizeof(FormData_pg_am),
		AmNameIndex,
	AmNameIndexScan},
107 108
	{AccessMethodOperatorRelationName,	/* AMOPOPID */
		3,
109 110
		{
			Anum_pg_amop_amopclaid,
111 112
			Anum_pg_amop_amopopr,
			Anum_pg_amop_amopid,
113 114
			0
		},
115
		sizeof(FormData_pg_amop),
116
		AccessMethodOpidIndex,
117
	AccessMethodOpidIndexScan},
118 119
	{AccessMethodOperatorRelationName,	/* AMOPSTRATEGY */
		3,
120 121
		{
			Anum_pg_amop_amopid,
122 123
			Anum_pg_amop_amopclaid,
			Anum_pg_amop_amopstrategy,
124 125
			0
		},
126
		sizeof(FormData_pg_amop),
127 128
		AccessMethodStrategyIndex,
	(ScanFunc) AccessMethodStrategyIndexScan},
129 130
	{AttributeRelationName,		/* ATTNAME */
		2,
131 132
		{
			Anum_pg_attribute_attrelid,
133 134
			Anum_pg_attribute_attname,
			0,
135 136
			0
		},
137
		ATTRIBUTE_TUPLE_SIZE,
138 139
		AttributeRelidNameIndex,
	AttributeRelidNameIndexScan},
140 141
	{AttributeRelationName,		/* ATTNUM */
		2,
142 143
		{
			Anum_pg_attribute_attrelid,
144 145
			Anum_pg_attribute_attnum,
			0,
146 147
			0
		},
148
		ATTRIBUTE_TUPLE_SIZE,
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
		AttributeRelidNumIndex,
	(ScanFunc) AttributeRelidNumIndexScan},
	{OperatorClassRelationName, /* CLADEFTYPE */
		1,
		{
			Anum_pg_opclass_opcdeftype,
			0,
			0,
			0
		},
		sizeof(FormData_pg_opclass),
		OpclassDeftypeIndex,
	OpclassDeftypeIndexScan},
	{OperatorClassRelationName, /* CLANAME */
		1,
		{
			Anum_pg_opclass_opcname,
			0,
			0,
			0
		},
		sizeof(FormData_pg_opclass),
		OpclassNameIndex,
	OpclassNameIndexScan},
	{GroupRelationName,			/* GRONAME */
		1,
		{
			Anum_pg_group_groname,
			0,
			0,
			0
		},
		offsetof(FormData_pg_group, grolist[0]),
		GroupNameIndex,
	GroupNameIndexScan},
	{GroupRelationName,			/* GROSYSID */
		1,
		{
			Anum_pg_group_grosysid,
			0,
			0,
			0
		},
		offsetof(FormData_pg_group, grolist[0]),
		GroupSysidIndex,
	GroupSysidIndexScan},
195 196
	{IndexRelationName,			/* INDEXRELID */
		1,
197 198
		{
			Anum_pg_index_indexrelid,
199 200
			0,
			0,
201 202
			0
		},
203
		offsetof(FormData_pg_index, indpred),
204
		IndexRelidIndex,
205 206 207 208 209 210 211 212 213 214 215 216 217
	IndexRelidIndexScan},
	{InheritsRelationName,		/* INHRELID */
		2,
		{
			Anum_pg_inherits_inhrelid,
			Anum_pg_inherits_inhseqno,
			0,
			0
		},
		sizeof(FormData_pg_inherits),
		InheritsRelidSeqnoIndex,
	InheritsRelidSeqnoIndexScan},
	{LanguageRelationName,		/* LANGNAME */
218
		1,
219 220
		{
			Anum_pg_language_lanname,
221 222
			0,
			0,
223 224
			0
		},
225
		offsetof(FormData_pg_language, lancompiler),
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
		LanguageNameIndex,
	LanguageNameIndexScan},
	{LanguageRelationName,		/* LANGOID */
		1,
		{
			ObjectIdAttributeNumber,
			0,
			0,
			0
		},
		offsetof(FormData_pg_language, lancompiler),
		LanguageOidIndex,
	LanguageOidIndexScan},
	{ListenerRelationName,		/* LISTENREL */
		2,
		{
			Anum_pg_listener_relname,
			Anum_pg_listener_pid,
			0,
			0
		},
		sizeof(FormData_pg_listener),
		ListenerRelnamePidIndex,
	ListenerRelnamePidIndexScan},
	{OperatorRelationName,		/* OPERNAME */
251
		4,
252 253
		{
			Anum_pg_operator_oprname,
254 255
			Anum_pg_operator_oprleft,
			Anum_pg_operator_oprright,
256 257
			Anum_pg_operator_oprkind
		},
258
		sizeof(FormData_pg_operator),
259 260 261
		OperatorNameIndex,
	(ScanFunc) OperatorNameIndexScan},
	{OperatorRelationName,		/* OPEROID */
262
		1,
263 264
		{
			ObjectIdAttributeNumber,
265 266
			0,
			0,
267 268
			0
		},
269
		sizeof(FormData_pg_operator),
270 271 272
		OperatorOidIndex,
	OperatorOidIndexScan},
	{ProcedureRelationName,		/* PROCNAME */
273
		3,
274 275
		{
			Anum_pg_proc_proname,
276 277
			Anum_pg_proc_pronargs,
			Anum_pg_proc_proargtypes,
278 279
			0
		},
280 281 282
		offsetof(FormData_pg_proc, prosrc),
		ProcedureNameIndex,
	(ScanFunc) ProcedureNameIndexScan},
283
	{ProcedureRelationName,		/* PROCOID */
284
		1,
285 286
		{
			ObjectIdAttributeNumber,
287 288
			0,
			0,
289 290
			0
		},
291 292
		offsetof(FormData_pg_proc, prosrc),
		ProcedureOidIndex,
293
	ProcedureOidIndexScan},
294 295
	{RelationRelationName,		/* RELNAME */
		1,
296 297
		{
			Anum_pg_class_relname,
298 299
			0,
			0,
300 301
			0
		},
302 303
		CLASS_TUPLE_SIZE,
		ClassNameIndex,
304
	ClassNameIndexScan},
305 306
	{RelationRelationName,		/* RELOID */
		1,
307 308
		{
			ObjectIdAttributeNumber,
309 310
			0,
			0,
311 312
			0
		},
313 314
		CLASS_TUPLE_SIZE,
		ClassOidIndex,
315 316
	ClassOidIndexScan},
	{RewriteRelationName,		/* REWRITENAME */
317
		1,
318
		{
319
			Anum_pg_rewrite_rulename,
320 321
			0,
			0,
322 323
			0
		},
324 325 326 327
		offsetof(FormData_pg_rewrite, ev_qual),
		RewriteRulenameIndex,
	RewriteRulenameIndexScan},
	{RewriteRelationName,		/* RULEOID */
328
		1,
329 330
		{
			ObjectIdAttributeNumber,
331 332
			0,
			0,
333 334
			0
		},
335 336 337
		offsetof(FormData_pg_rewrite, ev_qual),
		RewriteOidIndex,
	RewriteOidIndexScan},
338
	{ShadowRelationName,		/* SHADOWNAME */
339
		1,
340
		{
341
			Anum_pg_shadow_usename,
342 343
			0,
			0,
344 345
			0
		},
346 347 348 349 350
		sizeof(FormData_pg_shadow),
NULL,NULL
/*		ShadowNameIndex,
	ShadowNameIndexScan*/},
	{ShadowRelationName,		/* SHADOWSYSID */
351
		1,
352
		{
353
			Anum_pg_shadow_usesysid,
354 355
			0,
			0,
356 357
			0
		},
358 359 360 361 362 363 364 365 366 367 368 369 370 371
		sizeof(FormData_pg_shadow),
NULL,NULL
/*		ShadowSysidIndex,
	ShadowSysidIndexScan*/},
	{StatisticRelationName,		/* STATRELID */
		3,
		{
			Anum_pg_statistic_starelid,
			Anum_pg_statistic_staattnum,
			Anum_pg_statistic_staop,
			0
		},
		offsetof(FormData_pg_statistic, stacommonval),
		StatisticRelidAttnumOpIndex,
372
	(ScanFunc) StatisticRelidAttnumOpIndexScan},
373
	{TypeRelationName,			/* TYPENAME */
374
		1,
375
		{
376
			Anum_pg_type_typname,
377 378
			0,
			0,
379 380
			0
		},
381 382 383 384
		offsetof(FormData_pg_type, typalign) +sizeof(char),
		TypeNameIndex,
	TypeNameIndexScan},
	{TypeRelationName,			/* TYPEOID */
385
		1,
386
		{
387
			ObjectIdAttributeNumber,
388 389
			0,
			0,
390 391
			0
		},
392 393 394
		offsetof(FormData_pg_type, typalign) +sizeof(char),
		TypeOidIndex,
	TypeOidIndexScan}
395
};
396

397
static struct catcache *SysCache[lengthof(cacheinfo)];
398
static int32 SysCacheSize = lengthof(cacheinfo);
399 400


401
/*
402
 * zerocaches
403
 *
404
 *	  Make sure the SysCache structure is zero'd.
405 406 407 408
 */
void
zerocaches()
{
Bruce Momjian's avatar
Bruce Momjian committed
409
	MemSet((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
410 411 412 413
}

/*
 * Note:
414 415 416
 *		This function was written because the initialized catalog caches
 *		are used to determine which caches may contain tuples which need
 *		to be invalidated in other backends.
417 418 419 420
 */
void
InitCatalogCache()
{
421
	int			cacheId;		/* XXX type */
422 423 424 425 426 427 428 429

	if (!AMI_OVERRIDE)
	{
		for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
		{

			Assert(!PointerIsValid((Pointer) SysCache[cacheId]));

430
			SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
Bruce Momjian's avatar
Bruce Momjian committed
431 432 433 434 435
											 cacheinfo[cacheId].indname,
											 cacheId,
											 cacheinfo[cacheId].nkeys,
											 cacheinfo[cacheId].key,
										   cacheinfo[cacheId].iScanFunc);
436 437
			if (!PointerIsValid((char *) SysCache[cacheId]))
			{
438
				elog(ERROR,
439
					 "InitCatalogCache: Can't init cache %s(%d)",
440 441 442 443 444
					 cacheinfo[cacheId].name,
					 cacheId);
			}

		}
445 446
	}
}
447

448
/*
449
 * SearchSysCacheTupleCopy
450
 *
451
 *	This is like SearchSysCacheTuple, except it returns a copy of the tuple
452 453 454
 *	that the user is required to pfree().
 */
HeapTuple
455 456 457 458 459
SearchSysCacheTupleCopy(int cacheId,	/* cache selection code */
						Datum key1,
						Datum key2,
						Datum key3,
						Datum key4)
460 461 462 463 464 465 466
{
	HeapTuple	cachetup;

	cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
	if (PointerIsValid(cachetup))
		return heap_copytuple(cachetup);
	else
467
		return cachetup;		/* NULL */
468
}
469

470 471

/*
472
 * SearchSysCacheTuple
473
 *
474 475
 *	A layer on top of SearchSysCache that does the initialization and
 *	key-setting for you.
476
 *
477 478
 *	Returns the cache copy of the tuple if one is found, NULL if not.
 *	The tuple is the 'cache' copy.
479
 *
480
 *	XXX The tuple that is returned is NOT supposed to be pfree'd!
481 482
 */
HeapTuple
483
SearchSysCacheTuple(int cacheId,/* cache selection code */
484 485 486 487
					Datum key1,
					Datum key2,
					Datum key3,
					Datum key4)
488
{
489
	HeapTuple	tp;
490 491 492

	if (cacheId < 0 || cacheId >= SysCacheSize)
	{
493
		elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
494
		return (HeapTuple) NULL;
495 496
	}

497 498 499
	Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));

	if (!PointerIsValid(SysCache[cacheId]))
500
	{
501
		SysCache[cacheId] = InitSysCache(cacheinfo[cacheId].name,
Bruce Momjian's avatar
Bruce Momjian committed
502 503 504 505 506
										 cacheinfo[cacheId].indname,
										 cacheId,
										 cacheinfo[cacheId].nkeys,
										 cacheinfo[cacheId].key,
										 cacheinfo[cacheId].iScanFunc);
507
		if (!PointerIsValid(SysCache[cacheId]))
508
			elog(ERROR,
509
				 "InitCatalogCache: Can't init cache %s(%d)",
510 511
				 cacheinfo[cacheId].name,
				 cacheId);
512
	}
513

514 515 516 517 518 519
	/* temp table name remapping */
	if (cacheId == RELNAME)
	{
		char *nontemp_relname;

		if ((nontemp_relname =
520
			 get_temp_rel_by_username(DatumGetPointer(key1))) != NULL)
521 522 523
			key1 = PointerGetDatum(nontemp_relname);
	}
	
524 525 526
	tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
	if (!HeapTupleIsValid(tp))
	{
527
#ifdef CACHEDEBUG
528 529
		elog(DEBUG,
			 "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
530
			 cacheinfo[cacheId].name,
531
			 cacheId, key1, key2, key3, key4);
532
#endif
533
		return (HeapTuple) NULL;
534
	}
535
	return tp;
536 537 538 539
}


/*
540 541 542 543
 * SysCacheGetAttr
 *
 *		Given a tuple previously fetched by SearchSysCacheTuple() or
 *		SearchSysCacheTupleCopy(), extract a specific attribute.
544
 *
545 546 547 548 549
 * This is equivalent to using heap_getattr() on a tuple fetched
 * from a non-cached relation.  Usually, this is only used for attributes
 * 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/.
550
 *
551 552 553
 * 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!
554
 */
555 556 557 558
Datum
SysCacheGetAttr(int cacheId, HeapTuple tup,
				AttrNumber attributeNumber,
				bool *isnull)
559
{
560
	/*
561 562 563 564
	 * 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 is currently valid --- if the caller just fetched
	 * the tuple, then it should be.
565
	 */
566 567 568 569 570 571 572 573 574 575
	if (cacheId < 0 || cacheId >= SysCacheSize)
		elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId);
	if (! PointerIsValid(SysCache[cacheId]) ||
		SysCache[cacheId]->relationId == InvalidOid ||
		! PointerIsValid(SysCache[cacheId]->cc_tupdesc))
		elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId);

	return heap_getattr(tup, attributeNumber,
						SysCache[cacheId]->cc_tupdesc,
						isnull);
576
}