execMain.c 49.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * execMain.c
4
 *	  top level executor interface routines
5 6
 *
 * INTERFACE ROUTINES
7 8 9
 *	ExecutorStart()
 *	ExecutorRun()
 *	ExecutorEnd()
10
 *
11 12 13 14 15 16 17 18 19 20 21 22 23
 *	The old ExecutorMain() has been replaced by ExecutorStart(),
 *	ExecutorRun() and ExecutorEnd()
 *
 *	These three procedures are the external interfaces to the executor.
 *	In each case, the query descriptor and the execution state is required
 *	 as arguments
 *
 *	ExecutorStart() must be called at the beginning of any execution of any
 *	query plan and ExecutorEnd() should always be called at the end of
 *	execution of a plan.
 *
 *	ExecutorRun accepts 'feature' and 'count' arguments that specify whether
 *	the plan is to be executed forwards, backwards, and for how many tuples.
24
 *
B
Add:  
Bruce Momjian 已提交
25 26
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
27 28 29
 *
 *
 * IDENTIFICATION
30
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.127 2000/09/12 21:06:48 tgl Exp $
31 32 33
 *
 *-------------------------------------------------------------------------
 */
34 35
#include "postgres.h"

36 37
#include "access/heapam.h"
#include "catalog/heap.h"
38
#include "commands/command.h"
39
#include "commands/trigger.h"
B
Bruce Momjian 已提交
40 41 42 43 44 45
#include "executor/execdebug.h"
#include "executor/execdefs.h"
#include "miscadmin.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/acl.h"
46

47 48

/* decls for local routines only used within this module */
49
static TupleDesc InitPlan(CmdType operation,
B
Bruce Momjian 已提交
50 51 52
		 Query *parseTree,
		 Plan *plan,
		 EState *estate);
53
static void EndPlan(Plan *plan, EState *estate);
54
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
B
Bruce Momjian 已提交
55 56 57 58
			CmdType operation,
			int offsetTuples,
			int numberTuples,
			ScanDirection direction,
59
			DestReceiver *destfunc);
60
static void ExecRetrieve(TupleTableSlot *slot,
61
			 DestReceiver *destfunc,
B
Bruce Momjian 已提交
62
			 EState *estate);
63
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
64
		   EState *estate);
65
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
66
		   EState *estate);
67
static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
68
			EState *estate);
69
static TupleTableSlot *EvalPlanQualNext(EState *estate);
70
static void EndEvalPlanQual(EState *estate);
71
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
72
					Plan *plan);
73
static void ExecCheckPlanPerms(Plan *plan, CmdType operation,
74
				   int resultRelation, bool resultIsScanned);
75
static void ExecCheckRTPerms(List *rangeTable, CmdType operation,
76
				 int resultRelation, bool resultIsScanned);
77
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
78 79
				  bool isResultRelation, bool resultIsScanned);

80 81
/* end of local decls */

82

83
/* ----------------------------------------------------------------
84 85 86 87 88
 *		ExecutorStart
 *
 *		This routine must be called at the beginning of any execution of any
 *		query plan
 *
89
 *		returns a TupleDesc which describes the attributes of the tuples to
90
 *		be returned by the query.
91
 *
92 93 94
 * NB: the CurrentMemoryContext when this is called must be the context
 * to be used as the per-query context for the query plan.  ExecutorRun()
 * and ExecutorEnd() must be called in this same memory context.
95 96 97
 * ----------------------------------------------------------------
 */
TupleDesc
98
ExecutorStart(QueryDesc *queryDesc, EState *estate)
99
{
100
	TupleDesc	result;
101 102 103

	/* sanity checks */
	Assert(queryDesc != NULL);
104

V
Vadim B. Mikheev 已提交
105 106
	if (queryDesc->plantree->nParamExec > 0)
	{
107 108
		estate->es_param_exec_vals = (ParamExecData *)
			palloc(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
109 110
		MemSet(estate->es_param_exec_vals, 0,
			   queryDesc->plantree->nParamExec * sizeof(ParamExecData));
V
Vadim B. Mikheev 已提交
111
	}
112

113 114 115
	/*
	 * Make our own private copy of the current queries snapshot data
	 */
116
	if (QuerySnapshot == NULL)
J
Jan Wieck 已提交
117
		estate->es_snapshot = NULL;
118
	else
119
	{
B
Bruce Momjian 已提交
120
		estate->es_snapshot = (Snapshot) palloc(sizeof(SnapshotData));
121 122 123 124
		memcpy(estate->es_snapshot, QuerySnapshot, sizeof(SnapshotData));
		if (estate->es_snapshot->xcnt > 0)
		{
			estate->es_snapshot->xip = (TransactionId *)
B
Bruce Momjian 已提交
125
				palloc(estate->es_snapshot->xcnt * sizeof(TransactionId));
126
			memcpy(estate->es_snapshot->xip, QuerySnapshot->xip,
B
Bruce Momjian 已提交
127
				   estate->es_snapshot->xcnt * sizeof(TransactionId));
128
		}
129
	}
130

131 132 133
	/*
	 * Initialize the plan
	 */
134 135 136 137 138 139
	result = InitPlan(queryDesc->operation,
					  queryDesc->parsetree,
					  queryDesc->plantree,
					  estate);

	return result;
140 141 142
}

/* ----------------------------------------------------------------
143 144 145 146 147 148 149
 *		ExecutorRun
 *
 *		This is the main routine of the executor module. It accepts
 *		the query descriptor from the traffic cop and executes the
 *		query plan.
 *
 *		ExecutorStart must have been called already.
150
 *
151 152 153 154 155 156
 *		the different features supported are:
 *			 EXEC_RUN:	retrieve all tuples in the forward direction
 *			 EXEC_FOR:	retrieve 'count' number of tuples in the forward dir
 *			 EXEC_BACK: retrieve 'count' number of tuples in the backward dir
 *			 EXEC_RETONE: return one tuple but don't 'retrieve' it
 *						   used in postquel function processing
157 158 159
 *
 * ----------------------------------------------------------------
 */
160
TupleTableSlot *
B
Bruce Momjian 已提交
161 162
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
			Node *limoffset, Node *limcount)
163
{
B
Bruce Momjian 已提交
164 165
	CmdType		operation;
	Plan	   *plan;
166
	TupleTableSlot *result;
B
Bruce Momjian 已提交
167 168 169 170
	CommandDest dest;
	DestReceiver *destfunc;
	int			offset = 0;
	int			count = 0;
171

B
Bruce Momjian 已提交
172
	/*
B
Bruce Momjian 已提交
173
	 * sanity checks
174
	 */
175 176
	Assert(queryDesc != NULL);

B
Bruce Momjian 已提交
177
	/*
B
Bruce Momjian 已提交
178 179
	 * extract information from the query descriptor and the query
	 * feature.
180
	 */
181 182 183
	operation = queryDesc->operation;
	plan = queryDesc->plantree;
	dest = queryDesc->dest;
184
	destfunc = DestToFunction(dest);
185 186 187
	estate->es_processed = 0;
	estate->es_lastoid = InvalidOid;

B
Bruce Momjian 已提交
188
	/*
B
Bruce Momjian 已提交
189 190 191 192
	 * FIXME: the dest setup function ought to be handed the tuple desc
	 * for the tuples to be output, but I'm not quite sure how to get that
	 * info at this point.	For now, passing NULL is OK because no
	 * existing dest setup function actually uses the pointer.
193 194 195
	 */
	(*destfunc->setup) (destfunc, (TupleDesc) NULL);

B
Bruce Momjian 已提交
196 197 198 199 200 201 202 203 204 205
	/*
	 * if given get the offset of the LIMIT clause
	 */
	if (limoffset != NULL)
	{
		Const	   *coffset;
		Param	   *poffset;
		ParamListInfo paramLI;
		int			i;

206 207 208
		switch (nodeTag(limoffset))
		{
			case T_Const:
B
Bruce Momjian 已提交
209 210
				coffset = (Const *) limoffset;
				offset = (int) (coffset->constvalue);
211
				break;
B
Bruce Momjian 已提交
212

213
			case T_Param:
B
Bruce Momjian 已提交
214
				poffset = (Param *) limoffset;
215
				paramLI = estate->es_param_list_info;
B
Bruce Momjian 已提交
216

217 218 219 220 221 222 223 224 225 226 227
				if (paramLI == NULL)
					elog(ERROR, "parameter for limit offset not in executor state");
				for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
				{
					if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
						break;
				}
				if (paramLI[i].kind == PARAM_INVALID)
					elog(ERROR, "parameter for limit offset not in executor state");
				if (paramLI[i].isnull)
					elog(ERROR, "limit offset cannot be NULL value");
B
Bruce Momjian 已提交
228 229
				offset = (int) (paramLI[i].value);

230
				break;
B
Bruce Momjian 已提交
231

232 233 234
			default:
				elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
		}
B
Bruce Momjian 已提交
235

236 237 238
		if (offset < 0)
			elog(ERROR, "limit offset cannot be negative");
	}
B
Bruce Momjian 已提交
239

B
Bruce Momjian 已提交
240
	/*
B
Bruce Momjian 已提交
241
	 * if given get the count of the LIMIT clause
242 243 244
	 */
	if (limcount != NULL)
	{
B
Bruce Momjian 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
		Const	   *ccount;
		Param	   *pcount;
		ParamListInfo paramLI;
		int			i;

		switch (nodeTag(limcount))
		{
			case T_Const:
				ccount = (Const *) limcount;
				count = (int) (ccount->constvalue);
				break;

			case T_Param:
				pcount = (Param *) limcount;
				paramLI = estate->es_param_list_info;

				if (paramLI == NULL)
					elog(ERROR, "parameter for limit count not in executor state");
				for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
				{
					if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
						break;
				}
				if (paramLI[i].kind == PARAM_INVALID)
					elog(ERROR, "parameter for limit count not in executor state");
				if (paramLI[i].isnull)
					elog(ERROR, "limit count cannot be NULL value");
				count = (int) (paramLI[i].value);

				break;

			default:
				elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
		}

		if (count < 0)
			elog(ERROR, "limit count cannot be negative");
282 283
	}

284 285 286
	switch (feature)
	{

287 288 289 290
		case EXEC_RUN:
			result = ExecutePlan(estate,
								 plan,
								 operation,
291 292
								 offset,
								 count,
293
								 ForwardScanDirection,
294
								 destfunc);
295 296 297 298 299
			break;
		case EXEC_FOR:
			result = ExecutePlan(estate,
								 plan,
								 operation,
300
								 offset,
301 302
								 count,
								 ForwardScanDirection,
303
								 destfunc);
304
			break;
305

B
Bruce Momjian 已提交
306
			/*
B
Bruce Momjian 已提交
307
			 * retrieve next n "backward" tuples
308 309 310 311 312
			 */
		case EXEC_BACK:
			result = ExecutePlan(estate,
								 plan,
								 operation,
313
								 offset,
314 315
								 count,
								 BackwardScanDirection,
316
								 destfunc);
317
			break;
318

B
Bruce Momjian 已提交
319
			/*
B
Bruce Momjian 已提交
320 321
			 * return one tuple but don't "retrieve" it. (this is used by
			 * the rule manager..) -cim 9/14/89
322 323 324 325 326
			 */
		case EXEC_RETONE:
			result = ExecutePlan(estate,
								 plan,
								 operation,
327
								 0,
328 329
								 ONE_TUPLE,
								 ForwardScanDirection,
330
								 destfunc);
331 332 333 334 335
			break;
		default:
			result = NULL;
			elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
			break;
336 337
	}

338 339
	(*destfunc->cleanup) (destfunc);

340
	return result;
341 342 343
}

/* ----------------------------------------------------------------
344 345 346 347 348 349 350
 *		ExecutorEnd
 *
 *		This routine must be called at the end of any execution of any
 *		query plan
 *
 *		returns (AttrInfo*) which describes the attributes of the tuples to
 *		be returned by the query.
351 352 353 354
 *
 * ----------------------------------------------------------------
 */
void
355
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
356
{
357 358
	/* sanity checks */
	Assert(queryDesc != NULL);
359

360
	EndPlan(queryDesc->plantree, estate);
361

362
	/* XXX - clean up some more from ExecutorStart() - er1p */
B
Bruce Momjian 已提交
363 364 365 366 367 368 369 370 371
	if (NULL == estate->es_snapshot)
	{
		/* nothing to free */
	}
	else
	{
		if (estate->es_snapshot->xcnt > 0)
			pfree(estate->es_snapshot->xip);
		pfree(estate->es_snapshot);
372 373
	}

B
Bruce Momjian 已提交
374 375 376 377 378 379 380 381
	if (NULL == estate->es_param_exec_vals)
	{
		/* nothing to free */
	}
	else
	{
		pfree(estate->es_param_exec_vals);
		estate->es_param_exec_vals = NULL;
382
	}
383 384
}

385 386 387 388 389 390 391

/*
 * ExecCheckQueryPerms
 *		Check access permissions for all relations referenced in a query.
 */
static void
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
392
{
393 394 395
	List	   *rangeTable = parseTree->rtable;
	int			resultRelation = parseTree->resultRelation;
	bool		resultIsScanned = false;
396
	List	   *lp;
397

398 399 400 401
	/*
	 * If we have a result relation, determine whether the result rel is
	 * scanned or merely written.  If scanned, we will insist on read
	 * permission as well as modify permission.
402 403 404 405
	 *
	 * Note: it might look faster to apply rangeTableEntry_used(), but
	 * that's not correct since it will trigger on jointree references
	 * to the RTE.  We only want to know about actual Var nodes.
406 407 408
	 */
	if (resultRelation > 0)
	{
409
		List	   *qvars = pull_varnos((Node *) parseTree);
410

411
		resultIsScanned = intMember(resultRelation, qvars);
412 413
		freeList(qvars);
	}
414

415 416 417 418 419 420 421 422 423
	/*
	 * Check RTEs in the query's primary rangetable.
	 */
	ExecCheckRTPerms(rangeTable, operation, resultRelation, resultIsScanned);

	/*
	 * Check SELECT FOR UPDATE access rights.
	 */
	foreach(lp, parseTree->rowMark)
424
	{
425
		RowMark    *rm = lfirst(lp);
426

427 428
		if (!(rm->info & ROW_ACL_FOR_UPDATE))
			continue;
429

430 431 432
		ExecCheckRTEPerms(rt_fetch(rm->rti, rangeTable),
						  CMD_UPDATE, true, false);
	}
433

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
	/*
	 * Search for subplans and APPEND nodes to check their rangetables.
	 */
	ExecCheckPlanPerms(plan, operation, resultRelation, resultIsScanned);
}

/*
 * ExecCheckPlanPerms
 *		Recursively scan the plan tree to check access permissions in
 *		subplans.
 *
 * We also need to look at the local rangetables in Append plan nodes,
 * which is pretty bogus --- most likely, those tables should be mentioned
 * in the query's main rangetable.  But at the moment, they're not.
 */
static void
ExecCheckPlanPerms(Plan *plan, CmdType operation,
				   int resultRelation, bool resultIsScanned)
{
	List	   *subp;

	if (plan == NULL)
		return;

	/* Check subplans, which we assume are plain SELECT queries */

	foreach(subp, plan->initPlan)
	{
462
		SubPlan    *subplan = (SubPlan *) lfirst(subp);
463 464 465 466 467 468

		ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
		ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
	}
	foreach(subp, plan->subPlan)
	{
469
		SubPlan    *subplan = (SubPlan *) lfirst(subp);
M
Marc G. Fournier 已提交
470

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
		ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
		ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
	}

	/* Check lower plan nodes */

	ExecCheckPlanPerms(plan->lefttree, operation,
					   resultRelation, resultIsScanned);
	ExecCheckPlanPerms(plan->righttree, operation,
					   resultRelation, resultIsScanned);

	/* Do node-type-specific checks */

	switch (nodeTag(plan))
	{
		case T_Append:
487
			{
488 489
				Append	   *app = (Append *) plan;
				List	   *appendplans;
490

491
				if (app->inheritrelid > 0)
492 493
				{

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
					/*
					 * Append implements expansion of inheritance; all
					 * members of inheritrtable list will be plugged into
					 * same RTE slot. Therefore, they are either all
					 * result relations or none.
					 */
					List	   *rtable;

					foreach(rtable, app->inheritrtable)
					{
						ExecCheckRTEPerms((RangeTblEntry *) lfirst(rtable),
										  operation,
								   (app->inheritrelid == resultRelation),
										  resultIsScanned);
					}
				}
				else
511
				{
512 513 514 515 516 517 518 519
					/* Append implements UNION, which must be a SELECT */
					List	   *rtables;

					foreach(rtables, app->unionrtables)
					{
						ExecCheckRTPerms((List *) lfirst(rtables),
										 CMD_SELECT, 0, false);
					}
520 521
				}

522 523 524 525 526 527 528 529 530
				/* Check appended plans */
				foreach(appendplans, app->appendplans)
				{
					ExecCheckPlanPerms((Plan *) lfirst(appendplans),
									   operation,
									   resultRelation,
									   resultIsScanned);
				}
				break;
531 532 533
			}

		default:
534
			break;
535
	}
536
}
537

538 539 540 541 542
/*
 * ExecCheckRTPerms
 *		Check access permissions for all relations listed in a range table.
 *
 * If resultRelation is not 0, it is the RT index of the relation to be
543
 * treated as the result relation.	All other relations are assumed to be
544 545 546 547 548 549 550 551 552 553
 * read-only for the query.
 */
static void
ExecCheckRTPerms(List *rangeTable, CmdType operation,
				 int resultRelation, bool resultIsScanned)
{
	int			rtindex = 0;
	List	   *lp;

	foreach(lp, rangeTable)
554
	{
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
		RangeTblEntry *rte = lfirst(lp);

		++rtindex;

		ExecCheckRTEPerms(rte,
						  operation,
						  (rtindex == resultRelation),
						  resultIsScanned);
	}
}

/*
 * ExecCheckRTEPerms
 *		Check access permissions for a single RTE.
 */
static void
ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
				  bool isResultRelation, bool resultIsScanned)
{
	char	   *relName;
575
	Oid			userid;
576 577 578 579
	int32		aclcheck_result;

	if (rte->skipAcl)
	{
580

581
		/*
582 583 584
		 * This happens if the access to this table is due to a view query
		 * rewriting - the rewrite handler already checked the permissions
		 * against the view owner, so we just skip this entry.
585 586 587 588 589 590 591
		 */
		return;
	}

	relName = rte->relname;

	/*
592
	 * Note: GetUserId() is presently fast enough that there's no harm
593
	 * in calling it separately for each RTE.  If that stops being true,
594
	 * we could call it once in ExecCheckQueryPerms and pass the userid
595 596
	 * down from there.  But for now, no need for the extra clutter.
	 */
597
	userid = GetUserId();
598

599
#define CHECK(MODE)		pg_aclcheck(relName, userid, MODE)
600

601 602 603 604 605 606 607 608
	if (isResultRelation)
	{
		if (resultIsScanned)
		{
			aclcheck_result = CHECK(ACL_RD);
			if (aclcheck_result != ACLCHECK_OK)
				elog(ERROR, "%s: %s",
					 relName, aclcheck_error_strings[aclcheck_result]);
609
		}
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
		switch (operation)
		{
			case CMD_INSERT:
				/* Accept either APPEND or WRITE access for this */
				aclcheck_result = CHECK(ACL_AP);
				if (aclcheck_result != ACLCHECK_OK)
					aclcheck_result = CHECK(ACL_WR);
				break;
			case CMD_DELETE:
			case CMD_UPDATE:
				aclcheck_result = CHECK(ACL_WR);
				break;
			default:
				elog(ERROR, "ExecCheckRTEPerms: bogus operation %d",
					 operation);
625
				aclcheck_result = ACLCHECK_OK;	/* keep compiler quiet */
626 627 628 629 630 631 632 633 634
				break;
		}
	}
	else
		aclcheck_result = CHECK(ACL_RD);

	if (aclcheck_result != ACLCHECK_OK)
		elog(ERROR, "%s: %s",
			 relName, aclcheck_error_strings[aclcheck_result]);
635 636
}

637

638 639 640 641 642 643 644
/* ===============================================================
 * ===============================================================
						 static routines follow
 * ===============================================================
 * ===============================================================
 */

645 646 647
typedef struct execRowMark
{
	Relation	relation;
648
	Index		rti;
649
	char		resname[32];
650
} execRowMark;
651

652 653
typedef struct evalPlanQual
{
B
Bruce Momjian 已提交
654 655 656 657
	Plan	   *plan;
	Index		rti;
	EState		estate;
	struct evalPlanQual *free;
658
} evalPlanQual;
659

660
/* ----------------------------------------------------------------
661 662 663 664
 *		InitPlan
 *
 *		Initializes the query plan: open files, allocate storage
 *		and start up the rule manager
665 666
 * ----------------------------------------------------------------
 */
667
static TupleDesc
668
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
669
{
B
Bruce Momjian 已提交
670 671 672 673 674
	List	   *rangeTable;
	int			resultRelation;
	Relation	intoRelationDesc;
	TupleDesc	tupType;
	List	   *targetList;
675

676 677 678 679 680 681 682
	/*
	 * Do permissions checks.
	 */
#ifndef NO_SECURITY
	ExecCheckQueryPerms(operation, parseTree, plan);
#endif

B
Bruce Momjian 已提交
683
	/*
B
Bruce Momjian 已提交
684
	 * get information from query descriptor
685
	 */
686 687
	rangeTable = parseTree->rtable;
	resultRelation = parseTree->resultRelation;
688

B
Bruce Momjian 已提交
689
	/*
B
Bruce Momjian 已提交
690
	 * initialize the node's execution state
691
	 */
692 693
	estate->es_range_table = rangeTable;

B
Bruce Momjian 已提交
694
	/*
B
Bruce Momjian 已提交
695
	 * initialize result relation stuff
696
	 */
B
Bruce Momjian 已提交
697

698 699
	if (resultRelation != 0 && operation != CMD_SELECT)
	{
B
Bruce Momjian 已提交
700

B
Bruce Momjian 已提交
701
		/*
B
Bruce Momjian 已提交
702 703
		 * if we have a result relation, open it and initialize the result
		 * relation info stuff.
704
		 */
705 706 707 708
		RelationInfo *resultRelationInfo;
		Index		resultRelationIndex;
		Oid			resultRelationOid;
		Relation	resultRelationDesc;
709 710

		resultRelationIndex = resultRelation;
711
		resultRelationOid = getrelid(resultRelationIndex, rangeTable);
712
		resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);
713 714

		if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
715
			elog(ERROR, "You can't change sequence relation %s",
716
				 RelationGetRelationName(resultRelationDesc));
717

718 719 720 721
		if (resultRelationDesc->rd_rel->relkind == RELKIND_TOASTVALUE)
			elog(ERROR, "You can't change toast relation %s",
				 RelationGetRelationName(resultRelationDesc));

722 723 724 725
		if (resultRelationDesc->rd_rel->relkind == RELKIND_VIEW)
			elog(ERROR, "You can't change view relation %s",
				 RelationGetRelationName(resultRelationDesc));

726 727 728 729 730 731
		resultRelationInfo = makeNode(RelationInfo);
		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
		resultRelationInfo->ri_RelationDesc = resultRelationDesc;
		resultRelationInfo->ri_NumIndices = 0;
		resultRelationInfo->ri_IndexRelationDescs = NULL;
		resultRelationInfo->ri_IndexRelationInfo = NULL;
732

B
Bruce Momjian 已提交
733
		/*
734 735
		 * If there are indices on the result relation, open them and save
		 * descriptors in the result relation info, so that we can add new
736 737 738
		 * index entries for the tuples we add/update.	We need not do
		 * this for a DELETE, however, since deletion doesn't affect
		 * indexes.
739
		 */
740 741
		if (resultRelationDesc->rd_rel->relhasindex &&
			operation != CMD_DELETE)
742
			ExecOpenIndices(resultRelationInfo);
743 744

		estate->es_result_relation_info = resultRelationInfo;
745
	}
746 747
	else
	{
B
Bruce Momjian 已提交
748

B
Bruce Momjian 已提交
749
		/*
B
Bruce Momjian 已提交
750
		 * if no result relation, then set state appropriately
751 752 753 754
		 */
		estate->es_result_relation_info = NULL;
	}

755 756 757 758 759 760
	/*
	 * Have to lock relations selected for update
	 */
	estate->es_rowMark = NULL;
	if (parseTree->rowMark != NULL)
	{
B
Bruce Momjian 已提交
761
		List	   *l;
762 763 764

		foreach(l, parseTree->rowMark)
		{
765 766 767 768 769
			RowMark    *rm = lfirst(l);
			Oid			relid;
			Relation	relation;
			execRowMark *erm;

770 771
			if (!(rm->info & ROW_MARK_FOR_UPDATE))
				continue;
772
			relid = getrelid(rm->rti, rangeTable);
773
			relation = heap_open(relid, RowShareLock);
B
Bruce Momjian 已提交
774
			erm = (execRowMark *) palloc(sizeof(execRowMark));
775
			erm->relation = relation;
776
			erm->rti = rm->rti;
777 778 779 780
			sprintf(erm->resname, "ctid%u", rm->rti);
			estate->es_rowMark = lappend(estate->es_rowMark, erm);
		}
	}
781

B
Bruce Momjian 已提交
782
	/*
B
Bruce Momjian 已提交
783
	 * initialize the executor "tuple" table.
784 785
	 */
	{
786 787
		int			nSlots = ExecCountSlotsNode(plan);
		TupleTable	tupleTable = ExecCreateTupleTable(nSlots + 10);		/* why add ten? - jolly */
788

789 790
		estate->es_tupleTable = tupleTable;
	}
791

B
Bruce Momjian 已提交
792
	/*
B
Bruce Momjian 已提交
793 794
	 * initialize the private state information for all the nodes in the
	 * query tree.	This opens files, allocates storage and leaves us
795
	 * ready to start processing tuples.
796 797 798
	 */
	ExecInitNode(plan, estate, NULL);

B
Bruce Momjian 已提交
799
	/*
B
Bruce Momjian 已提交
800 801 802
	 * get the tuple descriptor describing the type of tuples to return..
	 * (this is especially important if we are creating a relation with
	 * "retrieve into")
803 804 805 806
	 */
	tupType = ExecGetTupType(plan);		/* tuple descriptor */
	targetList = plan->targetlist;

B
Bruce Momjian 已提交
807
	/*
808 809 810 811 812
	 * Now that we have the target list, initialize the junk filter if
	 * needed. SELECT and INSERT queries need a filter if there are any
	 * junk attrs in the tlist.  UPDATE and DELETE always need one, since
	 * there's always a junk 'ctid' attribute present --- no need to look
	 * first.
813 814
	 */
	{
815 816 817
		bool		junk_filter_needed = false;
		List	   *tlist;

818
		switch (operation)
819
		{
820 821 822
			case CMD_SELECT:
			case CMD_INSERT:
				foreach(tlist, targetList)
823
				{
824 825 826 827 828 829 830
					TargetEntry *tle = (TargetEntry *) lfirst(tlist);

					if (tle->resdom->resjunk)
					{
						junk_filter_needed = true;
						break;
					}
831
				}
832 833 834 835 836 837 838
				break;
			case CMD_UPDATE:
			case CMD_DELETE:
				junk_filter_needed = true;
				break;
			default:
				break;
839 840
		}

841
		if (junk_filter_needed)
842
		{
843
			JunkFilter *j = ExecInitJunkFilter(targetList, tupType);
844

845
			estate->es_junkFilter = j;
846

847 848 849 850 851 852
			if (operation == CMD_SELECT)
				tupType = j->jf_cleanTupType;
		}
		else
			estate->es_junkFilter = NULL;
	}
853

B
Bruce Momjian 已提交
854
	/*
B
Bruce Momjian 已提交
855
	 * initialize the "into" relation
856 857 858 859 860
	 */
	intoRelationDesc = (Relation) NULL;

	if (operation == CMD_SELECT)
	{
861 862 863
		char	   *intoName;
		Oid			intoRelationId;
		TupleDesc	tupdesc;
864 865 866 867 868 869 870 871 872

		if (!parseTree->isPortal)
		{

			/*
			 * a select into table
			 */
			if (parseTree->into != NULL)
			{
B
Bruce Momjian 已提交
873

B
Bruce Momjian 已提交
874
				/*
B
Bruce Momjian 已提交
875
				 * create the "into" relation
876 877 878 879 880 881 882 883
				 */
				intoName = parseTree->into;

				/*
				 * have to copy tupType to get rid of constraints
				 */
				tupdesc = CreateTupleDescCopy(tupType);

884 885 886 887 888 889
				intoRelationId =
					heap_create_with_catalog(intoName,
											 tupdesc,
											 RELKIND_RELATION,
											 parseTree->isTemp,
											 allowSystemTableMods);
890

891 892
				FreeTupleDesc(tupdesc);

B
Bruce Momjian 已提交
893
				/*
894 895
				 * Advance command counter so that the newly-created
				 * relation's catalog tuples will be visible to heap_open.
896
				 */
897
				CommandCounterIncrement();
898

899 900 901 902 903
				/*
				 * Eventually create a TOAST table for the into relation
				 */
				AlterTableCreateToastTable(intoName, true);

904 905
				intoRelationDesc = heap_open(intoRelationId,
											 AccessExclusiveLock);
906 907 908 909 910 911
			}
		}
	}

	estate->es_into_relation_descriptor = intoRelationDesc;

912 913 914 915 916
	estate->es_origPlan = plan;
	estate->es_evalPlanQual = NULL;
	estate->es_evTuple = NULL;
	estate->es_useEvalPlan = false;

917
	return tupType;
918 919 920
}

/* ----------------------------------------------------------------
921 922 923
 *		EndPlan
 *
 *		Cleans up the query plan -- closes files and free up storages
924 925 926
 * ----------------------------------------------------------------
 */
static void
927
EndPlan(Plan *plan, EState *estate)
928
{
929
	RelationInfo *resultRelationInfo;
930
	List	   *l;
931

932 933 934 935 936 937
	/*
	 * shut down any PlanQual processing we were doing
	 */
	if (estate->es_evalPlanQual != NULL)
		EndEvalPlanQual(estate);

B
Bruce Momjian 已提交
938
	/*
939
	 * shut down the node-type-specific query processing
940 941 942
	 */
	ExecEndNode(plan, plan);

B
Bruce Momjian 已提交
943
	/*
B
Bruce Momjian 已提交
944
	 * destroy the executor "tuple" table.
945
	 */
946 947
	ExecDropTupleTable(estate->es_tupleTable, true);
	estate->es_tupleTable = NULL;
948

B
Bruce Momjian 已提交
949
	/*
950 951 952
	 * close the result relation if necessary, but hold lock on it
	 * until xact commit.  NB: must not do this till after ExecEndNode(),
	 * see nodeAppend.c ...
953
	 */
954
	resultRelationInfo = estate->es_result_relation_info;
955 956
	if (resultRelationInfo != NULL)
	{
957 958
		heap_close(resultRelationInfo->ri_RelationDesc, NoLock);
		/* close indices on the result relation, too */
959 960 961
		ExecCloseIndices(resultRelationInfo);
	}

B
Bruce Momjian 已提交
962
	/*
963
	 * close the "into" relation if necessary, again keeping lock
964
	 */
965 966
	if (estate->es_into_relation_descriptor != NULL)
		heap_close(estate->es_into_relation_descriptor, NoLock);
967 968 969 970 971 972 973 974 975 976

	/*
	 * close any relations selected FOR UPDATE, again keeping locks
	 */
	foreach(l, estate->es_rowMark)
	{
		execRowMark *erm = lfirst(l);

		heap_close(erm->relation, NoLock);
	}
977 978 979
}

/* ----------------------------------------------------------------
980 981 982 983 984 985 986 987
 *		ExecutePlan
 *
 *		processes the query plan to retrieve 'tupleCount' tuples in the
 *		direction specified.
 *		Retrieves all tuples if tupleCount is 0
 *
 *		result is either a slot containing a tuple in the case
 *		of a RETRIEVE or NULL otherwise.
988 989 990 991 992 993 994 995
 *
 * ----------------------------------------------------------------
 */

/* the ctid attribute is a 'junk' attribute that is removed before the
   user can see it*/

static TupleTableSlot *
996 997
ExecutePlan(EState *estate,
			Plan *plan,
998
			CmdType operation,
999
			int offsetTuples,
1000 1001
			int numberTuples,
			ScanDirection direction,
1002
			DestReceiver *destfunc)
1003
{
1004
	JunkFilter *junkfilter;
1005
	TupleTableSlot *slot;
1006
	ItemPointer tupleid = NULL;
1007
	ItemPointerData tuple_ctid;
1008
	int			current_tuple_count;
1009 1010
	TupleTableSlot *result;

B
Bruce Momjian 已提交
1011
	/*
B
Bruce Momjian 已提交
1012
	 * initialize local variables
1013
	 */
1014 1015 1016 1017
	slot = NULL;
	current_tuple_count = 0;
	result = NULL;

B
Bruce Momjian 已提交
1018 1019
	/*
	 * Set the direction.
1020
	 */
1021 1022
	estate->es_direction = direction;

B
Bruce Momjian 已提交
1023
	/*
B
Bruce Momjian 已提交
1024 1025
	 * Loop until we've processed the proper number of tuples from the
	 * plan..
1026 1027 1028 1029
	 */

	for (;;)
	{
B
Bruce Momjian 已提交
1030

B
Bruce Momjian 已提交
1031
		/*
B
Bruce Momjian 已提交
1032
		 * Execute the plan and obtain a tuple
1033 1034
		 */
		/* at the top level, the parent of a plan (2nd arg) is itself */
B
Bruce Momjian 已提交
1035
lnext:	;
1036 1037 1038 1039 1040 1041 1042 1043
		if (estate->es_useEvalPlan)
		{
			slot = EvalPlanQualNext(estate);
			if (TupIsNull(slot))
				slot = ExecProcNode(plan, plan);
		}
		else
			slot = ExecProcNode(plan, plan);
1044

B
Bruce Momjian 已提交
1045
		/*
B
Bruce Momjian 已提交
1046 1047
		 * if the tuple is null, then we assume there is nothing more to
		 * process so we just return null...
1048 1049 1050 1051 1052
		 */
		if (TupIsNull(slot))
		{
			result = NULL;
			break;
1053 1054
		}

B
Bruce Momjian 已提交
1055
		/*
B
Bruce Momjian 已提交
1056 1057 1058
		 * For now we completely execute the plan and skip result tuples
		 * if requested by LIMIT offset. Finally we should try to do it in
		 * deeper levels if possible (during index scan) - Jan
1059 1060 1061 1062 1063 1064 1065
		 */
		if (offsetTuples > 0)
		{
			--offsetTuples;
			continue;
		}

B
Bruce Momjian 已提交
1066
		/*
B
Bruce Momjian 已提交
1067 1068
		 * if we have a junk filter, then project a new tuple with the
		 * junk removed.
1069
		 *
B
Bruce Momjian 已提交
1070
		 * Store this new "clean" tuple in the place of the original tuple.
1071
		 *
B
Bruce Momjian 已提交
1072
		 * Also, extract all the junk information we need.
1073 1074 1075
		 */
		if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
		{
1076 1077 1078
			Datum		datum;
			HeapTuple	newTuple;
			bool		isNull;
1079

B
Bruce Momjian 已提交
1080
			/*
1081 1082 1083 1084 1085 1086 1087 1088 1089
			 * extract the 'ctid' junk attribute.
			 */
			if (operation == CMD_UPDATE || operation == CMD_DELETE)
			{
				if (!ExecGetJunkAttribute(junkfilter,
										  slot,
										  "ctid",
										  &datum,
										  &isNull))
1090
					elog(ERROR, "ExecutePlan: NO (junk) `ctid' was found!");
1091 1092

				if (isNull)
1093
					elog(ERROR, "ExecutePlan: (junk) `ctid' is NULL!");
1094 1095 1096 1097 1098 1099

				tupleid = (ItemPointer) DatumGetPointer(datum);
				tuple_ctid = *tupleid;	/* make sure we don't free the
										 * ctid!! */
				tupleid = &tuple_ctid;
			}
1100 1101
			else if (estate->es_rowMark != NULL)
			{
B
Bruce Momjian 已提交
1102
				List	   *l;
1103

B
Bruce Momjian 已提交
1104 1105
		lmark:	;
				foreach(l, estate->es_rowMark)
1106
				{
1107 1108 1109 1110 1111 1112
					execRowMark *erm = lfirst(l);
					Buffer		buffer;
					HeapTupleData tuple;
					TupleTableSlot *newSlot;
					int			test;

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
					if (!ExecGetJunkAttribute(junkfilter,
											  slot,
											  erm->resname,
											  &datum,
											  &isNull))
						elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!", erm->resname);

					if (isNull)
						elog(ERROR, "ExecutePlan: (junk) `%s' is NULL!", erm->resname);

					tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
					test = heap_mark4update(erm->relation, &tuple, &buffer);
					ReleaseBuffer(buffer);
					switch (test)
					{
						case HeapTupleSelfUpdated:
						case HeapTupleMayBeUpdated:
							break;

						case HeapTupleUpdated:
							if (XactIsoLevel == XACT_SERIALIZABLE)
1134
							{
1135
								elog(ERROR, "Can't serialize access due to concurrent update");
B
Bruce Momjian 已提交
1136
								return (NULL);
1137
							}
B
Bruce Momjian 已提交
1138 1139
							else if (!(ItemPointerEquals(&(tuple.t_self),
								  (ItemPointer) DatumGetPointer(datum))))
1140
							{
B
Bruce Momjian 已提交
1141
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
1142 1143 1144 1145 1146 1147 1148
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1149 1150 1151 1152 1153

							/*
							 * if tuple was deleted or PlanQual failed for
							 * updated tuple - we have not return this
							 * tuple!
1154 1155
							 */
							goto lnext;
1156 1157 1158

						default:
							elog(ERROR, "Unknown status %u from heap_mark4update", test);
B
Bruce Momjian 已提交
1159
							return (NULL);
1160 1161 1162
					}
				}
			}
1163

B
Bruce Momjian 已提交
1164
			/*
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
			 * Finally create a new "clean" tuple with all junk attributes
			 * removed
			 */
			newTuple = ExecRemoveJunk(junkfilter, slot);

			slot = ExecStoreTuple(newTuple,		/* tuple to store */
								  slot, /* destination slot */
								  InvalidBuffer,		/* this tuple has no
														 * buffer */
								  true);		/* tuple should be pfreed */
		}						/* if (junkfilter... */

B
Bruce Momjian 已提交
1177
		/*
B
Bruce Momjian 已提交
1178 1179
		 * now that we have a tuple, do the appropriate thing with it..
		 * either return it to the user, add it to a relation someplace,
B
Bruce Momjian 已提交
1180
		 * delete it from a relation, or modify some of its attributes.
1181 1182 1183 1184
		 */

		switch (operation)
		{
1185 1186
			case CMD_SELECT:
				ExecRetrieve(slot,		/* slot containing tuple */
B
Bruce Momjian 已提交
1187 1188
							 destfunc,	/* destination's tuple-receiver
										 * obj */
1189 1190 1191
							 estate);	/* */
				result = slot;
				break;
1192

1193 1194 1195 1196
			case CMD_INSERT:
				ExecAppend(slot, tupleid, estate);
				result = NULL;
				break;
1197

1198 1199 1200 1201
			case CMD_DELETE:
				ExecDelete(slot, tupleid, estate);
				result = NULL;
				break;
1202

1203
			case CMD_UPDATE:
1204
				ExecReplace(slot, tupleid, estate);
1205 1206
				result = NULL;
				break;
1207

1208 1209
			default:
				elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
1210
				result = NULL;
1211
				break;
1212
		}
B
Bruce Momjian 已提交
1213

B
Bruce Momjian 已提交
1214
		/*
B
Bruce Momjian 已提交
1215 1216
		 * check our tuple count.. if we've returned the proper number
		 * then return, else loop again and process more tuples..
1217 1218 1219 1220
		 */
		current_tuple_count += 1;
		if (numberTuples == current_tuple_count)
			break;
1221
	}
1222

B
Bruce Momjian 已提交
1223
	/*
B
Bruce Momjian 已提交
1224 1225
	 * here, result is either a slot containing a tuple in the case of a
	 * RETRIEVE or NULL otherwise.
1226
	 */
1227
	return result;
1228 1229 1230
}

/* ----------------------------------------------------------------
1231
 *		ExecRetrieve
1232
 *
1233 1234 1235 1236 1237
 *		RETRIEVEs are easy.. we just pass the tuple to the appropriate
 *		print function.  The only complexity is when we do a
 *		"retrieve into", in which case we insert the tuple into
 *		the appropriate relation (note: this is a newly created relation
 *		so we don't need to worry about indices or locks.)
1238 1239 1240
 * ----------------------------------------------------------------
 */
static void
1241
ExecRetrieve(TupleTableSlot *slot,
1242
			 DestReceiver *destfunc,
1243
			 EState *estate)
1244
{
1245 1246
	HeapTuple	tuple;
	TupleDesc	attrtype;
1247

B
Bruce Momjian 已提交
1248
	/*
B
Bruce Momjian 已提交
1249
	 * get the heap tuple out of the tuple table slot
1250 1251 1252 1253
	 */
	tuple = slot->val;
	attrtype = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
1254
	/*
B
Bruce Momjian 已提交
1255
	 * insert the tuple into the "into relation"
1256 1257 1258 1259 1260 1261 1262
	 */
	if (estate->es_into_relation_descriptor != NULL)
	{
		heap_insert(estate->es_into_relation_descriptor, tuple);
		IncrAppended();
	}

B
Bruce Momjian 已提交
1263
	/*
B
Bruce Momjian 已提交
1264
	 * send the tuple to the front end (or the screen)
1265
	 */
1266
	(*destfunc->receiveTuple) (tuple, attrtype, destfunc);
1267 1268
	IncrRetrieved();
	(estate->es_processed)++;
1269 1270 1271
}

/* ----------------------------------------------------------------
1272
 *		ExecAppend
1273
 *
1274 1275 1276
 *		APPENDs are trickier.. we have to insert the tuple into
 *		the base relation and insert appropriate tuples into the
 *		index relations.
1277 1278 1279 1280
 * ----------------------------------------------------------------
 */

static void
1281
ExecAppend(TupleTableSlot *slot,
1282
		   ItemPointer tupleid,
1283
		   EState *estate)
1284
{
1285 1286 1287 1288 1289
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	int			numIndices;
	Oid			newId;
1290

B
Bruce Momjian 已提交
1291
	/*
B
Bruce Momjian 已提交
1292
	 * get the heap tuple out of the tuple table slot
1293 1294 1295
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1296
	/*
B
Bruce Momjian 已提交
1297
	 * get information on the result relation
1298 1299 1300 1301 1302 1303 1304 1305
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1306
		HeapTuple	newtuple;
1307 1308 1309 1310 1311 1312 1313 1314 1315

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

		if (newtuple == NULL)	/* "do nothing" */
			return;

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1316
			heap_freetuple(tuple);
1317 1318 1319 1320
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1321
	/*
1322
	 * Check the constraints of the tuple
1323 1324 1325
	 */

	if (resultRelationDesc->rd_att->constr)
1326
		ExecConstraints("ExecAppend", resultRelationDesc, slot, estate);
1327

B
Bruce Momjian 已提交
1328
	/*
B
Bruce Momjian 已提交
1329
	 * insert the tuple
1330
	 */
1331 1332
	newId = heap_insert(resultRelationDesc, tuple);

1333
	IncrAppended();
1334 1335
	(estate->es_processed)++;
	estate->es_lastoid = newId;
1336

B
Bruce Momjian 已提交
1337
	/*
B
Bruce Momjian 已提交
1338
	 * process indices
1339
	 *
B
Bruce Momjian 已提交
1340 1341 1342
	 * Note: heap_insert adds a new tuple to a relation.  As a side effect,
	 * the tupleid of the new tuple is placed in the new tuple's t_ctid
	 * field.
1343 1344 1345
	 */
	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1346
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1347 1348

	/* AFTER ROW INSERT Triggers */
1349
	if (resultRelationDesc->trigdesc)
1350
		ExecARInsertTriggers(resultRelationDesc, tuple);
1351 1352 1353
}

/* ----------------------------------------------------------------
1354
 *		ExecDelete
1355
 *
1356 1357
 *		DELETE is like append, we delete the tuple and its
 *		index tuples.
1358 1359 1360
 * ----------------------------------------------------------------
 */
static void
1361
ExecDelete(TupleTableSlot *slot,
1362
		   ItemPointer tupleid,
1363
		   EState *estate)
1364
{
B
Bruce Momjian 已提交
1365 1366 1367 1368
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
1369

B
Bruce Momjian 已提交
1370
	/*
B
Bruce Momjian 已提交
1371
	 * get the result relation information
1372 1373 1374 1375 1376 1377 1378 1379
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

	/* BEFORE ROW DELETE Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
	{
1380
		bool		dodelete;
1381

V
Vadim B. Mikheev 已提交
1382
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1383 1384 1385 1386 1387

		if (!dodelete)			/* "do nothing" */
			return;
	}

V
Vadim B. Mikheev 已提交
1388
	/*
B
Bruce Momjian 已提交
1389
	 * delete the tuple
1390
	 */
1391
ldelete:;
V
Vadim B. Mikheev 已提交
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
	result = heap_delete(resultRelationDesc, tupleid, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1402 1403
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1404 1405
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1406 1407
				TupleTableSlot *epqslot = EvalPlanQual(estate,
						  resultRelationInfo->ri_RangeTableIndex, &ctid);
1408

V
Vadim B. Mikheev 已提交
1409
				if (!TupIsNull(epqslot))
1410 1411 1412 1413 1414
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1415 1416 1417 1418 1419 1420
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1421 1422 1423 1424

	IncrDeleted();
	(estate->es_processed)++;

B
Bruce Momjian 已提交
1425
	/*
B
Bruce Momjian 已提交
1426 1427
	 * Note: Normally one would think that we have to delete index tuples
	 * associated with the heap tuple now..
1428
	 *
B
Bruce Momjian 已提交
1429 1430 1431
	 * ... but in POSTGRES, we have no need to do this because the vacuum
	 * daemon automatically opens an index scan and deletes index tuples
	 * when it finds deleted heap tuples. -cim 9/27/89
1432 1433 1434
	 */

	/* AFTER ROW DELETE Triggers */
1435
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1436
		ExecARDeleteTriggers(estate, tupleid);
1437 1438 1439 1440

}

/* ----------------------------------------------------------------
1441
 *		ExecReplace
1442
 *
1443 1444 1445 1446 1447 1448
 *		note: we can't run replace queries with transactions
 *		off because replaces are actually appends and our
 *		scan will mistakenly loop forever, replacing the tuple
 *		it just appended..	This should be fixed but until it
 *		is, we don't want to get stuck in an infinite loop
 *		which corrupts your database..
1449 1450 1451
 * ----------------------------------------------------------------
 */
static void
1452
ExecReplace(TupleTableSlot *slot,
1453
			ItemPointer tupleid,
1454
			EState *estate)
1455
{
B
Bruce Momjian 已提交
1456 1457 1458 1459 1460 1461
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
	int			numIndices;
1462

B
Bruce Momjian 已提交
1463
	/*
B
Bruce Momjian 已提交
1464
	 * abort the operation if not running transactions
1465 1466 1467
	 */
	if (IsBootstrapProcessingMode())
	{
1468
		elog(NOTICE, "ExecReplace: replace can't run without transactions");
1469 1470 1471
		return;
	}

B
Bruce Momjian 已提交
1472
	/*
B
Bruce Momjian 已提交
1473
	 * get the heap tuple out of the tuple table slot
1474 1475 1476
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1477
	/*
B
Bruce Momjian 已提交
1478
	 * get the result relation information
1479 1480 1481 1482 1483 1484 1485 1486
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

	/* BEFORE ROW UPDATE Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
	{
1487
		HeapTuple	newtuple;
1488

V
Vadim B. Mikheev 已提交
1489
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1490 1491 1492 1493 1494 1495 1496

		if (newtuple == NULL)	/* "do nothing" */
			return;

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1497
			heap_freetuple(tuple);
1498 1499 1500 1501
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1502
	/*
1503
	 * Check the constraints of the tuple
1504 1505 1506
	 */

	if (resultRelationDesc->rd_att->constr)
1507
		ExecConstraints("ExecReplace", resultRelationDesc, slot, estate);
1508

V
Vadim B. Mikheev 已提交
1509
	/*
B
Bruce Momjian 已提交
1510
	 * replace the heap tuple
1511
	 */
1512
lreplace:;
1513
	result = heap_update(resultRelationDesc, tupleid, tuple, &ctid);
V
Vadim B. Mikheev 已提交
1514 1515 1516 1517 1518 1519 1520 1521 1522
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1523 1524
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1525 1526
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1527 1528
				TupleTableSlot *epqslot = EvalPlanQual(estate,
						  resultRelationInfo->ri_RangeTableIndex, &ctid);
1529

V
Vadim B. Mikheev 已提交
1530
				if (!TupIsNull(epqslot))
1531 1532
				{
					*tupleid = ctid;
V
Vadim B. Mikheev 已提交
1533 1534
					tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
					slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1535 1536 1537
					goto lreplace;
				}
			}
V
Vadim B. Mikheev 已提交
1538 1539 1540
			return;

		default:
1541
			elog(ERROR, "Unknown status %u from heap_update", result);
V
Vadim B. Mikheev 已提交
1542
			return;
1543 1544 1545 1546 1547
	}

	IncrReplaced();
	(estate->es_processed)++;

B
Bruce Momjian 已提交
1548
	/*
B
Bruce Momjian 已提交
1549 1550
	 * Note: instead of having to update the old index tuples associated
	 * with the heap tuple, all we do is form and insert new index
1551 1552 1553
	 * tuples.  This is because replaces are actually deletes and inserts
	 * and index tuple deletion is done automagically by the vacuum
	 * daemon. All we do is insert new index tuples.  -cim 9/27/89
1554 1555
	 */

B
Bruce Momjian 已提交
1556
	/*
B
Bruce Momjian 已提交
1557
	 * process indices
1558
	 *
1559
	 * heap_update updates a tuple in the base relation by invalidating it
B
Bruce Momjian 已提交
1560 1561 1562 1563
	 * and then appending a new tuple to the relation.	As a side effect,
	 * the tupleid of the new tuple is placed in the new tuple's t_ctid
	 * field.  So we now insert index tuples using the new tupleid stored
	 * there.
1564 1565 1566 1567
	 */

	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1568
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1569 1570

	/* AFTER ROW UPDATE Triggers */
1571
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1572
		ExecARUpdateTriggers(estate, tupleid, tuple);
1573
}
V
Vadim B. Mikheev 已提交
1574

1575
static char *
1576
ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
V
Vadim B. Mikheev 已提交
1577
{
1578 1579
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
1580
	ExprContext *econtext;
1581
	MemoryContext oldContext;
1582 1583
	List	   *qual;
	int			i;
1584

1585
	/*
1586 1587 1588
	 * We will use the EState's per-tuple context for evaluating constraint
	 * expressions.  Create it if it's not already there; if it is, reset it
	 * to free previously-used storage.
1589
	 */
1590
	econtext = estate->es_per_tuple_exprcontext;
1591
	if (econtext == NULL)
1592 1593 1594 1595 1596 1597
	{
		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
		estate->es_per_tuple_exprcontext = econtext =
			MakeExprContext(NULL, estate->es_query_cxt);
		MemoryContextSwitchTo(oldContext);
	}
1598 1599
	else
		ResetExprContext(econtext);
1600

1601
	/*
1602 1603
	 * If first time through for current result relation, set up econtext's
	 * range table to refer to result rel, and build expression nodetrees
1604 1605
	 * for rel's constraint expressions.  All this stuff is kept in the
	 * per-query memory context so it will still be here next time through.
1606 1607 1608 1609 1610
	 *
	 * NOTE: if there are multiple result relations (eg, due to inheritance)
	 * then we leak storage for prior rel's expressions and rangetable.
	 * This should not be a big problem as long as result rels are processed
	 * sequentially within a command.
1611
	 */
1612 1613
	if (econtext->ecxt_range_table == NIL ||
		getrelid(1, econtext->ecxt_range_table) != RelationGetRelid(rel))
1614
	{
1615 1616 1617 1618 1619 1620 1621 1622
		RangeTblEntry *rte;

		/*
		 * Make sure expressions, etc are placed in appropriate context.
		 */
		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);

		rte = makeNode(RangeTblEntry);
1623 1624 1625

		rte->relname = RelationGetRelationName(rel);
		rte->relid = RelationGetRelid(rel);
1626 1627 1628
		rte->eref = makeNode(Attr);
		rte->eref->relname = rte->relname;
		/* inh, inFromCl, skipAcl won't be used, leave them zero */
1629

1630 1631
		/* Set up single-entry range table */
		econtext->ecxt_range_table = lcons(rte, NIL);
1632

1633
		estate->es_result_relation_constraints =
B
Bruce Momjian 已提交
1634
			(List **) palloc(ncheck * sizeof(List *));
1635 1636 1637 1638 1639 1640 1641

		for (i = 0; i < ncheck; i++)
		{
			qual = (List *) stringToNode(check[i].ccbin);
			estate->es_result_relation_constraints[i] = qual;
		}

1642 1643 1644
		/* Done with building long-lived items */
		MemoryContextSwitchTo(oldContext);
	}
1645 1646 1647 1648 1649

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

	/* And evaluate the constraints */
1650 1651
	for (i = 0; i < ncheck; i++)
	{
1652
		qual = estate->es_result_relation_constraints[i];
1653

1654 1655
		/*
		 * NOTE: SQL92 specifies that a NULL result from a constraint
1656 1657
		 * expression is not to be treated as a failure.  Therefore, tell
		 * ExecQual to return TRUE for NULL.
1658
		 */
1659
		if (!ExecQual(qual, econtext, true))
1660
			return check[i].ccname;
1661 1662
	}

1663
	/* NULL result means no error */
1664
	return (char *) NULL;
V
Vadim B. Mikheev 已提交
1665 1666
}

1667
void
1668 1669
ExecConstraints(char *caller, Relation rel,
				TupleTableSlot *slot, EState *estate)
V
Vadim B. Mikheev 已提交
1670
{
1671 1672 1673 1674
	HeapTuple	tuple = slot->val;
	TupleConstr *constr = rel->rd_att->constr;

	Assert(constr);
1675

1676
	if (constr->has_not_null)
V
Vadim B. Mikheev 已提交
1677
	{
1678
		int			natts = rel->rd_att->natts;
1679
		int			attrChk;
1680

1681
		for (attrChk = 1; attrChk <= natts; attrChk++)
1682
		{
1683 1684
			if (rel->rd_att->attrs[attrChk-1]->attnotnull &&
				heap_attisnull(tuple, attrChk))
1685
				elog(ERROR, "%s: Fail to add null value in not null attribute %s",
1686
					 caller, NameStr(rel->rd_att->attrs[attrChk-1]->attname));
1687 1688 1689
		}
	}

1690
	if (constr->num_check > 0)
1691
	{
1692
		char	   *failed;
1693

1694
		if ((failed = ExecRelCheck(rel, slot, estate)) != NULL)
1695 1696
			elog(ERROR, "%s: rejected due to CHECK constraint %s",
				 caller, failed);
1697
	}
V
Vadim B. Mikheev 已提交
1698
}
1699

B
Bruce Momjian 已提交
1700
TupleTableSlot *
1701 1702
EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
{
B
Bruce Momjian 已提交
1703 1704 1705 1706 1707 1708 1709
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	evalPlanQual *oldepq;
	EState	   *epqstate = NULL;
	Relation	relation;
	Buffer		buffer;
	HeapTupleData tuple;
	bool		endNode = true;
1710 1711 1712 1713 1714

	Assert(rti != 0);

	if (epq != NULL && epq->rti == 0)
	{
B
Bruce Momjian 已提交
1715 1716
		Assert(!(estate->es_useEvalPlan) &&
			   epq->estate.es_evalPlanQual == NULL);
1717 1718 1719 1720 1721 1722
		epq->rti = rti;
		endNode = false;
	}

	/*
	 * If this is request for another RTE - Ra, - then we have to check
B
Bruce Momjian 已提交
1723 1724 1725
	 * wasn't PlanQual requested for Ra already and if so then Ra' row was
	 * updated again and we have to re-start old execution for Ra and
	 * forget all what we done after Ra was suspended. Cool? -:))
1726
	 */
B
Bruce Momjian 已提交
1727
	if (epq != NULL && epq->rti != rti &&
1728 1729 1730 1731 1732 1733
		epq->estate.es_evTuple[rti - 1] != NULL)
	{
		do
		{
			/* pop previous PlanQual from the stack */
			epqstate = &(epq->estate);
B
Bruce Momjian 已提交
1734
			oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1735 1736 1737
			Assert(oldepq->rti != 0);
			/* stop execution */
			ExecEndNode(epq->plan, epq->plan);
1738
			epqstate->es_tupleTable->next = 0;
1739
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1740 1741 1742 1743 1744 1745 1746 1747
			epqstate->es_evTuple[epq->rti - 1] = NULL;
			/* push current PQ to freePQ stack */
			oldepq->free = epq;
			epq = oldepq;
		} while (epq->rti != rti);
		estate->es_evalPlanQual = (Pointer) epq;
	}

B
Bruce Momjian 已提交
1748
	/*
1749 1750 1751 1752 1753 1754
	 * If we are requested for another RTE then we have to suspend
	 * execution of current PlanQual and start execution for new one.
	 */
	if (epq == NULL || epq->rti != rti)
	{
		/* try to reuse plan used previously */
B
Bruce Momjian 已提交
1755
		evalPlanQual *newepq = (epq != NULL) ? epq->free : NULL;
1756

1757
		if (newepq == NULL)		/* first call or freePQ stack is empty */
1758
		{
B
Bruce Momjian 已提交
1759
			newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual));
1760 1761 1762
			/* Init EState */
			epqstate = &(newepq->estate);
			memset(epqstate, 0, sizeof(EState));
B
Bruce Momjian 已提交
1763
			epqstate->type = T_EState;
1764 1765 1766 1767 1768 1769
			epqstate->es_direction = ForwardScanDirection;
			epqstate->es_snapshot = estate->es_snapshot;
			epqstate->es_range_table = estate->es_range_table;
			epqstate->es_param_list_info = estate->es_param_list_info;
			if (estate->es_origPlan->nParamExec > 0)
				epqstate->es_param_exec_vals = (ParamExecData *)
B
Bruce Momjian 已提交
1770 1771 1772
					palloc(estate->es_origPlan->nParamExec *
						   sizeof(ParamExecData));
			epqstate->es_tupleTable =
1773 1774 1775 1776
				ExecCreateTupleTable(estate->es_tupleTable->size);
			/* ... rest */
			newepq->plan = copyObject(estate->es_origPlan);
			newepq->free = NULL;
B
Bruce Momjian 已提交
1777
			epqstate->es_evTupleNull = (bool *)
1778 1779
				palloc(length(estate->es_range_table) * sizeof(bool));
			if (epq == NULL)	/* first call */
1780
			{
B
Bruce Momjian 已提交
1781
				epqstate->es_evTuple = (HeapTuple *)
1782
					palloc(length(estate->es_range_table) * sizeof(HeapTuple));
B
Bruce Momjian 已提交
1783 1784
				memset(epqstate->es_evTuple, 0,
					 length(estate->es_range_table) * sizeof(HeapTuple));
1785 1786 1787 1788 1789 1790 1791 1792
			}
			else
				epqstate->es_evTuple = epq->estate.es_evTuple;
		}
		else
			epqstate = &(newepq->estate);
		/* push current PQ to the stack */
		epqstate->es_evalPlanQual = (Pointer) epq;
1793 1794
		epq = newepq;
		estate->es_evalPlanQual = (Pointer) epq;
1795 1796 1797 1798 1799 1800 1801
		epq->rti = rti;
		endNode = false;
	}

	epqstate = &(epq->estate);

	/*
B
Bruce Momjian 已提交
1802 1803
	 * Ok - we're requested for the same RTE (-:)). I'm not sure about
	 * ability to use ExecReScan instead of ExecInitNode, so...
1804 1805
	 */
	if (endNode)
1806
	{
1807
		ExecEndNode(epq->plan, epq->plan);
1808
		epqstate->es_tupleTable->next = 0;
1809
	}
1810 1811 1812 1813

	/* free old RTE' tuple */
	if (epqstate->es_evTuple[epq->rti - 1] != NULL)
	{
1814
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1815 1816 1817 1818
		epqstate->es_evTuple[epq->rti - 1] = NULL;
	}

	/* ** fetch tid tuple ** */
B
Bruce Momjian 已提交
1819
	if (estate->es_result_relation_info != NULL &&
1820 1821 1822 1823
		estate->es_result_relation_info->ri_RangeTableIndex == rti)
		relation = estate->es_result_relation_info->ri_RelationDesc;
	else
	{
B
Bruce Momjian 已提交
1824
		List	   *l;
1825

B
Bruce Momjian 已提交
1826
		foreach(l, estate->es_rowMark)
1827
		{
B
Bruce Momjian 已提交
1828
			if (((execRowMark *) lfirst(l))->rti == rti)
1829 1830
				break;
		}
B
Bruce Momjian 已提交
1831
		relation = ((execRowMark *) lfirst(l))->relation;
1832 1833
	}
	tuple.t_self = *tid;
B
Bruce Momjian 已提交
1834
	for (;;)
1835 1836 1837 1838 1839 1840 1841
	{
		heap_fetch(relation, SnapshotDirty, &tuple, &buffer);
		if (tuple.t_data != NULL)
		{
			TransactionId xwait = SnapshotDirty->xmax;

			if (TransactionIdIsValid(SnapshotDirty->xmin))
1842 1843 1844 1845 1846
			{
				elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!");
				Assert(!TransactionIdIsValid(SnapshotDirty->xmin));
				elog(ERROR, "Aborting this transaction");
			}
B
Bruce Momjian 已提交
1847

1848
			/*
B
Bruce Momjian 已提交
1849 1850
			 * If tuple is being updated by other transaction then we have
			 * to wait for its commit/abort.
1851 1852 1853 1854 1855 1856 1857
			 */
			if (TransactionIdIsValid(xwait))
			{
				ReleaseBuffer(buffer);
				XactLockTableWait(xwait);
				continue;
			}
B
Bruce Momjian 已提交
1858

1859 1860 1861
			/*
			 * Nice! We got tuple - now copy it.
			 */
1862
			if (epqstate->es_evTuple[epq->rti - 1] != NULL)
1863
				heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1864 1865 1866 1867
			epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple);
			ReleaseBuffer(buffer);
			break;
		}
B
Bruce Momjian 已提交
1868

1869 1870
		/*
		 * Ops! Invalid tuple. Have to check is it updated or deleted.
B
Bruce Momjian 已提交
1871 1872
		 * Note that it's possible to get invalid SnapshotDirty->tid if
		 * tuple updated by this transaction. Have we to check this ?
1873
		 */
B
Bruce Momjian 已提交
1874
		if (ItemPointerIsValid(&(SnapshotDirty->tid)) &&
1875 1876 1877 1878 1879
			!(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid))))
		{
			tuple.t_self = SnapshotDirty->tid;	/* updated ... */
			continue;
		}
B
Bruce Momjian 已提交
1880

1881
		/*
B
Bruce Momjian 已提交
1882 1883
		 * Deleted or updated by this transaction. Do not (re-)start
		 * execution of this PQ. Continue previous PQ.
1884
		 */
B
Bruce Momjian 已提交
1885
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895
		if (oldepq != NULL)
		{
			Assert(oldepq->rti != 0);
			/* push current PQ to freePQ stack */
			oldepq->free = epq;
			epq = oldepq;
			epqstate = &(epq->estate);
			estate->es_evalPlanQual = (Pointer) epq;
		}
		else
1896 1897 1898 1899
		{
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
1900 1901 1902 1903
		}
	}

	if (estate->es_origPlan->nParamExec > 0)
B
Bruce Momjian 已提交
1904 1905 1906 1907
		memset(epqstate->es_param_exec_vals, 0,
			   estate->es_origPlan->nParamExec * sizeof(ParamExecData));
	memset(epqstate->es_evTupleNull, false,
		   length(estate->es_range_table) * sizeof(bool));
1908
	Assert(epqstate->es_tupleTable->next == 0);
1909 1910 1911
	ExecInitNode(epq->plan, epqstate, NULL);

	/*
B
Bruce Momjian 已提交
1912 1913
	 * For UPDATE/DELETE we have to return tid of actual row we're
	 * executing PQ for.
1914 1915 1916
	 */
	*tid = tuple.t_self;

1917
	return EvalPlanQualNext(estate);
1918 1919
}

B
Bruce Momjian 已提交
1920
static TupleTableSlot *
1921 1922
EvalPlanQualNext(EState *estate)
{
B
Bruce Momjian 已提交
1923 1924 1925 1926
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	EState	   *epqstate = &(epq->estate);
	evalPlanQual *oldepq;
	TupleTableSlot *slot;
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938

	Assert(epq->rti != 0);

lpqnext:;
	slot = ExecProcNode(epq->plan, epq->plan);

	/*
	 * No more tuples for this PQ. Continue previous one.
	 */
	if (TupIsNull(slot))
	{
		ExecEndNode(epq->plan, epq->plan);
1939
		epqstate->es_tupleTable->next = 0;
1940
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1941 1942
		epqstate->es_evTuple[epq->rti - 1] = NULL;
		/* pop old PQ from the stack */
B
Bruce Momjian 已提交
1943 1944
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
1945
		{
1946 1947 1948
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
		}
		Assert(oldepq->rti != 0);
		/* push current PQ to freePQ stack */
		oldepq->free = epq;
		epq = oldepq;
		epqstate = &(epq->estate);
		estate->es_evalPlanQual = (Pointer) epq;
		goto lpqnext;
	}

	return (slot);
}
1961 1962 1963 1964 1965 1966 1967 1968

static void
EndEvalPlanQual(EState *estate)
{
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	EState	   *epqstate = &(epq->estate);
	evalPlanQual *oldepq;

1969 1970 1971
	if (epq->rti == 0)			/* plans already shutdowned */
	{
		Assert(epq->estate.es_evalPlanQual == NULL);
1972
		return;
1973
	}
1974 1975 1976 1977

	for (;;)
	{
		ExecEndNode(epq->plan, epq->plan);
1978
		epqstate->es_tupleTable->next = 0;
1979 1980 1981 1982 1983
		if (epqstate->es_evTuple[epq->rti - 1] != NULL)
		{
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
			epqstate->es_evTuple[epq->rti - 1] = NULL;
		}
1984 1985 1986 1987
		/* pop old PQ from the stack */
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
		{
1988 1989
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free */
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
			break;
		}
		Assert(oldepq->rti != 0);
		/* push current PQ to freePQ stack */
		oldepq->free = epq;
		epq = oldepq;
		epqstate = &(epq->estate);
		estate->es_evalPlanQual = (Pointer) epq;
	}
}