relcache.c 76.8 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.136 2001/06/01 02:41:36 tgl 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
#include "catalog/pg_rewrite.h"
#include "catalog/pg_type.h"
52
#include "commands/trigger.h"
Bruce Momjian's avatar
Bruce Momjian committed
53 54 55
#include "lib/hasht.h"
#include "miscadmin.h"
#include "storage/smgr.h"
56
#include "utils/builtins.h"
Bruce Momjian's avatar
Bruce Momjian committed
57
#include "utils/catcache.h"
58
#include "utils/fmgroids.h"
59
#include "utils/memutils.h"
Bruce Momjian's avatar
Bruce Momjian committed
60
#include "utils/relcache.h"
61
#include "utils/temprel.h"
Bruce Momjian's avatar
Bruce Momjian committed
62

63

64
/*
65
 *		hardcoded tuple descriptors.  see lib/backend/catalog/pg_attribute.h
66
 *
67
 */
68 69 70 71 72
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};
73

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

84 85 86 87 88 89 90
/*
 * 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;

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

98 99 100 101 102 103
/*
 * 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;

104

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

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

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

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

140
/*
141
 *		macros to manipulate name cache and id cache
142
 *
143 144
 */
#define RelationCacheInsert(RELATION)	\
145 146
do { \
	RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
147
	char *relname; RelNodeCacheEnt *nodentry; bool found; \
148
	relname = RelationGetPhysicalRelationName(RELATION); \
149 150
	namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
											   relname, \
151 152
											   HASH_ENTER, \
											   &found); \
153 154 155 156 157 158
	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, \
159
										   (char *)&(RELATION->rd_id), \
160 161 162 163 164 165 166
										   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; \
167 168 169 170 171 172 173 174 175
	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; \
176 177
} while(0)

178
#define RelationNameCacheLookup(NAME, RELATION) \
179 180 181 182 183 184 185 186 187 188 189 190
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)

191
#define RelationIdCacheLookup(ID, RELATION) \
192 193 194 195 196 197 198 199 200 201 202 203 204
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)

205 206 207 208 209 210 211 212 213 214 215 216 217 218
#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)

219 220 221
#define RelationCacheDelete(RELATION) \
do { \
	RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
222
	char *relname; RelNodeCacheEnt *nodentry; bool found; \
223
	relname = RelationGetPhysicalRelationName(RELATION); \
224 225 226 227 228 229 230 231 232
	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, \
233
										   (char *)&(RELATION->rd_id), \
234 235 236 237 238
										   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."); \
239 240 241 242 243 244 245
	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."); \
246
} while(0)
247

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

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

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

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

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

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

284

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

291

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

	/*
	 * 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.
	 */

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

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

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

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

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

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

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

370
		/*
371 372 373 374
		 * 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.
375
		 *
376
		 */
377
		return_tuple = heap_copytuple(pg_class_tuple);
378 379 380 381
	}

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

	return return_tuple;
385 386
}

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

393
	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
394

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

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

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

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

422
	heap_close(pg_class_desc, AccessShareLock);
423

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

426
	return return_tuple;
427 428
}

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

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

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

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

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

465
	/*
466
	 * Copy the relation tuple form
467
	 *
468 469 470 471 472 473
	 * 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.
474
	 *
475 476
	 */
	relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
477

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

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

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

	MemoryContextSwitchTo(oldcxt);

488
	return relation;
489 490
}

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

	/*
	 * 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.
	 */

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
515
static void
516 517 518 519
SetConstrOfRelation(Relation relation,
					TupleConstr *constr,
					int ndef,
					AttrDefault *attrdef)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
{
	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;
541 542
			constr->check = (ConstrCheck *)
				MemoryContextAlloc(CacheMemoryContext,
543
								constr->num_check * sizeof(ConstrCheck));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
544 545 546 547 548 549 550 551 552 553 554 555 556
			MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
			RelCheckFetch(relation);
		}
		else
			constr->num_check = 0;
	}
	else
	{
		pfree(constr);
		relation->rd_att->constr = NULL;
	}
}

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

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

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

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

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

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

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

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

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

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

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

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

647
	/*
648 649 650
	 * 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.
651
	 *
652 653 654
	 */
#ifdef USE_ASSERT_CHECKING
	{
655
		int			i;
656 657 658 659 660 661

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

662
	/*
663 664 665 666
	 * 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().
667
	 *
668 669 670
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

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

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

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

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

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

697
#endif	 /* _DROP_COLUMN_HACK__ */
698

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

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

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

722 723 724 725 726 727
		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);
728

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

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

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

755
	heap_close(attrel, AccessShareLock);
756

757
	/*
758 759 760
	 * 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.
761
	 *
762 763 764 765 766 767
	 */
#ifdef USE_ASSERT_CHECKING
	for (i = 0; i < relation->rd_rel->relnatts; i++)
		Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
#endif

768
	/*
769 770 771 772
	 * 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().
773
	 *
774 775 776
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

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

780
/*
781
 *		RelationBuildRuleLock
782
 *
783 784
 *		Form the relation's rewrite rules from information in
 *		the pg_rewrite system catalog.
785 786 787 788 789 790 791
 *
 * 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()
792
 * manageable.	The other subsidiary data structures are simple enough
793
 * to be easy to free explicitly, anyway.
794
 *
795 796 797 798
 */
static void
RelationBuildRuleLock(Relation relation)
{
799 800
	MemoryContext rulescxt;
	MemoryContext oldcxt;
801 802 803 804 805 806 807 808 809
	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;
810

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

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

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

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

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

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

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

863 864 865 866 867 868 869 870 871
		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,
872
											  Anum_pg_rewrite_is_instead,
873 874
													pg_rewrite_tupdesc,
													&isnull));
875

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

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

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

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

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

	relation->rd_rules = rulelock;
925 926
}

927
/*
928 929 930 931 932
 *		equalRuleLocks
 *
 *		Determine whether two RuleLocks are equivalent
 *
 *		Probably this should be in the rules code someplace...
933
 *
934 935 936 937
 */
static bool
equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
{
938 939
	int			i,
				j;
940 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

	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;
972
			if (!equal(rule1->qual, rule2->qual))
973
				return false;
974
			if (!equal(rule1->actions, rule2->actions))
975 976 977 978 979 980
				return false;
		}
	}
	else if (rlock2 != NULL)
		return false;
	return true;
981 982 983
}


984
/* ----------------------------------
985 986
 *		RelationBuildDesc
 *
987 988 989 990 991
 *		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.
 *
992 993 994
 *		To build a relation descriptor, we have to allocate space,
 *		open the underlying unix file and initialize the following
 *		fields:
995
 *
996 997 998 999 1000 1001
 *	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
1002
 *	Oid					   rd_id;		 relation's object id
1003
 *	LockInfoData		   rd_lockInfo;  lock manager's info
1004
 *	TupleDesc			   rd_att;		 tuple descriptor
1005
 *
1006 1007 1008 1009
 *		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
1010 1011
 * --------------------------------
 */
1012
static Relation
1013 1014
RelationBuildDesc(RelationBuildDescInfo buildinfo,
				  Relation oldrelation)
1015
{
1016 1017 1018
	Relation	relation;
	Oid			relid;
	Oid			relam;
1019
	HeapTuple	pg_class_tuple;
1020 1021
	Form_pg_class relp;
	MemoryContext oldcxt;
1022

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1119 1120 1121 1122 1123 1124
	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;

1125
	/*
1126
	 * Open the relation and assign the file descriptor returned by the
1127
	 * storage manager code to rd_fd.
1128
	 *
1129 1130 1131
	 * 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.
1132
	 */
1133
	if (relation->rd_rel->relkind != RELKIND_VIEW)
1134 1135 1136 1137 1138 1139 1140
	{
		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));
	}
1141
	else
1142
		relation->rd_fd = -1;
1143

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

1153
	return relation;
1154 1155 1156 1157 1158
}

static void
IndexedAccessMethodInitialize(Relation relation)
{
1159 1160 1161 1162 1163
	IndexStrategy strategy;
	RegProcedure *support;
	int			natts;
	Size		stratSize;
	Size		supportSize;
1164 1165
	uint16		amstrategies;
	uint16		amsupport;
1166 1167

	natts = relation->rd_rel->relnatts;
1168 1169 1170 1171
	amstrategies = relation->rd_am->amstrategies;
	amsupport = relation->rd_am->amsupport;

	stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
1172 1173
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  stratSize);
1174

1175
	if (amsupport > 0)
1176
	{
1177
		supportSize = natts * (amsupport * 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
						   RelationGetRelid(relation),
1187
						   relation->rd_rel->relam,
1188
						   amstrategies, amsupport, natts);
1189 1190

	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
	relation = (Relation) palloc(sizeof(RelationData));
	MemSet((char *) relation, 0, sizeof(RelationData));
1219

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

1225
	/*
1226
	 * initialize reference count
1227 1228 1229
	 */
	RelationSetReferenceCount(relation, 1);

1230
	/*
1231
	 * all entries built with this routine are nailed-in-cache
1232
	 */
1233
	relation->rd_isnailed = true;
1234

1235
	/*
1236
	 * initialize relation tuple form
1237
	 *
1238 1239 1240
	 * 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.
1241
	 */
1242 1243 1244 1245
	relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
	MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);

	strcpy(RelationGetPhysicalRelationName(relation), relationName);
1246 1247 1248 1249 1250 1251 1252 1253

	/*
	 * 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))
1254
		relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1255 1256 1257
	else
		relation->rd_rel->relisshared = false;

1258 1259
	relation->rd_rel->relpages = 1;
	relation->rd_rel->reltuples = 1;
1260
	relation->rd_rel->relkind = RELKIND_RELATION;
1261
	relation->rd_rel->relnatts = (int16) natts;
1262

1263
	/*
1264
	 * initialize attribute tuple form
1265 1266
	 */
	relation->rd_att = CreateTemplateTupleDesc(natts);
1267

1268
	/*
1269
	 * initialize tuple desc info
1270 1271 1272
	 */
	for (i = 0; i < natts; i++)
	{
1273
		relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1274 1275
		memcpy((char *) relation->rd_att->attrs[i],
			   (char *) &att[i],
1276 1277 1278
			   ATTRIBUTE_TUPLE_SIZE);
	}

1279
	/*
1280
	 * initialize relation id from info in att array (my, this is ugly)
1281
	 */
1282
	RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
1283

1284
	/*
1285
	 * initialize the relation's lock manager and RelFileNode information
1286 1287 1288
	 */
	RelationInitLockInfo(relation);		/* see lmgr.c */

1289 1290 1291 1292
	if (IsSharedSystemRelationName(relationName))
		relation->rd_node.tblNode = InvalidOid;
	else
		relation->rd_node.tblNode = MyDatabaseId;
1293
	relation->rd_node.relNode =
1294 1295
		relation->rd_rel->relfilenode = RelationGetRelid(relation);

1296
	/*
1297
	 * initialize the rel-has-index flag, using hardwired knowledge
1298
	 */
1299
	relation->rd_rel->relhasindex = false;
1300

1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
	/* 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;
			}
		}
	}

1314
	/*
1315
	 * add new reldesc to relcache
1316
	 */
1317
	RelationCacheInsert(relation);
1318 1319 1320
}


1321
/*
1322 1323 1324 1325
 *		fixrdesc
 *
 *		Update the phony data inserted by formrdesc() with real info
 *		from pg_class.
1326
 *
1327 1328 1329 1330 1331 1332 1333 1334 1335
 */
static void
fixrdesc(char *relationName)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
	Form_pg_class relp;
	Relation	relation;

1336
	/*
1337
	 * find the tuple in pg_class corresponding to the given relation name
1338
	 *
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
	 */
	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);

1350
	/*
1351
	 * find the pre-made relcache entry (better be there!)
1352
	 *
1353 1354 1355 1356 1357 1358
	 */
	relation = RelationNameCacheGetRelation(relationName);
	if (!RelationIsValid(relation))
		elog(FATAL, "fixrdesc: no existing relcache entry for %s",
			 relationName);

1359
	/*
1360 1361
	 * and copy pg_class_tuple to relation->rd_rel. (See notes in
	 * AllocateRelationDesc())
1362
	 *
1363 1364 1365 1366 1367 1368 1369 1370
	 */
	Assert(relation->rd_rel != NULL);
	memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);

	heap_freetuple(pg_class_tuple);
}


1371
/* ----------------------------------------------------------------
1372
 *				 Relation Descriptor Lookup Interface
1373 1374 1375
 * ----------------------------------------------------------------
 */

1376
/*
1377
 *		RelationIdCacheGetRelation
1378
 *
1379 1380 1381
 *		Lookup an existing reldesc by OID.
 *
 *		Only try to get the reldesc by looking in the cache,
1382 1383 1384 1385 1386
 *		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().)
1387
 *
1388 1389 1390 1391
 */
Relation
RelationIdCacheGetRelation(Oid relationId)
{
1392
	Relation	rd;
1393 1394 1395 1396 1397

	RelationIdCacheLookup(relationId, rd);

	if (RelationIsValid(rd))
	{
1398
		/* re-open files if necessary */
1399
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1400
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1401 1402

		RelationIncrementReferenceCount(rd);
1403
	}
1404

1405
	return rd;
1406 1407
}

1408
/*
1409
 *		RelationNameCacheGetRelation
1410 1411
 *
 *		As above, but lookup by name.
1412
 *
1413
 */
1414
static Relation
1415
RelationNameCacheGetRelation(const char *relationName)
1416
{
1417 1418
	Relation	rd;
	NameData	name;
1419 1420 1421 1422 1423 1424

	/*
	 * make sure that the name key used for hash lookup is properly
	 * null-padded
	 */
	namestrcpy(&name, relationName);
1425
	RelationNameCacheLookup(NameStr(name), rd);
1426 1427 1428

	if (RelationIsValid(rd))
	{
1429
		/* re-open files if necessary */
1430
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1431
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1432 1433

		RelationIncrementReferenceCount(rd);
1434
	}
1435

1436
	return rd;
1437 1438
}

1439 1440 1441 1442 1443 1444 1445 1446 1447
Relation
RelationNodeCacheGetRelation(RelFileNode rnode)
{
	Relation	rd;

	RelationNodeCacheLookup(rnode, rd);

	if (RelationIsValid(rd))
	{
1448
		/* re-open files if necessary */
1449
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1450
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1451 1452 1453 1454 1455 1456 1457

		RelationIncrementReferenceCount(rd);
	}

	return rd;
}

1458
/*
1459
 *		RelationIdGetRelation
1460
 *
1461 1462 1463 1464 1465
 *		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().)
1466
 *
1467 1468 1469 1470
 */
Relation
RelationIdGetRelation(Oid relationId)
{
1471
	Relation	rd;
1472 1473
	RelationBuildDescInfo buildinfo;

1474
	/*
1475
	 * increment access statistics
1476
	 *
1477 1478 1479 1480
	 */
	IncrHeapAccessStat(local_RelationIdGetRelation);
	IncrHeapAccessStat(global_RelationIdGetRelation);

1481
	/*
1482
	 * first try and get a reldesc from the cache
1483
	 *
1484 1485 1486 1487 1488
	 */
	rd = RelationIdCacheGetRelation(relationId);
	if (RelationIsValid(rd))
		return rd;

1489
	/*
1490 1491
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1492
	 *
1493 1494 1495 1496
	 */
	buildinfo.infotype = INFO_RELID;
	buildinfo.i.info_id = relationId;

1497
	rd = RelationBuildDesc(buildinfo, NULL);
1498
	return rd;
1499 1500
}

1501
/*
1502
 *		RelationNameGetRelation
1503
 *
1504
 *		As above, but lookup by name.
1505
 *
1506 1507
 */
Relation
1508
RelationNameGetRelation(const char *relationName)
1509
{
1510
	char	   *temprelname;
1511
	Relation	rd;
1512 1513
	RelationBuildDescInfo buildinfo;

1514
	/*
1515
	 * increment access statistics
1516
	 *
1517 1518 1519 1520
	 */
	IncrHeapAccessStat(local_RelationNameGetRelation);
	IncrHeapAccessStat(global_RelationNameGetRelation);

1521
	/*
1522 1523
	 * if caller is looking for a temp relation, substitute its real name;
	 * we only index temp rels by their real names.
1524
	 *
1525
	 */
1526
	temprelname = get_temp_rel_by_username(relationName);
1527
	if (temprelname != NULL)
1528 1529
		relationName = temprelname;

1530
	/*
1531
	 * first try and get a reldesc from the cache
1532
	 *
1533 1534 1535 1536 1537
	 */
	rd = RelationNameCacheGetRelation(relationName);
	if (RelationIsValid(rd))
		return rd;

1538
	/*
1539 1540
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1541
	 *
1542 1543
	 */
	buildinfo.infotype = INFO_RELNAME;
1544
	buildinfo.i.info_name = (char *) relationName;
1545

1546
	rd = RelationBuildDesc(buildinfo, NULL);
1547 1548 1549 1550
	return rd;
}

/* ----------------------------------------------------------------
1551
 *				cache invalidation support routines
1552 1553 1554
 * ----------------------------------------------------------------
 */

1555
/*
1556 1557
 * RelationClose - close an open relation
 *
1558 1559 1560 1561 1562 1563 1564
 *	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.
1565
 *
1566 1567 1568 1569
 */
void
RelationClose(Relation relation)
{
1570 1571
	/* Note: no locking manipulations needed */
	RelationDecrementReferenceCount(relation);
1572 1573 1574 1575 1576

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1579
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
1580
/*
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1581 1582 1583 1584 1585
 * RelationReloadClassinfo
 *
 *	This function is especially for nailed relations.
 *	relhasindex/relfilenode could be changed even for
 *	nailed relations.
1586
 *
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1587 1588 1589 1590 1591 1592
 */
static void
RelationReloadClassinfo(Relation relation)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
1593
	Form_pg_class relp;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613

	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;
}
1614 1615

#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1616

1617
/*
1618
 * RelationClearRelation
1619
 *
1620 1621 1622 1623 1624
 *	 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.
1625
 *
1626
 */
1627
static void
1628
RelationClearRelation(Relation relation, bool rebuildIt)
1629
{
1630 1631 1632
	MemoryContext oldcxt;

	/*
1633
	 * Make sure smgr and lower levels close the relation's files, if they
1634
	 * weren't closed already.  If the relation is not getting deleted,
1635
	 * the next smgr access should reopen the files automatically.	This
1636 1637
	 * ensures that the low-level file access state is updated after, say,
	 * a vacuum truncation.
1638
	 */
1639 1640
	if (relation->rd_fd >= 0)
		smgrclose(DEFAULT_SMGR, relation);
1641

1642
	/*
1643 1644
	 * Never, never ever blow away a nailed-in system relation, because
	 * we'd be unable to recover.
1645 1646
	 */
	if (relation->rd_isnailed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1647
	{
1648
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1649
		RelationReloadClassinfo(relation);
1650
#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1651
		return;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1652
	}
1653

1654 1655
	/*
	 * Remove relation from hash tables
1656 1657 1658 1659 1660
	 *
	 * 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...
	 */
1661
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
1662
	RelationCacheDelete(relation);
1663
	MemoryContextSwitchTo(oldcxt);
1664 1665 1666

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

1668
	/*
1669 1670 1671 1672 1673 1674
	 * 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:
1675 1676 1677 1678 1679 1680 1681 1682 1683
	 */
	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);
1684
	freeList(relation->rd_indexlist);
1685

1686
	/*
1687 1688 1689 1690
	 * 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).
1691
	 */
1692
	if (!rebuildIt)
1693
	{
1694 1695
		/* ok to zap remaining substructure */
		FreeTupleDesc(relation->rd_att);
1696 1697
		if (relation->rd_rulescxt)
			MemoryContextDelete(relation->rd_rulescxt);
1698
		FreeTriggerDesc(relation->trigdesc);
1699 1700 1701 1702
		pfree(relation);
	}
	else
	{
1703

1704 1705 1706
		/*
		 * When rebuilding an open relcache entry, must preserve ref count
		 * and myxactonly flag.  Also attempt to preserve the tupledesc,
1707 1708 1709
		 * 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).
1710
		 */
1711 1712 1713 1714
		uint16		old_refcnt = relation->rd_refcnt;
		bool		old_myxactonly = relation->rd_myxactonly;
		TupleDesc	old_att = relation->rd_att;
		RuleLock   *old_rules = relation->rd_rules;
1715
		MemoryContext old_rulescxt = relation->rd_rulescxt;
1716 1717
		TriggerDesc *old_trigdesc = relation->trigdesc;
		int			old_nblocks = relation->rd_nblocks;
1718
		RelationBuildDescInfo buildinfo;
1719

1720 1721
		buildinfo.infotype = INFO_RELID;
		buildinfo.i.info_id = RelationGetRelid(relation);
1722

1723
		if (RelationBuildDesc(buildinfo, relation) != relation)
1724
		{
1725
			/* Should only get here if relation was deleted */
1726
			FreeTupleDesc(old_att);
1727 1728
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1729
			FreeTriggerDesc(old_trigdesc);
1730
			pfree(relation);
1731
			elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
1732
				 buildinfo.i.info_id);
1733
		}
1734
		RelationSetReferenceCount(relation, old_refcnt);
1735
		relation->rd_myxactonly = old_myxactonly;
1736 1737 1738 1739 1740 1741 1742 1743 1744
		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))
		{
1745 1746
			if (relation->rd_rulescxt)
				MemoryContextDelete(relation->rd_rulescxt);
1747
			relation->rd_rules = old_rules;
1748
			relation->rd_rulescxt = old_rulescxt;
1749 1750 1751
		}
		else
		{
1752 1753
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1754 1755 1756 1757 1758 1759 1760 1761 1762
		}
		if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
		{
			FreeTriggerDesc(relation->trigdesc);
			relation->trigdesc = old_trigdesc;
		}
		else
			FreeTriggerDesc(old_trigdesc);
		relation->rd_nblocks = old_nblocks;
1763 1764 1765

		/*
		 * this is kind of expensive, but I think we must do it in case
1766 1767
		 * relation has been truncated...
		 */
1768
		relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
1769
	}
1770 1771
}

1772
/*
1773 1774 1775
 * RelationFlushRelation
 *
 *	 Rebuild the relation if it is open (refcount > 0), else blow it away.
1776
 *
1777 1778
 */
static void
1779
RelationFlushRelation(Relation relation)
1780
{
1781
	bool		rebuildIt;
1782 1783

	if (relation->rd_myxactonly)
1784
	{
1785

1786 1787 1788 1789 1790 1791 1792 1793
		/*
		 * Local rels should always be rebuilt, not flushed; the relcache
		 * entry must live until RelationPurgeLocalRelation().
		 */
		rebuildIt = true;
	}
	else
	{
1794

1795 1796 1797
		/*
		 * Nonlocal rels can be dropped from the relcache if not open.
		 */
1798
		rebuildIt = !RelationHasReferenceCountZero(relation);
1799
	}
1800

1801
	RelationClearRelation(relation, rebuildIt);
1802 1803
}

1804
/*
1805 1806 1807 1808
 * RelationForgetRelation -
 *
 *		   RelationClearRelation + if the relation is myxactonly then
 *		   remove the relation descriptor from the newly created
1809
 *		   relation list.
1810
 *
1811 1812
 */
void
1813
RelationForgetRelation(Oid rid)
1814
{
1815
	Relation	relation;
1816 1817 1818

	RelationIdCacheLookup(rid, relation);

1819
	if (PointerIsValid(relation))
1820
	{
1821
		if (relation->rd_myxactonly)
1822
		{
1823 1824
			List	   *curr;
			List	   *prev = NIL;
Bruce Momjian's avatar
Bruce Momjian committed
1825

1826 1827 1828
			foreach(curr, newlyCreatedRelns)
			{
				Relation	reln = lfirst(curr);
Bruce Momjian's avatar
Bruce Momjian committed
1829

1830 1831 1832 1833 1834 1835 1836
				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",
1837
					 RelationGetRelationName(relation));
1838 1839 1840 1841 1842
			if (prev == NIL)
				newlyCreatedRelns = lnext(newlyCreatedRelns);
			else
				lnext(prev) = lnext(curr);
			pfree(curr);
1843
		}
Bruce Momjian's avatar
Bruce Momjian committed
1844

1845 1846
		/* Unconditionally destroy the relcache entry */
		RelationClearRelation(relation, false);
1847
	}
1848 1849
}

1850
/*
1851
 *		RelationIdInvalidateRelationCacheByRelationId
1852 1853 1854 1855 1856 1857 1858 1859
 *
 *		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.
1860
 *
1861 1862 1863 1864
 */
void
RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
{
1865
	Relation	relation;
1866 1867 1868

	RelationIdCacheLookup(relationId, relation);

1869
	if (PointerIsValid(relation))
1870
		RelationFlushRelation(relation);
1871 1872
}

1873 1874 1875
#if NOT_USED
/* only used by RelationIdInvalidateRelationCacheByAccessMethodId,
 * which is dead code.
1876 1877
 */
static void
1878
RelationFlushIndexes(Relation *r,
1879
					 Oid accessMethodId)
1880
{
1881
	Relation	relation = *r;
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891

	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))
1892
		RelationFlushRelation(relation);
1893
}
1894

1895 1896
#endif

1897 1898 1899

/*
 * RelationCacheInvalidate
1900 1901
 *	 Blow away cached relation descriptors that have zero reference counts,
 *	 and rebuild those with positive reference counts.
1902
 *
1903
 *	 This is currently used only to recover from SI message buffer overflow,
1904 1905 1906
 *	 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).
1907 1908 1909 1910
 *
 *	 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
1911
 *	 the element it is currently visiting.	If a second SI overflow were to
1912 1913 1914 1915 1916 1917
 *	 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.
1918 1919
 */
void
1920
RelationCacheInvalidate(void)
1921
{
1922 1923
	List	   *rebuildList = NIL;
	List	   *l;
1924 1925 1926 1927 1928 1929 1930

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

	/* Phase 2: rebuild the items found to need rebuild in phase 1 */
1931
	foreach(l, rebuildList)
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943
	{
		Relation	relation = (Relation) lfirst(l);

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

static void
RelationCacheInvalidateWalker(Relation *relationPtr, Datum listp)
{
	Relation	relation = *relationPtr;
1944
	List	  **rebuildList = (List **) DatumGetPointer(listp);
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959

	/* 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);
	}
1960
}
1961

1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977
/*
 * 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)
{
1978 1979
	HashTableWalk(RelationNameCache,
				  (HashtFunc) RelationCacheAbortWalker,
1980 1981 1982 1983
				  0);
}

static void
1984
RelationCacheAbortWalker(Relation *relationPtr, Datum dummy)
1985 1986 1987 1988 1989 1990 1991 1992
{
	Relation	relation = *relationPtr;

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

1994
/*
1995 1996 1997
 *		RelationRegisterRelation -
 *		   register the Relation descriptor of a newly created relation
 *		   with the relation descriptor Cache.
1998
 *
1999 2000 2001 2002
 */
void
RelationRegisterRelation(Relation relation)
{
2003
	MemoryContext oldcxt;
2004 2005 2006

	RelationInitLockInfo(relation);

2007 2008
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

2009 2010
	RelationCacheInsert(relation);

2011 2012
	/*
	 * we've just created the relation. It is invisible to anyone else
Bruce Momjian's avatar
Bruce Momjian committed
2013 2014
	 * before the transaction is committed. Setting rd_myxactonly allows
	 * us to use the local buffer manager for select/insert/etc before the
2015 2016 2017 2018
	 * 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
	 */
2019
	relation->rd_myxactonly = TRUE;
2020 2021 2022
	newlyCreatedRelns = lcons(relation, newlyCreatedRelns);

	MemoryContextSwitchTo(oldcxt);
2023 2024 2025 2026
}

/*
 * RelationPurgeLocalRelation -
2027
 *	  find all the Relation descriptors marked rd_myxactonly and reset them.
2028 2029 2030
 *	  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.
2031 2032 2033 2034
 */
void
RelationPurgeLocalRelation(bool xactCommitted)
{
2035 2036
	while (newlyCreatedRelns)
	{
2037 2038
		List	   *l = newlyCreatedRelns;
		Relation	reln = lfirst(l);
2039

2040
		Assert(reln != NULL && reln->rd_myxactonly);
2041

2042
		reln->rd_myxactonly = false;	/* mark it not on list anymore */
2043 2044 2045 2046

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

2047
		/* XXX is this step still needed?  If so, why? */
2048
		if (!IsBootstrapProcessingMode())
2049
			RelationClearRelation(reln, false);
2050
	}
2051 2052
}

2053
/*
2054
 *		RelationCacheInitialize
2055
 *
2056
 *		This initializes the relation descriptor cache.
2057
 *
2058 2059
 */

2060
#define INITRELCACHESIZE		400
2061 2062

void
2063
RelationCacheInitialize(void)
2064
{
2065 2066
	MemoryContext oldcxt;
	HASHCTL		ctl;
2067

2068
	/*
2069
	 * switch to cache memory context
2070
	 *
2071
	 */
2072 2073
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
2074

2075
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2076

2077
	/*
2078
	 * create global caches
2079
	 *
2080
	 */
Bruce Momjian's avatar
Bruce Momjian committed
2081
	MemSet(&ctl, 0, (int) sizeof(ctl));
2082 2083 2084 2085 2086 2087 2088 2089 2090
	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);

2091 2092 2093
	ctl.keysize = sizeof(RelFileNode);
	ctl.hash = tag_hash;
	RelationNodeCache = hash_create(INITRELCACHESIZE, &ctl,
2094
									HASH_ELEM | HASH_FUNCTION);
2095

2096
	/*
2097 2098 2099
	 * initialize the cache with pre-made relation descriptors for some of
	 * the more important system relations.  These relations should always
	 * be in the cache.
2100
	 *
2101
	 * NB: see also the list in RelationCacheInitializePhase2().
2102
	 *
2103 2104 2105 2106 2107 2108 2109 2110
	 */
	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);

	/*
2111 2112 2113
	 * init_irels() used to be called here. It is changed to be called in
	 * RelationCacheInitializePhase2() now so that transactional control
	 * could guarantee the consistency.
2114 2115 2116
	 */

	MemoryContextSwitchTo(oldcxt);
2117 2118
}

2119
/*
2120 2121 2122 2123
 *		RelationCacheInitializePhase2
 *
 *		This completes initialization of the relcache after catcache
 *		is functional and we are able to actually load data from pg_class.
2124
 *
2125 2126 2127 2128
 */
void
RelationCacheInitializePhase2(void)
{
2129

2130 2131 2132
	/*
	 * Get the real pg_class tuple for each nailed-in-cache relcache entry
	 * that was made by RelationCacheInitialize(), and replace the phony
2133 2134 2135
	 * 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.
2136 2137 2138
	 */
	if (!IsBootstrapProcessingMode())
	{
2139

2140 2141 2142
		/*
		 * Initialize critical system index relation descriptors, first.
		 * They are to make building relation descriptors fast.
2143 2144
		 * init_irels() used to be called in RelationCacheInitialize(). It
		 * is changed to be called here to be transaction safe.
2145 2146
		 */
		MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2147

2148 2149 2150 2151
		init_irels();
		MemoryContextSwitchTo(oldcxt);

		/* fix nailed-in-cache relations */
2152 2153 2154 2155
		fixrdesc(RelationRelationName);
		fixrdesc(AttributeRelationName);
		fixrdesc(ProcedureRelationName);
		fixrdesc(TypeRelationName);
2156 2157

		/*
2158
		 * We don't bother to update the entries for pg_log.
2159
		 */
2160 2161 2162
	}
}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
2163
/* used by XLogInitCache */
2164 2165
void		CreateDummyCaches(void);
void		DestroyDummyCaches(void);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2166 2167 2168 2169

void
CreateDummyCaches(void)
{
2170 2171
	MemoryContext oldcxt;
	HASHCTL		ctl;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190

	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,
2191
									HASH_ELEM | HASH_FUNCTION);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2192 2193 2194 2195 2196 2197
	MemoryContextSwitchTo(oldcxt);
}

void
DestroyDummyCaches(void)
{
2198
	MemoryContext oldcxt;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216

	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);
}

2217
static void
2218
AttrDefaultFetch(Relation relation)
2219
{
2220 2221 2222
	AttrDefault *attrdef = relation->rd_att->constr->defval;
	int			ndef = relation->rd_att->constr->num_defval;
	Relation	adrel;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2223
	Relation	irel = (Relation) NULL;
2224
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2225
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2226
	HeapTuple	htup;
2227
	Form_pg_attrdef adform;
2228 2229
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc adscan = (HeapScanDesc) NULL;
2230
	RetrieveIndexResult indexRes;
2231
	Datum		val;
2232 2233 2234
	bool		isnull;
	int			found;
	int			i;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2235
	bool		hasindex;
2236 2237 2238 2239

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2240
						   (RegProcedure) F_OIDEQ,
2241
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2242

2243
	adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2244 2245 2246 2247 2248 2249 2250
	hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
	if (hasindex)
	{
		irel = index_openr(AttrDefaultIndex);
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
2251
		adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey);
2252
	tuple.t_datamcxt = NULL;
2253
	tuple.t_data = NULL;
2254 2255 2256

	for (found = 0;;)
	{
2257 2258
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277
		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;
		}
2278
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2279
		adform = (Form_pg_attrdef) GETSTRUCT(htup);
2280 2281 2282 2283
		for (i = 0; i < ndef; i++)
		{
			if (adform->adnum != attrdef[i].adnum)
				continue;
2284
			if (attrdef[i].adbin != NULL)
2285
				elog(NOTICE, "AttrDefaultFetch: second record found for attr %s in rel %s",
2286
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2287
					 RelationGetRelationName(relation));
2288

2289 2290 2291
			val = fastgetattr(htup,
							  Anum_pg_attrdef_adbin,
							  adrel->rd_att, &isnull);
2292
			if (isnull)
2293
				elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
2294
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2295
					 RelationGetRelationName(relation));
2296 2297
			else
				attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
2298 2299
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2300 2301
			break;
		}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2302 2303
		if (hasindex)
			ReleaseBuffer(buffer);
2304

2305
		if (i >= ndef)
2306
			elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
2307
				 adform->adnum,
2308
				 RelationGetRelationName(relation));
2309 2310 2311
	}

	if (found < ndef)
2312
		elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s",
2313
			 ndef - found, RelationGetRelationName(relation));
2314

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2315 2316 2317 2318 2319 2320 2321
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(adscan);
2322
	heap_close(adrel, AccessShareLock);
2323 2324
}

2325
static void
2326
RelCheckFetch(Relation relation)
2327
{
2328 2329 2330
	ConstrCheck *check = relation->rd_att->constr->check;
	int			ncheck = relation->rd_att->constr->num_check;
	Relation	rcrel;
2331
	Relation	irel = (Relation) NULL;
2332
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2333
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2334
	HeapTuple	htup;
2335 2336
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc rcscan = (HeapScanDesc) NULL;
2337
	RetrieveIndexResult indexRes;
2338
	Name		rcname;
2339
	Datum		val;
2340 2341
	bool		isnull;
	int			found;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2342
	bool		hasindex;
2343 2344 2345 2346

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2347
						   (RegProcedure) F_OIDEQ,
2348
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2349

2350
	rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2351 2352 2353 2354 2355 2356 2357 2358
	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);
2359
	tuple.t_datamcxt = NULL;
2360
	tuple.t_data = NULL;
2361 2362 2363

	for (found = 0;;)
	{
2364 2365
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384
		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;
		}
2385
		if (found == ncheck)
Bruce Momjian's avatar
Bruce Momjian committed
2386
			elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
2387
				 RelationGetRelationName(relation));
2388

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2389
		rcname = (Name) fastgetattr(htup,
2390 2391 2392
									Anum_pg_relcheck_rcname,
									rcrel->rd_att, &isnull);
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2393
			elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
2394
				 RelationGetRelationName(relation));
2395 2396
		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
												  NameStr(*rcname));
2397 2398 2399
		val = fastgetattr(htup,
						  Anum_pg_relcheck_rcbin,
						  rcrel->rd_att, &isnull);
2400
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2401
			elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
2402
				 RelationGetRelationName(relation));
2403
		check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
2404 2405
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2406
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2407 2408
		if (hasindex)
			ReleaseBuffer(buffer);
2409 2410 2411
	}

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2415 2416 2417 2418 2419 2420 2421
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(rcscan);
2422
	heap_close(rcrel, AccessShareLock);
2423 2424
}

2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
/*
 * 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.
 *
2435 2436 2437 2438 2439 2440
 * 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.
 *
2441 2442
 * 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
2443
 * may freeList() the returned list after scanning it.	This is necessary
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
 * 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,
2473
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2474 2475 2476 2477 2478 2479 2480 2481
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
	{
		ScanKeyEntryInitialize(&skey,
							   (bits16) 0x0,
							   (AttrNumber) Anum_pg_index_indrelid,
							   (RegProcedure) F_OIDEQ,
2482
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2483 2484 2485 2486
		hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
	}

	/*
2487 2488 2489 2490
	 * 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.
2491 2492
	 */
	result = NIL;
2493

2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
	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);

2526
		result = insert_ordered_oid(result, index->indexrelid);
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540

		if (hasindex)
			ReleaseBuffer(buffer);
	}

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

2541
	/* Now save a copy of the completed list in the relcache entry. */
2542
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2543 2544 2545 2546 2547 2548 2549
	relation->rd_indexlist = listCopy(result);
	relation->rd_indexfound = true;
	MemoryContextSwitchTo(oldcxt);

	return result;
}

2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582
/*
 * 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;
}


2583
/*
2584 2585
 *	init_irels(), write_irels() -- handle special-case initialization of
 *								   index relation descriptors.
2586
 *
2587 2588 2589
 *		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.
2590
 *
2591 2592 2593 2594
 *		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.
2595
 *
2596
 *		In order to get around the problem, we do the following:
2597
 *
2598 2599
 *		   +  When the database system is initialized (at initdb time), we
 *			  don't use indices on pg_attribute.  We do sequential scans.
2600
 *
2601 2602 2603
 *		   +  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.
2604
 *
2605
 *		   +  If the initialization file isn't there, then we create the
2606
 *			  relation descriptors using sequential scans and write 'em to
2607
 *			  the initialization file for use by subsequent backends.
2608
 *
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
 *		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.
2620 2621 2622 2623 2624
 */

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

2625
static void
2626
init_irels(void)
2627
{
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638
	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;
2639

2640
	if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | PG_BINARY, 0600)) < 0)
2641
	{
2642 2643 2644
		write_irels();
		return;
	}
2645 2646 2647 2648 2649 2650

	FileSeek(fd, 0L, SEEK_SET);

	for (relno = 0; relno < Num_indices_bootstrap; relno++)
	{
		/* first read the relation descriptor length */
2651
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2652 2653 2654 2655 2656 2657
		{
			write_irels();
			return;
		}

		ird = irel[relno] = (Relation) palloc(len);
Bruce Momjian's avatar
Bruce Momjian committed
2658
		MemSet(ird, 0, len);
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669

		/* 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;

2670 2671
		ird->rd_node.tblNode = MyDatabaseId;

2672
		/* next, read the access method tuple form */
2673
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688
		{
			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 */
2689
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710
		{
			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++)
		{
2711
			if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2712 2713 2714 2715 2716
			{
				write_irels();
				return;
			}

2717
			ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
2718 2719 2720 2721 2722 2723 2724 2725 2726

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

		/* next, read the index strategy map */
2727
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
		{
			write_irels();
			return;
		}

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

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

2743
		/* have to reinit the function pointers in the strategy maps */
2744 2745
		for (i = 0; i < am->amstrategies * relform->relnatts; i++)
		{
2746
			fmgr_info(SMD(i).sk_procedure,
2747
					  &(SMD(i).sk_func));
Bruce Momjian's avatar
Bruce Momjian committed
2748
		}
2749 2750 2751 2752 2753 2754 2755 2756

		/*
		 * 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 */
2757
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770
		{
			write_irels();
			return;
		}

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

2771
		RelationInitLockInfo(ird);
2772 2773

		RelationCacheInsert(ird);
2774
	}
2775
	criticalRelcachesBuilt = true;
2776 2777
}

2778
static void
2779
write_irels(void)
2780
{
Bruce Momjian's avatar
Bruce Momjian committed
2781
	Size		len;
2782 2783 2784 2785 2786 2787 2788 2789 2790 2791
	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;
2792
	RelationBuildDescInfo bi;
2793 2794 2795 2796
	char		tempfilename[MAXPGPATH];
	char		finalfilename[MAXPGPATH];

	/*
2797 2798 2799
	 * 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.
2800
	 */
2801 2802 2803 2804
	snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
			 DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid);
	snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
			 DatabasePath, RELCACHE_INIT_FILENAME);
2805

2806
	fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY, 0600);
2807
	if (fd < 0)
2808
	{
2809

2810 2811 2812 2813 2814 2815 2816
		/*
		 * 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;
	}
2817 2818 2819 2820

	FileSeek(fd, 0L, SEEK_SET);

	/*
2821
	 * Build relation descriptors for the critical system indexes without
2822 2823 2824 2825 2826
	 * 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.
2827 2828
	 */

2829 2830 2831 2832 2833 2834 2835 2836
	/*---------
	 * 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
2837
	 */
2838 2839

	bi.infotype = INFO_RELNAME;
2840
	bi.i.info_name = AttributeRelidNumIndex;
2841
	irel[0] = RelationBuildDesc(bi, NULL);
2842 2843 2844
	irel[0]->rd_isnailed = true;

	bi.i.info_name = ClassNameIndex;
2845
	irel[1] = RelationBuildDesc(bi, NULL);
2846 2847 2848
	irel[1]->rd_isnailed = true;

	bi.i.info_name = ClassOidIndex;
2849
	irel[2] = RelationBuildDesc(bi, NULL);
2850 2851
	irel[2]->rd_isnailed = true;

2852
	criticalRelcachesBuilt = true;
2853 2854 2855 2856

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

2859 2860 2861
	/*
	 * Write out the index reldescs to the special cache file.
	 */
2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880
	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 */
2881 2882
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2883 2884 2885 2886 2887 2888 2889 2890
			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);
2891 2892
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2893 2894 2895 2896 2897 2898 2899
			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);
2900 2901
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2902 2903 2904 2905 2906 2907 2908 2909 2910
			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++)
		{
2911 2912
			if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
				!= sizeof(len))
2913 2914 2915 2916 2917 2918 2919 2920 2921
				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);
2922 2923
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2924 2925 2926 2927 2928 2929 2930
			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));
2931 2932
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2933 2934 2935 2936 2937 2938 2939 2940
			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;
2941
	}
2942 2943

	FileClose(fd);
2944

2945 2946
	/*
	 * And rename the temp file to its final name, deleting any
2947
	 * previously-existing init file.
2948
	 */
2949 2950
	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);
2951
}