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.34 2002/11/26 03:01:57 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 /* ----------------------------------------------------------------
31 * ----------------------------------------------------------------
34 ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
36 Plan *plan = node->plan;
37 SubLink *sublink = node->sublink;
38 SubLinkType subLinkType = sublink->subLinkType;
39 bool useor = sublink->useor;
40 MemoryContext oldcontext;
43 bool found = false; /* TRUE if got at least one subplan tuple */
47 * We are probably in a short-lived expression-evaluation context.
48 * Switch to longer-lived per-query context.
50 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
52 if (node->setParam != NIL)
53 elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
56 * Set Params of this plan from parent plan correlation Vars
58 if (node->parParam != NIL)
60 foreach(lst, node->parParam)
64 prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
66 prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
72 plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
76 ExecReScan(plan, NULL, NULL);
79 * For all sublink types except EXPR_SUBLINK, the result is boolean as
80 * are the results of the combining operators. We combine results
81 * within a tuple (if there are multiple columns) using OR semantics
82 * if "useor" is true, AND semantics if not. We then combine results
83 * across tuples (if the subplan produces more than one) using OR
84 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
85 * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
86 * NULL results from the combining operators are handled according to
87 * the usual SQL semantics for OR and AND. The result for no input
88 * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
91 * For EXPR_SUBLINK we require the subplan to produce no more than one
92 * tuple, else an error is raised. If zero tuples are produced, we
93 * return NULL. Assuming we get a tuple, we just return its first
94 * column (there can be only one non-junk column in this case).
96 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
99 for (slot = ExecProcNode(plan, NULL);
101 slot = ExecProcNode(plan, NULL))
103 HeapTuple tup = slot->val;
104 TupleDesc tdesc = slot->ttc_tupleDescriptor;
105 Datum rowresult = BoolGetDatum(!useor);
106 bool rownull = false;
109 if (subLinkType == EXISTS_SUBLINK)
112 result = BoolGetDatum(true);
116 if (subLinkType == EXPR_SUBLINK)
118 /* cannot allow multiple input tuples for EXPR sublink */
120 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
124 * We need to copy the subplan's tuple in case the result is
125 * of pass-by-ref type --- our return value will point into
126 * this copied tuple! Can't use the subplan's instance of the
127 * tuple since it won't still be valid after next
128 * ExecProcNode() call. node->curTuple keeps track of the
129 * copied tuple for eventual freeing.
131 tup = heap_copytuple(tup);
133 heap_freetuple(node->curTuple);
134 node->curTuple = tup;
135 result = heap_getattr(tup, col, tdesc, isNull);
136 /* keep scanning subplan to make sure there's only one tuple */
140 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
141 if (subLinkType == MULTIEXPR_SUBLINK && found)
142 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
147 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
148 * operators for columns of tuple.
150 foreach(lst, sublink->oper)
152 Expr *expr = (Expr *) lfirst(lst);
153 Param *prm = lsecond(expr->args);
154 ParamExecData *prmdata;
159 * The righthand side of the expression should be either a
160 * Param or a function call or RelabelType node taking a Param
161 * as arg (these nodes represent run-time type coercions
162 * inserted by the parser to get to the input type needed by
163 * the operator). Find the Param node and insert the actual
164 * righthand-side value into the param's econtext slot.
166 * XXX possible improvement: could make a list of the ParamIDs
167 * at startup time, instead of repeating this check at each row.
169 if (!IsA(prm, Param))
171 switch (nodeTag(prm))
174 prm = lfirst(((Expr *) prm)->args);
177 prm = (Param *) (((RelabelType *) prm)->arg);
180 /* will fail below */
183 if (!IsA(prm, Param))
184 elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
186 Assert(prm->paramkind == PARAM_EXEC);
187 prmdata = &(econtext->ecxt_param_exec_vals[prm->paramid]);
188 Assert(prmdata->execPlan == NULL);
189 prmdata->value = heap_getattr(tup, col, tdesc,
193 * Now we can eval the combining operator for this column.
195 expresult = ExecEvalExprSwitchContext((Node *) expr, econtext,
199 * Combine the result into the row result as appropriate.
203 rowresult = expresult;
208 /* combine within row per OR semantics */
211 else if (DatumGetBool(expresult))
213 rowresult = BoolGetDatum(true);
215 break; /* needn't look at any more columns */
220 /* combine within row per AND semantics */
223 else if (!DatumGetBool(expresult))
225 rowresult = BoolGetDatum(false);
227 break; /* needn't look at any more columns */
233 if (subLinkType == ANY_SUBLINK)
235 /* combine across rows per OR semantics */
238 else if (DatumGetBool(rowresult))
240 result = BoolGetDatum(true);
242 break; /* needn't look at any more rows */
245 else if (subLinkType == ALL_SUBLINK)
247 /* combine across rows per AND semantics */
250 else if (!DatumGetBool(rowresult))
252 result = BoolGetDatum(false);
254 break; /* needn't look at any more rows */
259 /* must be MULTIEXPR_SUBLINK */
268 * deal with empty subplan result. result/isNull were previously
269 * initialized correctly for all sublink types except EXPR and
270 * MULTIEXPR; for those, return NULL.
272 if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
279 MemoryContextSwitchTo(oldcontext);
284 /* ----------------------------------------------------------------
287 * ----------------------------------------------------------------
290 ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
292 EState *sp_estate = CreateExecutorState();
294 sp_estate->es_range_table = node->rtable;
295 sp_estate->es_param_list_info = estate->es_param_list_info;
296 sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
297 sp_estate->es_tupleTable =
298 ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
299 sp_estate->es_snapshot = estate->es_snapshot;
301 node->needShutdown = false;
302 node->curTuple = NULL;
304 if (!ExecInitNode(node->plan, sp_estate, parent))
307 node->needShutdown = true; /* now we need to shutdown the subplan */
310 * If this plan is un-correlated or undirect correlated one and want
311 * to set params for parent plan then prepare parameters.
313 if (node->setParam != NIL)
317 foreach(lst, node->setParam)
319 ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
321 prm->execPlan = node;
325 * Note that in the case of un-correlated subqueries we don't care
326 * about setting parent->chgParam here: indices take care about
327 * it, for others - it doesn't matter...
334 /* ----------------------------------------------------------------
337 * Executes an InitPlan subplan and sets its output parameters.
339 * This is called from ExecEvalParam() when the value of a PARAM_EXEC
340 * parameter is requested and the param's execPlan field is set (indicating
341 * that the param has not yet been evaluated). This allows lazy evaluation
342 * of initplans: we don't run the subplan until/unless we need its output.
343 * Note that this routine MUST clear the execPlan fields of the plan's
344 * output parameters after evaluating them!
345 * ----------------------------------------------------------------
348 ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
350 Plan *plan = node->plan;
351 SubLink *sublink = node->sublink;
352 MemoryContext oldcontext;
353 TupleTableSlot *slot;
358 * We are probably in a short-lived expression-evaluation context.
359 * Switch to longer-lived per-query context.
361 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
363 if (sublink->subLinkType == ANY_SUBLINK ||
364 sublink->subLinkType == ALL_SUBLINK)
365 elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
367 if (plan->chgParam != NULL)
368 ExecReScan(plan, NULL, NULL);
370 for (slot = ExecProcNode(plan, NULL);
372 slot = ExecProcNode(plan, NULL))
374 HeapTuple tup = slot->val;
375 TupleDesc tdesc = slot->ttc_tupleDescriptor;
378 if (sublink->subLinkType == EXISTS_SUBLINK)
380 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
382 prm->execPlan = NULL;
383 prm->value = BoolGetDatum(true);
390 (sublink->subLinkType == EXPR_SUBLINK ||
391 sublink->subLinkType == MULTIEXPR_SUBLINK))
392 elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
397 * We need to copy the subplan's tuple in case any of the params
398 * are pass-by-ref type --- the pointers stored in the param
399 * structs will point at this copied tuple! node->curTuple keeps
400 * track of the copied tuple for eventual freeing.
402 tup = heap_copytuple(tup);
404 heap_freetuple(node->curTuple);
405 node->curTuple = tup;
407 foreach(lst, node->setParam)
409 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
411 prm->execPlan = NULL;
412 prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
419 if (sublink->subLinkType == EXISTS_SUBLINK)
421 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
423 prm->execPlan = NULL;
424 prm->value = BoolGetDatum(false);
429 foreach(lst, node->setParam)
431 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
433 prm->execPlan = NULL;
434 prm->value = (Datum) 0;
440 if (plan->extParam == NULL) /* un-correlated ... */
442 ExecEndNode(plan, NULL);
443 node->needShutdown = false;
446 MemoryContextSwitchTo(oldcontext);
449 /* ----------------------------------------------------------------
451 * ----------------------------------------------------------------
454 ExecEndSubPlan(SubPlan *node)
456 if (node->needShutdown)
458 ExecEndNode(node->plan, NULL);
459 node->needShutdown = false;
463 heap_freetuple(node->curTuple);
464 node->curTuple = NULL;
469 ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
471 Plan *plan = node->plan;
474 if (node->parParam != NULL)
475 elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
476 if (node->setParam == NULL)
477 elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
478 if (plan->extParam == NULL)
479 elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
482 * Don't actual re-scan: ExecSetParamPlan does re-scan if
483 * node->plan->chgParam is not NULL... ExecReScan (plan, NULL, NULL);
487 * Mark this subplan's output parameters as needing recalculation
489 foreach(lst, node->setParam)
491 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
493 prm->execPlan = node;
496 parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));