execUtils.c 22.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * execUtils.c
4
 *	  miscellaneous executor utility routines
5
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
B
Bruce Momjian 已提交
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.90 2002/09/04 20:31:18 momjian Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
17
 *		ExecAssignExprContext	Common code for plan node init routines.
18
 *
19 20
 *		ExecOpenIndices			\
 *		ExecCloseIndices		 | referenced by InitPlan, EndPlan,
21
 *		ExecInsertIndexTuples	/  ExecInsert, ExecUpdate
22
 *
23 24 25
 *		RegisterExprContextCallback    Register function shutdown callback
 *		UnregisterExprContextCallback  Deregister function shutdown callback
 *
26 27 28
 *	 NOTES
 *		This file has traditionally been the place to stick misc.
 *		executor support stuff that doesn't really go anyplace else.
29 30 31
 *
 */

32 33
#include "postgres.h"

34
#include "access/genam.h"
B
Bruce Momjian 已提交
35
#include "access/heapam.h"
36
#include "catalog/catname.h"
B
Bruce Momjian 已提交
37
#include "catalog/index.h"
H
Hiroshi Inoue 已提交
38
#include "catalog/catalog.h"
B
Bruce Momjian 已提交
39
#include "catalog/pg_index.h"
B
Bruce Momjian 已提交
40
#include "executor/execdebug.h"
H
Hiroshi Inoue 已提交
41
#include "miscadmin.h"
42 43
#include "utils/builtins.h"
#include "utils/fmgroids.h"
44
#include "utils/memutils.h"
45 46
#include "utils/relcache.h"
#include "utils/syscache.h"
47

48

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

64 65 66

static void ShutdownExprContext(ExprContext *econtext);

67
/* ----------------------------------------------------------------
68
 *						statistic functions
69 70 71 72
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
73
 *		ResetTupleCount
74 75
 * ----------------------------------------------------------------
 */
76
#ifdef NOT_USED
77
void
78
ResetTupleCount(void)
79
{
80 81 82 83 84 85
	NTupleProcessed = 0;
	NTupleRetrieved = 0;
	NTupleAppended = 0;
	NTupleDeleted = 0;
	NTupleReplaced = 0;
	NIndexTupleProcessed = 0;
86
}
87
#endif
88 89

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

/* ----------------------------------------------------------------
128
 *				 miscellaneous node-init support functions
129 130 131 132
 * ----------------------------------------------------------------
 */

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

149 150 151 152
	econtext->ecxt_scantuple = NULL;
	econtext->ecxt_innertuple = NULL;
	econtext->ecxt_outertuple = NULL;
	econtext->ecxt_per_query_memory = CurrentMemoryContext;
B
Bruce Momjian 已提交
153

154 155 156 157 158 159 160 161 162 163 164 165 166
	/*
	 * 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;
167
	econtext->ecxt_callbacks = NULL;
168 169

	commonstate->cs_ExprContext = econtext;
170 171 172
}

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

187 188 189 190
	econtext->ecxt_scantuple = slot;
	econtext->ecxt_innertuple = NULL;
	econtext->ecxt_outertuple = NULL;
	econtext->ecxt_per_query_memory = queryContext;
B
Bruce Momjian 已提交
191

192 193 194 195 196 197
	/*
	 * 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
B
Bruce Momjian 已提交
198 199 200
	 * 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.
201 202 203 204 205 206 207 208 209 210 211
	 */
	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;
212
	econtext->ecxt_callbacks = NULL;
213 214 215

	return econtext;
}
216

217 218
/*
 * Free an ExprContext made by MakeExprContext, including the temporary
B
Bruce Momjian 已提交
219
 * context used for expression evaluation.	Note this will cause any
220 221 222 223 224
 * pass-by-reference expression result to go away!
 */
void
FreeExprContext(ExprContext *econtext)
{
225 226 227
	/* Call any registered callbacks */
	ShutdownExprContext(econtext);
	/* And clean up the memory used */
228 229
	MemoryContextDelete(econtext->ecxt_per_tuple_memory);
	pfree(econtext);
230 231
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*
 * 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;
}

252
/* ----------------------------------------------------------------
253
 *		Result slot tuple type and ProjectionInfo support
254 255 256 257
 * ----------------------------------------------------------------
 */

/* ----------------
258
 *		ExecAssignResultType
259 260 261
 * ----------------
 */
void
262
ExecAssignResultType(CommonState *commonstate,
263
					 TupleDesc tupDesc, bool shouldFree)
264
{
265
	TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
266

267
	ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
268 269 270
}

/* ----------------
271
 *		ExecAssignResultTypeFromOuterPlan
272 273 274
 * ----------------
 */
void
275
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
276
{
277 278
	Plan	   *outerPlan;
	TupleDesc	tupDesc;
279 280 281 282

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

283
	ExecAssignResultType(commonstate, tupDesc, false);
284 285 286
}

/* ----------------
287
 *		ExecAssignResultTypeFromTL
288 289 290
 * ----------------
 */
void
291
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
292
{
293
	ResultRelInfo *ri;
294
	bool		hasoid = false;
295
	TupleDesc	tupDesc;
296

297 298 299
	/*
	 * This is pretty grotty: we need to ensure that result tuples have
	 * space for an OID iff they are going to be stored into a relation
B
Bruce Momjian 已提交
300 301 302 303 304
	 * that has OIDs.  We assume that estate->es_result_relation_info is
	 * already set up to describe the target relation.	One reason this is
	 * ugly is that all plan nodes in the plan tree will emit tuples with
	 * space for an OID, though we really only need the topmost plan to do
	 * so.
305 306 307 308
	 *
	 * It would be better to have InitPlan adjust the topmost plan node's
	 * output descriptor after plan tree initialization.  However, that
	 * doesn't quite work because in an UPDATE that spans an inheritance
B
Bruce Momjian 已提交
309 310 311 312
	 * tree, some of the target relations may have OIDs and some not. We
	 * have to make the decision on a per-relation basis as we initialize
	 * each of the child plans of the topmost Append plan.	So, this is
	 * ugly but it works, for now ...
313
	 */
314 315
	ri = node->state->es_result_relation_info;
	if (ri != NULL)
316 317
	{
		Relation	rel = ri->ri_RelationDesc;
318

319 320 321
		if (rel != NULL)
			hasoid = rel->rd_rel->relhasoids;
	}
B
Bruce Momjian 已提交
322

323
	tupDesc = ExecTypeFromTL(node->targetlist, hasoid);
324
	ExecAssignResultType(commonstate, tupDesc, true);
325 326 327
}

/* ----------------
328
 *		ExecGetResultType
329 330 331
 * ----------------
 */
TupleDesc
332
ExecGetResultType(CommonState *commonstate)
333
{
334 335 336
	TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;

	return slot->ttc_tupleDescriptor;
337 338 339
}

/* ----------------
340 341
 *		ExecAssignProjectionInfo
		  forms the projection information from the node's targetlist
342 343 344
 * ----------------
 */
void
345
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
346
{
347
	ProjectionInfo *projInfo;
348 349
	List	   *targetList;
	int			len;
350 351 352 353 354 355 356

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

	projInfo = makeNode(ProjectionInfo);
	projInfo->pi_targetlist = targetList;
	projInfo->pi_len = len;
357
	projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
358 359 360 361
	projInfo->pi_exprContext = commonstate->cs_ExprContext;
	projInfo->pi_slot = commonstate->cs_ResultTupleSlot;

	commonstate->cs_ProjInfo = projInfo;
362 363 364 365
}


/* ----------------
366
 *		ExecFreeProjectionInfo
367 368 369
 * ----------------
 */
void
370
ExecFreeProjectionInfo(CommonState *commonstate)
371
{
372 373
	ProjectionInfo *projInfo;

374 375 376
	/*
	 * get projection info.  if NULL then this node has none so we just
	 * return.
377 378 379 380 381
	 */
	projInfo = commonstate->cs_ProjInfo;
	if (projInfo == NULL)
		return;

382 383
	/*
	 * clean up memory used.
384 385 386 387 388 389
	 */
	if (projInfo->pi_tupValue != NULL)
		pfree(projInfo->pi_tupValue);

	pfree(projInfo);
	commonstate->cs_ProjInfo = NULL;
390 391
}

392 393 394 395 396 397 398 399 400
/* ----------------
 *		ExecFreeExprContext
 * ----------------
 */
void
ExecFreeExprContext(CommonState *commonstate)
{
	ExprContext *econtext;

401 402 403
	/*
	 * get expression context.	if NULL then this node has none so we just
	 * return.
404 405 406 407 408
	 */
	econtext = commonstate->cs_ExprContext;
	if (econtext == NULL)
		return;

409 410 411 412 413
	/*
	 * clean up any registered callbacks
	 */
	ShutdownExprContext(econtext);

414 415
	/*
	 * clean up memory used.
416
	 */
417
	MemoryContextDelete(econtext->ecxt_per_tuple_memory);
418 419 420 421
	pfree(econtext);
	commonstate->cs_ExprContext = NULL;
}

422
/* ----------------------------------------------------------------
423 424 425 426 427 428
 *		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
429 430 431 432
 * ----------------------------------------------------------------
 */

/* ----------------
433
 *		ExecGetScanType
434 435 436
 * ----------------
 */
TupleDesc
437
ExecGetScanType(CommonScanState *csstate)
438
{
439 440 441
	TupleTableSlot *slot = csstate->css_ScanTupleSlot;

	return slot->ttc_tupleDescriptor;
442 443 444
}

/* ----------------
445
 *		ExecAssignScanType
446 447 448
 * ----------------
 */
void
449
ExecAssignScanType(CommonScanState *csstate,
450
				   TupleDesc tupDesc, bool shouldFree)
451
{
452
	TupleTableSlot *slot = csstate->css_ScanTupleSlot;
453

454
	ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
455 456 457
}

/* ----------------
458
 *		ExecAssignScanTypeFromOuterPlan
459 460 461
 * ----------------
 */
void
462
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
463
{
464 465
	Plan	   *outerPlan;
	TupleDesc	tupDesc;
466 467 468

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

470
	ExecAssignScanType(csstate, tupDesc, false);
471 472 473 474
}


/* ----------------------------------------------------------------
475
 *				  ExecInsertIndexTuples support
476 477
 * ----------------------------------------------------------------
 */
478 479 480 481

/* ----------------------------------------------------------------
 *		ExecOpenIndices
 *
482
 *		Find the indices associated with a result relation, open them,
483
 *		and save information about them in the result ResultRelInfo.
484
 *
485
 *		At entry, caller has already opened and locked
486
 *		resultRelInfo->ri_RelationDesc.
487
 *
488
 *		This used to be horribly ugly code, and slow too because it
B
Bruce Momjian 已提交
489
 *		did a sequential scan of pg_index.	Now we rely on the relcache
490 491 492
 *		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.
493 494 495
 * ----------------------------------------------------------------
 */
void
496
ExecOpenIndices(ResultRelInfo *resultRelInfo)
497
{
498
	Relation	resultRelation = resultRelInfo->ri_RelationDesc;
499 500 501 502
	List	   *indexoidlist,
			   *indexoidscan;
	int			len,
				i;
503 504
	RelationPtr relationDescs;
	IndexInfo **indexInfoArray;
505

506
	resultRelInfo->ri_NumIndices = 0;
507 508

	/* checks for disabled indexes */
B
Bruce Momjian 已提交
509
	if (!RelationGetForm(resultRelation)->relhasindex)
H
Hiroshi Inoue 已提交
510 511
		return;
	if (IsIgnoringSystemIndexes() &&
512
		IsSystemRelation(resultRelation))
H
Hiroshi Inoue 已提交
513
		return;
514

515 516
	/*
	 * Get cached list of index OIDs
517
	 */
518 519 520 521
	indexoidlist = RelationGetIndexList(resultRelation);
	len = length(indexoidlist);
	if (len == 0)
		return;
522

523 524
	/*
	 * allocate space for result arrays
525
	 */
526 527 528
	relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
	indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));

529 530 531
	resultRelInfo->ri_NumIndices = len;
	resultRelInfo->ri_IndexRelationDescs = relationDescs;
	resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
532

533 534
	/*
	 * For each index, open the index relation and save pg_index info.
535
	 */
536 537
	i = 0;
	foreach(indexoidscan, indexoidlist)
538
	{
539 540 541
		Oid			indexOid = lfirsti(indexoidscan);
		Relation	indexDesc;
		IndexInfo  *ii;
542

543
		/*
544
		 * Open (and lock, if necessary) the index relation
545
		 *
546 547 548 549
		 * If the index AM is not safe for concurrent updates, obtain an
		 * exclusive lock on the index to lock out other updaters as well
		 * as readers (index_beginscan places AccessShareLock). We will
		 * release this lock in ExecCloseIndices.
550
		 *
551 552
		 * If the index AM supports concurrent updates, we obtain no lock
		 * here at all, which is a tad weird, but safe since any critical
553 554 555
		 * operation on the index (like deleting it) will acquire
		 * exclusive lock on the parent table.	Perhaps someday we should
		 * acquire RowExclusiveLock on the index here?
556 557
		 *
		 * If there are multiple not-concurrent-safe indexes, all backends
558 559 560 561
		 * must lock the indexes in the same order or we will get
		 * deadlocks here during concurrent updates.  This is guaranteed
		 * by RelationGetIndexList(), which promises to return the index
		 * list in OID order.
562
		 */
563 564
		indexDesc = index_open(indexOid);

565
		if (!indexDesc->rd_am->amconcurrent)
566
			LockRelation(indexDesc, AccessExclusiveLock);
567

568
		/*
569
		 * extract index key information from the index's pg_index tuple
570
		 */
571
		ii = BuildIndexInfo(indexDesc->rd_index);
572

573 574 575
		relationDescs[i] = indexDesc;
		indexInfoArray[i] = ii;
		i++;
576
	}
577

578
	freeList(indexoidlist);
579 580 581
}

/* ----------------------------------------------------------------
582
 *		ExecCloseIndices
583
 *
584
 *		Close the index relations stored in resultRelInfo
585 586 587
 * ----------------------------------------------------------------
 */
void
588
ExecCloseIndices(ResultRelInfo *resultRelInfo)
589
{
590 591
	int			i;
	int			numIndices;
592
	RelationPtr indexDescs;
593

594
	numIndices = resultRelInfo->ri_NumIndices;
595
	indexDescs = resultRelInfo->ri_IndexRelationDescs;
596 597

	for (i = 0; i < numIndices; i++)
V
Vadim B. Mikheev 已提交
598
	{
599
		if (indexDescs[i] == NULL)
V
Vadim B. Mikheev 已提交
600
			continue;
B
Bruce Momjian 已提交
601

602
		/* Drop lock, if one was acquired by ExecOpenIndices */
603
		if (!indexDescs[i]->rd_am->amconcurrent)
604
			UnlockRelation(indexDescs[i], AccessExclusiveLock);
605

606
		index_close(indexDescs[i]);
V
Vadim B. Mikheev 已提交
607
	}
B
Bruce Momjian 已提交
608

609 610 611
	/*
	 * XXX should free indexInfo array here too.
	 */
612 613 614
}

/* ----------------------------------------------------------------
615
 *		ExecInsertIndexTuples
616
 *
617 618 619 620 621 622 623
 *		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
624 625 626
 * ----------------------------------------------------------------
 */
void
627
ExecInsertIndexTuples(TupleTableSlot *slot,
628
					  ItemPointer tupleid,
629
					  EState *estate,
630
					  bool is_vacuum)
631
{
632
	HeapTuple	heapTuple;
633
	ResultRelInfo *resultRelInfo;
634 635 636 637
	int			i;
	int			numIndices;
	RelationPtr relationDescs;
	Relation	heapRelation;
638
	TupleDesc	heapDescriptor;
639 640
	IndexInfo **indexInfoArray;
	ExprContext *econtext;
641 642
	Datum		datum[INDEX_MAX_KEYS];
	char		nullv[INDEX_MAX_KEYS];
643 644

	heapTuple = slot->val;
645

646 647
	/*
	 * Get information from the result relation info structure.
648
	 */
649 650 651 652 653
	resultRelInfo = estate->es_result_relation_info;
	numIndices = resultRelInfo->ri_NumIndices;
	relationDescs = resultRelInfo->ri_IndexRelationDescs;
	indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
	heapRelation = resultRelInfo->ri_RelationDesc;
654 655
	heapDescriptor = RelationGetDescr(heapRelation);

656
	/*
B
Bruce Momjian 已提交
657 658 659
	 * We will use the EState's per-tuple context for evaluating
	 * predicates and functional-index functions (creating it if it's not
	 * already there).
660
	 */
661
	econtext = GetPerTupleExprContext(estate);
662 663 664

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

666 667
	/*
	 * for each index, form and insert the index tuple
668
	 */
669 670
	for (i = 0; i < numIndices; i++)
	{
671
		IndexInfo  *indexInfo;
672
		List	   *predicate;
673 674
		InsertIndexResult result;

675 676 677 678 679
		if (relationDescs[i] == NULL)
			continue;

		indexInfo = indexInfoArray[i];
		predicate = indexInfo->ii_Predicate;
680
		if (predicate != NIL)
681 682
		{
			/* Skip this index-update if the predicate isn't satisfied */
683
			if (!ExecQual(predicate, econtext, false))
684 685 686
				continue;
		}

687 688 689
		/*
		 * FormIndexDatum fills in its datum and null parameters with
		 * attribute information taken from the given heap tuple.
690
		 */
691 692 693 694 695 696
		FormIndexDatum(indexInfo,
					   heapTuple,
					   heapDescriptor,
					   econtext->ecxt_per_tuple_memory,
					   datum,
					   nullv);
697

698
		/*
B
Bruce Momjian 已提交
699
		 * The index AM does the rest.	Note we suppress unique-index
700 701 702
		 * checks if we are being called from VACUUM, since VACUUM may
		 * need to move dead tuples that have the same keys as live ones.
		 */
703 704
		result = index_insert(relationDescs[i], /* index relation */
							  datum,	/* array of heaptuple Datums */
705
							  nullv,	/* info on nulls */
B
Bruce Momjian 已提交
706
							  &(heapTuple->t_self),		/* tid of heap tuple */
707
							  heapRelation,
B
Bruce Momjian 已提交
708
				  relationDescs[i]->rd_index->indisunique && !is_vacuum);
709

710 711
		/*
		 * keep track of index inserts for debugging
712 713 714 715 716 717
		 */
		IncrIndexInserted();

		if (result)
			pfree(result);
	}
718
}
V
Vadim B. Mikheev 已提交
719

720 721
void
SetChangedParamList(Plan *node, List *newchg)
V
Vadim B. Mikheev 已提交
722
{
723 724 725
	List	   *nl;

	foreach(nl, newchg)
V
Vadim B. Mikheev 已提交
726
	{
727 728
		int			paramId = lfirsti(nl);

V
Vadim B. Mikheev 已提交
729
		/* if this node doesn't depend on a param ... */
730 731
		if (!intMember(paramId, node->extParam) &&
			!intMember(paramId, node->locParam))
V
Vadim B. Mikheev 已提交
732 733
			continue;
		/* if this param is already in list of changed ones ... */
734
		if (intMember(paramId, node->chgParam))
V
Vadim B. Mikheev 已提交
735 736
			continue;
		/* else - add this param to the list */
737
		node->chgParam = lappendi(node->chgParam, paramId);
V
Vadim B. Mikheev 已提交
738 739
	}
}
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755

/*
 * Register a shutdown callback in an ExprContext.
 *
 * Shutdown callbacks will be called (in reverse order of registration)
 * when the ExprContext is deleted or rescanned.  This provides a hook
 * for functions called in the context to do any cleanup needed --- it's
 * particularly useful for functions returning sets.  Note that the
 * callback will *not* be called in the event that execution is aborted
 * by an error.
 */
void
RegisterExprContextCallback(ExprContext *econtext,
							ExprContextCallbackFunction function,
							Datum arg)
{
B
Bruce Momjian 已提交
756
	ExprContext_CB *ecxt_callback;
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781

	/* Save the info in appropriate memory context */
	ecxt_callback = (ExprContext_CB *)
		MemoryContextAlloc(econtext->ecxt_per_query_memory,
						   sizeof(ExprContext_CB));

	ecxt_callback->function = function;
	ecxt_callback->arg = arg;

	/* link to front of list for appropriate execution order */
	ecxt_callback->next = econtext->ecxt_callbacks;
	econtext->ecxt_callbacks = ecxt_callback;
}

/*
 * Deregister a shutdown callback in an ExprContext.
 *
 * Any list entries matching the function and arg will be removed.
 * This can be used if it's no longer necessary to call the callback.
 */
void
UnregisterExprContextCallback(ExprContext *econtext,
							  ExprContextCallbackFunction function,
							  Datum arg)
{
B
Bruce Momjian 已提交
782 783
	ExprContext_CB **prev_callback;
	ExprContext_CB *ecxt_callback;
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807

	prev_callback = &econtext->ecxt_callbacks;

	while ((ecxt_callback = *prev_callback) != NULL)
	{
		if (ecxt_callback->function == function && ecxt_callback->arg == arg)
		{
			*prev_callback = ecxt_callback->next;
			pfree(ecxt_callback);
		}
		else
			prev_callback = &ecxt_callback->next;
	}
}

/*
 * Call all the shutdown callbacks registered in an ExprContext.
 *
 * The callback list is emptied (important in case this is only a rescan
 * reset, and not deletion of the ExprContext).
 */
static void
ShutdownExprContext(ExprContext *econtext)
{
B
Bruce Momjian 已提交
808
	ExprContext_CB *ecxt_callback;
809 810 811 812 813 814 815 816 817 818 819

	/*
	 * Call each callback function in reverse registration order.
	 */
	while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
	{
		econtext->ecxt_callbacks = ecxt_callback->next;
		(*ecxt_callback->function) (ecxt_callback->arg);
		pfree(ecxt_callback);
	}
}