1 /*-------------------------------------------------------------------------
4 * routines to support subselects
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.39 2002/12/15 16:17:46 tgl Exp $
12 *-------------------------------------------------------------------------
16 * ExecSubPlan - process a subselect
17 * ExecInitSubPlan - initialize a subselect
18 * ExecEndSubPlan - shut down a subselect
22 #include "access/heapam.h"
23 #include "executor/executor.h"
24 #include "executor/nodeSubplan.h"
25 #include "tcop/pquery.h"
28 /* ----------------------------------------------------------------
30 * ----------------------------------------------------------------
33 ExecSubPlan(SubPlanState *node,
34 ExprContext *econtext,
37 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
38 PlanState *planstate = node->planstate;
39 SubLinkType subLinkType = subplan->subLinkType;
40 bool useor = subplan->useor;
41 MemoryContext oldcontext;
44 bool found = false; /* TRUE if got at least one subplan tuple */
49 * We are probably in a short-lived expression-evaluation context.
50 * Switch to the child plan's per-query context for manipulating its
51 * chgParam, calling ExecProcNode on it, etc.
53 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
55 if (subplan->setParam != NIL)
56 elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
59 * Set Params of this plan from parent plan correlation Vars
62 if (subplan->parParam != NIL)
64 foreach(lst, subplan->parParam)
68 prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
70 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
76 planstate->chgParam = nconc(planstate->chgParam,
77 listCopy(subplan->parParam));
81 ExecReScan(planstate, NULL);
84 * For all sublink types except EXPR_SUBLINK, the result is boolean as
85 * are the results of the combining operators. We combine results
86 * within a tuple (if there are multiple columns) using OR semantics
87 * if "useor" is true, AND semantics if not. We then combine results
88 * across tuples (if the subplan produces more than one) using OR
89 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
90 * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
91 * NULL results from the combining operators are handled according to
92 * the usual SQL semantics for OR and AND. The result for no input
93 * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
96 * For EXPR_SUBLINK we require the subplan to produce no more than one
97 * tuple, else an error is raised. If zero tuples are produced, we
98 * return NULL. Assuming we get a tuple, we just return its first
99 * column (there can be only one non-junk column in this case).
101 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
104 for (slot = ExecProcNode(planstate);
106 slot = ExecProcNode(planstate))
108 HeapTuple tup = slot->val;
109 TupleDesc tdesc = slot->ttc_tupleDescriptor;
110 Datum rowresult = BoolGetDatum(!useor);
111 bool rownull = false;
114 if (subLinkType == EXISTS_SUBLINK)
117 result = BoolGetDatum(true);
121 if (subLinkType == EXPR_SUBLINK)
123 /* cannot allow multiple input tuples for EXPR sublink */
125 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
129 * We need to copy the subplan's tuple in case the result is
130 * of pass-by-ref type --- our return value will point into
131 * this copied tuple! Can't use the subplan's instance of the
132 * tuple since it won't still be valid after next
133 * ExecProcNode() call. node->curTuple keeps track of the
134 * copied tuple for eventual freeing.
136 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
137 tup = heap_copytuple(tup);
139 heap_freetuple(node->curTuple);
140 node->curTuple = tup;
141 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
143 result = heap_getattr(tup, col, tdesc, isNull);
144 /* keep scanning subplan to make sure there's only one tuple */
148 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
149 if (subLinkType == MULTIEXPR_SUBLINK && found)
150 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
155 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
156 * operators for columns of tuple.
158 foreach(lst, node->oper)
160 ExprState *exprstate = (ExprState *) lfirst(lst);
161 OpExpr *expr = (OpExpr *) exprstate->expr;
162 Param *prm = lsecond(expr->args);
163 ParamExecData *prmdata;
168 * The righthand side of the expression should be either a
169 * Param or a function call or RelabelType node taking a Param
170 * as arg (these nodes represent run-time type coercions
171 * inserted by the parser to get to the input type needed by
172 * the operator). Find the Param node and insert the actual
173 * righthand-side value into the param's econtext slot.
175 * XXX possible improvement: could make a list of the ParamIDs
176 * at startup time, instead of repeating this check at each row.
178 if (!IsA(prm, Param))
180 switch (nodeTag(prm))
183 prm = lfirst(((FuncExpr *) prm)->args);
186 prm = (Param *) (((RelabelType *) prm)->arg);
189 /* will fail below */
192 if (!IsA(prm, Param))
193 elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
195 Assert(prm->paramkind == PARAM_EXEC);
196 prmdata = &(econtext->ecxt_param_exec_vals[prm->paramid]);
197 Assert(prmdata->execPlan == NULL);
198 prmdata->value = heap_getattr(tup, col, tdesc,
202 * Now we can eval the combining operator for this column.
204 expresult = ExecEvalExprSwitchContext(exprstate, econtext,
208 * Combine the result into the row result as appropriate.
212 rowresult = expresult;
217 /* combine within row per OR semantics */
220 else if (DatumGetBool(expresult))
222 rowresult = BoolGetDatum(true);
224 break; /* needn't look at any more columns */
229 /* combine within row per AND semantics */
232 else if (!DatumGetBool(expresult))
234 rowresult = BoolGetDatum(false);
236 break; /* needn't look at any more columns */
242 if (subLinkType == ANY_SUBLINK)
244 /* combine across rows per OR semantics */
247 else if (DatumGetBool(rowresult))
249 result = BoolGetDatum(true);
251 break; /* needn't look at any more rows */
254 else if (subLinkType == ALL_SUBLINK)
256 /* combine across rows per AND semantics */
259 else if (!DatumGetBool(rowresult))
261 result = BoolGetDatum(false);
263 break; /* needn't look at any more rows */
268 /* must be MULTIEXPR_SUBLINK */
277 * deal with empty subplan result. result/isNull were previously
278 * initialized correctly for all sublink types except EXPR and
279 * MULTIEXPR; for those, return NULL.
281 if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
288 MemoryContextSwitchTo(oldcontext);
293 /* ----------------------------------------------------------------
295 * ----------------------------------------------------------------
298 ExecInitSubPlan(SubPlanState *node, EState *estate)
300 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
302 MemoryContext oldcontext;
305 * Do access checking on the rangetable entries in the subquery.
306 * Here, we assume the subquery is a SELECT.
308 ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
311 * initialize my state
313 node->needShutdown = false;
314 node->curTuple = NULL;
317 * create an EState for the subplan
319 * The subquery needs its own EState because it has its own rangetable.
320 * It shares our Param ID space, however. XXX if rangetable access were
321 * done differently, the subquery could share our EState, which would
322 * eliminate some thrashing about in this module...
324 sp_estate = CreateExecutorState();
325 node->sub_estate = sp_estate;
327 oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
329 sp_estate->es_range_table = subplan->rtable;
330 sp_estate->es_param_list_info = estate->es_param_list_info;
331 sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
332 sp_estate->es_tupleTable =
333 ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
334 sp_estate->es_snapshot = estate->es_snapshot;
335 sp_estate->es_instrument = estate->es_instrument;
338 * Start up the subplan (this is a very cut-down form of InitPlan())
340 node->planstate = ExecInitNode(subplan->plan, sp_estate);
342 node->needShutdown = true; /* now we need to shutdown the subplan */
344 MemoryContextSwitchTo(oldcontext);
347 * If this plan is un-correlated or undirect correlated one and want
348 * to set params for parent plan then prepare parameters.
350 if (subplan->setParam != NIL)
354 foreach(lst, subplan->setParam)
356 ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
358 prm->execPlan = node;
362 * Note that in the case of un-correlated subqueries we don't care
363 * about setting parent->chgParam here: indices take care about
364 * it, for others - it doesn't matter...
369 /* ----------------------------------------------------------------
372 * Executes an InitPlan subplan and sets its output parameters.
374 * This is called from ExecEvalParam() when the value of a PARAM_EXEC
375 * parameter is requested and the param's execPlan field is set (indicating
376 * that the param has not yet been evaluated). This allows lazy evaluation
377 * of initplans: we don't run the subplan until/unless we need its output.
378 * Note that this routine MUST clear the execPlan fields of the plan's
379 * output parameters after evaluating them!
380 * ----------------------------------------------------------------
383 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
385 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
386 PlanState *planstate = node->planstate;
387 SubLinkType subLinkType = subplan->subLinkType;
388 MemoryContext oldcontext;
389 TupleTableSlot *slot;
394 * Must switch to child query's per-query memory context.
396 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
398 if (subLinkType == ANY_SUBLINK ||
399 subLinkType == ALL_SUBLINK)
400 elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
402 if (planstate->chgParam != NULL)
403 ExecReScan(planstate, NULL);
405 for (slot = ExecProcNode(planstate);
407 slot = ExecProcNode(planstate))
409 HeapTuple tup = slot->val;
410 TupleDesc tdesc = slot->ttc_tupleDescriptor;
413 if (subLinkType == EXISTS_SUBLINK)
415 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]);
417 prm->execPlan = NULL;
418 prm->value = BoolGetDatum(true);
425 (subLinkType == EXPR_SUBLINK ||
426 subLinkType == MULTIEXPR_SUBLINK))
427 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
432 * We need to copy the subplan's tuple into our own context,
433 * in case any of the params are pass-by-ref type --- the pointers
434 * stored in the param structs will point at this copied tuple!
435 * node->curTuple keeps track of the copied tuple for eventual
438 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
439 tup = heap_copytuple(tup);
441 heap_freetuple(node->curTuple);
442 node->curTuple = tup;
443 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
445 foreach(lst, subplan->setParam)
447 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
449 prm->execPlan = NULL;
450 prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
457 if (subLinkType == EXISTS_SUBLINK)
459 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]);
461 prm->execPlan = NULL;
462 prm->value = BoolGetDatum(false);
467 foreach(lst, subplan->setParam)
469 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
471 prm->execPlan = NULL;
472 prm->value = (Datum) 0;
478 if (planstate->plan->extParam == NULL) /* un-correlated ... */
480 ExecEndPlan(planstate, node->sub_estate);
481 /* mustn't free context while still in it... */
482 MemoryContextSwitchTo(oldcontext);
483 FreeExecutorState(node->sub_estate);
484 node->needShutdown = false;
487 MemoryContextSwitchTo(oldcontext);
490 /* ----------------------------------------------------------------
492 * ----------------------------------------------------------------
495 ExecEndSubPlan(SubPlanState *node)
497 if (node->needShutdown)
499 MemoryContext oldcontext;
501 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
502 ExecEndPlan(node->planstate, node->sub_estate);
503 MemoryContextSwitchTo(oldcontext);
504 FreeExecutorState(node->sub_estate);
505 node->needShutdown = false;
509 heap_freetuple(node->curTuple);
510 node->curTuple = NULL;
515 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
517 PlanState *planstate = node->planstate;
518 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
519 EState *estate = parent->state;
522 if (subplan->parParam != NULL)
523 elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
524 if (subplan->setParam == NULL)
525 elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
526 if (planstate->plan->extParam == NULL)
527 elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
530 * Don't actually re-scan: ExecSetParamPlan does it if needed.
534 * Mark this subplan's output parameters as needing recalculation
536 foreach(lst, subplan->setParam)
538 ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
540 prm->execPlan = node;
543 parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));