index.c 58.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * index.c
4
 *	  code to create and destroy POSTGRES index relations
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/catalog/index.c,v 1.147 2001/05/14 21:53:16 momjian 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
#define AVG_ATTR_SIZE 8
#define NTUPLES_PER_PAGE(natts) \
58
	((BLCKSZ - MAXALIGN(sizeof(PageHeaderData))) / \
Bruce Momjian's avatar
Bruce Momjian committed
59
	((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(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
 *		GetHeapRelationOid
103 104
 * ----------------------------------------------------------------
 */
105
static Oid
106
GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
107
{
108 109
	Oid			indoid;
	Oid			heapoid;
110

Bruce Momjian's avatar
Bruce Momjian committed
111

112
	indoid = RelnameFindRelid(indexRelationName);
113

114
	if ((!istemp && OidIsValid(indoid)) ||
115
		(istemp && is_temp_rel_name(indexRelationName)))
Bruce Momjian's avatar
Bruce Momjian committed
116
		elog(ERROR, "Cannot create index: '%s' already exists",
117 118
			 indexRelationName);

119
	heapoid = RelnameFindRelid(heapRelationName);
120 121

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

125
	return heapoid;
126 127
}

128
static TupleDesc
129
BuildFuncTupleDesc(Oid funcOid)
130
{
131
	TupleDesc	funcTupDesc;
132
	HeapTuple	tuple;
133
	Oid			retType;
134 135

	/*
136
	 * Allocate and zero a tuple descriptor for a one-column tuple.
137 138
	 */
	funcTupDesc = CreateTemplateTupleDesc(1);
139
	funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
Bruce Momjian's avatar
Bruce Momjian committed
140
	MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
141 142

	/*
143
	 * Lookup the function to get its name and return type.
144
	 */
145 146 147
	tuple = SearchSysCache(PROCOID,
						   ObjectIdGetDatum(funcOid),
						   0, 0, 0);
148
	if (!HeapTupleIsValid(tuple))
149
		elog(ERROR, "Function %u does not exist", funcOid);
150 151 152
	retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;

	/*
153 154 155 156 157
	 * make the attributes name the same as the functions
	 */
	namestrcpy(&funcTupDesc->attrs[0]->attname,
			   NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));

158 159
	ReleaseSysCache(tuple);

160 161
	/*
	 * Lookup the return type in pg_type for the type length etc.
162
	 */
163 164 165
	tuple = SearchSysCache(TYPEOID,
						   ObjectIdGetDatum(retType),
						   0, 0, 0);
166
	if (!HeapTupleIsValid(tuple))
167
		elog(ERROR, "Type %u does not exist", retType);
168 169 170 171

	/*
	 * Assign some of the attributes values. Leave the rest as 0.
	 */
172
	funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
173 174
	funcTupDesc->attrs[0]->atttypid = retType;
	funcTupDesc->attrs[0]->attnum = 1;
175
	funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
Bruce Momjian's avatar
Bruce Momjian committed
176 177
	funcTupDesc->attrs[0]->attcacheoff = -1;
	funcTupDesc->attrs[0]->atttypmod = -1;
178
	funcTupDesc->attrs[0]->attstorage = ((Form_pg_type) GETSTRUCT(tuple))->typstorage;
179
	funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
180

181 182
	ReleaseSysCache(tuple);

183
	return funcTupDesc;
184 185 186
}

/* ----------------------------------------------------------------
187
 *		ConstructTupleDescriptor
188 189
 *
 * Build an index tuple descriptor for a new index (plain not functional)
190 191
 * ----------------------------------------------------------------
 */
192
static TupleDesc
193
ConstructTupleDescriptor(Relation heapRelation,
194
						 int numatts,
195
						 AttrNumber *attNums)
196
{
197 198
	TupleDesc	heapTupDesc;
	TupleDesc	indexTupDesc;
199
	int			natts;			/* #atts in heap rel --- for error checks */
200
	int			i;
201

202 203 204
	heapTupDesc = RelationGetDescr(heapRelation);
	natts = RelationGetForm(heapRelation)->relnatts;

205 206
	/*
	 * allocate the new tuple descriptor
207 208 209 210 211 212 213 214 215 216
	 */

	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
	 * ----------------
	 */
217
	for (i = 0; i < numatts; i++)
218
	{
219
		AttrNumber	atnum;		/* attributeNumber[attributeOffset] */
220 221
		Form_pg_attribute from;
		Form_pg_attribute to;
222

223 224 225
		/*
		 * get the attribute number and make sure it's valid; determine
		 * which attribute descriptor to copy
226 227 228 229 230
		 */
		atnum = attNums[i];

		if (!AttrNumberIsForUserDefinedAttr(atnum))
		{
231 232

			/*
233
			 * here we are indexing on a system attribute (-1...-n)
234
			 */
235
			from = SystemAttributeDefinition(atnum);
236 237 238
		}
		else
		{
239 240 241

			/*
			 * here we are indexing on a normal attribute (1...n)
242
			 */
243 244 245
			if (atnum > natts)
				elog(ERROR, "Cannot create index: attribute %d does not exist",
					 atnum);
246

247
			from = heapTupDesc->attrs[AttrNumberGetAttrOffset(atnum)];
248 249
		}

250 251 252
		/*
		 * now that we've determined the "from", let's copy the tuple desc
		 * data...
253
		 */
254 255
		indexTupDesc->attrs[i] = to =
			(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
256 257
		memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);

258
		/*
259 260
		 * Fix the stuff that should not be the same as the underlying
		 * attr
261
		 */
262
		to->attnum = i + 1;
263

264 265
		to->attstattarget = 0;
		to->attcacheoff = -1;
266 267
		to->attnotnull = false;
		to->atthasdef = false;
268

269
		/*
270 271 272
		 * We do not yet have the correct relation OID for the index, so
		 * just set it invalid for now.  InitializeAttributeOids() will
		 * fix it later.
273
		 */
274
		to->attrelid = InvalidOid;
275 276 277 278 279 280
	}

	return indexTupDesc;
}

/* ----------------------------------------------------------------
Bruce Momjian's avatar
Bruce Momjian committed
281
 * AccessMethodObjectIdGetForm
282 283
 *		Returns an access method tuple given its object identifier,
 *		or NULL if no such AM tuple can be found.
284
 *
285 286 287
 * Scanning is done using CurrentMemoryContext as working storage,
 * but the returned tuple will be allocated in resultCxt (which is
 * typically CacheMemoryContext).
288
 *
289
 * There was a note here about adding indexing, but I don't see a need
290
 * for it.	There are so few tuples in pg_am that an indexscan would
291
 * surely be slower.
292 293 294
 * ----------------------------------------------------------------
 */
Form_pg_am
295 296
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
							MemoryContext resultCxt)
297
{
298 299 300 301
	Relation	pg_am_desc;
	HeapScanDesc pg_am_scan;
	HeapTuple	pg_am_tuple;
	ScanKeyData key;
302
	Form_pg_am	aform;
303

304 305
	/*
	 * form a scan key for the pg_am relation
306 307
	 */
	ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
Bruce Momjian's avatar
Bruce Momjian committed
308
						   F_OIDEQ,
309 310
						   ObjectIdGetDatum(accessMethodObjectId));

311 312
	/*
	 * fetch the desired access method tuple
313
	 */
314
	pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
315
	pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
316

317
	pg_am_tuple = heap_getnext(pg_am_scan, 0);
318

319 320
	/*
	 * return NULL if not found
321 322 323 324
	 */
	if (!HeapTupleIsValid(pg_am_tuple))
	{
		heap_endscan(pg_am_scan);
325
		heap_close(pg_am_desc, AccessShareLock);
326
		return NULL;
327 328
	}

329 330
	/*
	 * if found AM tuple, then copy it into resultCxt and return the copy
331
	 */
332
	aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
333
	memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
334 335

	heap_endscan(pg_am_scan);
336
	heap_close(pg_am_desc, AccessShareLock);
337

338
	return aform;
339 340 341 342 343 344 345 346 347
}

/* ----------------------------------------------------------------
 *		ConstructIndexReldesc
 * ----------------------------------------------------------------
 */
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
348
	indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
349
													 CacheMemoryContext);
350

351 352
	/*
	 * XXX missing the initialization of some other fields
353 354 355 356 357 358 359 360 361 362 363 364 365
	 */

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

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

/* ----------------------------------------------------------------
 *		UpdateRelationRelation
 * ----------------------------------------------------------------
 */
366
static Oid
367
UpdateRelationRelation(Relation indexRelation, char *temp_relname)
368
{
369 370 371 372
	Relation	pg_class;
	HeapTuple	tuple;
	Oid			tupleOid;
	Relation	idescs[Num_pg_class_indices];
373

374
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
375 376 377

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

381 382 383 384
	/*
	 * the new tuple must have the same oid as the relcache entry for the
	 * index.  sure would be embarrassing to do this sort of thing in
	 * polite company.
385
	 */
386
	tuple->t_data->t_oid = RelationGetRelid(indexRelation);
387 388
	heap_insert(pg_class, tuple);

389 390
	if (temp_relname)
		create_temp_relation(temp_relname, tuple);
Bruce Momjian's avatar
Bruce Momjian committed
391

392 393 394 395 396 397 398
	/*
	 * 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
399
	if (!IsIgnoringSystemIndexes())
400 401 402 403 404 405
	{
		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);
	}

406
	tupleOid = tuple->t_data->t_oid;
407
	heap_freetuple(tuple);
408
	heap_close(pg_class, RowExclusiveLock);
409

410
	return tupleOid;
411 412 413 414 415 416 417 418 419 420 421
}

/* ----------------------------------------------------------------
 *		InitializeAttributeOids
 * ----------------------------------------------------------------
 */
static void
InitializeAttributeOids(Relation indexRelation,
						int numatts,
						Oid indexoid)
{
422 423
	TupleDesc	tupleDescriptor;
	int			i;
424

425
	tupleDescriptor = RelationGetDescr(indexRelation);
426 427 428 429 430 431 432 433 434 435 436 437 438 439

	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)
{
440
	Relation	pg_attribute;
441 442 443
	HeapTuple	init_tuple,
				cur_tuple = NULL,
				new_tuple;
444 445 446 447 448 449 450
	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;
451

452 453
	/*
	 * open the attribute relation
454
	 */
455
	pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
456

457 458
	/*
	 * initialize *null, *replace and *value
459
	 */
Bruce Momjian's avatar
Bruce Momjian committed
460 461
	MemSet(nullv, ' ', Natts_pg_attribute);
	MemSet(replace, ' ', Natts_pg_attribute);
462

463
	/* ----------
464 465
	 *	create the first attribute tuple.
	 *	XXX For now, only change the ATTNUM attribute value
466
	 * ----------
467 468 469 470 471 472 473
	 */
	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);

474
	init_tuple = heap_addheader(Natts_pg_attribute,
Bruce Momjian's avatar
Bruce Momjian committed
475
								ATTRIBUTE_TUPLE_SIZE,
476
							 (char *) (indexRelation->rd_att->attrs[0]));
477 478

	hasind = false;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
479
	if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
480 481 482 483 484
	{
		hasind = true;
		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
	}

485 486
	/*
	 * insert the first attribute tuple.
487
	 */
488
	cur_tuple = heap_modifytuple(init_tuple,
489 490 491 492
								 pg_attribute,
								 value,
								 nullv,
								 replace);
493
	heap_freetuple(init_tuple);
494

495
	heap_insert(pg_attribute, cur_tuple);
496
	if (hasind)
497
		CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
498

499 500 501
	/*
	 * now we use the information in the index cur_tuple descriptor to
	 * form the remaining attribute tuples.
502
	 */
503
	indexTupDesc = RelationGetDescr(indexRelation);
504 505 506

	for (i = 1; i < numatts; i += 1)
	{
507 508 509

		/*
		 * process the remaining attributes...
510
		 */
511
		memmove(GETSTRUCT(cur_tuple),
512
				(char *) indexTupDesc->attrs[i],
Bruce Momjian's avatar
Bruce Momjian committed
513
				ATTRIBUTE_TUPLE_SIZE);
514 515 516

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

517
		new_tuple = heap_modifytuple(cur_tuple,
518 519 520 521
									 pg_attribute,
									 value,
									 nullv,
									 replace);
522
		heap_freetuple(cur_tuple);
523

524
		heap_insert(pg_attribute, new_tuple);
525
		if (hasind)
526
			CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
527

528 529 530
		/*
		 * ModifyHeapTuple returns a new copy of a cur_tuple so we free
		 * the original and use the copy..
531
		 */
532
		cur_tuple = new_tuple;
533 534
	}

535
	if (cur_tuple)
536
		heap_freetuple(cur_tuple);
537
	heap_close(pg_attribute, RowExclusiveLock);
538 539 540 541 542 543 544 545 546 547 548
	if (hasind)
		CatalogCloseIndices(Num_pg_attr_indices, idescs);
}

/* ----------------------------------------------------------------
 *		UpdateIndexRelation
 * ----------------------------------------------------------------
 */
static void
UpdateIndexRelation(Oid indexoid,
					Oid heapoid,
549
					IndexInfo *indexInfo,
550
					Oid *classOids,
551
					bool islossy,
Bruce Momjian's avatar
Bruce Momjian committed
552
					bool primary)
553
{
554
	Form_pg_index indexForm;
555 556 557 558 559 560 561
	char	   *predString;
	text	   *predText;
	int			predLen,
				itupLen;
	Relation	pg_index;
	HeapTuple	tuple;
	int			i;
562
	Relation	idescs[Num_pg_index_indices];
563

564 565 566
	/*
	 * allocate a Form_pg_index big enough to hold the index-predicate (if
	 * any) in string form
567
	 */
568
	if (indexInfo->ii_Predicate != NULL)
569
	{
570
		predString = nodeToString(indexInfo->ii_Predicate);
571
		predText = DatumGetTextP(DirectFunctionCall1(textin,
572
										   CStringGetDatum(predString)));
573 574 575
		pfree(predString);
	}
	else
576
		predText = DatumGetTextP(DirectFunctionCall1(textin,
577
												   CStringGetDatum("")));
578

579 580
	predLen = VARSIZE(predText);
	itupLen = predLen + sizeof(FormData_pg_index);
581
	indexForm = (Form_pg_index) palloc(itupLen);
582
	MemSet(indexForm, 0, sizeof(FormData_pg_index));
583

584 585
	/*
	 * store information into the index tuple form
586 587
	 */
	indexForm->indexrelid = indexoid;
588 589
	indexForm->indrelid = heapoid;
	indexForm->indproc = indexInfo->ii_FuncOid;
590
	indexForm->indislossy = islossy;
591
	indexForm->indisunique = indexInfo->ii_Unique;
592
	indexForm->indisprimary = primary;
593
	memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
594

595 596
	/*
	 * copy index key and op class information
597
	 *
598
	 * We zeroed the extra slots (if any) above --- that's essential.
599
	 */
600 601
	for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
		indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
602

603 604
	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
		indexForm->indclass[i] = classOids[i];
605

606 607
	/*
	 * open the system catalog index relation
608
	 */
609
	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
610

611 612
	/*
	 * form a tuple to insert into pg_index
613 614 615 616 617
	 */
	tuple = heap_addheader(Natts_pg_index,
						   itupLen,
						   (char *) indexForm);

618 619
	/*
	 * insert the tuple into the pg_index
620 621 622
	 */
	heap_insert(pg_index, tuple);

623 624
	/*
	 * add index tuples for it
625
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
626
	if (!IsIgnoringSystemIndexes())
627 628 629 630 631
	{
		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);
	}
632

633 634
	/*
	 * close the relation and free the tuple
635
	 */
636
	heap_close(pg_index, RowExclusiveLock);
637 638
	pfree(predText);
	pfree(indexForm);
639
	heap_freetuple(tuple);
640 641 642 643 644 645 646
}

/* ----------------------------------------------------------------
 *		UpdateIndexPredicate
 * ----------------------------------------------------------------
 */
void
647
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
648
{
649 650 651 652 653 654 655 656 657 658
	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];
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673

	/*
	 * 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)
	{
674
		newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
675 676 677 678 679 680 681 682 683
								  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);
684
		predText = DatumGetTextP(DirectFunctionCall1(textin,
685
										   CStringGetDatum(predString)));
686 687 688
		pfree(predString);
	}
	else
689
		predText = DatumGetTextP(DirectFunctionCall1(textin,
690
												   CStringGetDatum("")));
691 692

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

695 696 697 698 699 700
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexoid),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
			 indexoid);
701

702 703 704 705 706 707 708 709 710 711
	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;

712
	newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
713

714
	simple_heap_update(pg_index, &newtup->t_self, newtup);
715

716
	heap_freetuple(newtup);
717 718
	ReleaseSysCache(tuple);

719
	heap_close(pg_index, RowExclusiveLock);
720 721 722 723 724 725 726 727 728 729 730 731
	pfree(predText);
}

/* ----------------------------------------------------------------
 *		InitIndexStrategy
 * ----------------------------------------------------------------
 */
void
InitIndexStrategy(int numatts,
				  Relation indexRelation,
				  Oid accessMethodObjectId)
{
732 733 734 735 736 737
	IndexStrategy strategy;
	RegProcedure *support;
	uint16		amstrategies;
	uint16		amsupport;
	Oid			attrelid;
	Size		strsize;
738

739 740
	/*
	 * get information from the index relation descriptor
741 742 743 744 745
	 */
	attrelid = indexRelation->rd_att->attrs[0]->attrelid;
	amstrategies = indexRelation->rd_am->amstrategies;
	amsupport = indexRelation->rd_am->amsupport;

746 747
	/*
	 * get the size of the strategy
748 749 750
	 */
	strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);

751 752
	/*
	 * allocate the new index strategy structure
753
	 *
754 755 756
	 * 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.
757
	 */
758 759
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
760

761 762
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  strsize);
763 764 765 766

	if (amsupport > 0)
	{
		strsize = numatts * (amsupport * sizeof(RegProcedure));
767
		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
768 769 770 771 772
													  strsize);
	}
	else
		support = (RegProcedure *) NULL;

773 774 775 776
	/*
	 * fill in the index strategy structure with information from the
	 * catalogs.  First we must advance the command counter so that we
	 * will see the newly-entered index catalog tuples.
777
	 */
778
	CommandCounterIncrement();
779 780

	IndexSupportInitialize(strategy, support,
781
						   &indexRelation->rd_uniqueindex,
782 783 784
						   attrelid, accessMethodObjectId,
						   amstrategies, amsupport, numatts);

785 786
	/*
	 * store the strategy information in the index reldesc
787 788 789 790 791 792 793 794 795 796 797 798
	 */
	RelationSetIndexSupport(indexRelation, strategy, support);
}


/* ----------------------------------------------------------------
 *		index_create
 * ----------------------------------------------------------------
 */
void
index_create(char *heapRelationName,
			 char *indexRelationName,
799
			 IndexInfo *indexInfo,
800
			 Oid accessMethodObjectId,
801
			 Oid *classObjectId,
802
			 bool islossy,
803 804
			 bool primary,
			 bool allow_system_table_mods)
805
{
806 807 808 809 810
	Relation	heapRelation;
	Relation	indexRelation;
	TupleDesc	indexTupDesc;
	Oid			heapoid;
	Oid			indexoid;
811
	bool		istemp = is_temp_rel_name(heapRelationName);
Bruce Momjian's avatar
Bruce Momjian committed
812 813
	char	   *temp_relname = NULL;

814 815
	SetReindexProcessing(false);

816 817
	/*
	 * check parameters
818
	 */
819 820
	if (indexInfo->ii_NumIndexAttrs < 1 ||
		indexInfo->ii_NumKeyAttrs < 1)
Bruce Momjian's avatar
Bruce Momjian committed
821
		elog(ERROR, "must index at least one attribute");
Bruce Momjian's avatar
Bruce Momjian committed
822

823 824 825 826
	if (heapRelationName && !allow_system_table_mods &&
		IsSystemRelationName(heapRelationName) && IsNormalProcessingMode())
		elog(ERROR, "User-defined indexes on system catalogs are not supported");

827 828
	/*
	 * get heap relation oid and open the heap relation
829
	 */
830
	heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
831

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
832
	/*
833
	 * Only SELECT ... FOR UPDATE are allowed while doing this
834
	 */
835
	heapRelation = heap_open(heapoid, ShareLock);
836

837 838
	/*
	 * construct new tuple descriptor
839
	 */
840 841
	if (OidIsValid(indexInfo->ii_FuncOid))
		indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
842
	else
843
		indexTupDesc = ConstructTupleDescriptor(heapRelation,
844
												indexInfo->ii_NumKeyAttrs,
845
										   indexInfo->ii_KeyAttrNumbers);
846

847 848
	if (istemp)
	{
849
		/* save user relation name because heap_create changes it */
850
		temp_relname = pstrdup(indexRelationName);		/* save original value */
851
		indexRelationName = palloc(NAMEDATALEN);
852 853
		strcpy(indexRelationName, temp_relname);		/* heap_create will
														 * change this */
854 855
	}

856 857
	/*
	 * create the index relation
858
	 */
859
	indexRelation = heap_create(indexRelationName, indexTupDesc,
860
								istemp, false, allow_system_table_mods);
861

862 863 864 865 866 867 868
	/*
	 * 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);

869 870
	/*
	 * construct the index relation descriptor
871
	 *
872
	 * XXX should have a proper way to create cataloged relations
873
	 */
874 875
	ConstructIndexReldesc(indexRelation, accessMethodObjectId);

876
	/* ----------------
877
	 *	  add index to catalogs
878
	 *	  (append RELATION tuple)
879 880
	 * ----------------
	 */
881
	indexoid = UpdateRelationRelation(indexRelation, temp_relname);
882

883 884 885 886
	/*
	 * We create the disk file for this relation here
	 */
	heap_storage_create(indexRelation);
887

888 889 890
	/*
	 * now update the object id's of all the attribute tuple forms in the
	 * index relation's tuple descriptor
891
	 */
892 893 894
	InitializeAttributeOids(indexRelation,
							indexInfo->ii_NumIndexAttrs,
							indexoid);
895

896 897
	/*
	 * append ATTRIBUTE tuples for the index
898
	 */
899
	AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
900

901
	/* ----------------
902 903 904 905 906
	 *	  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
907 908
	 * ----------------
	 */
909 910
	UpdateIndexRelation(indexoid, heapoid, indexInfo,
						classObjectId, islossy, primary);
911

912 913
	/*
	 * initialize the index strategy
914
	 */
915 916 917
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
					  indexRelation,
					  accessMethodObjectId);
918 919 920 921 922 923

	/*
	 * 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
924 925
	 * index.
	 *
926 927
	 * In normal processing mode, the heap and index relations are closed by
	 * index_build() --- but we continue to hold the ShareLock on the heap
928 929
	 * and the exclusive lock on the index that we acquired above, until
	 * end of transaction.
930 931
	 */
	if (IsBootstrapProcessingMode())
932
	{
933
		index_register(heapRelationName, indexRelationName, indexInfo);
934
		/* XXX shouldn't we close the heap and index rels here? */
935 936
	}
	else
937
		index_build(heapRelation, indexRelation, indexInfo, NULL);
938 939 940
}

/* ----------------------------------------------------------------
941
 *
942
 *		index_drop
943
 *
944 945 946
 * ----------------------------------------------------------------
 */
void
947
index_drop(Oid indexId)
948
{
949
	Oid			heapId;
950 951
	Relation	userHeapRelation;
	Relation	userIndexRelation;
952
	Relation	indexRelation;
953
	Relation	relationRelation;
Bruce Momjian's avatar
Bruce Momjian committed
954
	Relation	attributeRelation;
955
	HeapTuple	tuple;
Bruce Momjian's avatar
Bruce Momjian committed
956
	int16		attnum;
957
	int			i;
Bruce Momjian's avatar
Bruce Momjian committed
958

959
	Assert(OidIsValid(indexId));
960

961 962 963 964 965 966 967 968 969
	/*
	 * 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.
970
	 */
971 972
	heapId = IndexGetRelation(indexId);
	userHeapRelation = heap_open(heapId, AccessExclusiveLock);
973 974 975

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

977 978 979 980
	/*
	 * 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...
981 982
	 */

983
	/*
Bruce Momjian's avatar
Bruce Momjian committed
984 985 986
	 * fix DESCRIPTION relation
	 */
	DeleteComments(indexId);
987

988
	/*
989 990
	 * fix RELATION relation
	 */
991
	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
992

993
	/* Remove the pg_class tuple for the index itself */
994 995 996 997 998 999
	tuple = SearchSysCacheCopy(RELOID,
							   ObjectIdGetDatum(indexId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "index_drop: cache lookup failed for index %u",
			 indexId);
1000

1001
	simple_heap_delete(relationRelation, &tuple->t_self);
1002
	heap_freetuple(tuple);
1003 1004

	/*
1005 1006 1007 1008 1009 1010
	 * 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).
1011
	 */
1012
	setRelhasindex(heapId, true);
1013

1014
	heap_close(relationRelation, RowExclusiveLock);
1015

1016
	/*
1017 1018
	 * fix ATTRIBUTE relation
	 */
1019
	attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1020

1021
	attnum = 1;					/* indexes start at 1 */
1022

1023
	while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
1024 1025
											   ObjectIdGetDatum(indexId),
												   Int16GetDatum(attnum),
1026
													   0, 0)))
1027
	{
1028
		simple_heap_delete(attributeRelation, &tuple->t_self);
1029
		heap_freetuple(tuple);
1030 1031
		attnum++;
	}
1032
	heap_close(attributeRelation, RowExclusiveLock);
1033

1034
	/*
1035 1036
	 * fix INDEX relation
	 */
1037 1038
	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);

1039 1040 1041 1042 1043 1044
	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
1045

1046
	simple_heap_delete(indexRelation, &tuple->t_self);
1047
	heap_freetuple(tuple);
1048
	heap_close(indexRelation, RowExclusiveLock);
1049 1050

	/*
1051
	 * flush buffer cache and physically remove the file
1052
	 */
1053 1054 1055
	i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
	if (i < 0)
		elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
1056

1057
	smgrunlink(DEFAULT_SMGR, userIndexRelation);
1058

1059 1060 1061 1062 1063
	/*
	 * Close rels, but keep locks
	 */
	index_close(userIndexRelation);
	heap_close(userHeapRelation, NoLock);
1064 1065

	RelationForgetRelation(indexId);
1066

1067
	/* if it's a temp index, clear the temp mapping table entry */
1068
	remove_temp_rel_by_relid(indexId);
1069 1070 1071
}

/* ----------------------------------------------------------------
1072
 *						index_build support
1073 1074
 * ----------------------------------------------------------------
 */
1075 1076 1077 1078 1079 1080 1081

/* ----------------
 *		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
1082
 * of individual index tuples.	Normally we build an IndexInfo for an index
1083 1084 1085
 * just once per command, and then use it for (potentially) many tuples.
 * ----------------
 */
1086
IndexInfo  *
1087 1088 1089 1090 1091 1092 1093
BuildIndexInfo(HeapTuple indexTuple)
{
	Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
	IndexInfo  *ii = makeNode(IndexInfo);
	int			i;
	int			numKeys;

1094 1095
	/*
	 * count the number of keys, and copy them into the IndexInfo
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
	 */
	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;

1106 1107
	/*
	 * Handle functional index.
1108
	 *
1109 1110 1111
	 * 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.
1112 1113 1114 1115 1116 1117 1118
	 */
	ii->ii_FuncOid = indexStruct->indproc;

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

1124 1125
	/*
	 * If partial index, convert predicate into expression nodetree
1126 1127 1128 1129 1130 1131
	 */
	if (VARSIZE(&indexStruct->indpred) != 0)
	{
		char	   *predString;

		predString = DatumGetCString(DirectFunctionCall1(textout,
1132
								PointerGetDatum(&indexStruct->indpred)));
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
		ii->ii_Predicate = stringToNode(predString);
		pfree(predString);
	}
	else
		ii->ii_Predicate = NULL;

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

	return ii;
}

1145
/* ----------------
1146
 *		FormIndexDatum
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
 *			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[].
1158 1159 1160
 * ----------------
 */
void
1161
FormIndexDatum(IndexInfo *indexInfo,
1162 1163
			   HeapTuple heapTuple,
			   TupleDesc heapDescriptor,
1164
			   MemoryContext resultCxt,
1165
			   Datum *datum,
1166
			   char *nullv)
1167
{
1168 1169 1170
	MemoryContext oldContext;
	int			i;
	Datum		iDatum;
1171
	bool		isNull;
1172

1173
	oldContext = MemoryContextSwitchTo(resultCxt);
1174

1175
	if (OidIsValid(indexInfo->ii_FuncOid))
1176
	{
1177 1178 1179

		/*
		 * Functional index --- compute the single index attribute
1180
		 */
1181 1182
		FunctionCallInfoData fcinfo;
		bool		anynull = false;
1183

1184 1185 1186
		MemSet(&fcinfo, 0, sizeof(fcinfo));
		fcinfo.flinfo = &indexInfo->ii_FuncInfo;
		fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
Bruce Momjian's avatar
Bruce Momjian committed
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
		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
	{
1212 1213 1214 1215

		/*
		 * Plain index --- for each attribute we need from the heap tuple,
		 * get the attribute and stick it into the datum and nullv arrays.
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
		 */
		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' : ' ';
		}
1226
	}
1227 1228

	MemoryContextSwitchTo(oldContext);
1229 1230 1231
}


Hiroshi Inoue's avatar
Hiroshi Inoue committed
1232 1233 1234 1235
/* --------------------------------------------
 *		Lock class info for update
 * --------------------------------------------
 */
1236 1237 1238
static bool
LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
					   Buffer *buffer, bool confirmCommitted)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1239 1240 1241 1242 1243
{
	HeapTuple	classTuple;
	bool		test;
	Relation	relationRelation;

1244
	/*
1245 1246
	 * NOTE: get and hold RowExclusiveLock on pg_class, because caller
	 * will probably modify the rel's pg_class tuple later on.
1247 1248
	 */
	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
	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);

1259
	while (1)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1260
	{
1261
		ItemPointerData tidsave;
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278

		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
1279 1280 1281 1282
	}
	RelationInvalidateHeapTuple(relationRelation, rtup);
	if (confirmCommitted)
	{
1283 1284
		HeapTupleHeader th = rtup->t_data;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
		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 ?
 * ---------------------------------------------
 */
1299 1300
bool
IndexesAreActive(Oid relid, bool confirmCommitted)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1301
{
1302
	HeapTupleData tuple;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1303 1304
	Relation	indexRelation;
	Buffer		buffer;
1305 1306
	HeapScanDesc scan;
	ScanKeyData entry;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1307 1308 1309 1310
	bool		isactive;

	if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
		elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1311
	if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1312
	  ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1313
		elog(ERROR, "relation %u isn't an indexable relation", relid);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1314 1315 1316 1317 1318 1319
	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,
1320
						   F_OIDEQ, ObjectIdGetDatum(relid));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1321
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
1322
						  1, &entry);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1323 1324 1325
	if (!heap_getnext(scan, 0))
		isactive = true;
	heap_endscan(scan);
1326
	heap_close(indexRelation, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1327 1328 1329 1330
	return isactive;
}

/* ----------------
1331 1332 1333 1334 1335 1336 1337 1338
 *		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
1339 1340 1341
 * ----------------
 */
void
1342
setRelhasindex(Oid relid, bool hasindex)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1343 1344 1345
{
	Relation	pg_class;
	HeapTuple	tuple;
1346
	HeapScanDesc pg_class_scan = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1347

1348 1349
	/*
	 * Find the tuple to update in pg_class.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1350 1351 1352
	 */
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1353
#ifdef	OLD_FILE_NAMING
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1354
	if (!IsIgnoringSystemIndexes())
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1355 1356
#else
	if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
1357
#endif	 /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1358
	{
1359 1360 1361
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
	}
	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);
1381 1382
		elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
			 relid);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1383 1384
	}

1385 1386
	/*
	 * Update hasindex in pg_class.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1387
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1388 1389
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1390
	((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1391 1392
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1393

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1394 1395
	if (pg_class_scan)
	{
1396
		/* Write the modified tuple in-place */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1397
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1398 1399 1400
		/* Send out shared cache inval if necessary */
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1401
		BufferSync();
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1402 1403 1404
	}
	else
	{
1405
		simple_heap_update(pg_class, &tuple->t_self, tuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1406

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
		/* 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);
		}
	}
1418

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1419 1420 1421 1422 1423
	if (!pg_class_scan)
		heap_freetuple(tuple);
	else
		heap_endscan(pg_class_scan);

1424
	heap_close(pg_class, RowExclusiveLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1425 1426
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1427 1428 1429 1430
#ifndef OLD_FILE_NAMING
void
setNewRelfilenode(Relation relation)
{
1431 1432 1433
	Relation	pg_class,
				idescs[Num_pg_class_indices];
	Oid			newrelfilenode;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1434
	bool		in_place_update = false;
1435 1436
	HeapTupleData lockTupleData;
	HeapTuple	classTuple = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1437
	Buffer		buffer;
1438 1439
	RelationData workrel;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1440 1441 1442
	Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);

	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1443
	/* Fetch and lock the classTuple associated with this relation */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
	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;
1456
		simple_heap_update(pg_class, &classTuple->t_self, classTuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1457
	}
1458
	/* schedule unlinking old relfilenode */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1459 1460 1461 1462 1463 1464 1465 1466
	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);
1467
	smgrclose(DEFAULT_SMGR, &workrel);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
	/* 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,
1486
						   idescs);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1487 1488 1489 1490
		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
		CatalogCloseIndices(Num_pg_class_indices, idescs);
	}
	heap_close(pg_class, NoLock);
1491 1492
	if (!in_place_update)
		heap_freetuple(classTuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1493 1494 1495
	/* Make sure the relfilenode change */
	CommandCounterIncrement();
}
1496 1497

#endif	 /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1498

1499
/* ----------------
1500
 *		UpdateStats
1501 1502 1503 1504
 *
 * Update pg_class' relpages and reltuples statistics for the given relation
 * (which can be either a table or an index).  Note that this is not used
 * in the context of VACUUM.
1505 1506 1507
 * ----------------
 */
void
1508
UpdateStats(Oid relid, double reltuples)
1509
{
1510 1511
	Relation	whichRel;
	Relation	pg_class;
1512
	HeapTuple	tuple;
1513 1514 1515 1516 1517 1518 1519 1520
	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];
1521
	HeapScanDesc pg_class_scan = NULL;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1522
	bool		in_place_upd;
1523

1524
	/*
1525
	 * This routine handles updates for both the heap and index relation
1526 1527 1528
	 * 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.
1529 1530 1531
	 */
	CommandCounterIncrement();

1532
	/*
1533 1534 1535 1536 1537 1538 1539
	 * 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.
	 */

1540 1541 1542
	/*
	 * Can't use heap_open here since we don't know if it's an index...
	 */
1543 1544 1545
	whichRel = RelationIdGetRelation(relid);

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

1548
	/* Grab lock to be held till end of xact (probably redundant...) */
1549 1550
	LockRelation(whichRel, ShareLock);

1551
	/*
1552 1553
	 * Find the RELATION relation tuple for the given relation.
	 */
1554
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1555

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1556
#ifdef	OLD_FILE_NAMING
1557
	in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1558
#else
1559
	in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
1560
#endif	 /* OLD_FILE_NAMING */
1561

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1562
	if (!in_place_upd)
Bruce Momjian's avatar
Bruce Momjian committed
1563
	{
1564 1565 1566
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
Bruce Momjian's avatar
Bruce Momjian committed
1567 1568 1569 1570 1571 1572
	}
	else
	{
		ScanKeyData key[1];

		ScanKeyEntryInitialize(&key[0], 0,
1573 1574 1575
							   ObjectIdAttributeNumber,
							   F_OIDEQ,
							   ObjectIdGetDatum(relid));
Bruce Momjian's avatar
Bruce Momjian committed
1576 1577 1578 1579

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

1581
	if (!HeapTupleIsValid(tuple))
1582
	{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1583
		if (pg_class_scan)
Bruce Momjian's avatar
Bruce Momjian committed
1584
			heap_endscan(pg_class_scan);
1585
		heap_close(pg_class, RowExclusiveLock);
1586 1587
		elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
			 relid);
1588 1589
	}

1590
	/*
1591 1592
	 * Figure values to insert.
	 *
1593 1594
	 * If we found zero tuples in the scan, do NOT believe it; instead put a
	 * bogus estimate into the statistics fields.  Otherwise, the common
1595
	 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
1596 1597 1598
	 * 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 it is actually sizable.  See also CREATE TABLE in heap.c.
1599 1600 1601 1602
	 *
	 * Note: this path is also taken during bootstrap, because bootstrap.c
	 * passes reltuples = 0 after loading a table.  We have to estimate some
	 * number for reltuples based on the actual number of pages.
1603 1604 1605
	 */
	relpages = RelationGetNumberOfBlocks(whichRel);

1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
	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);
	}

1623 1624 1625 1626 1627 1628 1629 1630
	/*
	 * 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;

1631 1632
	/*
	 * Update statistics in pg_class.
1633
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1634
	if (in_place_upd)
1635
	{
1636

1637 1638
		/*
		 * At bootstrap time, we don't need to worry about concurrency or
1639
		 * visibility of changes, so we cheat.	Also cheat if REINDEX.
1640
		 */
1641
		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1642
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1643 1644
		rd_rel->relpages = relpages;
		rd_rel->reltuples = reltuples;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1645
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1646
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1647 1648
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
1649 1650 1651
	}
	else
	{
1652 1653 1654 1655
		/* During normal processing, must work harder. */

		for (i = 0; i < Natts_pg_class; i++)
		{
1656
			nulls[i] = ' ';
1657 1658 1659 1660
			replace[i] = ' ';
			values[i] = (Datum) NULL;
		}

1661
		replace[Anum_pg_class_relpages - 1] = 'r';
1662
		values[Anum_pg_class_relpages - 1] = Int32GetDatum(relpages);
1663
		replace[Anum_pg_class_reltuples - 1] = 'r';
1664
		values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples);
1665
		newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1666
		simple_heap_update(pg_class, &tuple->t_self, newtup);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1667 1668 1669 1670 1671 1672
		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);
		}
1673
		heap_freetuple(newtup);
1674 1675
	}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1676
	if (!pg_class_scan)
1677
		heap_freetuple(tuple);
Bruce Momjian's avatar
Bruce Momjian committed
1678 1679
	else
		heap_endscan(pg_class_scan);
1680

1681 1682
	heap_close(pg_class, RowExclusiveLock);
	/* Cheating a little bit since we didn't open it with heap_open... */
1683
	heap_close(whichRel, NoLock);
1684 1685 1686 1687
}


/* ----------------
1688
 *		DefaultBuild
1689 1690 1691 1692 1693
 *
 * 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?
1694 1695 1696 1697
 * ----------------
 */
static void
DefaultBuild(Relation heapRelation,
1698
			 Relation indexRelation,
1699 1700
			 IndexInfo *indexInfo,
			 Node *oldPred,
1701
			 IndexStrategy indexStrategy)		/* not used */
1702
{
1703 1704 1705
	HeapScanDesc scan;
	HeapTuple	heapTuple;
	TupleDesc	heapDescriptor;
1706 1707
	Datum		datum[INDEX_MAX_KEYS];
	char		nullv[INDEX_MAX_KEYS];
1708
	double		reltuples,
1709
				indtuples;
1710
	Node	   *predicate = indexInfo->ii_Predicate;
1711

1712
#ifndef OMIT_PARTIAL_INDEX
1713
	TupleTable	tupleTable;
1714
	TupleTableSlot *slot;
1715

1716
#endif
1717
	ExprContext *econtext;
1718 1719
	InsertIndexResult insertResult;

1720 1721
	/*
	 * more & better checking is needed
1722 1723 1724
	 */
	Assert(OidIsValid(indexRelation->rd_rel->relam));	/* XXX */

1725
	heapDescriptor = RelationGetDescr(heapRelation);
1726 1727 1728 1729 1730 1731

	/*
	 * 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
1732 1733 1734 1735
	 * 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
1736
	 */
1737
#ifndef OMIT_PARTIAL_INDEX
1738 1739 1740 1741
	if (predicate != NULL || oldPred != NULL)
	{
		tupleTable = ExecCreateTupleTable(1);
		slot = ExecAllocTableSlot(tupleTable);
1742
		ExecSetSlotDescriptor(slot, heapDescriptor, false);
1743
	}
Marc G. Fournier's avatar
Marc G. Fournier committed
1744 1745
	else
	{
1746
		tupleTable = NULL;
Marc G. Fournier's avatar
Marc G. Fournier committed
1747 1748
		slot = NULL;
	}
1749 1750 1751
	econtext = MakeExprContext(slot, TransactionCommandContext);
#else
	econtext = MakeExprContext(NULL, TransactionCommandContext);
1752
#endif	 /* OMIT_PARTIAL_INDEX */
1753

1754 1755
	/*
	 * Ok, begin our scan of the base relation.
1756
	 */
1757 1758
	scan = heap_beginscan(heapRelation, /* relation */
						  0,	/* start at end */
1759
						  SnapshotNow,	/* seeself */
1760 1761 1762
						  0,	/* number of keys */
						  (ScanKey) NULL);		/* scan key */

1763
	reltuples = indtuples = 0.0;
1764

1765 1766 1767 1768 1769
	/*
	 * 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.
1770
	 */
1771
	while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1772
	{
1773 1774
		MemoryContextReset(econtext->ecxt_per_tuple_memory);

1775
		reltuples += 1.0;
1776

1777
#ifndef OMIT_PARTIAL_INDEX
1778

1779 1780 1781 1782 1783 1784 1785
		/*
		 * 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;
1786
			if (ExecQual((List *) oldPred, econtext, false))
1787
			{
1788
				indtuples += 1.0;
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799
				continue;
			}
		}

		/*
		 * Skip this tuple if it doesn't satisfy the partial-index
		 * predicate
		 */
		if (predicate != NULL)
		{
			slot->val = heapTuple;
1800
			if (!ExecQual((List *) predicate, econtext, false))
1801 1802
				continue;
		}
1803
#endif	 /* OMIT_PARTIAL_INDEX */
1804

1805
		indtuples += 1.0;
1806

1807 1808 1809
		/*
		 * FormIndexDatum fills in its datum and null parameters with
		 * attribute information taken from the given heap tuple.
1810
		 */
1811 1812 1813 1814 1815 1816
		FormIndexDatum(indexInfo,
					   heapTuple,
					   heapDescriptor,
					   econtext->ecxt_per_tuple_memory,
					   datum,
					   nullv);
1817 1818

		insertResult = index_insert(indexRelation, datum, nullv,
1819
									&(heapTuple->t_self), heapRelation);
1820 1821 1822

		if (insertResult)
			pfree(insertResult);
1823
	}
1824 1825 1826

	heap_endscan(scan);

1827
#ifndef OMIT_PARTIAL_INDEX
1828
	if (predicate != NULL || oldPred != NULL)
1829
		ExecDropTupleTable(tupleTable, true);
1830
#endif	 /* OMIT_PARTIAL_INDEX */
1831
	FreeExprContext(econtext);
1832 1833

	/*
1834 1835
	 * 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
1836 1837 1838 1839 1840 1841 1842
	 * 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.
1843 1844
	 */
	if (IsNormalProcessingMode())
1845
	{
1846 1847
		Oid			hrelid = RelationGetRelid(heapRelation);
		Oid			irelid = RelationGetRelid(indexRelation);
1848 1849 1850

		heap_close(heapRelation, NoLock);
		index_close(indexRelation);
1851 1852
		UpdateStats(hrelid, reltuples);
		UpdateStats(irelid, indtuples);
1853 1854 1855 1856
		if (oldPred != NULL)
		{
			if (indtuples == reltuples)
				predicate = NULL;
1857
			UpdateIndexPredicate(irelid, oldPred, predicate);
1858
		}
1859
	}
1860 1861 1862
}

/* ----------------
1863
 *		index_build
1864 1865 1866 1867
 * ----------------
 */
void
index_build(Relation heapRelation,
1868
			Relation indexRelation,
1869 1870
			IndexInfo *indexInfo,
			Node *oldPred)
1871
{
1872
	RegProcedure procedure;
1873

1874 1875
	/*
	 * sanity checks
1876 1877 1878 1879 1880 1881
	 */
	Assert(RelationIsValid(indexRelation));
	Assert(PointerIsValid(indexRelation->rd_am));

	procedure = indexRelation->rd_am->ambuild;

1882 1883
	/*
	 * use the access method build procedure if supplied, else default.
1884 1885
	 */
	if (RegProcedureIsValid(procedure))
1886
		OidFunctionCall5(procedure,
1887 1888
						 PointerGetDatum(heapRelation),
						 PointerGetDatum(indexRelation),
1889 1890
						 PointerGetDatum(indexInfo),
						 PointerGetDatum(oldPred),
1891
			   PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
1892 1893 1894
	else
		DefaultBuild(heapRelation,
					 indexRelation,
1895 1896
					 indexInfo,
					 oldPred,
1897
					 RelationGetIndexStrategy(indexRelation));
1898 1899
}

1900 1901
/*
 * IndexGetRelation: given an index's relation OID, get the OID of the
1902
 * relation it is an index on.	Uses the system cache.
1903 1904 1905 1906 1907 1908
 */
static Oid
IndexGetRelation(Oid indexId)
{
	HeapTuple	tuple;
	Form_pg_index index;
1909
	Oid			result;
1910

1911 1912 1913
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexId),
						   0, 0, 0);
1914 1915 1916 1917 1918 1919
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "IndexGetRelation: can't find index id %u",
			 indexId);
	index = (Form_pg_index) GETSTRUCT(tuple);
	Assert(index->indexrelid == indexId);

1920 1921 1922
	result = index->indrelid;
	ReleaseSysCache(tuple);
	return result;
1923 1924
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1925 1926
/* ---------------------------------
 * activate_index -- activate/deactivate the specified index.
1927
 *		Note that currently PostgreSQL doesn't hold the
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1928 1929 1930
 *		status per index
 * ---------------------------------
 */
1931
static bool
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1932
activate_index(Oid indexId, bool activate, bool inplace)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1933
{
1934
	if (!activate)				/* Currently does nothing */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1935
		return true;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1936
	return reindex_index(indexId, false, inplace);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1937
}
1938

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1939 1940 1941 1942 1943
/* --------------------------------
 * reindex_index - This routine is used to recreate an index
 * --------------------------------
 */
bool
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1944
reindex_index(Oid indexId, bool force, bool inplace)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1945
{
1946 1947 1948 1949 1950 1951 1952
	Relation	iRel,
				indexRelation,
				heapRelation;
	ScanKeyData entry;
	HeapScanDesc scan;
	HeapTuple	indexTuple,
				classTuple;
1953
	IndexInfo  *indexInfo;
1954 1955
	Oid			heapId,
				accessMethodId;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1956 1957
	bool		old;

1958 1959 1960 1961
	/*
	 * 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.
1962 1963 1964 1965
	 */
	if (IsTransactionBlock())
		elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1966
	old = SetReindexProcessing(true);
1967 1968

	/* Scan pg_index to find the index's pg_index entry */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1969 1970 1971 1972 1973 1974
	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))
1975
		elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1976

1977 1978 1979 1980
	/* 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
1981

1982 1983 1984
	/* Complete the scan and close pg_index */
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1985 1986

	/* Fetch the classTuple associated with this index */
1987 1988 1989
	classTuple = SearchSysCache(RELOID,
								ObjectIdGetDatum(indexId),
								0, 0, 0);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1990
	if (!HeapTupleIsValid(classTuple))
1991
		elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1992
	accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
1993
	ReleaseSysCache(classTuple);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1994 1995 1996 1997 1998

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

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2003 2004
#ifndef OLD_FILE_NAMING
	if (!inplace)
2005 2006
	{
		inplace = IsSharedSystemRelationName(NameStr(iRel->rd_rel->relname));
2007 2008 2009
		if (!inplace)
			setNewRelfilenode(iRel);
	}
2010
#endif	 /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2011 2012 2013
	/* Obtain exclusive lock on it, just to be sure */
	LockRelation(iRel, AccessExclusiveLock);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2014 2015
	if (inplace)
	{
2016

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2017
		/*
2018 2019 2020
		 * Release any buffers associated with this index.	If they're
		 * dirty, they're just dropped without bothering to flush to disk.
		 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2021 2022 2023 2024 2025 2026
		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
2027 2028

	/* Initialize the index and rebuild */
2029 2030
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
	index_build(heapRelation, iRel, indexInfo, NULL);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2031 2032

	/*
2033
	 * index_build will close both the heap and index relations (but not
2034
	 * give up the locks we hold on them).	So we're done.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2035 2036 2037
	 */

	SetReindexProcessing(old);
2038

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2039 2040 2041 2042 2043
	return true;
}

/*
 * ----------------------------
2044
 * activate_indexes_of_a_table
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2045 2046 2047 2048 2049 2050 2051 2052 2053
 *	activate/deactivate indexes of the specified table.
 * ----------------------------
 */
bool
activate_indexes_of_a_table(Oid relid, bool activate)
{
	if (IndexesAreActive(relid, true))
	{
		if (!activate)
2054
			setRelhasindex(relid, false);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066
		else
			return false;
	}
	else
	{
		if (activate)
			reindex_relation(relid, false);
		else
			return false;
	}
	return true;
}
2067

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2068 2069 2070 2071 2072 2073 2074 2075 2076
/* --------------------------------
 * reindex_relation - This routine is used to recreate indexes
 * of a relation.
 * --------------------------------
 */
bool
reindex_relation(Oid relid, bool force)
{
	Relation	indexRelation;
2077 2078
	ScanKeyData entry;
	HeapScanDesc scan;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2079
	HeapTuple	indexTuple;
2080 2081
	bool		old,
				reindexed;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2082

2083 2084 2085 2086
	bool		deactivate_needed,
				overwrite,
				upd_pg_class_inplace;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2087
#ifdef OLD_FILE_NAMING
2088
	overwrite = upd_pg_class_inplace = deactivate_needed = true;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2089
#else
2090 2091 2092 2093
	Relation	rel;

	overwrite = upd_pg_class_inplace = deactivate_needed = false;

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2094
	/*
2095 2096 2097
	 * avoid heap_update() pg_class tuples while processing reindex for
	 * pg_class.
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2098 2099
	if (IsIgnoringSystemIndexes())
		upd_pg_class_inplace = true;
2100

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2101 2102 2103
	/*
	 * ignore the indexes of the target system relation while processing
	 * reindex.
2104
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2105 2106 2107
	rel = RelationIdGetRelation(relid);
	if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
		deactivate_needed = true;
2108 2109 2110 2111 2112 2113
#ifndef ENABLE_REINDEX_NAILED_RELATIONS

	/*
	 * nailed relations are never updated. We couldn't keep the
	 * consistency between the relation descriptors and pg_class tuples.
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123
	if (rel->rd_isnailed)
	{
		if (IsIgnoringSystemIndexes())
		{
			overwrite = true;
			deactivate_needed = true;
		}
		else
			elog(ERROR, "the target relation %u is nailed", relid);
	}
2124 2125
#endif	 /* ENABLE_REINDEX_NAILED_RELATIONS */

2126
	/*
2127 2128
	 * Shared system indexes must be overwritten because it's impossible
	 * to update pg_class tuples of all databases.
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
	 */
	if (IsSharedSystemRelationName(NameStr(rel->rd_rel->relname)))
	{
		if (IsIgnoringSystemIndexes())
		{
			overwrite = true;
			deactivate_needed = true;
		}
		else
			elog(ERROR, "the target relation %u is shared", relid);
	}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2140
	RelationClose(rel);
2141
#endif	 /* OLD_FILE_NAMING */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2142
	old = SetReindexProcessing(true);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2143
	if (deactivate_needed)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2144
	{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2145
		if (IndexesAreActive(relid, upd_pg_class_inplace))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2146
		{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2147 2148 2149 2150 2151 2152 2153
			if (!force)
			{
				SetReindexProcessing(old);
				return false;
			}
			activate_indexes_of_a_table(relid, false);
			CommandCounterIncrement();
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2154 2155 2156 2157 2158
		}
	}

	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2159
						   F_OIDEQ, ObjectIdGetDatum(relid));
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2160
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
2161
						  1, &entry);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2162 2163 2164
	reindexed = false;
	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
	{
2165 2166
		Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);

Hiroshi Inoue's avatar
Hiroshi Inoue committed
2167
		if (activate_index(index->indexrelid, true, overwrite))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2168 2169 2170 2171 2172 2173 2174 2175 2176 2177
			reindexed = true;
		else
		{
			reindexed = false;
			break;
		}
	}
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
	if (reindexed)
2178 2179 2180 2181 2182 2183

		/*
		 * Ok,we could use the reindexed indexes of the target system
		 * relation now.
		 */
	{
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2184 2185 2186 2187
		if (deactivate_needed)
		{
			if (!overwrite && relid == RelOid_pg_class)
			{
2188 2189 2190 2191

				/*
				 * For pg_class, relhasindex should be set to true here in
				 * place.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2192 2193 2194
				 */
				setRelhasindex(relid, true);
				CommandCounterIncrement();
2195 2196 2197 2198

				/*
				 * However the following setRelhasindex() is needed to
				 * keep consistency with WAL.
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2199 2200 2201 2202 2203
				 */
			}
			setRelhasindex(relid, true);
		}
	}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2204
	SetReindexProcessing(old);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2205

2206
	return reindexed;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
2207
}