index.c 62.3 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
B
Add:  
Bruce Momjian 已提交
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.141 2001/02/23 09:26:14 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

T
Tom Lane 已提交
24
#include <unistd.h>
B
Bruce Momjian 已提交
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"
B
Bruce Momjian 已提交
35
#include "catalog/pg_index.h"
36 37
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
B
Hello.  
Bruce Momjian 已提交
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.
 */
B
Bruce Momjian 已提交
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 */
B
Bruce Momjian 已提交
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);
H
Hiroshi Inoue 已提交
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)
H
Hiroshi Inoue 已提交
88
{
89 90
	bool		old = reindexing;

H
Hiroshi Inoue 已提交
91 92 93
	reindexing = reindexmode;
	return old;
}
94 95

bool
96
IsReindexProcessing(void)
H
Hiroshi Inoue 已提交
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

B
Bruce Momjian 已提交
144

145
	indoid = RelnameFindRelid(indexRelationName);
146

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

152
	heapoid = RelnameFindRelid(heapRelationName);
153 154

	if (!OidIsValid(heapoid))
B
Bruce Momjian 已提交
155
		elog(ERROR, "Cannot create index on '%s': relation does not exist",
156
			 heapRelationName);
B
Bruce Momjian 已提交
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
	 * Allocate and zero a tuple descriptor for a one-column tuple.
170 171
	 */
	funcTupDesc = CreateTemplateTupleDesc(1);
172
	funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
B
Bruce Momjian 已提交
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;
B
Bruce Momjian 已提交
209 210
	funcTupDesc->attrs[0]->attcacheoff = -1;
	funcTupDesc->attrs[0]->atttypmod = -1;
211
	funcTupDesc->attrs[0]->attstorage = ((Form_pg_type) GETSTRUCT(tuple))->typstorage;
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(Relation heapRelation,
227
						 int numatts,
228
						 AttrNumber *attNums)
229
{
230 231
	TupleDesc	heapTupDesc;
	TupleDesc	indexTupDesc;
232
	int			natts;			/* #atts in heap rel --- for error checks */
233
	int			i;
234

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

238 239 240 241 242 243 244 245 246 247 248 249 250
	/* ----------------
	 *	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
	 * ----------------
	 */
251
	for (i = 0; i < numatts; i++)
252
	{
253 254
		AttrNumber	atnum;		/* attributeNumber[attributeOffset] */
		AttrNumber	atind;
255 256
		Form_pg_attribute from;
		Form_pg_attribute to;
257 258

		/* ----------------
259 260
		 *	 get the attribute number and make sure it's valid;
		 *	 determine which attribute descriptor to copy
261 262 263 264 265 266 267
		 * ----------------
		 */
		atnum = attNums[i];

		if (!AttrNumberIsForUserDefinedAttr(atnum))
		{
			/* ----------------
268 269
			 *	  here we are indexing on a system attribute (-1...-n)
			 *	  so we convert atnum into a usable index 0...n-1 so we can
270 271 272 273 274
			 *	  use it to dereference the array sysatts[] which stores
			 *	  tuple descriptor information for system attributes.
			 * ----------------
			 */
			if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
B
Bruce Momjian 已提交
275
				elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
276 277
			atind = (-atnum) - 1;

278
			from = &sysatts[atind];
279 280 281 282 283 284 285
		}
		else
		{
			/* ----------------
			 *	  here we are indexing on a normal attribute (1...n)
			 * ----------------
			 */
286 287 288
			if (atnum > natts)
				elog(ERROR, "Cannot create index: attribute %d does not exist",
					 atnum);
289 290
			atind = AttrNumberGetAttrOffset(atnum);

291
			from = heapTupDesc->attrs[atind];
292 293 294 295 296 297 298
		}

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

303 304 305
		/*
		 * Fix the stuff that should not be the same as the underlying attr
		 */
306
		to->attnum = i + 1;
307

308 309 310 311
		to->attdispersion = 0.0;
		to->attnotnull = false;
		to->atthasdef = false;
		to->attcacheoff = -1;
312

313 314 315 316
		/*
		 * We do not yet have the correct relation OID for the index,
		 * so just set it invalid for now.  InitializeAttributeOids()
		 * will fix it later.
317
		 */
318
		to->attrelid = InvalidOid;
319 320 321 322 323 324
	}

	return indexTupDesc;
}

/* ----------------------------------------------------------------
B
Bruce Momjian 已提交
325
 * AccessMethodObjectIdGetForm
326 327
 *		Returns an access method tuple given its object identifier,
 *		or NULL if no such AM tuple can be found.
328
 *
329 330 331
 * Scanning is done using CurrentMemoryContext as working storage,
 * but the returned tuple will be allocated in resultCxt (which is
 * typically CacheMemoryContext).
332
 *
333 334 335
 * 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.
336 337 338
 * ----------------------------------------------------------------
 */
Form_pg_am
339 340
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
							MemoryContext resultCxt)
341
{
342 343 344 345
	Relation	pg_am_desc;
	HeapScanDesc pg_am_scan;
	HeapTuple	pg_am_tuple;
	ScanKeyData key;
346
	Form_pg_am	aform;
347 348 349 350 351 352

	/* ----------------
	 *	form a scan key for the pg_am relation
	 * ----------------
	 */
	ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
B
Bruce Momjian 已提交
353
						   F_OIDEQ,
354 355 356 357 358 359
						   ObjectIdGetDatum(accessMethodObjectId));

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

363
	pg_am_tuple = heap_getnext(pg_am_scan, 0);
364 365 366 367 368 369 370 371

	/* ----------------
	 *	return NULL if not found
	 * ----------------
	 */
	if (!HeapTupleIsValid(pg_am_tuple))
	{
		heap_endscan(pg_am_scan);
372
		heap_close(pg_am_desc, AccessShareLock);
373
		return NULL;
374 375 376
	}

	/* ----------------
377
	 *	if found AM tuple, then copy it into resultCxt and return the copy
378 379
	 * ----------------
	 */
380
	aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
381
	memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
382 383

	heap_endscan(pg_am_scan);
384
	heap_close(pg_am_desc, AccessShareLock);
385

386
	return aform;
387 388 389 390 391 392 393 394 395
}

/* ----------------------------------------------------------------
 *		ConstructIndexReldesc
 * ----------------------------------------------------------------
 */
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
396 397
	indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
													   CacheMemoryContext);
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414

	/* ----------------
	 *	 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
 * ----------------------------------------------------------------
 */
415
static Oid
416
UpdateRelationRelation(Relation indexRelation, char *temp_relname)
417
{
418 419 420 421
	Relation	pg_class;
	HeapTuple	tuple;
	Oid			tupleOid;
	Relation	idescs[Num_pg_class_indices];
422

423
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
424 425 426

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

430 431
	/* ----------------
	 *	the new tuple must have the same oid as the relcache entry for the
432 433
	 *	index.	sure would be embarrassing to do this sort of thing in
	 *	polite company.
434
	 * ----------------
435
	 */
436
	tuple->t_data->t_oid = RelationGetRelid(indexRelation);
437 438
	heap_insert(pg_class, tuple);

439 440
	if (temp_relname)
		create_temp_relation(temp_relname, tuple);
B
Bruce Momjian 已提交
441

442 443 444 445 446 447 448
	/*
	 * 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.
	 */

H
Hiroshi Inoue 已提交
449
	if (!IsIgnoringSystemIndexes())
450 451 452 453 454 455
	{
		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);
	}

456
	tupleOid = tuple->t_data->t_oid;
457
	heap_freetuple(tuple);
458
	heap_close(pg_class, RowExclusiveLock);
459

460
	return tupleOid;
461 462 463 464 465 466 467 468 469 470 471
}

/* ----------------------------------------------------------------
 *		InitializeAttributeOids
 * ----------------------------------------------------------------
 */
static void
InitializeAttributeOids(Relation indexRelation,
						int numatts,
						Oid indexoid)
{
472 473
	TupleDesc	tupleDescriptor;
	int			i;
474

475
	tupleDescriptor = RelationGetDescr(indexRelation);
476 477 478 479 480 481 482 483 484 485 486 487 488 489

	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)
{
490
	Relation	pg_attribute;
491 492 493
	HeapTuple	init_tuple,
				cur_tuple = NULL,
				new_tuple;
494 495 496 497 498 499 500
	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;
501 502 503 504 505

	/* ----------------
	 *	open the attribute relation
	 * ----------------
	 */
506
	pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
507 508

	/* ----------------
509
	 *	initialize *null, *replace and *value
510 511
	 * ----------------
	 */
B
Bruce Momjian 已提交
512 513
	MemSet(nullv, ' ', Natts_pg_attribute);
	MemSet(replace, ' ', Natts_pg_attribute);
514 515 516 517 518 519 520 521 522 523 524 525

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

526
	init_tuple = heap_addheader(Natts_pg_attribute,
B
Bruce Momjian 已提交
527
								ATTRIBUTE_TUPLE_SIZE,
528
							 (char *) (indexRelation->rd_att->attrs[0]));
529 530

	hasind = false;
H
Hiroshi Inoue 已提交
531
	if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
532 533 534 535 536 537 538 539 540
	{
		hasind = true;
		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
	}

	/* ----------------
	 *	insert the first attribute tuple.
	 * ----------------
	 */
541
	cur_tuple = heap_modifytuple(init_tuple,
542 543 544 545
								 pg_attribute,
								 value,
								 nullv,
								 replace);
546
	heap_freetuple(init_tuple);
547

548
	heap_insert(pg_attribute, cur_tuple);
549
	if (hasind)
550
		CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
551 552

	/* ----------------
553
	 *	now we use the information in the index cur_tuple
554 555 556
	 *	descriptor to form the remaining attribute tuples.
	 * ----------------
	 */
557
	indexTupDesc = RelationGetDescr(indexRelation);
558 559 560 561 562 563 564

	for (i = 1; i < numatts; i += 1)
	{
		/* ----------------
		 *	process the remaining attributes...
		 * ----------------
		 */
565
		memmove(GETSTRUCT(cur_tuple),
566
				(char *) indexTupDesc->attrs[i],
B
Bruce Momjian 已提交
567
				ATTRIBUTE_TUPLE_SIZE);
568 569 570

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

571
		new_tuple = heap_modifytuple(cur_tuple,
572 573 574 575
									 pg_attribute,
									 value,
									 nullv,
									 replace);
576
		heap_freetuple(cur_tuple);
577

578
		heap_insert(pg_attribute, new_tuple);
579
		if (hasind)
580
			CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
581 582

		/* ----------------
583
		 *	ModifyHeapTuple returns a new copy of a cur_tuple
584 585 586
		 *	so we free the original and use the copy..
		 * ----------------
		 */
587
		cur_tuple = new_tuple;
588 589
	}

590
	if (cur_tuple)
591
		heap_freetuple(cur_tuple);
592
	heap_close(pg_attribute, RowExclusiveLock);
593 594 595 596 597 598 599 600 601 602 603
	if (hasind)
		CatalogCloseIndices(Num_pg_attr_indices, idescs);
}

/* ----------------------------------------------------------------
 *		UpdateIndexRelation
 * ----------------------------------------------------------------
 */
static void
UpdateIndexRelation(Oid indexoid,
					Oid heapoid,
604
					IndexInfo *indexInfo,
605
					Oid *classOids,
606
					bool islossy,
B
Bruce Momjian 已提交
607
					bool primary)
608
{
609
	Form_pg_index indexForm;
610 611 612 613 614 615 616
	char	   *predString;
	text	   *predText;
	int			predLen,
				itupLen;
	Relation	pg_index;
	HeapTuple	tuple;
	int			i;
617
	Relation	idescs[Num_pg_index_indices];
618 619

	/* ----------------
620
	 *	allocate a Form_pg_index big enough to hold the
621 622 623
	 *	index-predicate (if any) in string form
	 * ----------------
	 */
624
	if (indexInfo->ii_Predicate != NULL)
625
	{
626
		predString = nodeToString(indexInfo->ii_Predicate);
627 628
		predText = DatumGetTextP(DirectFunctionCall1(textin,
											CStringGetDatum(predString)));
629 630 631
		pfree(predString);
	}
	else
632 633
		predText = DatumGetTextP(DirectFunctionCall1(textin,
													 CStringGetDatum("")));
634

635 636
	predLen = VARSIZE(predText);
	itupLen = predLen + sizeof(FormData_pg_index);
637
	indexForm = (Form_pg_index) palloc(itupLen);
638
	MemSet(indexForm, 0, sizeof(FormData_pg_index));
639 640

	/* ----------------
641
	 *	store information into the index tuple form
642 643 644
	 * ----------------
	 */
	indexForm->indexrelid = indexoid;
645 646 647
	indexForm->indrelid = heapoid;
	indexForm->indproc = indexInfo->ii_FuncOid;
	indexForm->indisclustered = false;
648
	indexForm->indislossy = islossy;
649 650
	indexForm->indhaskeytype = true; /* not actually used anymore */
	indexForm->indisunique = indexInfo->ii_Unique;
651
	indexForm->indisprimary = primary;
652
	memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
653 654 655

	/* ----------------
	 *	copy index key and op class information
656 657
	 *
	 *	We zeroed the extra slots (if any) above --- that's essential.
658 659
	 * ----------------
	 */
660 661
	for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
		indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
662

663 664
	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
		indexForm->indclass[i] = classOids[i];
665 666 667 668 669

	/* ----------------
	 *	open the system catalog index relation
	 * ----------------
	 */
670
	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

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

686
	/* ----------------
687
	 *	add index tuples for it
688 689
	 * ----------------
	 */
H
Hiroshi Inoue 已提交
690
	if (!IsIgnoringSystemIndexes())
691 692 693 694 695
	{
		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);
	}
696

697 698 699 700
	/* ----------------
	 *	close the relation and free the tuple
	 * ----------------
	 */
701
	heap_close(pg_index, RowExclusiveLock);
702 703
	pfree(predText);
	pfree(indexForm);
704
	heap_freetuple(tuple);
705 706 707 708 709 710 711
}

/* ----------------------------------------------------------------
 *		UpdateIndexPredicate
 * ----------------------------------------------------------------
 */
void
712
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
713
{
714 715 716 717 718 719 720 721 722 723
	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];
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738

	/*
	 * 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)
	{
739
		newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
740 741 742 743 744 745 746 747 748
								  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);
749 750
		predText = DatumGetTextP(DirectFunctionCall1(textin,
											CStringGetDatum(predString)));
751 752 753
		pfree(predString);
	}
	else
754 755
		predText = DatumGetTextP(DirectFunctionCall1(textin,
													 CStringGetDatum("")));
756 757

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

760 761 762 763 764 765
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexoid),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
			 indexoid);
766

767 768 769 770 771 772 773 774 775 776
	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;

777
	newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
778

779
	simple_heap_update(pg_index, &newtup->t_self, newtup);
780

781
	heap_freetuple(newtup);
782 783
	ReleaseSysCache(tuple);

784
	heap_close(pg_index, RowExclusiveLock);
785 786 787 788 789 790 791 792 793 794 795 796
	pfree(predText);
}

/* ----------------------------------------------------------------
 *		InitIndexStrategy
 * ----------------------------------------------------------------
 */
void
InitIndexStrategy(int numatts,
				  Relation indexRelation,
				  Oid accessMethodObjectId)
{
797 798 799 800 801 802
	IndexStrategy strategy;
	RegProcedure *support;
	uint16		amstrategies;
	uint16		amsupport;
	Oid			attrelid;
	Size		strsize;
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825

	/* ----------------
	 *	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.
	 * ----------------
	 */
826 827
	if (!CacheMemoryContext)
		CreateCacheMemoryContext();
828

829 830
	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
												  strsize);
831 832 833 834

	if (amsupport > 0)
	{
		strsize = numatts * (amsupport * sizeof(RegProcedure));
835
		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
836 837 838 839 840 841 842
													  strsize);
	}
	else
		support = (RegProcedure *) NULL;

	/* ----------------
	 *	fill in the index strategy structure with information
843 844
	 *	from the catalogs.	First we must advance the command counter
	 *	so that we will see the newly-entered index catalog tuples.
845 846
	 * ----------------
	 */
847
	CommandCounterIncrement();
848 849

	IndexSupportInitialize(strategy, support,
850
						   &indexRelation->rd_uniqueindex,
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
						   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,
869
			 IndexInfo *indexInfo,
870
			 Oid accessMethodObjectId,
871
			 Oid *classObjectId,
872
			 bool islossy,
873 874
			 bool primary,
			 bool allow_system_table_mods)
875
{
876 877 878 879 880
	Relation	heapRelation;
	Relation	indexRelation;
	TupleDesc	indexTupDesc;
	Oid			heapoid;
	Oid			indexoid;
881
	bool		istemp = is_temp_rel_name(heapRelationName);
B
Bruce Momjian 已提交
882 883
	char	   *temp_relname = NULL;

884 885
	SetReindexProcessing(false);

886 887 888 889
	/* ----------------
	 *	check parameters
	 * ----------------
	 */
890 891
	if (indexInfo->ii_NumIndexAttrs < 1 ||
		indexInfo->ii_NumKeyAttrs < 1)
B
Bruce Momjian 已提交
892
		elog(ERROR, "must index at least one attribute");
B
Bruce Momjian 已提交
893

894 895 896 897
	/* ----------------
	 *	  get heap relation oid and open the heap relation
	 * ----------------
	 */
898
	heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
899

V
Vadim B. Mikheev 已提交
900
	/*
901
	 * Only SELECT ... FOR UPDATE are allowed while doing this
902
	 */
903
	heapRelation = heap_open(heapoid, ShareLock);
904 905 906 907 908

	/* ----------------
	 *	  construct new tuple descriptor
	 * ----------------
	 */
909 910
	if (OidIsValid(indexInfo->ii_FuncOid))
		indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
911
	else
912
		indexTupDesc = ConstructTupleDescriptor(heapRelation,
913 914
												indexInfo->ii_NumKeyAttrs,
												indexInfo->ii_KeyAttrNumbers);
915

916 917
	if (istemp)
	{
918 919
		/* save user relation name because heap_create changes it */
		temp_relname = pstrdup(indexRelationName);	/* save original value */
920
		indexRelationName = palloc(NAMEDATALEN);
921 922
		strcpy(indexRelationName, temp_relname);	/* heap_create will
													 * change this */
923 924
	}

925
	/* ----------------
926
	 *	create the index relation
927 928
	 * ----------------
	 */
929
	indexRelation = heap_create(indexRelationName, indexTupDesc,
930
								istemp, false, allow_system_table_mods);
931

932 933 934 935 936 937 938
	/*
	 * 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);

939
	/* ----------------
940 941 942
	 *	  construct the index relation descriptor
	 *
	 *	  XXX should have a proper way to create cataloged relations
943 944
	 * ----------------
	 */
945 946
	ConstructIndexReldesc(indexRelation, accessMethodObjectId);

947
	/* ----------------
948
	 *	  add index to catalogs
949
	 *	  (append RELATION tuple)
950 951
	 * ----------------
	 */
952
	indexoid = UpdateRelationRelation(indexRelation, temp_relname);
953

954 955 956 957
	/*
	 * We create the disk file for this relation here
	 */
	heap_storage_create(indexRelation);
958

959 960 961 962 963
	/* ----------------
	 *	now update the object id's of all the attribute
	 *	tuple forms in the index relation's tuple descriptor
	 * ----------------
	 */
964 965 966
	InitializeAttributeOids(indexRelation,
							indexInfo->ii_NumIndexAttrs,
							indexoid);
967 968

	/* ----------------
969
	 *	  append ATTRIBUTE tuples for the index
970 971
	 * ----------------
	 */
972
	AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
973

974
	/* ----------------
975 976 977 978 979
	 *	  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
980 981
	 * ----------------
	 */
982 983
	UpdateIndexRelation(indexoid, heapoid, indexInfo,
						classObjectId, islossy, primary);
984 985 986 987 988

	/* ----------------
	 *	  initialize the index strategy
	 * ----------------
	 */
989 990 991
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
					  indexRelation,
					  accessMethodObjectId);
992 993 994 995 996 997

	/*
	 * 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
998 999
	 * index.
	 *
1000 1001
	 * In normal processing mode, the heap and index relations are closed by
	 * index_build() --- but we continue to hold the ShareLock on the heap
1002 1003
	 * and the exclusive lock on the index that we acquired above, until
	 * end of transaction.
1004 1005
	 */
	if (IsBootstrapProcessingMode())
1006
	{
1007
		index_register(heapRelationName, indexRelationName, indexInfo);
1008
		/* XXX shouldn't we close the heap and index rels here? */
1009 1010
	}
	else
1011
	{
1012
		index_build(heapRelation, indexRelation, indexInfo, NULL);
1013 1014 1015 1016
	}
}

/* ----------------------------------------------------------------
1017
 *
1018
 *		index_drop
1019
 *
1020 1021 1022
 * ----------------------------------------------------------------
 */
void
1023
index_drop(Oid indexId)
1024
{
1025
	Oid			heapId;
1026 1027
	Relation	userHeapRelation;
	Relation	userIndexRelation;
1028
	Relation	indexRelation;
1029
	Relation	relationRelation;
B
Bruce Momjian 已提交
1030
	Relation	attributeRelation;
1031
	HeapTuple	tuple;
B
Bruce Momjian 已提交
1032
	int16		attnum;
1033
	int			i;
B
Bruce Momjian 已提交
1034

1035
	Assert(OidIsValid(indexId));
1036

1037 1038 1039 1040 1041 1042 1043 1044 1045
	/* ----------------
	 *	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.
	 * ----------------
1046
	 */
1047 1048
	heapId = IndexGetRelation(indexId);
	userHeapRelation = heap_open(heapId, AccessExclusiveLock);
1049 1050 1051

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

1053
	/* ----------------
1054 1055 1056
	 *	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...
1057 1058 1059
	 * ----------------
	 */

B
Hello.  
Bruce Momjian 已提交
1060 1061 1062 1063 1064
	/* ----------------
	 * fix DESCRIPTION relation
	 * ----------------
	 */
	DeleteComments(indexId);
1065

1066 1067 1068 1069
	/* ----------------
	 * fix RELATION relation
	 * ----------------
	 */
1070
	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1071

1072
	/* Remove the pg_class tuple for the index itself */
1073 1074 1075 1076 1077 1078
	tuple = SearchSysCacheCopy(RELOID,
							   ObjectIdGetDatum(indexId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "index_drop: cache lookup failed for index %u",
			 indexId);
1079

1080
	simple_heap_delete(relationRelation, &tuple->t_self);
1081
	heap_freetuple(tuple);
1082 1083

	/*
1084 1085 1086 1087 1088 1089
	 * 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).
1090
	 */
1091
	setRelhasindex(heapId, true);
1092

1093
	heap_close(relationRelation, RowExclusiveLock);
1094 1095 1096 1097 1098

	/* ----------------
	 * fix ATTRIBUTE relation
	 * ----------------
	 */
1099
	attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1100

1101
	attnum = 1;					/* indexes start at 1 */
1102

1103
	while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
1104 1105
											   ObjectIdGetDatum(indexId),
												   Int16GetDatum(attnum),
1106
													   0, 0)))
1107
	{
1108
		simple_heap_delete(attributeRelation, &tuple->t_self);
1109
		heap_freetuple(tuple);
1110 1111
		attnum++;
	}
1112
	heap_close(attributeRelation, RowExclusiveLock);
1113

1114 1115 1116 1117
	/* ----------------
	 * fix INDEX relation
	 * ----------------
	 */
1118 1119
	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);

1120 1121 1122 1123 1124 1125
	tuple = SearchSysCacheCopy(INDEXRELID,
							   ObjectIdGetDatum(indexId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "index_drop: cache lookup failed for index %u",
			 indexId);
B
Bruce Momjian 已提交
1126

1127
	simple_heap_delete(indexRelation, &tuple->t_self);
1128
	heap_freetuple(tuple);
1129
	heap_close(indexRelation, RowExclusiveLock);
1130 1131

	/*
1132
	 * flush buffer cache and physically remove the file
1133
	 */
1134 1135 1136
	i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
	if (i < 0)
		elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
1137

1138
	smgrunlink(DEFAULT_SMGR, userIndexRelation);
1139

1140 1141 1142 1143 1144
	/*
	 * Close rels, but keep locks
	 */
	index_close(userIndexRelation);
	heap_close(userHeapRelation, NoLock);
1145 1146

	RelationForgetRelation(indexId);
1147

1148
	/* if it's a temp index, clear the temp mapping table entry */
1149
	remove_temp_rel_by_relid(indexId);
1150 1151 1152
}

/* ----------------------------------------------------------------
1153
 *						index_build support
1154 1155
 * ----------------------------------------------------------------
 */
1156 1157 1158 1159 1160 1161 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

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

1229
/* ----------------
1230
 *		FormIndexDatum
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
 *			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[].
1242 1243 1244
 * ----------------
 */
void
1245
FormIndexDatum(IndexInfo *indexInfo,
1246 1247
			   HeapTuple heapTuple,
			   TupleDesc heapDescriptor,
1248
			   MemoryContext resultCxt,
1249
			   Datum *datum,
1250
			   char *nullv)
1251
{
1252 1253 1254
	MemoryContext oldContext;
	int			i;
	Datum		iDatum;
1255
	bool		isNull;
1256

1257
	oldContext = MemoryContextSwitchTo(resultCxt);
1258

1259
	if (OidIsValid(indexInfo->ii_FuncOid))
1260
	{
1261 1262 1263 1264 1265 1266
		/* ----------------
		 *	Functional index --- compute the single index attribute
		 * ----------------
		 */
		FunctionCallInfoData	fcinfo;
		bool					anynull = false;
1267

1268 1269 1270
		MemSet(&fcinfo, 0, sizeof(fcinfo));
		fcinfo.flinfo = &indexInfo->ii_FuncInfo;
		fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
B
Bruce Momjian 已提交
1271

1272 1273 1274 1275 1276 1277 1278 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
		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' : ' ';
		}
1310
	}
1311 1312

	MemoryContextSwitchTo(oldContext);
1313 1314 1315
}


H
Hiroshi Inoue 已提交
1316 1317 1318 1319
/* --------------------------------------------
 *		Lock class info for update
 * --------------------------------------------
 */
1320 1321 1322
static bool
LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
					   Buffer *buffer, bool confirmCommitted)
H
Hiroshi Inoue 已提交
1323 1324 1325 1326 1327
{
	HeapTuple	classTuple;
	bool		test;
	Relation	relationRelation;

1328 1329 1330 1331 1332
	/*
	 * 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);
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
	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);

1343
	while (1)
H
Hiroshi Inoue 已提交
1344
	{
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
		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;
H
Hiroshi Inoue 已提交
1363 1364 1365 1366
	}
	RelationInvalidateHeapTuple(relationRelation, rtup);
	if (confirmCommitted)
	{
1367 1368
		HeapTupleHeader th = rtup->t_data;

H
Hiroshi Inoue 已提交
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
		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 ?
 * ---------------------------------------------
 */
1383 1384
bool
IndexesAreActive(Oid relid, bool confirmCommitted)
H
Hiroshi Inoue 已提交
1385
{
1386
	HeapTupleData tuple;
H
Hiroshi Inoue 已提交
1387 1388
	Relation	indexRelation;
	Buffer		buffer;
1389 1390
	HeapScanDesc scan;
	ScanKeyData entry;
H
Hiroshi Inoue 已提交
1391 1392 1393 1394
	bool		isactive;

	if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
		elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1395
	if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1396
		((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1397
		elog(ERROR, "relation %u isn't an indexable relation", relid);
H
Hiroshi Inoue 已提交
1398 1399 1400 1401 1402 1403
	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,
1404
						   F_OIDEQ, ObjectIdGetDatum(relid));
H
Hiroshi Inoue 已提交
1405
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
1406
						  1, &entry);
H
Hiroshi Inoue 已提交
1407 1408 1409
	if (!heap_getnext(scan, 0))
		isactive = true;
	heap_endscan(scan);
1410
	heap_close(indexRelation, AccessShareLock);
H
Hiroshi Inoue 已提交
1411 1412 1413 1414
	return isactive;
}

/* ----------------
1415 1416 1417 1418 1419 1420 1421 1422
 *		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.
H
Hiroshi Inoue 已提交
1423 1424 1425
 * ----------------
 */
void
1426
setRelhasindex(Oid relid, bool hasindex)
H
Hiroshi Inoue 已提交
1427 1428 1429
{
	Relation	pg_class;
	HeapTuple	tuple;
1430
	HeapScanDesc pg_class_scan = NULL;
H
Hiroshi Inoue 已提交
1431

1432 1433
	/*
	 * Find the tuple to update in pg_class.
H
Hiroshi Inoue 已提交
1434 1435 1436
	 */
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);

H
Hiroshi Inoue 已提交
1437
#ifdef	OLD_FILE_NAMING
H
Hiroshi Inoue 已提交
1438
	if (!IsIgnoringSystemIndexes())
H
Hiroshi Inoue 已提交
1439 1440 1441
#else
	if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
#endif /* OLD_FILE_NAMING */
H
Hiroshi Inoue 已提交
1442
	{
1443 1444 1445
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
H
Hiroshi Inoue 已提交
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
	}
	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);
1465 1466
		elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
			 relid);
H
Hiroshi Inoue 已提交
1467 1468 1469 1470 1471 1472
	}

	/* ----------------
	 *	Update hasindex in pg_class.
	 * ----------------
	 */
H
Hiroshi Inoue 已提交
1473 1474
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1475
	((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
H
Hiroshi Inoue 已提交
1476 1477
	if (pg_class_scan)
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1478

H
Hiroshi Inoue 已提交
1479 1480
	if (pg_class_scan)
	{
1481
		/* Write the modified tuple in-place */
H
Hiroshi Inoue 已提交
1482
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1483 1484 1485
		/* Send out shared cache inval if necessary */
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
H
Hiroshi Inoue 已提交
1486
		BufferSync();
H
Hiroshi Inoue 已提交
1487 1488 1489
	}
	else
	{
1490
		simple_heap_update(pg_class, &tuple->t_self, tuple);
H
Hiroshi Inoue 已提交
1491

1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
		/* 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);
		}
	}
1503

H
Hiroshi Inoue 已提交
1504 1505 1506 1507 1508
	if (!pg_class_scan)
		heap_freetuple(tuple);
	else
		heap_endscan(pg_class_scan);

1509
	heap_close(pg_class, RowExclusiveLock);
H
Hiroshi Inoue 已提交
1510 1511
}

H
Hiroshi Inoue 已提交
1512 1513 1514 1515 1516 1517 1518 1519
#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;
T
Tom Lane 已提交
1520
	HeapTuple 	classTuple = NULL;
H
Hiroshi Inoue 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
	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;
1540
		simple_heap_update(pg_class, &classTuple->t_self, classTuple);
H
Hiroshi Inoue 已提交
1541
	}
1542
	/* schedule unlinking old relfilenode */
H
Hiroshi Inoue 已提交
1543 1544 1545 1546 1547 1548 1549 1550
	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);
H
Hiroshi Inoue 已提交
1551
	smgrclose(DEFAULT_SMGR, &workrel);
H
Hiroshi Inoue 已提交
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
	/* 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_close(pg_class, NoLock);
H
Hiroshi Inoue 已提交
1575 1576
	if (!in_place_update)
		heap_freetuple(classTuple);
H
Hiroshi Inoue 已提交
1577 1578 1579 1580 1581
	/* Make sure the relfilenode change */
	CommandCounterIncrement();
}
#endif /* OLD_FILE_NAMING */

1582
/* ----------------
1583
 *		UpdateStats
1584 1585 1586
 * ----------------
 */
void
1587
UpdateStats(Oid relid, long reltuples)
1588
{
1589 1590
	Relation	whichRel;
	Relation	pg_class;
1591
	HeapTuple	tuple;
1592 1593 1594 1595 1596 1597 1598 1599
	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];
1600
	HeapScanDesc pg_class_scan = NULL;
H
Hiroshi Inoue 已提交
1601
	bool		in_place_upd;
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620

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

1621 1622 1623
	/*
	 * Can't use heap_open here since we don't know if it's an index...
	 */
1624 1625 1626
	whichRel = RelationIdGetRelation(relid);

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

1629
	/* Grab lock to be held till end of xact (probably redundant...) */
1630 1631
	LockRelation(whichRel, ShareLock);

1632 1633 1634 1635
	/* ----------------
	 * Find the RELATION relation tuple for the given relation.
	 * ----------------
	 */
1636
	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1637

H
Hiroshi Inoue 已提交
1638
#ifdef	OLD_FILE_NAMING
1639
	in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
H
Hiroshi Inoue 已提交
1640
#else
1641
	in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
H
Hiroshi Inoue 已提交
1642
#endif /* OLD_FILE_NAMING */
1643

H
Hiroshi Inoue 已提交
1644
	if (!in_place_upd)
B
Bruce Momjian 已提交
1645
	{
1646 1647 1648
		tuple = SearchSysCacheCopy(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
B
Bruce Momjian 已提交
1649 1650 1651 1652 1653 1654
	}
	else
	{
		ScanKeyData key[1];

		ScanKeyEntryInitialize(&key[0], 0,
1655 1656 1657
							   ObjectIdAttributeNumber,
							   F_OIDEQ,
							   ObjectIdGetDatum(relid));
B
Bruce Momjian 已提交
1658 1659 1660 1661

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

1663
	if (!HeapTupleIsValid(tuple))
1664
	{
H
Hiroshi Inoue 已提交
1665
		if (pg_class_scan)
B
Bruce Momjian 已提交
1666
			heap_endscan(pg_class_scan);
1667
		heap_close(pg_class, RowExclusiveLock);
1668 1669
		elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
			 relid);
1670 1671 1672
	}

	/* ----------------
1673 1674 1675 1676 1677 1678 1679
	 * 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
1680
	 * it is actually sizable.	See also CREATE TABLE in heap.c.
1681 1682 1683 1684
	 * ----------------
	 */
	relpages = RelationGetNumberOfBlocks(whichRel);

1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
	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);
	}

1702 1703 1704 1705 1706 1707 1708 1709
	/*
	 * 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;

1710 1711 1712
	/* ----------------
	 *	Update statistics in pg_class.
	 * ----------------
1713
	 */
H
Hiroshi Inoue 已提交
1714
	if (in_place_upd)
1715 1716 1717
	{
		/*
		 * At bootstrap time, we don't need to worry about concurrency or
1718
		 * visibility of changes, so we cheat.  Also cheat if REINDEX.
1719
		 */
1720
		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
H
Hiroshi Inoue 已提交
1721
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1722 1723
		rd_rel->relpages = relpages;
		rd_rel->reltuples = reltuples;
H
Hiroshi Inoue 已提交
1724
		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1725
		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1726 1727
		if (!IsBootstrapProcessingMode())
			RelationInvalidateHeapTuple(pg_class, tuple);
1728 1729 1730
	}
	else
	{
1731 1732 1733 1734 1735 1736 1737 1738 1739
		/* 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;
		}

1740 1741 1742 1743
		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;
1744
		newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1745
		simple_heap_update(pg_class, &tuple->t_self, newtup);
H
Hiroshi Inoue 已提交
1746 1747 1748 1749 1750 1751
		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);
		}
1752
		heap_freetuple(newtup);
1753 1754
	}

H
Hiroshi Inoue 已提交
1755
	if (!pg_class_scan)
1756
		heap_freetuple(tuple);
B
Bruce Momjian 已提交
1757 1758
	else
		heap_endscan(pg_class_scan);
1759

1760 1761
	heap_close(pg_class, RowExclusiveLock);
	/* Cheating a little bit since we didn't open it with heap_open... */
1762
	heap_close(whichRel, NoLock);
1763 1764 1765 1766
}


/* ----------------
1767
 *		DefaultBuild
1768 1769 1770 1771 1772
 *
 * 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?
1773 1774 1775 1776
 * ----------------
 */
static void
DefaultBuild(Relation heapRelation,
1777
			 Relation indexRelation,
1778 1779
			 IndexInfo *indexInfo,
			 Node *oldPred,
1780
			 IndexStrategy indexStrategy) /* not used */
1781
{
1782 1783 1784
	HeapScanDesc scan;
	HeapTuple	heapTuple;
	TupleDesc	heapDescriptor;
1785 1786
	Datum		datum[INDEX_MAX_KEYS];
	char		nullv[INDEX_MAX_KEYS];
1787 1788
	long		reltuples,
				indtuples;
1789
	Node	   *predicate = indexInfo->ii_Predicate;
1790
#ifndef OMIT_PARTIAL_INDEX
1791
	TupleTable	tupleTable;
1792
	TupleTableSlot *slot;
1793
#endif
1794
	ExprContext *econtext;
1795 1796 1797 1798 1799 1800 1801 1802
	InsertIndexResult insertResult;

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

1803
	heapDescriptor = RelationGetDescr(heapRelation);
1804 1805 1806 1807 1808 1809

	/*
	 * 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
1810 1811 1812 1813
	 * 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
1814
	 */
1815
#ifndef OMIT_PARTIAL_INDEX
1816 1817 1818 1819
	if (predicate != NULL || oldPred != NULL)
	{
		tupleTable = ExecCreateTupleTable(1);
		slot = ExecAllocTableSlot(tupleTable);
1820
		ExecSetSlotDescriptor(slot, heapDescriptor, false);
1821
	}
M
Marc G. Fournier 已提交
1822 1823
	else
	{
1824
		tupleTable = NULL;
M
Marc G. Fournier 已提交
1825 1826
		slot = NULL;
	}
1827 1828 1829
	econtext = MakeExprContext(slot, TransactionCommandContext);
#else
	econtext = MakeExprContext(NULL, TransactionCommandContext);
1830
#endif	 /* OMIT_PARTIAL_INDEX */
1831 1832 1833 1834

	/* ----------------
	 *	Ok, begin our scan of the base relation.
	 * ----------------
1835
	 */
1836 1837
	scan = heap_beginscan(heapRelation, /* relation */
						  0,	/* start at end */
1838
						  SnapshotNow,	/* seeself */
1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850
						  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.
	 * ----------------
	 */
1851
	while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1852
	{
1853 1854
		MemoryContextReset(econtext->ecxt_per_tuple_memory);

1855 1856
		reltuples++;

1857
#ifndef OMIT_PARTIAL_INDEX
1858 1859 1860 1861 1862 1863 1864
		/*
		 * 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;
1865
			if (ExecQual((List *) oldPred, econtext, false))
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
			{
				indtuples++;
				continue;
			}
		}

		/*
		 * Skip this tuple if it doesn't satisfy the partial-index
		 * predicate
		 */
		if (predicate != NULL)
		{
			slot->val = heapTuple;
1879
			if (!ExecQual((List *) predicate, econtext, false))
1880 1881
				continue;
		}
1882
#endif	 /* OMIT_PARTIAL_INDEX */
1883

1884
		indtuples++;
1885 1886 1887 1888 1889 1890

		/* ----------------
		 *	FormIndexDatum fills in its datum and null parameters
		 *	with attribute information taken from the given heap tuple.
		 * ----------------
		 */
1891 1892 1893 1894 1895 1896
		FormIndexDatum(indexInfo,
					   heapTuple,
					   heapDescriptor,
					   econtext->ecxt_per_tuple_memory,
					   datum,
					   nullv);
1897 1898

		insertResult = index_insert(indexRelation, datum, nullv,
1899
									&(heapTuple->t_self), heapRelation);
1900 1901 1902

		if (insertResult)
			pfree(insertResult);
1903
	}
1904 1905 1906

	heap_endscan(scan);

1907
#ifndef OMIT_PARTIAL_INDEX
1908 1909
	if (predicate != NULL || oldPred != NULL)
	{
1910
		ExecDropTupleTable(tupleTable, true);
1911
	}
1912
#endif	 /* OMIT_PARTIAL_INDEX */
1913
	FreeExprContext(econtext);
1914 1915

	/*
1916 1917
	 * 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
1918 1919 1920 1921 1922 1923 1924
	 * 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.
1925 1926
	 */
	if (IsNormalProcessingMode())
1927
	{
1928 1929
		Oid			hrelid = RelationGetRelid(heapRelation);
		Oid			irelid = RelationGetRelid(indexRelation);
1930 1931 1932

		heap_close(heapRelation, NoLock);
		index_close(indexRelation);
1933 1934
		UpdateStats(hrelid, reltuples);
		UpdateStats(irelid, indtuples);
1935 1936 1937 1938
		if (oldPred != NULL)
		{
			if (indtuples == reltuples)
				predicate = NULL;
1939
			UpdateIndexPredicate(irelid, oldPred, predicate);
1940
		}
1941
	}
1942 1943 1944
}

/* ----------------
1945
 *		index_build
1946 1947 1948 1949
 * ----------------
 */
void
index_build(Relation heapRelation,
1950
			Relation indexRelation,
1951 1952
			IndexInfo *indexInfo,
			Node *oldPred)
1953
{
1954
	RegProcedure procedure;
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965

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

	procedure = indexRelation->rd_am->ambuild;

	/* ----------------
1966
	 *	use the access method build procedure if supplied, else default.
1967 1968 1969
	 * ----------------
	 */
	if (RegProcedureIsValid(procedure))
1970
		OidFunctionCall5(procedure,
1971 1972
						 PointerGetDatum(heapRelation),
						 PointerGetDatum(indexRelation),
1973 1974
						 PointerGetDatum(indexInfo),
						 PointerGetDatum(oldPred),
1975
						 PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
1976 1977 1978
	else
		DefaultBuild(heapRelation,
					 indexRelation,
1979 1980
					 indexInfo,
					 oldPred,
1981
					 RelationGetIndexStrategy(indexRelation));
1982 1983
}

1984 1985
/*
 * IndexGetRelation: given an index's relation OID, get the OID of the
1986
 * relation it is an index on.	Uses the system cache.
1987 1988 1989 1990 1991 1992
 */
static Oid
IndexGetRelation(Oid indexId)
{
	HeapTuple	tuple;
	Form_pg_index index;
1993
	Oid			result;
1994

1995 1996 1997
	tuple = SearchSysCache(INDEXRELID,
						   ObjectIdGetDatum(indexId),
						   0, 0, 0);
1998 1999 2000 2001 2002 2003
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "IndexGetRelation: can't find index id %u",
			 indexId);
	index = (Form_pg_index) GETSTRUCT(tuple);
	Assert(index->indexrelid == indexId);

2004 2005 2006
	result = index->indrelid;
	ReleaseSysCache(tuple);
	return result;
2007 2008
}

H
Hiroshi Inoue 已提交
2009 2010
/* ---------------------------------
 * activate_index -- activate/deactivate the specified index.
2011
 *		Note that currently PostgreSQL doesn't hold the
H
Hiroshi Inoue 已提交
2012 2013 2014
 *		status per index
 * ---------------------------------
 */
2015
static bool
H
Hiroshi Inoue 已提交
2016
activate_index(Oid indexId, bool activate, bool inplace)
H
Hiroshi Inoue 已提交
2017
{
2018
	if (!activate)				/* Currently does nothing */
H
Hiroshi Inoue 已提交
2019
		return true;
H
Hiroshi Inoue 已提交
2020
	return reindex_index(indexId, false, inplace);
H
Hiroshi Inoue 已提交
2021
}
2022

H
Hiroshi Inoue 已提交
2023 2024 2025 2026 2027
/* --------------------------------
 * reindex_index - This routine is used to recreate an index
 * --------------------------------
 */
bool
H
Hiroshi Inoue 已提交
2028
reindex_index(Oid indexId, bool force, bool inplace)
H
Hiroshi Inoue 已提交
2029
{
2030 2031 2032 2033 2034 2035 2036
	Relation	iRel,
				indexRelation,
				heapRelation;
	ScanKeyData entry;
	HeapScanDesc scan;
	HeapTuple	indexTuple,
				classTuple;
2037
	IndexInfo  *indexInfo;
2038 2039
	Oid			heapId,
				accessMethodId;
H
Hiroshi Inoue 已提交
2040 2041
	bool		old;

2042 2043 2044 2045 2046 2047 2048 2049 2050
	/* ----------------
	 *	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");

H
Hiroshi Inoue 已提交
2051
	old = SetReindexProcessing(true);
2052 2053

	/* Scan pg_index to find the index's pg_index entry */
H
Hiroshi Inoue 已提交
2054 2055 2056 2057 2058 2059
	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))
2060
		elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
H
Hiroshi Inoue 已提交
2061

2062 2063 2064 2065
	/* Get OID of index's parent table */
	heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
	/* Fetch info needed for index_build */
	indexInfo = BuildIndexInfo(indexTuple);
H
Hiroshi Inoue 已提交
2066

2067 2068 2069
	/* Complete the scan and close pg_index */
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
H
Hiroshi Inoue 已提交
2070 2071

	/* Fetch the classTuple associated with this index */
2072 2073 2074
	classTuple = SearchSysCache(RELOID,
								ObjectIdGetDatum(indexId),
								0, 0, 0);
H
Hiroshi Inoue 已提交
2075
	if (!HeapTupleIsValid(classTuple))
2076
		elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
H
Hiroshi Inoue 已提交
2077
	accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
2078
	ReleaseSysCache(classTuple);
H
Hiroshi Inoue 已提交
2079 2080 2081 2082 2083

	/* Open our index relation */
	heapRelation = heap_open(heapId, ExclusiveLock);
	if (heapRelation == NULL)
		elog(ERROR, "reindex_index: can't open heap relation");
2084 2085 2086
	iRel = index_open(indexId);
	if (iRel == NULL)
		elog(ERROR, "reindex_index: can't open index relation");
H
Hiroshi Inoue 已提交
2087

H
Hiroshi Inoue 已提交
2088 2089
#ifndef OLD_FILE_NAMING
	if (!inplace)
2090 2091 2092 2093 2094 2095
        {
                inplace = IsSharedSystemRelationName(NameStr(iRel->rd_rel->relna
me));
		if (!inplace)
			setNewRelfilenode(iRel);
	}
H
Hiroshi Inoue 已提交
2096
#endif /* OLD_FILE_NAMING */
H
Hiroshi Inoue 已提交
2097 2098 2099
	/* Obtain exclusive lock on it, just to be sure */
	LockRelation(iRel, AccessExclusiveLock);

H
Hiroshi Inoue 已提交
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
	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;
	}
H
Hiroshi Inoue 已提交
2112 2113

	/* Initialize the index and rebuild */
2114 2115
	InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
	index_build(heapRelation, iRel, indexInfo, NULL);
H
Hiroshi Inoue 已提交
2116 2117

	/*
2118
	 * index_build will close both the heap and index relations (but not
2119
	 * give up the locks we hold on them).  So we're done.
H
Hiroshi Inoue 已提交
2120 2121 2122
	 */

	SetReindexProcessing(old);
2123

H
Hiroshi Inoue 已提交
2124 2125 2126 2127 2128
	return true;
}

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

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

H
Hiroshi Inoue 已提交
2168 2169 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
	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 */
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217
	/*
	 * Shared system indexes must be overwritten because it's
	 * impossible to update pg_class tuples of all databases.
	 */
	if (IsSharedSystemRelationName(NameStr(rel->rd_rel->relname)))
	{
		if (IsIgnoringSystemIndexes())
		{
			overwrite = true;
			deactivate_needed = true;
		}
		else
			elog(ERROR, "the target relation %u is shared", relid);
	}
H
Hiroshi Inoue 已提交
2218 2219
	RelationClose(rel);
#endif /* OLD_FILE_NAMING */
H
Hiroshi Inoue 已提交
2220
	old = SetReindexProcessing(true);
H
Hiroshi Inoue 已提交
2221
	if (deactivate_needed)
H
Hiroshi Inoue 已提交
2222
	{
H
Hiroshi Inoue 已提交
2223
		if (IndexesAreActive(relid, upd_pg_class_inplace))
H
Hiroshi Inoue 已提交
2224
		{
H
Hiroshi Inoue 已提交
2225 2226 2227 2228 2229 2230 2231
			if (!force)
			{
				SetReindexProcessing(old);
				return false;
			}
			activate_indexes_of_a_table(relid, false);
			CommandCounterIncrement();
H
Hiroshi Inoue 已提交
2232 2233 2234 2235 2236
		}
	}

	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2237
						   F_OIDEQ, ObjectIdGetDatum(relid));
H
Hiroshi Inoue 已提交
2238
	scan = heap_beginscan(indexRelation, false, SnapshotNow,
2239
						  1, &entry);
H
Hiroshi Inoue 已提交
2240 2241 2242
	reindexed = false;
	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
	{
2243 2244
		Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);

H
Hiroshi Inoue 已提交
2245
		if (activate_index(index->indexrelid, true, overwrite))
H
Hiroshi Inoue 已提交
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255
			reindexed = true;
		else
		{
			reindexed = false;
			break;
		}
	}
	heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
	if (reindexed)
H
Hiroshi Inoue 已提交
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
	/*
	 * 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);
		}
	}
H
Hiroshi Inoue 已提交
2279
	SetReindexProcessing(old);
H
Hiroshi Inoue 已提交
2280

2281
	return reindexed;
H
Hiroshi Inoue 已提交
2282
}