index.c 62 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * index.c
4
 *	  code to create and destroy POSTGRES index relations
5
 *
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.134 2001/01/18 04:01:42 inoue Exp $
12 13 14
 *
 *
 * INTERFACE ROUTINES
15
 *		index_create()			- Create a cataloged index relation
16
 *		index_drop()			- Removes index relation from catalogs
17 18
 *		BuildIndexInfo()		- Prepare to insert index tuples
 *		FormIndexDatum()		- Construct datum vector for one index tuple
19 20 21
 *
 *-------------------------------------------------------------------------
 */
22
#include "postgres.h"
23

Tom Lane's avatar
Tom Lane committed
24
#include <unistd.h>
Bruce Momjian's avatar
Bruce Momjian committed
25

26 27 28 29
#include "access/genam.h"
#include "access/heapam.h"
#include "access/istrat.h"
#include "bootstrap/bootstrap.h"
30
#include "catalog/catalog.h"
31 32 33 34
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
Bruce Momjian's avatar
Bruce Momjian committed
35
#include "catalog/pg_index.h"
36 37
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
Bruce Momjian's avatar
Bruce Momjian committed
38
#include "commands/comment.h"
39 40 41 42 43 44 45
#include "executor/executor.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
#include "parser/parse_func.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
46
#include "utils/catcache.h"
47
#include "utils/fmgroids.h"
48
#include "utils/inval.h"
49 50
#include "utils/relcache.h"
#include "utils/syscache.h"
51
#include "utils/temprel.h"
52

53 54 55
/*
 * macros used in guessing how many tuples are on a page.
 */
Bruce Momjian's avatar
Bruce Momjian committed
56 57 58 59
#define AVG_ATTR_SIZE 8
#define NTUPLES_PER_PAGE(natts) \
	((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
	((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
60 61

/* non-export function prototypes */
Bruce Momjian's avatar
Bruce Momjian committed
62
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
63
				   bool istemp);
64
static TupleDesc BuildFuncTupleDesc(Oid funcOid);
65
static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
66
										  int numatts, AttrNumber *attNums);
67
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
68
static Oid	UpdateRelationRelation(Relation indexRelation, char *temp_relname);
69
static void InitializeAttributeOids(Relation indexRelation,
70
						int numatts, Oid indexoid);
71
static void AppendAttributeTuples(Relation indexRelation, int numatts);
72
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
73 74 75
								IndexInfo *indexInfo,
								Oid *classOids,
								bool islossy, bool primary);
76
static void DefaultBuild(Relation heapRelation, Relation indexRelation,
77 78
						 IndexInfo *indexInfo, Node *oldPred,
						 IndexStrategy indexStrategy);
79
static Oid	IndexGetRelation(Oid indexId);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
80
static bool activate_index(Oid indexId, bool activate, bool inplace);
81

82

83
static bool reindexing = false;
84 85 86


bool
87
SetReindexProcessing(bool reindexmode)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
88
{
89 90
	bool		old = reindexing;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
91 92 93
	reindexing = reindexmode;
	return old;
}
94 95

bool
96
IsReindexProcessing(void)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
97 98 99
{
	return reindexing;
}
100

101
/* ----------------------------------------------------------------
102 103 104
 *	  sysatts is a structure containing attribute tuple forms
 *	  for system attributes (numbered -1, -2, ...).  This really
 *	  should be generated or eliminated or moved elsewhere. -cim 1/19/91
105 106
 *
 * typedef struct FormData_pg_attribute {
107 108 109 110 111 112 113 114
 *		Oid				attrelid;
 *		NameData		attname;
 *		Oid				atttypid;
 *		uint32			attnvals;
 *		int16			attlen;
 *		AttrNumber		attnum;
 *		uint32			attnelems;
 *		int32			attcacheoff;
115
 *		int32			atttypmod;
116 117 118 119 120
 *		bool			attbyval;
 *		bool			attisset;
 *		char			attalign;
 *		bool			attnotnull;
 *		bool			atthasdef;
121 122 123 124
 * } FormData_pg_attribute;
 *
 * ----------------------------------------------------------------
 */
125
static FormData_pg_attribute sysatts[] = {
126 127 128 129 130 131
	{0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'},
	{0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
	{0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
	{0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
	{0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
	{0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
132 133 134
};

/* ----------------------------------------------------------------
135
 *		GetHeapRelationOid
136 137
 * ----------------------------------------------------------------
 */
138
static Oid
139
GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
140
{
141 142
	Oid			indoid;
	Oid			heapoid;
143

Bruce Momjian's avatar
Bruce Momjian committed
144

145
	indoid = RelnameFindRelid(indexRelationName);
146

147
	if ((!istemp && OidIsValid(indoid)) ||
148
		(istemp && is_temp_rel_name(indexRelationName)))
Bruce Momjian's avatar
Bruce Momjian committed
149
		elog(ERROR, "Cannot create index: '%s' already exists",
150 151
			 indexRelationName);

152
	heapoid = RelnameFindRelid(heapRelationName);
153 154

	if (!OidIsValid(heapoid))
Bruce Momjian's avatar
Bruce Momjian committed
155
		elog(ERROR, "Cannot create index on '%s': relation does not exist",
156
			 heapRelationName);
Bruce Momjian's avatar
Bruce Momjian committed
157

158
	return heapoid;
159 160
}

161
static TupleDesc
162
BuildFuncTupleDesc(Oid funcOid)
163
{
164
	TupleDesc	funcTupDesc;
165
	HeapTuple	tuple;
166
	Oid			retType;
167 168 169 170 171

	/*
	 * Allocate and zero a tuple descriptor.
	 */
	funcTupDesc = CreateTemplateTupleDesc(1);
172
	funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
Bruce Momjian's avatar
Bruce Momjian committed
173
	MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
174 175

	/*
176
	 * Lookup the function to get its name and return type.
177
	 */
178 179 180
	tuple = SearchSysCache(PROCOID,
						   ObjectIdGetDatum(funcOid),
						   0, 0, 0);
181
	if (!HeapTupleIsValid(tuple))
182
		elog(ERROR, "Function %u does not exist", funcOid);
183 184 185
	retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;

	/*
186 187 188 189 190
	 * make the attributes name the same as the functions
	 */
	namestrcpy(&funcTupDesc->attrs[0]->attname,
			   NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));

191 192
	ReleaseSysCache(tuple);

193 194
	/*
	 * Lookup the return type in pg_type for the type length etc.
195
	 */
196 197 198
	tuple = SearchSysCache(TYPEOID,
						   ObjectIdGetDatum(retType),
						   0, 0, 0);
199
	if (!HeapTupleIsValid(tuple))
200
		elog(ERROR, "Type %u does not exist", retType);
201 202 203 204

	/*
	 * Assign some of the attributes values. Leave the rest as 0.
	 */
205
	funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
206 207
	funcTupDesc->attrs[0]->atttypid = retType;
	funcTupDesc->attrs[0]->attnum = 1;
208
	funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
Bruce Momjian's avatar
Bruce Momjian committed
209 210
	funcTupDesc->attrs[0]->attcacheoff = -1;
	funcTupDesc->attrs[0]->atttypmod = -1;
211
	funcTupDesc->attrs[0]->attstorage = 'p';
212
	funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
213

214 215
	ReleaseSysCache(tuple);

216
	return funcTupDesc;
217 218 219
}

/* ----------------------------------------------------------------
220
 *		ConstructTupleDescriptor
221 222
 *
 * Build an index tuple descriptor for a new index (plain not functional)
223 224
 * ----------------------------------------------------------------
 */
225
static TupleDesc
226
ConstructTupleDescriptor(Oid heapoid,
227 228
						 Relation heapRelation,
						 int numatts,
229
						 AttrNumber *attNums)
230
{
231 232
	TupleDesc	heapTupDesc;
	TupleDesc	indexTupDesc;
233
	int			natts;			/* #atts in heap rel --- for error checks */
234
	int			i;
235

236 237 238
	heapTupDesc = RelationGetDescr(heapRelation);
	natts = RelationGetForm(heapRelation)->relnatts;

239 240 241 242 243 244 245 246 247 248 249 250 251
	/* ----------------
	 *	allocate the new tuple descriptor
	 * ----------------
	 */

	indexTupDesc = CreateTemplateTupleDesc(numatts);

	/* ----------------
	 *	  for each attribute we are indexing, obtain its attribute
	 *	  tuple form from either the static table of system attribute
	 *	  tuple forms or the relation tuple descriptor
	 * ----------------
	 */
252
	for (i = 0; i < numatts; i++)
253
	{
254 255 256 257
		AttrNumber	atnum;		/* attributeNumber[attributeOffset] */
		AttrNumber	atind;
		char	   *from;		/* used to simplify memcpy below */
		char	   *to;			/* used to simplify memcpy below */
258 259 260 261 262 263 264

		/* ----------------
		 *	 get the attribute number and make sure it's valid
		 * ----------------
		 */
		atnum = attNums[i];
		if (atnum > natts)
Bruce Momjian's avatar
Bruce Momjian committed
265
			elog(ERROR, "Cannot create index: attribute %d does not exist",
266 267
				 atnum);

268 269
		indexTupDesc->attrs[i] =
			(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
270 271 272 273 274 275 276 277

		/* ----------------
		 *	 determine which tuple descriptor to copy
		 * ----------------
		 */
		if (!AttrNumberIsForUserDefinedAttr(atnum))
		{
			/* ----------------
278 279
			 *	  here we are indexing on a system attribute (-1...-n)
			 *	  so we convert atnum into a usable index 0...n-1 so we can
280 281 282 283 284
			 *	  use it to dereference the array sysatts[] which stores
			 *	  tuple descriptor information for system attributes.
			 * ----------------
			 */
			if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
Bruce Momjian's avatar
Bruce Momjian committed
285
				elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
			atind = (-atnum) - 1;

			from = (char *) (&sysatts[atind]);
		}
		else
		{
			/* ----------------
			 *	  here we are indexing on a normal attribute (1...n)
			 * ----------------
			 */
			atind = AttrNumberGetAttrOffset(atnum);

			from = (char *) (heapTupDesc->attrs[atind]);
		}

		/* ----------------
		 *	 now that we've determined the "from", let's copy
		 *	 the tuple desc data...
		 * ----------------
		 */
		to = (char *) (indexTupDesc->attrs[i]);
		memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);

309 310 311
		/*
		 * Fix the stuff that should not be the same as the underlying attr
		 */
312
		((Form_pg_attribute) to)->attnum = i + 1;
313

314
		((Form_pg_attribute) to)->attdispersion = 0.0;
315 316 317
		((Form_pg_attribute) to)->attnotnull = false;
		((Form_pg_attribute) to)->atthasdef = false;
		((Form_pg_attribute) to)->attcacheoff = -1;
318 319 320 321 322 323 324

		/* ----------------
		 *	  now we have to drop in the proper relation descriptor
		 *	  into the copied tuple form's attrelid and we should be
		 *	  all set.
		 * ----------------
		 */
325
		((Form_pg_attribute) to)->attrelid = heapoid;
326 327 328 329 330 331
	}

	return indexTupDesc;
}

/* ----------------------------------------------------------------
Bruce Momjian's avatar
Bruce Momjian committed
332
 * AccessMethodObjectIdGetForm
333 334
 *		Returns an access method tuple given its object identifier,
 *		or NULL if no such AM tuple can be found.
335
 *
336 337 338
 * Scanning is done using CurrentMemoryContext as working storage,
 * but the returned tuple will be allocated in resultCxt (which is
 * typically CacheMemoryContext).
339
 *
340 341 342
 * There was a note here about adding indexing, but I don't see a need
 * for it.  There are so few tuples in pg_am that an indexscan would
 * surely be slower.
343 344 345
 * ----------------------------------------------------------------
 */
Form_pg_am
346 347
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
							MemoryContext resultCxt)
348
{
349 350 351 352
	Relation	pg_am_desc;
	HeapScanDesc pg_am_scan;
	HeapTuple	pg_am_tuple;
	ScanKeyData key;
353
	Form_pg_am	aform;
354 355 356 357 358 359

	/* ----------------
	 *	form a scan key for the pg_am relation
	 * ----------------
	 */
	ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
Bruce Momjian's avatar
Bruce Momjian committed
360
						   F_OIDEQ,
361 362 363 364 365 366
						   ObjectIdGetDatum(accessMethodObjectId));

	/* ----------------
	 *	fetch the desired access method tuple
	 * ----------------
	 */
367
	pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
368
	pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
369

370
	pg_am_tuple = heap_getnext(pg_am_scan, 0);
371 372 373 374 375 376 377 378

	/* ----------------
	 *	return NULL if not found
	 * ----------------
	 */
	if (!HeapTupleIsValid(pg_am_tuple))
	{
		heap_endscan(pg_am_scan);
379
		heap_close(pg_am_desc, AccessShareLock);
380
		return NULL;
381 382 383
	}

	/* ----------------
384
	 *	if found AM tuple, then copy it into resultCxt and return the copy
385 386
	 * ----------------
	 */
387
	aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
388
	memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
389 390

	heap_endscan(pg_am_scan);
391
	heap_close(pg_am_desc, AccessShareLock);
392

393
	return aform;
394 395 396 397 398 399 400 401 402
}

/* ----------------------------------------------------------------
 *		ConstructIndexReldesc
 * ----------------------------------------------------------------
 */
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
403 404
	indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
													   CacheMemoryContext);
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

	/* ----------------
	 *	 XXX missing the initialization of some other fields
	 * ----------------
	 */

	indexRelation->rd_rel->relowner = GetUserId();

	indexRelation->rd_rel->relam = amoid;
	indexRelation->rd_rel->reltuples = 1;		/* XXX */
	indexRelation->rd_rel->relkind = RELKIND_INDEX;
}

/* ----------------------------------------------------------------
 *		UpdateRelationRelation
 * ----------------------------------------------------------------
 */
422
static Oid
423
UpdateRelationRelation(Relation indexRelation, char *temp_relname)
424
{
425 426 427 428
	Relation	pg_class;
	HeapTuple	tuple;
	Oid			tupleOid;
	Relation	idescs[Num_pg_class_indices];
429

430
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
431 432 433

	/* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
	tuple = heap_addheader(Natts_pg_class_fixed,
434
						   CLASS_TUPLE_SIZE,
435 436
						   (char *) indexRelation->rd_rel);

437 438
	/* ----------------
	 *	the new tuple must have the same oid as the relcache entry for the
439 440
	 *	index.	sure would be embarrassing to do this sort of thing in
	 *	polite company.
441
	 * ----------------
442
	 */
443
	tuple->t_data->t_oid = RelationGetRelid(indexRelation);
444 445
	heap_insert(pg_class, tuple);

446 447
	if (temp_relname)
		create_temp_relation(temp_relname, tuple);
Bruce Momjian's avatar
Bruce Momjian committed
448

449 450 451 452 453 454 455
	/*
	 * During normal processing, we need to make sure that the system
	 * catalog indices are correct.  Bootstrap (initdb) time doesn't
	 * require this, because we make sure that the indices are correct
	 * just before exiting.
	 */

Hiroshi Inoue's avatar
Hiroshi Inoue committed
456
	if (!IsIgnoringSystemIndexes())
457 458 459 460 461 462
	{
		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
		CatalogCloseIndices(Num_pg_class_indices, idescs);
	}

463
	tupleOid = tuple->t_data->t_oid;
464
	heap_freetuple(tuple);
465
	heap_close(pg_class, RowExclusiveLock);
466

467
	return tupleOid;
468 469 470 471 472 473 474 475 476 477 478
}

/* ----------------------------------------------------------------
 *		InitializeAttributeOids
 * ----------------------------------------------------------------
 */
static void
InitializeAttributeOids(Relation indexRelation,
						int numatts,
						Oid indexoid)
{
479 480
	TupleDesc	tupleDescriptor;
	int			i;
481

482
	tupleDescriptor = RelationGetDescr(indexRelation);
483 484 485 486 487 488 489 490 491 492 493 494 495 496

	for (i = 0; i < numatts; i += 1)
		tupleDescriptor->attrs[i]->attrelid = indexoid;
}

/* ----------------------------------------------------------------
 *		AppendAttributeTuples
 *
 *		XXX For now, only change the ATTNUM attribute value
 * ----------------------------------------------------------------
 */
static void
AppendAttributeTuples(Relation indexRelation, int numatts)
{
497
	Relation	pg_attribute;
498 499 500
	HeapTuple	init_tuple,
				cur_tuple = NULL,
				new_tuple;
501 502 503 504 505 506 507
	bool		hasind;
	Relation	idescs[Num_pg_attr_indices];
	Datum		value[Natts_pg_attribute];
	char		nullv[Natts_pg_attribute];
	char		replace[Natts_pg_attribute];
	TupleDesc	indexTupDesc;
	int			i;
508 509 510 511 512

	/* ----------------
	 *	open the attribute relation
	 * ----------------
	 */
513
	pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
514 515

	/* ----------------
516
	 *	initialize *null, *replace and *value
517 518
	 * ----------------
	 */
Bruce Momjian's avatar
Bruce Momjian committed
519 520
	MemSet(nullv, ' ', Natts_pg_attribute);
	MemSet(replace, ' ', Natts_pg_attribute);
521 522 523 524 525 526 527 528 529 530 531 532

	/* ----------------
	 *	create the first attribute tuple.
	 *	XXX For now, only change the ATTNUM attribute value
	 * ----------------
	 */
	replace[Anum_pg_attribute_attnum - 1] = 'r';
	replace[Anum_pg_attribute_attcacheoff - 1] = 'r';

	value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
	value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);

533
	init_tuple = heap_addheader(Natts_pg_attribute,
Bruce Momjian's avatar
Bruce Momjian committed
534
								ATTRIBUTE_TUPLE_SIZE,
535
							 (char *) (indexRelation->rd_att->attrs[0]));
536 537

	hasind = false;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
538
	if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
539 540 541 542 543 544 545 546 547
	{
		hasind = true;
		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
	}

	/* ----------------
	 *	insert the first attribute tuple.
	 * ----------------
	 */
548
	cur_tuple = heap_modifytuple(init_tuple,
549 550 551 552
								 pg_attribute,
								 value,
								 nullv,
								 replace);
553
	heap_freetuple(init_tuple);
554

555
	heap_insert(pg_attribute, cur_tuple);
556
	if (hasind)
557
		CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
558 559

	/* ----------------
560
	 *	now we use the information in the index cur_tuple
561 562 563
	 *	descriptor to form the remaining attribute tuples.
	 * ----------------
	 */
564
	indexTupDesc = RelationGetDescr(indexRelation);
565 566 567 568 569 570 571

	for (i = 1; i < numatts; i += 1)
	{
		/* ----------------
		 *	process the remaining attributes...
		 * ----------------
		 */
572
		memmove(GETSTRUCT(cur_tuple),
573
				(char *) indexTupDesc->attrs[i],
Bruce Momjian's avatar
Bruce Momjian committed
574
				ATTRIBUTE_TUPLE_SIZE);
575 576 577

		value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);

578
		new_tuple = heap_modifytuple(cur_tuple,
579 580 581 582
									 pg_attribute,
									 value,
									 nullv,
									 replace);
583
		heap_freetuple(cur_tuple);
584

585
		heap_insert(pg_attribute, new_tuple);
586
		if (hasind)
587
			CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
588 589

		/* ----------------
590
		 *	ModifyHeapTuple returns a new copy of a cur_tuple
591 592 593
		 *	so we free the original and use the copy..
		 * ----------------
		 */
594
		cur_tuple = new_tuple;
595 596
	}

597
	if (cur_tuple)
598
		heap_freetuple(cur_tuple);
599
	heap_close(pg_attribute, RowExclusiveLock);
600 601 602 603 604 605 606 607 608 609 610
	if (hasind)
		CatalogCloseIndices(Num_pg_attr_indices, idescs);
}

/* ----------------------------------------------------------------
 *		UpdateIndexRelation
 * ----------------------------------------------------------------
 */
static void
UpdateIndexRelation(Oid indexoid,
					Oid heapoid,
611
					IndexInfo *indexInfo,
612
					Oid *classOids,
613
					bool islossy,
Bruce Momjian's avatar
Bruce Momjian committed
614
					bool primary)
615
{
616
	Form_pg_index indexForm;
617 618 619 620 621 622 623
	char	   *predString;
	text	   *predText;
	int			predLen,
				itupLen;
	Relation	pg_index;
	HeapTuple	tuple;
	int			i;
624
	Relation	idescs[Num_pg_index_indices];
625 626

	/* ----------------
627
	 *	allocate a Form_pg_index big enough to hold the
628 629 630
	 *	index-predicate (if any) in string form
	 * ----------------
	 */
631
	if (indexInfo->ii_Predicate != NULL)
632
	{
633
		predString = nodeToString(indexInfo->ii_Predicate);
634 635
		predText = DatumGetTextP(DirectFunctionCall1(textin,
											CStringGetDatum(predString)));
636 637 638
		pfree(predString);
	}
	else
639 640
		predText = DatumGetTextP(DirectFunctionCall1(textin,
													 CStringGetDatum("")));
641

642 643
	predLen = VARSIZE(predText);
	itupLen = predLen + sizeof(FormData_pg_index);
644
	indexForm = (Form_pg_index) palloc(itupLen);
645
	MemSet(indexForm, 0, sizeof(FormData_pg_index));
646 647

	/* ----------------
648
	 *	store information into the index tuple form
649 650 651
	 * ----------------
	 */
	indexForm->indexrelid = indexoid;
652 653 654
	indexForm->indrelid = heapoid;
	indexForm->indproc = indexInfo->ii_FuncOid;
	indexForm->indisclustered = false;
655
	indexForm->indislossy = islossy;
656 657
	indexForm->indhaskeytype = true; /* not actually used anymore */
	indexForm->indisunique = indexInfo->ii_Unique;
658
	indexForm->indisprimary = primary;
659
	memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
660 661 662

	/* ----------------
	 *	copy index key and op class information
663 664
	 *
	 *	We zeroed the extra slots (if any) above --- that's essential.
665 666
	 * ----------------
	 */
667 668
	for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
		indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
669

670 671
	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
		indexForm->indclass[i] = classOids[i];
672 673 674 675 676

	/* ----------------
	 *	open the system catalog index relation
	 * ----------------
	 */
677
	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

	/* ----------------
	 *	form a tuple to insert into pg_index
	 * ----------------
	 */
	tuple = heap_addheader(Natts_pg_index,
						   itupLen,
						   (char *) indexForm);

	/* ----------------
	 *	insert the tuple into the pg_index
	 * ----------------
	 */
	heap_insert(pg_index, tuple);

693
	/* ----------------
694
	 *	add index tuples for it
695 696
	 * ----------------
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
697
	if (!IsIgnoringSystemIndexes())
698 699 700 701 702
	{
		CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
		CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
		CatalogCloseIndices(Num_pg_index_indices, idescs);
	}
703

704 705 706 707
	/* ----------------
	 *	close the relation and free the tuple
	 * ----------------
	 */
708
	heap_close(pg_index, RowExclusiveLock);
709 710
	pfree(predText);
	pfree(indexForm);
711
	heap_freetuple(tuple);
712 713 714 715 716 717 718
}

/* ----------------------------------------------------------------
 *		UpdateIndexPredicate
 * ----------------------------------------------------------------
 */
void
719
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
720
{
721 722 723 724 725 726 727 728 729 730
	Node	   *newPred;
	char	   *predString;
	text	   *predText;
	Relation	pg_index;
	HeapTuple	tuple;
	HeapTuple	newtup;
	int			i;
	Datum		values[Natts_pg_index];
	char		nulls[Natts_pg_index];
	char		replace[Natts_pg_index];
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745

	/*
	 * Construct newPred as a CNF expression equivalent to the OR of the
	 * original partial-index predicate ("oldPred") and the extension
	 * predicate ("predicate").
	 *
	 * This should really try to process the result to change things like
	 * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
	 * that if the extension predicate is NULL (i.e., it is being extended
	 * to be a complete index), then newPred will be NULL - in effect,
	 * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
	 */
	newPred = NULL;
	if (predicate != NULL)
	{
746
		newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
747 748 749 750 751 752 753 754 755
								  lcons(make_andclause((List *) oldPred),
										NIL)));
		newPred = (Node *) cnfify((Expr *) newPred, true);
	}

	/* translate the index-predicate to string form */
	if (newPred != NULL)
	{
		predString = nodeToString(newPred);
756 757
		predText = DatumGetTextP(DirectFunctionCall1(textin,
											CStringGetDatum(predString)));
758 759 760
		pfree(predString);
	}
	else
761 762
		predText = DatumGetTextP(DirectFunctionCall1(textin,
													 CStringGetDatum("")));
763 764

	/* open the index system catalog relation */
765
	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
766

767 768 769 770 771 772
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexoid),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
			 indexoid);
773

774 775 776 777 778 779 780 781 782 783
	for (i = 0; i < Natts_pg_index; i++)
	{
		nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
		replace[i] = ' ';
		values[i] = (Datum) NULL;
	}

	replace[Anum_pg_index_indpred - 1] = 'r';
	values[Anum_pg_index_indpred - 1] = (Datum) predText;

784
	newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
785

786
	heap_update(pg_index, &newtup->t_self, newtup, NULL);
787

788
	heap_freetuple(newtup);
789 790
	ReleaseSysCache(tuple);

791
	heap_close(pg_index, RowExclusiveLock);
792 793 794 795 796 797 798 799 800 801 802 803
	pfree(predText);
}

/* ----------------------------------------------------------------
 *		InitIndexStrategy
 * ----------------------------------------------------------------
 */
void
InitIndexStrategy(int numatts,
				  Relation indexRelation,
				  Oid accessMethodObjectId)
{
804 805 806 807 808 809
	IndexStrategy strategy;
	RegProcedure *support;
	uint16		amstrategies;
	uint16		amsupport;
	Oid			attrelid;
	Size		strsize;
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832

	/* ----------------
	 *	get information from the index relation descriptor
	 * ----------------
	 */
	attrelid = indexRelation->rd_att->attrs[0]->attrelid;
	amstrategies = indexRelation->rd_am->amstrategies;
	amsupport = indexRelation->rd_am->amsupport;

	/* ----------------
	 *	get the size of the strategy
	 * ----------------
	 */
	strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);

	/* ----------------
	 *	allocate the new index strategy structure
	 *
	 *	the index strategy has to be allocated in the same
	 *	context as the relation descriptor cache or else
	 *	it will be lost at the end of the transaction.
	 * ----------------
	 */
833 834
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
835

836 837
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  strsize);
838 839 840 841

	if (amsupport > 0)
	{
		strsize = numatts * (amsupport * sizeof(RegProcedure));
842
		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
843 844 845 846 847 848 849
													  strsize);
	}
	else
		support = (RegProcedure *) NULL;

	/* ----------------
	 *	fill in the index strategy structure with information
850 851
	 *	from the catalogs.	First we must advance the command counter
	 *	so that we will see the newly-entered index catalog tuples.
852 853
	 * ----------------
	 */
854
	CommandCounterIncrement();
855 856

	IndexSupportInitialize(strategy, support,
857
						   &indexRelation->rd_uniqueindex,
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
						   attrelid, accessMethodObjectId,
						   amstrategies, amsupport, numatts);

	/* ----------------
	 *	store the strategy information in the index reldesc
	 * ----------------
	 */
	RelationSetIndexSupport(indexRelation, strategy, support);
}


/* ----------------------------------------------------------------
 *		index_create
 * ----------------------------------------------------------------
 */
void
index_create(char *heapRelationName,
			 char *indexRelationName,
876
			 IndexInfo *indexInfo,
877
			 Oid accessMethodObjectId,
878
			 Oid *classObjectId,
879
			 bool islossy,
880 881
			 bool primary,
			 bool allow_system_table_mods)
882
{
883 884 885 886 887
	Relation	heapRelation;
	Relation	indexRelation;
	TupleDesc	indexTupDesc;
	Oid			heapoid;
	Oid			indexoid;
888
	bool		istemp = is_temp_rel_name(heapRelationName);
Bruce Momjian's avatar
Bruce Momjian committed
889 890
	char	   *temp_relname = NULL;

891 892
	SetReindexProcessing(false);

893 894 895 896
	/* ----------------
	 *	check parameters
	 * ----------------
	 */
897 898
	if (indexInfo->ii_NumIndexAttrs < 1 ||
		indexInfo->ii_NumKeyAttrs < 1)
Bruce Momjian's avatar
Bruce Momjian committed
899
		elog(ERROR, "must index at least one attribute");
Bruce Momjian's avatar
Bruce Momjian committed
900

901 902 903 904
	/* ----------------
	 *	  get heap relation oid and open the heap relation
	 * ----------------
	 */
905
	heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
906

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
907
	/*
908
	 * Only SELECT ... FOR UPDATE are allowed while doing this
909
	 */
910
	heapRelation = heap_open(heapoid, ShareLock);
911 912 913 914 915

	/* ----------------
	 *	  construct new tuple descriptor
	 * ----------------
	 */
916 917
	if (OidIsValid(indexInfo->ii_FuncOid))
		indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
918 919 920
	else
		indexTupDesc = ConstructTupleDescriptor(heapoid,
												heapRelation,
921 922
												indexInfo->ii_NumKeyAttrs,
												indexInfo->ii_KeyAttrNumbers);
923

924 925
	if (istemp)
	{
926 927
		/* save user relation name because heap_create changes it */
		temp_relname = pstrdup(indexRelationName);	/* save original value */
928
		indexRelationName = palloc(NAMEDATALEN);
929 930
		strcpy(indexRelationName, temp_relname);	/* heap_create will
													 * change this */
931 932
	}

933
	/* ----------------
934
	 *	create the index relation
935 936
	 * ----------------
	 */
937
	indexRelation = heap_create(indexRelationName, indexTupDesc,
938
								istemp, false, allow_system_table_mods);
939

940 941 942 943 944 945 946
	/*
	 * Obtain exclusive lock on it.  Although no other backends can see it
	 * until we commit, this prevents deadlock-risk complaints from lock
	 * manager in cases such as CLUSTER.
	 */
	LockRelation(indexRelation, AccessExclusiveLock);

947
	/* ----------------
948 949 950
	 *	  construct the index relation descriptor
	 *
	 *	  XXX should have a proper way to create cataloged relations
951 952
	 * ----------------
	 */
953 954
	ConstructIndexReldesc(indexRelation, accessMethodObjectId);

955
	/* ----------------
956
	 *	  add index to catalogs
957
	 *	  (append RELATION tuple)
958 959
	 * ----------------
	 */
960
	indexoid = UpdateRelationRelation(indexRelation, temp_relname);
961

962 963 964 965
	/*
	 * We create the disk file for this relation here
	 */
	heap_storage_create(indexRelation);
966

967 968 969 970 971
	/* ----------------
	 *	now update the object id's of all the attribute
	 *	tuple forms in the index relation's tuple descriptor
	 * ----------------
	 */
972 973 974
	InitializeAttributeOids(indexRelation,
							indexInfo->ii_NumIndexAttrs,
							indexoid);
975 976

	/* ----------------
977
	 *	  append ATTRIBUTE tuples for the index
978 979
	 * ----------------
	 */
980
	AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
981

982
	/* ----------------
983 984 985 986 987
	 *	  update pg_index
	 *	  (append INDEX tuple)
	 *
	 *	  Note that this stows away a representation of "predicate".
	 *	  (Or, could define a rule to maintain the predicate) --Nels, Feb '92
988 989
	 * ----------------
	 */
990 991
	UpdateIndexRelation(indexoid, heapoid, indexInfo,
						classObjectId, islossy, primary);
992 993 994 995 996

	/* ----------------
	 *	  initialize the index strategy
	 * ----------------
	 */
997 998 999
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
					  indexRelation,
					  accessMethodObjectId);
1000 1001 1002 1003 1004 1005

	/*
	 * If this is bootstrap (initdb) time, then we don't actually fill in
	 * the index yet.  We'll be creating more indices and classes later,
	 * so we delay filling them in until just before we're done with
	 * bootstrapping.  Otherwise, we call the routine that constructs the
1006 1007
	 * index.
	 *
1008 1009
	 * In normal processing mode, the heap and index relations are closed by
	 * index_build() --- but we continue to hold the ShareLock on the heap
1010 1011
	 * and the exclusive lock on the index that we acquired above, until
	 * end of transaction.
1012 1013
	 */
	if (IsBootstrapProcessingMode())
1014
	{
1015
		index_register(heapRelationName, indexRelationName, indexInfo);
1016
		/* XXX shouldn't we close the heap and index rels here? */
1017 1018
	}
	else
1019
	{
1020
		index_build(heapRelation, indexRelation, indexInfo, NULL);
1021 1022 1023 1024
	}
}

/* ----------------------------------------------------------------
1025
 *
1026
 *		index_drop
1027
 *
1028 1029 1030
 * ----------------------------------------------------------------
 */
void
1031
index_drop(Oid indexId)
1032
{
1033
	Oid			heapId;
1034 1035
	Relation	userHeapRelation;
	Relation	userIndexRelation;
1036
	Relation	indexRelation;
1037
	Relation	relationRelation;
Bruce Momjian's avatar
Bruce Momjian committed
1038
	Relation	attributeRelation;
1039
	HeapTuple	tuple;
Bruce Momjian's avatar
Bruce Momjian committed
1040
	int16		attnum;
1041
	int			i;
Bruce Momjian's avatar
Bruce Momjian committed
1042

1043
	Assert(OidIsValid(indexId));
1044

1045 1046 1047 1048 1049 1050 1051 1052 1053
	/* ----------------
	 *	To drop an index safely, we must grab exclusive lock on its parent
	 *	table; otherwise there could be other backends using the index!
	 *	Exclusive lock on the index alone is insufficient because the index
	 *	access routines are a little slipshod about obtaining adequate locking
	 *	(see ExecOpenIndices()).  We do grab exclusive lock on the index too,
	 *	just to be safe.  Both locks must be held till end of transaction,
	 *	else other backends will still see this index in pg_index.
	 * ----------------
1054
	 */
1055 1056
	heapId = IndexGetRelation(indexId);
	userHeapRelation = heap_open(heapId, AccessExclusiveLock);
1057 1058 1059

	userIndexRelation = index_open(indexId);
	LockRelation(userIndexRelation, AccessExclusiveLock);
1060

1061
	/* ----------------
1062 1063 1064
	 *	Note: unlike heap_drop_with_catalog, we do not need to prevent
	 *	deletion of system indexes here; that's checked for upstream.
	 *	If we did check it here, deletion of TOAST tables would fail...
1065 1066 1067
	 * ----------------
	 */

Bruce Momjian's avatar
Bruce Momjian committed
1068 1069 1070 1071 1072
	/* ----------------
	 * fix DESCRIPTION relation
	 * ----------------
	 */
	DeleteComments(indexId);
1073

1074 1075 1076 1077
	/* ----------------
	 * fix RELATION relation
	 * ----------------
	 */
1078
	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1079

1080
	/* Remove the pg_class tuple for the index itself */
1081 1082 1083 1084 1085 1086
	tuple = SearchSysCacheCopy(RELOID,
							   ObjectIdGetDatum(indexId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "index_drop: cache lookup failed for index %u",
			 indexId);
1087

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1088
	heap_delete(relationRelation, &tuple->t_self, NULL);
1089
	heap_freetuple(tuple);
1090 1091

	/*
1092 1093 1094 1095 1096 1097
	 * Update the pg_class tuple for the owning relation.  We are presently
	 * too lazy to attempt to compute the new correct value of relhasindex
	 * (the next VACUUM will fix it if necessary).  But we must send out a
	 * shared-cache-inval notice on the owning relation to ensure other
	 * backends update their relcache lists of indexes.  So, unconditionally
	 * do setRelhasindex(true).
1098
	 */
1099
	setRelhasindex(heapId, true);
1100

1101
	heap_close(relationRelation, RowExclusiveLock);
1102 1103 1104 1105 1106

	/* ----------------
	 * fix ATTRIBUTE relation
	 * ----------------
	 */
1107
	attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1108

1109
	attnum = 1;					/* indexes start at 1 */
1110

1111
	while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
1112 1113
											   ObjectIdGetDatum(indexId),
												   Int16GetDatum(attnum),
1114
													   0, 0)))
1115
	{
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1116
		heap_delete(attributeRelation, &tuple->t_self, NULL);
1117
		heap_freetuple(tuple);
1118 1119
		attnum++;
	}
1120
	heap_close(attributeRelation, RowExclusiveLock);
1121

1122 1123 1124 1125
	/* ----------------
	 * fix INDEX relation
	 * ----------------
	 */
1126 1127
	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);

1128 1129 1130 1131 1132 1133
	tuple = SearchSysCacheCopy(INDEXRELID,
							   ObjectIdGetDatum(indexId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "index_drop: cache lookup failed for index %u",
			 indexId);
Bruce Momjian's avatar
Bruce Momjian committed
1134

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1135
	heap_delete(indexRelation, &tuple->t_self, NULL);
1136
	heap_freetuple(tuple);
1137
	heap_close(indexRelation, RowExclusiveLock);
1138 1139

	/*
1140
	 * flush buffer cache and physically remove the file
1141
	 */
1142 1143 1144
	i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
	if (i < 0)
		elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
1145

1146
	smgrunlink(DEFAULT_SMGR, userIndexRelation);
1147

1148 1149 1150 1151 1152
	/*
	 * Close rels, but keep locks
	 */
	index_close(userIndexRelation);
	heap_close(userHeapRelation, NoLock);
1153 1154

	RelationForgetRelation(indexId);
1155

1156
	/* if it's a temp index, clear the temp mapping table entry */
1157
	remove_temp_rel_by_relid(indexId);
1158 1159 1160
}

/* ----------------------------------------------------------------
1161
 *						index_build support
1162 1163
 * ----------------------------------------------------------------
 */
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236

/* ----------------
 *		BuildIndexInfo
 *			Construct an IndexInfo record given the index's pg_index tuple
 *
 * IndexInfo stores the information about the index that's needed by
 * FormIndexDatum, which is used for both index_build() and later insertion
 * of individual index tuples.  Normally we build an IndexInfo for an index
 * just once per command, and then use it for (potentially) many tuples.
 * ----------------
 */
IndexInfo *
BuildIndexInfo(HeapTuple indexTuple)
{
	Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
	IndexInfo  *ii = makeNode(IndexInfo);
	int			i;
	int			numKeys;

	/* ----------------
	 *	count the number of keys, and copy them into the IndexInfo
	 * ----------------
	 */
	numKeys = 0;
	for (i = 0; i < INDEX_MAX_KEYS &&
		 indexStruct->indkey[i] != InvalidAttrNumber; i++)
	{
		ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
		numKeys++;
	}
	ii->ii_NumKeyAttrs = numKeys;

	/* ----------------
	 *	Handle functional index.
	 *
	 *	If we have a functional index then the number of
	 *	attributes defined in the index must be 1 (the function's
	 *	single return value).  Otherwise it's same as number of keys.
	 * ----------------
	 */
	ii->ii_FuncOid = indexStruct->indproc;

	if (OidIsValid(indexStruct->indproc))
	{
		ii->ii_NumIndexAttrs = 1;
		/* Do a lookup on the function, too */
		fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
	}
	else
		ii->ii_NumIndexAttrs = numKeys;

	/* ----------------
	 *	If partial index, convert predicate into expression nodetree
	 * ----------------
	 */
	if (VARSIZE(&indexStruct->indpred) != 0)
	{
		char	   *predString;

		predString = DatumGetCString(DirectFunctionCall1(textout,
									 PointerGetDatum(&indexStruct->indpred)));
		ii->ii_Predicate = stringToNode(predString);
		pfree(predString);
	}
	else
		ii->ii_Predicate = NULL;

	/* Other info */
	ii->ii_Unique = indexStruct->indisunique;

	return ii;
}

1237
/* ----------------
1238
 *		FormIndexDatum
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
 *			Construct Datum[] and nullv[] arrays for a new index tuple.
 *
 *	indexInfo		Info about the index
 *	heapTuple		Heap tuple for which we must prepare an index entry
 *	heapDescriptor	tupledesc for heap tuple
 *	resultCxt		Temporary memory context for any palloc'd datums created
 *	datum			Array of index Datums (output area)
 *	nullv			Array of is-null indicators (output area)
 *
 * For largely historical reasons, we don't actually call index_formtuple()
 * here, we just prepare its input arrays datum[] and nullv[].
1250 1251 1252
 * ----------------
 */
void
1253
FormIndexDatum(IndexInfo *indexInfo,
1254 1255
			   HeapTuple heapTuple,
			   TupleDesc heapDescriptor,
1256
			   MemoryContext resultCxt,
1257
			   Datum *datum,
1258
			   char *nullv)
1259
{
1260 1261 1262
	MemoryContext oldContext;
	int			i;
	Datum		iDatum;
1263
	bool		isNull;
1264

1265
	oldContext = MemoryContextSwitchTo(resultCxt);
1266

1267
	if (OidIsValid(indexInfo->ii_FuncOid))
1268
	{
1269 1270 1271 1272 1273 1274
		/* ----------------
		 *	Functional index --- compute the single index attribute
		 * ----------------
		 */
		FunctionCallInfoData	fcinfo;
		bool					anynull = false;
1275

1276 1277 1278
		MemSet(&fcinfo, 0, sizeof(fcinfo));
		fcinfo.flinfo = &indexInfo->ii_FuncInfo;
		fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
Bruce Momjian's avatar
Bruce Momjian committed
1279

1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
		for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
		{
			fcinfo.arg[i] = heap_getattr(heapTuple,
										 indexInfo->ii_KeyAttrNumbers[i],
										 heapDescriptor,
										 &fcinfo.argnull[i]);
			anynull |= fcinfo.argnull[i];
		}
		if (indexInfo->ii_FuncInfo.fn_strict && anynull)
		{
			/* force a null result for strict function */
			iDatum = (Datum) 0;
			isNull = true;
		}
		else
		{
			iDatum = FunctionCallInvoke(&fcinfo);
			isNull = fcinfo.isnull;
		}
		datum[0] = iDatum;
		nullv[0] = (isNull) ? 'n' : ' ';
	}
	else
	{
		/* ----------------
		 *	Plain index --- for each attribute we need from the heap tuple,
		 *	get the attribute and stick it into the datum and nullv arrays.
		 * ----------------
		 */
		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
		{
			iDatum = heap_getattr(heapTuple,
								  indexInfo->ii_KeyAttrNumbers[i],
								  heapDescriptor,
								  &isNull);
			datum[i] = iDatum;
			nullv[i] = (isNull) ? 'n' : ' ';
		}
1318
	}
1319 1320

	MemoryContextSwitchTo(oldContext);
1321 1322 1323
}


Hiroshi Inoue's avatar
Hiroshi Inoue committed
1324 1325 1326 1327
/* --------------------------------------------
 *		Lock class info for update
 * --------------------------------------------
 */
1328 1329 1330
static bool
LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
					   Buffer *buffer, bool confirmCommitted)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1331 1332 1333 1334 1335
{
	HeapTuple	classTuple;
	bool		test;
	Relation	relationRelation;

1336 1337 1338 1339 1340
	/*
	 * NOTE: get and hold RowExclusiveLock on pg_class, because caller will
	 * probably modify the rel's pg_class tuple later on.
	 */
	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
	classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
								0, 0, 0);
	if (!HeapTupleIsValid(classTuple))
	{
		heap_close(relationRelation, NoLock);
		return false;
	}
	rtup->t_self = classTuple->t_self;
	ReleaseSysCache(classTuple);

1351
	while (1)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1352
	{
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
		ItemPointerData	tidsave;

		ItemPointerCopy(&(rtup->t_self), &tidsave);
		test = heap_mark4update(relationRelation, rtup, buffer);
		switch (test)
		{
			case HeapTupleSelfUpdated:
			case HeapTupleMayBeUpdated:
				break;
			case HeapTupleUpdated:
				ReleaseBuffer(*buffer);
				if (!ItemPointerEquals(&(rtup->t_self), &tidsave))
					continue;
			default:
				elog(ERROR, "LockClassinfoForUpdate couldn't lock relid %u", relid);
				return false;
		}
		break;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1371 1372 1373 1374
	}
	RelationInvalidateHeapTuple(relationRelation, rtup);
	if (confirmCommitted)
	{
1375 1376
		HeapTupleHeader th = rtup->t_data;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
		if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
			elog(ERROR, "The tuple isn't committed");
		if (th->t_infomask & HEAP_XMAX_COMMITTED)
			if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
				elog(ERROR, "The tuple is already deleted");
	}
	heap_close(relationRelation, NoLock);
	return true;
}

/* ---------------------------------------------
 *		Indexes of the relation active ?
 * ---------------------------------------------
 */
1391 1392
bool
IndexesAreActive(Oid relid, bool confirmCommitted)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1393
{
1394
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1395 1396
	Relation	indexRelation;
	Buffer		buffer;
1397 1398
	HeapScanDesc scan;
	ScanKeyData entry;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1399 1400 1401 1402
	bool		isactive;

	if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
		elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1403
	if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1404
		((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1405
		elog(ERROR, "relation %u isn't an indexable relation", relid);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1406 1407 1408 1409 1410 1411
	isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
	ReleaseBuffer(buffer);
	if (isactive)
		return isactive;
	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1412
						   F_OIDEQ, ObjectIdGetDatum(relid));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1413
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
1414
						  1, &entry);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1415 1416 1417
	if (!heap_getnext(scan, 0))
		isactive = true;
	heap_endscan(scan);
1418
	heap_close(indexRelation, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1419 1420 1421 1422
	return isactive;
}

/* ----------------
1423 1424 1425 1426 1427 1428 1429 1430
 *		set relhasindex of relation's pg_class entry
 *
 * NOTE: an important side-effect of this operation is that an SI invalidation
 * message is sent out to all backends --- including me --- causing relcache
 * entries to be flushed or updated with the new hasindex data.
 * Therefore, we execute the update even if relhasindex has the right value
 * already.  Possible future improvement: skip the disk update and just send
 * an SI message in that case.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1431 1432 1433
 * ----------------
 */
void
1434
setRelhasindex(Oid relid, bool hasindex)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1435 1436 1437
{
	Relation	pg_class;
	HeapTuple	tuple;
1438
	HeapScanDesc pg_class_scan = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1439

1440 1441
	/*
	 * Find the tuple to update in pg_class.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1442 1443 1444
	 */
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1445
#ifdef	OLD_FILE_NAMING
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1446
	if (!IsIgnoringSystemIndexes())
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1447 1448 1449
#else
	if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
#endif /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1450
	{
1451 1452 1453
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
	}
	else
	{
		ScanKeyData key[1];

		ScanKeyEntryInitialize(&key[0], 0,
							   ObjectIdAttributeNumber,
							   F_OIDEQ,
							   ObjectIdGetDatum(relid));

		pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
		tuple = heap_getnext(pg_class_scan, 0);
	}

	if (!HeapTupleIsValid(tuple))
	{
		if (pg_class_scan)
			heap_endscan(pg_class_scan);
		heap_close(pg_class, RowExclusiveLock);
1473 1474
		elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
			 relid);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1475 1476 1477 1478 1479 1480
	}

	/* ----------------
	 *	Update hasindex in pg_class.
	 * ----------------
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1481 1482
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1483
	((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1484 1485
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1486

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1487 1488
	if (pg_class_scan)
	{
1489
		/* Write the modified tuple in-place */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1490
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1491 1492 1493
		/* Send out shared cache inval if necessary */
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1494
		BufferSync();
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1495 1496 1497
	}
	else
	{
1498
		heap_update(pg_class, &tuple->t_self, tuple, NULL);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1499

1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
		/* Keep the catalog indices up to date */
		if (!IsIgnoringSystemIndexes())
		{
			Relation	idescs[Num_pg_class_indices];

			CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
							   idescs);
			CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
			CatalogCloseIndices(Num_pg_class_indices, idescs);
		}
	}
1511

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1512 1513 1514 1515 1516
	if (!pg_class_scan)
		heap_freetuple(tuple);
	else
		heap_endscan(pg_class_scan);

1517
	heap_close(pg_class, RowExclusiveLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1518 1519
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1520 1521 1522 1523 1524 1525 1526 1527
#ifndef OLD_FILE_NAMING
void
setNewRelfilenode(Relation relation)
{
	Relation	pg_class, idescs[Num_pg_class_indices];
	Oid		newrelfilenode;
	bool		in_place_update = false;
	HeapTupleData 	lockTupleData;
Tom Lane's avatar
Tom Lane committed
1528
	HeapTuple 	classTuple = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
	Buffer		buffer;
	RelationData	workrel;
	
	Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);

	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
	 /* Fetch and lock the classTuple associated with this relation */
	if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
		elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
	if (IsIgnoringSystemIndexes())
		in_place_update = true;
	/* Allocate a new relfilenode */
	newrelfilenode = newoid();
	/* update pg_class tuple with new relfilenode */
	if (!in_place_update)
	{
		classTuple = heap_copytuple(&lockTupleData);
		ReleaseBuffer(buffer);
		((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
		heap_update(pg_class, &classTuple->t_self, classTuple, NULL);
	}
	/* unlink old relfilenode */
	DropRelationBuffers(relation);
	smgrunlink(DEFAULT_SMGR, relation);
	/* cleanup pg_internal.init if necessary */
	if (relation->rd_isnailed)
		unlink(RELCACHE_INIT_FILENAME);
	/* create another storage file. Is it a little ugly ? */
	memcpy((char *) &workrel, relation, sizeof(RelationData));
	workrel.rd_node.relNode = newrelfilenode;
	heap_storage_create(&workrel);
	/* update pg_class tuple with new relfilenode in place */
	if (in_place_update)
	{
		classTuple = &lockTupleData;
		/* Send out shared cache inval if necessary */
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, classTuple);
		/* Update the buffer in-place */
		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
		((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
		WriteBuffer(buffer);
		BufferSync();
	}
	/* Keep the catalog indices up to date */
	if (!in_place_update && pg_class->rd_rel->relhasindex)
	{
		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
							   idescs);
		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
		CatalogCloseIndices(Num_pg_class_indices, idescs);
		heap_freetuple(classTuple);
	}
	heap_close(pg_class, NoLock);
	/* Make sure the relfilenode change */
	CommandCounterIncrement();
}
#endif /* OLD_FILE_NAMING */

1589
/* ----------------
1590
 *		UpdateStats
1591 1592 1593
 * ----------------
 */
void
1594
UpdateStats(Oid relid, long reltuples)
1595
{
1596 1597
	Relation	whichRel;
	Relation	pg_class;
1598
	HeapTuple	tuple;
1599 1600 1601 1602 1603 1604 1605 1606
	HeapTuple	newtup;
	long		relpages;
	int			i;
	Form_pg_class rd_rel;
	Relation	idescs[Num_pg_class_indices];
	Datum		values[Natts_pg_class];
	char		nulls[Natts_pg_class];
	char		replace[Natts_pg_class];
1607
	HeapScanDesc pg_class_scan = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1608
	bool		in_place_upd;
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627

	/* ----------------
	 * This routine handles updates for both the heap and index relation
	 * statistics.	In order to guarantee that we're able to *see* the index
	 * relation tuple, we bump the command counter id here.  The index
	 * relation tuple was created in the current transaction.
	 * ----------------
	 */
	CommandCounterIncrement();

	/* ----------------
	 * CommandCounterIncrement() flushes invalid cache entries, including
	 * those for the heap and index relations for which we're updating
	 * statistics.	Now that the cache is flushed, it's safe to open the
	 * relation again.	We need the relation open in order to figure out
	 * how many blocks it contains.
	 * ----------------
	 */

1628 1629 1630
	/*
	 * Can't use heap_open here since we don't know if it's an index...
	 */
1631 1632 1633
	whichRel = RelationIdGetRelation(relid);

	if (!RelationIsValid(whichRel))
1634
		elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
1635

1636
	/* Grab lock to be held till end of xact (probably redundant...) */
1637 1638
	LockRelation(whichRel, ShareLock);

1639 1640 1641 1642
	/* ----------------
	 * Find the RELATION relation tuple for the given relation.
	 * ----------------
	 */
1643
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1644

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1645
#ifdef	OLD_FILE_NAMING
1646
	in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1647
#else
1648
	in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1649
#endif /* OLD_FILE_NAMING */
1650

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1651
	if (!in_place_upd)
Bruce Momjian's avatar
Bruce Momjian committed
1652
	{
1653 1654 1655
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
Bruce Momjian's avatar
Bruce Momjian committed
1656 1657 1658 1659 1660 1661
	}
	else
	{
		ScanKeyData key[1];

		ScanKeyEntryInitialize(&key[0], 0,
1662 1663 1664
							   ObjectIdAttributeNumber,
							   F_OIDEQ,
							   ObjectIdGetDatum(relid));
Bruce Momjian's avatar
Bruce Momjian committed
1665 1666 1667 1668

		pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
		tuple = heap_getnext(pg_class_scan, 0);
	}
1669

1670
	if (!HeapTupleIsValid(tuple))
1671
	{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1672
		if (pg_class_scan)
Bruce Momjian's avatar
Bruce Momjian committed
1673
			heap_endscan(pg_class_scan);
1674
		heap_close(pg_class, RowExclusiveLock);
1675 1676
		elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
			 relid);
1677 1678 1679
	}

	/* ----------------
1680 1681 1682 1683 1684 1685 1686
	 * Figure values to insert.
	 *
	 * If we found zero tuples in the scan, do NOT believe it; instead put
	 * a bogus estimate into the statistics fields.  Otherwise, the common
	 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
	 * with zero size statistics until a VACUUM is done.  The optimizer will
	 * generate very bad plans if the stats claim the table is empty when
1687
	 * it is actually sizable.	See also CREATE TABLE in heap.c.
1688 1689 1690 1691
	 * ----------------
	 */
	relpages = RelationGetNumberOfBlocks(whichRel);

1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
	if (reltuples == 0)
	{
		if (relpages == 0)
		{
			/* Bogus defaults for a virgin table, same as heap.c */
			reltuples = 1000;
			relpages = 10;
		}
		else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
		{
			/* Empty index, leave bogus defaults in place */
			reltuples = 1000;
		}
		else
			reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
	}

1709 1710 1711 1712 1713 1714 1715 1716
	/*
	 * We shouldn't have to do this, but we do...  Modify the reldesc in
	 * place with the new values so that the cache contains the latest
	 * copy.
	 */
	whichRel->rd_rel->relpages = relpages;
	whichRel->rd_rel->reltuples = reltuples;

1717 1718 1719
	/* ----------------
	 *	Update statistics in pg_class.
	 * ----------------
1720
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1721
	if (in_place_upd)
1722 1723 1724
	{
		/*
		 * At bootstrap time, we don't need to worry about concurrency or
1725
		 * visibility of changes, so we cheat.  Also cheat if REINDEX.
1726
		 */
1727
		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1728
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1729 1730
		rd_rel->relpages = relpages;
		rd_rel->reltuples = reltuples;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1731
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1732
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1733 1734
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
1735 1736 1737
	}
	else
	{
1738 1739 1740 1741 1742 1743 1744 1745 1746
		/* During normal processing, must work harder. */

		for (i = 0; i < Natts_pg_class; i++)
		{
			nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
			replace[i] = ' ';
			values[i] = (Datum) NULL;
		}

1747 1748 1749 1750
		replace[Anum_pg_class_relpages - 1] = 'r';
		values[Anum_pg_class_relpages - 1] = (Datum) relpages;
		replace[Anum_pg_class_reltuples - 1] = 'r';
		values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
1751
		newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1752
		heap_update(pg_class, &tuple->t_self, newtup, NULL);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1753 1754 1755 1756 1757 1758
		if (!IsIgnoringSystemIndexes())
		{
			CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
			CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
			CatalogCloseIndices(Num_pg_class_indices, idescs);
		}
1759
		heap_freetuple(newtup);
1760 1761
	}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1762
	if (!pg_class_scan)
1763
		heap_freetuple(tuple);
Bruce Momjian's avatar
Bruce Momjian committed
1764 1765
	else
		heap_endscan(pg_class_scan);
1766

1767 1768
	heap_close(pg_class, RowExclusiveLock);
	/* Cheating a little bit since we didn't open it with heap_open... */
1769
	heap_close(whichRel, NoLock);
1770 1771 1772 1773
}


/* ----------------
1774
 *		DefaultBuild
1775 1776 1777 1778 1779
 *
 * NB: this routine is dead code, and likely always has been, because
 * there are no access methods that don't supply their own ambuild procedure.
 *
 * Anyone want to wager whether it would actually work if executed?
1780 1781 1782 1783
 * ----------------
 */
static void
DefaultBuild(Relation heapRelation,
1784
			 Relation indexRelation,
1785 1786
			 IndexInfo *indexInfo,
			 Node *oldPred,
1787
			 IndexStrategy indexStrategy) /* not used */
1788
{
1789 1790 1791
	HeapScanDesc scan;
	HeapTuple	heapTuple;
	TupleDesc	heapDescriptor;
1792 1793
	Datum		datum[INDEX_MAX_KEYS];
	char		nullv[INDEX_MAX_KEYS];
1794 1795
	long		reltuples,
				indtuples;
1796
	Node	   *predicate = indexInfo->ii_Predicate;
1797
#ifndef OMIT_PARTIAL_INDEX
1798
	TupleTable	tupleTable;
1799
	TupleTableSlot *slot;
1800
#endif
1801
	ExprContext *econtext;
1802 1803 1804 1805 1806 1807 1808 1809
	InsertIndexResult insertResult;

	/* ----------------
	 *	more & better checking is needed
	 * ----------------
	 */
	Assert(OidIsValid(indexRelation->rd_rel->relam));	/* XXX */

1810
	heapDescriptor = RelationGetDescr(heapRelation);
1811 1812 1813 1814 1815 1816

	/*
	 * If this is a predicate (partial) index, we will need to evaluate
	 * the predicate using ExecQual, which requires the current tuple to
	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
	 * ExprContext referring to that slot.	Here, we initialize dummy
1817 1818 1819 1820
	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
	 *
	 * We construct the ExprContext anyway since we need a per-tuple
	 * temporary memory context for function evaluation -- tgl July 00
1821
	 */
1822
#ifndef OMIT_PARTIAL_INDEX
1823 1824 1825 1826
	if (predicate != NULL || oldPred != NULL)
	{
		tupleTable = ExecCreateTupleTable(1);
		slot = ExecAllocTableSlot(tupleTable);
1827
		ExecSetSlotDescriptor(slot, heapDescriptor);
1828
	}
Marc G. Fournier's avatar
Marc G. Fournier committed
1829 1830
	else
	{
1831
		tupleTable = NULL;
Marc G. Fournier's avatar
Marc G. Fournier committed
1832 1833
		slot = NULL;
	}
1834 1835 1836
	econtext = MakeExprContext(slot, TransactionCommandContext);
#else
	econtext = MakeExprContext(NULL, TransactionCommandContext);
1837
#endif	 /* OMIT_PARTIAL_INDEX */
1838 1839 1840 1841

	/* ----------------
	 *	Ok, begin our scan of the base relation.
	 * ----------------
1842
	 */
1843 1844
	scan = heap_beginscan(heapRelation, /* relation */
						  0,	/* start at end */
1845
						  SnapshotNow,	/* seeself */
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857
						  0,	/* number of keys */
						  (ScanKey) NULL);		/* scan key */

	reltuples = indtuples = 0;

	/* ----------------
	 *	for each tuple in the base relation, we create an index
	 *	tuple and add it to the index relation.  We keep a running
	 *	count of the number of tuples so that we can update pg_class
	 *	with correct statistics when we're done building the index.
	 * ----------------
	 */
1858
	while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1859
	{
1860 1861
		MemoryContextReset(econtext->ecxt_per_tuple_memory);

1862 1863
		reltuples++;

1864
#ifndef OMIT_PARTIAL_INDEX
1865 1866 1867 1868 1869 1870 1871
		/*
		 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
		 * this tuple if it was already in the existing partial index
		 */
		if (oldPred != NULL)
		{
			slot->val = heapTuple;
1872
			if (ExecQual((List *) oldPred, econtext, false))
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
			{
				indtuples++;
				continue;
			}
		}

		/*
		 * Skip this tuple if it doesn't satisfy the partial-index
		 * predicate
		 */
		if (predicate != NULL)
		{
			slot->val = heapTuple;
1886
			if (!ExecQual((List *) predicate, econtext, false))
1887 1888
				continue;
		}
1889
#endif	 /* OMIT_PARTIAL_INDEX */
1890

1891
		indtuples++;
1892 1893 1894 1895 1896 1897

		/* ----------------
		 *	FormIndexDatum fills in its datum and null parameters
		 *	with attribute information taken from the given heap tuple.
		 * ----------------
		 */
1898 1899 1900 1901 1902 1903
		FormIndexDatum(indexInfo,
					   heapTuple,
					   heapDescriptor,
					   econtext->ecxt_per_tuple_memory,
					   datum,
					   nullv);
1904 1905

		insertResult = index_insert(indexRelation, datum, nullv,
1906
									&(heapTuple->t_self), heapRelation);
1907 1908 1909

		if (insertResult)
			pfree(insertResult);
1910
	}
1911 1912 1913

	heap_endscan(scan);

1914
#ifndef OMIT_PARTIAL_INDEX
1915 1916
	if (predicate != NULL || oldPred != NULL)
	{
1917
		ExecDropTupleTable(tupleTable, true);
1918
	}
1919
#endif	 /* OMIT_PARTIAL_INDEX */
1920
	FreeExprContext(econtext);
1921 1922

	/*
1923 1924
	 * Since we just counted the tuples in the heap, we update its stats
	 * in pg_class to guarantee that the planner takes advantage of the
1925 1926 1927 1928 1929 1930 1931
	 * index we just created.  But, only update statistics during normal
	 * index definitions, not for indices on system catalogs created
	 * during bootstrap processing.  We must close the relations before
	 * updating statistics to guarantee that the relcache entries are
	 * flushed when we increment the command counter in UpdateStats(). But
	 * we do not release any locks on the relations; those will be held
	 * until end of transaction.
1932 1933
	 */
	if (IsNormalProcessingMode())
1934
	{
1935 1936
		Oid			hrelid = RelationGetRelid(heapRelation);
		Oid			irelid = RelationGetRelid(indexRelation);
1937 1938 1939

		heap_close(heapRelation, NoLock);
		index_close(indexRelation);
1940 1941
		UpdateStats(hrelid, reltuples);
		UpdateStats(irelid, indtuples);
1942 1943 1944 1945
		if (oldPred != NULL)
		{
			if (indtuples == reltuples)
				predicate = NULL;
1946
			UpdateIndexPredicate(irelid, oldPred, predicate);
1947
		}
1948
	}
1949 1950 1951
}

/* ----------------
1952
 *		index_build
1953 1954 1955 1956
 * ----------------
 */
void
index_build(Relation heapRelation,
1957
			Relation indexRelation,
1958 1959
			IndexInfo *indexInfo,
			Node *oldPred)
1960
{
1961
	RegProcedure procedure;
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972

	/* ----------------
	 *	sanity checks
	 * ----------------
	 */
	Assert(RelationIsValid(indexRelation));
	Assert(PointerIsValid(indexRelation->rd_am));

	procedure = indexRelation->rd_am->ambuild;

	/* ----------------
1973
	 *	use the access method build procedure if supplied, else default.
1974 1975 1976
	 * ----------------
	 */
	if (RegProcedureIsValid(procedure))
1977
		OidFunctionCall5(procedure,
1978 1979
						 PointerGetDatum(heapRelation),
						 PointerGetDatum(indexRelation),
1980 1981
						 PointerGetDatum(indexInfo),
						 PointerGetDatum(oldPred),
1982
						 PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
1983 1984 1985
	else
		DefaultBuild(heapRelation,
					 indexRelation,
1986 1987
					 indexInfo,
					 oldPred,
1988
					 RelationGetIndexStrategy(indexRelation));
1989 1990
}

1991 1992
/*
 * IndexGetRelation: given an index's relation OID, get the OID of the
1993
 * relation it is an index on.	Uses the system cache.
1994 1995 1996 1997 1998 1999
 */
static Oid
IndexGetRelation(Oid indexId)
{
	HeapTuple	tuple;
	Form_pg_index index;
2000
	Oid			result;
2001

2002 2003 2004
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexId),
						   0, 0, 0);
2005 2006 2007 2008 2009 2010
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "IndexGetRelation: can't find index id %u",
			 indexId);
	index = (Form_pg_index) GETSTRUCT(tuple);
	Assert(index->indexrelid == indexId);

2011 2012 2013
	result = index->indrelid;
	ReleaseSysCache(tuple);
	return result;
2014 2015
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2016 2017
/* ---------------------------------
 * activate_index -- activate/deactivate the specified index.
2018
 *		Note that currently PostgreSQL doesn't hold the
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2019 2020 2021
 *		status per index
 * ---------------------------------
 */
2022
static bool
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2023
activate_index(Oid indexId, bool activate, bool inplace)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2024
{
2025
	if (!activate)				/* Currently does nothing */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2026
		return true;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2027
	return reindex_index(indexId, false, inplace);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2028
}
2029

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2030 2031 2032 2033 2034
/* --------------------------------
 * reindex_index - This routine is used to recreate an index
 * --------------------------------
 */
bool
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2035
reindex_index(Oid indexId, bool force, bool inplace)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2036
{
2037 2038 2039 2040 2041 2042 2043
	Relation	iRel,
				indexRelation,
				heapRelation;
	ScanKeyData entry;
	HeapScanDesc scan;
	HeapTuple	indexTuple,
				classTuple;
2044
	IndexInfo  *indexInfo;
2045 2046
	Oid			heapId,
				accessMethodId;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2047 2048
	bool		old;

2049 2050 2051 2052 2053 2054 2055 2056 2057
	/* ----------------
	 *	REINDEX within a transaction block is dangerous, because
	 *	if the transaction is later rolled back we have no way to
	 *	undo truncation of the index's physical file.  Disallow it.
	 * ----------------
	 */
	if (IsTransactionBlock())
		elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2058
	old = SetReindexProcessing(true);
2059 2060

	/* Scan pg_index to find the index's pg_index entry */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2061 2062 2063 2064 2065 2066
	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
						   ObjectIdGetDatum(indexId));
	scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
	indexTuple = heap_getnext(scan, 0);
	if (!HeapTupleIsValid(indexTuple))
2067
		elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2068

2069 2070 2071 2072
	/* Get OID of index's parent table */
	heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
	/* Fetch info needed for index_build */
	indexInfo = BuildIndexInfo(indexTuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2073

2074 2075 2076
	/* Complete the scan and close pg_index */
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2077 2078

	/* Fetch the classTuple associated with this index */
2079 2080 2081
	classTuple = SearchSysCache(RELOID,
								ObjectIdGetDatum(indexId),
								0, 0, 0);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2082
	if (!HeapTupleIsValid(classTuple))
2083
		elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2084
	accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
2085
	ReleaseSysCache(classTuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2086 2087 2088 2089 2090

	/* Open our index relation */
	heapRelation = heap_open(heapId, ExclusiveLock);
	if (heapRelation == NULL)
		elog(ERROR, "reindex_index: can't open heap relation");
2091 2092 2093
	iRel = index_open(indexId);
	if (iRel == NULL)
		elog(ERROR, "reindex_index: can't open index relation");
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2094

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2095 2096 2097 2098
#ifndef OLD_FILE_NAMING
	if (!inplace)
		setNewRelfilenode(iRel);
#endif /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2099 2100 2101
	/* Obtain exclusive lock on it, just to be sure */
	LockRelation(iRel, AccessExclusiveLock);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113
	if (inplace)
	{
		/*
	 	 * Release any buffers associated with this index.	If they're dirty,
	 	 * they're just dropped without bothering to flush to disk.
	 	 */
		DropRelationBuffers(iRel);

		/* Now truncate the actual data and set blocks to zero */
		smgrtruncate(DEFAULT_SMGR, iRel, 0);
		iRel->rd_nblocks = 0;
	}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2114 2115

	/* Initialize the index and rebuild */
2116 2117
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
	index_build(heapRelation, iRel, indexInfo, NULL);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2118 2119

	/*
2120
	 * index_build will close both the heap and index relations (but not
2121
	 * give up the locks we hold on them).  So we're done.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2122 2123 2124
	 */

	SetReindexProcessing(old);
2125

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2126 2127 2128 2129 2130
	return true;
}

/*
 * ----------------------------
2131
 * activate_indexes_of_a_table
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2132 2133 2134 2135 2136 2137 2138 2139 2140
 *	activate/deactivate indexes of the specified table.
 * ----------------------------
 */
bool
activate_indexes_of_a_table(Oid relid, bool activate)
{
	if (IndexesAreActive(relid, true))
	{
		if (!activate)
2141
			setRelhasindex(relid, false);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
		else
			return false;
	}
	else
	{
		if (activate)
			reindex_relation(relid, false);
		else
			return false;
	}
	return true;
}
2154

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2155 2156 2157 2158 2159 2160 2161 2162 2163
/* --------------------------------
 * reindex_relation - This routine is used to recreate indexes
 * of a relation.
 * --------------------------------
 */
bool
reindex_relation(Oid relid, bool force)
{
	Relation	indexRelation;
2164 2165
	ScanKeyData entry;
	HeapScanDesc scan;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2166
	HeapTuple	indexTuple;
2167 2168
	bool		old,
				reindexed;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2169

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
	bool	deactivate_needed, overwrite, upd_pg_class_inplace;
#ifdef OLD_FILE_NAMING
	overwrite = upd_pg_class_inplace = deactivate_needed = true;	
#else
	Relation rel;
	overwrite = upd_pg_class_inplace = deactivate_needed = false;	
	/*
 	 * avoid heap_update() pg_class tuples while processing
 	 * reindex for pg_class. 
 	 */
	if (IsIgnoringSystemIndexes())
		upd_pg_class_inplace = true;
	/*
	 * ignore the indexes of the target system relation while processing
	 * reindex.
	 */ 
	rel = RelationIdGetRelation(relid);
	if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
		deactivate_needed = true;
#ifndef	ENABLE_REINDEX_NAILED_RELATIONS
	/* 
 	 * nailed relations are never updated.
 	 * We couldn't keep the consistency between the relation
 	 * descriptors and pg_class tuples.
 	 */
	if (rel->rd_isnailed)
	{
		if (IsIgnoringSystemIndexes())
		{
			overwrite = true;
			deactivate_needed = true;
		}
		else
			elog(ERROR, "the target relation %u is nailed", relid);
	}
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
	RelationClose(rel);
#endif /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2208
	old = SetReindexProcessing(true);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2209
	if (deactivate_needed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2210
	{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2211
		if (IndexesAreActive(relid, upd_pg_class_inplace))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2212
		{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2213 2214 2215 2216 2217 2218 2219
			if (!force)
			{
				SetReindexProcessing(old);
				return false;
			}
			activate_indexes_of_a_table(relid, false);
			CommandCounterIncrement();
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2220 2221 2222 2223 2224
		}
	}

	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2225
						   F_OIDEQ, ObjectIdGetDatum(relid));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2226
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
2227
						  1, &entry);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2228 2229 2230
	reindexed = false;
	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
	{
2231 2232
		Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2233
		if (activate_index(index->indexrelid, true, overwrite))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
			reindexed = true;
		else
		{
			reindexed = false;
			break;
		}
	}
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
	if (reindexed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266
	/*
	 * Ok,we could use the reindexed indexes of the target
	 * system relation now.
	 */
	{ 
		if (deactivate_needed)
		{
			if (!overwrite && relid == RelOid_pg_class)
			{
				/* 
				 * For pg_class, relhasindex should be set
				 * to true here in place.
				 */
				setRelhasindex(relid, true);
				CommandCounterIncrement();
				/* 
				 * However the following setRelhasindex()
				 * is needed to keep consistency with WAL.
				 */
			}
			setRelhasindex(relid, true);
		}
	}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2267
	SetReindexProcessing(old);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2268

2269
	return reindexed;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2270
}