execMain.c 50.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.121 2000/07/05 16:17:43 wieck 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 89 90
 *		ExecutorStart
 *
 *		This routine must be called at the beginning of any execution of any
 *		query plan
 *
 *		returns (AttrInfo*) which describes the attributes of the tuples to
 *		be returned by the query.
91 92 93 94
 *
 * ----------------------------------------------------------------
 */
TupleDesc
95
ExecutorStart(QueryDesc *queryDesc, EState *estate)
96
{
97
	TupleDesc	result;
98 99 100

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

V
Vadim B. Mikheev 已提交
102 103
	if (queryDesc->plantree->nParamExec > 0)
	{
104 105 106
		estate->es_param_exec_vals = (ParamExecData *)
			palloc(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
		memset(estate->es_param_exec_vals, 0, queryDesc->plantree->nParamExec * sizeof(ParamExecData));
V
Vadim B. Mikheev 已提交
107
	}
108

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

127 128 129
	/*
	 * Initialize the plan
	 */
130 131 132 133 134 135
	result = InitPlan(queryDesc->operation,
					  queryDesc->parsetree,
					  queryDesc->plantree,
					  estate);

	return result;
136 137 138
}

/* ----------------------------------------------------------------
139 140 141 142 143 144 145
 *		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.
146
 *
147 148 149 150 151 152
 *		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
153 154 155 156
 *
 *
 * ----------------------------------------------------------------
 */
157
TupleTableSlot *
B
Bruce Momjian 已提交
158 159
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
			Node *limoffset, Node *limcount)
160
{
B
Bruce Momjian 已提交
161 162
	CmdType		operation;
	Plan	   *plan;
163
	TupleTableSlot *result;
B
Bruce Momjian 已提交
164 165 166 167
	CommandDest dest;
	DestReceiver *destfunc;
	int			offset = 0;
	int			count = 0;
168

B
Bruce Momjian 已提交
169
	/*
B
Bruce Momjian 已提交
170
	 * sanity checks
171
	 */
172 173
	Assert(queryDesc != NULL);

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

B
Bruce Momjian 已提交
185
	/*
B
Bruce Momjian 已提交
186 187 188 189
	 * 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.
190 191 192
	 */
	(*destfunc->setup) (destfunc, (TupleDesc) NULL);

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

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

210
			case T_Param:
B
Bruce Momjian 已提交
211
				poffset = (Param *) limoffset;
212
				paramLI = estate->es_param_list_info;
B
Bruce Momjian 已提交
213

214 215 216 217 218 219 220 221 222 223 224
				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 已提交
225 226
				offset = (int) (paramLI[i].value);

227
				break;
B
Bruce Momjian 已提交
228

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

233 234 235
		if (offset < 0)
			elog(ERROR, "limit offset cannot be negative");
	}
B
Bruce Momjian 已提交
236

B
Bruce Momjian 已提交
237
	/*
B
Bruce Momjian 已提交
238
	 * if given get the count of the LIMIT clause
239 240 241
	 */
	if (limcount != NULL)
	{
B
Bruce Momjian 已提交
242 243 244 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
		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");
279 280
	}

281 282 283
	switch (feature)
	{

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

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

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

335 336
	(*destfunc->cleanup) (destfunc);

337
	return result;
338 339 340
}

/* ----------------------------------------------------------------
341 342 343 344 345 346 347
 *		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.
348 349 350 351
 *
 * ----------------------------------------------------------------
 */
void
352
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
353
{
354 355
	/* sanity checks */
	Assert(queryDesc != NULL);
356

357
	EndPlan(queryDesc->plantree, estate);
358

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

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

382 383 384 385 386 387 388

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

395 396 397 398 399 400 401 402 403
	/*
	 * 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.
	 */
	if (resultRelation > 0)
	{
		List	   *qvars = pull_varnos(parseTree->qual);
		List	   *tvars = pull_varnos((Node *) parseTree->targetList);
404

405 406 407 408 409
		resultIsScanned = (intMember(resultRelation, qvars) ||
						   intMember(resultRelation, tvars));
		freeList(qvars);
		freeList(tvars);
	}
410

411 412 413 414 415 416 417 418 419
	/*
	 * Check RTEs in the query's primary rangetable.
	 */
	ExecCheckRTPerms(rangeTable, operation, resultRelation, resultIsScanned);

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

423 424
		if (!(rm->info & ROW_ACL_FOR_UPDATE))
			continue;
425

426 427 428
		ExecCheckRTEPerms(rt_fetch(rm->rti, rangeTable),
						  CMD_UPDATE, true, false);
	}
429

430 431 432 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
	/*
	 * 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)
	{
458
		SubPlan    *subplan = (SubPlan *) lfirst(subp);
459 460 461 462 463 464

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

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
		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:
483
			{
484 485
				Append	   *app = (Append *) plan;
				List	   *appendplans;
486

487
				if (app->inheritrelid > 0)
488 489
				{

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
					/*
					 * 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
507
				{
508 509 510 511 512 513 514 515
					/* Append implements UNION, which must be a SELECT */
					List	   *rtables;

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

518 519 520 521 522 523 524 525 526
				/* Check appended plans */
				foreach(appendplans, app->appendplans)
				{
					ExecCheckPlanPerms((Plan *) lfirst(appendplans),
									   operation,
									   resultRelation,
									   resultIsScanned);
				}
				break;
527 528 529
			}

		default:
530
			break;
531
	}
532
}
533

534 535 536 537 538
/*
 * 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
539
 * treated as the result relation.	All other relations are assumed to be
540 541 542 543 544 545 546 547 548 549
 * read-only for the query.
 */
static void
ExecCheckRTPerms(List *rangeTable, CmdType operation,
				 int resultRelation, bool resultIsScanned)
{
	int			rtindex = 0;
	List	   *lp;

	foreach(lp, rangeTable)
550
	{
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
		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;
	char	   *userName;
	int32		aclcheck_result;

	if (rte->skipAcl)
	{
576

577
		/*
578 579 580
		 * 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.
581 582 583 584 585 586 587 588 589 590 591 592 593
		 */
		return;
	}

	relName = rte->relname;

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

595
#define CHECK(MODE)		pg_aclcheck(relName, userName, MODE)
596

597 598 599 600 601 602 603 604
	if (isResultRelation)
	{
		if (resultIsScanned)
		{
			aclcheck_result = CHECK(ACL_RD);
			if (aclcheck_result != ACLCHECK_OK)
				elog(ERROR, "%s: %s",
					 relName, aclcheck_error_strings[aclcheck_result]);
605
		}
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		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);
621
				aclcheck_result = ACLCHECK_OK;	/* keep compiler quiet */
622 623 624 625 626 627 628 629 630
				break;
		}
	}
	else
		aclcheck_result = CHECK(ACL_RD);

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

633

634 635 636 637 638 639 640
/* ===============================================================
 * ===============================================================
						 static routines follow
 * ===============================================================
 * ===============================================================
 */

641 642 643
typedef struct execRowMark
{
	Relation	relation;
644
	Index		rti;
645
	char		resname[32];
646
} execRowMark;
647

648 649
typedef struct evalPlanQual
{
B
Bruce Momjian 已提交
650 651 652 653
	Plan	   *plan;
	Index		rti;
	EState		estate;
	struct evalPlanQual *free;
654
} evalPlanQual;
655

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

672 673 674 675 676 677 678
	/*
	 * Do permissions checks.
	 */
#ifndef NO_SECURITY
	ExecCheckQueryPerms(operation, parseTree, plan);
#endif

B
Bruce Momjian 已提交
679
	/*
B
Bruce Momjian 已提交
680
	 * get information from query descriptor
681
	 */
682 683
	rangeTable = parseTree->rtable;
	resultRelation = parseTree->resultRelation;
684

B
Bruce Momjian 已提交
685
	/*
B
Bruce Momjian 已提交
686
	 * initialize the node's execution state
687
	 */
688 689
	estate->es_range_table = rangeTable;

B
Bruce Momjian 已提交
690
	/*
B
Bruce Momjian 已提交
691 692 693
	 * initialize the BaseId counter so node base_id's are assigned
	 * correctly.  Someday baseid's will have to be stored someplace other
	 * than estate because they should be unique per query planned.
694
	 */
695
	estate->es_BaseId = 1;
696

B
Bruce Momjian 已提交
697
	/*
B
Bruce Momjian 已提交
698
	 * initialize result relation stuff
699
	 */
B
Bruce Momjian 已提交
700

701 702
	if (resultRelation != 0 && operation != CMD_SELECT)
	{
B
Bruce Momjian 已提交
703

B
Bruce Momjian 已提交
704
		/*
B
Bruce Momjian 已提交
705 706
		 * if we have a result relation, open it and initialize the result
		 * relation info stuff.
707
		 */
708 709 710 711 712
		RelationInfo *resultRelationInfo;
		Index		resultRelationIndex;
		RangeTblEntry *rtentry;
		Oid			resultRelationOid;
		Relation	resultRelationDesc;
713 714 715 716

		resultRelationIndex = resultRelation;
		rtentry = rt_fetch(resultRelationIndex, rangeTable);
		resultRelationOid = rtentry->relid;
717
		resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);
718 719

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

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

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

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

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

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

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

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

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

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

790 791
		estate->es_tupleTable = tupleTable;
	}
792

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

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

B
Bruce Momjian 已提交
808
	/*
809 810 811 812 813
	 * 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.
814 815
	 */
	{
816 817 818
		bool		junk_filter_needed = false;
		List	   *tlist;

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

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

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

846
			estate->es_junkFilter = j;
847

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

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

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

		if (!parseTree->isPortal)
		{

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

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

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

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

892 893
				FreeTupleDesc(tupdesc);

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

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

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

	estate->es_into_relation_descriptor = intoRelationDesc;

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

918
	return tupType;
919 920 921
}

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

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

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

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

B
Bruce Momjian 已提交
950
	/*
951 952 953
	 * 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 ...
954
	 */
955
	resultRelationInfo = estate->es_result_relation_info;
956 957
	if (resultRelationInfo != NULL)
	{
958 959
		heap_close(resultRelationInfo->ri_RelationDesc, NoLock);
		/* close indices on the result relation, too */
960 961 962
		ExecCloseIndices(resultRelationInfo);
	}

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

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

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

/* ----------------------------------------------------------------
981 982 983 984 985 986 987 988
 *		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.
989 990 991 992 993 994 995 996
 *
 * ----------------------------------------------------------------
 */

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
1056
		/*
B
Bruce Momjian 已提交
1057 1058 1059
		 * 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
1060 1061 1062 1063 1064 1065 1066
		 */
		if (offsetTuples > 0)
		{
			--offsetTuples;
			continue;
		}

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

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

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

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

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

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
					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)
1135
							{
1136
								elog(ERROR, "Can't serialize access due to concurrent update");
B
Bruce Momjian 已提交
1137
								return (NULL);
1138
							}
B
Bruce Momjian 已提交
1139 1140
							else if (!(ItemPointerEquals(&(tuple.t_self),
								  (ItemPointer) DatumGetPointer(datum))))
1141
							{
B
Bruce Momjian 已提交
1142
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
1143 1144 1145 1146 1147 1148 1149
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1150 1151 1152 1153 1154

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

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

B
Bruce Momjian 已提交
1165
			/*
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
			 * 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 已提交
1178
		/*
B
Bruce Momjian 已提交
1179 1180
		 * 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 已提交
1181
		 * delete it from a relation, or modify some of its attributes.
1182 1183 1184 1185
		 */

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

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

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

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

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

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

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

/* ----------------------------------------------------------------
1232
 *		ExecRetrieve
1233
 *
1234 1235 1236 1237 1238
 *		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.)
1239 1240 1241
 * ----------------------------------------------------------------
 */
static void
1242
ExecRetrieve(TupleTableSlot *slot,
1243
			 DestReceiver *destfunc,
1244
			 EState *estate)
1245
{
1246 1247
	HeapTuple	tuple;
	TupleDesc	attrtype;
1248

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
1303
	/*
B
Bruce Momjian 已提交
1304
	 * have to add code to preform unique checking here. cim -12/1/89
1305 1306 1307 1308 1309 1310
	 */

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1311
		HeapTuple	newtuple;
1312 1313 1314 1315 1316 1317 1318 1319 1320

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1321
			heap_freetuple(tuple);
1322 1323 1324 1325
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1326
	/*
1327 1328 1329 1330
	 * Check the constraints of a tuple
	 */

	if (resultRelationDesc->rd_att->constr)
1331
		ExecConstraints("ExecAppend", resultRelationDesc, tuple, estate);
1332

B
Bruce Momjian 已提交
1333
	/*
B
Bruce Momjian 已提交
1334
	 * insert the tuple
1335 1336 1337 1338 1339
	 */
	newId = heap_insert(resultRelationDesc,		/* relation desc */
						tuple); /* heap tuple */
	IncrAppended();

B
Bruce Momjian 已提交
1340
	/*
B
Bruce Momjian 已提交
1341
	 * process indices
1342
	 *
B
Bruce Momjian 已提交
1343 1344 1345
	 * 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.
1346 1347 1348
	 */
	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1349
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1350 1351 1352 1353
	(estate->es_processed)++;
	estate->es_lastoid = newId;

	/* AFTER ROW INSERT Triggers */
1354
	if (resultRelationDesc->trigdesc)
1355
		ExecARInsertTriggers(resultRelationDesc, tuple);
1356 1357 1358
}

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

B
Bruce Momjian 已提交
1375
	/*
B
Bruce Momjian 已提交
1376
	 * get the result relation information
1377 1378 1379 1380 1381 1382 1383 1384
	 */
	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)
	{
1385
		bool		dodelete;
1386

V
Vadim B. Mikheev 已提交
1387
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1388 1389 1390 1391 1392

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

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

		case HeapTupleMayBeUpdated:
			break;

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

V
Vadim B. Mikheev 已提交
1414
				if (!TupIsNull(epqslot))
1415 1416 1417 1418 1419
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1420 1421 1422 1423 1424 1425
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1426 1427 1428 1429

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

B
Bruce Momjian 已提交
1430
	/*
B
Bruce Momjian 已提交
1431 1432
	 * Note: Normally one would think that we have to delete index tuples
	 * associated with the heap tuple now..
1433
	 *
B
Bruce Momjian 已提交
1434 1435 1436
	 * ... 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
1437 1438 1439
	 */

	/* AFTER ROW DELETE Triggers */
1440
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1441
		ExecARDeleteTriggers(estate, tupleid);
1442 1443 1444 1445

}

/* ----------------------------------------------------------------
1446
 *		ExecReplace
1447
 *
1448 1449 1450 1451 1452 1453
 *		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..
1454 1455 1456
 * ----------------------------------------------------------------
 */
static void
1457
ExecReplace(TupleTableSlot *slot,
1458
			ItemPointer tupleid,
1459
			EState *estate)
1460
{
B
Bruce Momjian 已提交
1461 1462 1463 1464 1465 1466
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
	int			numIndices;
1467

B
Bruce Momjian 已提交
1468
	/*
B
Bruce Momjian 已提交
1469
	 * abort the operation if not running transactions
1470 1471 1472 1473 1474 1475 1476
	 */
	if (IsBootstrapProcessingMode())
	{
		elog(DEBUG, "ExecReplace: replace can't run without transactions");
		return;
	}

B
Bruce Momjian 已提交
1477
	/*
B
Bruce Momjian 已提交
1478
	 * get the heap tuple out of the tuple table slot
1479 1480 1481
	 */
	tuple = slot->val;

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

B
Bruce Momjian 已提交
1488
	/*
B
Bruce Momjian 已提交
1489 1490 1491
	 * have to add code to preform unique checking here. in the event of
	 * unique tuples, this becomes a deletion of the original tuple
	 * affected by the replace. cim -12/1/89
1492 1493 1494 1495 1496 1497
	 */

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

V
Vadim B. Mikheev 已提交
1500
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1501 1502 1503 1504 1505 1506 1507

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1508
			heap_freetuple(tuple);
1509 1510 1511 1512
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1513
	/*
1514 1515 1516 1517
	 * Check the constraints of a tuple
	 */

	if (resultRelationDesc->rd_att->constr)
1518
		ExecConstraints("ExecReplace", resultRelationDesc, tuple, estate);
1519

V
Vadim B. Mikheev 已提交
1520
	/*
B
Bruce Momjian 已提交
1521
	 * replace the heap tuple
1522
	 */
1523
lreplace:;
1524
	result = heap_update(resultRelationDesc, tupleid, tuple, &ctid);
V
Vadim B. Mikheev 已提交
1525 1526 1527 1528 1529 1530 1531 1532 1533
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1534 1535
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1536 1537
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1538 1539
				TupleTableSlot *epqslot = EvalPlanQual(estate,
						  resultRelationInfo->ri_RangeTableIndex, &ctid);
1540

V
Vadim B. Mikheev 已提交
1541
				if (!TupIsNull(epqslot))
1542 1543
				{
					*tupleid = ctid;
V
Vadim B. Mikheev 已提交
1544 1545
					tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
					slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1546 1547 1548
					goto lreplace;
				}
			}
V
Vadim B. Mikheev 已提交
1549 1550 1551
			return;

		default:
1552
			elog(ERROR, "Unknown status %u from heap_update", result);
V
Vadim B. Mikheev 已提交
1553
			return;
1554 1555 1556 1557 1558
	}

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

B
Bruce Momjian 已提交
1559
	/*
B
Bruce Momjian 已提交
1560 1561 1562 1563 1564
	 * Note: instead of having to update the old index tuples associated
	 * with the heap tuple, all we do is form and insert new index
	 * tuples..  This is because replaces are actually deletes and inserts
	 * and index tuple deletion is done automagically by the vaccuum
	 * deamon.. All we do is insert new index tuples.  -cim 9/27/89
1565 1566
	 */

B
Bruce Momjian 已提交
1567
	/*
B
Bruce Momjian 已提交
1568
	 * process indices
1569
	 *
1570
	 * heap_update updates a tuple in the base relation by invalidating it
B
Bruce Momjian 已提交
1571 1572 1573 1574
	 * 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.
1575 1576 1577 1578
	 */

	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1579
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1580 1581

	/* AFTER ROW UPDATE Triggers */
1582
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1583
		ExecARUpdateTriggers(estate, tupleid, tuple);
1584
}
V
Vadim B. Mikheev 已提交
1585

M
 
Marc G. Fournier 已提交
1586
#ifdef NOT_USED
1587
static HeapTuple
1588
ExecAttrDefault(Relation rel, HeapTuple tuple)
V
Vadim B. Mikheev 已提交
1589
{
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
	int			ndef = rel->rd_att->constr->num_defval;
	AttrDefault *attrdef = rel->rd_att->constr->defval;
	ExprContext *econtext = makeNode(ExprContext);
	HeapTuple	newtuple;
	Node	   *expr;
	bool		isnull;
	bool		isdone;
	Datum		val;
	Datum	   *replValue = NULL;
	char	   *replNull = NULL;
	char	   *repl = NULL;
	int			i;
1602 1603 1604 1605 1606 1607

	econtext->ecxt_scantuple = NULL;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = NULL;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
1608 1609
	econtext->ecxt_param_list_info = NULL;		/* param list info */
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
	econtext->ecxt_range_table = NULL;	/* range table */
	for (i = 0; i < ndef; i++)
	{
		if (!heap_attisnull(tuple, attrdef[i].adnum))
			continue;
		expr = (Node *) stringToNode(attrdef[i].adbin);

		val = ExecEvalExpr(expr, econtext, &isnull, &isdone);

		pfree(expr);

		if (isnull)
			continue;

		if (repl == NULL)
		{
			repl = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replNull = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum));
B
Bruce Momjian 已提交
1629
			MemSet(repl, ' ', rel->rd_att->natts * sizeof(char));
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
		}

		repl[attrdef[i].adnum - 1] = 'r';
		replNull[attrdef[i].adnum - 1] = ' ';
		replValue[attrdef[i].adnum - 1] = val;

	}

	pfree(econtext);

	if (repl == NULL)
1641
		return tuple;
1642

1643
	newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
1644 1645

	pfree(repl);
1646
	heap_freetuple(tuple);
1647 1648 1649
	pfree(replNull);
	pfree(replValue);

1650
	return newtuple;
1651

V
Vadim B. Mikheev 已提交
1652
}
1653

1654
#endif
V
Vadim B. Mikheev 已提交
1655

1656
static char *
1657
ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
V
Vadim B. Mikheev 已提交
1658
{
1659 1660 1661
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
	ExprContext *econtext = makeNode(ExprContext);
1662
	TupleTableSlot *slot = makeNode(TupleTableSlot);
1663 1664 1665 1666
	RangeTblEntry *rte = makeNode(RangeTblEntry);
	List	   *rtlist;
	List	   *qual;
	int			i;
1667 1668 1669 1670 1671 1672 1673

	slot->val = tuple;
	slot->ttc_shouldFree = false;
	slot->ttc_descIsNew = true;
	slot->ttc_tupleDescriptor = rel->rd_att;
	slot->ttc_buffer = InvalidBuffer;
	slot->ttc_whichplan = -1;
1674
	rte->relname = RelationGetRelationName(rel);
1675 1676
	rte->ref = makeNode(Attr);
	rte->ref->relname = rte->relname;
1677
	rte->relid = RelationGetRelid(rel);
1678
	/* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
1679 1680 1681 1682 1683 1684 1685
	rtlist = lcons(rte, NIL);
	econtext->ecxt_scantuple = slot;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = rel;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
	econtext->ecxt_param_list_info = NULL;		/* param list info */
V
Vadim B. Mikheev 已提交
1686
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1687 1688
	econtext->ecxt_range_table = rtlist;		/* range table */

1689 1690 1691
	if (estate->es_result_relation_constraints == NULL)
	{
		estate->es_result_relation_constraints =
B
Bruce Momjian 已提交
1692
			(List **) palloc(ncheck * sizeof(List *));
1693 1694 1695 1696 1697 1698 1699 1700

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

1701 1702
	for (i = 0; i < ncheck; i++)
	{
1703
		qual = estate->es_result_relation_constraints[i];
1704

1705 1706
		/*
		 * NOTE: SQL92 specifies that a NULL result from a constraint
1707 1708
		 * expression is not to be treated as a failure.  Therefore, tell
		 * ExecQual to return TRUE for NULL.
1709
		 */
1710
		if (!ExecQual(qual, econtext, true))
1711
			return check[i].ccname;
1712 1713 1714 1715 1716 1717 1718
	}

	pfree(slot);
	pfree(rte);
	pfree(rtlist);
	pfree(econtext);

1719
	return (char *) NULL;
1720

V
Vadim B. Mikheev 已提交
1721 1722
}

1723
void
1724
ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
V
Vadim B. Mikheev 已提交
1725
{
1726 1727 1728 1729

	Assert(rel->rd_att->constr);

	if (rel->rd_att->constr->has_not_null)
V
Vadim B. Mikheev 已提交
1730
	{
1731
		int			attrChk;
1732 1733 1734 1735

		for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
		{
			if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
1736
				elog(ERROR, "%s: Fail to add null value in not null attribute %s",
1737
					 caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
1738 1739 1740 1741 1742
		}
	}

	if (rel->rd_att->constr->num_check > 0)
	{
1743
		char	   *failed;
1744

1745
		if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL)
1746
			elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed);
1747 1748
	}

1749
	return;
V
Vadim B. Mikheev 已提交
1750
}
1751

B
Bruce Momjian 已提交
1752
TupleTableSlot *
1753 1754
EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
{
B
Bruce Momjian 已提交
1755 1756 1757 1758 1759 1760 1761
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	evalPlanQual *oldepq;
	EState	   *epqstate = NULL;
	Relation	relation;
	Buffer		buffer;
	HeapTupleData tuple;
	bool		endNode = true;
1762 1763 1764 1765 1766

	Assert(rti != 0);

	if (epq != NULL && epq->rti == 0)
	{
B
Bruce Momjian 已提交
1767 1768
		Assert(!(estate->es_useEvalPlan) &&
			   epq->estate.es_evalPlanQual == NULL);
1769 1770 1771 1772 1773 1774
		epq->rti = rti;
		endNode = false;
	}

	/*
	 * If this is request for another RTE - Ra, - then we have to check
B
Bruce Momjian 已提交
1775 1776 1777
	 * 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? -:))
1778
	 */
B
Bruce Momjian 已提交
1779
	if (epq != NULL && epq->rti != rti &&
1780 1781 1782 1783 1784 1785
		epq->estate.es_evTuple[rti - 1] != NULL)
	{
		do
		{
			/* pop previous PlanQual from the stack */
			epqstate = &(epq->estate);
B
Bruce Momjian 已提交
1786
			oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1787 1788 1789
			Assert(oldepq->rti != 0);
			/* stop execution */
			ExecEndNode(epq->plan, epq->plan);
1790
			epqstate->es_tupleTable->next = 0;
1791
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1792 1793 1794 1795 1796 1797 1798 1799
			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 已提交
1800
	/*
1801 1802 1803 1804 1805 1806
	 * 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 已提交
1807
		evalPlanQual *newepq = (epq != NULL) ? epq->free : NULL;
1808

1809
		if (newepq == NULL)		/* first call or freePQ stack is empty */
1810
		{
B
Bruce Momjian 已提交
1811
			newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual));
1812 1813 1814
			/* Init EState */
			epqstate = &(newepq->estate);
			memset(epqstate, 0, sizeof(EState));
B
Bruce Momjian 已提交
1815
			epqstate->type = T_EState;
1816 1817 1818 1819 1820 1821
			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 已提交
1822 1823 1824
					palloc(estate->es_origPlan->nParamExec *
						   sizeof(ParamExecData));
			epqstate->es_tupleTable =
1825 1826 1827 1828
				ExecCreateTupleTable(estate->es_tupleTable->size);
			/* ... rest */
			newepq->plan = copyObject(estate->es_origPlan);
			newepq->free = NULL;
B
Bruce Momjian 已提交
1829
			epqstate->es_evTupleNull = (bool *)
1830 1831
				palloc(length(estate->es_range_table) * sizeof(bool));
			if (epq == NULL)	/* first call */
1832
			{
B
Bruce Momjian 已提交
1833
				epqstate->es_evTuple = (HeapTuple *)
1834
					palloc(length(estate->es_range_table) * sizeof(HeapTuple));
B
Bruce Momjian 已提交
1835 1836
				memset(epqstate->es_evTuple, 0,
					 length(estate->es_range_table) * sizeof(HeapTuple));
1837 1838 1839 1840 1841 1842 1843 1844
			}
			else
				epqstate->es_evTuple = epq->estate.es_evTuple;
		}
		else
			epqstate = &(newepq->estate);
		/* push current PQ to the stack */
		epqstate->es_evalPlanQual = (Pointer) epq;
1845 1846
		epq = newepq;
		estate->es_evalPlanQual = (Pointer) epq;
1847 1848 1849 1850 1851 1852 1853
		epq->rti = rti;
		endNode = false;
	}

	epqstate = &(epq->estate);

	/*
B
Bruce Momjian 已提交
1854 1855
	 * Ok - we're requested for the same RTE (-:)). I'm not sure about
	 * ability to use ExecReScan instead of ExecInitNode, so...
1856 1857
	 */
	if (endNode)
1858
	{
1859
		ExecEndNode(epq->plan, epq->plan);
1860
		epqstate->es_tupleTable->next = 0;
1861
	}
1862 1863 1864 1865

	/* free old RTE' tuple */
	if (epqstate->es_evTuple[epq->rti - 1] != NULL)
	{
1866
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1867 1868 1869 1870
		epqstate->es_evTuple[epq->rti - 1] = NULL;
	}

	/* ** fetch tid tuple ** */
B
Bruce Momjian 已提交
1871
	if (estate->es_result_relation_info != NULL &&
1872 1873 1874 1875
		estate->es_result_relation_info->ri_RangeTableIndex == rti)
		relation = estate->es_result_relation_info->ri_RelationDesc;
	else
	{
B
Bruce Momjian 已提交
1876
		List	   *l;
1877

B
Bruce Momjian 已提交
1878
		foreach(l, estate->es_rowMark)
1879
		{
B
Bruce Momjian 已提交
1880
			if (((execRowMark *) lfirst(l))->rti == rti)
1881 1882
				break;
		}
B
Bruce Momjian 已提交
1883
		relation = ((execRowMark *) lfirst(l))->relation;
1884 1885
	}
	tuple.t_self = *tid;
B
Bruce Momjian 已提交
1886
	for (;;)
1887 1888 1889 1890 1891 1892 1893
	{
		heap_fetch(relation, SnapshotDirty, &tuple, &buffer);
		if (tuple.t_data != NULL)
		{
			TransactionId xwait = SnapshotDirty->xmax;

			if (TransactionIdIsValid(SnapshotDirty->xmin))
1894 1895 1896 1897 1898
			{
				elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!");
				Assert(!TransactionIdIsValid(SnapshotDirty->xmin));
				elog(ERROR, "Aborting this transaction");
			}
B
Bruce Momjian 已提交
1899

1900
			/*
B
Bruce Momjian 已提交
1901 1902
			 * If tuple is being updated by other transaction then we have
			 * to wait for its commit/abort.
1903 1904 1905 1906 1907 1908 1909
			 */
			if (TransactionIdIsValid(xwait))
			{
				ReleaseBuffer(buffer);
				XactLockTableWait(xwait);
				continue;
			}
B
Bruce Momjian 已提交
1910

1911 1912 1913
			/*
			 * Nice! We got tuple - now copy it.
			 */
1914
			if (epqstate->es_evTuple[epq->rti - 1] != NULL)
1915
				heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1916 1917 1918 1919
			epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple);
			ReleaseBuffer(buffer);
			break;
		}
B
Bruce Momjian 已提交
1920

1921 1922
		/*
		 * Ops! Invalid tuple. Have to check is it updated or deleted.
B
Bruce Momjian 已提交
1923 1924
		 * Note that it's possible to get invalid SnapshotDirty->tid if
		 * tuple updated by this transaction. Have we to check this ?
1925
		 */
B
Bruce Momjian 已提交
1926
		if (ItemPointerIsValid(&(SnapshotDirty->tid)) &&
1927 1928 1929 1930 1931
			!(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid))))
		{
			tuple.t_self = SnapshotDirty->tid;	/* updated ... */
			continue;
		}
B
Bruce Momjian 已提交
1932

1933
		/*
B
Bruce Momjian 已提交
1934 1935
		 * Deleted or updated by this transaction. Do not (re-)start
		 * execution of this PQ. Continue previous PQ.
1936
		 */
B
Bruce Momjian 已提交
1937
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947
		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
1948 1949 1950 1951
		{
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
1952 1953 1954 1955
		}
	}

	if (estate->es_origPlan->nParamExec > 0)
B
Bruce Momjian 已提交
1956 1957 1958 1959
		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));
1960
	Assert(epqstate->es_tupleTable->next == 0);
1961 1962 1963
	ExecInitNode(epq->plan, epqstate, NULL);

	/*
B
Bruce Momjian 已提交
1964 1965
	 * For UPDATE/DELETE we have to return tid of actual row we're
	 * executing PQ for.
1966 1967 1968
	 */
	*tid = tuple.t_self;

1969
	return EvalPlanQualNext(estate);
1970 1971
}

B
Bruce Momjian 已提交
1972
static TupleTableSlot *
1973 1974
EvalPlanQualNext(EState *estate)
{
B
Bruce Momjian 已提交
1975 1976 1977 1978
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	EState	   *epqstate = &(epq->estate);
	evalPlanQual *oldepq;
	TupleTableSlot *slot;
1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990

	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);
1991
		epqstate->es_tupleTable->next = 0;
1992
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1993 1994
		epqstate->es_evTuple[epq->rti - 1] = NULL;
		/* pop old PQ from the stack */
B
Bruce Momjian 已提交
1995 1996
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
1997
		{
1998 1999 2000
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
		}
		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);
}
2013 2014 2015 2016 2017 2018 2019 2020

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

2021 2022 2023
	if (epq->rti == 0)			/* plans already shutdowned */
	{
		Assert(epq->estate.es_evalPlanQual == NULL);
2024
		return;
2025
	}
2026 2027 2028 2029

	for (;;)
	{
		ExecEndNode(epq->plan, epq->plan);
2030
		epqstate->es_tupleTable->next = 0;
2031 2032 2033 2034 2035
		if (epqstate->es_evTuple[epq->rti - 1] != NULL)
		{
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
			epqstate->es_evTuple[epq->rti - 1] = NULL;
		}
2036 2037 2038 2039
		/* pop old PQ from the stack */
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
		{
2040 2041
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free */
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
			break;
		}
		Assert(oldepq->rti != 0);
		/* push current PQ to freePQ stack */
		oldepq->free = epq;
		epq = oldepq;
		epqstate = &(epq->estate);
		estate->es_evalPlanQual = (Pointer) epq;
	}
}