execUtils.c 28.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * execUtils.c
4
 *	  miscellaneous executor utility routines
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.63 2000/07/12 02:37:03 tgl Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
17
 *		ExecAssignExprContext	Common code for plan node init routines.
18
 *
19 20 21 22 23 24
 *		ExecGetTypeInfo			  |  old execCStructs interface
 *		ExecMakeTypeInfo		  |  code from the version 1
 *		ExecOrderTypeInfo		  |  lisp system.  These should
 *		ExecSetTypeInfo			  |  go away or be updated soon.
 *		ExecFreeTypeInfo		  |  -cim 11/1/89
 *		ExecTupleAttributes		/
25 26
 *

27 28
 *		QueryDescGetTypeInfo - moved here from main.c
 *								am not sure what uses it -cim 10/12/89
29
 *
30 31 32 33 34 35 36 37 38
 *		ExecGetIndexKeyInfo		\
 *		ExecOpenIndices			 | referenced by InitPlan, EndPlan,
 *		ExecCloseIndices		 | ExecAppend, ExecReplace
 *		ExecFormIndexTuple		 |
 *		ExecInsertIndexTuple	/
 *
 *	 NOTES
 *		This file has traditionally been the place to stick misc.
 *		executor support stuff that doesn't really go anyplace else.
39 40 41
 *
 */

42 43
#include "postgres.h"

44
#include "access/genam.h"
B
Bruce Momjian 已提交
45
#include "access/heapam.h"
46
#include "catalog/catname.h"
B
Bruce Momjian 已提交
47
#include "catalog/index.h"
H
Hiroshi Inoue 已提交
48
#include "catalog/catalog.h"
B
Bruce Momjian 已提交
49
#include "catalog/pg_index.h"
B
Bruce Momjian 已提交
50
#include "executor/execdebug.h"
H
Hiroshi Inoue 已提交
51
#include "miscadmin.h"
52 53
#include "utils/builtins.h"
#include "utils/fmgroids.h"
54
#include "utils/memutils.h"
55 56
#include "utils/relcache.h"
#include "utils/syscache.h"
57

58
static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
B
Bruce Momjian 已提交
59
					AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
60

61
/* ----------------------------------------------------------------
62 63
 *		global counters for number of tuples processed, retrieved,
 *		appended, replaced, deleted.
64 65
 * ----------------------------------------------------------------
 */
66 67 68 69 70 71 72
int			NTupleProcessed;
int			NTupleRetrieved;
int			NTupleReplaced;
int			NTupleAppended;
int			NTupleDeleted;
int			NIndexTupleInserted;
extern int	NIndexTupleProcessed;		/* have to be defined in the
73 74
										 * access method level so that the
										 * cinterface.a will link ok. */
75 76

/* ----------------------------------------------------------------
77
 *						statistic functions
78 79 80 81
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
82
 *		ResetTupleCount
83 84
 * ----------------------------------------------------------------
 */
85
#ifdef NOT_USED
86
void
87
ResetTupleCount(void)
88
{
89 90 91 92 93 94
	NTupleProcessed = 0;
	NTupleRetrieved = 0;
	NTupleAppended = 0;
	NTupleDeleted = 0;
	NTupleReplaced = 0;
	NIndexTupleProcessed = 0;
95
}
96

97
#endif
98 99

/* ----------------------------------------------------------------
100
 *		PrintTupleCount
101 102
 * ----------------------------------------------------------------
 */
103
#ifdef NOT_USED
104
void
105
DisplayTupleCount(FILE *statfp)
106
{
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
	if (NTupleProcessed > 0)
		fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
				(NTupleProcessed == 1) ? "" : "s");
	else
	{
		fprintf(statfp, "!\tno tuples processed.\n");
		return;
	}
	if (NIndexTupleProcessed > 0)
		fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
				(NIndexTupleProcessed == 1) ? "" : "s");
	if (NIndexTupleInserted > 0)
		fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
				(NIndexTupleInserted == 1) ? "" : "s");
	if (NTupleRetrieved > 0)
		fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
				(NTupleRetrieved == 1) ? "" : "s");
	if (NTupleAppended > 0)
		fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
				(NTupleAppended == 1) ? "" : "s");
	if (NTupleDeleted > 0)
		fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
				(NTupleDeleted == 1) ? "" : "s");
	if (NTupleReplaced > 0)
		fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
				(NTupleReplaced == 1) ? "" : "s");
	fprintf(statfp, "\n");
134
}
135

136
#endif
137 138

/* ----------------------------------------------------------------
139
 *				 miscellaneous node-init support functions
140
 *
141
 *		ExecAssignExprContext	- assigns the node's expression context
142 143 144 145
 * ----------------------------------------------------------------
 */

/* ----------------
146 147 148 149 150 151
 *		ExecAssignExprContext
 *
 *		This initializes the ExprContext field.  It is only necessary
 *		to do this for nodes which use ExecQual or ExecProject
 *		because those routines depend on econtext.	Other nodes that
 *		don't have to evaluate expressions don't need to do this.
152
 *
153 154
 * Note: we assume CurrentMemoryContext is the correct per-query context.
 * This should be true during plan node initialization.
155 156 157
 * ----------------
 */
void
158
ExecAssignExprContext(EState *estate, CommonState *commonstate)
159
{
160
	ExprContext *econtext = makeNode(ExprContext);
161

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	econtext->ecxt_scantuple = NULL;
	econtext->ecxt_innertuple = NULL;
	econtext->ecxt_outertuple = NULL;
	econtext->ecxt_per_query_memory = CurrentMemoryContext;
	/*
	 * Create working memory for expression evaluation in this context.
	 */
	econtext->ecxt_per_tuple_memory =
		AllocSetContextCreate(CurrentMemoryContext,
							  "PlanExprContext",
							  ALLOCSET_DEFAULT_MINSIZE,
							  ALLOCSET_DEFAULT_INITSIZE,
							  ALLOCSET_DEFAULT_MAXSIZE);
	econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
	econtext->ecxt_param_list_info = estate->es_param_list_info;
	econtext->ecxt_aggvalues = NULL;
	econtext->ecxt_aggnulls = NULL;
	econtext->ecxt_range_table = estate->es_range_table;

	commonstate->cs_ExprContext = econtext;
182 183 184
}

/* ----------------
185
 *		MakeExprContext
186
 *
187 188 189 190
 *		Build an expression context for use outside normal plan-node cases.
 *		A fake scan-tuple slot can be supplied (pass NULL if not needed).
 *		A memory context sufficiently long-lived to use as fcache context
 *		must be supplied as well.
191 192
 * ----------------
 */
193 194 195
ExprContext *
MakeExprContext(TupleTableSlot *slot,
				MemoryContext queryContext)
196
{
197
	ExprContext *econtext = makeNode(ExprContext);
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
	econtext->ecxt_scantuple = slot;
	econtext->ecxt_innertuple = NULL;
	econtext->ecxt_outertuple = NULL;
	econtext->ecxt_per_query_memory = queryContext;
	/*
	 * We make the temporary context a child of current working context,
	 * not of the specified queryContext.  This seems reasonable but I'm
	 * not totally sure about it...
	 *
	 * Expression contexts made via this routine typically don't live long
	 * enough to get reset, so specify a minsize of 0.  That avoids alloc'ing
	 * any memory in the common case where expr eval doesn't use any.
	 */
	econtext->ecxt_per_tuple_memory =
		AllocSetContextCreate(CurrentMemoryContext,
							  "TempExprContext",
							  0,
							  ALLOCSET_DEFAULT_INITSIZE,
							  ALLOCSET_DEFAULT_MAXSIZE);
	econtext->ecxt_param_exec_vals = NULL;
	econtext->ecxt_param_list_info = NULL;
	econtext->ecxt_aggvalues = NULL;
	econtext->ecxt_aggnulls = NULL;
	econtext->ecxt_range_table = NIL;

	return econtext;
}
226

227 228 229 230 231 232 233 234 235 236
/*
 * Free an ExprContext made by MakeExprContext, including the temporary
 * context used for expression evaluation.  Note this will cause any
 * pass-by-reference expression result to go away!
 */
void
FreeExprContext(ExprContext *econtext)
{
	MemoryContextDelete(econtext->ecxt_per_tuple_memory);
	pfree(econtext);
237 238 239
}

/* ----------------------------------------------------------------
240
 *		Result slot tuple type and ProjectionInfo support
241 242 243 244
 * ----------------------------------------------------------------
 */

/* ----------------
245
 *		ExecAssignResultType
246 247 248
 * ----------------
 */
void
249
ExecAssignResultType(CommonState *commonstate,
250
					 TupleDesc tupDesc)
251
{
252 253 254 255
	TupleTableSlot *slot;

	slot = commonstate->cs_ResultTupleSlot;
	slot->ttc_tupleDescriptor = tupDesc;
256 257 258
}

/* ----------------
259
 *		ExecAssignResultTypeFromOuterPlan
260 261 262
 * ----------------
 */
void
263
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
264
{
265 266
	Plan	   *outerPlan;
	TupleDesc	tupDesc;
267 268 269 270 271

	outerPlan = outerPlan(node);
	tupDesc = ExecGetTupType(outerPlan);

	ExecAssignResultType(commonstate, tupDesc);
272 273 274
}

/* ----------------
275
 *		ExecAssignResultTypeFromTL
276 277 278
 * ----------------
 */
void
279
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
280
{
281 282 283 284 285 286 287
	List	   *targetList;
	int			i;
	int			len;
	List	   *tl;
	TargetEntry *tle;
	List	   *fjtl;
	TupleDesc	origTupDesc;
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

	targetList = node->targetlist;
	origTupDesc = ExecTypeFromTL(targetList);
	len = ExecTargetListLength(targetList);

	fjtl = NIL;
	tl = targetList;
	i = 0;
	while (tl != NIL || fjtl != NIL)
	{
		if (fjtl != NIL)
		{
			tle = lfirst(fjtl);
			fjtl = lnext(fjtl);
		}
		else
		{
			tle = lfirst(tl);
			tl = lnext(tl);
		}
308
#ifdef SETS_FIXED
309 310
		if (!tl_is_resdom(tle))
		{
311
			Fjoin	   *fj = (Fjoin *) lfirst(tle);
312 313 314 315 316

			/* it is a FJoin */
			fjtl = lnext(tle);
			tle = fj->fj_innerNode;
		}
317
#endif
318 319
		i++;
	}
320

321 322 323 324 325 326 327 328
	if (len > 0)
	{
		ExecAssignResultType(commonstate,
							 origTupDesc);
	}
	else
		ExecAssignResultType(commonstate,
							 (TupleDesc) NULL);
329 330 331
}

/* ----------------
332
 *		ExecGetResultType
333 334 335
 * ----------------
 */
TupleDesc
336
ExecGetResultType(CommonState *commonstate)
337
{
338 339 340
	TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;

	return slot->ttc_tupleDescriptor;
341 342 343
}

/* ----------------
344
 *		ExecFreeResultType
345 346
 * ----------------
 */
347
#ifdef NOT_USED
348
void
349
ExecFreeResultType(CommonState *commonstate)
350
{
351
	TupleTableSlot *slot;
352
	TupleDesc	tupType;
353 354 355 356

	slot = commonstate->cs_ResultTupleSlot;
	tupType = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
357
	ExecFreeTypeInfo(tupType);
358
}
359

360
#endif
361 362

/* ----------------
363 364
 *		ExecAssignProjectionInfo
		  forms the projection information from the node's targetlist
365 366 367
 * ----------------
 */
void
368
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
369
{
370
	ProjectionInfo *projInfo;
371 372
	List	   *targetList;
	int			len;
373 374 375 376 377 378 379

	targetList = node->targetlist;
	len = ExecTargetListLength(targetList);

	projInfo = makeNode(ProjectionInfo);
	projInfo->pi_targetlist = targetList;
	projInfo->pi_len = len;
380
	projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
381 382 383 384
	projInfo->pi_exprContext = commonstate->cs_ExprContext;
	projInfo->pi_slot = commonstate->cs_ResultTupleSlot;

	commonstate->cs_ProjInfo = projInfo;
385 386 387 388
}


/* ----------------
389
 *		ExecFreeProjectionInfo
390 391 392
 * ----------------
 */
void
393
ExecFreeProjectionInfo(CommonState *commonstate)
394
{
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
	ProjectionInfo *projInfo;

	/* ----------------
	 *	get projection info.  if NULL then this node has
	 *	none so we just return.
	 * ----------------
	 */
	projInfo = commonstate->cs_ProjInfo;
	if (projInfo == NULL)
		return;

	/* ----------------
	 *	clean up memory used.
	 * ----------------
	 */
	if (projInfo->pi_tupValue != NULL)
		pfree(projInfo->pi_tupValue);

	pfree(projInfo);
	commonstate->cs_ProjInfo = NULL;
415 416
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
/* ----------------
 *		ExecFreeExprContext
 * ----------------
 */
void
ExecFreeExprContext(CommonState *commonstate)
{
	ExprContext *econtext;

	/* ----------------
	 *	get expression context.  if NULL then this node has
	 *	none so we just return.
	 * ----------------
	 */
	econtext = commonstate->cs_ExprContext;
	if (econtext == NULL)
		return;

	/* ----------------
	 *	clean up memory used.
	 * ----------------
	 */
439
	MemoryContextDelete(econtext->ecxt_per_tuple_memory);
440 441 442 443 444 445 446 447
	pfree(econtext);
	commonstate->cs_ExprContext = NULL;
}

/* ----------------
 *		ExecFreeTypeInfo
 * ----------------
 */
448
#ifdef NOT_USED
449 450 451
void
ExecFreeTypeInfo(CommonState *commonstate)
{
B
Bruce Momjian 已提交
452
	TupleDesc	tupDesc;
453 454 455 456 457 458 459 460 461 462 463 464

	tupDesc = commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor;
	if (tupDesc == NULL)
		return;

	/* ----------------
	 *	clean up memory used.
	 * ----------------
	 */
	FreeTupleDesc(tupDesc);
	commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL;
}
465
#endif
466

467
/* ----------------------------------------------------------------
468 469 470 471 472 473
 *		the following scan type support functions are for
 *		those nodes which are stubborn and return tuples in
 *		their Scan tuple slot instead of their Result tuple
 *		slot..	luck fur us, these nodes do not do projections
 *		so we don't have to worry about getting the ProjectionInfo
 *		right for them...  -cim 6/3/91
474 475 476 477
 * ----------------------------------------------------------------
 */

/* ----------------
478
 *		ExecGetScanType
479 480 481
 * ----------------
 */
TupleDesc
482
ExecGetScanType(CommonScanState *csstate)
483
{
484 485 486
	TupleTableSlot *slot = csstate->css_ScanTupleSlot;

	return slot->ttc_tupleDescriptor;
487 488 489
}

/* ----------------
490
 *		ExecFreeScanType
491 492
 * ----------------
 */
493
#ifdef NOT_USED
494
void
495
ExecFreeScanType(CommonScanState *csstate)
496
{
497
	TupleTableSlot *slot;
498
	TupleDesc	tupType;
499 500 501 502

	slot = csstate->css_ScanTupleSlot;
	tupType = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
503
	ExecFreeTypeInfo(tupType);
504
}
505

506
#endif
507 508

/* ----------------
509
 *		ExecAssignScanType
510 511 512
 * ----------------
 */
void
513
ExecAssignScanType(CommonScanState *csstate,
514
				   TupleDesc tupDesc)
515
{
516 517 518 519
	TupleTableSlot *slot;

	slot = (TupleTableSlot *) csstate->css_ScanTupleSlot;
	slot->ttc_tupleDescriptor = tupDesc;
520 521 522
}

/* ----------------
523
 *		ExecAssignScanTypeFromOuterPlan
524 525 526
 * ----------------
 */
void
527
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
528
{
529 530
	Plan	   *outerPlan;
	TupleDesc	tupDesc;
531 532 533

	outerPlan = outerPlan(node);
	tupDesc = ExecGetTupType(outerPlan);
534

535
	ExecAssignScanType(csstate, tupDesc);
536 537 538 539
}


/* ----------------------------------------------------------------
540
 *		ExecTypeFromTL support routines.
541
 *
542 543
 *		these routines are used mainly from ExecTypeFromTL.
 *		-cim 6/12/90
544 545
 *
 * old comments
546 547
 *		Routines dealing with the structure 'attribute' which conatains
 *		the type information about attributes in a tuple:
548
 *
B
Bruce Momjian 已提交
549
 *		ExecMakeTypeInfo(noType)
550
 *				returns pointer to array of 'noType' structure 'attribute'.
B
Bruce Momjian 已提交
551
 *		ExecSetTypeInfo(index, typeInfo, attNum, attLen)
552 553
 *				sets the element indexed by 'index' in typeInfo with
 *				the values: attNum, attLen.
B
Bruce Momjian 已提交
554
 *		ExecFreeTypeInfo(typeInfo)
555
 *				frees the structure 'typeInfo'.
556 557 558 559
 * ----------------------------------------------------------------
 */

/* ----------------
560
 *		ExecSetTypeInfo
561
 *
562 563
 *		This initializes fields of a single attribute in a
 *		tuple descriptor from the specified parameters.
564
 *
565 566 567
 *		XXX this duplicates much of the functionality of TupleDescInitEntry.
 *			the routines should be moved to the same place and be rewritten
 *			to share common code.
568 569
 * ----------------
 */
570
#ifdef NOT_USED
571 572
void
ExecSetTypeInfo(int index,
573 574 575 576 577 578 579
				TupleDesc typeInfo,
				Oid typeID,
				int attNum,
				int attLen,
				char *attName,
				bool attbyVal,
				char attalign)
580
{
581
	Form_pg_attribute att;
582 583 584 585 586 587 588

	/* ----------------
	 *	get attribute pointer and preform a sanity check..
	 * ----------------
	 */
	att = typeInfo[index];
	if (att == NULL)
589
		elog(ERROR, "ExecSetTypeInfo: trying to assign through NULL");
590 591 592 593 594 595 596 597 598 599 600 601 602 603

	/* ----------------
	 *	assign values to the tuple descriptor, being careful not
	 *	to copy a null attName..
	 *
	 *	XXX it is unknown exactly what information is needed to
	 *		initialize the attribute struct correctly so for now
	 *		we use 0.  this should be fixed -- otherwise we run the
	 *		risk of using garbage data. -cim 5/5/91
	 * ----------------
	 */
	att->attrelid = 0;			/* dummy value */

	if (attName != (char *) NULL)
604
		StrNCpy(NameStr(att->attname), attName, NAMEDATALEN);
605
	else
606
		MemSet(NameStr(att->attname), 0, NAMEDATALEN);
607 608 609 610 611 612 613 614 615 616 617 618 619

	att->atttypid = typeID;
	att->attdefrel = 0;			/* dummy value */
	att->attdisbursion = 0;		/* dummy value */
	att->atttyparg = 0;			/* dummy value */
	att->attlen = attLen;
	att->attnum = attNum;
	att->attbound = 0;			/* dummy value */
	att->attbyval = attbyVal;
	att->attcanindex = 0;		/* dummy value */
	att->attproc = 0;			/* dummy value */
	att->attnelems = 0;			/* dummy value */
	att->attcacheoff = -1;
B
Bruce Momjian 已提交
620
	att->atttypmod = -1;
621
	att->attisset = false;
622
	att->attstorage = 'p';
623
	att->attalign = attalign;
624 625 626
}

/* ----------------
627 628
 *		ExecFreeTypeInfo frees the array of attrbutes
 *		created by ExecMakeTypeInfo and returned by ExecTypeFromTL...
629 630 631 632 633
 * ----------------
 */
void
ExecFreeTypeInfo(TupleDesc typeInfo)
{
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
	/* ----------------
	 *	do nothing if asked to free a null pointer
	 * ----------------
	 */
	if (typeInfo == NULL)
		return;

	/* ----------------
	 *	the entire array of typeinfo pointers created by
	 *	ExecMakeTypeInfo was allocated with a single palloc()
	 *	so we can deallocate the whole array with a single pfree().
	 *	(we should not try and free all the elements in the array)
	 *	-cim 6/12/90
	 * ----------------
	 */
	pfree(typeInfo);
650 651 652 653
}


/* ----------------------------------------------------------------
654
 *		QueryDescGetTypeInfo
655
 *
656 657
 *|		I don't know how this is used, all I know is that it
 *|		appeared one day in main.c so I moved it here. -cim 11/1/89
658 659 660
 * ----------------------------------------------------------------
 */
TupleDesc
661
QueryDescGetTypeInfo(QueryDesc *queryDesc)
662
{
663 664 665 666
	Plan	   *plan;
	TupleDesc	tupleType;
	List	   *targetList;
	AttrInfo   *attinfo = (AttrInfo *) palloc(sizeof(AttrInfo));
667 668 669

	plan = queryDesc->plantree;
	tupleType = (TupleDesc) ExecGetTupType(plan);
670
/*
671
	targetList =  plan->targetlist;
672

673 674
	attinfo->numAttr = ExecTargetListLength(targetList);
	attinfo->attrs = tupleType;
675
*/
676 677 678
	attinfo->numAttr = tupleType->natts;
	attinfo->attrs = tupleType->attrs;
	return attinfo;
679
}
680

681 682 683
#endif

/* ----------------------------------------------------------------
684
 *				  ExecInsertIndexTuples support
685 686 687
 * ----------------------------------------------------------------
 */
/* ----------------------------------------------------------------
688
 *		ExecGetIndexKeyInfo
689
 *
690 691 692 693 694
 *		Extracts the index key attribute numbers from
 *		an index tuple form (i.e. a tuple from the pg_index relation)
 *		into an array of attribute numbers.  The array and the
 *		size of the array are returned to the caller via return
 *		parameters.
695 696
 * ----------------------------------------------------------------
 */
697
static void
698
ExecGetIndexKeyInfo(Form_pg_index indexTuple,
699
					int *numAttsOutP,
B
Bruce Momjian 已提交
700
					AttrNumber **attsOutP,
701
					FuncIndexInfoPtr fInfoP)
702
{
703 704 705
	int			i;
	int			numKeys;
	AttrNumber *attKeys;
706 707

	/* ----------------
708
	 *	check parameters
709 710
	 * ----------------
	 */
711
	if (numAttsOutP == NULL || attsOutP == NULL)
712 713 714 715 716
	{
		elog(DEBUG, "ExecGetIndexKeyInfo: %s",
		"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
	}

717
	/* ----------------
718
	 * set the procid for a possible functional index.
719 720
	 * ----------------
	 */
721 722
	FIsetProcOid(fInfoP, indexTuple->indproc);

723
	/* ----------------
724
	 *	count the number of keys..
725 726
	 * ----------------
	 */
727
	numKeys = 0;
B
Bruce Momjian 已提交
728
	for (i = 0; i < INDEX_MAX_KEYS &&
B
Bruce Momjian 已提交
729
		 indexTuple->indkey[i] != InvalidAttrNumber; i++)
730 731
		numKeys++;

732
	/* ----------------
733 734 735 736 737 738
	 *	place number keys in callers return area
	 *	or the number of arguments for a functional index.
	 *
	 *	If we have a functional index then the number of
	 *	attributes defined in the index must 1 (the function's
	 *	single return value).
739 740
	 * ----------------
	 */
741 742 743 744 745 746 747 748 749 750 751 752 753 754
	if (FIgetProcOid(fInfoP) != InvalidOid)
	{
		FIsetnArgs(fInfoP, numKeys);
		(*numAttsOutP) = 1;
	}
	else
		(*numAttsOutP) = numKeys;

	if (numKeys < 1)
	{
		elog(DEBUG, "ExecGetIndexKeyInfo: %s",
			 "all index key attribute numbers are zero!");
		(*attsOutP) = NULL;
		return;
755
	}
756

757
	/* ----------------
758
	 *	allocate and fill in array of key attribute numbers
759 760
	 * ----------------
	 */
761 762
	CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);

B
Bruce Momjian 已提交
763
	attKeys = (AttrNumber *) palloc(numKeys * sizeof(AttrNumber));
764 765 766 767

	for (i = 0; i < numKeys; i++)
		attKeys[i] = indexTuple->indkey[i];

768
	/* ----------------
769
	 *	return array to caller.
770 771
	 * ----------------
	 */
772 773 774 775 776 777
	(*attsOutP) = attKeys;
}

/* ----------------------------------------------------------------
 *		ExecOpenIndices
 *
778 779
 *		Find the indices associated with a result relation, open them,
 *		and save information about them in the result RelationInfo.
780
 *
781 782
 *		At entry, caller has already opened and locked
 *		resultRelationInfo->ri_RelationDesc.
783
 *
784 785 786 787 788
 *		This used to be horribly ugly code, and slow too because it
 *		did a sequential scan of pg_index.  Now we rely on the relcache
 *		to cache a list of the OIDs of the indices associated with any
 *		specific relation, and we use the pg_index syscache to get the
 *		entries we need from pg_index.
789 790 791
 * ----------------------------------------------------------------
 */
void
792
ExecOpenIndices(RelationInfo *resultRelationInfo)
793
{
794 795 796 797 798
	Relation	resultRelation = resultRelationInfo->ri_RelationDesc;
	List	   *indexoidlist,
			   *indexoidscan;
	int			len,
				i;
799 800
	RelationPtr relationDescs;
	IndexInfo **indexInfoArray;
801

H
Hiroshi Inoue 已提交
802
	resultRelationInfo->ri_NumIndices = 0;
803 804 805

	/* checks for disabled indexes */
	if (! RelationGetForm(resultRelation)->relhasindex)
H
Hiroshi Inoue 已提交
806 807
		return;
	if (IsIgnoringSystemIndexes() &&
808
		IsSystemRelationName(RelationGetRelationName(resultRelation)))
H
Hiroshi Inoue 已提交
809
		return;
810

811
	/* ----------------
812
	 *	 Get cached list of index OIDs
813 814
	 * ----------------
	 */
815 816 817 818
	indexoidlist = RelationGetIndexList(resultRelation);
	len = length(indexoidlist);
	if (len == 0)
		return;
819

820
	/* ----------------
821
	 *	 allocate space for result arrays
822 823
	 * ----------------
	 */
824 825 826 827 828 829
	relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
	indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));

	resultRelationInfo->ri_NumIndices = len;
	resultRelationInfo->ri_IndexRelationDescs = relationDescs;
	resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
830 831

	/* ----------------
832
	 *	 For each index, open the index relation and save pg_index info.
833 834
	 * ----------------
	 */
835 836
	i = 0;
	foreach(indexoidscan, indexoidlist)
837
	{
838 839 840 841 842 843 844 845 846
		Oid			indexOid = lfirsti(indexoidscan);
		Relation	indexDesc;
		HeapTuple	indexTuple;
		Form_pg_index indexStruct;
		int			numKeyAtts;
		AttrNumber *indexKeyAtts;
		FuncIndexInfoPtr fInfoP;
		PredInfo   *predicate;
		IndexInfo  *ii;
847 848

		/* ----------------
849
		 * Open (and lock, if necessary) the index relation
850
		 *
851 852 853 854 855 856 857 858 859 860 861 862 863 864
		 * Hack for not btree and hash indices: they use relation level
		 * exclusive locking on update (i.e. - they are not ready for MVCC)
		 * and so we have to exclusively lock indices here to prevent
		 * deadlocks if we will scan them - index_beginscan places
		 * AccessShareLock, indices update methods don't use locks at all.
		 * We release this lock in ExecCloseIndices. Note, that hashes use
		 * page level locking - i.e. are not deadlock-free - let's them be
		 * on their way -:)) vadim 03-12-1998
		 *
		 * If there are multiple not-btree-or-hash indices, all backends must
		 * lock the indices in the same order or we will get deadlocks here
		 * during concurrent updates.  This is now guaranteed by
		 * RelationGetIndexList(), which promises to return the index list
		 * in OID order.  tgl 06-19-2000
865 866
		 * ----------------
		 */
867 868 869 870 871
		indexDesc = index_open(indexOid);

		if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
			indexDesc->rd_rel->relam != HASH_AM_OID)
			LockRelation(indexDesc, AccessExclusiveLock);
872 873

		/* ----------------
874
		 *	Get the pg_index tuple for the index
875 876
		 * ----------------
		 */
877 878 879 880 881 882
		indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
											 ObjectIdGetDatum(indexOid),
											 0, 0, 0);
		if (!HeapTupleIsValid(indexTuple))
			elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
883 884

		/* ----------------
885
		 *	extract the index key information from the tuple
886 887
		 * ----------------
		 */
888
		fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
889 890 891 892 893 894 895 896 897 898 899
		ExecGetIndexKeyInfo(indexStruct,
							&numKeyAtts,
							&indexKeyAtts,
							fInfoP);

		/* ----------------
		 *	next get the index predicate from the tuple
		 * ----------------
		 */
		if (VARSIZE(&indexStruct->indpred) != 0)
		{
900 901
			char	   *predString;

902 903
			predString = DatumGetCString(DirectFunctionCall1(textout,
									PointerGetDatum(&indexStruct->indpred)));
904 905 906 907 908 909
			predicate = (PredInfo *) stringToNode(predString);
			pfree(predString);
		}
		else
			predicate = NULL;

910 911 912 913 914 915
		/* Save the index info */
		ii = makeNode(IndexInfo);
		ii->ii_NumKeyAttributes = numKeyAtts;
		ii->ii_KeyAttributeNumbers = indexKeyAtts;
		ii->ii_FuncIndexInfo = fInfoP;
		ii->ii_Predicate = (Node *) predicate;
916

917
		heap_freetuple(indexTuple);
918

919 920 921
		relationDescs[i] = indexDesc;
		indexInfoArray[i] = ii;
		i++;
922
	}
923

924
	freeList(indexoidlist);
925 926 927
}

/* ----------------------------------------------------------------
928
 *		ExecCloseIndices
929
 *
930
 *		Close the index relations stored in resultRelationInfo
931 932 933
 * ----------------------------------------------------------------
 */
void
934
ExecCloseIndices(RelationInfo *resultRelationInfo)
935
{
936 937 938
	int			i;
	int			numIndices;
	RelationPtr relationDescs;
939 940 941 942 943

	numIndices = resultRelationInfo->ri_NumIndices;
	relationDescs = resultRelationInfo->ri_IndexRelationDescs;

	for (i = 0; i < numIndices; i++)
V
Vadim B. Mikheev 已提交
944 945 946
	{
		if (relationDescs[i] == NULL)
			continue;
B
Bruce Momjian 已提交
947

V
Vadim B. Mikheev 已提交
948
		/*
949
		 * See notes in ExecOpenIndices.
V
Vadim B. Mikheev 已提交
950
		 */
B
Bruce Momjian 已提交
951 952
		if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
			relationDescs[i]->rd_rel->relam != HASH_AM_OID)
V
Vadim B. Mikheev 已提交
953
			UnlockRelation(relationDescs[i], AccessExclusiveLock);
954

V
Vadim B. Mikheev 已提交
955 956
		index_close(relationDescs[i]);
	}
B
Bruce Momjian 已提交
957

958 959 960
	/*
	 * XXX should free indexInfo array here too.
	 */
961 962 963
}

/* ----------------------------------------------------------------
964
 *		ExecInsertIndexTuples
965
 *
966 967 968 969 970 971 972
 *		This routine takes care of inserting index tuples
 *		into all the relations indexing the result relation
 *		when a heap tuple is inserted into the result relation.
 *		Much of this code should be moved into the genam
 *		stuff as it only exists here because the genam stuff
 *		doesn't provide the functionality needed by the
 *		executor.. -cim 9/27/89
973 974 975
 * ----------------------------------------------------------------
 */
void
976
ExecInsertIndexTuples(TupleTableSlot *slot,
977
					  ItemPointer tupleid,
978
					  EState *estate,
979
					  bool is_update)
980
{
981 982 983 984 985 986 987 988 989 990
	HeapTuple	heapTuple;
	RelationInfo *resultRelationInfo;
	int			i;
	int			numIndices;
	RelationPtr relationDescs;
	Relation	heapRelation;
	IndexInfo **indexInfoArray;
	IndexInfo  *indexInfo;
	Node	   *predicate;
	ExprContext *econtext;
991
	InsertIndexResult result;
992 993
	int			numberOfAttributes;
	AttrNumber *keyAttributeNumbers;
994
	FuncIndexInfoPtr fInfoP;
995 996 997
	TupleDesc	heapDescriptor;
	Datum	   *datum;
	char	   *nulls;
998 999

	heapTuple = slot->val;
1000 1001

	/* ----------------
1002
	 *	get information from the result relation info structure.
1003 1004
	 * ----------------
	 */
1005 1006 1007 1008 1009 1010
	resultRelationInfo = estate->es_result_relation_info;
	numIndices = resultRelationInfo->ri_NumIndices;
	relationDescs = resultRelationInfo->ri_IndexRelationDescs;
	indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
	heapRelation = resultRelationInfo->ri_RelationDesc;

1011
	/* ----------------
1012
	 *	for each index, form and insert the index tuple
1013 1014
	 * ----------------
	 */
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
	econtext = NULL;
	for (i = 0; i < numIndices; i++)
	{
		if (relationDescs[i] == NULL)
			continue;

		indexInfo = indexInfoArray[i];
		predicate = indexInfo->ii_Predicate;
		if (predicate != NULL)
		{
			if (econtext == NULL)
1026 1027
				econtext = MakeExprContext(slot,
										   TransactionCommandContext);
1028 1029

			/* Skip this index-update if the predicate isn't satisfied */
1030
			if (!ExecQual((List *) predicate, econtext, false))
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
				continue;
		}

		/* ----------------
		 *		get information from index info structure
		 * ----------------
		 */
		numberOfAttributes = indexInfo->ii_NumKeyAttributes;
		keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
		fInfoP = indexInfo->ii_FuncIndexInfo;
		datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
		nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
1043
		heapDescriptor = (TupleDesc) RelationGetDescr(heapRelation);
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057

		FormIndexDatum(numberOfAttributes,		/* num attributes */
					   keyAttributeNumbers,		/* array of att nums to
												 * extract */
					   heapTuple,		/* tuple from base relation */
					   heapDescriptor,	/* heap tuple's descriptor */
					   datum,	/* return: array of attributes */
					   nulls,	/* return: array of char's */
					   fInfoP); /* functional index information */


		result = index_insert(relationDescs[i], /* index relation */
							  datum,	/* array of heaptuple Datums */
							  nulls,	/* info on nulls */
B
Bruce Momjian 已提交
1058
							  &(heapTuple->t_self),		/* tid of heap tuple */
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
							  heapRelation);

		/* ----------------
		 *		keep track of index inserts for debugging
		 * ----------------
		 */
		IncrIndexInserted();

		/* ----------------
		 *		free index tuple after insertion
		 * ----------------
		 */
		if (result)
			pfree(result);
	}
	if (econtext != NULL)
1075
		FreeExprContext(econtext);
1076
}
V
Vadim B. Mikheev 已提交
1077

1078 1079
void
SetChangedParamList(Plan *node, List *newchg)
V
Vadim B. Mikheev 已提交
1080
{
1081 1082 1083
	List	   *nl;

	foreach(nl, newchg)
V
Vadim B. Mikheev 已提交
1084
	{
1085 1086
		int			paramId = lfirsti(nl);

V
Vadim B. Mikheev 已提交
1087
		/* if this node doesn't depend on a param ... */
1088 1089
		if (!intMember(paramId, node->extParam) &&
			!intMember(paramId, node->locParam))
V
Vadim B. Mikheev 已提交
1090 1091
			continue;
		/* if this param is already in list of changed ones ... */
1092
		if (intMember(paramId, node->chgParam))
V
Vadim B. Mikheev 已提交
1093 1094
			continue;
		/* else - add this param to the list */
1095
		node->chgParam = lappendi(node->chgParam, paramId);
V
Vadim B. Mikheev 已提交
1096 1097 1098
	}

}