1 /*-------------------------------------------------------------------------
4 * routines to support subselects
6 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.18 1999/12/16 22:19:44 wieck Exp $
11 *-------------------------------------------------------------------------
15 * ExecSubPlan - process a subselect
16 * ExecInitSubPlan - initialize a subselect
17 * ExecEndSubPlan - shut down a subselect
21 #include "access/heapam.h"
22 #include "executor/executor.h"
23 #include "executor/nodeSubplan.h"
24 #include "tcop/pquery.h"
26 /* should be exported by execMain.c */
27 extern void ExecCheckPerms(CmdType op, int resRel, List *rtable, Query *q);
29 /* ----------------------------------------------------------------
32 * ----------------------------------------------------------------
35 ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
37 Plan *plan = node->plan;
38 SubLink *sublink = node->sublink;
39 SubLinkType subLinkType = sublink->subLinkType;
40 bool useor = sublink->useor;
43 bool found = false; /* TRUE if got at least one subplan tuple */
46 if (node->setParam != NIL)
47 elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
50 * Set Params of this plan from parent plan correlation Vars
52 if (node->parParam != NIL)
54 foreach(lst, node->parParam)
56 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
59 prm->value = ExecEvalExpr((Node *) lfirst(pvar),
61 &(prm->isnull), NULL);
64 plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
68 ExecReScan(plan, (ExprContext *) NULL, plan);
71 * For all sublink types except EXPR_SUBLINK, the result is boolean
72 * as are the results of the combining operators. We combine results
73 * within a tuple (if there are multiple columns) using OR semantics
74 * if "useor" is true, AND semantics if not. We then combine results
75 * across tuples (if the subplan produces more than one) using OR
76 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
77 * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
78 * NULL results from the combining operators are handled according to
79 * the usual SQL semantics for OR and AND. The result for no input
80 * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
83 * For EXPR_SUBLINK we require the subplan to produce no more than one
84 * tuple, else an error is raised. If zero tuples are produced, we
85 * return NULL. Assuming we get a tuple, we just return its first
86 * column (there can be only one non-junk column in this case).
88 result = (Datum) (subLinkType == ALL_SUBLINK ? true : false);
91 for (slot = ExecProcNode(plan, plan);
93 slot = ExecProcNode(plan, plan))
95 HeapTuple tup = slot->val;
96 TupleDesc tdesc = slot->ttc_tupleDescriptor;
97 Datum rowresult = (Datum) (useor ? false : true);
101 if (subLinkType == EXISTS_SUBLINK)
104 if (subLinkType == EXPR_SUBLINK)
106 /* cannot allow multiple input tuples for EXPR sublink */
108 elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
111 * We need to copy the subplan's tuple in case the result is of
112 * pass-by-ref type --- our return value will point into this
113 * copied tuple! Can't use the subplan's instance of the tuple
114 * since it won't still be valid after next ExecProcNode() call.
115 * node->curTuple keeps track of the copied tuple for eventual
118 tup = heap_copytuple(tup);
120 heap_freetuple(node->curTuple);
121 node->curTuple = tup;
122 result = heap_getattr(tup, col, tdesc, isNull);
123 /* keep scanning subplan to make sure there's only one tuple */
127 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
128 if (subLinkType == MULTIEXPR_SUBLINK && found)
129 elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
133 /* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
134 * operators for columns of tuple.
136 foreach(lst, sublink->oper)
138 Expr *expr = (Expr *) lfirst(lst);
139 Const *con = lsecond(expr->args);
144 * The righthand side of the expression should be either a Const
145 * or a function call taking a Const as arg (the function would
146 * be a run-time type coercion inserted by the parser to get to
147 * the input type needed by the operator). Find the Const node
148 * and insert the actual righthand side value into it.
150 if (! IsA(con, Const))
152 Assert(IsA(con, Expr));
153 con = lfirst(((Expr *) con)->args);
154 Assert(IsA(con, Const));
156 con->constvalue = heap_getattr(tup, col, tdesc,
157 &(con->constisnull));
159 * Now we can eval the combining operator for this column.
161 expresult = ExecEvalExpr((Node *) expr, econtext, &expnull,
164 * Combine the result into the row result as appropriate.
168 rowresult = expresult;
173 /* combine within row per OR semantics */
176 else if (DatumGetInt32(expresult) != 0)
178 rowresult = (Datum) true;
180 break; /* needn't look at any more columns */
185 /* combine within row per AND semantics */
188 else if (DatumGetInt32(expresult) == 0)
190 rowresult = (Datum) false;
192 break; /* needn't look at any more columns */
198 if (subLinkType == ANY_SUBLINK)
200 /* combine across rows per OR semantics */
203 else if (DatumGetInt32(rowresult) != 0)
205 result = (Datum) true;
207 break; /* needn't look at any more rows */
210 else if (subLinkType == ALL_SUBLINK)
212 /* combine across rows per AND semantics */
215 else if (DatumGetInt32(rowresult) == 0)
217 result = (Datum) false;
219 break; /* needn't look at any more rows */
224 /* must be MULTIEXPR_SUBLINK */
232 /* deal with empty subplan result. result/isNull were previously
233 * initialized correctly for all sublink types except EXPR and
234 * MULTIEXPR; for those, return NULL.
236 if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
238 result = (Datum) false;
246 /* ----------------------------------------------------------------
249 * ----------------------------------------------------------------
252 ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
254 EState *sp_estate = CreateExecutorState();
256 ExecCheckPerms(CMD_SELECT, 0, node->rtable, (Query *) NULL);
258 sp_estate->es_range_table = node->rtable;
259 sp_estate->es_param_list_info = estate->es_param_list_info;
260 sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
261 sp_estate->es_tupleTable =
262 ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
263 sp_estate->es_snapshot = estate->es_snapshot;
265 node->shutdown = false;
266 node->curTuple = NULL;
268 if (!ExecInitNode(node->plan, sp_estate, NULL))
271 node->shutdown = true; /* now we need to shutdown the subplan */
274 * If this plan is un-correlated or undirect correlated one and want
275 * to set params for parent plan then prepare parameters.
277 if (node->setParam != NIL)
281 foreach(lst, node->setParam)
283 ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
285 prm->execPlan = node;
289 * Note that in the case of un-correlated subqueries we don't care
290 * about setting parent->chgParam here: indices take care about
291 * it, for others - it doesn't matter...
298 /* ----------------------------------------------------------------
301 * Executes plan of node and sets parameters.
302 * ----------------------------------------------------------------
305 ExecSetParamPlan(SubPlan *node)
307 Plan *plan = node->plan;
308 SubLink *sublink = node->sublink;
309 TupleTableSlot *slot;
313 if (sublink->subLinkType == ANY_SUBLINK ||
314 sublink->subLinkType == ALL_SUBLINK)
315 elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
317 if (plan->chgParam != NULL)
318 ExecReScan(plan, (ExprContext *) NULL, plan);
320 for (slot = ExecProcNode(plan, plan);
322 slot = ExecProcNode(plan, plan))
324 HeapTuple tup = slot->val;
325 TupleDesc tdesc = slot->ttc_tupleDescriptor;
328 if (sublink->subLinkType == EXISTS_SUBLINK)
330 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
332 prm->execPlan = NULL;
333 prm->value = (Datum) true;
340 (sublink->subLinkType == EXPR_SUBLINK ||
341 sublink->subLinkType == MULTIEXPR_SUBLINK))
342 elog(ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect");
347 * We need to copy the subplan's tuple in case any of the params
348 * are pass-by-ref type --- the pointers stored in the param structs
349 * will point at this copied tuple! node->curTuple keeps track
350 * of the copied tuple for eventual freeing.
352 tup = heap_copytuple(tup);
354 heap_freetuple(node->curTuple);
355 node->curTuple = tup;
357 foreach(lst, node->setParam)
359 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
361 prm->execPlan = NULL;
362 prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
369 if (sublink->subLinkType == EXISTS_SUBLINK)
371 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
373 prm->execPlan = NULL;
374 prm->value = (Datum) false;
379 foreach(lst, node->setParam)
381 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
383 prm->execPlan = NULL;
384 prm->value = (Datum) NULL;
390 if (plan->extParam == NULL) /* un-correlated ... */
392 ExecEndNode(plan, plan);
393 node->shutdown = false;
397 /* ----------------------------------------------------------------
399 * ----------------------------------------------------------------
402 ExecEndSubPlan(SubPlan *node)
406 ExecEndNode(node->plan, node->plan);
407 node->shutdown = false;
411 heap_freetuple(node->curTuple);
412 node->curTuple = NULL;
417 ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
419 Plan *plan = node->plan;
422 if (node->parParam != NULL)
423 elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
424 if (node->setParam == NULL)
425 elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
426 if (plan->extParam == NULL)
427 elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
430 * Don't actual re-scan: ExecSetParamPlan does re-scan if
431 * node->plan->chgParam is not NULL... ExecReScan (plan, NULL, plan);
434 foreach(lst, node->setParam)
436 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
438 prm->execPlan = node;
441 parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));