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
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.89 2002/09/02 01:05:05 tgl 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 300 301 302 303 304 305 306 307 308 309 310 311 312 313
	/*
	 * 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
	 * 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.
	 *
	 * 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
	 * 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 ...
	 */
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;
	}
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 699 700 701 702
		/*
		 * The index AM does the rest.  Note we suppress unique-index
		 * 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,
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 756 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 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821

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

	/* 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)
{
	ExprContext_CB   **prev_callback;
	ExprContext_CB   *ecxt_callback;

	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)
{
	ExprContext_CB   *ecxt_callback;

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