aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSubplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r--src/backend/executor/nodeSubplan.c119
1 files changed, 67 insertions, 52 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 43b36dcd3b4..a33efce3fe1 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -235,32 +235,6 @@ ExecScanSubPlan(SubPlanState *node,
ListCell *l;
ArrayBuildStateAny *astate = NULL;
- /*
- * MULTIEXPR subplans, when "executed", just return NULL; but first we
- * mark the subplan's output parameters as needing recalculation. (This
- * is a bit of a hack: it relies on the subplan appearing later in its
- * targetlist than any of the referencing Params, so that all the Params
- * have been evaluated before we re-mark them for the next evaluation
- * cycle. But in general resjunk tlist items appear after non-resjunk
- * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do
- * *not* set bits in the parent plan node's chgParam, because we don't
- * want to cause a rescan of the parent.
- */
- if (subLinkType == MULTIEXPR_SUBLINK)
- {
- EState *estate = node->parent->state;
-
- foreach(l, subplan->setParam)
- {
- int paramid = lfirst_int(l);
- ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
-
- prm->execPlan = node;
- }
- *isNull = true;
- return (Datum) 0;
- }
-
/* Initialize ArrayBuildStateAny in caller's context, if needed */
if (subLinkType == ARRAY_SUBLINK)
astate = initArrayResultAny(subplan->firstColType,
@@ -312,6 +286,11 @@ ExecScanSubPlan(SubPlanState *node,
* NULL. Assuming we get a tuple, we just use its first column (there can
* be only one non-junk column in this case).
*
+ * For MULTIEXPR_SUBLINK, we push the per-column subplan outputs out to
+ * the setParams and then return a dummy false value. There must not be
+ * multiple tuples returned from the subplan; if zero tuples are produced,
+ * set the setParams to NULL.
+ *
* For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
* and form an array of the first column's values. Note in particular
* that we produce a zero-element array if no tuples are produced (this is
@@ -363,6 +342,47 @@ ExecScanSubPlan(SubPlanState *node,
continue;
}
+ if (subLinkType == MULTIEXPR_SUBLINK)
+ {
+ /* cannot allow multiple input tuples for MULTIEXPR sublink */
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_CARDINALITY_VIOLATION),
+ errmsg("more than one row returned by a subquery used as an expression")));
+ found = true;
+
+ /*
+ * We need to copy the subplan's tuple in case any result is of
+ * pass-by-ref type --- our output values 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.
+ */
+ if (node->curTuple)
+ heap_freetuple(node->curTuple);
+ node->curTuple = ExecCopySlotHeapTuple(slot);
+
+ /*
+ * Now set all the setParam params from the columns of the tuple
+ */
+ col = 1;
+ foreach(plst, subplan->setParam)
+ {
+ int paramid = lfirst_int(plst);
+ ParamExecData *prmdata;
+
+ prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
+ Assert(prmdata->execPlan == NULL);
+ prmdata->value = heap_getattr(node->curTuple, col, tdesc,
+ &(prmdata->isnull));
+ col++;
+ }
+
+ /* keep scanning subplan to make sure there's only one tuple */
+ continue;
+ }
+
if (subLinkType == ARRAY_SUBLINK)
{
Datum dvalue;
@@ -458,6 +478,20 @@ ExecScanSubPlan(SubPlanState *node,
result = (Datum) 0;
*isNull = true;
}
+ else if (subLinkType == MULTIEXPR_SUBLINK)
+ {
+ /* We don't care about function result, but set the setParams */
+ foreach(l, subplan->setParam)
+ {
+ int paramid = lfirst_int(l);
+ ParamExecData *prmdata;
+
+ prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
+ Assert(prmdata->execPlan == NULL);
+ prmdata->value = (Datum) 0;
+ prmdata->isnull = true;
+ }
+ }
}
return result;
@@ -833,10 +867,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
sstate->cur_eq_funcs = NULL;
/*
- * If this is an initplan or MULTIEXPR subplan, it has output parameters
- * that the parent plan will use, so mark those parameters as needing
- * evaluation. We don't actually run the subplan until we first need one
- * of its outputs.
+ * If this is an initplan, it has output parameters that the parent plan
+ * will use, so mark those parameters as needing evaluation. We don't
+ * actually run the subplan until we first need one of its outputs.
*
* A CTE subplan's output parameter is never to be evaluated in the normal
* way, so skip this in that case.
@@ -844,7 +877,8 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
* Note that we don't set parent->chgParam here: the parent plan hasn't
* been run yet, so no need to force it to re-run.
*/
- if (subplan->setParam != NIL && subplan->subLinkType != CTE_SUBLINK)
+ if (subplan->setParam != NIL && subplan->parParam == NIL &&
+ subplan->subLinkType != CTE_SUBLINK)
{
ListCell *lst;
@@ -1064,7 +1098,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
ScanDirection dir = estate->es_direction;
MemoryContext oldcontext;
TupleTableSlot *slot;
- ListCell *pvar;
ListCell *l;
bool found = false;
ArrayBuildStateAny *astate = NULL;
@@ -1074,6 +1107,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
elog(ERROR, "ANY/ALL subselect unsupported as initplan");
if (subLinkType == CTE_SUBLINK)
elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
+ if (subplan->parParam || node->args)
+ elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
/*
* Enforce forward scan direction regardless of caller. It's hard but not
@@ -1092,26 +1127,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
/*
- * Set Params of this plan from parent plan correlation values. (Any
- * calculation we have to do is done in the parent econtext, since the
- * Param values don't need to have per-query lifetime.) Currently, we
- * expect only MULTIEXPR_SUBLINK plans to have any correlation values.
- */
- Assert(subplan->parParam == NIL || subLinkType == MULTIEXPR_SUBLINK);
- Assert(list_length(subplan->parParam) == list_length(node->args));
-
- forboth(l, subplan->parParam, pvar, node->args)
- {
- int paramid = lfirst_int(l);
- ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
-
- prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
- econtext,
- &(prm->isnull));
- planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
- }
-
- /*
* Run the plan. (If it needs to be rescanned, the first ExecProcNode
* call will take care of that.)
*/