nodeSubplan.c 14.2 KB
Newer Older
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1 2
/*-------------------------------------------------------------------------
 *
3
 * nodeSubplan.c
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
4 5
 *	  routines to support subselects
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.35 2002/12/05 15:50:33 tgl Exp $
11
 *
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
12 13 14 15
 *-------------------------------------------------------------------------
 */
/*
 *	 INTERFACE ROUTINES
16
 *		ExecSubPlan  - process a subselect
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
17
 *		ExecInitSubPlan - initialize a subselect
18
 *		ExecEndSubPlan	- shut down a subselect
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
19 20 21 22 23 24
 */
#include "postgres.h"

#include "access/heapam.h"
#include "executor/executor.h"
#include "executor/nodeSubplan.h"
Bruce Momjian's avatar
Bruce Momjian committed
25
#include "tcop/pquery.h"
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
26

27

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
28 29 30 31 32
/* ----------------------------------------------------------------
 *		ExecSubPlan(node)
 * ----------------------------------------------------------------
 */
Datum
33 34
ExecSubPlan(SubPlanState *node, List *pvar,
			ExprContext *econtext, bool *isNull)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
35
{
36 37 38
	PlanState  *planstate = node->planstate;
	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
	SubLink    *sublink = subplan->sublink;
39
	SubLinkType subLinkType = sublink->subLinkType;
40
	bool		useor = sublink->useor;
41
	MemoryContext oldcontext;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
42
	TupleTableSlot *slot;
43
	Datum		result;
44
	bool		found = false;	/* TRUE if got at least one subplan tuple */
45
	List	   *lst;
46

47 48 49 50 51 52
	/*
	 * We are probably in a short-lived expression-evaluation context.
	 * Switch to longer-lived per-query context.
	 */
	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);

53
	if (subplan->setParam != NIL)
54 55
		elog(ERROR, "ExecSubPlan: can't set parent params from subquery");

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
56 57 58
	/*
	 * Set Params of this plan from parent plan correlation Vars
	 */
59
	if (subplan->parParam != NIL)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
60
	{
61
		foreach(lst, subplan->parParam)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
62
		{
63
			ParamExecData *prm;
64

65
			prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
66
			Assert(pvar != NIL);
67 68 69
			prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
												   econtext,
												   &(prm->isnull),
70
												   NULL);
71
			pvar = lnext(pvar);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
72
		}
73 74
		planstate->chgParam = nconc(planstate->chgParam,
									listCopy(subplan->parParam));
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
75
	}
76
	Assert(pvar == NIL);
77

78
	ExecReScan(planstate, NULL);
79

80
	/*
81 82
	 * For all sublink types except EXPR_SUBLINK, the result is boolean as
	 * are the results of the combining operators.	We combine results
83 84 85
	 * within a tuple (if there are multiple columns) using OR semantics
	 * if "useor" is true, AND semantics if not.  We then combine results
	 * across tuples (if the subplan produces more than one) using OR
86 87 88
	 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
	 * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
	 * NULL results from the combining operators are handled according to
89
	 * the usual SQL semantics for OR and AND.	The result for no input
90 91
	 * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
	 * MULTIEXPR_SUBLINK.
92
	 *
93
	 * For EXPR_SUBLINK we require the subplan to produce no more than one
94
	 * tuple, else an error is raised.	If zero tuples are produced, we
95 96
	 * return NULL.  Assuming we get a tuple, we just return its first
	 * column (there can be only one non-junk column in this case).
97
	 */
98
	result = BoolGetDatum(subLinkType == ALL_SUBLINK);
99
	*isNull = false;
100

101
	for (slot = ExecProcNode(planstate);
102
		 !TupIsNull(slot);
103
		 slot = ExecProcNode(planstate))
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
104 105 106
	{
		HeapTuple	tup = slot->val;
		TupleDesc	tdesc = slot->ttc_tupleDescriptor;
107
		Datum		rowresult = BoolGetDatum(!useor);
108 109
		bool		rownull = false;
		int			col = 1;
110

111
		if (subLinkType == EXISTS_SUBLINK)
112 113 114 115 116
		{
			found = true;
			result = BoolGetDatum(true);
			break;
		}
117

118 119 120 121
		if (subLinkType == EXPR_SUBLINK)
		{
			/* cannot allow multiple input tuples for EXPR sublink */
			if (found)
122
				elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
123
			found = true;
124

125
			/*
126 127 128 129 130 131
			 * We need to copy the subplan's tuple in case the result is
			 * of pass-by-ref type --- our return value will point into
			 * this copied tuple!  Can't use the subplan's instance of the
			 * tuple since it won't still be valid after next
			 * ExecProcNode() call. node->curTuple keeps track of the
			 * copied tuple for eventual freeing.
132
			 */
133
			tup = heap_copytuple(tup);
134
			if (node->curTuple)
135
				heap_freetuple(node->curTuple);
136
			node->curTuple = tup;
137 138 139 140 141 142 143
			result = heap_getattr(tup, col, tdesc, isNull);
			/* keep scanning subplan to make sure there's only one tuple */
			continue;
		}

		/* cannot allow multiple input tuples for MULTIEXPR sublink either */
		if (subLinkType == MULTIEXPR_SUBLINK && found)
144
			elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
145

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
146
		found = true;
147

148 149
		/*
		 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
150 151
		 * operators for columns of tuple.
		 */
152
		foreach(lst, sublink->oper)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
153
		{
154
			Expr	   *expr = (Expr *) lfirst(lst);
155 156
			Param	   *prm = lsecond(expr->args);
			ParamExecData *prmdata;
157 158
			Datum		expresult;
			bool		expnull;
159

160
			/*
161
			 * The righthand side of the expression should be either a
162
			 * Param or a function call or RelabelType node taking a Param
163 164
			 * as arg (these nodes represent run-time type coercions
			 * inserted by the parser to get to the input type needed by
165 166 167 168 169
			 * the operator). Find the Param node and insert the actual
			 * righthand-side value into the param's econtext slot.
			 *
			 * XXX possible improvement: could make a list of the ParamIDs
			 * at startup time, instead of repeating this check at each row.
170
			 */
171
			if (!IsA(prm, Param))
172
			{
173
				switch (nodeTag(prm))
174 175
				{
					case T_Expr:
176
						prm = lfirst(((Expr *) prm)->args);
177 178
						break;
					case T_RelabelType:
179
						prm = (Param *) (((RelabelType *) prm)->arg);
180 181 182 183 184
						break;
					default:
						/* will fail below */
						break;
				}
185
				if (!IsA(prm, Param))
186
					elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
187
			}
188 189 190 191 192
			Assert(prm->paramkind == PARAM_EXEC);
			prmdata = &(econtext->ecxt_param_exec_vals[prm->paramid]);
			Assert(prmdata->execPlan == NULL);
			prmdata->value = heap_getattr(tup, col, tdesc,
										  &(prmdata->isnull));
193

194
			/*
195
			 * Now we can eval the combining operator for this column.
196
			 */
197
			expresult = ExecEvalExprSwitchContext((Node *) expr, econtext,
198
												  &expnull, NULL);
199

200 201 202 203
			/*
			 * Combine the result into the row result as appropriate.
			 */
			if (col == 1)
204
			{
205 206
				rowresult = expresult;
				rownull = expnull;
207
			}
208
			else if (useor)
209
			{
210 211 212
				/* combine within row per OR semantics */
				if (expnull)
					rownull = true;
213
				else if (DatumGetBool(expresult))
214
				{
215
					rowresult = BoolGetDatum(true);
216 217 218
					rownull = false;
					break;		/* needn't look at any more columns */
				}
219
			}
220 221 222 223 224
			else
			{
				/* combine within row per AND semantics */
				if (expnull)
					rownull = true;
225
				else if (!DatumGetBool(expresult))
226
				{
227
					rowresult = BoolGetDatum(false);
228 229 230 231 232
					rownull = false;
					break;		/* needn't look at any more columns */
				}
			}
			col++;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
233
		}
234

235 236 237 238 239
		if (subLinkType == ANY_SUBLINK)
		{
			/* combine across rows per OR semantics */
			if (rownull)
				*isNull = true;
240
			else if (DatumGetBool(rowresult))
241
			{
242
				result = BoolGetDatum(true);
243 244 245 246 247 248 249 250 251
				*isNull = false;
				break;			/* needn't look at any more rows */
			}
		}
		else if (subLinkType == ALL_SUBLINK)
		{
			/* combine across rows per AND semantics */
			if (rownull)
				*isNull = true;
252
			else if (!DatumGetBool(rowresult))
253
			{
254
				result = BoolGetDatum(false);
255 256 257 258 259 260
				*isNull = false;
				break;			/* needn't look at any more rows */
			}
		}
		else
		{
261
			/* must be MULTIEXPR_SUBLINK */
262 263 264
			result = rowresult;
			*isNull = rownull;
		}
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
265
	}
266

267 268
	if (!found)
	{
269 270
		/*
		 * deal with empty subplan result.	result/isNull were previously
271 272
		 * initialized correctly for all sublink types except EXPR and
		 * MULTIEXPR; for those, return NULL.
273
		 */
274
		if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
275
		{
276
			result = (Datum) 0;
277
			*isNull = true;
278
		}
279
	}
280

281 282
	MemoryContextSwitchTo(oldcontext);

283
	return result;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
284 285 286 287 288 289
}

/* ----------------------------------------------------------------
 *		ExecInitSubPlan
 * ----------------------------------------------------------------
 */
290 291
SubPlanState *
ExecInitSubPlan(SubPlan *node, EState *estate)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
292
{
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	SubPlanState *subplanstate;
	EState	   *sp_estate;

	/*
	 * Do access checking on the rangetable entries in the subquery.
	 * Here, we assume the subquery is a SELECT.
	 */
	ExecCheckRTPerms(node->rtable, CMD_SELECT);

	/*
	 * create state structure
	 */
	subplanstate = makeNode(SubPlanState);
	subplanstate->ps.plan = (Plan *) node;
	subplanstate->ps.state = estate;

	subplanstate->needShutdown = false;
	subplanstate->curTuple = NULL;

	/* XXX temporary hack */
	node->pstate = subplanstate;

	/*
	 * create an EState for the subplan
	 */
	sp_estate = CreateExecutorState();
319

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
320 321 322
	sp_estate->es_range_table = node->rtable;
	sp_estate->es_param_list_info = estate->es_param_list_info;
	sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
323 324
	sp_estate->es_tupleTable =
		ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
325
	sp_estate->es_snapshot = estate->es_snapshot;
326
	sp_estate->es_instrument = estate->es_instrument;
327

328 329 330 331
	/*
	 * Start up the subplan
	 */
	subplanstate->planstate = ExecInitNode(node->plan, sp_estate);
332

333
	subplanstate->needShutdown = true;	/* now we need to shutdown the subplan */
334

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
335
	/*
336 337
	 * If this plan is un-correlated or undirect correlated one and want
	 * to set params for parent plan then prepare parameters.
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
338
	 */
339
	if (node->setParam != NIL)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
340
	{
341 342 343
		List	   *lst;

		foreach(lst, node->setParam)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
344
		{
345 346
			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);

347
			prm->execPlan = subplanstate;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
348
		}
349

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
350 351
		/*
		 * Note that in the case of un-correlated subqueries we don't care
352 353
		 * about setting parent->chgParam here: indices take care about
		 * it, for others - it doesn't matter...
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
354 355
		 */
	}
356

357
	return subplanstate;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
358 359 360 361 362
}

/* ----------------------------------------------------------------
 *		ExecSetParamPlan
 *
363 364 365 366
 *		Executes an InitPlan subplan and sets its output parameters.
 *
 * This is called from ExecEvalParam() when the value of a PARAM_EXEC
 * parameter is requested and the param's execPlan field is set (indicating
367
 * that the param has not yet been evaluated).	This allows lazy evaluation
368 369 370
 * of initplans: we don't run the subplan until/unless we need its output.
 * Note that this routine MUST clear the execPlan fields of the plan's
 * output parameters after evaluating them!
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
371 372 373
 * ----------------------------------------------------------------
 */
void
374
ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
375
{
376 377 378 379
	PlanState  *planstate = node->planstate;
	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
	SubLink    *sublink = subplan->sublink;
	EState	   *estate = node->ps.state;
380
	MemoryContext oldcontext;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
381
	TupleTableSlot *slot;
382 383 384
	List	   *lst;
	bool		found = false;

385 386 387 388 389 390
	/*
	 * We are probably in a short-lived expression-evaluation context.
	 * Switch to longer-lived per-query context.
	 */
	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);

391 392 393 394
	if (sublink->subLinkType == ANY_SUBLINK ||
		sublink->subLinkType == ALL_SUBLINK)
		elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");

395 396
	if (planstate->chgParam != NULL)
		ExecReScan(planstate, NULL);
397

398
	for (slot = ExecProcNode(planstate);
399
		 !TupIsNull(slot);
400
		 slot = ExecProcNode(planstate))
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
401 402 403 404
	{
		HeapTuple	tup = slot->val;
		TupleDesc	tdesc = slot->ttc_tupleDescriptor;
		int			i = 1;
405 406

		if (sublink->subLinkType == EXISTS_SUBLINK)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
407
		{
408
			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
409

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
410
			prm->execPlan = NULL;
411
			prm->value = BoolGetDatum(true);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
412
			prm->isnull = false;
413
			found = true;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
414 415
			break;
		}
416

417 418 419
		if (found &&
			(sublink->subLinkType == EXPR_SUBLINK ||
			 sublink->subLinkType == MULTIEXPR_SUBLINK))
Tom Lane's avatar
Tom Lane committed
420
			elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
421 422 423

		found = true;

424
		/*
425
		 * We need to copy the subplan's tuple in case any of the params
426 427 428
		 * are pass-by-ref type --- the pointers stored in the param
		 * structs will point at this copied tuple!  node->curTuple keeps
		 * track of the copied tuple for eventual freeing.
429
		 */
430
		tup = heap_copytuple(tup);
431
		if (node->curTuple)
432
			heap_freetuple(node->curTuple);
433
		node->curTuple = tup;
434

435
		foreach(lst, subplan->setParam)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
436
		{
437
			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
438

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
439
			prm->execPlan = NULL;
440
			prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
441 442 443
			i++;
		}
	}
444 445

	if (!found)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
446
	{
447
		if (sublink->subLinkType == EXISTS_SUBLINK)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
448
		{
449
			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
450

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
451
			prm->execPlan = NULL;
452
			prm->value = BoolGetDatum(false);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
453 454 455 456
			prm->isnull = false;
		}
		else
		{
457
			foreach(lst, subplan->setParam)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
458
			{
459
				ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
460

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
461
				prm->execPlan = NULL;
462
				prm->value = (Datum) 0;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
463 464 465 466
				prm->isnull = true;
			}
		}
	}
467

468
	if (planstate->plan->extParam == NULL) /* un-correlated ... */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
469
	{
470
		ExecEndNode(planstate);
471
		node->needShutdown = false;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
472
	}
473 474

	MemoryContextSwitchTo(oldcontext);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
475 476 477 478 479 480 481
}

/* ----------------------------------------------------------------
 *		ExecEndSubPlan
 * ----------------------------------------------------------------
 */
void
482
ExecEndSubPlan(SubPlanState *node)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
483
{
484
	if (node->needShutdown)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
485
	{
486
		ExecEndNode(node->planstate);
487
		node->needShutdown = false;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
488
	}
489 490
	if (node->curTuple)
	{
491
		heap_freetuple(node->curTuple);
492 493
		node->curTuple = NULL;
	}
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
494 495
}

496
void
497
ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
498
{
499 500 501
	PlanState  *planstate = node->planstate;
	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
	EState	   *estate = node->ps.state;
502 503
	List	   *lst;

504
	if (subplan->parParam != NULL)
505
		elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
506
	if (subplan->setParam == NULL)
507
		elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
508
	if (planstate->plan->extParam == NULL)
509 510 511 512
		elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");

	/*
	 * Don't actual re-scan: ExecSetParamPlan does re-scan if
513
	 * subplan->plan->chgParam is not NULL... ExecReScan (planstate, NULL);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
514
	 */
515

516 517 518
	/*
	 * Mark this subplan's output parameters as needing recalculation
	 */
519
	foreach(lst, subplan->setParam)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
520
	{
521
		ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
522

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
523 524
		prm->execPlan = node;
	}
525

526
	parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
527
}