execUtils.c 19.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * execUtils.c
4
 *	  miscellaneous executor utility routines
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.73 2001/01/29 00:39:19 tgl Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
17
 *		ExecAssignExprContext	Common code for plan node init routines.
18
 *
19 20 21
 *		ExecOpenIndices			\
 *		ExecCloseIndices		 | referenced by InitPlan, EndPlan,
 *		ExecInsertIndexTuples	/  ExecAppend, ExecReplace
22 23 24 25
 *
 *	 NOTES
 *		This file has traditionally been the place to stick misc.
 *		executor support stuff that doesn't really go anyplace else.
26 27 28
 *
 */

29 30
#include "postgres.h"

31
#include "access/genam.h"
Bruce Momjian's avatar
Bruce Momjian committed
32
#include "access/heapam.h"
33
#include "catalog/catname.h"
Bruce Momjian's avatar
Bruce Momjian committed
34
#include "catalog/index.h"
Hiroshi Inoue's avatar
Hiroshi Inoue committed
35
#include "catalog/catalog.h"
Bruce Momjian's avatar
Bruce Momjian committed
36
#include "catalog/pg_index.h"
Bruce Momjian's avatar
Bruce Momjian committed
37
#include "executor/execdebug.h"
Hiroshi Inoue's avatar
Hiroshi Inoue committed
38
#include "miscadmin.h"
39 40
#include "utils/builtins.h"
#include "utils/fmgroids.h"
41
#include "utils/memutils.h"
42 43
#include "utils/relcache.h"
#include "utils/syscache.h"
44

45

46
/* ----------------------------------------------------------------
47 48
 *		global counters for number of tuples processed, retrieved,
 *		appended, replaced, deleted.
49 50
 * ----------------------------------------------------------------
 */
51 52 53 54 55 56 57
int			NTupleProcessed;
int			NTupleRetrieved;
int			NTupleReplaced;
int			NTupleAppended;
int			NTupleDeleted;
int			NIndexTupleInserted;
extern int	NIndexTupleProcessed;		/* have to be defined in the
58 59
										 * access method level so that the
										 * cinterface.a will link ok. */
60 61

/* ----------------------------------------------------------------
62
 *						statistic functions
63 64 65 66
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
67
 *		ResetTupleCount
68 69
 * ----------------------------------------------------------------
 */
70
#ifdef NOT_USED
71
void
72
ResetTupleCount(void)
73
{
74 75 76 77 78 79
	NTupleProcessed = 0;
	NTupleRetrieved = 0;
	NTupleAppended = 0;
	NTupleDeleted = 0;
	NTupleReplaced = 0;
	NIndexTupleProcessed = 0;
80
}
81

82
#endif
83 84

/* ----------------------------------------------------------------
85
 *		PrintTupleCount
86 87
 * ----------------------------------------------------------------
 */
88
#ifdef NOT_USED
89
void
90
DisplayTupleCount(FILE *statfp)
91
{
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	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");
119
}
120

121
#endif
122 123

/* ----------------------------------------------------------------
124
 *				 miscellaneous node-init support functions
125
 *
126
 *		ExecAssignExprContext	- assigns the node's expression context
127 128 129 130
 * ----------------------------------------------------------------
 */

/* ----------------
131 132 133 134 135 136
 *		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.
137
 *
138 139
 * Note: we assume CurrentMemoryContext is the correct per-query context.
 * This should be true during plan node initialization.
140 141 142
 * ----------------
 */
void
143
ExecAssignExprContext(EState *estate, CommonState *commonstate)
144
{
145
	ExprContext *econtext = makeNode(ExprContext);
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	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;

	commonstate->cs_ExprContext = econtext;
166 167 168
}

/* ----------------
169
 *		MakeExprContext
170
 *
171 172 173 174
 *		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.
175 176
 * ----------------
 */
177 178 179
ExprContext *
MakeExprContext(TupleTableSlot *slot,
				MemoryContext queryContext)
180
{
181
	ExprContext *econtext = makeNode(ExprContext);
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
	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;

	return econtext;
}
209

210 211 212 213 214 215 216 217 218 219
/*
 * 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);
220 221
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
/*
 * Build a per-output-tuple ExprContext for an EState.
 *
 * This is normally invoked via GetPerTupleExprContext() macro.
 */
ExprContext *
MakePerTupleExprContext(EState *estate)
{
	if (estate->es_per_tuple_exprcontext == NULL)
	{
		MemoryContext oldContext;

		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
		estate->es_per_tuple_exprcontext =
			MakeExprContext(NULL, estate->es_query_cxt);
		MemoryContextSwitchTo(oldContext);
	}
	return estate->es_per_tuple_exprcontext;
}

242
/* ----------------------------------------------------------------
243
 *		Result slot tuple type and ProjectionInfo support
244 245 246 247
 * ----------------------------------------------------------------
 */

/* ----------------
248
 *		ExecAssignResultType
249 250 251
 * ----------------
 */
void
252
ExecAssignResultType(CommonState *commonstate,
253
					 TupleDesc tupDesc, bool shouldFree)
254
{
255
	TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
256

257
	ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
258 259 260
}

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

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

273
	ExecAssignResultType(commonstate, tupDesc, false);
274 275 276
}

/* ----------------
277
 *		ExecAssignResultTypeFromTL
278 279 280
 * ----------------
 */
void
281
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
282
{
283
	TupleDesc	tupDesc;
284

285 286
	tupDesc = ExecTypeFromTL(node->targetlist);
	ExecAssignResultType(commonstate, tupDesc, true);
287 288 289
}

/* ----------------
290
 *		ExecGetResultType
291 292 293
 * ----------------
 */
TupleDesc
294
ExecGetResultType(CommonState *commonstate)
295
{
296 297 298
	TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;

	return slot->ttc_tupleDescriptor;
299 300 301
}

/* ----------------
302 303
 *		ExecAssignProjectionInfo
		  forms the projection information from the node's targetlist
304 305 306
 * ----------------
 */
void
307
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
308
{
309
	ProjectionInfo *projInfo;
310 311
	List	   *targetList;
	int			len;
312 313 314 315 316 317 318

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

	projInfo = makeNode(ProjectionInfo);
	projInfo->pi_targetlist = targetList;
	projInfo->pi_len = len;
319
	projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
320 321 322 323
	projInfo->pi_exprContext = commonstate->cs_ExprContext;
	projInfo->pi_slot = commonstate->cs_ResultTupleSlot;

	commonstate->cs_ProjInfo = projInfo;
324 325 326 327
}


/* ----------------
328
 *		ExecFreeProjectionInfo
329 330 331
 * ----------------
 */
void
332
ExecFreeProjectionInfo(CommonState *commonstate)
333
{
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
	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;
354 355
}

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
/* ----------------
 *		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.
	 * ----------------
	 */
378
	MemoryContextDelete(econtext->ecxt_per_tuple_memory);
379 380 381 382
	pfree(econtext);
	commonstate->cs_ExprContext = NULL;
}

383
/* ----------------------------------------------------------------
384 385 386 387 388 389
 *		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
390 391 392 393
 * ----------------------------------------------------------------
 */

/* ----------------
394
 *		ExecGetScanType
395 396 397
 * ----------------
 */
TupleDesc
398
ExecGetScanType(CommonScanState *csstate)
399
{
400 401 402
	TupleTableSlot *slot = csstate->css_ScanTupleSlot;

	return slot->ttc_tupleDescriptor;
403 404 405
}

/* ----------------
406
 *		ExecAssignScanType
407 408 409
 * ----------------
 */
void
410
ExecAssignScanType(CommonScanState *csstate,
411
				   TupleDesc tupDesc, bool shouldFree)
412
{
413
	TupleTableSlot *slot = csstate->css_ScanTupleSlot;
414

415
	ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
416 417 418
}

/* ----------------
419
 *		ExecAssignScanTypeFromOuterPlan
420 421 422
 * ----------------
 */
void
423
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
424
{
425 426
	Plan	   *outerPlan;
	TupleDesc	tupDesc;
427 428 429

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

431
	ExecAssignScanType(csstate, tupDesc, false);
432 433 434 435
}


/* ----------------------------------------------------------------
436
 *				  ExecInsertIndexTuples support
437 438
 * ----------------------------------------------------------------
 */
439 440 441 442

/* ----------------------------------------------------------------
 *		ExecOpenIndices
 *
443
 *		Find the indices associated with a result relation, open them,
444
 *		and save information about them in the result ResultRelInfo.
445
 *
446
 *		At entry, caller has already opened and locked
447
 *		resultRelInfo->ri_RelationDesc.
448
 *
449 450 451 452 453
 *		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.
454 455 456
 * ----------------------------------------------------------------
 */
void
457
ExecOpenIndices(ResultRelInfo *resultRelInfo)
458
{
459
	Relation	resultRelation = resultRelInfo->ri_RelationDesc;
460 461 462 463
	List	   *indexoidlist,
			   *indexoidscan;
	int			len,
				i;
464 465
	RelationPtr relationDescs;
	IndexInfo **indexInfoArray;
466

467
	resultRelInfo->ri_NumIndices = 0;
468 469 470

	/* checks for disabled indexes */
	if (! RelationGetForm(resultRelation)->relhasindex)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
471 472
		return;
	if (IsIgnoringSystemIndexes() &&
473
		IsSystemRelationName(RelationGetRelationName(resultRelation)))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
474
		return;
475

476
	/* ----------------
477
	 *	 Get cached list of index OIDs
478 479
	 * ----------------
	 */
480 481 482 483
	indexoidlist = RelationGetIndexList(resultRelation);
	len = length(indexoidlist);
	if (len == 0)
		return;
484

485
	/* ----------------
486
	 *	 allocate space for result arrays
487 488
	 * ----------------
	 */
489 490 491
	relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
	indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));

492 493 494
	resultRelInfo->ri_NumIndices = len;
	resultRelInfo->ri_IndexRelationDescs = relationDescs;
	resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
495 496

	/* ----------------
497
	 *	 For each index, open the index relation and save pg_index info.
498 499
	 * ----------------
	 */
500 501
	i = 0;
	foreach(indexoidscan, indexoidlist)
502
	{
503 504 505 506
		Oid			indexOid = lfirsti(indexoidscan);
		Relation	indexDesc;
		HeapTuple	indexTuple;
		IndexInfo  *ii;
507 508

		/* ----------------
509
		 * Open (and lock, if necessary) the index relation
510
		 *
511 512 513 514 515 516 517 518 519 520 521 522 523 524
		 * 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
525 526
		 * ----------------
		 */
527 528 529 530 531
		indexDesc = index_open(indexOid);

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

		/* ----------------
534
		 *	Get the pg_index tuple for the index
535 536
		 * ----------------
		 */
537 538 539
		indexTuple = SearchSysCache(INDEXRELID,
									ObjectIdGetDatum(indexOid),
									0, 0, 0);
540 541
		if (!HeapTupleIsValid(indexTuple))
			elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
542 543

		/* ----------------
544
		 *	extract the index key information from the tuple
545 546
		 * ----------------
		 */
547
		ii = BuildIndexInfo(indexTuple);
548

549 550
		ReleaseSysCache(indexTuple);

551 552 553
		relationDescs[i] = indexDesc;
		indexInfoArray[i] = ii;
		i++;
554
	}
555

556
	freeList(indexoidlist);
557 558 559
}

/* ----------------------------------------------------------------
560
 *		ExecCloseIndices
561
 *
562
 *		Close the index relations stored in resultRelInfo
563 564 565
 * ----------------------------------------------------------------
 */
void
566
ExecCloseIndices(ResultRelInfo *resultRelInfo)
567
{
568 569 570
	int			i;
	int			numIndices;
	RelationPtr relationDescs;
571

572 573
	numIndices = resultRelInfo->ri_NumIndices;
	relationDescs = resultRelInfo->ri_IndexRelationDescs;
574 575

	for (i = 0; i < numIndices; i++)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
576 577 578
	{
		if (relationDescs[i] == NULL)
			continue;
Bruce Momjian's avatar
Bruce Momjian committed
579

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
580
		/*
581
		 * See notes in ExecOpenIndices.
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
582
		 */
Bruce Momjian's avatar
Bruce Momjian committed
583 584
		if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
			relationDescs[i]->rd_rel->relam != HASH_AM_OID)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
585
			UnlockRelation(relationDescs[i], AccessExclusiveLock);
586

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
587 588
		index_close(relationDescs[i]);
	}
Bruce Momjian's avatar
Bruce Momjian committed
589

590 591 592
	/*
	 * XXX should free indexInfo array here too.
	 */
593 594 595
}

/* ----------------------------------------------------------------
596
 *		ExecInsertIndexTuples
597
 *
598 599 600 601 602 603 604
 *		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
605 606 607
 * ----------------------------------------------------------------
 */
void
608
ExecInsertIndexTuples(TupleTableSlot *slot,
609
					  ItemPointer tupleid,
610
					  EState *estate,
611
					  bool is_update)
612
{
613
	HeapTuple	heapTuple;
614
	ResultRelInfo *resultRelInfo;
615 616 617 618
	int			i;
	int			numIndices;
	RelationPtr relationDescs;
	Relation	heapRelation;
619
	TupleDesc	heapDescriptor;
620 621
	IndexInfo **indexInfoArray;
	ExprContext *econtext;
622 623
	Datum		datum[INDEX_MAX_KEYS];
	char		nullv[INDEX_MAX_KEYS];
624 625

	heapTuple = slot->val;
626

627 628
	/*
	 * Get information from the result relation info structure.
629
	 */
630 631 632 633 634
	resultRelInfo = estate->es_result_relation_info;
	numIndices = resultRelInfo->ri_NumIndices;
	relationDescs = resultRelInfo->ri_IndexRelationDescs;
	indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
	heapRelation = resultRelInfo->ri_RelationDesc;
635 636
	heapDescriptor = RelationGetDescr(heapRelation);

637 638
	/*
	 * We will use the EState's per-tuple context for evaluating predicates
639
	 * and functional-index functions (creating it if it's not already there).
640
	 */
641
	econtext = GetPerTupleExprContext(estate);
642 643 644

	/* Arrange for econtext's scan tuple to be the tuple under test */
	econtext->ecxt_scantuple = slot;
645

646
	/* ----------------
647
	 *	for each index, form and insert the index tuple
648 649
	 * ----------------
	 */
650 651
	for (i = 0; i < numIndices; i++)
	{
652 653 654 655
		IndexInfo  *indexInfo;
		Node	   *predicate;
		InsertIndexResult result;

656 657 658 659 660 661 662 663
		if (relationDescs[i] == NULL)
			continue;

		indexInfo = indexInfoArray[i];
		predicate = indexInfo->ii_Predicate;
		if (predicate != NULL)
		{
			/* Skip this index-update if the predicate isn't satisfied */
664
			if (!ExecQual((List *) predicate, econtext, false))
665 666 667 668
				continue;
		}

		/* ----------------
669 670
		 *	FormIndexDatum fills in its datum and null parameters
		 *	with attribute information taken from the given heap tuple.
671 672
		 * ----------------
		 */
673 674 675 676 677 678
		FormIndexDatum(indexInfo,
					   heapTuple,
					   heapDescriptor,
					   econtext->ecxt_per_tuple_memory,
					   datum,
					   nullv);
679 680 681

		result = index_insert(relationDescs[i], /* index relation */
							  datum,	/* array of heaptuple Datums */
682
							  nullv,	/* info on nulls */
Bruce Momjian's avatar
Bruce Momjian committed
683
							  &(heapTuple->t_self),		/* tid of heap tuple */
684 685 686 687 688 689 690 691 692 693 694
							  heapRelation);

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

		if (result)
			pfree(result);
	}
695
}
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
696

697 698
void
SetChangedParamList(Plan *node, List *newchg)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
699
{
700 701 702
	List	   *nl;

	foreach(nl, newchg)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
703
	{
704 705
		int			paramId = lfirsti(nl);

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
706
		/* if this node doesn't depend on a param ... */
707 708
		if (!intMember(paramId, node->extParam) &&
			!intMember(paramId, node->locParam))
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
709 710
			continue;
		/* if this param is already in list of changed ones ... */
711
		if (intMember(paramId, node->chgParam))
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
712 713
			continue;
		/* else - add this param to the list */
714
		node->chgParam = lappendi(node->chgParam, paramId);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
715 716
	}
}