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.140 2001/06/27 23:31:39 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
#include "postgres.h"

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

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

62

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

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

81 82 83 84 85 86 87
/*
 * 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;

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

95 96 97 98 99 100
/*
 * 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;

101

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

118 119 120 121 122 123
typedef struct relnamecacheent
{
	NameData	relname;
	Relation	reldesc;
} RelNameCacheEnt;

124 125
typedef struct relidcacheent
{
126 127
	Oid			reloid;
	Relation	reldesc;
128
} RelIdCacheEnt;
129

130
typedef struct relnodecacheent
131
{
132
	RelFileNode relnode;
133
	Relation	reldesc;
134
} RelNodeCacheEnt;
135

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

173
#define RelationNameCacheLookup(NAME, RELATION) \
174 175 176 177 178 179 180 181 182 183 184 185
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)

186
#define RelationIdCacheLookup(ID, RELATION) \
187 188 189 190 191 192 193 194 195 196 197 198 199
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)

200 201 202 203 204 205 206 207 208 209 210 211 212 213
#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)

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

243
/* non-export function prototypes */
244 245

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
247 248
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
static void RelationReloadClassinfo(Relation relation);
249 250

#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
251
static void RelationFlushRelation(Relation relation);
252
static Relation RelationNameCacheGetRelation(const char *relationName);
253 254
static void RelationCacheInvalidateWalker(Relation *relationPtr, Datum listp);
static void RelationCacheAbortWalker(Relation *relationPtr, Datum dummy);
255 256 257
static void init_irels(void);
static void write_irels(void);

258
static void formrdesc(char *relationName, int natts,
259
		  FormData_pg_attribute *att);
260
static void fixrdesc(char *relationName);
261

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

279

280
/*
281 282
 *		RelationIdGetRelation() and RelationNameGetRelation()
 *						support functions
283 284
 */

285

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

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

306
	if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
307
		return scan_pg_rel_seq(buildinfo);
308
	else
309
		return scan_pg_rel_ind(buildinfo);
310 311
}

312
static HeapTuple
313 314
scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
{
315 316 317 318 319
	HeapTuple	pg_class_tuple;
	HeapTuple	return_tuple;
	Relation	pg_class_desc;
	HeapScanDesc pg_class_scan;
	ScanKeyData key;
320

321
	/*
322
	 * form a scan key
323
	 */
324 325
	switch (buildinfo.infotype)
	{
326 327 328
		case INFO_RELID:
			ScanKeyEntryInitialize(&key, 0,
								   ObjectIdAttributeNumber,
Bruce Momjian's avatar
Bruce Momjian committed
329
								   F_OIDEQ,
330 331 332 333 334 335
								   ObjectIdGetDatum(buildinfo.i.info_id));
			break;

		case INFO_RELNAME:
			ScanKeyEntryInitialize(&key, 0,
								   Anum_pg_class_relname,
Bruce Momjian's avatar
Bruce Momjian committed
336
								   F_NAMEEQ,
337 338 339 340
								   NameGetDatum(buildinfo.i.info_name));
			break;

		default:
341
			elog(ERROR, "ScanPgRelation: bad buildinfo");
342
			return NULL;
343 344
	}

345
	/*
346
	 * open pg_class and fetch a tuple
347
	 */
348
	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
349 350
	pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
	pg_class_tuple = heap_getnext(pg_class_scan, 0);
351

352
	/*
353
	 * get set to return tuple
354 355 356 357 358
	 */
	if (!HeapTupleIsValid(pg_class_tuple))
		return_tuple = pg_class_tuple;
	else
	{
359

360
		/*
361 362 363 364
		 * 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.
365
		 */
366
		return_tuple = heap_copytuple(pg_class_tuple);
367 368 369 370
	}

	/* all done */
	heap_endscan(pg_class_scan);
371
	heap_close(pg_class_desc, AccessShareLock);
372 373

	return return_tuple;
374 375
}

376
static HeapTuple
377 378
scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
{
379 380
	Relation	pg_class_desc;
	HeapTuple	return_tuple;
381

382
	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
383

Hiroshi Inoue's avatar
Hiroshi Inoue committed
384
	/*
385 386
	 * If the indexes of pg_class are deactivated we have to call
	 * scan_pg_rel_seq() instead.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
387 388 389 390 391 392
	 */
	if (!pg_class_desc->rd_rel->relhasindex)
	{
		heap_close(pg_class_desc, AccessShareLock);
		return scan_pg_rel_seq(buildinfo);
	}
393 394 395

	switch (buildinfo.infotype)
	{
396
		case INFO_RELID:
397
			return_tuple = ClassOidIndexScan(pg_class_desc,
398
								  ObjectIdGetDatum(buildinfo.i.info_id));
399
			break;
400

401 402
		case INFO_RELNAME:
			return_tuple = ClassNameIndexScan(pg_class_desc,
403
								 PointerGetDatum(buildinfo.i.info_name));
404
			break;
405

406
		default:
407
			elog(ERROR, "ScanPgRelation: bad buildinfo");
408
			return_tuple = NULL;/* keep compiler quiet */
409 410
	}

411
	heap_close(pg_class_desc, AccessShareLock);
412

413 414
	/* The xxxIndexScan routines will have returned a palloc'd tuple. */

415
	return return_tuple;
416 417
}

418
/*
419
 *		AllocateRelationDesc
420
 *
421 422
 *		This is used to allocate memory for a new relation descriptor
 *		and initialize the rd_rel field.
423 424 425
 *
 *		If 'relation' is NULL, allocate a new RelationData object.
 *		If not, reuse the given object (that path is taken only when
426
 *		we have to rebuild a relcache entry during RelationClearRelation).
427
 */
428
static Relation
429
AllocateRelationDesc(Relation relation, Form_pg_class relp)
430
{
431
	MemoryContext oldcxt;
432
	Form_pg_class relationForm;
433

434 435
	/* Relcache entries must live in CacheMemoryContext */
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
436

437
	/*
438
	 * allocate space for new relation descriptor, if needed
439
	 */
440
	if (relation == NULL)
441
		relation = (Relation) palloc(sizeof(RelationData));
442

443
	/*
444
	 * clear all fields of reldesc
445
	 */
446
	MemSet((char *) relation, 0, sizeof(RelationData));
447
	relation->rd_targblock = InvalidBlockNumber;
448

449 450 451
	/* make sure relation is marked as having no open file yet */
	relation->rd_fd = -1;

452
	/*
453
	 * Copy the relation tuple form
454
	 *
455 456 457 458 459 460
	 * 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.
461 462
	 */
	relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
463

464 465 466
	memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);

	/* initialize relation tuple form */
467
	relation->rd_rel = relationForm;
468

469 470 471 472 473
	/* and allocate attribute tuple form storage */
	relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);

	MemoryContextSwitchTo(oldcxt);

474
	return relation;
475 476
}

477
/*
478
 *		RelationBuildTupleDesc
479
 *
480 481
 *		Form the relation's tuple descriptor from information in
 *		the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
482 483
 */
static void
484
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
485
					   Relation relation)
486
{
487 488 489 490 491 492 493

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

494 495
	if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
		build_tupdesc_seq(buildinfo, relation);
496
	else
497
		build_tupdesc_ind(buildinfo, relation);
498 499
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
500
static void
501 502 503 504
SetConstrOfRelation(Relation relation,
					TupleConstr *constr,
					int ndef,
					AttrDefault *attrdef)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
{
	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;
526 527
			constr->check = (ConstrCheck *)
				MemoryContextAlloc(CacheMemoryContext,
528
								constr->num_check * sizeof(ConstrCheck));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
529 530 531 532 533 534 535 536 537 538 539 540 541
			MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
			RelCheckFetch(relation);
		}
		else
			constr->num_check = 0;
	}
	else
	{
		pfree(constr);
		relation->rd_att->constr = NULL;
	}
}

542 543
static void
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
544
				  Relation relation)
545
{
546 547 548
	HeapTuple	pg_attribute_tuple;
	Relation	pg_attribute_desc;
	HeapScanDesc pg_attribute_scan;
549
	Form_pg_attribute attp;
550 551
	ScanKeyData key;
	int			need;
552
	TupleConstr *constr;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
553
	AttrDefault *attrdef = NULL;
554
	int			ndef = 0;
555

556 557
	constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
												sizeof(TupleConstr));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
558
	constr->has_not_null = false;
559

560
	/*
561
	 * form a scan key
562 563 564
	 */
	ScanKeyEntryInitialize(&key, 0,
						   Anum_pg_attribute_attrelid,
Bruce Momjian's avatar
Bruce Momjian committed
565
						   F_OIDEQ,
566
						   ObjectIdGetDatum(RelationGetRelid(relation)));
567

568
	/*
569
	 * open pg_attribute and begin a scan
570
	 */
571
	pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock);
572
	pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
573

574
	/*
575
	 * add attribute data to relation->rd_att
576
	 */
577
	need = relation->rd_rel->relnatts;
578

579
	pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
580 581
	while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
	{
582
		attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
583 584 585 586

		if (attp->attnum > 0)
		{
			relation->rd_att->attrs[attp->attnum - 1] =
587
				(Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
588
												   ATTRIBUTE_TUPLE_SIZE);
589

590 591 592
			memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
				   (char *) attp,
				   ATTRIBUTE_TUPLE_SIZE);
593
			need--;
594

Hiroshi Inoue's avatar
Hiroshi Inoue committed
595 596 597 598 599 600 601 602
			/* Update if this attribute have a constraint */
			if (attp->attnotnull)
				constr->has_not_null = true;

			if (attp->atthasdef)
			{
				if (attrdef == NULL)
				{
603 604 605 606
					attrdef = (AttrDefault *)
						MemoryContextAlloc(CacheMemoryContext,
										   relation->rd_rel->relnatts *
										   sizeof(AttrDefault));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
607
					MemSet(attrdef, 0,
608
					   relation->rd_rel->relnatts * sizeof(AttrDefault));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
609 610 611 612 613
				}
				attrdef[ndef].adnum = attp->attnum;
				attrdef[ndef].adbin = NULL;
				ndef++;
			}
614
		}
615
		pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
616
	}
617 618

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

622
	/*
623
	 * end the scan and close the attribute relation
624 625
	 */
	heap_endscan(pg_attribute_scan);
626
	heap_close(pg_attribute_desc, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
627

628
	/*
629 630 631
	 * 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.
632 633 634
	 */
#ifdef USE_ASSERT_CHECKING
	{
635
		int			i;
636 637 638 639 640 641

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

642
	/*
643 644 645 646
	 * 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().
647 648 649
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
650
	SetConstrOfRelation(relation, constr, ndef, attrdef);
651 652 653 654
}

static void
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
655
				  Relation relation)
656
{
657 658
	Relation	attrel;
	HeapTuple	atttup;
659
	Form_pg_attribute attp;
660
	TupleConstr *constr;
661 662 663
	AttrDefault *attrdef = NULL;
	int			ndef = 0;
	int			i;
664

665 666
	constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
												sizeof(TupleConstr));
667 668
	constr->has_not_null = false;

669
	attrel = heap_openr(AttributeRelationName, AccessShareLock);
670 671

	for (i = 1; i <= relation->rd_rel->relnatts; i++)
672
	{
673
#ifdef	_DROP_COLUMN_HACK__
674
		bool		columnDropped = false;
675

676
#endif	 /* _DROP_COLUMN_HACK__ */
677

678
		atttup = AttributeRelidNumIndexScan(attrel,
679
							ObjectIdGetDatum(RelationGetRelid(relation)),
680
											Int32GetDatum(i));
681 682

		if (!HeapTupleIsValid(atttup))
683
		{
684
#ifdef	_DROP_COLUMN_HACK__
685
			atttup = AttributeRelidNumIndexScan(attrel,
686 687
							ObjectIdGetDatum(RelationGetRelid(relation)),
								 Int32GetDatum(DROPPED_COLUMN_INDEX(i)));
688
			if (!HeapTupleIsValid(atttup))
689 690 691
#endif	 /* _DROP_COLUMN_HACK__ */
				elog(ERROR, "cannot find attribute %d of relation %s", i,
					 RelationGetRelationName(relation));
692 693
#ifdef	_DROP_COLUMN_HACK__
			columnDropped = true;
694
#endif	 /* _DROP_COLUMN_HACK__ */
695
		}
696

697
		relation->rd_att->attrs[i - 1] = attp =
698 699
			(Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
												   ATTRIBUTE_TUPLE_SIZE);
700

701 702 703 704 705 706
		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);
707

708 709 710
#ifdef	_DROP_COLUMN_HACK__
		if (columnDropped)
			continue;
711
#endif	 /* _DROP_COLUMN_HACK__ */
712

713 714 715 716 717 718 719
		/* Update if this attribute have a constraint */
		if (attp->attnotnull)
			constr->has_not_null = true;

		if (attp->atthasdef)
		{
			if (attrdef == NULL)
720
			{
721 722 723 724
				attrdef = (AttrDefault *)
					MemoryContextAlloc(CacheMemoryContext,
									   relation->rd_rel->relnatts *
									   sizeof(AttrDefault));
725 726 727
				MemSet(attrdef, 0,
					   relation->rd_rel->relnatts * sizeof(AttrDefault));
			}
728 729 730 731
			attrdef[ndef].adnum = i;
			attrdef[ndef].adbin = NULL;
			ndef++;
		}
732
	}
733

734
	heap_close(attrel, AccessShareLock);
735

736
	/*
737 738 739
	 * 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.
740 741 742 743 744 745
	 */
#ifdef USE_ASSERT_CHECKING
	for (i = 0; i < relation->rd_rel->relnatts; i++)
		Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
#endif

746
	/*
747 748 749 750
	 * 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().
751 752 753
	 */
	relation->rd_att->attrs[0]->attcacheoff = 0;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
754
	SetConstrOfRelation(relation, constr, ndef, attrdef);
755 756
}

757
/*
758
 *		RelationBuildRuleLock
759
 *
760 761
 *		Form the relation's rewrite rules from information in
 *		the pg_rewrite system catalog.
762 763 764 765 766 767 768
 *
 * 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()
769
 * manageable.	The other subsidiary data structures are simple enough
770
 * to be easy to free explicitly, anyway.
771 772 773 774
 */
static void
RelationBuildRuleLock(Relation relation)
{
775 776
	MemoryContext rulescxt;
	MemoryContext oldcxt;
777 778 779 780 781 782 783 784 785
	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;
786

787 788 789 790 791 792
	/*
	 * Make the private context.  Parameters are set on the assumption
	 * that it'll probably not contain much data.
	 */
	rulescxt = AllocSetContextCreate(CacheMemoryContext,
									 RelationGetRelationName(relation),
793
									 0,			/* minsize */
794 795
									 1024,		/* initsize */
									 1024);		/* maxsize */
796 797
	relation->rd_rulescxt = rulescxt;

798
	/*
799 800
	 * form an array to hold the rewrite rules (the array is extended if
	 * necessary)
801 802
	 */
	maxlocks = 4;
803 804
	rules = (RewriteRule **)
		MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
805 806
	numlocks = 0;

807
	/*
808
	 * form a scan key
809 810 811
	 */
	ScanKeyEntryInitialize(&key, 0,
						   Anum_pg_rewrite_ev_class,
Bruce Momjian's avatar
Bruce Momjian committed
812
						   F_OIDEQ,
813
						   ObjectIdGetDatum(RelationGetRelid(relation)));
814

815
	/*
816
	 * open pg_rewrite and begin a scan
817
	 */
818
	pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
819
	pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key);
820
	pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
821

822
	while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
823
	{
824
		bool		isnull;
825
		Datum		ruleaction;
826 827 828
		Datum		rule_evqual;
		char	   *ruleaction_str;
		char	   *rule_evqual_str;
829
		RewriteRule *rule;
830

831 832
		rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
												  sizeof(RewriteRule));
833

834
		rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
835

836 837 838 839 840 841 842 843 844
		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,
845
											  Anum_pg_rewrite_is_instead,
846 847
													pg_rewrite_tupdesc,
													&isnull));
848

849
		ruleaction = heap_getattr(pg_rewrite_tuple,
850 851
								  Anum_pg_rewrite_ev_action,
								  pg_rewrite_tupdesc,
Bruce Momjian's avatar
Bruce Momjian committed
852
								  &isnull);
853
		Assert(!isnull);
Tom Lane's avatar
Tom Lane committed
854 855
		ruleaction_str = DatumGetCString(DirectFunctionCall1(textout,
															 ruleaction));
856
		oldcxt = MemoryContextSwitchTo(rulescxt);
857
		rule->actions = (List *) stringToNode(ruleaction_str);
858
		MemoryContextSwitchTo(oldcxt);
859 860 861 862 863 864
		pfree(ruleaction_str);

		rule_evqual = heap_getattr(pg_rewrite_tuple,
								   Anum_pg_rewrite_ev_qual,
								   pg_rewrite_tupdesc,
								   &isnull);
865
		Assert(!isnull);
Tom Lane's avatar
Tom Lane committed
866
		rule_evqual_str = DatumGetCString(DirectFunctionCall1(textout,
867
														   rule_evqual));
868
		oldcxt = MemoryContextSwitchTo(rulescxt);
869
		rule->qual = (Node *) stringToNode(rule_evqual_str);
870
		MemoryContextSwitchTo(oldcxt);
871 872 873
		pfree(rule_evqual_str);

		if (numlocks >= maxlocks)
874 875
		{
			maxlocks *= 2;
876 877
			rules = (RewriteRule **)
				repalloc(rules, sizeof(RewriteRule *) * maxlocks);
878
		}
879
		rules[numlocks++] = rule;
880
	}
881

882
	/*
883
	 * end the scan and close the attribute relation
884 885
	 */
	heap_endscan(pg_rewrite_scan);
886
	heap_close(pg_rewrite_desc, AccessShareLock);
887

888
	/*
889
	 * form a RuleLock and insert into relation
890
	 */
891
	rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
892 893 894 895
	rulelock->numLocks = numlocks;
	rulelock->rules = rules;

	relation->rd_rules = rulelock;
896 897
}

898
/*
899 900 901 902 903 904 905 906 907
 *		equalRuleLocks
 *
 *		Determine whether two RuleLocks are equivalent
 *
 *		Probably this should be in the rules code someplace...
 */
static bool
equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
{
908 909
	int			i,
				j;
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941

	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;
942
			if (!equal(rule1->qual, rule2->qual))
943
				return false;
944
			if (!equal(rule1->actions, rule2->actions))
945 946 947 948 949 950
				return false;
		}
	}
	else if (rlock2 != NULL)
		return false;
	return true;
951 952 953
}


954
/* ----------------------------------
955 956
 *		RelationBuildDesc
 *
957 958 959 960 961
 *		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.
 *
962 963 964
 *		To build a relation descriptor, we have to allocate space,
 *		open the underlying unix file and initialize the following
 *		fields:
965
 *
966
 *	File				   rd_fd;		 open file descriptor
967
 *	BlockNumber			   rd_nblocks;	 number of blocks in rel
968
 *										 it will be set in ambeginscan()
969
 *	int					   rd_refcnt;	 reference count
970 971
 *	Form_pg_am			   rd_am;		 AM tuple
 *	Form_pg_class		   rd_rel;		 RELATION tuple
972
 *	Oid					   rd_id;		 relation's object id
973
 *	LockInfoData		   rd_lockInfo;  lock manager's info
974
 *	TupleDesc			   rd_att;		 tuple descriptor
975
 *
976 977 978 979
 *		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
980 981
 * --------------------------------
 */
982
static Relation
983 984
RelationBuildDesc(RelationBuildDescInfo buildinfo,
				  Relation oldrelation)
985
{
986 987 988
	Relation	relation;
	Oid			relid;
	Oid			relam;
989
	HeapTuple	pg_class_tuple;
990 991
	Form_pg_class relp;
	MemoryContext oldcxt;
992

993
	/*
994
	 * find the tuple in pg_class corresponding to the given relation id
995 996 997
	 */
	pg_class_tuple = ScanPgRelation(buildinfo);

998
	/*
999
	 * if no such tuple exists, return NULL
1000 1001 1002 1003
	 */
	if (!HeapTupleIsValid(pg_class_tuple))
		return NULL;

1004
	/*
1005
	 * get information from the pg_class_tuple
1006
	 */
1007
	relid = pg_class_tuple->t_data->t_oid;
1008 1009
	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);

1010
	/*
1011 1012
	 * allocate storage for the relation descriptor, and copy
	 * pg_class_tuple to relation->rd_rel.
1013
	 */
1014 1015
	relation = AllocateRelationDesc(oldrelation, relp);

1016
	/*
1017
	 * now we can free the memory allocated for pg_class_tuple
1018 1019
	 */
	heap_freetuple(pg_class_tuple);
1020

1021
	/*
1022
	 * initialize the relation's relation id (relation->rd_id)
1023
	 */
1024
	RelationGetRelid(relation) = relid;
1025

1026
	/*
1027
	 * initialize relation->rd_refcnt
1028 1029 1030
	 */
	RelationSetReferenceCount(relation, 1);

1031
	/*
1032
	 * normal relations are not nailed into the cache
1033 1034 1035
	 */
	relation->rd_isnailed = false;

1036
	/*
1037
	 * initialize the access method information (relation->rd_am)
1038
	 */
1039
	relam = relation->rd_rel->relam;
1040
	if (OidIsValid(relam))
1041 1042
		relation->rd_am = AccessMethodObjectIdGetForm(relam,
													  CacheMemoryContext);
1043

1044
	/*
1045
	 * initialize the tuple descriptor (relation->rd_att).
1046
	 */
1047
	RelationBuildTupleDesc(buildinfo, relation);
1048

1049
	/*
1050
	 * Fetch rules and triggers that affect this relation
1051
	 */
1052
	if (relation->rd_rel->relhasrules)
1053 1054
		RelationBuildRuleLock(relation);
	else
1055
	{
1056
		relation->rd_rules = NULL;
1057 1058
		relation->rd_rulescxt = NULL;
	}
1059

1060
	if (relation->rd_rel->reltriggers > 0)
1061 1062 1063 1064
		RelationBuildTriggers(relation);
	else
		relation->trigdesc = NULL;

1065
	/*
1066
	 * initialize index strategy and support information for this relation
1067 1068 1069 1070
	 */
	if (OidIsValid(relam))
		IndexedAccessMethodInitialize(relation);

1071
	/*
1072
	 * initialize the relation lock manager information
1073 1074 1075
	 */
	RelationInitLockInfo(relation);		/* see lmgr.c */

1076
	if (relation->rd_rel->relisshared)
1077 1078 1079 1080 1081
		relation->rd_node.tblNode = InvalidOid;
	else
		relation->rd_node.tblNode = MyDatabaseId;
	relation->rd_node.relNode = relation->rd_rel->relfilenode;

1082
	/*
1083
	 * Open the relation and assign the file descriptor returned by the
1084
	 * storage manager code to rd_fd.
1085
	 *
1086 1087 1088
	 * 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.
1089
	 */
1090
	if (relation->rd_rel->relkind != RELKIND_VIEW)
1091 1092 1093 1094 1095 1096 1097
	{
		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));
	}
1098
	else
1099
		relation->rd_fd = -1;
1100

1101
	/*
1102 1103
	 * insert newly created relation into proper relcaches, restore memory
	 * context and return the new reldesc.
1104
	 */
1105
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
1106
	RelationCacheInsert(relation);
1107 1108
	MemoryContextSwitchTo(oldcxt);

1109
	return relation;
1110 1111 1112 1113 1114
}

static void
IndexedAccessMethodInitialize(Relation relation)
{
1115 1116 1117 1118 1119
	IndexStrategy strategy;
	RegProcedure *support;
	int			natts;
	Size		stratSize;
	Size		supportSize;
1120 1121
	uint16		amstrategies;
	uint16		amsupport;
1122 1123

	natts = relation->rd_rel->relnatts;
1124 1125 1126 1127
	amstrategies = relation->rd_am->amstrategies;
	amsupport = relation->rd_am->amsupport;

	stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
1128 1129
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  stratSize);
1130

1131
	if (amsupport > 0)
1132
	{
1133
		supportSize = natts * (amsupport * sizeof(RegProcedure));
1134 1135
		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
													  supportSize);
1136 1137 1138 1139 1140
	}
	else
		support = (RegProcedure *) NULL;

	IndexSupportInitialize(strategy, support,
1141
						   &relation->rd_uniqueindex,
1142
						   RelationGetRelid(relation),
1143
						   relation->rd_rel->relam,
1144
						   amstrategies, amsupport, natts);
1145 1146

	RelationSetIndexSupport(relation, strategy, support);
1147 1148
}

1149
/*
1150
 *		formrdesc
1151
 *
1152
 *		This is a special cut-down version of RelationBuildDesc()
1153 1154
 *		used by RelationCacheInitialize() in initializing the relcache.
 *		The relation descriptor is built just from the supplied parameters,
1155 1156 1157
 *		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...
1158 1159
 *
 * NOTE: we assume we are already switched into CacheMemoryContext.
1160 1161 1162
 */
static void
formrdesc(char *relationName,
1163
		  int natts,
1164
		  FormData_pg_attribute *att)
1165
{
1166
	Relation	relation;
1167
	int			i;
1168

1169
	/*
1170
	 * allocate new relation desc
1171
	 */
1172
	relation = (Relation) palloc(sizeof(RelationData));
1173

1174
	/*
1175
	 * clear all fields of reldesc
1176
	 */
1177 1178 1179 1180
	MemSet((char *) relation, 0, sizeof(RelationData));
	relation->rd_targblock = InvalidBlockNumber;

	/* make sure relation is marked as having no open file yet */
1181 1182
	relation->rd_fd = -1;

1183
	/*
1184
	 * initialize reference count
1185 1186 1187
	 */
	RelationSetReferenceCount(relation, 1);

1188
	/*
1189
	 * all entries built with this routine are nailed-in-cache
1190
	 */
1191
	relation->rd_isnailed = true;
1192

1193
	/*
1194
	 * initialize relation tuple form
1195
	 *
1196 1197 1198
	 * 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.
1199
	 */
1200 1201 1202 1203
	relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
	MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);

	strcpy(RelationGetPhysicalRelationName(relation), relationName);
1204 1205

	/*
1206 1207
	 * It's important to distinguish between shared and non-shared relations,
	 * even at bootstrap time, to make sure we know where they are stored.
1208
	 */
1209
	relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1210

1211 1212
	relation->rd_rel->relpages = 1;
	relation->rd_rel->reltuples = 1;
1213
	relation->rd_rel->relkind = RELKIND_RELATION;
1214
	relation->rd_rel->relnatts = (int16) natts;
1215

1216
	/*
1217
	 * initialize attribute tuple form
1218 1219
	 */
	relation->rd_att = CreateTemplateTupleDesc(natts);
1220

1221
	/*
1222
	 * initialize tuple desc info
1223 1224 1225
	 */
	for (i = 0; i < natts; i++)
	{
1226
		relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1227 1228
		memcpy((char *) relation->rd_att->attrs[i],
			   (char *) &att[i],
1229 1230 1231
			   ATTRIBUTE_TUPLE_SIZE);
	}

1232
	/*
1233
	 * initialize relation id from info in att array (my, this is ugly)
1234
	 */
1235
	RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
1236

1237
	/*
1238
	 * initialize the relation's lock manager and RelFileNode information
1239 1240 1241
	 */
	RelationInitLockInfo(relation);		/* see lmgr.c */

1242
	if (relation->rd_rel->relisshared)
1243 1244 1245
		relation->rd_node.tblNode = InvalidOid;
	else
		relation->rd_node.tblNode = MyDatabaseId;
1246
	relation->rd_node.relNode =
1247 1248
		relation->rd_rel->relfilenode = RelationGetRelid(relation);

1249
	/*
1250
	 * initialize the rel-has-index flag, using hardwired knowledge
1251
	 */
1252
	relation->rd_rel->relhasindex = false;
1253

1254 1255 1256
	/* In bootstrap mode, we have no indexes */
	if (!IsBootstrapProcessingMode())
	{
1257 1258 1259 1260 1261 1262 1263 1264 1265
		/*
		 * This list is incomplete, but it only has to work for the
		 * set of rels that formrdesc is used for ...
		 */
		if (strcmp(relationName, RelationRelationName) == 0 ||
			strcmp(relationName, AttributeRelationName) == 0 ||
			strcmp(relationName, ProcedureRelationName) == 0 ||
			strcmp(relationName, TypeRelationName) == 0)
			relation->rd_rel->relhasindex = true;
1266 1267
	}

1268
	/*
1269
	 * add new reldesc to relcache
1270
	 */
1271
	RelationCacheInsert(relation);
1272 1273 1274
}


1275
/*
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
 *		fixrdesc
 *
 *		Update the phony data inserted by formrdesc() with real info
 *		from pg_class.
 */
static void
fixrdesc(char *relationName)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
	Form_pg_class relp;
	Relation	relation;

1289
	/*
1290
	 * find the tuple in pg_class corresponding to the given relation name
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
	 */
	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);

1302
	/*
1303
	 * find the pre-made relcache entry (better be there!)
1304 1305 1306 1307 1308 1309
	 */
	relation = RelationNameCacheGetRelation(relationName);
	if (!RelationIsValid(relation))
		elog(FATAL, "fixrdesc: no existing relcache entry for %s",
			 relationName);

1310
	/*
1311 1312
	 * and copy pg_class_tuple to relation->rd_rel. (See notes in
	 * AllocateRelationDesc())
1313 1314 1315 1316 1317 1318 1319 1320
	 */
	Assert(relation->rd_rel != NULL);
	memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);

	heap_freetuple(pg_class_tuple);
}


1321
/* ----------------------------------------------------------------
1322
 *				 Relation Descriptor Lookup Interface
1323 1324 1325
 * ----------------------------------------------------------------
 */

1326
/*
1327
 *		RelationIdCacheGetRelation
1328
 *
1329 1330 1331
 *		Lookup an existing reldesc by OID.
 *
 *		Only try to get the reldesc by looking in the cache,
1332 1333 1334 1335 1336
 *		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().)
1337 1338 1339 1340
 */
Relation
RelationIdCacheGetRelation(Oid relationId)
{
1341
	Relation	rd;
1342 1343 1344 1345 1346

	RelationIdCacheLookup(relationId, rd);

	if (RelationIsValid(rd))
	{
1347
		/* re-open files if necessary */
1348
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1349
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1350 1351

		RelationIncrementReferenceCount(rd);
1352
	}
1353

1354
	return rd;
1355 1356
}

1357
/*
1358
 *		RelationNameCacheGetRelation
1359 1360
 *
 *		As above, but lookup by name.
1361
 */
1362
static Relation
1363
RelationNameCacheGetRelation(const char *relationName)
1364
{
1365 1366
	Relation	rd;
	NameData	name;
1367 1368 1369 1370 1371 1372

	/*
	 * make sure that the name key used for hash lookup is properly
	 * null-padded
	 */
	namestrcpy(&name, relationName);
1373
	RelationNameCacheLookup(NameStr(name), rd);
1374 1375 1376

	if (RelationIsValid(rd))
	{
1377
		/* re-open files if necessary */
1378
		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
1379
			rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
1380 1381

		RelationIncrementReferenceCount(rd);
1382
	}
1383

1384
	return rd;
1385 1386
}

1387 1388 1389 1390 1391 1392 1393 1394 1395
Relation
RelationNodeCacheGetRelation(RelFileNode rnode)
{
	Relation	rd;

	RelationNodeCacheLookup(rnode, rd);

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

		RelationIncrementReferenceCount(rd);
	}

	return rd;
}

1406
/*
1407
 *		RelationIdGetRelation
1408
 *
1409 1410 1411 1412 1413
 *		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().)
1414 1415 1416 1417
 */
Relation
RelationIdGetRelation(Oid relationId)
{
1418
	Relation	rd;
1419 1420
	RelationBuildDescInfo buildinfo;

1421
	/*
1422
	 * increment access statistics
1423 1424 1425 1426
	 */
	IncrHeapAccessStat(local_RelationIdGetRelation);
	IncrHeapAccessStat(global_RelationIdGetRelation);

1427
	/*
1428
	 * first try and get a reldesc from the cache
1429 1430 1431 1432 1433
	 */
	rd = RelationIdCacheGetRelation(relationId);
	if (RelationIsValid(rd))
		return rd;

1434
	/*
1435 1436
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1437 1438 1439 1440
	 */
	buildinfo.infotype = INFO_RELID;
	buildinfo.i.info_id = relationId;

1441
	rd = RelationBuildDesc(buildinfo, NULL);
1442
	return rd;
1443 1444
}

1445
/*
1446
 *		RelationNameGetRelation
1447
 *
1448
 *		As above, but lookup by name.
1449 1450
 */
Relation
1451
RelationNameGetRelation(const char *relationName)
1452
{
1453
	char	   *temprelname;
1454
	Relation	rd;
1455 1456
	RelationBuildDescInfo buildinfo;

1457
	/*
1458
	 * increment access statistics
1459 1460 1461 1462
	 */
	IncrHeapAccessStat(local_RelationNameGetRelation);
	IncrHeapAccessStat(global_RelationNameGetRelation);

1463
	/*
1464 1465
	 * if caller is looking for a temp relation, substitute its real name;
	 * we only index temp rels by their real names.
1466
	 */
1467
	temprelname = get_temp_rel_by_username(relationName);
1468
	if (temprelname != NULL)
1469 1470
		relationName = temprelname;

1471
	/*
1472
	 * first try and get a reldesc from the cache
1473 1474 1475 1476 1477
	 */
	rd = RelationNameCacheGetRelation(relationName);
	if (RelationIsValid(rd))
		return rd;

1478
	/*
1479 1480
	 * no reldesc in the cache, so have RelationBuildDesc() build one and
	 * add it.
1481 1482
	 */
	buildinfo.infotype = INFO_RELNAME;
1483
	buildinfo.i.info_name = (char *) relationName;
1484

1485
	rd = RelationBuildDesc(buildinfo, NULL);
1486 1487 1488 1489
	return rd;
}

/* ----------------------------------------------------------------
1490
 *				cache invalidation support routines
1491 1492 1493
 * ----------------------------------------------------------------
 */

1494
/*
1495 1496
 * RelationClose - close an open relation
 *
1497 1498 1499 1500 1501 1502 1503
 *	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.
1504 1505 1506 1507
 */
void
RelationClose(Relation relation)
{
1508 1509
	/* Note: no locking manipulations needed */
	RelationDecrementReferenceCount(relation);
1510 1511 1512 1513 1514

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1517
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
1518
/*
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
 * RelationReloadClassinfo
 *
 *	This function is especially for nailed relations.
 *	relhasindex/relfilenode could be changed even for
 *	nailed relations.
 */
static void
RelationReloadClassinfo(Relation relation)
{
	RelationBuildDescInfo buildinfo;
	HeapTuple	pg_class_tuple;
1530
	Form_pg_class relp;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550

	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;
}
1551 1552

#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1553

1554
/*
1555
 * RelationClearRelation
1556
 *
1557 1558 1559 1560 1561
 *	 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.
1562
 */
1563
static void
1564
RelationClearRelation(Relation relation, bool rebuildIt)
1565
{
1566 1567 1568
	MemoryContext oldcxt;

	/*
1569
	 * Make sure smgr and lower levels close the relation's files, if they
1570
	 * weren't closed already.  If the relation is not getting deleted,
1571
	 * the next smgr access should reopen the files automatically.	This
1572 1573
	 * ensures that the low-level file access state is updated after, say,
	 * a vacuum truncation.
1574
	 */
1575
	if (relation->rd_fd >= 0)
1576
	{
1577
		smgrclose(DEFAULT_SMGR, relation);
1578 1579
		relation->rd_fd = -1;
	}
1580

1581
	/*
1582 1583
	 * Never, never ever blow away a nailed-in system relation, because
	 * we'd be unable to recover.
1584 1585
	 */
	if (relation->rd_isnailed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1586
	{
1587
#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1588
		RelationReloadClassinfo(relation);
1589
#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */
1590
		return;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1591
	}
1592

1593 1594
	/*
	 * Remove relation from hash tables
1595 1596 1597 1598 1599
	 *
	 * 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...
	 */
1600
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
1601
	RelationCacheDelete(relation);
1602
	MemoryContextSwitchTo(oldcxt);
1603 1604

	/* Clear out catcache's entries for this relation */
1605
	CatalogCacheFlushRelation(RelationGetRelid(relation));
1606

1607
	/*
1608 1609 1610 1611 1612 1613
	 * 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:
1614 1615 1616 1617 1618 1619 1620 1621 1622
	 */
	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);
1623
	freeList(relation->rd_indexlist);
1624

1625
	/*
1626 1627 1628 1629
	 * 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).
1630
	 */
1631
	if (!rebuildIt)
1632
	{
1633 1634
		/* ok to zap remaining substructure */
		FreeTupleDesc(relation->rd_att);
1635 1636
		if (relation->rd_rulescxt)
			MemoryContextDelete(relation->rd_rulescxt);
1637
		FreeTriggerDesc(relation->trigdesc);
1638 1639 1640 1641
		pfree(relation);
	}
	else
	{
1642

1643 1644 1645
		/*
		 * When rebuilding an open relcache entry, must preserve ref count
		 * and myxactonly flag.  Also attempt to preserve the tupledesc,
1646 1647 1648
		 * 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).
1649
		 */
1650
		int			old_refcnt = relation->rd_refcnt;
1651 1652 1653
		bool		old_myxactonly = relation->rd_myxactonly;
		TupleDesc	old_att = relation->rd_att;
		RuleLock   *old_rules = relation->rd_rules;
1654
		MemoryContext old_rulescxt = relation->rd_rulescxt;
1655
		TriggerDesc *old_trigdesc = relation->trigdesc;
1656
		BlockNumber	old_nblocks = relation->rd_nblocks;
1657
		RelationBuildDescInfo buildinfo;
1658

1659 1660
		buildinfo.infotype = INFO_RELID;
		buildinfo.i.info_id = RelationGetRelid(relation);
1661

1662
		if (RelationBuildDesc(buildinfo, relation) != relation)
1663
		{
1664
			/* Should only get here if relation was deleted */
1665
			FreeTupleDesc(old_att);
1666 1667
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1668
			FreeTriggerDesc(old_trigdesc);
1669
			pfree(relation);
1670
			elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
1671
				 buildinfo.i.info_id);
1672
		}
1673
		RelationSetReferenceCount(relation, old_refcnt);
1674
		relation->rd_myxactonly = old_myxactonly;
1675 1676 1677 1678 1679 1680 1681 1682 1683
		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))
		{
1684 1685
			if (relation->rd_rulescxt)
				MemoryContextDelete(relation->rd_rulescxt);
1686
			relation->rd_rules = old_rules;
1687
			relation->rd_rulescxt = old_rulescxt;
1688 1689 1690
		}
		else
		{
1691 1692
			if (old_rulescxt)
				MemoryContextDelete(old_rulescxt);
1693 1694 1695 1696 1697 1698 1699 1700 1701
		}
		if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
		{
			FreeTriggerDesc(relation->trigdesc);
			relation->trigdesc = old_trigdesc;
		}
		else
			FreeTriggerDesc(old_trigdesc);
		relation->rd_nblocks = old_nblocks;
1702 1703 1704

		/*
		 * this is kind of expensive, but I think we must do it in case
1705 1706
		 * relation has been truncated...
		 */
1707
		relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
1708
	}
1709 1710
}

1711
/*
1712 1713 1714 1715 1716
 * RelationFlushRelation
 *
 *	 Rebuild the relation if it is open (refcount > 0), else blow it away.
 */
static void
1717
RelationFlushRelation(Relation relation)
1718
{
1719
	bool		rebuildIt;
1720 1721

	if (relation->rd_myxactonly)
1722
	{
1723

1724 1725 1726 1727 1728 1729 1730 1731
		/*
		 * Local rels should always be rebuilt, not flushed; the relcache
		 * entry must live until RelationPurgeLocalRelation().
		 */
		rebuildIt = true;
	}
	else
	{
1732

1733 1734 1735
		/*
		 * Nonlocal rels can be dropped from the relcache if not open.
		 */
1736
		rebuildIt = !RelationHasReferenceCountZero(relation);
1737
	}
1738

1739
	RelationClearRelation(relation, rebuildIt);
1740 1741
}

1742
/*
1743 1744 1745 1746
 * RelationForgetRelation -
 *
 *		   RelationClearRelation + if the relation is myxactonly then
 *		   remove the relation descriptor from the newly created
1747
 *		   relation list.
1748 1749
 */
void
1750
RelationForgetRelation(Oid rid)
1751
{
1752
	Relation	relation;
1753 1754 1755

	RelationIdCacheLookup(rid, relation);

1756
	if (PointerIsValid(relation))
1757
	{
1758
		if (relation->rd_myxactonly)
1759
		{
1760 1761
			List	   *curr;
			List	   *prev = NIL;
Bruce Momjian's avatar
Bruce Momjian committed
1762

1763 1764 1765
			foreach(curr, newlyCreatedRelns)
			{
				Relation	reln = lfirst(curr);
Bruce Momjian's avatar
Bruce Momjian committed
1766

1767 1768 1769 1770 1771 1772 1773
				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",
1774
					 RelationGetRelationName(relation));
1775 1776 1777 1778 1779
			if (prev == NIL)
				newlyCreatedRelns = lnext(newlyCreatedRelns);
			else
				lnext(prev) = lnext(curr);
			pfree(curr);
1780
		}
Bruce Momjian's avatar
Bruce Momjian committed
1781

1782 1783
		/* Unconditionally destroy the relcache entry */
		RelationClearRelation(relation, false);
1784
	}
1785 1786
}

1787
/*
1788
 *		RelationIdInvalidateRelationCacheByRelationId
1789 1790 1791 1792 1793 1794 1795 1796
 *
 *		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.
1797 1798 1799 1800
 */
void
RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
{
1801
	Relation	relation;
1802 1803 1804

	RelationIdCacheLookup(relationId, relation);

1805
	if (PointerIsValid(relation))
1806
		RelationFlushRelation(relation);
1807 1808
}

1809 1810 1811
#if NOT_USED
/* only used by RelationIdInvalidateRelationCacheByAccessMethodId,
 * which is dead code.
1812 1813
 */
static void
1814
RelationFlushIndexes(Relation *r,
1815
					 Oid accessMethodId)
1816
{
1817
	Relation	relation = *r;
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827

	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))
1828
		RelationFlushRelation(relation);
1829
}
1830

1831 1832
#endif

1833 1834 1835

/*
 * RelationCacheInvalidate
1836 1837
 *	 Blow away cached relation descriptors that have zero reference counts,
 *	 and rebuild those with positive reference counts.
1838
 *
1839
 *	 This is currently used only to recover from SI message buffer overflow,
1840 1841 1842
 *	 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).
1843 1844 1845 1846
 *
 *	 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
1847
 *	 the element it is currently visiting.	If a second SI overflow were to
1848 1849 1850 1851 1852 1853
 *	 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.
1854 1855
 */
void
1856
RelationCacheInvalidate(void)
1857
{
1858 1859
	List	   *rebuildList = NIL;
	List	   *l;
1860 1861 1862 1863 1864 1865 1866

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

	/* Phase 2: rebuild the items found to need rebuild in phase 1 */
1867
	foreach(l, rebuildList)
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879
	{
		Relation	relation = (Relation) lfirst(l);

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

static void
RelationCacheInvalidateWalker(Relation *relationPtr, Datum listp)
{
	Relation	relation = *relationPtr;
1880
	List	  **rebuildList = (List **) DatumGetPointer(listp);
1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895

	/* 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);
	}
1896
}
1897

1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
/*
 * 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)
{
1914 1915
	HashTableWalk(RelationNameCache,
				  (HashtFunc) RelationCacheAbortWalker,
1916 1917 1918 1919
				  0);
}

static void
1920
RelationCacheAbortWalker(Relation *relationPtr, Datum dummy)
1921 1922 1923 1924 1925 1926 1927 1928
{
	Relation	relation = *relationPtr;

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

1930
/*
1931 1932 1933
 *		RelationRegisterRelation -
 *		   register the Relation descriptor of a newly created relation
 *		   with the relation descriptor Cache.
1934 1935 1936 1937
 */
void
RelationRegisterRelation(Relation relation)
{
1938
	MemoryContext oldcxt;
1939 1940 1941

	RelationInitLockInfo(relation);

1942 1943
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

1944 1945
	RelationCacheInsert(relation);

1946 1947
	/*
	 * we've just created the relation. It is invisible to anyone else
Bruce Momjian's avatar
Bruce Momjian committed
1948 1949
	 * before the transaction is committed. Setting rd_myxactonly allows
	 * us to use the local buffer manager for select/insert/etc before the
1950 1951 1952 1953
	 * 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
	 */
1954
	relation->rd_myxactonly = TRUE;
1955 1956 1957
	newlyCreatedRelns = lcons(relation, newlyCreatedRelns);

	MemoryContextSwitchTo(oldcxt);
1958 1959 1960 1961
}

/*
 * RelationPurgeLocalRelation -
1962
 *	  find all the Relation descriptors marked rd_myxactonly and reset them.
1963 1964 1965
 *	  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.
1966 1967 1968 1969
 */
void
RelationPurgeLocalRelation(bool xactCommitted)
{
1970 1971
	while (newlyCreatedRelns)
	{
1972 1973
		List	   *l = newlyCreatedRelns;
		Relation	reln = lfirst(l);
1974

1975
		Assert(reln != NULL && reln->rd_myxactonly);
1976

1977
		reln->rd_myxactonly = false;	/* mark it not on list anymore */
1978 1979 1980 1981

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

1982
		/* XXX is this step still needed?  If so, why? */
1983
		if (!IsBootstrapProcessingMode())
1984
			RelationClearRelation(reln, false);
1985
	}
1986 1987
}

1988
/*
1989
 *		RelationCacheInitialize
1990
 *
1991
 *		This initializes the relation descriptor cache.
1992 1993
 */

1994
#define INITRELCACHESIZE		400
1995 1996

void
1997
RelationCacheInitialize(void)
1998
{
1999 2000
	MemoryContext oldcxt;
	HASHCTL		ctl;
2001

2002
	/*
2003
	 * switch to cache memory context
2004
	 */
2005 2006
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
2007

2008
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2009

2010
	/*
2011
	 * create global caches
2012
	 */
Bruce Momjian's avatar
Bruce Momjian committed
2013
	MemSet(&ctl, 0, (int) sizeof(ctl));
2014 2015 2016 2017 2018 2019 2020 2021 2022
	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);

2023 2024 2025
	ctl.keysize = sizeof(RelFileNode);
	ctl.hash = tag_hash;
	RelationNodeCache = hash_create(INITRELCACHESIZE, &ctl,
2026
									HASH_ELEM | HASH_FUNCTION);
2027

2028
	/*
2029 2030 2031
	 * initialize the cache with pre-made relation descriptors for some of
	 * the more important system relations.  These relations should always
	 * be in the cache.
2032
	 *
2033
	 * NB: see also the list in RelationCacheInitializePhase2().
2034 2035 2036 2037 2038 2039 2040 2041
	 */
	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);

	/*
2042 2043 2044
	 * init_irels() used to be called here. It is changed to be called in
	 * RelationCacheInitializePhase2() now so that transactional control
	 * could guarantee the consistency.
2045 2046 2047
	 */

	MemoryContextSwitchTo(oldcxt);
2048 2049
}

2050
/*
2051 2052 2053 2054 2055 2056 2057 2058
 *		RelationCacheInitializePhase2
 *
 *		This completes initialization of the relcache after catcache
 *		is functional and we are able to actually load data from pg_class.
 */
void
RelationCacheInitializePhase2(void)
{
2059

2060 2061 2062
	/*
	 * Get the real pg_class tuple for each nailed-in-cache relcache entry
	 * that was made by RelationCacheInitialize(), and replace the phony
2063 2064 2065
	 * 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.
2066 2067 2068
	 */
	if (!IsBootstrapProcessingMode())
	{
2069

2070 2071 2072
		/*
		 * Initialize critical system index relation descriptors, first.
		 * They are to make building relation descriptors fast.
2073 2074
		 * init_irels() used to be called in RelationCacheInitialize(). It
		 * is changed to be called here to be transaction safe.
2075 2076
		 */
		MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2077

2078 2079 2080 2081
		init_irels();
		MemoryContextSwitchTo(oldcxt);

		/* fix nailed-in-cache relations */
2082 2083 2084 2085
		fixrdesc(RelationRelationName);
		fixrdesc(AttributeRelationName);
		fixrdesc(ProcedureRelationName);
		fixrdesc(TypeRelationName);
2086 2087

		/*
2088
		 * We don't bother to update the entries for pg_log.
2089
		 */
2090 2091 2092
	}
}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
2093
/* used by XLogInitCache */
2094 2095
void		CreateDummyCaches(void);
void		DestroyDummyCaches(void);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2096 2097 2098 2099

void
CreateDummyCaches(void)
{
2100 2101
	MemoryContext oldcxt;
	HASHCTL		ctl;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120

	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,
2121
									HASH_ELEM | HASH_FUNCTION);
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2122 2123 2124 2125 2126 2127
	MemoryContextSwitchTo(oldcxt);
}

void
DestroyDummyCaches(void)
{
2128
	MemoryContext oldcxt;
Vadim B. Mikheev's avatar
WAL  
Vadim B. Mikheev committed
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146

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

2147
static void
2148
AttrDefaultFetch(Relation relation)
2149
{
2150 2151 2152
	AttrDefault *attrdef = relation->rd_att->constr->defval;
	int			ndef = relation->rd_att->constr->num_defval;
	Relation	adrel;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2153
	Relation	irel = (Relation) NULL;
2154
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2155
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2156
	HeapTuple	htup;
2157
	Form_pg_attrdef adform;
2158 2159
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc adscan = (HeapScanDesc) NULL;
2160
	RetrieveIndexResult indexRes;
2161
	Datum		val;
2162 2163 2164
	bool		isnull;
	int			found;
	int			i;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2165
	bool		hasindex;
2166 2167 2168 2169

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2170
						   (RegProcedure) F_OIDEQ,
2171
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2172

2173
	adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2174 2175 2176 2177 2178 2179 2180
	hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
	if (hasindex)
	{
		irel = index_openr(AttrDefaultIndex);
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
2181
		adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey);
2182
	tuple.t_datamcxt = NULL;
2183
	tuple.t_data = NULL;
2184 2185 2186

	for (found = 0;;)
	{
2187 2188
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2189 2190 2191 2192 2193 2194 2195
		if (hasindex)
		{
			indexRes = index_getnext(sd, ForwardScanDirection);
			if (!indexRes)
				break;

			tuple.t_self = indexRes->heap_iptr;
2196
			heap_fetch(adrel, SnapshotNow, &tuple, &buffer, sd);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
			pfree(indexRes);
			if (tuple.t_data == NULL)
				continue;
			htup = &tuple;
		}
		else
		{
			htup = heap_getnext(adscan, 0);
			if (!HeapTupleIsValid(htup))
				break;
		}
2208
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2209
		adform = (Form_pg_attrdef) GETSTRUCT(htup);
2210 2211 2212 2213
		for (i = 0; i < ndef; i++)
		{
			if (adform->adnum != attrdef[i].adnum)
				continue;
2214
			if (attrdef[i].adbin != NULL)
2215
				elog(NOTICE, "AttrDefaultFetch: second record found for attr %s in rel %s",
2216
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2217
					 RelationGetRelationName(relation));
2218

2219 2220 2221
			val = fastgetattr(htup,
							  Anum_pg_attrdef_adbin,
							  adrel->rd_att, &isnull);
2222
			if (isnull)
2223
				elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
2224
					 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
2225
					 RelationGetRelationName(relation));
2226 2227
			else
				attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
2228 2229
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2230 2231
			break;
		}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2232 2233
		if (hasindex)
			ReleaseBuffer(buffer);
2234

2235
		if (i >= ndef)
2236
			elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
2237
				 adform->adnum,
2238
				 RelationGetRelationName(relation));
2239 2240 2241
	}

	if (found < ndef)
2242
		elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s",
2243
			 ndef - found, RelationGetRelationName(relation));
2244

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2245 2246 2247 2248 2249 2250 2251
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(adscan);
2252
	heap_close(adrel, AccessShareLock);
2253 2254
}

2255
static void
2256
RelCheckFetch(Relation relation)
2257
{
2258 2259 2260
	ConstrCheck *check = relation->rd_att->constr->check;
	int			ncheck = relation->rd_att->constr->num_check;
	Relation	rcrel;
2261
	Relation	irel = (Relation) NULL;
2262
	ScanKeyData skey;
Bruce Momjian's avatar
Bruce Momjian committed
2263
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2264
	HeapTuple	htup;
2265 2266
	IndexScanDesc sd = (IndexScanDesc) NULL;
	HeapScanDesc rcscan = (HeapScanDesc) NULL;
2267
	RetrieveIndexResult indexRes;
2268
	Name		rcname;
2269
	Datum		val;
2270 2271
	bool		isnull;
	int			found;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2272
	bool		hasindex;
2273 2274 2275 2276

	ScanKeyEntryInitialize(&skey,
						   (bits16) 0x0,
						   (AttrNumber) 1,
Bruce Momjian's avatar
Bruce Momjian committed
2277
						   (RegProcedure) F_OIDEQ,
2278
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2279

2280
	rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2281 2282 2283 2284 2285 2286 2287 2288
	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);
2289
	tuple.t_datamcxt = NULL;
2290
	tuple.t_data = NULL;
2291 2292 2293

	for (found = 0;;)
	{
2294 2295
		Buffer		buffer;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2296 2297 2298 2299 2300 2301 2302
		if (hasindex)
		{
			indexRes = index_getnext(sd, ForwardScanDirection);
			if (!indexRes)
				break;

			tuple.t_self = indexRes->heap_iptr;
2303
			heap_fetch(rcrel, SnapshotNow, &tuple, &buffer, sd);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314
			pfree(indexRes);
			if (tuple.t_data == NULL)
				continue;
			htup = &tuple;
		}
		else
		{
			htup = heap_getnext(rcscan, 0);
			if (!HeapTupleIsValid(htup))
				break;
		}
2315
		if (found == ncheck)
Bruce Momjian's avatar
Bruce Momjian committed
2316
			elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
2317
				 RelationGetRelationName(relation));
2318

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2319
		rcname = (Name) fastgetattr(htup,
2320 2321 2322
									Anum_pg_relcheck_rcname,
									rcrel->rd_att, &isnull);
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2323
			elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
2324
				 RelationGetRelationName(relation));
2325 2326
		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
												  NameStr(*rcname));
2327 2328 2329
		val = fastgetattr(htup,
						  Anum_pg_relcheck_rcbin,
						  rcrel->rd_att, &isnull);
2330
		if (isnull)
Bruce Momjian's avatar
Bruce Momjian committed
2331
			elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
2332
				 RelationGetRelationName(relation));
2333
		check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
2334 2335
							 DatumGetCString(DirectFunctionCall1(textout,
																 val)));
2336
		found++;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2337 2338
		if (hasindex)
			ReleaseBuffer(buffer);
2339 2340 2341
	}

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2345 2346 2347 2348 2349 2350 2351
	if (hasindex)
	{
		index_endscan(sd);
		index_close(irel);
	}
	else
		heap_endscan(rcscan);
2352
	heap_close(rcrel, AccessShareLock);
2353 2354
}

2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
/*
 * 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.
 *
2365 2366 2367 2368 2369 2370
 * 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.
 *
2371 2372
 * 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
2373
 * may freeList() the returned list after scanning it.	This is necessary
2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
 * 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,
2403
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2404 2405 2406 2407 2408 2409 2410 2411
		sd = index_beginscan(irel, false, 1, &skey);
	}
	else
	{
		ScanKeyEntryInitialize(&skey,
							   (bits16) 0x0,
							   (AttrNumber) Anum_pg_index_indrelid,
							   (RegProcedure) F_OIDEQ,
2412
						   ObjectIdGetDatum(RelationGetRelid(relation)));
2413 2414 2415 2416
		hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
	}

	/*
2417 2418 2419 2420
	 * 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.
2421 2422
	 */
	result = NIL;
2423

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
	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;
2441
			heap_fetch(indrel, SnapshotNow, &tuple, &buffer, sd);
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
			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);

2456
		result = insert_ordered_oid(result, index->indexrelid);
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470

		if (hasindex)
			ReleaseBuffer(buffer);
	}

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

2471
	/* Now save a copy of the completed list in the relcache entry. */
2472
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
2473 2474 2475 2476 2477 2478 2479
	relation->rd_indexlist = listCopy(result);
	relation->rd_indexfound = true;
	MemoryContextSwitchTo(oldcxt);

	return result;
}

2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512
/*
 * 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;
}


2513
/*
2514 2515
 *	init_irels(), write_irels() -- handle special-case initialization of
 *								   index relation descriptors.
2516
 *
2517 2518 2519
 *		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.
2520
 *
2521 2522 2523 2524
 *		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.
2525
 *
2526
 *		In order to get around the problem, we do the following:
2527
 *
2528 2529
 *		   +  When the database system is initialized (at initdb time), we
 *			  don't use indices on pg_attribute.  We do sequential scans.
2530
 *
2531 2532 2533
 *		   +  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.
2534
 *
2535
 *		   +  If the initialization file isn't there, then we create the
2536
 *			  relation descriptors using sequential scans and write 'em to
2537
 *			  the initialization file for use by subsequent backends.
2538
 *
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
 *		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.
2550 2551 2552 2553 2554
 */

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

2555
static void
2556
init_irels(void)
2557
{
2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568
	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;
2569

2570
	if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | PG_BINARY, 0600)) < 0)
2571
	{
2572 2573 2574
		write_irels();
		return;
	}
2575 2576 2577 2578 2579 2580

	FileSeek(fd, 0L, SEEK_SET);

	for (relno = 0; relno < Num_indices_bootstrap; relno++)
	{
		/* first read the relation descriptor length */
2581
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2582 2583 2584 2585 2586 2587
		{
			write_irels();
			return;
		}

		ird = irel[relno] = (Relation) palloc(len);
Bruce Momjian's avatar
Bruce Momjian committed
2588
		MemSet(ird, 0, len);
2589 2590 2591 2592 2593 2594 2595 2596

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

2597 2598
		/* reset transient fields */
		ird->rd_targblock = InvalidBlockNumber;
2599 2600
		ird->rd_fd = -1;

2601 2602
		ird->rd_node.tblNode = MyDatabaseId;

2603
		/* next, read the access method tuple form */
2604
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
		{
			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 */
2620
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
		{
			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++)
		{
2642
			if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2643 2644 2645 2646 2647
			{
				write_irels();
				return;
			}

2648
			ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
2649 2650 2651 2652 2653 2654 2655 2656 2657

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

		/* next, read the index strategy map */
2658
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671
		{
			write_irels();
			return;
		}

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

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

2674
		/* have to reinit the function pointers in the strategy maps */
2675 2676
		for (i = 0; i < am->amstrategies * relform->relnatts; i++)
		{
2677
			fmgr_info(SMD(i).sk_procedure,
2678
					  &(SMD(i).sk_func));
Bruce Momjian's avatar
Bruce Momjian committed
2679
		}
2680 2681 2682 2683 2684 2685 2686 2687

		/*
		 * 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 */
2688
		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
		{
			write_irels();
			return;
		}

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

2702
		RelationInitLockInfo(ird);
2703 2704

		RelationCacheInsert(ird);
2705
	}
2706
	criticalRelcachesBuilt = true;
2707 2708
}

2709
static void
2710
write_irels(void)
2711
{
Bruce Momjian's avatar
Bruce Momjian committed
2712
	Size		len;
2713 2714 2715 2716 2717 2718 2719 2720 2721 2722
	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;
2723
	RelationBuildDescInfo bi;
2724 2725 2726 2727
	char		tempfilename[MAXPGPATH];
	char		finalfilename[MAXPGPATH];

	/*
2728 2729 2730
	 * 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.
2731
	 */
2732 2733 2734 2735
	snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
			 DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid);
	snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
			 DatabasePath, RELCACHE_INIT_FILENAME);
2736

2737
	fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY, 0600);
2738
	if (fd < 0)
2739
	{
2740

2741 2742 2743 2744 2745 2746 2747
		/*
		 * 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;
	}
2748 2749 2750 2751

	FileSeek(fd, 0L, SEEK_SET);

	/*
2752
	 * Build relation descriptors for the critical system indexes without
2753 2754 2755 2756 2757
	 * 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.
2758 2759
	 */

2760 2761 2762 2763 2764 2765 2766 2767
	/*---------
	 * 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
2768
	 */
2769 2770

	bi.infotype = INFO_RELNAME;
2771
	bi.i.info_name = AttributeRelidNumIndex;
2772
	irel[0] = RelationBuildDesc(bi, NULL);
2773 2774 2775
	irel[0]->rd_isnailed = true;

	bi.i.info_name = ClassNameIndex;
2776
	irel[1] = RelationBuildDesc(bi, NULL);
2777 2778 2779
	irel[1]->rd_isnailed = true;

	bi.i.info_name = ClassOidIndex;
2780
	irel[2] = RelationBuildDesc(bi, NULL);
2781 2782
	irel[2]->rd_isnailed = true;

2783
	criticalRelcachesBuilt = true;
2784 2785 2786 2787

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

2790 2791 2792
	/*
	 * Write out the index reldescs to the special cache file.
	 */
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
	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 */
2812 2813
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2814 2815 2816 2817 2818 2819 2820 2821
			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);
2822 2823
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2824 2825 2826 2827 2828 2829 2830
			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);
2831 2832
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2833 2834 2835 2836 2837 2838 2839 2840 2841
			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++)
		{
2842 2843
			if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
				!= sizeof(len))
2844 2845 2846 2847 2848 2849 2850 2851 2852
				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);
2853 2854
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2855 2856 2857 2858 2859 2860 2861
			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));
2862 2863
		if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
			!= sizeof(len))
2864 2865 2866 2867 2868 2869 2870 2871
			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;
2872
	}
2873 2874

	FileClose(fd);
2875

2876 2877
	/*
	 * And rename the temp file to its final name, deleting any
2878
	 * previously-existing init file.
2879
	 */
2880 2881
	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);
2882
}