execMain.c 47.0 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.132 2000/11/12 00:36:57 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 765 766 767 768
				/*
				 * Eventually create a TOAST table for the into relation
				 */
				AlterTableCreateToastTable(intoName, true);

769 770
				intoRelationDesc = heap_open(intoRelationId,
											 AccessExclusiveLock);
771 772 773 774 775 776
			}
		}
	}

	estate->es_into_relation_descriptor = intoRelationDesc;

777 778 779 780 781
	estate->es_origPlan = plan;
	estate->es_evalPlanQual = NULL;
	estate->es_evTuple = NULL;
	estate->es_useEvalPlan = false;

782
	return tupType;
783 784
}

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
/*
 * 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);
}

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

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

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

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

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

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

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

		heap_close(erm->relation, NoLock);
	}
896 897 898
}

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

B
Bruce Momjian 已提交
927
	/*
B
Bruce Momjian 已提交
928
	 * initialize local variables
929
	 */
930 931 932 933
	slot = NULL;
	current_tuple_count = 0;
	result = NULL;

B
Bruce Momjian 已提交
934 935
	/*
	 * Set the direction.
936
	 */
937 938
	estate->es_direction = direction;

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

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

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

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

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

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

				if (isNull)
998
					elog(ERROR, "ExecutePlan: (junk) `ctid' is NULL!");
999 1000 1001 1002 1003 1004

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

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

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

					if (isNull)
1027 1028
						elog(ERROR, "ExecutePlan: (junk) `%s' is NULL!",
							 erm->resname);
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040

					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)
1041
							{
1042
								elog(ERROR, "Can't serialize access due to concurrent update");
B
Bruce Momjian 已提交
1043
								return (NULL);
1044
							}
B
Bruce Momjian 已提交
1045 1046
							else if (!(ItemPointerEquals(&(tuple.t_self),
								  (ItemPointer) DatumGetPointer(datum))))
1047
							{
B
Bruce Momjian 已提交
1048
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
1049 1050 1051 1052 1053 1054 1055
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1056 1057 1058 1059 1060

							/*
							 * if tuple was deleted or PlanQual failed for
							 * updated tuple - we have not return this
							 * tuple!
1061 1062
							 */
							goto lnext;
1063 1064 1065

						default:
							elog(ERROR, "Unknown status %u from heap_mark4update", test);
B
Bruce Momjian 已提交
1066
							return (NULL);
1067 1068 1069
					}
				}
			}
1070

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

		switch (operation)
		{
1092 1093
			case CMD_SELECT:
				ExecRetrieve(slot,		/* slot containing tuple */
B
Bruce Momjian 已提交
1094 1095
							 destfunc,	/* destination's tuple-receiver
										 * obj */
1096 1097 1098
							 estate);	/* */
				result = slot;
				break;
1099

1100 1101 1102 1103
			case CMD_INSERT:
				ExecAppend(slot, tupleid, estate);
				result = NULL;
				break;
1104

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

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

1115 1116
			default:
				elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
1117
				result = NULL;
1118
				break;
1119
		}
B
Bruce Momjian 已提交
1120

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

B
Bruce Momjian 已提交
1130
	/*
B
Bruce Momjian 已提交
1131 1132
	 * here, result is either a slot containing a tuple in the case of a
	 * RETRIEVE or NULL otherwise.
1133
	 */
1134
	return result;
1135 1136 1137
}

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

B
Bruce Momjian 已提交
1155
	/*
B
Bruce Momjian 已提交
1156
	 * get the heap tuple out of the tuple table slot
1157 1158 1159 1160
	 */
	tuple = slot->val;
	attrtype = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
1161
	/*
B
Bruce Momjian 已提交
1162
	 * insert the tuple into the "into relation"
1163 1164 1165 1166 1167 1168 1169
	 */
	if (estate->es_into_relation_descriptor != NULL)
	{
		heap_insert(estate->es_into_relation_descriptor, tuple);
		IncrAppended();
	}

B
Bruce Momjian 已提交
1170
	/*
B
Bruce Momjian 已提交
1171
	 * send the tuple to the front end (or the screen)
1172
	 */
1173
	(*destfunc->receiveTuple) (tuple, attrtype, destfunc);
1174 1175
	IncrRetrieved();
	(estate->es_processed)++;
1176 1177 1178
}

/* ----------------------------------------------------------------
1179
 *		ExecAppend
1180
 *
1181 1182 1183
 *		APPENDs are trickier.. we have to insert the tuple into
 *		the base relation and insert appropriate tuples into the
 *		index relations.
1184 1185 1186 1187
 * ----------------------------------------------------------------
 */

static void
1188
ExecAppend(TupleTableSlot *slot,
1189
		   ItemPointer tupleid,
1190
		   EState *estate)
1191
{
1192
	HeapTuple	tuple;
1193
	ResultRelInfo *resultRelInfo;
1194 1195 1196
	Relation	resultRelationDesc;
	int			numIndices;
	Oid			newId;
1197

B
Bruce Momjian 已提交
1198
	/*
B
Bruce Momjian 已提交
1199
	 * get the heap tuple out of the tuple table slot
1200 1201 1202
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1203
	/*
1204
	 * get information on the (current) result relation
1205
	 */
1206 1207
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1208 1209 1210 1211 1212

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1213
		HeapTuple	newtuple;
1214 1215 1216 1217 1218 1219 1220 1221 1222

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1223
			heap_freetuple(tuple);
1224 1225 1226 1227
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1228
	/*
1229
	 * Check the constraints of the tuple
1230 1231
	 */
	if (resultRelationDesc->rd_att->constr)
1232
		ExecConstraints("ExecAppend", resultRelInfo, slot, estate);
1233

B
Bruce Momjian 已提交
1234
	/*
B
Bruce Momjian 已提交
1235
	 * insert the tuple
1236
	 */
1237 1238
	newId = heap_insert(resultRelationDesc, tuple);

1239
	IncrAppended();
1240 1241
	(estate->es_processed)++;
	estate->es_lastoid = newId;
1242

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

	/* AFTER ROW INSERT Triggers */
1255
	if (resultRelationDesc->trigdesc)
1256
		ExecARInsertTriggers(resultRelationDesc, tuple);
1257 1258 1259
}

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

B
Bruce Momjian 已提交
1276
	/*
1277
	 * get information on the (current) result relation
1278
	 */
1279 1280
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1281 1282 1283 1284 1285

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

V
Vadim B. Mikheev 已提交
1288
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1289 1290 1291 1292 1293

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

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

		case HeapTupleMayBeUpdated:
			break;

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

V
Vadim B. Mikheev 已提交
1315
				if (!TupIsNull(epqslot))
1316 1317 1318 1319 1320
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1321 1322 1323 1324 1325 1326
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1327 1328 1329 1330

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

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

	/* AFTER ROW DELETE Triggers */
1341
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1342
		ExecARDeleteTriggers(estate, tupleid);
1343 1344 1345 1346

}

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

B
Bruce Momjian 已提交
1369
	/*
B
Bruce Momjian 已提交
1370
	 * abort the operation if not running transactions
1371 1372 1373
	 */
	if (IsBootstrapProcessingMode())
	{
1374
		elog(NOTICE, "ExecReplace: replace can't run without transactions");
1375 1376 1377
		return;
	}

B
Bruce Momjian 已提交
1378
	/*
B
Bruce Momjian 已提交
1379
	 * get the heap tuple out of the tuple table slot
1380 1381 1382
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1383
	/*
1384
	 * get information on the (current) result relation
1385
	 */
1386 1387
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1388 1389 1390 1391 1392

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

V
Vadim B. Mikheev 已提交
1395
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1396 1397 1398 1399 1400 1401 1402

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
1403
			heap_freetuple(tuple);
1404 1405 1406 1407
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1408
	/*
1409
	 * Check the constraints of the tuple
1410 1411
	 */
	if (resultRelationDesc->rd_att->constr)
1412
		ExecConstraints("ExecReplace", resultRelInfo, slot, estate);
1413

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

		case HeapTupleMayBeUpdated:
			break;

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

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

		default:
1446
			elog(ERROR, "Unknown status %u from heap_update", result);
V
Vadim B. Mikheev 已提交
1447
			return;
1448 1449 1450 1451 1452
	}

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

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

B
Bruce Momjian 已提交
1461
	/*
B
Bruce Momjian 已提交
1462
	 * process indices
1463
	 *
1464
	 * heap_update updates a tuple in the base relation by invalidating it
B
Bruce Momjian 已提交
1465 1466 1467 1468
	 * 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.
1469 1470
	 */

1471
	numIndices = resultRelInfo->ri_NumIndices;
1472
	if (numIndices > 0)
1473
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1474 1475

	/* AFTER ROW UPDATE Triggers */
1476
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1477
		ExecARUpdateTriggers(estate, tupleid, tuple);
1478
}
V
Vadim B. Mikheev 已提交
1479

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

1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
	/*
	 * 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);
	}

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

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

	/* And evaluate the constraints */
1530 1531
	for (i = 0; i < ncheck; i++)
	{
1532
		qual = resultRelInfo->ri_ConstraintExprs[i];
1533

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

1543
	/* NULL result means no error */
1544
	return (char *) NULL;
V
Vadim B. Mikheev 已提交
1545 1546
}

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

	Assert(constr);
1556

1557
	if (constr->has_not_null)
V
Vadim B. Mikheev 已提交
1558
	{
1559
		int			natts = rel->rd_att->natts;
1560
		int			attrChk;
1561

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

1571
	if (constr->num_check > 0)
1572
	{
1573
		char	   *failed;
1574

1575
		if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
1576 1577
			elog(ERROR, "%s: rejected due to CHECK constraint %s",
				 caller, failed);
1578
	}
V
Vadim B. Mikheev 已提交
1579
}
1580

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

	Assert(rti != 0);

	if (epq != NULL && epq->rti == 0)
	{
B
Bruce Momjian 已提交
1596 1597
		Assert(!(estate->es_useEvalPlan) &&
			   epq->estate.es_evalPlanQual == NULL);
1598 1599 1600 1601 1602 1603
		epq->rti = rti;
		endNode = false;
	}

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

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

	epqstate = &(epq->estate);

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

	/* free old RTE' tuple */
	if (epqstate->es_evTuple[epq->rti - 1] != NULL)
	{
1695
		heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
1696 1697 1698 1699
		epqstate->es_evTuple[epq->rti - 1] = NULL;
	}

	/* ** fetch tid tuple ** */
B
Bruce Momjian 已提交
1700
	if (estate->es_result_relation_info != NULL &&
1701 1702 1703 1704
		estate->es_result_relation_info->ri_RangeTableIndex == rti)
		relation = estate->es_result_relation_info->ri_RelationDesc;
	else
	{
B
Bruce Momjian 已提交
1705
		List	   *l;
1706

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

			if (TransactionIdIsValid(SnapshotDirty->xmin))
1723 1724 1725 1726 1727
			{
				elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!");
				Assert(!TransactionIdIsValid(SnapshotDirty->xmin));
				elog(ERROR, "Aborting this transaction");
			}
B
Bruce Momjian 已提交
1728

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

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

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

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

	if (estate->es_origPlan->nParamExec > 0)
B
Bruce Momjian 已提交
1785 1786 1787 1788
		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));
1789
	Assert(epqstate->es_tupleTable->next == 0);
1790 1791 1792
	ExecInitNode(epq->plan, epqstate, NULL);

	/*
B
Bruce Momjian 已提交
1793 1794
	 * For UPDATE/DELETE we have to return tid of actual row we're
	 * executing PQ for.
1795 1796 1797
	 */
	*tid = tuple.t_self;

1798
	return EvalPlanQualNext(estate);
1799 1800
}

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

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

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

1850 1851 1852
	if (epq->rti == 0)			/* plans already shutdowned */
	{
		Assert(epq->estate.es_evalPlanQual == NULL);
1853
		return;
1854
	}
1855 1856 1857 1858

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