11/*-------------------------------------------------------------------------
22 *
33 * nodeSubplan.c
4- * routines to support subselects
4+ * routines to support sub-selects appearing in expressions
5+ *
6+ * This module is concerned with executing SubPlan expression nodes, which
7+ * should not be confused with sub-SELECTs appearing in FROM. SubPlans are
8+ * divided into "initplans", which are those that need only one evaluation per
9+ * query (among other restrictions, this requires that they don't use any
10+ * direct correlation variables from the parent plan level), and "regular"
11+ * subplans, which are re-evaluated every time their result is required.
12+ *
513 *
614 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
715 * Portions Copyright (c) 1994, Regents of the University of California
@@ -54,6 +62,8 @@ static bool slotNoNulls(TupleTableSlot *slot);
5462
5563/* ----------------------------------------------------------------
5664 * ExecSubPlan
65+ *
66+ * This is the main entry point for execution of a regular SubPlan.
5767 * ----------------------------------------------------------------
5868 */
5969static Datum
@@ -72,7 +82,7 @@ ExecSubPlan(SubPlanState *node,
7282 /* Sanity checks */
7383 if (subplan -> subLinkType == CTE_SUBLINK )
7484 elog (ERROR , "CTE subplans should not be executed via ExecSubPlan" );
75- if (subplan -> setParam != NIL )
85+ if (subplan -> setParam != NIL && subplan -> subLinkType != MULTIEXPR_SUBLINK )
7686 elog (ERROR , "cannot set parent params from subquery" );
7787
7888 /* Select appropriate evaluation strategy */
@@ -223,6 +233,32 @@ ExecScanSubPlan(SubPlanState *node,
223233 ListCell * l ;
224234 ArrayBuildState * astate = NULL ;
225235
236+ /*
237+ * MULTIEXPR subplans, when "executed", just return NULL; but first we
238+ * mark the subplan's output parameters as needing recalculation. (This
239+ * is a bit of a hack: it relies on the subplan appearing later in its
240+ * targetlist than any of the referencing Params, so that all the Params
241+ * have been evaluated before we re-mark them for the next evaluation
242+ * cycle. But in general resjunk tlist items appear after non-resjunk
243+ * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do
244+ * *not* set bits in the parent plan node's chgParam, because we don't
245+ * want to cause a rescan of the parent.
246+ */
247+ if (subLinkType == MULTIEXPR_SUBLINK )
248+ {
249+ EState * estate = node -> parent -> state ;
250+
251+ foreach (l , subplan -> setParam )
252+ {
253+ int paramid = lfirst_int (l );
254+ ParamExecData * prm = & (estate -> es_param_exec_vals [paramid ]);
255+
256+ prm -> execPlan = node ;
257+ }
258+ * isNull = true;
259+ return (Datum ) 0 ;
260+ }
261+
226262 /*
227263 * We are probably in a short-lived expression-evaluation context. Switch
228264 * to the per-query context for manipulating the child plan's chgParam,
@@ -667,6 +703,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
667703 sstate -> planstate = (PlanState * ) list_nth (estate -> es_subplanstates ,
668704 subplan -> plan_id - 1 );
669705
706+ /* ... and to its parent's state */
707+ sstate -> parent = parent ;
708+
670709 /* Initialize subexpressions */
671710 sstate -> testexpr = ExecInitExpr ((Expr * ) subplan -> testexpr , parent );
672711 sstate -> args = (List * ) ExecInitExpr ((Expr * ) subplan -> args , parent );
@@ -690,15 +729,16 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
690729 sstate -> cur_eq_funcs = NULL ;
691730
692731 /*
693- * If this plan is un-correlated or undirect correlated one and want to
694- * set params for parent plan then mark parameters as needing evaluation.
732+ * If this is an initplan or MULTIEXPR subplan, it has output parameters
733+ * that the parent plan will use, so mark those parameters as needing
734+ * evaluation. We don't actually run the subplan until we first need one
735+ * of its outputs.
695736 *
696737 * A CTE subplan's output parameter is never to be evaluated in the normal
697738 * way, so skip this in that case.
698739 *
699- * Note that in the case of un-correlated subqueries we don't care about
700- * setting parent->chgParam here: indices take care about it, for others -
701- * it doesn't matter...
740+ * Note that we don't set parent->chgParam here: the parent plan hasn't
741+ * been run yet, so no need to force it to re-run.
702742 */
703743 if (subplan -> setParam != NIL && subplan -> subLinkType != CTE_SUBLINK )
704744 {
@@ -890,7 +930,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
890930/* ----------------------------------------------------------------
891931 * ExecSetParamPlan
892932 *
893- * Executes an InitPlan subplan and sets its output parameters.
933+ * Executes a subplan and sets its output parameters.
894934 *
895935 * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
896936 * parameter is requested and the param's execPlan field is set (indicating
@@ -908,6 +948,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
908948 SubLinkType subLinkType = subplan -> subLinkType ;
909949 MemoryContext oldcontext ;
910950 TupleTableSlot * slot ;
951+ ListCell * pvar ;
911952 ListCell * l ;
912953 bool found = false;
913954 ArrayBuildState * astate = NULL ;
@@ -923,6 +964,27 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
923964 */
924965 oldcontext = MemoryContextSwitchTo (econtext -> ecxt_per_query_memory );
925966
967+ /*
968+ * Set Params of this plan from parent plan correlation values. (Any
969+ * calculation we have to do is done in the parent econtext, since the
970+ * Param values don't need to have per-query lifetime.) Currently, we
971+ * expect only MULTIEXPR_SUBLINK plans to have any correlation values.
972+ */
973+ Assert (subplan -> parParam == NIL || subLinkType == MULTIEXPR_SUBLINK );
974+ Assert (list_length (subplan -> parParam ) == list_length (node -> args ));
975+
976+ forboth (l , subplan -> parParam , pvar , node -> args )
977+ {
978+ int paramid = lfirst_int (l );
979+ ParamExecData * prm = & (econtext -> ecxt_param_exec_vals [paramid ]);
980+
981+ prm -> value = ExecEvalExprSwitchContext ((ExprState * ) lfirst (pvar ),
982+ econtext ,
983+ & (prm -> isnull ),
984+ NULL );
985+ planstate -> chgParam = bms_add_member (planstate -> chgParam , paramid );
986+ }
987+
926988 /*
927989 * Run the plan. (If it needs to be rescanned, the first ExecProcNode
928990 * call will take care of that.)
@@ -964,6 +1026,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
9641026
9651027 if (found &&
9661028 (subLinkType == EXPR_SUBLINK ||
1029+ subLinkType == MULTIEXPR_SUBLINK ||
9671030 subLinkType == ROWCOMPARE_SUBLINK ))
9681031 ereport (ERROR ,
9691032 (errcode (ERRCODE_CARDINALITY_VIOLATION ),
@@ -1035,6 +1098,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
10351098 }
10361099 else
10371100 {
1101+ /* For other sublink types, set all the output params to NULL */
10381102 foreach (l , subplan -> setParam )
10391103 {
10401104 int paramid = lfirst_int (l );
0 commit comments