execMain.c 47.5 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
 *
25
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
26
 * 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.137 2001/01/27 05:16:58 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
	 * Loop until we've processed the proper number of tuples from the
944
	 * plan.
945 946 947 948
	 */

	for (;;)
	{
949 950
		/* Reset the per-output-tuple exprcontext */
		ResetPerTupleExprContext(estate);
B
Bruce Momjian 已提交
951

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

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

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

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

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

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

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

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

1032 1033 1034 1035 1036
					/*
					 * 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.
					 */
1037
					if (isNull)
1038
						continue;
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

					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");
1052
							if (!(ItemPointerEquals(&(tuple.t_self),
B
Bruce Momjian 已提交
1053
								  (ItemPointer) DatumGetPointer(datum))))
1054
							{
B
Bruce Momjian 已提交
1055
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
1056 1057 1058 1059 1060 1061 1062
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1063 1064 1065 1066 1067

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1222
		newtuple = ExecBRInsertTriggers(estate, resultRelationDesc, tuple);
1223 1224 1225 1226 1227 1228

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
1229 1230 1231 1232 1233 1234 1235 1236
			/*
			 * Insert modified tuple into tuple table slot, replacing the
			 * original.  We assume that it was allocated in per-tuple
			 * memory context, and therefore will go away by itself.
			 * The tuple table slot should not try to clear it.
			 */
			ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
			tuple = newtuple;
1237 1238 1239
		}
	}

B
Bruce Momjian 已提交
1240
	/*
1241
	 * Check the constraints of the tuple
1242 1243
	 */
	if (resultRelationDesc->rd_att->constr)
1244
		ExecConstraints("ExecAppend", resultRelInfo, slot, estate);
1245

B
Bruce Momjian 已提交
1246
	/*
B
Bruce Momjian 已提交
1247
	 * insert the tuple
1248
	 */
1249 1250
	newId = heap_insert(resultRelationDesc, tuple);

1251
	IncrAppended();
1252 1253
	(estate->es_processed)++;
	estate->es_lastoid = newId;
1254

B
Bruce Momjian 已提交
1255
	/*
B
Bruce Momjian 已提交
1256
	 * process indices
1257
	 *
B
Bruce Momjian 已提交
1258 1259 1260
	 * 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.
1261
	 */
1262
	numIndices = resultRelInfo->ri_NumIndices;
1263
	if (numIndices > 0)
1264
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1265 1266

	/* AFTER ROW INSERT Triggers */
1267
	if (resultRelationDesc->trigdesc)
1268
		ExecARInsertTriggers(estate, resultRelationDesc, tuple);
1269 1270 1271
}

/* ----------------------------------------------------------------
1272
 *		ExecDelete
1273
 *
1274 1275
 *		DELETE is like append, we delete the tuple and its
 *		index tuples.
1276 1277 1278
 * ----------------------------------------------------------------
 */
static void
1279
ExecDelete(TupleTableSlot *slot,
1280
		   ItemPointer tupleid,
1281
		   EState *estate)
1282
{
1283
	ResultRelInfo *resultRelInfo;
B
Bruce Momjian 已提交
1284 1285 1286
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
1287

B
Bruce Momjian 已提交
1288
	/*
1289
	 * get information on the (current) result relation
1290
	 */
1291 1292
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1293 1294 1295

	/* BEFORE ROW DELETE Triggers */
	if (resultRelationDesc->trigdesc &&
1296
		resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
1297
	{
1298
		bool		dodelete;
1299

V
Vadim B. Mikheev 已提交
1300
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1301 1302 1303 1304 1305

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

V
Vadim B. Mikheev 已提交
1306
	/*
B
Bruce Momjian 已提交
1307
	 * delete the tuple
1308
	 */
1309
ldelete:;
V
Vadim B. Mikheev 已提交
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
	result = heap_delete(resultRelationDesc, tupleid, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1320 1321
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1322 1323
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1324
				TupleTableSlot *epqslot = EvalPlanQual(estate,
1325
						  resultRelInfo->ri_RangeTableIndex, &ctid);
1326

V
Vadim B. Mikheev 已提交
1327
				if (!TupIsNull(epqslot))
1328 1329 1330 1331 1332
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1333 1334 1335 1336 1337 1338
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1339 1340 1341 1342

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

B
Bruce Momjian 已提交
1343
	/*
B
Bruce Momjian 已提交
1344 1345
	 * Note: Normally one would think that we have to delete index tuples
	 * associated with the heap tuple now..
1346
	 *
B
Bruce Momjian 已提交
1347 1348 1349
	 * ... 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
1350 1351 1352
	 */

	/* AFTER ROW DELETE Triggers */
1353
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1354
		ExecARDeleteTriggers(estate, tupleid);
1355 1356 1357
}

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

B
Bruce Momjian 已提交
1380
	/*
B
Bruce Momjian 已提交
1381
	 * abort the operation if not running transactions
1382 1383 1384
	 */
	if (IsBootstrapProcessingMode())
	{
1385
		elog(NOTICE, "ExecReplace: replace can't run without transactions");
1386 1387 1388
		return;
	}

B
Bruce Momjian 已提交
1389
	/*
B
Bruce Momjian 已提交
1390
	 * get the heap tuple out of the tuple table slot
1391 1392 1393
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1394
	/*
1395
	 * get information on the (current) result relation
1396
	 */
1397 1398
	resultRelInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelInfo->ri_RelationDesc;
1399 1400 1401

	/* BEFORE ROW UPDATE Triggers */
	if (resultRelationDesc->trigdesc &&
1402
		resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
1403
	{
1404
		HeapTuple	newtuple;
1405

V
Vadim B. Mikheev 已提交
1406
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1407 1408 1409 1410 1411 1412

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
1413 1414 1415 1416 1417 1418 1419 1420
			/*
			 * Insert modified tuple into tuple table slot, replacing the
			 * original.  We assume that it was allocated in per-tuple
			 * memory context, and therefore will go away by itself.
			 * The tuple table slot should not try to clear it.
			 */
			ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
			tuple = newtuple;
1421 1422 1423
		}
	}

B
Bruce Momjian 已提交
1424
	/*
1425
	 * Check the constraints of the tuple
1426 1427
	 */
	if (resultRelationDesc->rd_att->constr)
1428
		ExecConstraints("ExecReplace", resultRelInfo, slot, estate);
1429

V
Vadim B. Mikheev 已提交
1430
	/*
B
Bruce Momjian 已提交
1431
	 * replace the heap tuple
1432
	 */
1433
lreplace:;
1434
	result = heap_update(resultRelationDesc, tupleid, tuple, &ctid);
V
Vadim B. Mikheev 已提交
1435 1436 1437 1438 1439 1440 1441 1442 1443
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1444 1445
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1446 1447
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1448
				TupleTableSlot *epqslot = EvalPlanQual(estate,
1449
						  resultRelInfo->ri_RangeTableIndex, &ctid);
1450

V
Vadim B. Mikheev 已提交
1451
				if (!TupIsNull(epqslot))
1452 1453
				{
					*tupleid = ctid;
V
Vadim B. Mikheev 已提交
1454 1455
					tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
					slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1456 1457 1458
					goto lreplace;
				}
			}
V
Vadim B. Mikheev 已提交
1459 1460 1461
			return;

		default:
1462
			elog(ERROR, "Unknown status %u from heap_update", result);
V
Vadim B. Mikheev 已提交
1463
			return;
1464 1465 1466 1467 1468
	}

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

B
Bruce Momjian 已提交
1469
	/*
B
Bruce Momjian 已提交
1470 1471
	 * Note: instead of having to update the old index tuples associated
	 * with the heap tuple, all we do is form and insert new index
1472 1473 1474
	 * 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
1475 1476
	 */

B
Bruce Momjian 已提交
1477
	/*
B
Bruce Momjian 已提交
1478
	 * process indices
1479
	 *
1480
	 * heap_update updates a tuple in the base relation by invalidating it
B
Bruce Momjian 已提交
1481 1482 1483 1484
	 * 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.
1485 1486
	 */

1487
	numIndices = resultRelInfo->ri_NumIndices;
1488
	if (numIndices > 0)
1489
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1490 1491

	/* AFTER ROW UPDATE Triggers */
1492
	if (resultRelationDesc->trigdesc)
V
Vadim B. Mikheev 已提交
1493
		ExecARUpdateTriggers(estate, tupleid, tuple);
1494
}
V
Vadim B. Mikheev 已提交
1495

1496
static char *
1497 1498
ExecRelCheck(ResultRelInfo *resultRelInfo,
			 TupleTableSlot *slot, EState *estate)
V
Vadim B. Mikheev 已提交
1499
{
1500
	Relation	rel = resultRelInfo->ri_RelationDesc;
1501 1502
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
1503
	ExprContext *econtext;
1504
	MemoryContext oldContext;
1505 1506
	List	   *qual;
	int			i;
1507

1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
	/*
	 * 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);
	}

1526
	/*
1527
	 * We will use the EState's per-tuple context for evaluating constraint
1528
	 * expressions (creating it if it's not already there).
1529
	 */
1530
	econtext = GetPerTupleExprContext(estate);
1531

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

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

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

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

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

	Assert(constr);
1562

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

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

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

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

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

	Assert(rti != 0);

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

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

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

	epqstate = &(epq->estate);

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

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

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

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

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

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

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

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

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

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

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

1804
	return EvalPlanQualNext(estate);
1805 1806
}

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

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

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

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

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