relcache.c 77 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * relcache.c
4
 *	  POSTGRES relation descriptor cache code
5
 *
6
 * Portions Copyright (c) 1996-2001, 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/relcache.c,v 1.133 2001/05/14 21:53:16 momjian Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
17 18
 *		RelationCacheInitialize			- initialize relcache
 *		RelationCacheInitializePhase2	- finish initializing relcache
19 20 21 22 23
 *		RelationIdCacheGetRelation		- get a reldesc from the cache (id)
 *		RelationNameCacheGetRelation	- get a reldesc from the cache (name)
 *		RelationIdGetRelation			- get a reldesc by relation id
 *		RelationNameGetRelation			- get a reldesc by relation name
 *		RelationClose					- close an open relation
24 25
 *
 * NOTES
26 27
 *		The following code contains many undocumented hacks.  Please be
 *		careful....
28 29
 *
 */
30 31
#include "postgres.h"

32
#include <sys/types.h>
33 34
#include <errno.h>
#include <sys/file.h>
35
#include <fcntl.h>
36
#include <unistd.h>
37

38 39 40 41
#include "access/genam.h"
#include "access/heapam.h"
#include "access/istrat.h"
#include "catalog/catalog.h"
Bruce Momjian's avatar
Bruce Momjian committed
42 43 44 45
#include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_attrdef.h"
46
#include "catalog/pg_index.h"
Bruce Momjian's avatar
Bruce Momjian committed
47
#include "catalog/pg_log.h"
Bruce Momjian's avatar
Bruce Momjian committed
48
#include "catalog/pg_proc.h"
Bruce Momjian's avatar
Bruce Momjian committed
49
#include "catalog/pg_relcheck.h"
50 51 52
#include "catalog/pg_rewrite.h"
#include "catalog/pg_type.h"
#include "catalog/pg_variable.h"
53
#include "commands/trigger.h"
Bruce Momjian's avatar
Bruce Momjian committed
54 55 56
#include "lib/hasht.h"
#include "miscadmin.h"
#include "storage/smgr.h"
57
#include "utils/builtins.h"
Bruce Momjian's avatar
Bruce Momjian committed
58
#include "utils/catcache.h"
59
#include "utils/fmgroids.h"
60
#include "utils/memutils.h"
Bruce Momjian's avatar
Bruce Momjian committed
61
#include "utils/relcache.h"
62
#include "utils/temprel.h"
Bruce Momjian's avatar
Bruce Momjian committed
63

64

65
/*
66
 *		hardcoded tuple descriptors.  see lib/backend/catalog/pg_attribute.h
67
 *
68
 */
69 70 71 72 73
static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
static FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};
static FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};
static FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log};
74

75
/*
76
 *		Hash tables that index the relation cache
77
 *
78
 *		Relations are looked up two ways, by name and by id,
79
 *		thus there are two hash tables for referencing them.
80
 *
81
 */
82 83
static HTAB *RelationNameCache;
static HTAB *RelationIdCache;
84

85 86 87 88 89 90 91
/*
 * Bufmgr uses RelFileNode for lookup. Actually, I would like to do
 * not pass Relation to bufmgr & beyond at all and keep some cache
 * in smgr, but no time to do it right way now.		-- vadim 10/22/2000
 */
static HTAB *RelationNodeCache;

92 93 94 95 96 97 98
/*
 * newlyCreatedRelns -
 *	  relations created during this transaction. We need to keep track of
 *	  these.
 */
static List *newlyCreatedRelns = NULL;

99 100 101 102 103 104
/*
 * This flag is false until we have prepared the critical relcache entries
 * that are needed to do indexscans on the tables read by relcache building.
 */
static bool criticalRelcachesBuilt = false;

105

106
/*
107 108
 *		RelationBuildDescInfo exists so code can be shared
 *		between RelationIdGetRelation() and RelationNameGetRelation()
109
 *
110
 */
111 112
typedef struct RelationBuildDescInfo
{
113
	int			infotype;		/* lookup by id or by name */
114 115
#define INFO_RELID 1
#define INFO_RELNAME 2
116 117
	union
	{
118 119 120
		Oid			info_id;	/* relation object id */
		char	   *info_name;	/* relation name */
	}			i;
121
} RelationBuildDescInfo;
122

123 124 125 126 127 128
typedef struct relnamecacheent
{
	NameData	relname;
	Relation	reldesc;
} RelNameCacheEnt;

129 130
typedef struct relidcacheent
{
131 132
	Oid			reloid;
	Relation	reldesc;
133
} RelIdCacheEnt;
134

135
typedef struct relnodecacheent
136
{
137
	RelFileNode relnode;
138
	Relation	reldesc;
139
} RelNodeCacheEnt;
140

141
/*
142
 *		macros to manipulate name cache and id cache
143
 *
144 145
 */
#define RelationCacheInsert(RELATION)	\
146 147
do { \
	RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
148
	char *relname; RelNodeCacheEnt *nodentry; bool found; \
149
	relname = RelationGetPhysicalRelationName(RELATION); \
150 151
	namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
											   relname, \
152 153
											   HASH_ENTER, \
											   &found); \
154 155 156 157 158 159
	if (namehentry == NULL) \
		elog(FATAL, "can't insert into relation descriptor cache"); \
	if (found && !IsBootstrapProcessingMode()) \
		/* used to give notice -- now just keep quiet */ ; \
	namehentry->reldesc = RELATION; \
	idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
160
										   (char *)&(RELATION->rd_id), \
161 162 163 164 165 166 167
										   HASH_ENTER, \
										   &found); \
	if (idhentry == NULL) \
		elog(FATAL, "can't insert into relation descriptor cache"); \
	if (found && !IsBootstrapProcessingMode()) \
		/* used to give notice -- now just keep quiet */ ; \
	idhentry->reldesc = RELATION; \
168 169 170 171 172 173 174 175 176
	nodentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \
										   (char *)&(RELATION->rd_node), \
										   HASH_ENTER, \
										   &found); \
	if (nodentry == NULL) \
		elog(FATAL, "can't insert into relation descriptor cache"); \
	if (found && !IsBootstrapProcessingMode()) \
		/* used to give notice -- now just keep quiet */ ; \
	nodentry->reldesc = RELATION; \
177 178
} while(0)

179
#define RelationNameCacheLookup(NAME, RELATION) \
180 181 182 183 184 185 186 187 188 189 190 191
do { \
	RelNameCacheEnt *hentry; bool found; \
	hentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
										   (char *)NAME,HASH_FIND,&found); \
	if (hentry == NULL) \
		elog(FATAL, "error in CACHE"); \
	if (found) \
		RELATION = hentry->reldesc; \
	else \
		RELATION = NULL; \
} while(0)

192
#define RelationIdCacheLookup(ID, RELATION) \
193 194 195 196 197 198 199 200 201 202 203 204 205
do { \
	RelIdCacheEnt *hentry; \
	bool found; \
	hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
										 (char *)&(ID),HASH_FIND, &found); \
	if (hentry == NULL) \
		elog(FATAL, "error in CACHE"); \
	if (found) \
		RELATION = hentry->reldesc; \
	else \
		RELATION = NULL; \
} while(0)

206 207 208 209 210 211 212 213 214 215 216 217 218 219
#define RelationNodeCacheLookup(NODE, RELATION) \
do { \
	RelNodeCacheEnt *hentry; \
	bool found; \
	hentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \
									 (char *)&(NODE),HASH_FIND, &found); \
	if (hentry == NULL) \
		elog(FATAL, "error in CACHE"); \
	if (found) \
		RELATION = hentry->reldesc; \
	else \
		RELATION = NULL; \
} while(0)

220 221 222
#define RelationCacheDelete(RELATION) \
do { \
	RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
223
	char *relname; RelNodeCacheEnt *nodentry; bool found; \
224
	relname = RelationGetPhysicalRelationName(RELATION); \
225 226 227 228 229 230 231 232 233
	namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
											   relname, \
											   HASH_REMOVE, \
											   &found); \
	if (namehentry == NULL) \
		elog(FATAL, "can't delete from relation descriptor cache"); \
	if (!found) \
		elog(NOTICE, "trying to delete a reldesc that does not exist."); \
	idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
234
										   (char *)&(RELATION->rd_id), \
235 236 237 238 239
										   HASH_REMOVE, &found); \
	if (idhentry == NULL) \
		elog(FATAL, "can't delete from relation descriptor cache"); \
	if (!found) \
		elog(NOTICE, "trying to delete a reldesc that does not exist."); \
240 241 242 243 244 245 246
	nodentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \
										   (char *)&(RELATION->rd_node), \
										   HASH_REMOVE, &found); \
	if (nodentry == NULL) \
		elog(FATAL, "can't delete from relation descriptor cache"); \
	if (!found) \
		elog(NOTICE, "trying to delete a reldesc that does not exist."); \
247
} while(0)
248

249
/* non-export function prototypes */
250 251

static void RelationClearRelation(Relation relation, bool rebuildIt);
252

Hiroshi Inoue's avatar
Hiroshi Inoue committed
253 254
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
static void RelationReloadClassinfo(Relation relation);
255 256

#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
257
static void RelationFlushRelation(Relation relation);
258
static Relation RelationNameCacheGetRelation(const char *relationName);
259 260
static void RelationCacheInvalidateWalker(Relation *relationPtr, Datum listp);
static void RelationCacheAbortWalker(Relation *relationPtr, Datum dummy);
261 262 263
static void init_irels(void);
static void write_irels(void);

264
static void formrdesc(char *relationName, int natts,
265
		  FormData_pg_attribute *att);
266
static void fixrdesc(char *relationName);
267

268 269 270
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
271
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
272
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
273
					   Relation relation);
274
static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
275
				  Relation relation);
276
static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
277
				  Relation relation);
278
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
279
				  Relation oldrelation);
280 281 282
static void IndexedAccessMethodInitialize(Relation relation);
static void AttrDefaultFetch(Relation relation);
static void RelCheckFetch(Relation relation);
283
static List *insert_ordered_oid(List *list, Oid datum);
284

285

286
/*
287 288
 *		RelationIdGetRelation() and RelationNameGetRelation()
 *						support functions
289
 *
290 291
 */

292

293
/*
294
 *		ScanPgRelation
295
 *
296 297 298
 *		this is used by RelationBuildDesc to find a pg_class
 *		tuple matching either a relation name or a relation id
 *		as specified in buildinfo.
299 300 301
 *
 *		NB: the returned tuple has been copied into palloc'd storage
 *		and must eventually be freed with heap_freetuple.
302
 *
303
 */
304
static HeapTuple
305 306
ScanPgRelation(RelationBuildDescInfo buildinfo)
{
307 308 309 310 311 312 313

	/*
	 * If this is bootstrap time (initdb), then we can't use the system
	 * catalog indices, because they may not exist yet.  Otherwise, we
	 * can, and do.
	 */

314
	if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
315
		return scan_pg_rel_seq(buildinfo);
316
	else
317
		return scan_pg_rel_ind(buildinfo);
318 319
}

320
static HeapTuple
321 322
scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
{
323 324 325 326 327
	HeapTuple	pg_class_tuple;
	HeapTuple	return_tuple;
	Relation	pg_class_desc;
	HeapScanDesc pg_class_scan;
	ScanKeyData key;
328

329
	/*
330
	 * form a scan key
331
	 *
332
	 */
333 334
	switch (buildinfo.infotype)
	{
335 336 337
		case INFO_RELID:
			ScanKeyEntryInitialize(&key, 0,
								   ObjectIdAttributeNumber,
Bruce Momjian's avatar
Bruce Momjian committed
338
								   F_OIDEQ,
339 340 341 342 343 344
								   ObjectIdGetDatum(buildinfo.i.info_id));
			break;

		case INFO_RELNAME:
			ScanKeyEntryInitialize(&key, 0,
								   Anum_pg_class_relname,
Bruce Momjian's avatar
Bruce Momjian committed
345
								   F_NAMEEQ,
346 347 348 349
								   NameGetDatum(buildinfo.i.info_name));
			break;

		default:
350
			elog(ERROR, "ScanPgRelation: bad buildinfo");
351
			return NULL;
352 353
	}

354
	/*
355
	 * open pg_class and fetch a tuple
356
	 *
357
	 */
358
	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
359 360
	pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
	pg_class_tuple = heap_getnext(pg_class_scan, 0);
361

362
	/*
363
	 * get set to return tuple
364
	 *
365 366 367 368 369
	 */
	if (!HeapTupleIsValid(pg_class_tuple))
		return_tuple = pg_class_tuple;
	else
	{
370

371
		/*
372 373 374 375
		 * a satanic bug used to live here: pg_class_tuple used to be
		 * returned here without having the corresponding buffer pinned.
		 * so when the buffer gets replaced, all hell breaks loose. this
		 * bug is discovered and killed by wei on 9/27/91.
376
		 *
377
		 */
378
		return_tuple = heap_copytuple(pg_class_tuple);
379 380 381 382
	}

	/* all done */
	heap_endscan(pg_class_scan);
383
	heap_close(pg_class_desc, AccessShareLock);
384 385

	return return_tuple;
386 387
}

388
static HeapTuple
389 390
scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
{
391 392
	Relation	pg_class_desc;
	HeapTuple	return_tuple;
393

394
	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
395

Hiroshi Inoue's avatar
Hiroshi Inoue committed
396
	/*
397 398
	 * If the indexes of pg_class are deactivated we have to call
	 * scan_pg_rel_seq() instead.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
399 400 401 402 403 404
	 */
	if (!pg_class_desc->rd_rel->relhasindex)
	{
		heap_close(pg_class_desc, AccessShareLock);
		return scan_pg_rel_seq(buildinfo);
	}
405 406 407

	switch (buildinfo.infotype)
	{
408
		case INFO_RELID:
409
			return_tuple = ClassOidIndexScan(pg_class_desc,
410
								  ObjectIdGetDatum(buildinfo.i.info_id));
411
			break;
412

413 414
		case INFO_RELNAME:
			return_tuple = ClassNameIndexScan(pg_class_desc,
415
								 PointerGetDatum(buildinfo.i.info_name));
416
			break;
417

418
		default:
419
			elog(ERROR, "ScanPgRelation: bad buildinfo");
420
			return_tuple = NULL;/* keep compiler quiet */
421 422
	}

423
	heap_close(pg_class_desc, AccessShareLock);
424

425 426
	/* The xxxIndexScan routines will have returned a palloc'd tuple. */

427
	return return_tuple;
428 429
}

430
/*
431
 *		AllocateRelationDesc
432
 *
433 434
 *		This is used to allocate memory for a new relation descriptor
 *		and initialize the rd_rel field.
435 436 437
 *
 *		If 'relation' is NULL, allocate a new RelationData object.
 *		If not, reuse the given object (that path is taken only when
438
 *		we have to rebuild a relcache entry during RelationClearRelation).
439
 *
440
 */
441
static Relation
442
AllocateRelationDesc(Relation relation, Form_pg_class relp)
443
{
444
	MemoryContext oldcxt;
445
	Form_pg_class relationForm;
446

447 448
	/* Relcache entries must live in CacheMemoryContext */
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
449

450
	/*
451
	 * allocate space for new relation descriptor, if needed
452
	 *
453
	 */
454
	if (relation == NULL)
455
		relation = (Relation) palloc(sizeof(RelationData));
456

457
	/*
458
	 * clear all fields of reldesc
459
	 *
460
	 */
461
	MemSet((char *) relation, 0, sizeof(RelationData));
462

463 464 465
	/* make sure relation is marked as having no open file yet */
	relation->rd_fd = -1;

466
	/*
467
	 * Copy the relation tuple form
468
	 *
469 470 471 472 473 474
	 * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.
	 * relacl is NOT stored in the relcache --- there'd be little point in
	 * it, since we don't copy the tuple's nullvalues bitmap and hence
	 * wouldn't know if the value is valid ... bottom line is that relacl
	 * *cannot* be retrieved from the relcache.  Get it from the syscache
	 * if you need it.
475
	 *
476 477
	 */
	relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
478

479 480 481
	memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);

	/* initialize relation tuple form */
482
	relation->rd_rel = relationForm;
483

484 485 486 487 488
	/* and allocate attribute tuple form storage */
	relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);

	MemoryContextSwitchTo(oldcxt);

489
	return relation;
490 491
}

492
/*
493
 *		RelationBuildTupleDesc
494
 *
495 496
 *		Form the relation's tuple descriptor from information in
 *		the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
497
 *
498 499
 */
static void
500
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
501
					   Relation relation)
502
{
503 504 505 506 507 508 509

	/*
	 * If this is bootstrap time (initdb), then we can't use the system
	 * catalog indices, because they may not exist yet.  Otherwise, we
	 * can, and do.
	 */

510 511
	if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
		build_tupdesc_seq(buildinfo, relation);
512
	else
513
		build_tupdesc_ind(buildinfo, relation);
514 515
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
516
static void
517 518 519 520
SetConstrOfRelation(Relation relation,
					TupleConstr *constr,
					int ndef,
					AttrDefault *attrdef)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
{
	if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
	{
		relation->rd_att->constr = constr;

		if (ndef > 0)			/* DEFAULTs */
		{
			if (ndef < relation->rd_rel->relnatts)
				constr->defval = (AttrDefault *)
					repalloc(attrdef, ndef * sizeof(AttrDefault));
			else
				constr->defval = attrdef;
			constr->num_defval = ndef;
			AttrDefaultFetch(relation);
		}
		else
			constr->num_defval = 0;

		if (relation->rd_rel->relchecks > 0)	/* CHECKs */
		{
			constr->num_check = relation->rd_rel->relchecks;
542 543
			constr->check = (ConstrCheck *)
				MemoryContextAlloc(CacheMemoryContext,
544
								constr->num_check * sizeof(ConstrCheck));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
545 546 547 548 549 550 551 552 553 554 555 556 557
			MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
			RelCheckFetch(relation);
		}
		else
			constr->num_check = 0;
	}
	else
	{
		pfree(constr);
		relation->rd_att->constr = NULL;
	}
}

558 559
static void
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
560
				  Relation relation)
561
{
562 563 564
	HeapTuple	pg_attribute_tuple;
	Relation	pg_attribute_desc;
	HeapScanDesc pg_attribute_scan;
565
	Form_pg_attribute attp;
566 567
	ScanKeyData key;
	int			need;
568
	TupleConstr *constr;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
569
	AttrDefault *attrdef = NULL;
570
	int			ndef = 0;
571

572 573
	constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
												sizeof(TupleConstr));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
574
	constr->has_not_null = false;
575

576
	/*
577
	 * form a scan key
578
	 *
579 580 581
	 */
	ScanKeyEntryInitialize(&key, 0,
						   Anum_pg_attribute_attrelid,
Bruce Momjian's avatar
Bruce Momjian committed
582
						   F_OIDEQ,
583
						   ObjectIdGetDatum(RelationGetRelid(relation)));
584

585
	/*
586
	 * open pg_attribute and begin a scan
587
	 *
588
	 */
589
	pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock);
590
	pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
591

592
	/*
593
	 * add attribute data to relation->rd_att
594
	 *
595
	 */
596
	need = relation->rd_rel->relnatts;
597

598
	pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
599 600
	while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
	{
601
		attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
602 603 604 605

		if (attp->attnum > 0)
		{
			relation->rd_att->attrs[attp->attnum - 1] =
606
				(Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
607
												   ATTRIBUTE_TUPLE_SIZE);
608

609 610 611
			memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
				   (char *) attp,
				   ATTRIBUTE_TUPLE_SIZE);
612
			need--;
613

Hiroshi Inoue's avatar
Hiroshi Inoue committed
614 615 616 617 618 619 620 621
			/* Update if this attribute have a constraint */
			if (attp->attnotnull)
				constr->has_not_null = true;

			if (attp->atthasdef)
			{
				if (attrdef == NULL)
				{
622 623 624 625
					attrdef = (AttrDefault *)
						MemoryContextAlloc(CacheMemoryContext,
										   relation->rd_rel->relnatts *
										   sizeof(AttrDefault));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
626
					MemSet(attrdef, 0,
627
					   relation->rd_rel->relnatts * sizeof(AttrDefault));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
628 629 630 631 632
				}
				attrdef[ndef].adnum = attp->attnum;
				attrdef[ndef].adbin = NULL;
				ndef++;
			}
633
		}
634
		pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
635
	}
636 637

	if (need > 0)
638
		elog(ERROR, "catalog is missing %d attribute%s for relid %u",
639
			 need, (need == 1 ? "" : "s"), RelationGetRelid(relation));
640

641
	/*
642
	 * end the scan and close the attribute relation
643
	 *
644 645
	 */
	heap_endscan(pg_attribute_scan);
646
	heap_close(pg_attribute_desc, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
647

648
	/*
649 650 651
	 * The attcacheoff values we read from pg_attribute should all be -1
	 * ("unknown").  Verify this if assert checking is on.	They will be
	 * computed when and if needed during tuple access.
652
	 *
653 654 655
	 */
#ifdef USE_ASSERT_CHECKING
	{
656
		int			i;
657 658 659 660 661 662

		for (i = 0; i < relation->rd_rel->relnatts; i++)
			Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
	}
#endif

663
	/*
664 665 666 667
	 * However, we can easily set the attcacheoff value for the first
	 * attribute: it must be zero.	This eliminates the need for special
	 * cases for attnum=1 that used to exist in fastgetattr() and
	 * index_getattr().
668
	 *
669 670 671
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
672
	SetConstrOfRelation(relation, constr, ndef, attrdef);
673 674 675 676
}

static void
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
677
				  Relation relation)
678
{
679 680
	Relation	attrel;
	HeapTuple	atttup;
681
	Form_pg_attribute attp;
682
	TupleConstr *constr;
683 684 685
	AttrDefault *attrdef = NULL;
	int			ndef = 0;
	int			i;
686

687 688
	constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
												sizeof(TupleConstr));
689 690
	constr->has_not_null = false;

691
	attrel = heap_openr(AttributeRelationName, AccessShareLock);
692 693

	for (i = 1; i <= relation->rd_rel->relnatts; i++)
694
	{
695
#ifdef	_DROP_COLUMN_HACK__
696
		bool		columnDropped = false;
697

698
#endif	 /* _DROP_COLUMN_HACK__ */
699

700
		atttup = AttributeRelidNumIndexScan(attrel,
701
							ObjectIdGetDatum(RelationGetRelid(relation)),
702
											Int32GetDatum(i));
703 704

		if (!HeapTupleIsValid(atttup))
705
		{
706
#ifdef	_DROP_COLUMN_HACK__
707
			atttup = AttributeRelidNumIndexScan(attrel,
708 709
							ObjectIdGetDatum(RelationGetRelid(relation)),
								 Int32GetDatum(DROPPED_COLUMN_INDEX(i)));
710
			if (!HeapTupleIsValid(atttup))
711 712 713
#endif	 /* _DROP_COLUMN_HACK__ */
				elog(ERROR, "cannot find attribute %d of relation %s", i,
					 RelationGetRelationName(relation));
714 715
#ifdef	_DROP_COLUMN_HACK__
			columnDropped = true;
716
#endif	 /* _DROP_COLUMN_HACK__ */
717
		}
718

719
		relation->rd_att->attrs[i - 1] = attp =
720 721
			(Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
												   ATTRIBUTE_TUPLE_SIZE);
722

723 724 725 726 727 728
		memcpy((char *) attp,
			   (char *) (Form_pg_attribute) GETSTRUCT(atttup),
			   ATTRIBUTE_TUPLE_SIZE);

		/* don't forget to free the tuple returned from xxxIndexScan */
		heap_freetuple(atttup);
729

730 731 732
#ifdef	_DROP_COLUMN_HACK__
		if (columnDropped)
			continue;
733
#endif	 /* _DROP_COLUMN_HACK__ */
734

735 736 737 738 739 740 741
		/* Update if this attribute have a constraint */
		if (attp->attnotnull)
			constr->has_not_null = true;

		if (attp->atthasdef)
		{
			if (attrdef == NULL)
742
			{
743 744 745 746
				attrdef = (AttrDefault *)
					MemoryContextAlloc(CacheMemoryContext,
									   relation->rd_rel->relnatts *
									   sizeof(AttrDefault));
747 748 749
				MemSet(attrdef, 0,
					   relation->rd_rel->relnatts * sizeof(AttrDefault));
			}
750 751 752 753
			attrdef[ndef].adnum = i;
			attrdef[ndef].adbin = NULL;
			ndef++;
		}
754
	}
755

756
	heap_close(attrel, AccessShareLock);
757

758
	/*
759 760 761
	 * The attcacheoff values we read from pg_attribute should all be -1
	 * ("unknown").  Verify this if assert checking is on.	They will be
	 * computed when and if needed during tuple access.
762
	 *
763 764 765 766 767 768
	 */
#ifdef USE_ASSERT_CHECKING
	for (i = 0; i < relation->rd_rel->relnatts; i++)
		Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
#endif

769
	/*
770 771 772 773
	 * However, we can easily set the attcacheoff value for the first
	 * attribute: it must be zero.	This eliminates the need for special
	 * cases for attnum=1 that used to exist in fastgetattr() and
	 * index_getattr().
774
	 *
775 776 777
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
778
	SetConstrOfRelation(relation, constr, ndef, attrdef);
779 780
}

781
/*
782
 *		RelationBuildRuleLock
783
 *
784 785
 *		Form the relation's rewrite rules from information in
 *		the pg_rewrite system catalog.
786 787 788 789 790 791 792
 *
 * Note: The rule parsetrees are potentially very complex node structures.
 * To allow these trees to be freed when the relcache entry is flushed,
 * we make a private memory context to hold the RuleLock information for
 * each relcache entry that has associated rules.  The context is used
 * just for rule info, not for any other subsidiary data of the relcache
 * entry, because that keeps the update logic in RelationClearRelation()
793
 * manageable.	The other subsidiary data structures are simple enough
794
 * to be easy to free explicitly, anyway.
795
 *
796 797 798 799
 */
static void
RelationBuildRuleLock(Relation relation)
{
800 801
	MemoryContext rulescxt;
	MemoryContext oldcxt;
802 803 804 805 806 807 808 809 810
	HeapTuple	pg_rewrite_tuple;
	Relation	pg_rewrite_desc;
	TupleDesc	pg_rewrite_tupdesc;
	HeapScanDesc pg_rewrite_scan;
	ScanKeyData key;
	RuleLock   *rulelock;
	int			numlocks;
	RewriteRule **rules;
	int			maxlocks;
811

812 813 814 815 816 817
	/*
	 * Make the private context.  Parameters are set on the assumption
	 * that it'll probably not contain much data.
	 */
	rulescxt = AllocSetContextCreate(CacheMemoryContext,
									 RelationGetRelationName(relation),
818 819 820
									 0, /* minsize */
									 1024,		/* initsize */
									 1024);		/* maxsize */
821 822
	relation->rd_rulescxt = rulescxt;

823
	/*
824 825
	 * form an array to hold the rewrite rules (the array is extended if
	 * necessary)
826
	 *
827 828
	 */
	maxlocks = 4;
829 830
	rules = (RewriteRule **)
		MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
831 832
	numlocks = 0;

833
	/*
834
	 * form a scan key
835
	 *
836 837 838
	 */
	ScanKeyEntryInitialize(&key, 0,
						   Anum_pg_rewrite_ev_class,
Bruce Momjian's avatar
Bruce Momjian committed
839
						   F_OIDEQ,
840
						   ObjectIdGetDatum(RelationGetRelid(relation)));
841

842
	/*
843
	 * open pg_rewrite and begin a scan
844
	 *
845
	 */
846
	pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
847
	pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key);
848
	pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
849

850
	while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
851
	{
852
		bool		isnull;
853
		Datum		ruleaction;
854 855 856
		Datum		rule_evqual;
		char	   *ruleaction_str;
		char	   *rule_evqual_str;
857
		RewriteRule *rule;
858

859 860
		rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
												  sizeof(RewriteRule));
861

862
		rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
863

864 865 866 867 868 869 870 871 872
		rule->event = DatumGetInt32(heap_getattr(pg_rewrite_tuple,
												 Anum_pg_rewrite_ev_type,
												 pg_rewrite_tupdesc,
												 &isnull)) - 48;
		rule->attrno = DatumGetInt16(heap_getattr(pg_rewrite_tuple,
												  Anum_pg_rewrite_ev_attr,
												  pg_rewrite_tupdesc,
												  &isnull));
		rule->isInstead = DatumGetBool(heap_getattr(pg_rewrite_tuple,
873
											  Anum_pg_rewrite_is_instead,
874 875
													pg_rewrite_tupdesc,
													&isnull));
876

877
		ruleaction = heap_getattr(pg_rewrite_tuple,
878 879
								  Anum_pg_rewrite_ev_action,
								  pg_rewrite_tupdesc,
Bruce Momjian's avatar
Bruce Momjian committed
880
								  &isnull);
881
		Assert(!isnull);
Tom Lane's avatar
Tom Lane committed
882 883
		ruleaction_str = DatumGetCString(DirectFunctionCall1(textout,
															 ruleaction));
884
		oldcxt = MemoryContextSwitchTo(rulescxt);
885
		rule->actions = (List *) stringToNode(ruleaction_str);
886
		MemoryContextSwitchTo(oldcxt);
887 888 889 890 891 892
		pfree(ruleaction_str);

		rule_evqual = heap_getattr(pg_rewrite_tuple,
								   Anum_pg_rewrite_ev_qual,
								   pg_rewrite_tupdesc,
								   &isnull);
893
		Assert(!isnull);
Tom Lane's avatar
Tom Lane committed
894
		rule_evqual_str = DatumGetCString(DirectFunctionCall1(textout,
895
														   rule_evqual));
896
		oldcxt = MemoryContextSwitchTo(rulescxt);
897
		rule->qual = (Node *) stringToNode(rule_evqual_str);
898
		MemoryContextSwitchTo(oldcxt);
899 900 901
		pfree(rule_evqual_str);

		if (numlocks >= maxlocks)
902 903
		{
			maxlocks *= 2;
904 905
			rules = (RewriteRule **)
				repalloc(rules, sizeof(RewriteRule *) * maxlocks);
906
		}
907
		rules[numlocks++] = rule;
908
	}
909

910
	/*
911
	 * end the scan and close the attribute relation
912
	 *
913 914
	 */
	heap_endscan(pg_rewrite_scan);
915
	heap_close(pg_rewrite_desc, AccessShareLock);
916

917
	/*
918
	 * form a RuleLock and insert into relation
919
	 *
920
	 */
921
	rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
922 923 924 925
	rulelock->numLocks = numlocks;
	rulelock->rules = rules;

	relation->rd_rules = rulelock;
926 927
}

928
/*
929 930 931 932 933
 *		equalRuleLocks
 *
 *		Determine whether two RuleLocks are equivalent
 *
 *		Probably this should be in the rules code someplace...
934
 *
935 936 937 938
 */
static bool
equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
{
939 940
	int			i,
				j;
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972

	if (rlock1 != NULL)
	{
		if (rlock2 == NULL)
			return false;
		if (rlock1->numLocks != rlock2->numLocks)
			return false;
		for (i = 0; i < rlock1->numLocks; i++)
		{
			RewriteRule *rule1 = rlock1->rules[i];
			RewriteRule *rule2 = NULL;

			/*
			 * We can't assume that the rules are always read from
			 * pg_rewrite in the same order; so use the rule OIDs to
			 * identify the rules to compare.  (We assume here that the
			 * same OID won't appear twice in either ruleset.)
			 */
			for (j = 0; j < rlock2->numLocks; j++)
			{
				rule2 = rlock2->rules[j];
				if (rule1->ruleId == rule2->ruleId)
					break;
			}
			if (j >= rlock2->numLocks)
				return false;
			if (rule1->event != rule2->event)
				return false;
			if (rule1->attrno != rule2->attrno)
				return false;
			if (rule1->isInstead != rule2->isInstead)
				return false;
973
			if (!equal(rule1->qual, rule2->qual))
974
				return false;
975
			if (!equal(rule1->actions, rule2->actions))
976 977 978 979 980 981
				return false;
		}
	}
	else if (rlock2 != NULL)
		return false;
	return true;
982 983 984
}


985
/* ----------------------------------
986 987
 *		RelationBuildDesc
 *
988 989 990 991 992
 *		Build a relation descriptor --- either a new one, or by
 *		recycling the given old relation object.  The latter case
 *		supports rebuilding a relcache entry without invalidating
 *		pointers to it.
 *
993 994 995
 *		To build a relation descriptor, we have to allocate space,
 *		open the underlying unix file and initialize the following
 *		fields:
996
 *
997 998 999 1000 1001 1002
 *	File				   rd_fd;		 open file descriptor
 *	int					   rd_nblocks;	 number of blocks in rel
 *										 it will be set in ambeginscan()
 *	uint16				   rd_refcnt;	 reference count
 *	Form_pg_am			   rd_am;		 AM tuple
 *	Form_pg_class		   rd_rel;		 RELATION tuple
1003
 *	Oid					   rd_id;		 relation's object id
1004
 *	LockInfoData		   rd_lockInfo;  lock manager's info
1005
 *	TupleDesc			   rd_att;		 tuple descriptor
1006
 *
1007 1008 1009 1010
 *		Note: rd_ismem (rel is in-memory only) is currently unused
 *		by any part of the system.	someday this will indicate that
 *		the relation lives only in the main-memory buffer pool
 *		-cim 2/4/91
1011 1012
 * --------------------------------
 */
1013
static Relation
1014 1015
RelationBuildDesc(RelationBuildDescInfo buildinfo,
				  Relation oldrelation)
1016
{
1017 1018 1019
	Relation	relation;
	Oid			relid;
	Oid			relam;
1020
	HeapTuple	pg_class_tuple;
1021 1022
	Form_pg_class relp;
	MemoryContext oldcxt;
1023

1024
	/*
1025
	 * find the tuple in pg_class corresponding to the given relation id
1026
	 *
1027 1028 1029
	 */
	pg_class_tuple = ScanPgRelation(buildinfo);

1030
	/*
1031
	 * if no such tuple exists, return NULL
1032
	 *
1033 1034 1035 1036
	 */
	if (!HeapTupleIsValid(pg_class_tuple))
		return NULL;

1037
	/*
1038
	 * get information from the pg_class_tuple
1039
	 *
1040
	 */
1041
	relid = pg_class_tuple->t_data->t_oid;
1042 1043
	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);

1044
	/*
1045 1046
	 * allocate storage for the relation descriptor, and copy
	 * pg_class_tuple to relation->rd_rel.
1047
	 *
1048
	 */
1049 1050
	relation = AllocateRelationDesc(oldrelation, relp);

1051
	/*
1052
	 * now we can free the memory allocated for pg_class_tuple
1053
	 *
1054 1055
	 */
	heap_freetuple(pg_class_tuple);
1056

1057
	/*
1058
	 * initialize the relation's relation id (relation->rd_id)
1059
	 *
1060
	 */
1061
	RelationGetRelid(relation) = relid;
1062

1063
	/*
1064
	 * initialize relation->rd_refcnt
1065
	 *
1066 1067 1068
	 */
	RelationSetReferenceCount(relation, 1);

1069
	/*
1070
	 * normal relations are not nailed into the cache
1071
	 *
1072 1073 1074
	 */
	relation->rd_isnailed = false;

1075
	/*
1076
	 * initialize the access method information (relation->rd_am)
1077
	 *
1078
	 */
1079
	relam = relation->rd_rel->relam;
1080
	if (OidIsValid(relam))
1081 1082
		relation->rd_am = AccessMethodObjectIdGetForm(relam,
													  CacheMemoryContext);
1083

1084
	/*
1085
	 * initialize the tuple descriptor (relation->rd_att).
1086
	 *
1087
	 */
1088
	RelationBuildTupleDesc(buildinfo, relation);
1089

1090
	/*
1091
	 * Fetch rules and triggers that affect this relation
1092
	 *
1093
	 */
1094
	if (relation->rd_rel->relhasrules)
1095 1096
		RelationBuildRuleLock(relation);
	else
1097
	{
1098
		relation->rd_rules = NULL;
1099 1100
		relation->rd_rulescxt = NULL;
	}
1101

1102
	if (relation->rd_rel->reltriggers > 0)
1103 1104 1105 1106
		RelationBuildTriggers(relation);
	else
		relation->trigdesc = NULL;

1107
	/*
1108
	 * initialize index strategy and support information for this relation
1109
	 *
1110 1111 1112 1113
	 */
	if (OidIsValid(relam))
		IndexedAccessMethodInitialize(relation);

1114
	/*
1115
	 * initialize the relation lock manager information
1116
	 *
1117 1118 1119
	 */
	RelationInitLockInfo(relation);		/* see lmgr.c */

1120 1121 1122 1123 1124 1125
	if (IsSharedSystemRelationName(NameStr(relation->rd_rel->relname)))
		relation->rd_node.tblNode = InvalidOid;
	else
		relation->rd_node.tblNode = MyDatabaseId;
	relation->rd_node.relNode = relation->rd_rel->relfilenode;

1126
	/*
1127
	 * Open the relation and assign the file descriptor returned by the
1128
	 * storage manager code to rd_fd.
1129
	 *
1130 1131 1132
	 * We do not raise a hard error if we fail to open the relation at this
	 * point.  If we did, it would be impossible to drop a relation whose
	 * underlying physical file had disappeared.
1133
	 */
1134
	if (relation->rd_rel->relkind != RELKIND_VIEW)
1135 1136 1137 1138 1139 1140 1141
	{
		relation->rd_fd = smgropen(DEFAULT_SMGR, relation, true);
		Assert(relation->rd_fd >= -1);
		if (relation->rd_fd == -1)
			elog(NOTICE, "RelationBuildDesc: can't open %s: %m",
				 RelationGetRelationName(relation));
	}
1142
	else
1143
		relation->rd_fd = -1;
1144

1145
	/*
1146 1147
	 * insert newly created relation into proper relcaches, restore memory
	 * context and return the new reldesc.
1148
	 *
1149
	 */
1150
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
1151
	RelationCacheInsert(relation);
1152 1153
	MemoryContextSwitchTo(oldcxt);

1154
	return relation;
1155 1156 1157 1158 1159
}

static void
IndexedAccessMethodInitialize(Relation relation)
{
1160 1161 1162 1163 1164 1165 1166
	IndexStrategy strategy;
	RegProcedure *support;
	int			natts;
	Size		stratSize;
	Size		supportSize;
	uint16		relamstrategies;
	uint16		relamsupport;
1167 1168 1169 1170

	natts = relation->rd_rel->relnatts;
	relamstrategies = relation->rd_am->amstrategies;
	stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
1171 1172
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  stratSize);
1173

1174
	relamsupport = relation->rd_am->amsupport;
1175 1176 1177
	if (relamsupport > 0)
	{
		supportSize = natts * (relamsupport * sizeof(RegProcedure));
1178 1179
		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
													  supportSize);
1180 1181 1182 1183 1184
	}
	else
		support = (RegProcedure *) NULL;

	IndexSupportInitialize(strategy, support,
1185
						   &relation->rd_uniqueindex,
1186 1187 1188 1189 1190
						   relation->rd_att->attrs[0]->attrelid,
						   relation->rd_rel->relam,
						   relamstrategies, relamsupport, natts);

	RelationSetIndexSupport(relation, strategy, support);
1191 1192
}

1193
/*
1194
 *		formrdesc
1195
 *
1196
 *		This is a special cut-down version of RelationBuildDesc()
1197 1198
 *		used by RelationCacheInitialize() in initializing the relcache.
 *		The relation descriptor is built just from the supplied parameters,
1199 1200 1201
 *		without actually looking at any system table entries.  We cheat
 *		quite a lot since we only need to work for a few basic system
 *		catalogs...
1202 1203
 *
 * NOTE: we assume we are already switched into CacheMemoryContext.
1204
 *
1205 1206 1207
 */
static void
formrdesc(char *relationName,
1208
		  int natts,
1209
		  FormData_pg_attribute *att)
1210
{
1211
	Relation	relation;
1212
	int			i;
1213

1214
	/*
1215
	 * allocate new relation desc
1216
	 *
1217
	 */
1218 1219
	relation = (Relation) palloc(sizeof(RelationData));
	MemSet((char *) relation, 0, sizeof(RelationData));
1220

1221
	/*
1222
	 * don't open the unix file yet..
1223
	 *
1224 1225 1226
	 */
	relation->rd_fd = -1;

1227
	/*
1228
	 * initialize reference count
1229
	 *
1230 1231 1232
	 */
	RelationSetReferenceCount(relation, 1);

1233
	/*
1234
	 * all entries built with this routine are nailed-in-cache
1235
	 *
1236
	 */
1237
	relation->rd_isnailed = true;
1238

1239
	/*
1240
	 * initialize relation tuple form
1241
	 *
1242 1243 1244
	 * The data we insert here is pretty incomplete/bogus, but it'll serve to
	 * get us launched.  RelationCacheInitializePhase2() will read the
	 * real data from pg_class and replace what we've done here.
1245
	 *
1246
	 */
1247 1248 1249 1250
	relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
	MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);

	strcpy(RelationGetPhysicalRelationName(relation), relationName);
1251 1252 1253 1254 1255 1256 1257 1258

	/*
	 * For debugging purposes, it's important to distinguish between
	 * shared and non-shared relations, even at bootstrap time.  There's
	 * code in the buffer manager that traces allocations that has to know
	 * about this.
	 */
	if (IsSystemRelationName(relationName))
1259
		relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1260 1261 1262
	else
		relation->rd_rel->relisshared = false;

1263 1264
	relation->rd_rel->relpages = 1;
	relation->rd_rel->reltuples = 1;
1265
	relation->rd_rel->relkind = RELKIND_RELATION;
1266
	relation->rd_rel->relnatts = (int16) natts;
1267

1268
	/*
1269
	 * initialize attribute tuple form
1270
	 *
1271 1272
	 */
	relation->rd_att = CreateTemplateTupleDesc(natts);
1273

1274
	/*
1275
	 * initialize tuple desc info
1276
	 *
1277 1278 1279
	 */
	for (i = 0; i < natts; i++)
	{
1280
		relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1281 1282
		memcpy((char *) relation->rd_att->attrs[i],
			   (char *) &att[i],
1283 1284 1285
			   ATTRIBUTE_TUPLE_SIZE);
	}

1286
	/*
1287
	 * initialize relation id
1288
	 *
1289
	 */
1290
	RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
1291

1292
	/*
1293
	 * initialize the relation's lock manager and RelFileNode information
1294
	 *
1295 1296 1297
	 */
	RelationInitLockInfo(relation);		/* see lmgr.c */

1298 1299 1300 1301
	if (IsSharedSystemRelationName(relationName))
		relation->rd_node.tblNode = InvalidOid;
	else
		relation->rd_node.tblNode = MyDatabaseId;
1302
	relation->rd_node.relNode =
1303 1304
		relation->rd_rel->relfilenode = RelationGetRelid(relation);

1305
	/*
1306
	 * initialize the rel-has-index flag, using hardwired knowledge
1307
	 *
1308
	 */
1309
	relation->rd_rel->relhasindex = false;
1310

1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
	/* In bootstrap mode, we have no indexes */
	if (!IsBootstrapProcessingMode())
	{
		for (i = 0; IndexedCatalogNames[i] != NULL; i++)
		{
			if (strcmp(IndexedCatalogNames[i], relationName) == 0)
			{
				relation->rd_rel->relhasindex = true;
				break;
			}
		}
	}

1324
	/*
1325
	 * add new reldesc to relcache
1326
	 *
1327
	 */
1328
	RelationCacheInsert(relation);
1329 1330 1331
}


1332
/*
1333 1334 1335 1336
 *		fixrdesc
 *
 *		Update the phony data inserted by formrdesc() with real info
 *		from pg_class.
1337
 *
1338 1339 1340 1341 1342 1343 1344 1345 1346
 */
static void
fixrdesc(char *relationName)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
	Form_pg_class relp;
	Relation	relation;

1347
	/*
1348
	 * find the tuple in pg_class corresponding to the given relation name
1349
	 *
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
	 */
	buildinfo.infotype = INFO_RELNAME;
	buildinfo.i.info_name = relationName;

	pg_class_tuple = ScanPgRelation(buildinfo);

	if (!HeapTupleIsValid(pg_class_tuple))
		elog(FATAL, "fixrdesc: no pg_class entry for %s",
			 relationName);
	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);

1361
	/*
1362
	 * find the pre-made relcache entry (better be there!)
1363
	 *
1364 1365 1366 1367 1368 1369
	 */
	relation = RelationNameCacheGetRelation(relationName);
	if (!RelationIsValid(relation))
		elog(FATAL, "fixrdesc: no existing relcache entry for %s",
			 relationName);

1370
	/*
1371 1372
	 * and copy pg_class_tuple to relation->rd_rel. (See notes in
	 * AllocateRelationDesc())
1373
	 *
1374 1375 1376 1377 1378 1379 1380 1381
	 */
	Assert(relation->rd_rel != NULL);
	memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);

	heap_freetuple(pg_class_tuple);
}


1382
/* ----------------------------------------------------------------
1383
 *				 Relation Descriptor Lookup Interface
1384 1385 1386
 * ----------------------------------------------------------------
 */

1387
/*
1388
 *		RelationIdCacheGetRelation
1389
 *
1390 1391 1392
 *		Lookup an existing reldesc by OID.
 *
 *		Only try to get the reldesc by looking in the cache,
1393 1394 1395 1396 1397
 *		do not go to the disk.
 *
 *		NB: relation ref count is incremented if successful.
 *		Caller should eventually decrement count.  (Usually,
 *		that happens by calling RelationClose().)
1398
 *
1399 1400 1401 1402
 */
Relation
RelationIdCacheGetRelation(Oid relationId)
{
1403
	Relation	rd;
1404 1405 1406 1407 1408

	RelationIdCacheLookup(relationId, rd);

	if (RelationIsValid(rd))
	{
1409
		/* re-open files if necessary */
1410
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1411
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1412 1413

		RelationIncrementReferenceCount(rd);
1414
	}
1415

1416
	return rd;
1417 1418
}

1419
/*
1420
 *		RelationNameCacheGetRelation
1421 1422
 *
 *		As above, but lookup by name.
1423
 *
1424
 */
1425
static Relation
1426
RelationNameCacheGetRelation(const char *relationName)
1427
{
1428 1429
	Relation	rd;
	NameData	name;
1430 1431 1432 1433 1434 1435

	/*
	 * make sure that the name key used for hash lookup is properly
	 * null-padded
	 */
	namestrcpy(&name, relationName);
1436
	RelationNameCacheLookup(NameStr(name), rd);
1437 1438 1439

	if (RelationIsValid(rd))
	{
1440
		/* re-open files if necessary */
1441
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1442
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1443 1444

		RelationIncrementReferenceCount(rd);
1445
	}
1446

1447
	return rd;
1448 1449
}

1450 1451 1452 1453 1454 1455 1456 1457 1458
Relation
RelationNodeCacheGetRelation(RelFileNode rnode)
{
	Relation	rd;

	RelationNodeCacheLookup(rnode, rd);

	if (RelationIsValid(rd))
	{
1459
		/* re-open files if necessary */
1460
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1461
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1462 1463 1464 1465 1466 1467 1468

		RelationIncrementReferenceCount(rd);
	}

	return rd;
}

1469
/*
1470
 *		RelationIdGetRelation
1471
 *
1472 1473 1474 1475 1476
 *		Lookup a reldesc by OID; make one if not already in cache.
 *
 *		NB: relation ref count is incremented, or set to 1 if new entry.
 *		Caller should eventually decrement count.  (Usually,
 *		that happens by calling RelationClose().)
1477
 *
1478 1479 1480 1481
 */
Relation
RelationIdGetRelation(Oid relationId)
{
1482
	Relation	rd;
1483 1484
	RelationBuildDescInfo buildinfo;

1485
	/*
1486
	 * increment access statistics
1487
	 *
1488 1489 1490 1491
	 */
	IncrHeapAccessStat(local_RelationIdGetRelation);
	IncrHeapAccessStat(global_RelationIdGetRelation);

1492
	/*
1493
	 * first try and get a reldesc from the cache
1494
	 *
1495 1496 1497 1498 1499
	 */
	rd = RelationIdCacheGetRelation(relationId);
	if (RelationIsValid(rd))
		return rd;

1500
	/*
1501 1502
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1503
	 *
1504 1505 1506 1507
	 */
	buildinfo.infotype = INFO_RELID;
	buildinfo.i.info_id = relationId;

1508
	rd = RelationBuildDesc(buildinfo, NULL);
1509
	return rd;
1510 1511
}

1512
/*
1513
 *		RelationNameGetRelation
1514
 *
1515
 *		As above, but lookup by name.
1516
 *
1517 1518
 */
Relation
1519
RelationNameGetRelation(const char *relationName)
1520
{
1521
	char	   *temprelname;
1522
	Relation	rd;
1523 1524
	RelationBuildDescInfo buildinfo;

1525
	/*
1526
	 * increment access statistics
1527
	 *
1528 1529 1530 1531
	 */
	IncrHeapAccessStat(local_RelationNameGetRelation);
	IncrHeapAccessStat(global_RelationNameGetRelation);

1532
	/*
1533 1534
	 * if caller is looking for a temp relation, substitute its real name;
	 * we only index temp rels by their real names.
1535
	 *
1536
	 */
1537
	temprelname = get_temp_rel_by_username(relationName);
1538
	if (temprelname != NULL)
1539 1540
		relationName = temprelname;

1541
	/*
1542
	 * first try and get a reldesc from the cache
1543
	 *
1544 1545 1546 1547 1548
	 */
	rd = RelationNameCacheGetRelation(relationName);
	if (RelationIsValid(rd))
		return rd;

1549
	/*
1550 1551
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1552
	 *
1553 1554
	 */
	buildinfo.infotype = INFO_RELNAME;
1555
	buildinfo.i.info_name = (char *) relationName;
1556

1557
	rd = RelationBuildDesc(buildinfo, NULL);
1558 1559 1560 1561
	return rd;
}

/* ----------------------------------------------------------------
1562
 *				cache invalidation support routines
1563 1564 1565
 * ----------------------------------------------------------------
 */

1566
/*
1567 1568
 * RelationClose - close an open relation
 *
1569 1570 1571 1572 1573 1574 1575
 *	Actually, we just decrement the refcount.
 *
 *	NOTE: if compiled with -DRELCACHE_FORCE_RELEASE then relcache entries
 *	will be freed as soon as their refcount goes to zero.  In combination
 *	with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test
 *	to catch references to already-released relcache entries.  It slows
 *	things down quite a bit, however.
1576
 *
1577 1578 1579 1580
 */
void
RelationClose(Relation relation)
{
1581 1582
	/* Note: no locking manipulations needed */
	RelationDecrementReferenceCount(relation);
1583 1584 1585 1586 1587

#ifdef RELCACHE_FORCE_RELEASE
	if (RelationHasReferenceCountZero(relation) && !relation->rd_myxactonly)
		RelationClearRelation(relation, false);
#endif
1588 1589
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1590
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
1591
/*
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1592 1593 1594 1595 1596
 * RelationReloadClassinfo
 *
 *	This function is especially for nailed relations.
 *	relhasindex/relfilenode could be changed even for
 *	nailed relations.
1597
 *
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1598 1599 1600 1601 1602 1603
 */
static void
RelationReloadClassinfo(Relation relation)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
1604
	Form_pg_class relp;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624

	if (!relation->rd_rel)
		return;
	buildinfo.infotype = INFO_RELID;
	buildinfo.i.info_id = relation->rd_id;
	pg_class_tuple = ScanPgRelation(buildinfo);
	if (!HeapTupleIsValid(pg_class_tuple))
	{
		elog(ERROR, "RelationReloadClassinfo system relation id=%d doesn't exist", relation->rd_id);
		return;
	}
	RelationCacheDelete(relation);
	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
	memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
	relation->rd_node.relNode = relp->relfilenode;
	RelationCacheInsert(relation);
	heap_freetuple(pg_class_tuple);

	return;
}
1625 1626

#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1627

1628
/*
1629
 * RelationClearRelation
1630
 *
1631 1632 1633 1634 1635
 *	 Physically blow away a relation cache entry, or reset it and rebuild
 *	 it from scratch (that is, from catalog entries).  The latter path is
 *	 usually used when we are notified of a change to an open relation
 *	 (one with refcount > 0).  However, this routine just does whichever
 *	 it's told to do; callers must determine which they want.
1636
 *
1637
 */
1638
static void
1639
RelationClearRelation(Relation relation, bool rebuildIt)
1640
{
1641 1642 1643
	MemoryContext oldcxt;

	/*
1644
	 * Make sure smgr and lower levels close the relation's files, if they
1645
	 * weren't closed already.  If the relation is not getting deleted,
1646
	 * the next smgr access should reopen the files automatically.	This
1647 1648
	 * ensures that the low-level file access state is updated after, say,
	 * a vacuum truncation.
1649
	 */
1650 1651
	if (relation->rd_fd >= 0)
		smgrclose(DEFAULT_SMGR, relation);
1652

1653
	/*
1654 1655
	 * Never, never ever blow away a nailed-in system relation, because
	 * we'd be unable to recover.
1656 1657
	 */
	if (relation->rd_isnailed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1658
	{
1659
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1660
		RelationReloadClassinfo(relation);
1661
#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1662
		return;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1663
	}
1664

1665 1666
	/*
	 * Remove relation from hash tables
1667 1668 1669 1670 1671
	 *
	 * Note: we might be reinserting it momentarily, but we must not have it
	 * visible in the hash tables until it's valid again, so don't try to
	 * optimize this away...
	 */
1672
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
1673
	RelationCacheDelete(relation);
1674
	MemoryContextSwitchTo(oldcxt);
1675 1676 1677

	/* Clear out catcache's entries for this relation */
	SystemCacheRelationFlushed(RelationGetRelid(relation));
1678

1679
	/*
1680 1681 1682 1683 1684 1685
	 * Free all the subsidiary data structures of the relcache entry. We
	 * cannot free rd_att if we are trying to rebuild the entry, however,
	 * because pointers to it may be cached in various places. The trigger
	 * manager might also have pointers into the trigdesc, and the rule
	 * manager might have pointers into the rewrite rules. So to begin
	 * with, we can only get rid of these fields:
1686 1687 1688 1689 1690 1691 1692 1693 1694
	 */
	if (relation->rd_am)
		pfree(relation->rd_am);
	if (relation->rd_rel)
		pfree(relation->rd_rel);
	if (relation->rd_istrat)
		pfree(relation->rd_istrat);
	if (relation->rd_support)
		pfree(relation->rd_support);
1695
	freeList(relation->rd_indexlist);
1696

1697
	/*
1698 1699 1700 1701
	 * If we're really done with the relcache entry, blow it away. But if
	 * someone is still using it, reconstruct the whole deal without
	 * moving the physical RelationData record (so that the someone's
	 * pointer is still valid).
1702
	 */
1703
	if (!rebuildIt)
1704
	{
1705 1706
		/* ok to zap remaining substructure */
		FreeTupleDesc(relation->rd_att);
1707 1708
		if (relation->rd_rulescxt)
			MemoryContextDelete(relation->rd_rulescxt);
1709
		FreeTriggerDesc(relation->trigdesc);
1710 1711 1712 1713
		pfree(relation);
	}
	else
	{
1714

1715 1716 1717
		/*
		 * When rebuilding an open relcache entry, must preserve ref count
		 * and myxactonly flag.  Also attempt to preserve the tupledesc,
1718 1719 1720
		 * rewrite rules, and trigger substructures in place. Furthermore
		 * we save/restore rd_nblocks (in case it is a local relation)
		 * *and* call RelationGetNumberOfBlocks (in case it isn't).
1721
		 */
1722 1723 1724 1725
		uint16		old_refcnt = relation->rd_refcnt;
		bool		old_myxactonly = relation->rd_myxactonly;
		TupleDesc	old_att = relation->rd_att;
		RuleLock   *old_rules = relation->rd_rules;
1726
		MemoryContext old_rulescxt = relation->rd_rulescxt;
1727 1728
		TriggerDesc *old_trigdesc = relation->trigdesc;
		int			old_nblocks = relation->rd_nblocks;
1729
		RelationBuildDescInfo buildinfo;
1730

1731 1732
		buildinfo.infotype = INFO_RELID;
		buildinfo.i.info_id = RelationGetRelid(relation);
1733

1734
		if (RelationBuildDesc(buildinfo, relation) != relation)
1735
		{
1736
			/* Should only get here if relation was deleted */
1737
			FreeTupleDesc(old_att);
1738 1739
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1740
			FreeTriggerDesc(old_trigdesc);
1741
			pfree(relation);
1742
			elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
1743
				 buildinfo.i.info_id);
1744
		}
1745
		RelationSetReferenceCount(relation, old_refcnt);
1746
		relation->rd_myxactonly = old_myxactonly;
1747 1748 1749 1750 1751 1752 1753 1754 1755
		if (equalTupleDescs(old_att, relation->rd_att))
		{
			FreeTupleDesc(relation->rd_att);
			relation->rd_att = old_att;
		}
		else
			FreeTupleDesc(old_att);
		if (equalRuleLocks(old_rules, relation->rd_rules))
		{
1756 1757
			if (relation->rd_rulescxt)
				MemoryContextDelete(relation->rd_rulescxt);
1758
			relation->rd_rules = old_rules;
1759
			relation->rd_rulescxt = old_rulescxt;
1760 1761 1762
		}
		else
		{
1763 1764
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1765 1766 1767 1768 1769 1770 1771 1772 1773
		}
		if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
		{
			FreeTriggerDesc(relation->trigdesc);
			relation->trigdesc = old_trigdesc;
		}
		else
			FreeTriggerDesc(old_trigdesc);
		relation->rd_nblocks = old_nblocks;
1774 1775 1776

		/*
		 * this is kind of expensive, but I think we must do it in case
1777 1778
		 * relation has been truncated...
		 */
1779
		relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
1780
	}
1781 1782
}

1783
/*
1784 1785 1786
 * RelationFlushRelation
 *
 *	 Rebuild the relation if it is open (refcount > 0), else blow it away.
1787
 *
1788 1789
 */
static void
1790
RelationFlushRelation(Relation relation)
1791
{
1792
	bool		rebuildIt;
1793 1794

	if (relation->rd_myxactonly)
1795
	{
1796

1797 1798 1799 1800 1801 1802 1803 1804
		/*
		 * Local rels should always be rebuilt, not flushed; the relcache
		 * entry must live until RelationPurgeLocalRelation().
		 */
		rebuildIt = true;
	}
	else
	{
1805

1806 1807 1808
		/*
		 * Nonlocal rels can be dropped from the relcache if not open.
		 */
1809
		rebuildIt = !RelationHasReferenceCountZero(relation);
1810
	}
1811

1812
	RelationClearRelation(relation, rebuildIt);
1813 1814
}

1815
/*
1816 1817 1818 1819
 * RelationForgetRelation -
 *
 *		   RelationClearRelation + if the relation is myxactonly then
 *		   remove the relation descriptor from the newly created
1820
 *		   relation list.
1821
 *
1822 1823
 */
void
1824
RelationForgetRelation(Oid rid)
1825
{
1826
	Relation	relation;
1827 1828 1829

	RelationIdCacheLookup(rid, relation);

1830
	if (PointerIsValid(relation))
1831
	{
1832
		if (relation->rd_myxactonly)
1833
		{
1834 1835
			List	   *curr;
			List	   *prev = NIL;
Bruce Momjian's avatar
Bruce Momjian committed
1836

1837 1838 1839
			foreach(curr, newlyCreatedRelns)
			{
				Relation	reln = lfirst(curr);
Bruce Momjian's avatar
Bruce Momjian committed
1840

1841 1842 1843 1844 1845 1846 1847
				Assert(reln != NULL && reln->rd_myxactonly);
				if (RelationGetRelid(reln) == rid)
					break;
				prev = curr;
			}
			if (curr == NIL)
				elog(FATAL, "Local relation %s not found in list",
1848
					 RelationGetRelationName(relation));
1849 1850 1851 1852 1853
			if (prev == NIL)
				newlyCreatedRelns = lnext(newlyCreatedRelns);
			else
				lnext(prev) = lnext(curr);
			pfree(curr);
1854
		}
Bruce Momjian's avatar
Bruce Momjian committed
1855

1856 1857
		/* Unconditionally destroy the relcache entry */
		RelationClearRelation(relation, false);
1858
	}
1859 1860
}

1861
/*
1862
 *		RelationIdInvalidateRelationCacheByRelationId
1863 1864 1865 1866 1867 1868 1869 1870
 *
 *		This routine is invoked for SI cache flush messages.
 *
 *		We used to skip local relations, on the grounds that they could
 *		not be targets of cross-backend SI update messages; but it seems
 *		safer to process them, so that our *own* SI update messages will
 *		have the same effects during CommandCounterIncrement for both
 *		local and nonlocal relations.
1871
 *
1872 1873 1874 1875
 */
void
RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
{
1876
	Relation	relation;
1877 1878 1879

	RelationIdCacheLookup(relationId, relation);

1880
	if (PointerIsValid(relation))
1881
		RelationFlushRelation(relation);
1882 1883
}

1884 1885 1886
#if NOT_USED
/* only used by RelationIdInvalidateRelationCacheByAccessMethodId,
 * which is dead code.
1887 1888
 */
static void
1889
RelationFlushIndexes(Relation *r,
1890
					 Oid accessMethodId)
1891
{
1892
	Relation	relation = *r;
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902

	if (!RelationIsValid(relation))
	{
		elog(NOTICE, "inval call to RFI");
		return;
	}

	if (relation->rd_rel->relkind == RELKIND_INDEX &&	/* XXX style */
		(!OidIsValid(accessMethodId) ||
		 relation->rd_rel->relam == accessMethodId))
1903
		RelationFlushRelation(relation);
1904
}
1905

1906 1907
#endif

1908 1909 1910

/*
 * RelationCacheInvalidate
1911 1912
 *	 Blow away cached relation descriptors that have zero reference counts,
 *	 and rebuild those with positive reference counts.
1913
 *
1914
 *	 This is currently used only to recover from SI message buffer overflow,
1915 1916 1917
 *	 so we do not touch transaction-local relations; they cannot be targets
 *	 of cross-backend SI updates (and our own updates now go through a
 *	 separate linked list that isn't limited by the SI message buffer size).
1918 1919 1920 1921
 *
 *	 We do this in two phases: the first pass deletes deletable items, and
 *	 the second one rebuilds the rebuildable items.  This is essential for
 *	 safety, because HashTableWalk only copes with concurrent deletion of
1922
 *	 the element it is currently visiting.	If a second SI overflow were to
1923 1924 1925 1926 1927 1928
 *	 occur while we are walking the table, resulting in recursive entry to
 *	 this routine, we could crash because the inner invocation blows away
 *	 the entry next to be visited by the outer scan.  But this way is OK,
 *	 because (a) during the first pass we won't process any more SI messages,
 *	 so HashTableWalk will complete safely; (b) during the second pass we
 *	 only hold onto pointers to nondeletable entries.
1929 1930
 */
void
1931
RelationCacheInvalidate(void)
1932
{
1933 1934
	List	   *rebuildList = NIL;
	List	   *l;
1935 1936 1937 1938 1939 1940 1941

	/* Phase 1 */
	HashTableWalk(RelationNameCache,
				  (HashtFunc) RelationCacheInvalidateWalker,
				  PointerGetDatum(&rebuildList));

	/* Phase 2: rebuild the items found to need rebuild in phase 1 */
1942
	foreach(l, rebuildList)
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
	{
		Relation	relation = (Relation) lfirst(l);

		RelationClearRelation(relation, true);
	}
	freeList(rebuildList);
}

static void
RelationCacheInvalidateWalker(Relation *relationPtr, Datum listp)
{
	Relation	relation = *relationPtr;
1955
	List	  **rebuildList = (List **) DatumGetPointer(listp);
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970

	/* We can ignore xact-local relations, since they are never SI targets */
	if (relation->rd_myxactonly)
		return;

	if (RelationHasReferenceCountZero(relation))
	{
		/* Delete this entry immediately */
		RelationClearRelation(relation, false);
	}
	else
	{
		/* Add entry to list of stuff to rebuild in second pass */
		*rebuildList = lcons(relation, *rebuildList);
	}
1971
}
1972

1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
/*
 * RelationCacheAbort
 *
 *	Clean up the relcache at transaction abort.
 *
 *	What we need to do here is reset relcache entry ref counts to
 *	their normal not-in-a-transaction state.  A ref count may be
 *	too high because some routine was exited by elog() between
 *	incrementing and decrementing the count.
 *
 *	XXX Maybe we should do this at transaction commit, too, in case
 *	someone forgets to decrement a refcount in a non-error path?
 */
void
RelationCacheAbort(void)
{
1989 1990
	HashTableWalk(RelationNameCache,
				  (HashtFunc) RelationCacheAbortWalker,
1991 1992 1993 1994
				  0);
}

static void
1995
RelationCacheAbortWalker(Relation *relationPtr, Datum dummy)
1996 1997 1998 1999 2000 2001 2002 2003
{
	Relation	relation = *relationPtr;

	if (relation->rd_isnailed)
		RelationSetReferenceCount(relation, 1);
	else
		RelationSetReferenceCount(relation, 0);
}
2004

2005
/*
2006 2007 2008
 *		RelationRegisterRelation -
 *		   register the Relation descriptor of a newly created relation
 *		   with the relation descriptor Cache.
2009
 *
2010 2011 2012 2013
 */
void
RelationRegisterRelation(Relation relation)
{
2014
	MemoryContext oldcxt;
2015 2016 2017

	RelationInitLockInfo(relation);

2018 2019
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

2020 2021
	RelationCacheInsert(relation);

2022 2023
	/*
	 * we've just created the relation. It is invisible to anyone else
Bruce Momjian's avatar
Bruce Momjian committed
2024 2025
	 * before the transaction is committed. Setting rd_myxactonly allows
	 * us to use the local buffer manager for select/insert/etc before the
2026 2027 2028 2029
	 * end of transaction. (We also need to keep track of relations
	 * created during a transaction and does the necessary clean up at the
	 * end of the transaction.)				- ay 3/95
	 */
2030
	relation->rd_myxactonly = TRUE;
2031 2032 2033
	newlyCreatedRelns = lcons(relation, newlyCreatedRelns);

	MemoryContextSwitchTo(oldcxt);
2034 2035 2036 2037
}

/*
 * RelationPurgeLocalRelation -
2038
 *	  find all the Relation descriptors marked rd_myxactonly and reset them.
2039 2040 2041
 *	  This should be called at the end of a transaction (commit/abort) when
 *	  the "local" relations will become visible to others and the multi-user
 *	  buffer pool should be used.
2042 2043 2044 2045
 */
void
RelationPurgeLocalRelation(bool xactCommitted)
{
2046 2047
	while (newlyCreatedRelns)
	{
2048 2049
		List	   *l = newlyCreatedRelns;
		Relation	reln = lfirst(l);
2050

2051
		Assert(reln != NULL && reln->rd_myxactonly);
2052

2053
		reln->rd_myxactonly = false;	/* mark it not on list anymore */
2054 2055 2056 2057

		newlyCreatedRelns = lnext(newlyCreatedRelns);
		pfree(l);

2058
		/* XXX is this step still needed?  If so, why? */
2059
		if (!IsBootstrapProcessingMode())
2060
			RelationClearRelation(reln, false);
2061
	}
2062 2063
}

2064
/*
2065
 *		RelationCacheInitialize
2066
 *
2067
 *		This initializes the relation descriptor cache.
2068
 *
2069 2070
 */

2071
#define INITRELCACHESIZE		400
2072 2073

void
2074
RelationCacheInitialize(void)
2075
{
2076 2077
	MemoryContext oldcxt;
	HASHCTL		ctl;
2078

2079
	/*
2080
	 * switch to cache memory context
2081
	 *
2082
	 */
2083 2084
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
2085

2086
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2087

2088
	/*
2089
	 * create global caches
2090
	 *
2091
	 */
Bruce Momjian's avatar
Bruce Momjian committed
2092
	MemSet(&ctl, 0, (int) sizeof(ctl));
2093 2094 2095 2096 2097 2098 2099 2100 2101
	ctl.keysize = sizeof(NameData);
	ctl.datasize = sizeof(Relation);
	RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);

	ctl.keysize = sizeof(Oid);
	ctl.hash = tag_hash;
	RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
								  HASH_ELEM | HASH_FUNCTION);

2102 2103 2104
	ctl.keysize = sizeof(RelFileNode);
	ctl.hash = tag_hash;
	RelationNodeCache = hash_create(INITRELCACHESIZE, &ctl,
2105
									HASH_ELEM | HASH_FUNCTION);
2106

2107
	/*
2108 2109 2110
	 * initialize the cache with pre-made relation descriptors for some of
	 * the more important system relations.  These relations should always
	 * be in the cache.
2111
	 *
2112
	 * NB: see also the list in RelationCacheInitializePhase2().
2113
	 *
2114 2115 2116 2117 2118 2119 2120 2121
	 */
	formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
	formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
	formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
	formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
	formrdesc(LogRelationName, Natts_pg_log, Desc_pg_log);

	/*
2122 2123 2124
	 * init_irels() used to be called here. It is changed to be called in
	 * RelationCacheInitializePhase2() now so that transactional control
	 * could guarantee the consistency.
2125 2126 2127
	 */

	MemoryContextSwitchTo(oldcxt);
2128 2129
}

2130
/*
2131 2132 2133 2134
 *		RelationCacheInitializePhase2
 *
 *		This completes initialization of the relcache after catcache
 *		is functional and we are able to actually load data from pg_class.
2135
 *
2136 2137 2138 2139
 */
void
RelationCacheInitializePhase2(void)
{
2140

2141 2142 2143
	/*
	 * Get the real pg_class tuple for each nailed-in-cache relcache entry
	 * that was made by RelationCacheInitialize(), and replace the phony
2144 2145 2146
	 * rd_rel entry made by formrdesc().  This is necessary so that we
	 * have, for example, the correct toast-table info for tables that
	 * have such.
2147 2148 2149
	 */
	if (!IsBootstrapProcessingMode())
	{
2150

2151 2152 2153
		/*
		 * Initialize critical system index relation descriptors, first.
		 * They are to make building relation descriptors fast.
2154 2155
		 * init_irels() used to be called in RelationCacheInitialize(). It
		 * is changed to be called here to be transaction safe.
2156 2157
		 */
		MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2158

2159 2160 2161 2162
		init_irels();
		MemoryContextSwitchTo(oldcxt);

		/* fix nailed-in-cache relations */
2163 2164 2165 2166
		fixrdesc(RelationRelationName);
		fixrdesc(AttributeRelationName);
		fixrdesc(ProcedureRelationName);
		fixrdesc(TypeRelationName);
2167 2168 2169 2170 2171

		/*
		 * We don't bother to update the entries for pg_variable or
		 * pg_log.
		 */
2172 2173 2174
	}
}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
2175
/* used by XLogInitCache */
2176 2177
void		CreateDummyCaches(void);
void		DestroyDummyCaches(void);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2178 2179 2180 2181

void
CreateDummyCaches(void)
{
2182 2183
	MemoryContext oldcxt;
	HASHCTL		ctl;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202

	if (!CacheMemoryContext)
		CreateCacheMemoryContext();

	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

	MemSet(&ctl, 0, (int) sizeof(ctl));
	ctl.keysize = sizeof(NameData);
	ctl.datasize = sizeof(Relation);
	RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);

	ctl.keysize = sizeof(Oid);
	ctl.hash = tag_hash;
	RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
								  HASH_ELEM | HASH_FUNCTION);

	ctl.keysize = sizeof(RelFileNode);
	ctl.hash = tag_hash;
	RelationNodeCache = hash_create(INITRELCACHESIZE, &ctl,
2203
									HASH_ELEM | HASH_FUNCTION);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2204 2205 2206 2207 2208 2209
	MemoryContextSwitchTo(oldcxt);
}

void
DestroyDummyCaches(void)
{
2210
	MemoryContext oldcxt;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228

	if (!CacheMemoryContext)
		return;

	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

	if (RelationNameCache)
		hash_destroy(RelationNameCache);
	if (RelationIdCache)
		hash_destroy(RelationIdCache);
	if (RelationNodeCache)
		hash_destroy(RelationNodeCache);

	RelationNameCache = RelationIdCache = RelationNodeCache = NULL;

	MemoryContextSwitchTo(oldcxt);
}

2229
static void
2230
AttrDefaultFetch(Relation relation)
2231
{
2232 2233 2234
	AttrDefault *attrdef = relation->rd_att->constr->defval;
	int			ndef = relation->rd_att->constr->num_defval;
	Relation	adrel;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2235
	Relation	irel = (Relation) NULL;
2236
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2237
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2238
	HeapTuple	htup;
2239
	Form_pg_attrdef adform;
2240 2241
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc adscan = (HeapScanDesc) NULL;
2242
	RetrieveIndexResult indexRes;
2243
	Datum		val;
2244 2245 2246
	bool		isnull;
	int			found;
	int			i;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2247
	bool		hasindex;
2248 2249 2250 2251

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2252
						   (RegProcedure) F_OIDEQ,
2253
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2254

2255
	adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2256 2257 2258 2259 2260 2261 2262
	hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
	if (hasindex)
	{
		irel = index_openr(AttrDefaultIndex);
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
2263
		adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey);
2264
	tuple.t_datamcxt = NULL;
2265
	tuple.t_data = NULL;
2266 2267 2268

	for (found = 0;;)
	{
2269 2270
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
		if (hasindex)
		{
			indexRes = index_getnext(sd, ForwardScanDirection);
			if (!indexRes)
				break;

			tuple.t_self = indexRes->heap_iptr;
			heap_fetch(adrel, SnapshotNow, &tuple, &buffer);
			pfree(indexRes);
			if (tuple.t_data == NULL)
				continue;
			htup = &tuple;
		}
		else
		{
			htup = heap_getnext(adscan, 0);
			if (!HeapTupleIsValid(htup))
				break;
		}
2290
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2291
		adform = (Form_pg_attrdef) GETSTRUCT(htup);
2292 2293 2294 2295
		for (i = 0; i < ndef; i++)
		{
			if (adform->adnum != attrdef[i].adnum)
				continue;
2296
			if (attrdef[i].adbin != NULL)
2297
				elog(NOTICE, "AttrDefaultFetch: second record found for attr %s in rel %s",
2298
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2299
					 RelationGetRelationName(relation));
2300

2301 2302 2303
			val = fastgetattr(htup,
							  Anum_pg_attrdef_adbin,
							  adrel->rd_att, &isnull);
2304
			if (isnull)
2305
				elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
2306
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2307
					 RelationGetRelationName(relation));
2308 2309
			else
				attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
2310 2311
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2312 2313
			break;
		}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2314 2315
		if (hasindex)
			ReleaseBuffer(buffer);
2316

2317
		if (i >= ndef)
2318
			elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
2319
				 adform->adnum,
2320
				 RelationGetRelationName(relation));
2321 2322 2323
	}

	if (found < ndef)
2324
		elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s",
2325
			 ndef - found, RelationGetRelationName(relation));
2326

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2327 2328 2329 2330 2331 2332 2333
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(adscan);
2334
	heap_close(adrel, AccessShareLock);
2335 2336
}

2337
static void
2338
RelCheckFetch(Relation relation)
2339
{
2340 2341 2342
	ConstrCheck *check = relation->rd_att->constr->check;
	int			ncheck = relation->rd_att->constr->num_check;
	Relation	rcrel;
2343
	Relation	irel = (Relation) NULL;
2344
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2345
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2346
	HeapTuple	htup;
2347 2348
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc rcscan = (HeapScanDesc) NULL;
2349
	RetrieveIndexResult indexRes;
2350
	Name		rcname;
2351
	Datum		val;
2352 2353
	bool		isnull;
	int			found;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2354
	bool		hasindex;
2355 2356 2357 2358

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2359
						   (RegProcedure) F_OIDEQ,
2360
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2361

2362
	rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2363 2364 2365 2366 2367 2368 2369 2370
	hasindex = (rcrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
	if (hasindex)
	{
		irel = index_openr(RelCheckIndex);
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
		rcscan = heap_beginscan(rcrel, false, SnapshotNow, 1, &skey);
2371
	tuple.t_datamcxt = NULL;
2372
	tuple.t_data = NULL;
2373 2374 2375

	for (found = 0;;)
	{
2376 2377
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
		if (hasindex)
		{
			indexRes = index_getnext(sd, ForwardScanDirection);
			if (!indexRes)
				break;

			tuple.t_self = indexRes->heap_iptr;
			heap_fetch(rcrel, SnapshotNow, &tuple, &buffer);
			pfree(indexRes);
			if (tuple.t_data == NULL)
				continue;
			htup = &tuple;
		}
		else
		{
			htup = heap_getnext(rcscan, 0);
			if (!HeapTupleIsValid(htup))
				break;
		}
2397
		if (found == ncheck)
Bruce Momjian's avatar
Bruce Momjian committed
2398
			elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
2399
				 RelationGetRelationName(relation));
2400

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2401
		rcname = (Name) fastgetattr(htup,
2402 2403 2404
									Anum_pg_relcheck_rcname,
									rcrel->rd_att, &isnull);
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2405
			elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
2406
				 RelationGetRelationName(relation));
2407 2408
		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
												  NameStr(*rcname));
2409 2410 2411
		val = fastgetattr(htup,
						  Anum_pg_relcheck_rcbin,
						  rcrel->rd_att, &isnull);
2412
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2413
			elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
2414
				 RelationGetRelationName(relation));
2415
		check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
2416 2417
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2418
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2419 2420
		if (hasindex)
			ReleaseBuffer(buffer);
2421 2422 2423
	}

	if (found < ncheck)
Bruce Momjian's avatar
Bruce Momjian committed
2424
		elog(ERROR, "RelCheckFetch: %d record not found for rel %s",
2425
			 ncheck - found, RelationGetRelationName(relation));
2426

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2427 2428 2429 2430 2431 2432 2433
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(rcscan);
2434
	heap_close(rcrel, AccessShareLock);
2435 2436
}

2437 2438 2439 2440 2441 2442 2443 2444 2445 2446
/*
 * RelationGetIndexList -- get a list of OIDs of indexes on this relation
 *
 * The index list is created only if someone requests it.  We scan pg_index
 * to find relevant indexes, and add the list to the relcache entry so that
 * we won't have to compute it again.  Note that shared cache inval of a
 * relcache entry will delete the old list and set rd_indexfound to false,
 * so that we must recompute the index list on next request.  This handles
 * creation or deletion of an index.
 *
2447 2448 2449 2450 2451 2452
 * The returned list is guaranteed to be sorted in order by OID.  This is
 * needed by the executor, since for index types that we obtain exclusive
 * locks on when updating the index, all backends must lock the indexes in
 * the same order or we will get deadlocks (see ExecOpenIndices()).  Any
 * consistent ordering would do, but ordering by OID is easy.
 *
2453 2454
 * Since shared cache inval causes the relcache's copy of the list to go away,
 * we return a copy of the list palloc'd in the caller's context.  The caller
2455
 * may freeList() the returned list after scanning it.	This is necessary
2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484
 * since the caller will typically be doing syscache lookups on the relevant
 * indexes, and syscache lookup could cause SI messages to be processed!
 */
List *
RelationGetIndexList(Relation relation)
{
	Relation	indrel;
	Relation	irel = (Relation) NULL;
	ScanKeyData skey;
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc hscan = (HeapScanDesc) NULL;
	bool		hasindex;
	List	   *result;
	MemoryContext oldcxt;

	/* Quick exit if we already computed the list. */
	if (relation->rd_indexfound)
		return listCopy(relation->rd_indexlist);

	/* Prepare to scan pg_index for entries having indrelid = this rel. */
	indrel = heap_openr(IndexRelationName, AccessShareLock);
	hasindex = (indrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
	if (hasindex)
	{
		irel = index_openr(IndexIndrelidIndex);
		ScanKeyEntryInitialize(&skey,
							   (bits16) 0x0,
							   (AttrNumber) 1,
							   (RegProcedure) F_OIDEQ,
2485
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2486 2487 2488 2489 2490 2491 2492 2493
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
	{
		ScanKeyEntryInitialize(&skey,
							   (bits16) 0x0,
							   (AttrNumber) Anum_pg_index_indrelid,
							   (RegProcedure) F_OIDEQ,
2494
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2495 2496 2497 2498
		hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
	}

	/*
2499 2500 2501 2502
	 * We build the list we intend to return (in the caller's context)
	 * while doing the scan.  After successfully completing the scan, we
	 * copy that list into the relcache entry.	This avoids cache-context
	 * memory leakage if we get some sort of error partway through.
2503 2504
	 */
	result = NIL;
2505

2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
	for (;;)
	{
		HeapTupleData tuple;
		HeapTuple	htup;
		Buffer		buffer;
		Form_pg_index index;

		if (hasindex)
		{
			RetrieveIndexResult indexRes;

			indexRes = index_getnext(sd, ForwardScanDirection);
			if (!indexRes)
				break;
			tuple.t_self = indexRes->heap_iptr;
			tuple.t_datamcxt = NULL;
			tuple.t_data = NULL;
			heap_fetch(indrel, SnapshotNow, &tuple, &buffer);
			pfree(indexRes);
			if (tuple.t_data == NULL)
				continue;
			htup = &tuple;
		}
		else
		{
			htup = heap_getnext(hscan, 0);
			if (!HeapTupleIsValid(htup))
				break;
		}

		index = (Form_pg_index) GETSTRUCT(htup);

2538
		result = insert_ordered_oid(result, index->indexrelid);
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552

		if (hasindex)
			ReleaseBuffer(buffer);
	}

	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(hscan);
	heap_close(indrel, AccessShareLock);

2553
	/* Now save a copy of the completed list in the relcache entry. */
2554
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2555 2556 2557 2558 2559 2560 2561
	relation->rd_indexlist = listCopy(result);
	relation->rd_indexfound = true;
	MemoryContextSwitchTo(oldcxt);

	return result;
}

2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
/*
 * insert_ordered_oid
 *		Insert a new Oid into a sorted list of Oids, preserving ordering
 *
 * Building the ordered list this way is O(N^2), but with a pretty small
 * constant, so for the number of entries we expect it will probably be
 * faster than trying to apply qsort().  Most tables don't have very many
 * indexes...
 */
static List *
insert_ordered_oid(List *list, Oid datum)
{
	List	   *l;

	/* Does the datum belong at the front? */
	if (list == NIL || datum < (Oid) lfirsti(list))
		return lconsi(datum, list);
	/* No, so find the entry it belongs after */
	l = list;
	for (;;)
	{
		List	   *n = lnext(l);

		if (n == NIL || datum < (Oid) lfirsti(n))
			break;				/* it belongs before n */
		l = n;
	}
	/* Insert datum into list after item l */
	lnext(l) = lconsi(datum, lnext(l));
	return list;
}


2595
/*
2596 2597
 *	init_irels(), write_irels() -- handle special-case initialization of
 *								   index relation descriptors.
2598
 *
2599 2600 2601
 *		In late 1992, we started regularly having databases with more than
 *		a thousand classes in them.  With this number of classes, it became
 *		critical to do indexed lookups on the system catalogs.
2602
 *
2603 2604 2605 2606
 *		Bootstrapping these lookups is very hard.  We want to be able to
 *		use an index on pg_attribute, for example, but in order to do so,
 *		we must have read pg_attribute for the attributes in the index,
 *		which implies that we need to use the index.
2607
 *
2608
 *		In order to get around the problem, we do the following:
2609
 *
2610 2611
 *		   +  When the database system is initialized (at initdb time), we
 *			  don't use indices on pg_attribute.  We do sequential scans.
2612
 *
2613 2614 2615
 *		   +  When the backend is started up in normal mode, we load an image
 *			  of the appropriate relation descriptors, in internal format,
 *			  from an initialization file in the data/base/... directory.
2616
 *
2617
 *		   +  If the initialization file isn't there, then we create the
2618
 *			  relation descriptors using sequential scans and write 'em to
2619
 *			  the initialization file for use by subsequent backends.
2620
 *
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631
 *		We could dispense with the initialization file and just build the
 *		critical reldescs the hard way on every backend startup, but that
 *		slows down backend startup noticeably if pg_class is large.
 *
 *		As of v6.5, vacuum.c deletes the initialization file at completion
 *		of a VACUUM, so that it will be rebuilt at the next backend startup.
 *		This ensures that vacuum-collected stats for the system indexes
 *		will eventually get used by the optimizer --- otherwise the relcache
 *		entries for these indexes will show zero sizes forever, since the
 *		relcache entries are pinned in memory and will never be reloaded
 *		from pg_class.
2632 2633 2634 2635 2636
 */

/* pg_attnumind, pg_classnameind, pg_classoidind */
#define Num_indices_bootstrap	3

2637
static void
2638
init_irels(void)
2639
{
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
	Size		len;
	int			nread;
	File		fd;
	Relation	irel[Num_indices_bootstrap];
	Relation	ird;
	Form_pg_am	am;
	Form_pg_class relform;
	IndexStrategy strat;
	RegProcedure *support;
	int			i;
	int			relno;
2651

2652
	if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | PG_BINARY, 0600)) < 0)
2653
	{
2654 2655 2656
		write_irels();
		return;
	}
2657 2658 2659 2660 2661 2662

	FileSeek(fd, 0L, SEEK_SET);

	for (relno = 0; relno < Num_indices_bootstrap; relno++)
	{
		/* first read the relation descriptor length */
2663
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2664 2665 2666 2667 2668 2669
		{
			write_irels();
			return;
		}

		ird = irel[relno] = (Relation) palloc(len);
Bruce Momjian's avatar
Bruce Momjian committed
2670
		MemSet(ird, 0, len);
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681

		/* then, read the Relation structure */
		if ((nread = FileRead(fd, (char *) ird, len)) != len)
		{
			write_irels();
			return;
		}

		/* the file descriptor is not yet opened */
		ird->rd_fd = -1;

2682 2683
		ird->rd_node.tblNode = MyDatabaseId;

2684
		/* next, read the access method tuple form */
2685
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
		{
			write_irels();
			return;
		}

		am = (Form_pg_am) palloc(len);
		if ((nread = FileRead(fd, (char *) am, len)) != len)
		{
			write_irels();
			return;
		}

		ird->rd_am = am;

		/* next read the relation tuple form */
2701
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722
		{
			write_irels();
			return;
		}

		relform = (Form_pg_class) palloc(len);
		if ((nread = FileRead(fd, (char *) relform, len)) != len)
		{
			write_irels();
			return;
		}

		ird->rd_rel = relform;

		/* initialize attribute tuple forms */
		ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);

		/* next read all the attribute tuple form data entries */
		len = ATTRIBUTE_TUPLE_SIZE;
		for (i = 0; i < relform->relnatts; i++)
		{
2723
			if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2724 2725 2726 2727 2728
			{
				write_irels();
				return;
			}

2729
			ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
2730 2731 2732 2733 2734 2735 2736 2737 2738

			if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
			{
				write_irels();
				return;
			}
		}

		/* next, read the index strategy map */
2739
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
		{
			write_irels();
			return;
		}

		strat = (IndexStrategy) palloc(len);
		if ((nread = FileRead(fd, (char *) strat, len)) != len)
		{
			write_irels();
			return;
		}

		/* oh, for god's sake... */
2753
#define SMD(i)	strat->strategyMapData[i].entry[0]
2754

2755
		/* have to reinit the function pointers in the strategy maps */
2756 2757
		for (i = 0; i < am->amstrategies * relform->relnatts; i++)
		{
2758
			fmgr_info(SMD(i).sk_procedure,
2759
					  &(SMD(i).sk_func));
Bruce Momjian's avatar
Bruce Momjian committed
2760 2761
			SMD(i).sk_nargs = SMD(i).sk_func.fn_nargs;
		}
2762 2763 2764 2765 2766 2767 2768 2769 2770


		/*
		 * use a real field called rd_istrat instead of the bogosity of
		 * hanging invisible fields off the end of a structure - jolly
		 */
		ird->rd_istrat = strat;

		/* finally, read the vector of support procedures */
2771
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784
		{
			write_irels();
			return;
		}

		support = (RegProcedure *) palloc(len);
		if ((nread = FileRead(fd, (char *) support, len)) != len)
		{
			write_irels();
			return;
		}
		ird->rd_support = support;

2785
		RelationInitLockInfo(ird);
2786 2787

		RelationCacheInsert(ird);
2788
	}
2789
	criticalRelcachesBuilt = true;
2790 2791
}

2792
static void
2793
write_irels(void)
2794
{
Bruce Momjian's avatar
Bruce Momjian committed
2795
	Size		len;
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805
	int			nwritten;
	File		fd;
	Relation	irel[Num_indices_bootstrap];
	Relation	ird;
	Form_pg_am	am;
	Form_pg_class relform;
	IndexStrategy strat;
	RegProcedure *support;
	int			i;
	int			relno;
2806
	RelationBuildDescInfo bi;
2807 2808 2809 2810
	char		tempfilename[MAXPGPATH];
	char		finalfilename[MAXPGPATH];

	/*
2811 2812 2813
	 * We must write a temporary file and rename it into place. Otherwise,
	 * another backend starting at about the same time might crash trying
	 * to read the partially-complete file.
2814 2815 2816 2817 2818
	 */
	snprintf(tempfilename, sizeof(tempfilename), "%s%c%s.%d",
			 DatabasePath, SEP_CHAR, RELCACHE_INIT_FILENAME, MyProcPid);
	snprintf(finalfilename, sizeof(finalfilename), "%s%c%s",
			 DatabasePath, SEP_CHAR, RELCACHE_INIT_FILENAME);
2819

2820
	fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY, 0600);
2821
	if (fd < 0)
2822
	{
2823

2824 2825 2826 2827 2828 2829 2830
		/*
		 * We used to consider this a fatal error, but we might as well
		 * continue with backend startup ...
		 */
		elog(NOTICE, "Cannot create init file %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename);
		return;
	}
2831 2832 2833 2834

	FileSeek(fd, 0L, SEEK_SET);

	/*
2835
	 * Build relation descriptors for the critical system indexes without
2836 2837 2838 2839 2840
	 * resort to the descriptor cache.	In order to do this, we set
	 * ProcessingMode to Bootstrap.  The effect of this is to disable
	 * indexed relation searches -- a necessary step, since we're trying
	 * to instantiate the index relation descriptors here.	Once we have
	 * the descriptors, nail them into cache so we never lose them.
2841 2842
	 */

2843 2844 2845 2846 2847 2848 2849 2850
	/*---------
	 * Removed the following ProcessingMode change -- inoue
	 * At this point
	 * 1) Catalog Cache isn't initialized
	 * 2) Relation Cache for the following critical indexes aren't built
	 * oldmode = GetProcessingMode();
	 * SetProcessingMode(BootstrapProcessing);
	 *---------
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2851
	 */
2852 2853

	bi.infotype = INFO_RELNAME;
2854
	bi.i.info_name = AttributeRelidNumIndex;
2855
	irel[0] = RelationBuildDesc(bi, NULL);
2856 2857 2858
	irel[0]->rd_isnailed = true;

	bi.i.info_name = ClassNameIndex;
2859
	irel[1] = RelationBuildDesc(bi, NULL);
2860 2861 2862
	irel[1]->rd_isnailed = true;

	bi.i.info_name = ClassOidIndex;
2863
	irel[2] = RelationBuildDesc(bi, NULL);
2864 2865
	irel[2]->rd_isnailed = true;

2866
	criticalRelcachesBuilt = true;
2867 2868 2869 2870

	/*
	 * Removed the following ProcessingMode -- inoue
	 * SetProcessingMode(oldmode);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2871
	 */
2872

2873 2874 2875
	/*
	 * Write out the index reldescs to the special cache file.
	 */
2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894
	for (relno = 0; relno < Num_indices_bootstrap; relno++)
	{
		ird = irel[relno];

		/* save the volatile fields in the relation descriptor */
		am = ird->rd_am;
		ird->rd_am = (Form_pg_am) NULL;
		relform = ird->rd_rel;
		ird->rd_rel = (Form_pg_class) NULL;
		strat = ird->rd_istrat;
		support = ird->rd_support;

		/*
		 * first write the relation descriptor , excluding strategy and
		 * support
		 */
		len = sizeof(RelationData);

		/* first, write the relation descriptor length */
2895 2896
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2897 2898 2899 2900 2901 2902 2903 2904
			elog(FATAL, "cannot write init file -- descriptor length");

		/* next, write out the Relation structure */
		if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
			elog(FATAL, "cannot write init file -- reldesc");

		/* next, write the access method tuple form */
		len = sizeof(FormData_pg_am);
2905 2906
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2907 2908 2909 2910 2911 2912 2913
			elog(FATAL, "cannot write init file -- am tuple form length");

		if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
			elog(FATAL, "cannot write init file -- am tuple form");

		/* next write the relation tuple form */
		len = sizeof(FormData_pg_class);
2914 2915
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2916 2917 2918 2919 2920 2921 2922 2923 2924
			elog(FATAL, "cannot write init file -- relation tuple form length");

		if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
			elog(FATAL, "cannot write init file -- relation tuple form");

		/* next, do all the attribute tuple form data entries */
		len = ATTRIBUTE_TUPLE_SIZE;
		for (i = 0; i < relform->relnatts; i++)
		{
2925 2926
			if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
				!= sizeof(len))
2927 2928 2929 2930 2931 2932 2933 2934 2935
				elog(FATAL, "cannot write init file -- length of attdesc %d", i);
			if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len))
				!= len)
				elog(FATAL, "cannot write init file -- attdesc %d", i);
		}

		/* next, write the index strategy map */
		len = AttributeNumberGetIndexStrategySize(relform->relnatts,
												  am->amstrategies);
2936 2937
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2938 2939 2940 2941 2942 2943 2944
			elog(FATAL, "cannot write init file -- strategy map length");

		if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
			elog(FATAL, "cannot write init file -- strategy map");

		/* finally, write the vector of support procedures */
		len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
2945 2946
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2947 2948 2949 2950 2951 2952 2953 2954
			elog(FATAL, "cannot write init file -- support vector length");

		if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
			elog(FATAL, "cannot write init file -- support vector");

		/* restore volatile fields */
		ird->rd_am = am;
		ird->rd_rel = relform;
2955
	}
2956 2957

	FileClose(fd);
2958

2959 2960
	/*
	 * And rename the temp file to its final name, deleting any
2961
	 * previously-existing init file.
2962
	 */
2963 2964
	if (rename(tempfilename, finalfilename) < 0)
		elog(NOTICE, "Cannot rename init file %s to %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename, finalfilename);
2965
}