execMain.c 46.2 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 26 27 28
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
B
Bruce Momjian 已提交
29
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.91 1999/07/16 03:12:50 momjian Exp $
30 31 32
 *
 *-------------------------------------------------------------------------
 */
33
#include <string.h>
34
#include "postgres.h"
35
#include "miscadmin.h"
36

37
#include "executor/executor.h"
38 39
#include "executor/execdefs.h"
#include "executor/execdebug.h"
40 41
#include "utils/builtins.h"
#include "utils/acl.h"
42
#include "utils/syscache.h"
B
Bruce Momjian 已提交
43
#include "parser/parsetree.h"
44 45
/* #include "access/localam.h" */
#include "optimizer/var.h"
46 47
#include "access/heapam.h"
#include "catalog/heap.h"
48
#include "commands/trigger.h"
49

50
void ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable,
51
			   Query *parseTree);
52 53 54


/* decls for local routines only used within this module */
55
static TupleDesc InitPlan(CmdType operation,
B
Bruce Momjian 已提交
56 57 58
		 Query *parseTree,
		 Plan *plan,
		 EState *estate);
59
static void EndPlan(Plan *plan,
B
Bruce Momjian 已提交
60
		EState *estate);
61
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
B
Bruce Momjian 已提交
62 63 64 65
			CmdType operation,
			int offsetTuples,
			int numberTuples,
			ScanDirection direction,
66
			DestReceiver *destfunc);
67
static void ExecRetrieve(TupleTableSlot *slot,
68
			 DestReceiver *destfunc,
B
Bruce Momjian 已提交
69
			 EState *estate);
70
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
71
		   EState *estate);
72
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
73
		   EState *estate);
74
static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
B
Bruce Momjian 已提交
75
			EState *estate);
76 77 78 79

TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
static TupleTableSlot *EvalPlanQualNext(EState *estate);

80 81 82 83

/* end of local decls */

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

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

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

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

127 128 129
	/*
	 * Initialize the plan
	 */
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	result = InitPlan(queryDesc->operation,
					  queryDesc->parsetree,
					  queryDesc->plantree,
					  estate);

	/*
	 * reset buffer refcount.  the current refcounts are saved and will be
	 * restored when ExecutorEnd is called
	 *
	 * this makes sure that when ExecutorRun's are called recursively as for
	 * postquel functions, the buffers pinned by one ExecutorRun will not
	 * be unpinned by another ExecutorRun.
	 */
	BufferRefCountReset(estate->es_refcount);

	return result;
146 147 148
}

/* ----------------------------------------------------------------
149 150 151 152 153 154 155
 *		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.
156
 *
157 158 159 160 161 162
 *		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
163 164 165 166
 *
 *
 * ----------------------------------------------------------------
 */
167
TupleTableSlot *
B
Bruce Momjian 已提交
168 169
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
			Node *limoffset, Node *limcount)
170
{
B
Bruce Momjian 已提交
171 172
	CmdType		operation;
	Plan	   *plan;
173
	TupleTableSlot *result;
B
Bruce Momjian 已提交
174 175 176 177
	CommandDest dest;
	DestReceiver *destfunc;
	int			offset = 0;
	int			count = 0;
178

B
Bruce Momjian 已提交
179
	/*
B
Bruce Momjian 已提交
180
	 * sanity checks
181
	 */
182 183
	Assert(queryDesc != NULL);

B
Bruce Momjian 已提交
184
	/*
B
Bruce Momjian 已提交
185 186
	 * extract information from the query descriptor and the query
	 * feature.
187
	 */
188 189 190
	operation = queryDesc->operation;
	plan = queryDesc->plantree;
	dest = queryDesc->dest;
191
	destfunc = DestToFunction(dest);
192 193 194
	estate->es_processed = 0;
	estate->es_lastoid = InvalidOid;

B
Bruce Momjian 已提交
195
	/*
B
Bruce Momjian 已提交
196 197 198 199
	 * 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.
200 201 202
	 */
	(*destfunc->setup) (destfunc, (TupleDesc) NULL);

B
Bruce Momjian 已提交
203 204 205 206 207 208 209 210 211 212
	/*
	 * if given get the offset of the LIMIT clause
	 */
	if (limoffset != NULL)
	{
		Const	   *coffset;
		Param	   *poffset;
		ParamListInfo paramLI;
		int			i;

213 214 215
		switch (nodeTag(limoffset))
		{
			case T_Const:
B
Bruce Momjian 已提交
216 217
				coffset = (Const *) limoffset;
				offset = (int) (coffset->constvalue);
218
				break;
B
Bruce Momjian 已提交
219

220
			case T_Param:
B
Bruce Momjian 已提交
221
				poffset = (Param *) limoffset;
222
				paramLI = estate->es_param_list_info;
B
Bruce Momjian 已提交
223

224 225 226 227 228 229 230 231 232 233 234
				if (paramLI == NULL)
					elog(ERROR, "parameter for limit offset not in executor state");
				for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
				{
					if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
						break;
				}
				if (paramLI[i].kind == PARAM_INVALID)
					elog(ERROR, "parameter for limit offset not in executor state");
				if (paramLI[i].isnull)
					elog(ERROR, "limit offset cannot be NULL value");
B
Bruce Momjian 已提交
235 236
				offset = (int) (paramLI[i].value);

237
				break;
B
Bruce Momjian 已提交
238

239 240 241
			default:
				elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
		}
B
Bruce Momjian 已提交
242

243 244 245
		if (offset < 0)
			elog(ERROR, "limit offset cannot be negative");
	}
B
Bruce Momjian 已提交
246

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

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

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

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

				break;

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

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

291 292 293
	switch (feature)
	{

294 295 296 297
		case EXEC_RUN:
			result = ExecutePlan(estate,
								 plan,
								 operation,
298 299
								 offset,
								 count,
300
								 ForwardScanDirection,
301
								 destfunc);
302 303 304 305 306
			break;
		case EXEC_FOR:
			result = ExecutePlan(estate,
								 plan,
								 operation,
307
								 offset,
308 309
								 count,
								 ForwardScanDirection,
310
								 destfunc);
311
			break;
312

B
Bruce Momjian 已提交
313
			/*
B
Bruce Momjian 已提交
314
			 * retrieve next n "backward" tuples
315 316 317 318 319
			 */
		case EXEC_BACK:
			result = ExecutePlan(estate,
								 plan,
								 operation,
320
								 offset,
321 322
								 count,
								 BackwardScanDirection,
323
								 destfunc);
324
			break;
325

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

345 346
	(*destfunc->cleanup) (destfunc);

347
	return result;
348 349 350
}

/* ----------------------------------------------------------------
351 352 353 354 355 356 357
 *		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.
358 359 360 361
 *
 * ----------------------------------------------------------------
 */
void
362
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
363
{
364 365
	/* sanity checks */
	Assert(queryDesc != NULL);
366

367
	EndPlan(queryDesc->plantree, estate);
368

369
	/* XXX - clean up some more from ExecutorStart() - er1p */
B
Bruce Momjian 已提交
370 371 372 373 374 375 376 377 378
	if (NULL == estate->es_snapshot)
	{
		/* nothing to free */
	}
	else
	{
		if (estate->es_snapshot->xcnt > 0)
			pfree(estate->es_snapshot->xip);
		pfree(estate->es_snapshot);
379 380
	}

B
Bruce Momjian 已提交
381 382 383 384 385 386 387 388
	if (NULL == estate->es_param_exec_vals)
	{
		/* nothing to free */
	}
	else
	{
		pfree(estate->es_param_exec_vals);
		estate->es_param_exec_vals = NULL;
389 390
	}

391 392
	/* restore saved refcounts. */
	BufferRefCountRestore(estate->es_refcount);
393

394 395
}

396
void
397
ExecCheckPerms(CmdType operation,
398
			   int resultRelation,
399 400
			   List *rangeTable,
			   Query *parseTree)
401
{
402 403
	int			i = 1;
	Oid			relid;
404
	HeapTuple	htup;
405 406 407 408 409 410 411 412
	List	   *lp;
	List	   *qvars,
			   *tvars;
	int32		ok = 1,
				aclcheck_result = -1;
	char	   *opstr;
	NameData	rname;
	char	   *userName;
413 414 415 416 417 418 419

#define CHECK(MODE)		pg_aclcheck(rname.data, userName, MODE)

	userName = GetPgUserName();

	foreach(lp, rangeTable)
	{
420
		RangeTblEntry *rte = lfirst(lp);
421

M
Marc G. Fournier 已提交
422 423
		if (rte->skipAcl)
		{
424

M
Marc G. Fournier 已提交
425
			/*
426 427 428 429
			 * This happens if the access to this table is due to a view
			 * query rewriting - the rewrite handler checked the
			 * permissions against the view owner, so we just skip this
			 * entry.
M
Marc G. Fournier 已提交
430 431 432 433
			 */
			continue;
		}

434
		relid = rte->relid;
435
		htup = SearchSysCacheTuple(RELOID,
436 437
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
438
		if (!HeapTupleIsValid(htup))
439
			elog(ERROR, "ExecCheckPerms: bogus RT relid: %u", relid);
440
		StrNCpy(rname.data,
441
				((Form_pg_class) GETSTRUCT(htup))->relname.data,
442
				NAMEDATALEN);
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
		if (i == resultRelation)
		{						/* this is the result relation */
			qvars = pull_varnos(parseTree->qual);
			tvars = pull_varnos((Node *) parseTree->targetList);
			if (intMember(resultRelation, qvars) ||
				intMember(resultRelation, tvars))
			{
				/* result relation is scanned */
				ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
				opstr = "read";
				if (!ok)
					break;
			}
			switch (operation)
			{
458 459 460 461 462 463 464 465 466 467 468
				case CMD_INSERT:
					ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
						((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
					opstr = "append";
					break;
				case CMD_DELETE:
				case CMD_UPDATE:
					ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
					opstr = "write";
					break;
				default:
469
					elog(ERROR, "ExecCheckPerms: bogus operation %d",
470
						 operation);
471 472 473 474 475 476 477
			}
		}
		else
		{
			ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
			opstr = "read";
		}
478
		if (!ok)
479 480
			break;
		++i;
481 482
	}
	if (!ok)
483
		elog(ERROR, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
484

T
Tom Lane 已提交
485
	if (parseTree != NULL && parseTree->rowMark != NULL)
486 487 488
	{
		foreach(lp, parseTree->rowMark)
		{
B
Bruce Momjian 已提交
489
			RowMark    *rm = lfirst(lp);
490 491 492 493

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

B
Bruce Momjian 已提交
494
			relid = ((RangeTblEntry *) nth(rm->rti - 1, rangeTable))->relid;
495
			htup = SearchSysCacheTuple(RELOID,
B
Bruce Momjian 已提交
496 497
									   ObjectIdGetDatum(relid),
									   0, 0, 0);
498
			if (!HeapTupleIsValid(htup))
499
				elog(ERROR, "ExecCheckPerms: bogus RT relid: %u", relid);
500 501 502 503 504 505 506 507 508
			StrNCpy(rname.data,
					((Form_pg_class) GETSTRUCT(htup))->relname.data,
					NAMEDATALEN);
			ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
			opstr = "write";
			if (!ok)
				elog(ERROR, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
		}
	}
509 510
}

511 512 513 514 515 516 517
/* ===============================================================
 * ===============================================================
						 static routines follow
 * ===============================================================
 * ===============================================================
 */

518 519 520
typedef struct execRowMark
{
	Relation	relation;
521
	Index		rti;
522
	char		resname[32];
523
} execRowMark;
524

525 526
typedef struct evalPlanQual
{
B
Bruce Momjian 已提交
527 528 529 530
	Plan	   *plan;
	Index		rti;
	EState		estate;
	struct evalPlanQual *free;
531
} evalPlanQual;
532

533
/* ----------------------------------------------------------------
534 535 536 537
 *		InitPlan
 *
 *		Initializes the query plan: open files, allocate storage
 *		and start up the rule manager
538 539
 * ----------------------------------------------------------------
 */
540
static TupleDesc
541
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
542
{
B
Bruce Momjian 已提交
543 544 545 546 547 548
	List	   *rangeTable;
	int			resultRelation;
	Relation	intoRelationDesc;
	TupleDesc	tupType;
	List	   *targetList;
	int			len;
549

B
Bruce Momjian 已提交
550
	/*
B
Bruce Momjian 已提交
551
	 * get information from query descriptor
552
	 */
553 554
	rangeTable = parseTree->rtable;
	resultRelation = parseTree->resultRelation;
555

556 557 558 559
#ifndef NO_SECURITY
	ExecCheckPerms(operation, resultRelation, rangeTable, parseTree);
#endif

B
Bruce Momjian 已提交
560
	/*
B
Bruce Momjian 已提交
561
	 * initialize the node's execution state
562
	 */
563 564
	estate->es_range_table = rangeTable;

B
Bruce Momjian 已提交
565
	/*
B
Bruce Momjian 已提交
566 567 568
	 * initialize the BaseId counter so node base_id's are assigned
	 * correctly.  Someday baseid's will have to be stored someplace other
	 * than estate because they should be unique per query planned.
569
	 */
570
	estate->es_BaseId = 1;
571

B
Bruce Momjian 已提交
572
	/*
B
Bruce Momjian 已提交
573
	 * initialize result relation stuff
574
	 */
B
Bruce Momjian 已提交
575

576 577
	if (resultRelation != 0 && operation != CMD_SELECT)
	{
B
Bruce Momjian 已提交
578

B
Bruce Momjian 已提交
579
		/*
B
Bruce Momjian 已提交
580 581
		 * if we have a result relation, open it and initialize the result
		 * relation info stuff.
582
		 */
583 584 585 586 587
		RelationInfo *resultRelationInfo;
		Index		resultRelationIndex;
		RangeTblEntry *rtentry;
		Oid			resultRelationOid;
		Relation	resultRelationDesc;
588 589 590 591 592 593 594

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

		if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
595
			elog(ERROR, "You can't change sequence relation %s",
596 597
				 resultRelationDesc->rd_rel->relname.data);

V
Vadim B. Mikheev 已提交
598
		LockRelation(resultRelationDesc, RowExclusiveLock);
599 600 601 602 603 604 605

		resultRelationInfo = makeNode(RelationInfo);
		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
		resultRelationInfo->ri_RelationDesc = resultRelationDesc;
		resultRelationInfo->ri_NumIndices = 0;
		resultRelationInfo->ri_IndexRelationDescs = NULL;
		resultRelationInfo->ri_IndexRelationInfo = NULL;
606

B
Bruce Momjian 已提交
607
		/*
B
Bruce Momjian 已提交
608 609
		 * open indices on result relation and save descriptors in the
		 * result relation information..
610
		 */
V
Vadim B. Mikheev 已提交
611 612
		if (operation != CMD_DELETE)
			ExecOpenIndices(resultRelationOid, resultRelationInfo);
613 614

		estate->es_result_relation_info = resultRelationInfo;
615
	}
616 617
	else
	{
B
Bruce Momjian 已提交
618

B
Bruce Momjian 已提交
619
		/*
B
Bruce Momjian 已提交
620
		 * if no result relation, then set state appropriately
621 622 623 624
		 */
		estate->es_result_relation_info = NULL;
	}

625 626 627 628 629 630
	/*
	 * Have to lock relations selected for update
	 */
	estate->es_rowMark = NULL;
	if (parseTree->rowMark != NULL)
	{
B
Bruce Momjian 已提交
631 632 633 634 635
		Relation	relation;
		Oid			relid;
		RowMark    *rm;
		List	   *l;
		execRowMark *erm;
636 637 638 639

		foreach(l, parseTree->rowMark)
		{
			rm = lfirst(l);
B
Bruce Momjian 已提交
640
			relid = ((RangeTblEntry *) nth(rm->rti - 1, rangeTable))->relid;
641 642 643 644
			relation = heap_open(relid);
			LockRelation(relation, RowShareLock);
			if (!(rm->info & ROW_MARK_FOR_UPDATE))
				continue;
B
Bruce Momjian 已提交
645
			erm = (execRowMark *) palloc(sizeof(execRowMark));
646
			erm->relation = relation;
647
			erm->rti = rm->rti;
648 649 650 651
			sprintf(erm->resname, "ctid%u", rm->rti);
			estate->es_rowMark = lappend(estate->es_rowMark, erm);
		}
	}
652

B
Bruce Momjian 已提交
653
	/*
B
Bruce Momjian 已提交
654
	 * initialize the executor "tuple" table.
655 656
	 */
	{
657 658
		int			nSlots = ExecCountSlotsNode(plan);
		TupleTable	tupleTable = ExecCreateTupleTable(nSlots + 10);		/* why add ten? - jolly */
659

660 661
		estate->es_tupleTable = tupleTable;
	}
662

B
Bruce Momjian 已提交
663
	/*
B
Bruce Momjian 已提交
664 665 666
	 * initialize the private state information for all the nodes in the
	 * query tree.	This opens files, allocates storage and leaves us
	 * ready to start processing tuples..
667 668 669
	 */
	ExecInitNode(plan, estate, NULL);

B
Bruce Momjian 已提交
670
	/*
B
Bruce Momjian 已提交
671 672 673
	 * get the tuple descriptor describing the type of tuples to return..
	 * (this is especially important if we are creating a relation with
	 * "retrieve into")
674 675 676 677 678
	 */
	tupType = ExecGetTupType(plan);		/* tuple descriptor */
	targetList = plan->targetlist;
	len = ExecTargetListLength(targetList);		/* number of attributes */

B
Bruce Momjian 已提交
679
	/*
B
Bruce Momjian 已提交
680 681 682 683 684 685 686
	 * now that we have the target list, initialize the junk filter if
	 * this is a REPLACE or a DELETE query. We also init the junk filter
	 * if this is an append query (there might be some rule lock info
	 * there...) NOTE: in the future we might want to initialize the junk
	 * filter for all queries. SELECT added by daveh@insightdist.com
	 * 5/20/98 to allow ORDER/GROUP BY have an identifier missing from the
	 * target.
687 688
	 */
	{
689 690 691
		bool		junk_filter_needed = false;
		List	   *tlist;

692
		if (operation == CMD_SELECT)
693 694 695
		{
			foreach(tlist, targetList)
			{
696 697
				TargetEntry *tle = lfirst(tlist);

698 699 700 701 702 703 704 705 706 707 708 709 710
				if (tle->resdom->resjunk)
				{
					junk_filter_needed = true;
					break;
				}
			}
		}

		if (operation == CMD_UPDATE || operation == CMD_DELETE ||
			operation == CMD_INSERT ||
			(operation == CMD_SELECT && junk_filter_needed))
		{
			JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
711

712
			estate->es_junkFilter = j;
713

714 715 716 717 718 719
			if (operation == CMD_SELECT)
				tupType = j->jf_cleanTupType;
		}
		else
			estate->es_junkFilter = NULL;
	}
720

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

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

		if (!parseTree->isPortal)
		{

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

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

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

751
				intoRelationId = heap_create_with_catalog(intoName,
B
Bruce Momjian 已提交
752
						   tupdesc, RELKIND_RELATION, parseTree->isTemp);
753

754 755
				FreeTupleDesc(tupdesc);

B
Bruce Momjian 已提交
756
				/*
B
Bruce Momjian 已提交
757 758 759
				 * XXX rather than having to call setheapoverride(true)
				 * and then back to false, we should change the arguments
				 * to heap_open() instead..
760 761 762 763 764 765 766 767 768 769 770 771
				 */
				setheapoverride(true);

				intoRelationDesc = heap_open(intoRelationId);

				setheapoverride(false);
			}
		}
	}

	estate->es_into_relation_descriptor = intoRelationDesc;

772 773 774 775 776
	estate->es_origPlan = plan;
	estate->es_evalPlanQual = NULL;
	estate->es_evTuple = NULL;
	estate->es_useEvalPlan = false;

777
	return tupType;
778 779 780
}

/* ----------------------------------------------------------------
781 782 783
 *		EndPlan
 *
 *		Cleans up the query plan -- closes files and free up storages
784 785 786
 * ----------------------------------------------------------------
 */
static void
787
EndPlan(Plan *plan, EState *estate)
788
{
789 790
	RelationInfo *resultRelationInfo;
	Relation	intoRelationDesc;
791

B
Bruce Momjian 已提交
792
	/*
B
Bruce Momjian 已提交
793
	 * get information from state
794
	 */
795 796 797
	resultRelationInfo = estate->es_result_relation_info;
	intoRelationDesc = estate->es_into_relation_descriptor;

B
Bruce Momjian 已提交
798
	/*
B
Bruce Momjian 已提交
799
	 * shut down the query
800 801 802
	 */
	ExecEndNode(plan, plan);

B
Bruce Momjian 已提交
803
	/*
B
Bruce Momjian 已提交
804
	 * destroy the executor "tuple" table.
805 806
	 */
	{
807
		TupleTable	tupleTable = (TupleTable) estate->es_tupleTable;
808 809 810 811 812

		ExecDestroyTupleTable(tupleTable, true);		/* was missing last arg */
		estate->es_tupleTable = NULL;
	}

B
Bruce Momjian 已提交
813
	/*
B
Bruce Momjian 已提交
814
	 * close the result relations if necessary
815 816 817
	 */
	if (resultRelationInfo != NULL)
	{
818
		Relation	resultRelationDesc;
819 820 821 822

		resultRelationDesc = resultRelationInfo->ri_RelationDesc;
		heap_close(resultRelationDesc);

B
Bruce Momjian 已提交
823
		/*
B
Bruce Momjian 已提交
824
		 * close indices on the result relation
825 826 827 828
		 */
		ExecCloseIndices(resultRelationInfo);
	}

B
Bruce Momjian 已提交
829
	/*
B
Bruce Momjian 已提交
830
	 * close the "into" relation if necessary
831 832 833
	 */
	if (intoRelationDesc != NULL)
		heap_close(intoRelationDesc);
834 835 836
}

/* ----------------------------------------------------------------
837 838 839 840 841 842 843 844
 *		ExecutePlan
 *
 *		processes the query plan to retrieve 'tupleCount' tuples in the
 *		direction specified.
 *		Retrieves all tuples if tupleCount is 0
 *
 *		result is either a slot containing a tuple in the case
 *		of a RETRIEVE or NULL otherwise.
845 846 847 848 849 850 851 852
 *
 * ----------------------------------------------------------------
 */

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

static TupleTableSlot *
853 854
ExecutePlan(EState *estate,
			Plan *plan,
855
			CmdType operation,
856
			int offsetTuples,
857 858
			int numberTuples,
			ScanDirection direction,
859
			DestReceiver *destfunc)
860
{
861
	JunkFilter *junkfilter;
862
	TupleTableSlot *slot;
863
	ItemPointer tupleid = NULL;
864
	ItemPointerData tuple_ctid;
865
	int			current_tuple_count;
866 867
	TupleTableSlot *result;

B
Bruce Momjian 已提交
868
	/*
B
Bruce Momjian 已提交
869
	 * initialize local variables
870
	 */
871 872 873 874
	slot = NULL;
	current_tuple_count = 0;
	result = NULL;

B
Bruce Momjian 已提交
875 876
	/*
	 * Set the direction.
877
	 */
878 879
	estate->es_direction = direction;

B
Bruce Momjian 已提交
880
	/*
B
Bruce Momjian 已提交
881 882
	 * Loop until we've processed the proper number of tuples from the
	 * plan..
883 884 885 886
	 */

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

B
Bruce Momjian 已提交
888
		/*
B
Bruce Momjian 已提交
889
		 * Execute the plan and obtain a tuple
890 891
		 */
		/* at the top level, the parent of a plan (2nd arg) is itself */
B
Bruce Momjian 已提交
892
lnext:	;
893 894 895 896 897 898 899 900
		if (estate->es_useEvalPlan)
		{
			slot = EvalPlanQualNext(estate);
			if (TupIsNull(slot))
				slot = ExecProcNode(plan, plan);
		}
		else
			slot = ExecProcNode(plan, plan);
901

B
Bruce Momjian 已提交
902
		/*
B
Bruce Momjian 已提交
903 904
		 * if the tuple is null, then we assume there is nothing more to
		 * process so we just return null...
905 906 907 908 909
		 */
		if (TupIsNull(slot))
		{
			result = NULL;
			break;
910 911
		}

B
Bruce Momjian 已提交
912
		/*
B
Bruce Momjian 已提交
913 914 915
		 * For now we completely execute the plan and skip result tuples
		 * if requested by LIMIT offset. Finally we should try to do it in
		 * deeper levels if possible (during index scan) - Jan
916 917 918 919 920 921 922
		 */
		if (offsetTuples > 0)
		{
			--offsetTuples;
			continue;
		}

B
Bruce Momjian 已提交
923
		/*
B
Bruce Momjian 已提交
924 925
		 * if we have a junk filter, then project a new tuple with the
		 * junk removed.
926
		 *
B
Bruce Momjian 已提交
927
		 * Store this new "clean" tuple in the place of the original tuple.
928
		 *
B
Bruce Momjian 已提交
929
		 * Also, extract all the junk information we need.
930 931 932
		 */
		if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
		{
933 934 935
			Datum		datum;
			HeapTuple	newTuple;
			bool		isNull;
936

B
Bruce Momjian 已提交
937
			/*
938 939 940 941 942 943 944 945 946
			 * extract the 'ctid' junk attribute.
			 */
			if (operation == CMD_UPDATE || operation == CMD_DELETE)
			{
				if (!ExecGetJunkAttribute(junkfilter,
										  slot,
										  "ctid",
										  &datum,
										  &isNull))
947
					elog(ERROR, "ExecutePlan: NO (junk) `ctid' was found!");
948 949

				if (isNull)
950
					elog(ERROR, "ExecutePlan: (junk) `ctid' is NULL!");
951 952 953 954 955 956

				tupleid = (ItemPointer) DatumGetPointer(datum);
				tuple_ctid = *tupleid;	/* make sure we don't free the
										 * ctid!! */
				tupleid = &tuple_ctid;
			}
957 958
			else if (estate->es_rowMark != NULL)
			{
B
Bruce Momjian 已提交
959 960 961 962
				List	   *l;
				execRowMark *erm;
				Buffer		buffer;
				HeapTupleData tuple;
963
				TupleTableSlot *newSlot;
B
Bruce Momjian 已提交
964
				int			test;
965

B
Bruce Momjian 已提交
966 967
		lmark:	;
				foreach(l, estate->es_rowMark)
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
				{
					erm = lfirst(l);
					if (!ExecGetJunkAttribute(junkfilter,
											  slot,
											  erm->resname,
											  &datum,
											  &isNull))
						elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!", erm->resname);

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

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

						case HeapTupleUpdated:
							if (XactIsoLevel == XACT_SERIALIZABLE)
991
							{
992
								elog(ERROR, "Can't serialize access due to concurrent update");
B
Bruce Momjian 已提交
993
								return (NULL);
994
							}
B
Bruce Momjian 已提交
995 996
							else if (!(ItemPointerEquals(&(tuple.t_self),
								  (ItemPointer) DatumGetPointer(datum))))
997
							{
B
Bruce Momjian 已提交
998
								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));
999 1000 1001 1002 1003 1004 1005
								if (!(TupIsNull(newSlot)))
								{
									slot = newSlot;
									estate->es_useEvalPlan = true;
									goto lmark;
								}
							}
B
Bruce Momjian 已提交
1006 1007 1008 1009 1010

							/*
							 * if tuple was deleted or PlanQual failed for
							 * updated tuple - we have not return this
							 * tuple!
1011 1012
							 */
							goto lnext;
1013 1014 1015

						default:
							elog(ERROR, "Unknown status %u from heap_mark4update", test);
B
Bruce Momjian 已提交
1016
							return (NULL);
1017 1018 1019
					}
				}
			}
1020

B
Bruce Momjian 已提交
1021
			/*
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
			 * 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 已提交
1034
		/*
B
Bruce Momjian 已提交
1035 1036 1037
		 * now that we have a tuple, do the appropriate thing with it..
		 * either return it to the user, add it to a relation someplace,
		 * delete it from a relation, or modify some of it's attributes.
1038 1039 1040 1041
		 */

		switch (operation)
		{
1042 1043
			case CMD_SELECT:
				ExecRetrieve(slot,		/* slot containing tuple */
B
Bruce Momjian 已提交
1044 1045
							 destfunc,	/* destination's tuple-receiver
										 * obj */
1046 1047 1048
							 estate);	/* */
				result = slot;
				break;
1049

1050 1051 1052 1053
			case CMD_INSERT:
				ExecAppend(slot, tupleid, estate);
				result = NULL;
				break;
1054

1055 1056 1057 1058
			case CMD_DELETE:
				ExecDelete(slot, tupleid, estate);
				result = NULL;
				break;
1059

1060
			case CMD_UPDATE:
1061
				ExecReplace(slot, tupleid, estate);
1062 1063
				result = NULL;
				break;
1064

1065 1066
			default:
				elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
1067
				result = NULL;
1068
				break;
1069
		}
B
Bruce Momjian 已提交
1070

B
Bruce Momjian 已提交
1071
		/*
B
Bruce Momjian 已提交
1072 1073
		 * check our tuple count.. if we've returned the proper number
		 * then return, else loop again and process more tuples..
1074 1075 1076 1077
		 */
		current_tuple_count += 1;
		if (numberTuples == current_tuple_count)
			break;
1078
	}
1079

B
Bruce Momjian 已提交
1080
	/*
B
Bruce Momjian 已提交
1081 1082
	 * here, result is either a slot containing a tuple in the case of a
	 * RETRIEVE or NULL otherwise.
1083
	 */
1084
	return result;
1085 1086 1087
}

/* ----------------------------------------------------------------
1088
 *		ExecRetrieve
1089
 *
1090 1091 1092 1093 1094
 *		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.)
1095 1096 1097
 * ----------------------------------------------------------------
 */
static void
1098
ExecRetrieve(TupleTableSlot *slot,
1099
			 DestReceiver *destfunc,
1100
			 EState *estate)
1101
{
1102 1103
	HeapTuple	tuple;
	TupleDesc	attrtype;
1104

B
Bruce Momjian 已提交
1105
	/*
B
Bruce Momjian 已提交
1106
	 * get the heap tuple out of the tuple table slot
1107 1108 1109 1110
	 */
	tuple = slot->val;
	attrtype = slot->ttc_tupleDescriptor;

B
Bruce Momjian 已提交
1111
	/*
B
Bruce Momjian 已提交
1112
	 * insert the tuple into the "into relation"
1113 1114 1115 1116 1117 1118 1119
	 */
	if (estate->es_into_relation_descriptor != NULL)
	{
		heap_insert(estate->es_into_relation_descriptor, tuple);
		IncrAppended();
	}

B
Bruce Momjian 已提交
1120
	/*
B
Bruce Momjian 已提交
1121
	 * send the tuple to the front end (or the screen)
1122
	 */
1123
	(*destfunc->receiveTuple) (tuple, attrtype, destfunc);
1124 1125
	IncrRetrieved();
	(estate->es_processed)++;
1126 1127 1128
}

/* ----------------------------------------------------------------
1129
 *		ExecAppend
1130
 *
1131 1132 1133
 *		APPENDs are trickier.. we have to insert the tuple into
 *		the base relation and insert appropriate tuples into the
 *		index relations.
1134 1135 1136 1137
 * ----------------------------------------------------------------
 */

static void
1138
ExecAppend(TupleTableSlot *slot,
1139
		   ItemPointer tupleid,
1140
		   EState *estate)
1141
{
1142 1143 1144 1145 1146
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	int			numIndices;
	Oid			newId;
1147

B
Bruce Momjian 已提交
1148
	/*
B
Bruce Momjian 已提交
1149
	 * get the heap tuple out of the tuple table slot
1150 1151 1152
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1153
	/*
B
Bruce Momjian 已提交
1154
	 * get information on the result relation
1155 1156 1157 1158
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

B
Bruce Momjian 已提交
1159
	/*
B
Bruce Momjian 已提交
1160
	 * have to add code to preform unique checking here. cim -12/1/89
1161 1162 1163 1164 1165 1166
	 */

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1167
		HeapTuple	newtuple;
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
			pfree(tuple);
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1182
	/*
1183 1184 1185 1186
	 * Check the constraints of a tuple
	 */

	if (resultRelationDesc->rd_att->constr)
1187
		ExecConstraints("ExecAppend", resultRelationDesc, tuple, estate);
1188

B
Bruce Momjian 已提交
1189
	/*
B
Bruce Momjian 已提交
1190
	 * insert the tuple
1191 1192 1193 1194 1195
	 */
	newId = heap_insert(resultRelationDesc,		/* relation desc */
						tuple); /* heap tuple */
	IncrAppended();

B
Bruce Momjian 已提交
1196
	/*
B
Bruce Momjian 已提交
1197
	 * process indices
1198
	 *
B
Bruce Momjian 已提交
1199 1200 1201
	 * 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.
1202 1203 1204
	 */
	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1205
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1206 1207 1208 1209 1210 1211 1212
	(estate->es_processed)++;
	estate->es_lastoid = newId;

	/* AFTER ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
		ExecARInsertTriggers(resultRelationDesc, tuple);
1213 1214 1215
}

/* ----------------------------------------------------------------
1216
 *		ExecDelete
1217
 *
1218 1219
 *		DELETE is like append, we delete the tuple and its
 *		index tuples.
1220 1221 1222
 * ----------------------------------------------------------------
 */
static void
1223
ExecDelete(TupleTableSlot *slot,
1224
		   ItemPointer tupleid,
1225
		   EState *estate)
1226
{
B
Bruce Momjian 已提交
1227 1228 1229 1230
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
1231

B
Bruce Momjian 已提交
1232
	/*
B
Bruce Momjian 已提交
1233
	 * get the result relation information
1234 1235 1236 1237 1238 1239 1240 1241
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

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

V
Vadim B. Mikheev 已提交
1244
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1245 1246 1247 1248 1249

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

V
Vadim B. Mikheev 已提交
1250
	/*
B
Bruce Momjian 已提交
1251
	 * delete the tuple
1252
	 */
1253
ldelete:;
V
Vadim B. Mikheev 已提交
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
	result = heap_delete(resultRelationDesc, tupleid, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1264 1265
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1266 1267
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1268 1269
				TupleTableSlot *epqslot = EvalPlanQual(estate,
						  resultRelationInfo->ri_RangeTableIndex, &ctid);
1270

V
Vadim B. Mikheev 已提交
1271
				if (!TupIsNull(epqslot))
1272 1273 1274 1275 1276
				{
					*tupleid = ctid;
					goto ldelete;
				}
			}
V
Vadim B. Mikheev 已提交
1277 1278 1279 1280 1281 1282
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1283 1284 1285 1286

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

B
Bruce Momjian 已提交
1287
	/*
B
Bruce Momjian 已提交
1288 1289
	 * Note: Normally one would think that we have to delete index tuples
	 * associated with the heap tuple now..
1290
	 *
B
Bruce Momjian 已提交
1291 1292 1293
	 * ... 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
1294 1295 1296 1297 1298
	 */

	/* AFTER ROW DELETE Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
V
Vadim B. Mikheev 已提交
1299
		ExecARDeleteTriggers(estate, tupleid);
1300 1301 1302 1303

}

/* ----------------------------------------------------------------
1304
 *		ExecReplace
1305
 *
1306 1307 1308 1309 1310 1311
 *		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..
1312 1313 1314
 * ----------------------------------------------------------------
 */
static void
1315
ExecReplace(TupleTableSlot *slot,
1316
			ItemPointer tupleid,
1317
			EState *estate)
1318
{
B
Bruce Momjian 已提交
1319 1320 1321 1322 1323 1324
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	ItemPointerData ctid;
	int			result;
	int			numIndices;
1325

B
Bruce Momjian 已提交
1326
	/*
B
Bruce Momjian 已提交
1327
	 * abort the operation if not running transactions
1328 1329 1330 1331 1332 1333 1334
	 */
	if (IsBootstrapProcessingMode())
	{
		elog(DEBUG, "ExecReplace: replace can't run without transactions");
		return;
	}

B
Bruce Momjian 已提交
1335
	/*
B
Bruce Momjian 已提交
1336
	 * get the heap tuple out of the tuple table slot
1337 1338 1339
	 */
	tuple = slot->val;

B
Bruce Momjian 已提交
1340
	/*
B
Bruce Momjian 已提交
1341
	 * get the result relation information
1342 1343 1344 1345
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

B
Bruce Momjian 已提交
1346
	/*
B
Bruce Momjian 已提交
1347 1348 1349
	 * have to add code to preform unique checking here. in the event of
	 * unique tuples, this becomes a deletion of the original tuple
	 * affected by the replace. cim -12/1/89
1350 1351 1352 1353 1354 1355
	 */

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

V
Vadim B. Mikheev 已提交
1358
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370

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

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
			pfree(tuple);
			slot->val = tuple = newtuple;
		}
	}

B
Bruce Momjian 已提交
1371
	/*
1372 1373 1374 1375
	 * Check the constraints of a tuple
	 */

	if (resultRelationDesc->rd_att->constr)
1376
		ExecConstraints("ExecReplace", resultRelationDesc, tuple, estate);
1377

V
Vadim B. Mikheev 已提交
1378
	/*
B
Bruce Momjian 已提交
1379
	 * replace the heap tuple
1380
	 */
1381
lreplace:;
V
Vadim B. Mikheev 已提交
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
	result = heap_replace(resultRelationDesc, tupleid, tuple, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1392 1393
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
1394 1395
			else if (!(ItemPointerEquals(tupleid, &ctid)))
			{
B
Bruce Momjian 已提交
1396 1397
				TupleTableSlot *epqslot = EvalPlanQual(estate,
						  resultRelationInfo->ri_RangeTableIndex, &ctid);
1398

V
Vadim B. Mikheev 已提交
1399
				if (!TupIsNull(epqslot))
1400 1401
				{
					*tupleid = ctid;
V
Vadim B. Mikheev 已提交
1402 1403
					tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
					slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1404 1405 1406
					goto lreplace;
				}
			}
V
Vadim B. Mikheev 已提交
1407 1408 1409 1410 1411
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_replace", result);
			return;
1412 1413 1414 1415 1416
	}

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

B
Bruce Momjian 已提交
1417
	/*
B
Bruce Momjian 已提交
1418 1419 1420 1421 1422
	 * Note: instead of having to update the old index tuples associated
	 * with the heap tuple, all we do is form and insert new index
	 * tuples..  This is because replaces are actually deletes and inserts
	 * and index tuple deletion is done automagically by the vaccuum
	 * deamon.. All we do is insert new index tuples.  -cim 9/27/89
1423 1424
	 */

B
Bruce Momjian 已提交
1425
	/*
B
Bruce Momjian 已提交
1426
	 * process indices
1427
	 *
B
Bruce Momjian 已提交
1428 1429 1430 1431 1432
	 * heap_replace updates a tuple in the base relation by invalidating it
	 * 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.
1433 1434 1435 1436
	 */

	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1437
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1438 1439 1440 1441

	/* AFTER ROW UPDATE Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
V
Vadim B. Mikheev 已提交
1442
		ExecARUpdateTriggers(estate, tupleid, tuple);
1443
}
V
Vadim B. Mikheev 已提交
1444

M
 
Marc G. Fournier 已提交
1445
#ifdef NOT_USED
1446
static HeapTuple
1447
ExecAttrDefault(Relation rel, HeapTuple tuple)
V
Vadim B. Mikheev 已提交
1448
{
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
	int			ndef = rel->rd_att->constr->num_defval;
	AttrDefault *attrdef = rel->rd_att->constr->defval;
	ExprContext *econtext = makeNode(ExprContext);
	HeapTuple	newtuple;
	Node	   *expr;
	bool		isnull;
	bool		isdone;
	Datum		val;
	Datum	   *replValue = NULL;
	char	   *replNull = NULL;
	char	   *repl = NULL;
	int			i;
1461 1462 1463 1464 1465 1466

	econtext->ecxt_scantuple = NULL;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = NULL;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
1467 1468
	econtext->ecxt_param_list_info = NULL;		/* param list info */
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
	econtext->ecxt_range_table = NULL;	/* range table */
	for (i = 0; i < ndef; i++)
	{
		if (!heap_attisnull(tuple, attrdef[i].adnum))
			continue;
		expr = (Node *) stringToNode(attrdef[i].adbin);

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

		pfree(expr);

		if (isnull)
			continue;

		if (repl == NULL)
		{
			repl = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replNull = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum));
B
Bruce Momjian 已提交
1488
			MemSet(repl, ' ', rel->rd_att->natts * sizeof(char));
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
		}

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

	}

	pfree(econtext);

	if (repl == NULL)
1500
		return tuple;
1501

1502
	newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
1503 1504

	pfree(repl);
1505
	pfree(tuple);
1506 1507 1508
	pfree(replNull);
	pfree(replValue);

1509
	return newtuple;
1510

V
Vadim B. Mikheev 已提交
1511
}
1512

1513
#endif
V
Vadim B. Mikheev 已提交
1514

1515
static char *
1516
ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
V
Vadim B. Mikheev 已提交
1517
{
1518 1519 1520
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
	ExprContext *econtext = makeNode(ExprContext);
1521
	TupleTableSlot *slot = makeNode(TupleTableSlot);
1522 1523 1524 1525 1526
	RangeTblEntry *rte = makeNode(RangeTblEntry);
	List	   *rtlist;
	List	   *qual;
	bool		res;
	int			i;
1527 1528 1529 1530 1531 1532 1533 1534 1535

	slot->val = tuple;
	slot->ttc_shouldFree = false;
	slot->ttc_descIsNew = true;
	slot->ttc_tupleDescriptor = rel->rd_att;
	slot->ttc_buffer = InvalidBuffer;
	slot->ttc_whichplan = -1;
	rte->relname = nameout(&(rel->rd_rel->relname));
	rte->refname = rte->relname;
1536
	rte->relid = RelationGetRelid(rel);
1537 1538 1539 1540 1541 1542 1543 1544 1545
	rte->inh = false;
	rte->inFromCl = true;
	rtlist = lcons(rte, NIL);
	econtext->ecxt_scantuple = slot;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = rel;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
	econtext->ecxt_param_list_info = NULL;		/* param list info */
V
Vadim B. Mikheev 已提交
1546
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1547 1548
	econtext->ecxt_range_table = rtlist;		/* range table */

1549 1550 1551
	if (estate->es_result_relation_constraints == NULL)
	{
		estate->es_result_relation_constraints =
B
Bruce Momjian 已提交
1552
			(List **) palloc(ncheck * sizeof(List *));
1553 1554 1555 1556 1557 1558 1559 1560

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

1561 1562
	for (i = 0; i < ncheck; i++)
	{
1563
		qual = estate->es_result_relation_constraints[i];
1564 1565 1566 1567

		res = ExecQual(qual, econtext);

		if (!res)
1568
			return check[i].ccname;
1569 1570 1571 1572 1573 1574 1575 1576
	}

	pfree(slot);
	pfree(rte->relname);
	pfree(rte);
	pfree(rtlist);
	pfree(econtext);

1577
	return (char *) NULL;
1578

V
Vadim B. Mikheev 已提交
1579 1580
}

1581
void
1582
ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
V
Vadim B. Mikheev 已提交
1583
{
1584 1585 1586 1587

	Assert(rel->rd_att->constr);

	if (rel->rd_att->constr->has_not_null)
V
Vadim B. Mikheev 已提交
1588
	{
1589
		int			attrChk;
1590 1591 1592 1593

		for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
		{
			if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
1594
				elog(ERROR, "%s: Fail to add null value in not null attribute %s",
1595 1596 1597 1598 1599 1600
				  caller, rel->rd_att->attrs[attrChk - 1]->attname.data);
		}
	}

	if (rel->rd_att->constr->num_check > 0)
	{
1601
		char	   *failed;
1602

1603
		if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL)
1604
			elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed);
1605 1606
	}

1607
	return;
V
Vadim B. Mikheev 已提交
1608
}
1609

B
Bruce Momjian 已提交
1610
TupleTableSlot *
1611 1612
EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
{
B
Bruce Momjian 已提交
1613 1614 1615 1616 1617 1618 1619
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	evalPlanQual *oldepq;
	EState	   *epqstate = NULL;
	Relation	relation;
	Buffer		buffer;
	HeapTupleData tuple;
	bool		endNode = true;
1620 1621 1622 1623 1624

	Assert(rti != 0);

	if (epq != NULL && epq->rti == 0)
	{
B
Bruce Momjian 已提交
1625 1626
		Assert(!(estate->es_useEvalPlan) &&
			   epq->estate.es_evalPlanQual == NULL);
1627 1628 1629 1630 1631 1632
		epq->rti = rti;
		endNode = false;
	}

	/*
	 * If this is request for another RTE - Ra, - then we have to check
B
Bruce Momjian 已提交
1633 1634 1635
	 * 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? -:))
1636
	 */
B
Bruce Momjian 已提交
1637
	if (epq != NULL && epq->rti != rti &&
1638 1639 1640 1641 1642 1643
		epq->estate.es_evTuple[rti - 1] != NULL)
	{
		do
		{
			/* pop previous PlanQual from the stack */
			epqstate = &(epq->estate);
B
Bruce Momjian 已提交
1644
			oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1645 1646 1647
			Assert(oldepq->rti != 0);
			/* stop execution */
			ExecEndNode(epq->plan, epq->plan);
1648
		    epqstate->es_tupleTable->next = 0;
1649 1650 1651 1652 1653 1654 1655 1656 1657
			pfree(epqstate->es_evTuple[epq->rti - 1]);
			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 已提交
1658
	/*
1659 1660 1661 1662 1663 1664
	 * 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 已提交
1665
		evalPlanQual *newepq = (epq != NULL) ? epq->free : NULL;
1666

1667
		if (newepq == NULL)		/* first call or freePQ stack is empty */
1668
		{
B
Bruce Momjian 已提交
1669
			newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual));
1670 1671 1672
			/* Init EState */
			epqstate = &(newepq->estate);
			memset(epqstate, 0, sizeof(EState));
B
Bruce Momjian 已提交
1673
			epqstate->type = T_EState;
1674 1675 1676 1677 1678 1679
			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 已提交
1680 1681 1682
					palloc(estate->es_origPlan->nParamExec *
						   sizeof(ParamExecData));
			epqstate->es_tupleTable =
1683 1684 1685 1686 1687
				ExecCreateTupleTable(estate->es_tupleTable->size);
			epqstate->es_refcount = estate->es_refcount;
			/* ... rest */
			newepq->plan = copyObject(estate->es_origPlan);
			newepq->free = NULL;
B
Bruce Momjian 已提交
1688
			epqstate->es_evTupleNull = (bool *)
1689 1690
				palloc(length(estate->es_range_table) * sizeof(bool));
			if (epq == NULL)	/* first call */
1691
			{
B
Bruce Momjian 已提交
1692
				epqstate->es_evTuple = (HeapTuple *)
1693
					palloc(length(estate->es_range_table) * sizeof(HeapTuple));
B
Bruce Momjian 已提交
1694 1695
				memset(epqstate->es_evTuple, 0,
					 length(estate->es_range_table) * sizeof(HeapTuple));
1696 1697 1698 1699 1700 1701 1702 1703
			}
			else
				epqstate->es_evTuple = epq->estate.es_evTuple;
		}
		else
			epqstate = &(newepq->estate);
		/* push current PQ to the stack */
		epqstate->es_evalPlanQual = (Pointer) epq;
1704 1705
		epq = newepq;
		estate->es_evalPlanQual = (Pointer) epq;
1706 1707 1708 1709 1710 1711 1712
		epq->rti = rti;
		endNode = false;
	}

	epqstate = &(epq->estate);

	/*
B
Bruce Momjian 已提交
1713 1714
	 * Ok - we're requested for the same RTE (-:)). I'm not sure about
	 * ability to use ExecReScan instead of ExecInitNode, so...
1715 1716
	 */
	if (endNode)
1717
	{
1718
		ExecEndNode(epq->plan, epq->plan);
1719 1720
	    epqstate->es_tupleTable->next = 0;
	}
1721 1722 1723 1724 1725 1726 1727 1728 1729

	/* free old RTE' tuple */
	if (epqstate->es_evTuple[epq->rti - 1] != NULL)
	{
		pfree(epqstate->es_evTuple[epq->rti - 1]);
		epqstate->es_evTuple[epq->rti - 1] = NULL;
	}

	/* ** fetch tid tuple ** */
B
Bruce Momjian 已提交
1730
	if (estate->es_result_relation_info != NULL &&
1731 1732 1733 1734
		estate->es_result_relation_info->ri_RangeTableIndex == rti)
		relation = estate->es_result_relation_info->ri_RelationDesc;
	else
	{
B
Bruce Momjian 已提交
1735
		List	   *l;
1736

B
Bruce Momjian 已提交
1737
		foreach(l, estate->es_rowMark)
1738
		{
B
Bruce Momjian 已提交
1739
			if (((execRowMark *) lfirst(l))->rti == rti)
1740 1741
				break;
		}
B
Bruce Momjian 已提交
1742
		relation = ((execRowMark *) lfirst(l))->relation;
1743 1744
	}
	tuple.t_self = *tid;
B
Bruce Momjian 已提交
1745
	for (;;)
1746 1747 1748 1749 1750 1751 1752
	{
		heap_fetch(relation, SnapshotDirty, &tuple, &buffer);
		if (tuple.t_data != NULL)
		{
			TransactionId xwait = SnapshotDirty->xmax;

			if (TransactionIdIsValid(SnapshotDirty->xmin))
1753 1754 1755 1756 1757
			{
				elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!");
				Assert(!TransactionIdIsValid(SnapshotDirty->xmin));
				elog(ERROR, "Aborting this transaction");
			}
B
Bruce Momjian 已提交
1758

1759
			/*
B
Bruce Momjian 已提交
1760 1761
			 * If tuple is being updated by other transaction then we have
			 * to wait for its commit/abort.
1762 1763 1764 1765 1766 1767 1768
			 */
			if (TransactionIdIsValid(xwait))
			{
				ReleaseBuffer(buffer);
				XactLockTableWait(xwait);
				continue;
			}
B
Bruce Momjian 已提交
1769

1770 1771 1772
			/*
			 * Nice! We got tuple - now copy it.
			 */
1773 1774
			if (epqstate->es_evTuple[epq->rti - 1] != NULL)
				pfree(epqstate->es_evTuple[epq->rti - 1]);
1775 1776 1777 1778
			epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple);
			ReleaseBuffer(buffer);
			break;
		}
B
Bruce Momjian 已提交
1779

1780 1781
		/*
		 * Ops! Invalid tuple. Have to check is it updated or deleted.
B
Bruce Momjian 已提交
1782 1783
		 * Note that it's possible to get invalid SnapshotDirty->tid if
		 * tuple updated by this transaction. Have we to check this ?
1784
		 */
B
Bruce Momjian 已提交
1785
		if (ItemPointerIsValid(&(SnapshotDirty->tid)) &&
1786 1787 1788 1789 1790
			!(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid))))
		{
			tuple.t_self = SnapshotDirty->tid;	/* updated ... */
			continue;
		}
B
Bruce Momjian 已提交
1791

1792
		/*
B
Bruce Momjian 已提交
1793 1794
		 * Deleted or updated by this transaction. Do not (re-)start
		 * execution of this PQ. Continue previous PQ.
1795
		 */
B
Bruce Momjian 已提交
1796
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806
		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
1807 1808 1809 1810
		{									
			epq->rti = 0;					/* this is the first (oldest) */
			estate->es_useEvalPlan = false;	/* PQ - mark as free and      */
			return (NULL);					/* continue Query execution   */
1811 1812 1813 1814
		}
	}

	if (estate->es_origPlan->nParamExec > 0)
B
Bruce Momjian 已提交
1815 1816 1817 1818
		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));
1819
    Assert(epqstate->es_tupleTable->next == 0);
1820 1821 1822
	ExecInitNode(epq->plan, epqstate, NULL);

	/*
B
Bruce Momjian 已提交
1823 1824
	 * For UPDATE/DELETE we have to return tid of actual row we're
	 * executing PQ for.
1825 1826 1827 1828 1829 1830
	 */
	*tid = tuple.t_self;

	return (EvalPlanQualNext(estate));
}

B
Bruce Momjian 已提交
1831
static TupleTableSlot *
1832 1833
EvalPlanQualNext(EState *estate)
{
B
Bruce Momjian 已提交
1834 1835 1836 1837
	evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual;
	EState	   *epqstate = &(epq->estate);
	evalPlanQual *oldepq;
	TupleTableSlot *slot;
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849

	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);
1850
	    epqstate->es_tupleTable->next = 0;
1851 1852 1853
		pfree(epqstate->es_evTuple[epq->rti - 1]);
		epqstate->es_evTuple[epq->rti - 1] = NULL;
		/* pop old PQ from the stack */
B
Bruce Momjian 已提交
1854 1855
		oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
		if (oldepq == (evalPlanQual *) NULL)
1856 1857 1858 1859
		{
			epq->rti = 0;					/* this is the first (oldest) */
			estate->es_useEvalPlan = false;	/* PQ - mark as free and	  */
			return (NULL);					/* continue Query execution   */
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
		}
		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);
}