execMain.c 47.3 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
T
Tom Lane 已提交
30
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.134 2001/01/01 21:22:54 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 54 55 56
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
							  Index resultRelationIndex,
							  List *rangeTable,
							  CmdType operation);
57
static void EndPlan(Plan *plan, EState *estate);
58
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
59 60 61 62
								   CmdType operation,
								   long numberTuples,
								   ScanDirection direction,
								   DestReceiver *destfunc);
63
static void ExecRetrieve(TupleTableSlot *slot,
64
			 DestReceiver *destfunc,
B
Bruce Momjian 已提交
65
			 EState *estate);
66
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
67
		   EState *estate);
68
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
69
		   EState *estate);
70
static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
71
			EState *estate);
72
static TupleTableSlot *EvalPlanQualNext(EState *estate);
73
static void EndEvalPlanQual(EState *estate);
74
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
75 76 77 78 79
								Plan *plan);
static void ExecCheckPlanPerms(Plan *plan, List *rangeTable,
							   CmdType operation);
static void ExecCheckRTPerms(List *rangeTable, CmdType operation);
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
80

81 82
/* end of local decls */

83

84
/* ----------------------------------------------------------------
85 86 87 88 89
 *		ExecutorStart
 *
 *		This routine must be called at the beginning of any execution of any
 *		query plan
 *
90
 *		returns a TupleDesc which describes the attributes of the tuples to
91
 *		be returned by the query.
92
 *
93 94 95
 * 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.
96 97 98
 * ----------------------------------------------------------------
 */
TupleDesc
99
ExecutorStart(QueryDesc *queryDesc, EState *estate)
100
{
101
	TupleDesc	result;
102 103 104

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

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

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

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

	return result;
141 142 143
}

/* ----------------------------------------------------------------
144 145 146 147 148 149 150
 *		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.
151
 *
152 153 154 155 156 157
 *		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
158
 *
159 160
 *		Note: count = 0 is interpreted as "no limit".
 *
161 162
 * ----------------------------------------------------------------
 */
163
TupleTableSlot *
164
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
165
{
B
Bruce Momjian 已提交
166 167
	CmdType		operation;
	Plan	   *plan;
168
	TupleTableSlot *result;
B
Bruce Momjian 已提交
169 170
	CommandDest dest;
	DestReceiver *destfunc;
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);

196 197
	switch (feature)
	{
198 199 200 201
		case EXEC_RUN:
			result = ExecutePlan(estate,
								 plan,
								 operation,
202
								 count,
203
								 ForwardScanDirection,
204
								 destfunc);
205
			break;
206

207 208 209 210 211 212
		case EXEC_FOR:
			result = ExecutePlan(estate,
								 plan,
								 operation,
								 count,
								 ForwardScanDirection,
213
								 destfunc);
214
			break;
215

B
Bruce Momjian 已提交
216
			/*
B
Bruce Momjian 已提交
217
			 * retrieve next n "backward" tuples
218 219 220 221 222 223 224
			 */
		case EXEC_BACK:
			result = ExecutePlan(estate,
								 plan,
								 operation,
								 count,
								 BackwardScanDirection,
225
								 destfunc);
226
			break;
227

B
Bruce Momjian 已提交
228
			/*
B
Bruce Momjian 已提交
229 230
			 * return one tuple but don't "retrieve" it. (this is used by
			 * the rule manager..) -cim 9/14/89
231 232 233 234 235 236 237
			 */
		case EXEC_RETONE:
			result = ExecutePlan(estate,
								 plan,
								 operation,
								 ONE_TUPLE,
								 ForwardScanDirection,
238
								 destfunc);
239
			break;
240

241 242
		default:
			elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
243
			result = NULL;
244
			break;
245 246
	}

247 248
	(*destfunc->cleanup) (destfunc);

249
	return result;
250 251 252
}

/* ----------------------------------------------------------------
253 254 255 256 257 258 259
 *		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.
260 261 262 263
 *
 * ----------------------------------------------------------------
 */
void
264
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
265
{
266 267
	/* sanity checks */
	Assert(queryDesc != NULL);
268

269
	EndPlan(queryDesc->plantree, estate);
270

271
	/* XXX - clean up some more from ExecutorStart() - er1p */
B
Bruce Momjian 已提交
272 273 274 275 276 277 278 279 280
	if (NULL == estate->es_snapshot)
	{
		/* nothing to free */
	}
	else
	{
		if (estate->es_snapshot->xcnt > 0)
			pfree(estate->es_snapshot->xip);
		pfree(estate->es_snapshot);
281 282
	}

B
Bruce Momjian 已提交
283 284 285 286 287 288 289 290
	if (NULL == estate->es_param_exec_vals)
	{
		/* nothing to free */
	}
	else
	{
		pfree(estate->es_param_exec_vals);
		estate->es_param_exec_vals = NULL;
291
	}
292 293
}

294 295 296 297 298 299 300

/*
 * ExecCheckQueryPerms
 *		Check access permissions for all relations referenced in a query.
 */
static void
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
301
{
302 303 304
	/*
	 * Check RTEs in the query's primary rangetable.
	 */
305
	ExecCheckRTPerms(parseTree->rtable, operation);
306

307 308 309
	/*
	 * Search for subplans and APPEND nodes to check their rangetables.
	 */
310
	ExecCheckPlanPerms(plan, parseTree->rtable, operation);
311 312 313 314 315 316 317 318
}

/*
 * ExecCheckPlanPerms
 *		Recursively scan the plan tree to check access permissions in
 *		subplans.
 */
static void
319
ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
320 321 322 323 324 325 326 327 328 329
{
	List	   *subp;

	if (plan == NULL)
		return;

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

	foreach(subp, plan->initPlan)
	{
330
		SubPlan    *subplan = (SubPlan *) lfirst(subp);
331

332 333
		ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
		ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
334 335 336
	}
	foreach(subp, plan->subPlan)
	{
337
		SubPlan    *subplan = (SubPlan *) lfirst(subp);
M
Marc G. Fournier 已提交
338

339 340
		ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
		ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
341 342 343 344
	}

	/* Check lower plan nodes */

345 346
	ExecCheckPlanPerms(plan->lefttree, rangeTable, operation);
	ExecCheckPlanPerms(plan->righttree, rangeTable, operation);
347 348 349 350 351

	/* Do node-type-specific checks */

	switch (nodeTag(plan))
	{
352 353 354 355 356 357 358 359 360 361 362
		case T_SubqueryScan:
			{
				SubqueryScan   *scan = (SubqueryScan *) plan;
				RangeTblEntry *rte;

				/* Recursively check the subquery */
				rte = rt_fetch(scan->scan.scanrelid, rangeTable);
				Assert(rte->subquery != NULL);
				ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
				break;
			}
363
		case T_Append:
364
			{
365 366
				Append	   *app = (Append *) plan;
				List	   *appendplans;
367

368
				foreach(appendplans, app->appendplans)
369
				{
370 371 372
					ExecCheckPlanPerms((Plan *) lfirst(appendplans),
									   rangeTable,
									   operation);
373
				}
374
				break;
375 376 377
			}

		default:
378
			break;
379
	}
380
}
381

382 383 384 385 386
/*
 * ExecCheckRTPerms
 *		Check access permissions for all relations listed in a range table.
 */
static void
387
ExecCheckRTPerms(List *rangeTable, CmdType operation)
388 389 390 391
{
	List	   *lp;

	foreach(lp, rangeTable)
392
	{
393 394
		RangeTblEntry *rte = lfirst(lp);

395
		ExecCheckRTEPerms(rte, operation);
396 397 398 399 400 401 402 403
	}
}

/*
 * ExecCheckRTEPerms
 *		Check access permissions for a single RTE.
 */
static void
404
ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
405 406
{
	char	   *relName;
407
	Oid			userid;
408 409
	int32		aclcheck_result;

410 411 412 413 414
	/*
	 * If it's a subquery RTE, ignore it --- it will be checked when
	 * ExecCheckPlanPerms finds the SubqueryScan node for it.
	 */
	if (rte->subquery)
415 416 417 418 419
		return;

	relName = rte->relname;

	/*
420 421
	 * userid to check as: current user unless we have a setuid indication.
	 *
422
	 * Note: GetUserId() is presently fast enough that there's no harm
423
	 * in calling it separately for each RTE.  If that stops being true,
424
	 * we could call it once in ExecCheckQueryPerms and pass the userid
425 426
	 * down from there.  But for now, no need for the extra clutter.
	 */
427
	userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
428

429
#define CHECK(MODE)		pg_aclcheck(relName, userid, MODE)
430

431
	if (rte->checkForRead)
432
	{
433 434 435 436 437 438 439 440 441 442 443 444 445
		aclcheck_result = CHECK(ACL_RD);
		if (aclcheck_result != ACLCHECK_OK)
			elog(ERROR, "%s: %s",
				 relName, aclcheck_error_strings[aclcheck_result]);
	}

	if (rte->checkForWrite)
	{
		/*
		 * Note: write access in a SELECT context means SELECT FOR UPDATE.
		 * Right now we don't distinguish that from true update as far as
		 * permissions checks are concerned.
		 */
446 447 448 449 450 451 452 453
		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;
454
			case CMD_SELECT:
455 456 457 458 459 460 461
			case CMD_DELETE:
			case CMD_UPDATE:
				aclcheck_result = CHECK(ACL_WR);
				break;
			default:
				elog(ERROR, "ExecCheckRTEPerms: bogus operation %d",
					 operation);
462
				aclcheck_result = ACLCHECK_OK;	/* keep compiler quiet */
463 464
				break;
		}
465 466 467
		if (aclcheck_result != ACLCHECK_OK)
			elog(ERROR, "%s: %s",
				 relName, aclcheck_error_strings[aclcheck_result]);
468
	}
469 470
}

471

472 473 474 475 476 477 478
/* ===============================================================
 * ===============================================================
						 static routines follow
 * ===============================================================
 * ===============================================================
 */

479 480 481
typedef struct execRowMark
{
	Relation	relation;
482
	Index		rti;
483
	char		resname[32];
484
} execRowMark;
485

486 487
typedef struct evalPlanQual
{
B
Bruce Momjian 已提交
488 489 490 491
	Plan	   *plan;
	Index		rti;
	EState		estate;
	struct evalPlanQual *free;
492
} evalPlanQual;
493

494
/* ----------------------------------------------------------------
495 496 497 498
 *		InitPlan
 *
 *		Initializes the query plan: open files, allocate storage
 *		and start up the rule manager
499 500
 * ----------------------------------------------------------------
 */
501
static TupleDesc
502
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
503
{
B
Bruce Momjian 已提交
504 505 506
	List	   *rangeTable;
	Relation	intoRelationDesc;
	TupleDesc	tupType;
507

508 509 510 511 512
	/*
	 * Do permissions checks.
	 */
	ExecCheckQueryPerms(operation, parseTree, plan);

B
Bruce Momjian 已提交
513
	/*
B
Bruce Momjian 已提交
514
	 * get information from query descriptor
515
	 */
516
	rangeTable = parseTree->rtable;
517

B
Bruce Momjian 已提交
518
	/*
B
Bruce Momjian 已提交
519
	 * initialize the node's execution state
520
	 */
521 522
	estate->es_range_table = rangeTable;

B
Bruce Momjian 已提交
523
	/*
524
	 * if there is a result relation, initialize result relation stuff
525
	 */
526
	if (parseTree->resultRelation != 0 && operation != CMD_SELECT)
527
	{
528 529 530
		List	   *resultRelations = parseTree->resultRelations;
		int			numResultRelations;
		ResultRelInfo *resultRelInfos;
B
Bruce Momjian 已提交
531

532 533 534 535 536 537 538
		if (resultRelations != NIL)
		{
			/*
			 * Multiple result relations (due to inheritance)
			 * parseTree->resultRelations identifies them all
			 */
			ResultRelInfo *resultRelInfo;
539

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
			numResultRelations = length(resultRelations);
			resultRelInfos = (ResultRelInfo *)
				palloc(numResultRelations * sizeof(ResultRelInfo));
			resultRelInfo = resultRelInfos;
			while (resultRelations != NIL)
			{
				initResultRelInfo(resultRelInfo,
								  lfirsti(resultRelations),
								  rangeTable,
								  operation);
				resultRelInfo++;
				resultRelations = lnext(resultRelations);
			}
		}
		else
		{
			/*
			 * Single result relation identified by parseTree->resultRelation
			 */
			numResultRelations = 1;
			resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
			initResultRelInfo(resultRelInfos,
							  parseTree->resultRelation,
							  rangeTable,
							  operation);
		}
566

567 568 569 570
		estate->es_result_relations = resultRelInfos;
		estate->es_num_result_relations = numResultRelations;
		/* Initialize to first or only result rel */
		estate->es_result_relation_info = resultRelInfos;
571
	}
572 573
	else
	{
B
Bruce Momjian 已提交
574
		/*
B
Bruce Momjian 已提交
575
		 * if no result relation, then set state appropriately
576
		 */
577 578
		estate->es_result_relations = NULL;
		estate->es_num_result_relations = 0;
579 580 581
		estate->es_result_relation_info = NULL;
	}

582 583 584
	/*
	 * Have to lock relations selected for update
	 */
585 586
	estate->es_rowMark = NIL;
	if (parseTree->rowMarks != NIL)
587
	{
B
Bruce Momjian 已提交
588
		List	   *l;
589

590
		foreach(l, parseTree->rowMarks)
591
		{
592 593
			Index		rti = lfirsti(l);
			Oid			relid = getrelid(rti, rangeTable);
594 595 596 597
			Relation	relation;
			execRowMark *erm;

			relation = heap_open(relid, RowShareLock);
B
Bruce Momjian 已提交
598
			erm = (execRowMark *) palloc(sizeof(execRowMark));
599
			erm->relation = relation;
600 601
			erm->rti = rti;
			sprintf(erm->resname, "ctid%u", rti);
602 603 604
			estate->es_rowMark = lappend(estate->es_rowMark, erm);
		}
	}
605

B
Bruce Momjian 已提交
606
	/*
B
Bruce Momjian 已提交
607
	 * initialize the executor "tuple" table.
608 609
	 */
	{
610 611
		int			nSlots = ExecCountSlotsNode(plan);
		TupleTable	tupleTable = ExecCreateTupleTable(nSlots + 10);		/* why add ten? - jolly */
612

613 614
		estate->es_tupleTable = tupleTable;
	}
615

B
Bruce Momjian 已提交
616
	/*
B
Bruce Momjian 已提交
617 618
	 * initialize the private state information for all the nodes in the
	 * query tree.	This opens files, allocates storage and leaves us
619
	 * ready to start processing tuples.
620 621 622
	 */
	ExecInitNode(plan, estate, NULL);

B
Bruce Momjian 已提交
623
	/*
624
	 * Get the tuple descriptor describing the type of tuples to return.
B
Bruce Momjian 已提交
625 626
	 * (this is especially important if we are creating a relation with
	 * "retrieve into")
627 628 629
	 */
	tupType = ExecGetTupType(plan);		/* tuple descriptor */

B
Bruce Momjian 已提交
630
	/*
631 632 633 634
	 * 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.
635 636
	 */
	{
637 638 639
		bool		junk_filter_needed = false;
		List	   *tlist;

640
		switch (operation)
641
		{
642 643
			case CMD_SELECT:
			case CMD_INSERT:
644
				foreach(tlist, plan->targetlist)
645
				{
646 647 648 649 650 651 652
					TargetEntry *tle = (TargetEntry *) lfirst(tlist);

					if (tle->resdom->resjunk)
					{
						junk_filter_needed = true;
						break;
					}
653
				}
654 655 656 657 658 659 660
				break;
			case CMD_UPDATE:
			case CMD_DELETE:
				junk_filter_needed = true;
				break;
			default:
				break;
661 662
		}

663
		if (junk_filter_needed)
664
		{
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
			/*
			 * If there are multiple result relations, each one needs
			 * its own junk filter.  Note this is only possible for
			 * UPDATE/DELETE, so we can't be fooled by some needing
			 * a filter and some not.
			 */
			if (parseTree->resultRelations != NIL)
			{
				List	   *subplans;
				ResultRelInfo *resultRelInfo;

				/* Top plan had better be an Append here. */
				Assert(IsA(plan, Append));
				Assert(((Append *) plan)->isTarget);
				subplans = ((Append *) plan)->appendplans;
				Assert(length(subplans) == estate->es_num_result_relations);
				resultRelInfo = estate->es_result_relations;
				while (subplans != NIL)
				{
					Plan	   *subplan = (Plan *) lfirst(subplans);
					JunkFilter *j;

					j = ExecInitJunkFilter(subplan->targetlist,
										   ExecGetTupType(subplan));
					resultRelInfo->ri_junkFilter = j;
					resultRelInfo++;
					subplans = lnext(subplans);
				}
				/*
				 * Set active junkfilter too; at this point ExecInitAppend
				 * has already selected an active result relation...
				 */
				estate->es_junkFilter =
					estate->es_result_relation_info->ri_junkFilter;
			}
			else
			{
				/* Normal case with just one JunkFilter */
				JunkFilter *j = ExecInitJunkFilter(plan->targetlist,
												   tupType);
705

706 707 708
				estate->es_junkFilter = j;
				if (estate->es_result_relation_info)
					estate->es_result_relation_info->ri_junkFilter = j;
709

710 711 712 713
				/* For SELECT, want to return the cleaned tuple type */
				if (operation == CMD_SELECT)
					tupType = j->jf_cleanTupType;
			}
714 715 716 717
		}
		else
			estate->es_junkFilter = NULL;
	}
718

B
Bruce Momjian 已提交
719
	/*
B
Bruce Momjian 已提交
720
	 * initialize the "into" relation
721 722 723 724 725
	 */
	intoRelationDesc = (Relation) NULL;

	if (operation == CMD_SELECT)
	{
726 727 728
		char	   *intoName;
		Oid			intoRelationId;
		TupleDesc	tupdesc;
729 730 731 732 733 734 735 736 737

		if (!parseTree->isPortal)
		{

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

B
Bruce Momjian 已提交
739
				/*
B
Bruce Momjian 已提交
740
				 * create the "into" relation
741 742 743 744 745 746 747 748
				 */
				intoName = parseTree->into;

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

749 750 751 752 753 754
				intoRelationId =
					heap_create_with_catalog(intoName,
											 tupdesc,
											 RELKIND_RELATION,
											 parseTree->isTemp,
											 allowSystemTableMods);
755

756 757
				FreeTupleDesc(tupdesc);

B
Bruce Momjian 已提交
758
				/*
759 760
				 * Advance command counter so that the newly-created
				 * relation's catalog tuples will be visible to heap_open.
761
				 */
762
				CommandCounterIncrement();
763

764
				/*
T
Tom Lane 已提交
765 766 767 768
				 * If necessary, create a TOAST table for the into relation.
				 * Note that AlterTableCreateToastTable ends with
				 * CommandCounterIncrement(), so that the TOAST table will
				 * be visible for insertion.
769 770 771
				 */
				AlterTableCreateToastTable(intoName, true);

772 773
				intoRelationDesc = heap_open(intoRelationId,
											 AccessExclusiveLock);
774 775 776 777 778 779
			}
		}
	}

	estate->es_into_relation_descriptor = intoRelationDesc;

780 781 782 783 784
	estate->es_origPlan = plan;
	estate->es_evalPlanQual = NULL;
	estate->es_evTuple = NULL;
	estate->es_useEvalPlan = false;

785
	return tupType;
786 787
}

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
/*
 * Initialize ResultRelInfo data for one result relation
 */
static void
initResultRelInfo(ResultRelInfo *resultRelInfo,
				  Index resultRelationIndex,
				  List *rangeTable,
				  CmdType operation)
{
	Oid			resultRelationOid;
	Relation	resultRelationDesc;

	resultRelationOid = getrelid(resultRelationIndex, rangeTable);
	resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);

	switch (resultRelationDesc->rd_rel->relkind)
	{
		case RELKIND_SEQUENCE:
			elog(ERROR, "You can't change sequence relation %s",
				 RelationGetRelationName(resultRelationDesc));
			break;
		case RELKIND_TOASTVALUE:
			elog(ERROR, "You can't change toast relation %s",
				 RelationGetRelationName(resultRelationDesc));
			break;
		case RELKIND_VIEW:
			elog(ERROR, "You can't change view relation %s",
				 RelationGetRelationName(resultRelationDesc));
			break;
	}

	MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
	resultRelInfo->type = T_ResultRelInfo;
	resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
	resultRelInfo->ri_RelationDesc = resultRelationDesc;
	resultRelInfo->ri_NumIndices = 0;
	resultRelInfo->ri_IndexRelationDescs = NULL;
	resultRelInfo->ri_IndexRelationInfo = NULL;
	resultRelInfo->ri_ConstraintExprs = NULL;
	resultRelInfo->ri_junkFilter = NULL;

	/*
	 * If there are indices on the result relation, open them and save
	 * descriptors in the result relation info, so that we can add new
	 * index entries for the tuples we add/update.	We need not do
	 * this for a DELETE, however, since deletion doesn't affect
	 * indexes.
	 */
	if (resultRelationDesc->rd_rel->relhasindex &&
		operation != CMD_DELETE)
		ExecOpenIndices(resultRelInfo);
}

841
/* ----------------------------------------------------------------
842 843 844
 *		EndPlan
 *
 *		Cleans up the query plan -- closes files and free up storages
845 846 847
 * ----------------------------------------------------------------
 */
static void
848
EndPlan(Plan *plan, EState *estate)
849
{
850 851
	ResultRelInfo *resultRelInfo;
	int			i;
852
	List	   *l;
853

854 855 856 857 858 859
	/*
	 * shut down any PlanQual processing we were doing
	 */
	if (estate->es_evalPlanQual != NULL)
		EndEvalPlanQual(estate);

B
Bruce Momjian 已提交
860
	/*
861
	 * shut down the node-type-specific query processing
862 863 864
	 */
	ExecEndNode(plan, plan);

B
Bruce Momjian 已提交
865
	/*
B
Bruce Momjian 已提交
866
	 * destroy the executor "tuple" table.
867
	 */
868 869
	ExecDropTupleTable(estate->es_tupleTable, true);
	estate->es_tupleTable = NULL;
870

B
Bruce Momjian 已提交
871
	/*
872 873
	 * close the result relation(s) if any, but hold locks
	 * until xact commit.
874
	 */
875 876
	resultRelInfo = estate->es_result_relations;
	for (i = estate->es_num_result_relations; i > 0; i--)
877
	{
878 879 880 881
		/* Close indices and then the relation itself */
		ExecCloseIndices(resultRelInfo);
		heap_close(resultRelInfo->ri_RelationDesc, NoLock);
		resultRelInfo++;
882 883
	}

B
Bruce Momjian 已提交
884
	/*
885
	 * close the "into" relation if necessary, again keeping lock
886
	 */
887 888
	if (estate->es_into_relation_descriptor != NULL)
		heap_close(estate->es_into_relation_descriptor, NoLock);
889 890 891 892 893 894 895 896 897 898

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

		heap_close(erm->relation, NoLock);
	}
899 900 901
}

/* ----------------------------------------------------------------
902 903
 *		ExecutePlan
 *
904
 *		processes the query plan to retrieve 'numberTuples' tuples in the
905 906 907
 *		direction specified.
 *		Retrieves all tuples if tupleCount is 0
 *
908
 *		result is either a slot containing the last tuple in the case
909
 *		of a RETRIEVE or NULL otherwise.
910
 *
911 912
 * Note: the ctid attribute is a 'junk' attribute that is removed before the
 * user can see it
913 914 915
 * ----------------------------------------------------------------
 */
static TupleTableSlot *
916 917
ExecutePlan(EState *estate,
			Plan *plan,
918
			CmdType operation,
919
			long numberTuples,
920
			ScanDirection direction,
921
			DestReceiver *destfunc)
922
{
923
	JunkFilter *junkfilter;
924
	TupleTableSlot *slot;
925
	ItemPointer tupleid = NULL;
926
	ItemPointerData tuple_ctid;
927
	long		current_tuple_count;
928 929
	TupleTableSlot *result;

B
Bruce Momjian 已提交
930
	/*
B
Bruce Momjian 已提交
931
	 * initialize local variables
932
	 */
933 934 935 936
	slot = NULL;
	current_tuple_count = 0;
	result = NULL;

B
Bruce Momjian 已提交
937 938
	/*
	 * Set the direction.
939
	 */
940 941
	estate->es_direction = direction;

B
Bruce Momjian 已提交
942
	/*
B
Bruce Momjian 已提交
943 944
	 * Loop until we've processed the proper number of tuples from the
	 * plan..
945 946 947 948
	 */

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

B
Bruce Momjian 已提交
950
		/*
B
Bruce Momjian 已提交
951
		 * Execute the plan and obtain a tuple
952 953
		 */
		/* at the top level, the parent of a plan (2nd arg) is itself */
B
Bruce Momjian 已提交
954
lnext:	;
955 956 957 958 959 960 961 962
		if (estate->es_useEvalPlan)
		{
			slot = EvalPlanQualNext(estate);
			if (TupIsNull(slot))
				slot = ExecProcNode(plan, plan);
		}
		else
			slot = ExecProcNode(plan, plan);
963

B
Bruce Momjian 已提交
964
		/*
B
Bruce Momjian 已提交
965 966
		 * if the tuple is null, then we assume there is nothing more to
		 * process so we just return null...
967 968 969 970 971
		 */
		if (TupIsNull(slot))
		{
			result = NULL;
			break;
972 973
		}

B
Bruce Momjian 已提交
974
		/*
B
Bruce Momjian 已提交
975 976
		 * if we have a junk filter, then project a new tuple with the
		 * junk removed.
977
		 *
B
Bruce Momjian 已提交
978
		 * Store this new "clean" tuple in the place of the original tuple.
979
		 *
B
Bruce Momjian 已提交
980
		 * Also, extract all the junk information we need.
981 982 983
		 */
		if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
		{
984 985 986
			Datum		datum;
			HeapTuple	newTuple;
			bool		isNull;
987

B
Bruce Momjian 已提交
988
			/*
989 990 991 992 993 994 995 996 997
			 * extract the 'ctid' junk attribute.
			 */
			if (operation == CMD_UPDATE || operation == CMD_DELETE)
			{
				if (!ExecGetJunkAttribute(junkfilter,
										  slot,
										  "ctid",
										  &datum,
										  &isNull))
998
					elog(ERROR, "ExecutePlan: NO (junk) `ctid' was found!");
999

1000
				/* shouldn't ever get a null result... */
1001
				if (isNull)
1002
					elog(ERROR, "ExecutePlan: (junk) `ctid' is NULL!");
1003 1004 1005 1006 1007 1008

				tupleid = (ItemPointer) DatumGetPointer(datum);
				tuple_ctid = *tupleid;	/* make sure we don't free the
										 * ctid!! */
				tupleid = &tuple_ctid;
			}
1009
			else if (estate->es_rowMark != NIL)
1010
			{
B
Bruce Momjian 已提交
1011
				List	   *l;
1012

B
Bruce Momjian 已提交
1013 1014
		lmark:	;
				foreach(l, estate->es_rowMark)
1015
				{
1016 1017 1018 1019 1020 1021
					execRowMark *erm = lfirst(l);
					Buffer		buffer;
					HeapTupleData tuple;
					TupleTableSlot *newSlot;
					int			test;

1022 1023 1024 1025 1026
					if (!ExecGetJunkAttribute(junkfilter,
											  slot,
											  erm->resname,
											  &datum,
											  &isNull))
1027 1028
						elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!",
							 erm->resname);
1029

1030 1031 1032 1033 1034
					/*
					 * Unlike the UPDATE/DELETE case, a null result is
					 * possible here, when the referenced table is on the
					 * nullable side of an outer join.  Ignore nulls.
					 */
1035
					if (isNull)
1036
						continue;
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049

					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)
								elog(ERROR, "Can't serialize access due to concurrent update");
1050
							if (!(ItemPointerEquals(&(tuple.t_self),
B
Bruce Momjian 已提交
1051
								  (ItemPointer) DatumGetPointer(datum))))
1052
							{
B
Bruce Momjian 已提交
1053
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
1054 1055 1056 1057 1058 1059 1060
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1061 1062 1063 1064 1065

							/*
							 * if tuple was deleted or PlanQual failed for
							 * updated tuple - we have not return this
							 * tuple!
1066 1067
							 */
							goto lnext;
1068 1069 1070

						default:
							elog(ERROR, "Unknown status %u from heap_mark4update", test);
B
Bruce Momjian 已提交
1071
							return (NULL);
1072 1073 1074
					}
				}
			}
1075

B
Bruce Momjian 已提交
1076
			/*
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
			 * 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 已提交
1089
		/*
B
Bruce Momjian 已提交
1090 1091
		 * 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 已提交
1092
		 * delete it from a relation, or modify some of its attributes.
1093 1094 1095 1096
		 */

		switch (operation)
		{
1097 1098
			case CMD_SELECT:
				ExecRetrieve(slot,		/* slot containing tuple */
B
Bruce Momjian 已提交
1099 1100
							 destfunc,	/* destination's tuple-receiver
										 * obj */
1101 1102 1103
							 estate);	/* */
				result = slot;
				break;
1104

1105 1106 1107 1108
			case CMD_INSERT:
				ExecAppend(slot, tupleid, estate);
				result = NULL;
				break;
1109

1110 1111 1112 1113
			case CMD_DELETE:
				ExecDelete(slot, tupleid, estate);
				result = NULL;
				break;
1114

1115
			case CMD_UPDATE:
1116
				ExecReplace(slot, tupleid, estate);
1117 1118
				result = NULL;
				break;
1119

1120 1121
			default:
				elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
1122
				result = NULL;
1123
				break;
1124
		}
B
Bruce Momjian 已提交
1125

B
Bruce Momjian 已提交
1126
		/*
1127 1128
		 * check our tuple count.. if we've processed the proper number
		 * then quit, else loop again and process more tuples..
1129
		 */
1130
		current_tuple_count++;
1131 1132
		if (numberTuples == current_tuple_count)
			break;
1133
	}
1134

B
Bruce Momjian 已提交
1135
	/*
B
Bruce Momjian 已提交
1136 1137
	 * here, result is either a slot containing a tuple in the case of a
	 * RETRIEVE or NULL otherwise.
1138
	 */
1139
	return result;
1140 1141 1142
}

/* ----------------------------------------------------------------
1143
 *		ExecRetrieve
1144
 *
1145 1146 1147 1148 1149
 *		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.)
1150 1151 1152
 * ----------------------------------------------------------------
 */
static void
1153
ExecRetrieve(TupleTableSlot *slot,
1154
			 DestReceiver *destfunc,
1155
			 EState *estate)
1156
{
1157 1158
	HeapTuple	tuple;
	TupleDesc	attrtype;
1159

B
Bruce Momjian 已提交
1160
	/*
B
Bruce Momjian 已提交
1161
	 * get the heap tuple out of the tuple table slot
1162 1163 1164 1165
	 */
	tuple = slot->val;
	attrtype = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
1166
	/*
B
Bruce Momjian 已提交
1167
	 * insert the tuple into the "into relation"
1168 1169 1170 1171 1172 1173 1174
	 */
	if (estate->es_into_relation_descriptor != NULL)
	{
		heap_insert(estate->es_into_relation_descriptor, tuple);
		IncrAppended();
	}

B
Bruce Momjian 已提交
1175
	/*
B
Bruce Momjian 已提交
1176
	 * send the tuple to the front end (or the screen)
1177
	 */
1178
	(*destfunc->receiveTuple) (tuple, attrtype, destfunc);
1179 1180
	IncrRetrieved();
	(estate->es_processed)++;
1181 1182 1183
}

/* ----------------------------------------------------------------
1184
 *		ExecAppend
1185
 *
1186 1187 1188
 *		APPENDs are trickier.. we have to insert the tuple into
 *		the base relation and insert appropriate tuples into the
 *		index relations.
1189 1190 1191 1192
 * ----------------------------------------------------------------
 */

static void
1193
ExecAppend(TupleTableSlot *slot,
1194
		   ItemPointer tupleid,
1195
		   EState *estate)
1196
{
1197
	HeapTuple	tuple;
1198
	ResultRelInfo *resultRelInfo;
1199 1200 1201
	Relation	resultRelationDesc;
	int			numIndices;
	Oid			newId;
1202

B
Bruce Momjian 已提交
1203
	/*
B
Bruce Momjian 已提交
1204
	 * get the heap tuple out of the tuple table slot
1205 1206 1207
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1208
	/*
1209
	 * get information on the (current) result relation
1210
	 */
1211 1212
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1213 1214 1215 1216 1217

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1218
		HeapTuple	newtuple;
1219 1220 1221 1222 1223 1224 1225 1226 1227

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1228
			heap_freetuple(tuple);
1229 1230 1231 1232
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1233
	/*
1234
	 * Check the constraints of the tuple
1235 1236
	 */
	if (resultRelationDesc->rd_att->constr)
1237
		ExecConstraints("ExecAppend", resultRelInfo, slot, estate);
1238

B
Bruce Momjian 已提交
1239
	/*
B
Bruce Momjian 已提交
1240
	 * insert the tuple
1241
	 */
1242 1243
	newId = heap_insert(resultRelationDesc, tuple);

1244
	IncrAppended();
1245 1246
	(estate->es_processed)++;
	estate->es_lastoid = newId;
1247

B
Bruce Momjian 已提交
1248
	/*
B
Bruce Momjian 已提交
1249
	 * process indices
1250
	 *
B
Bruce Momjian 已提交
1251 1252 1253
	 * 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.
1254
	 */
1255
	numIndices = resultRelInfo->ri_NumIndices;
1256
	if (numIndices > 0)
1257
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1258 1259

	/* AFTER ROW INSERT Triggers */
1260
	if (resultRelationDesc->trigdesc)
1261
		ExecARInsertTriggers(resultRelationDesc, tuple);
1262 1263 1264
}

/* ----------------------------------------------------------------
1265
 *		ExecDelete
1266
 *
1267 1268
 *		DELETE is like append, we delete the tuple and its
 *		index tuples.
1269 1270 1271
 * ----------------------------------------------------------------
 */
static void
1272
ExecDelete(TupleTableSlot *slot,
1273
		   ItemPointer tupleid,
1274
		   EState *estate)
1275
{
1276
	ResultRelInfo *resultRelInfo;
B
Bruce Momjian 已提交
1277 1278 1279
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
1280

B
Bruce Momjian 已提交
1281
	/*
1282
	 * get information on the (current) result relation
1283
	 */
1284 1285
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1286 1287 1288 1289 1290

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

V
Vadim B. Mikheev 已提交
1293
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1294 1295 1296 1297 1298

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

V
Vadim B. Mikheev 已提交
1299
	/*
B
Bruce Momjian 已提交
1300
	 * delete the tuple
1301
	 */
1302
ldelete:;
V
Vadim B. Mikheev 已提交
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
	result = heap_delete(resultRelationDesc, tupleid, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1313 1314
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1315 1316
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1317
				TupleTableSlot *epqslot = EvalPlanQual(estate,
1318
						  resultRelInfo->ri_RangeTableIndex, &ctid);
1319

V
Vadim B. Mikheev 已提交
1320
				if (!TupIsNull(epqslot))
1321 1322 1323 1324 1325
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1326 1327 1328 1329 1330 1331
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1332 1333 1334 1335

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

B
Bruce Momjian 已提交
1336
	/*
B
Bruce Momjian 已提交
1337 1338
	 * Note: Normally one would think that we have to delete index tuples
	 * associated with the heap tuple now..
1339
	 *
B
Bruce Momjian 已提交
1340 1341 1342
	 * ... 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
1343 1344 1345
	 */

	/* AFTER ROW DELETE Triggers */
1346
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1347
		ExecARDeleteTriggers(estate, tupleid);
1348 1349 1350 1351

}

/* ----------------------------------------------------------------
1352
 *		ExecReplace
1353
 *
1354 1355 1356 1357 1358 1359
 *		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..
1360 1361 1362
 * ----------------------------------------------------------------
 */
static void
1363
ExecReplace(TupleTableSlot *slot,
1364
			ItemPointer tupleid,
1365
			EState *estate)
1366
{
B
Bruce Momjian 已提交
1367
	HeapTuple	tuple;
1368
	ResultRelInfo *resultRelInfo;
B
Bruce Momjian 已提交
1369 1370 1371 1372
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
	int			numIndices;
1373

B
Bruce Momjian 已提交
1374
	/*
B
Bruce Momjian 已提交
1375
	 * abort the operation if not running transactions
1376 1377 1378
	 */
	if (IsBootstrapProcessingMode())
	{
1379
		elog(NOTICE, "ExecReplace: replace can't run without transactions");
1380 1381 1382
		return;
	}

B
Bruce Momjian 已提交
1383
	/*
B
Bruce Momjian 已提交
1384
	 * get the heap tuple out of the tuple table slot
1385 1386 1387
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1388
	/*
1389
	 * get information on the (current) result relation
1390
	 */
1391 1392
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1393 1394 1395 1396 1397

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

V
Vadim B. Mikheev 已提交
1400
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1401 1402 1403 1404 1405 1406 1407

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1408
			heap_freetuple(tuple);
1409 1410 1411 1412
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1413
	/*
1414
	 * Check the constraints of the tuple
1415 1416
	 */
	if (resultRelationDesc->rd_att->constr)
1417
		ExecConstraints("ExecReplace", resultRelInfo, slot, estate);
1418

V
Vadim B. Mikheev 已提交
1419
	/*
B
Bruce Momjian 已提交
1420
	 * replace the heap tuple
1421
	 */
1422
lreplace:;
1423
	result = heap_update(resultRelationDesc, tupleid, tuple, &ctid);
V
Vadim B. Mikheev 已提交
1424 1425 1426 1427 1428 1429 1430 1431 1432
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1433 1434
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1435 1436
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1437
				TupleTableSlot *epqslot = EvalPlanQual(estate,
1438
						  resultRelInfo->ri_RangeTableIndex, &ctid);
1439

V
Vadim B. Mikheev 已提交
1440
				if (!TupIsNull(epqslot))
1441 1442
				{
					*tupleid = ctid;
V
Vadim B. Mikheev 已提交
1443 1444
					tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
					slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1445 1446 1447
					goto lreplace;
				}
			}
V
Vadim B. Mikheev 已提交
1448 1449 1450
			return;

		default:
1451
			elog(ERROR, "Unknown status %u from heap_update", result);
V
Vadim B. Mikheev 已提交
1452
			return;
1453 1454 1455 1456 1457
	}

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

B
Bruce Momjian 已提交
1458
	/*
B
Bruce Momjian 已提交
1459 1460
	 * Note: instead of having to update the old index tuples associated
	 * with the heap tuple, all we do is form and insert new index
1461 1462 1463
	 * 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
1464 1465
	 */

B
Bruce Momjian 已提交
1466
	/*
B
Bruce Momjian 已提交
1467
	 * process indices
1468
	 *
1469
	 * heap_update updates a tuple in the base relation by invalidating it
B
Bruce Momjian 已提交
1470 1471 1472 1473
	 * 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.
1474 1475
	 */

1476
	numIndices = resultRelInfo->ri_NumIndices;
1477
	if (numIndices > 0)
1478
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1479 1480

	/* AFTER ROW UPDATE Triggers */
1481
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1482
		ExecARUpdateTriggers(estate, tupleid, tuple);
1483
}
V
Vadim B. Mikheev 已提交
1484

1485
static char *
1486 1487
ExecRelCheck(ResultRelInfo *resultRelInfo,
			 TupleTableSlot *slot, EState *estate)
V
Vadim B. Mikheev 已提交
1488
{
1489
	Relation	rel = resultRelInfo->ri_RelationDesc;
1490 1491
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
1492
	ExprContext *econtext;
1493
	MemoryContext oldContext;
1494 1495
	List	   *qual;
	int			i;
1496

1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
	/*
	 * If first time through for this result relation, build expression
	 * nodetrees for rel's constraint expressions.  Keep them in the
	 * per-query memory context so they'll survive throughout the query.
	 */
	if (resultRelInfo->ri_ConstraintExprs == NULL)
	{
		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
		resultRelInfo->ri_ConstraintExprs =
			(List **) palloc(ncheck * sizeof(List *));
		for (i = 0; i < ncheck; i++)
		{
			qual = (List *) stringToNode(check[i].ccbin);
			resultRelInfo->ri_ConstraintExprs[i] = qual;
		}
		MemoryContextSwitchTo(oldContext);
	}

1515
	/*
1516 1517 1518
	 * 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.
1519
	 */
1520
	econtext = estate->es_per_tuple_exprcontext;
1521
	if (econtext == NULL)
1522 1523 1524 1525 1526 1527
	{
		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
		estate->es_per_tuple_exprcontext = econtext =
			MakeExprContext(NULL, estate->es_query_cxt);
		MemoryContextSwitchTo(oldContext);
	}
1528 1529
	else
		ResetExprContext(econtext);
1530

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

	/* And evaluate the constraints */
1535 1536
	for (i = 0; i < ncheck; i++)
	{
1537
		qual = resultRelInfo->ri_ConstraintExprs[i];
1538

1539 1540
		/*
		 * NOTE: SQL92 specifies that a NULL result from a constraint
1541 1542
		 * expression is not to be treated as a failure.  Therefore, tell
		 * ExecQual to return TRUE for NULL.
1543
		 */
1544
		if (!ExecQual(qual, econtext, true))
1545
			return check[i].ccname;
1546 1547
	}

1548
	/* NULL result means no error */
1549
	return (char *) NULL;
V
Vadim B. Mikheev 已提交
1550 1551
}

1552
void
1553
ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
1554
				TupleTableSlot *slot, EState *estate)
V
Vadim B. Mikheev 已提交
1555
{
1556
	Relation	rel = resultRelInfo->ri_RelationDesc;
1557 1558 1559 1560
	HeapTuple	tuple = slot->val;
	TupleConstr *constr = rel->rd_att->constr;

	Assert(constr);
1561

1562
	if (constr->has_not_null)
V
Vadim B. Mikheev 已提交
1563
	{
1564
		int			natts = rel->rd_att->natts;
1565
		int			attrChk;
1566

1567
		for (attrChk = 1; attrChk <= natts; attrChk++)
1568
		{
1569 1570
			if (rel->rd_att->attrs[attrChk-1]->attnotnull &&
				heap_attisnull(tuple, attrChk))
1571
				elog(ERROR, "%s: Fail to add null value in not null attribute %s",
1572
					 caller, NameStr(rel->rd_att->attrs[attrChk-1]->attname));
1573 1574 1575
		}
	}

1576
	if (constr->num_check > 0)
1577
	{
1578
		char	   *failed;
1579

1580
		if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
1581 1582
			elog(ERROR, "%s: rejected due to CHECK constraint %s",
				 caller, failed);
1583
	}
V
Vadim B. Mikheev 已提交
1584
}
1585

B
Bruce Momjian 已提交
1586
TupleTableSlot *
1587 1588
EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
{
B
Bruce Momjian 已提交
1589 1590 1591 1592 1593 1594 1595
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	evalPlanQual *oldepq;
	EState	   *epqstate = NULL;
	Relation	relation;
	Buffer		buffer;
	HeapTupleData tuple;
	bool		endNode = true;
1596 1597 1598 1599 1600

	Assert(rti != 0);

	if (epq != NULL && epq->rti == 0)
	{
B
Bruce Momjian 已提交
1601 1602
		Assert(!(estate->es_useEvalPlan) &&
			   epq->estate.es_evalPlanQual == NULL);
1603 1604 1605 1606 1607 1608
		epq->rti = rti;
		endNode = false;
	}

	/*
	 * If this is request for another RTE - Ra, - then we have to check
B
Bruce Momjian 已提交
1609 1610 1611
	 * 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? -:))
1612
	 */
B
Bruce Momjian 已提交
1613
	if (epq != NULL && epq->rti != rti &&
1614 1615 1616 1617 1618 1619
		epq->estate.es_evTuple[rti - 1] != NULL)
	{
		do
		{
			/* pop previous PlanQual from the stack */
			epqstate = &(epq->estate);
B
Bruce Momjian 已提交
1620
			oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1621 1622 1623
			Assert(oldepq->rti != 0);
			/* stop execution */
			ExecEndNode(epq->plan, epq->plan);
1624
			epqstate->es_tupleTable->next = 0;
1625
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1626 1627 1628 1629 1630 1631 1632 1633
			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 已提交
1634
	/*
1635 1636 1637 1638 1639 1640
	 * 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 已提交
1641
		evalPlanQual *newepq = (epq != NULL) ? epq->free : NULL;
1642

1643
		if (newepq == NULL)		/* first call or freePQ stack is empty */
1644
		{
B
Bruce Momjian 已提交
1645
			newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual));
1646 1647 1648
			/* Init EState */
			epqstate = &(newepq->estate);
			memset(epqstate, 0, sizeof(EState));
B
Bruce Momjian 已提交
1649
			epqstate->type = T_EState;
1650 1651 1652 1653 1654 1655
			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 已提交
1656 1657 1658
					palloc(estate->es_origPlan->nParamExec *
						   sizeof(ParamExecData));
			epqstate->es_tupleTable =
1659 1660 1661 1662
				ExecCreateTupleTable(estate->es_tupleTable->size);
			/* ... rest */
			newepq->plan = copyObject(estate->es_origPlan);
			newepq->free = NULL;
B
Bruce Momjian 已提交
1663
			epqstate->es_evTupleNull = (bool *)
1664 1665
				palloc(length(estate->es_range_table) * sizeof(bool));
			if (epq == NULL)	/* first call */
1666
			{
B
Bruce Momjian 已提交
1667
				epqstate->es_evTuple = (HeapTuple *)
1668
					palloc(length(estate->es_range_table) * sizeof(HeapTuple));
B
Bruce Momjian 已提交
1669 1670
				memset(epqstate->es_evTuple, 0,
					 length(estate->es_range_table) * sizeof(HeapTuple));
1671 1672 1673 1674 1675 1676 1677 1678
			}
			else
				epqstate->es_evTuple = epq->estate.es_evTuple;
		}
		else
			epqstate = &(newepq->estate);
		/* push current PQ to the stack */
		epqstate->es_evalPlanQual = (Pointer) epq;
1679 1680
		epq = newepq;
		estate->es_evalPlanQual = (Pointer) epq;
1681 1682 1683 1684 1685 1686 1687
		epq->rti = rti;
		endNode = false;
	}

	epqstate = &(epq->estate);

	/*
B
Bruce Momjian 已提交
1688 1689
	 * Ok - we're requested for the same RTE (-:)). I'm not sure about
	 * ability to use ExecReScan instead of ExecInitNode, so...
1690 1691
	 */
	if (endNode)
1692
	{
1693
		ExecEndNode(epq->plan, epq->plan);
1694
		epqstate->es_tupleTable->next = 0;
1695
	}
1696 1697 1698 1699

	/* free old RTE' tuple */
	if (epqstate->es_evTuple[epq->rti - 1] != NULL)
	{
1700
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1701 1702 1703 1704
		epqstate->es_evTuple[epq->rti - 1] = NULL;
	}

	/* ** fetch tid tuple ** */
B
Bruce Momjian 已提交
1705
	if (estate->es_result_relation_info != NULL &&
1706 1707 1708 1709
		estate->es_result_relation_info->ri_RangeTableIndex == rti)
		relation = estate->es_result_relation_info->ri_RelationDesc;
	else
	{
B
Bruce Momjian 已提交
1710
		List	   *l;
1711

B
Bruce Momjian 已提交
1712
		foreach(l, estate->es_rowMark)
1713
		{
B
Bruce Momjian 已提交
1714
			if (((execRowMark *) lfirst(l))->rti == rti)
1715 1716
				break;
		}
B
Bruce Momjian 已提交
1717
		relation = ((execRowMark *) lfirst(l))->relation;
1718 1719
	}
	tuple.t_self = *tid;
B
Bruce Momjian 已提交
1720
	for (;;)
1721 1722 1723 1724 1725 1726 1727
	{
		heap_fetch(relation, SnapshotDirty, &tuple, &buffer);
		if (tuple.t_data != NULL)
		{
			TransactionId xwait = SnapshotDirty->xmax;

			if (TransactionIdIsValid(SnapshotDirty->xmin))
1728 1729 1730 1731 1732
			{
				elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!");
				Assert(!TransactionIdIsValid(SnapshotDirty->xmin));
				elog(ERROR, "Aborting this transaction");
			}
B
Bruce Momjian 已提交
1733

1734
			/*
B
Bruce Momjian 已提交
1735 1736
			 * If tuple is being updated by other transaction then we have
			 * to wait for its commit/abort.
1737 1738 1739 1740 1741 1742 1743
			 */
			if (TransactionIdIsValid(xwait))
			{
				ReleaseBuffer(buffer);
				XactLockTableWait(xwait);
				continue;
			}
B
Bruce Momjian 已提交
1744

1745 1746 1747
			/*
			 * Nice! We got tuple - now copy it.
			 */
1748
			if (epqstate->es_evTuple[epq->rti - 1] != NULL)
1749
				heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1750 1751 1752 1753
			epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple);
			ReleaseBuffer(buffer);
			break;
		}
B
Bruce Momjian 已提交
1754

1755 1756
		/*
		 * Ops! Invalid tuple. Have to check is it updated or deleted.
B
Bruce Momjian 已提交
1757 1758
		 * Note that it's possible to get invalid SnapshotDirty->tid if
		 * tuple updated by this transaction. Have we to check this ?
1759
		 */
B
Bruce Momjian 已提交
1760
		if (ItemPointerIsValid(&(SnapshotDirty->tid)) &&
1761 1762 1763 1764 1765
			!(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid))))
		{
			tuple.t_self = SnapshotDirty->tid;	/* updated ... */
			continue;
		}
B
Bruce Momjian 已提交
1766

1767
		/*
B
Bruce Momjian 已提交
1768 1769
		 * Deleted or updated by this transaction. Do not (re-)start
		 * execution of this PQ. Continue previous PQ.
1770
		 */
B
Bruce Momjian 已提交
1771
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781
		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
1782 1783 1784 1785
		{
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
1786 1787 1788 1789
		}
	}

	if (estate->es_origPlan->nParamExec > 0)
B
Bruce Momjian 已提交
1790 1791 1792 1793
		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));
1794
	Assert(epqstate->es_tupleTable->next == 0);
1795 1796 1797
	ExecInitNode(epq->plan, epqstate, NULL);

	/*
B
Bruce Momjian 已提交
1798 1799
	 * For UPDATE/DELETE we have to return tid of actual row we're
	 * executing PQ for.
1800 1801 1802
	 */
	*tid = tuple.t_self;

1803
	return EvalPlanQualNext(estate);
1804 1805
}

B
Bruce Momjian 已提交
1806
static TupleTableSlot *
1807 1808
EvalPlanQualNext(EState *estate)
{
B
Bruce Momjian 已提交
1809 1810 1811 1812
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	EState	   *epqstate = &(epq->estate);
	evalPlanQual *oldepq;
	TupleTableSlot *slot;
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824

	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);
1825
		epqstate->es_tupleTable->next = 0;
1826
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1827 1828
		epqstate->es_evTuple[epq->rti - 1] = NULL;
		/* pop old PQ from the stack */
B
Bruce Momjian 已提交
1829 1830
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
1831
		{
1832 1833 1834
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free and	  */
			return (NULL);		/* continue Query execution   */
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
		}
		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);
}
1847 1848 1849 1850 1851 1852 1853 1854

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

1855 1856 1857
	if (epq->rti == 0)			/* plans already shutdowned */
	{
		Assert(epq->estate.es_evalPlanQual == NULL);
1858
		return;
1859
	}
1860 1861 1862 1863

	for (;;)
	{
		ExecEndNode(epq->plan, epq->plan);
1864
		epqstate->es_tupleTable->next = 0;
1865 1866 1867 1868 1869
		if (epqstate->es_evTuple[epq->rti - 1] != NULL)
		{
			heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
			epqstate->es_evTuple[epq->rti - 1] = NULL;
		}
1870 1871 1872 1873
		/* pop old PQ from the stack */
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
		{
1874 1875
			epq->rti = 0;		/* this is the first (oldest) */
			estate->es_useEvalPlan = false;		/* PQ - mark as free */
1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
			break;
		}
		Assert(oldepq->rti != 0);
		/* push current PQ to freePQ stack */
		oldepq->free = epq;
		epq = oldepq;
		epqstate = &(epq->estate);
		estate->es_evalPlanQual = (Pointer) epq;
	}
}