5151#include "utils/typcache.h"
5252
5353
54- typedef struct LastAttnumInfo
54+ typedef struct ExprSetupInfo
5555{
56+ /* Highest attribute numbers fetched from inner/outer/scan tuple slots: */
5657AttrNumber last_inner ;
5758AttrNumber last_outer ;
5859AttrNumber last_scan ;
59- }LastAttnumInfo ;
60+ /* MULTIEXPR SubPlan nodes appearing in the expression: */
61+ List * multiexpr_subplans ;
62+ }ExprSetupInfo ;
6063
6164static void ExecReadyExpr (ExprState * state );
6265static void ExecInitExprRec (Expr * node ,ExprState * state ,
6366Datum * resv ,bool * resnull );
6467static void ExecInitFunc (ExprEvalStep * scratch ,Expr * node ,List * args ,
6568Oid funcid ,Oid inputcollid ,
6669ExprState * state );
67- static void ExecInitExprSlots (ExprState * state ,Node * node );
68- static void ExecPushExprSlots (ExprState * state ,LastAttnumInfo * info );
69- static bool get_last_attnums_walker (Node * node ,LastAttnumInfo * info );
70+ static void ExecCreateExprSetupSteps (ExprState * state ,Node * node );
71+ static void ExecPushExprSetupSteps (ExprState * state ,ExprSetupInfo * info );
72+ static bool expr_setup_walker (Node * node ,ExprSetupInfo * info );
7073static bool ExecComputeSlotInfo (ExprState * state ,ExprEvalStep * op );
7174static void ExecInitWholeRowVar (ExprEvalStep * scratch ,Var * variable ,
7275ExprState * state );
@@ -135,8 +138,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
135138state -> parent = parent ;
136139state -> ext_params = NULL ;
137140
138- /* InsertEEOP_*_FETCHSOME steps as needed */
139- ExecInitExprSlots (state , (Node * )node );
141+ /* Insertsetup steps as needed */
142+ ExecCreateExprSetupSteps (state , (Node * )node );
140143
141144/* Compile the expression proper */
142145ExecInitExprRec (node ,state ,& state -> resvalue ,& state -> resnull );
@@ -172,8 +175,8 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
172175state -> parent = NULL ;
173176state -> ext_params = ext_params ;
174177
175- /* InsertEEOP_*_FETCHSOME steps as needed */
176- ExecInitExprSlots (state , (Node * )node );
178+ /* Insertsetup steps as needed */
179+ ExecCreateExprSetupSteps (state , (Node * )node );
177180
178181/* Compile the expression proper */
179182ExecInitExprRec (node ,state ,& state -> resvalue ,& state -> resnull );
@@ -227,8 +230,8 @@ ExecInitQual(List *qual, PlanState *parent)
227230/* mark expression as to be used with ExecQual() */
228231state -> flags = EEO_FLAG_IS_QUAL ;
229232
230- /* InsertEEOP_*_FETCHSOME steps as needed */
231- ExecInitExprSlots (state , (Node * )qual );
233+ /* Insertsetup steps as needed */
234+ ExecCreateExprSetupSteps (state , (Node * )qual );
232235
233236/*
234237 * ExecQual() needs to return false for an expression returning NULL. That
@@ -371,8 +374,8 @@ ExecBuildProjectionInfo(List *targetList,
371374
372375state -> resultslot = slot ;
373376
374- /* InsertEEOP_*_FETCHSOME steps as needed */
375- ExecInitExprSlots (state , (Node * )targetList );
377+ /* Insertsetup steps as needed */
378+ ExecCreateExprSetupSteps (state , (Node * )targetList );
376379
377380/* Now compile each tlist column */
378381foreach (lc ,targetList )
@@ -523,7 +526,7 @@ ExecBuildUpdateProjection(List *targetList,
523526int nAssignableCols ;
524527bool sawJunk ;
525528Bitmapset * assignedCols ;
526- LastAttnumInfo deform = {0 ,0 ,0 };
529+ ExprSetupInfo deform = {0 ,0 ,0 , NIL };
527530ExprEvalStep scratch = {0 };
528531int outerattnum ;
529532ListCell * lc ,
@@ -602,17 +605,18 @@ ExecBuildUpdateProjection(List *targetList,
602605 * number of columns of the "outer" tuple.
603606 */
604607if (evalTargetList )
605- get_last_attnums_walker ((Node * )targetList ,& deform );
608+ expr_setup_walker ((Node * )targetList ,& deform );
606609else
607610deform .last_outer = nAssignableCols ;
608611
609- ExecPushExprSlots (state ,& deform );
612+ ExecPushExprSetupSteps (state ,& deform );
610613
611614/*
612615 * Now generate code to evaluate the tlist's assignable expressions or
613616 * fetch them from the outer tuple, incidentally validating that they'll
614617 * be of the right data type. The checks above ensure that the forboth()
615- * will iterate over exactly the non-junk columns.
618+ * will iterate over exactly the non-junk columns. Note that we don't
619+ * bother evaluating any remaining resjunk columns.
616620 */
617621outerattnum = 0 ;
618622forboth (lc ,targetList ,lc2 ,targetColnos )
@@ -675,22 +679,6 @@ ExecBuildUpdateProjection(List *targetList,
675679outerattnum ++ ;
676680}
677681
678- /*
679- * If we're evaluating the tlist, must evaluate any resjunk columns too.
680- * (This matters for things like MULTIEXPR_SUBLINK SubPlans.)
681- */
682- if (evalTargetList )
683- {
684- for_each_cell (lc ,targetList ,lc )
685- {
686- TargetEntry * tle = lfirst_node (TargetEntry ,lc );
687-
688- Assert (tle -> resjunk );
689- ExecInitExprRec (tle -> expr ,state ,
690- & state -> resvalue ,& state -> resnull );
691- }
692- }
693-
694682/*
695683 * Now generate code to copy over any old columns that were not assigned
696684 * to, and to ensure that dropped columns are set to NULL.
@@ -1401,6 +1389,21 @@ ExecInitExprRec(Expr *node, ExprState *state,
14011389SubPlan * subplan = (SubPlan * )node ;
14021390SubPlanState * sstate ;
14031391
1392+ /*
1393+ * Real execution of a MULTIEXPR SubPlan has already been
1394+ * done. What we have to do here is return a dummy NULL record
1395+ * value in case this targetlist element is assigned
1396+ * someplace.
1397+ */
1398+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
1399+ {
1400+ scratch .opcode = EEOP_CONST ;
1401+ scratch .d .constval .value = (Datum )0 ;
1402+ scratch .d .constval .isnull = true;
1403+ ExprEvalPushStep (state ,& scratch );
1404+ break ;
1405+ }
1406+
14041407if (!state -> parent )
14051408elog (ERROR ,"SubPlan found with no parent plan" );
14061409
@@ -2552,36 +2555,38 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
25522555}
25532556
25542557/*
2555- * Add expression stepsdeforming the ExprState 'sinner/outer/scan slots
2556- *as much as required by the expression.
2558+ * Add expression stepsperforming setup that 'sneeded before any of the
2559+ *main execution of the expression.
25572560 */
25582561static void
2559- ExecInitExprSlots (ExprState * state ,Node * node )
2562+ ExecCreateExprSetupSteps (ExprState * state ,Node * node )
25602563{
2561- LastAttnumInfo info = {0 ,0 ,0 };
2564+ ExprSetupInfo info = {0 ,0 ,0 , NIL };
25622565
2563- /*
2564- * Figure out which attributes we're going to need.
2565- */
2566- get_last_attnums_walker (node ,& info );
2566+ /* Prescan to find out what we need. */
2567+ expr_setup_walker (node ,& info );
25672568
2568- ExecPushExprSlots (state ,& info );
2569+ /* And generate those steps. */
2570+ ExecPushExprSetupSteps (state ,& info );
25692571}
25702572
25712573/*
2572- * Add steps deforming the ExprState's inner/out/scan slots as much as
2573- * indicated by info. This is useful when building an ExprState covering more
2574- * than one expression.
2574+ * Add steps performing expression setup as indicated by "info".
2575+ * This is useful when building an ExprState covering more than one expression.
25752576 */
25762577static void
2577- ExecPushExprSlots (ExprState * state ,LastAttnumInfo * info )
2578+ ExecPushExprSetupSteps (ExprState * state ,ExprSetupInfo * info )
25782579{
25792580ExprEvalStep scratch = {0 };
2581+ ListCell * lc ;
25802582
25812583scratch .resvalue = NULL ;
25822584scratch .resnull = NULL ;
25832585
2584- /* Emit steps as needed */
2586+ /*
2587+ * Add steps deforming the ExprState's inner/outer/scan slots as much as
2588+ * required by any Vars appearing in the expression.
2589+ */
25852590if (info -> last_inner > 0 )
25862591{
25872592scratch .opcode = EEOP_INNER_FETCHSOME ;
@@ -2612,13 +2617,48 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
26122617if (ExecComputeSlotInfo (state ,& scratch ))
26132618ExprEvalPushStep (state ,& scratch );
26142619}
2620+
2621+ /*
2622+ * Add steps to execute any MULTIEXPR SubPlans appearing in the
2623+ * expression. We need to evaluate these before any of the Params
2624+ * referencing their outputs are used, but after we've prepared for any
2625+ * Var references they may contain. (There cannot be cross-references
2626+ * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2627+ */
2628+ foreach (lc ,info -> multiexpr_subplans )
2629+ {
2630+ SubPlan * subplan = (SubPlan * )lfirst (lc );
2631+ SubPlanState * sstate ;
2632+
2633+ Assert (subplan -> subLinkType == MULTIEXPR_SUBLINK );
2634+
2635+ /* This should match what ExecInitExprRec does for other SubPlans: */
2636+
2637+ if (!state -> parent )
2638+ elog (ERROR ,"SubPlan found with no parent plan" );
2639+
2640+ sstate = ExecInitSubPlan (subplan ,state -> parent );
2641+
2642+ /* add SubPlanState nodes to state->parent->subPlan */
2643+ state -> parent -> subPlan = lappend (state -> parent -> subPlan ,
2644+ sstate );
2645+
2646+ scratch .opcode = EEOP_SUBPLAN ;
2647+ scratch .d .subplan .sstate = sstate ;
2648+
2649+ /* The result can be ignored, but we better put it somewhere */
2650+ scratch .resvalue = & state -> resvalue ;
2651+ scratch .resnull = & state -> resnull ;
2652+
2653+ ExprEvalPushStep (state ,& scratch );
2654+ }
26152655}
26162656
26172657/*
2618- *get_last_attnums_walker : expression walker forExecInitExprSlots
2658+ *expr_setup_walker : expression walker forExecCreateExprSetupSteps
26192659 */
26202660static bool
2621- get_last_attnums_walker (Node * node ,LastAttnumInfo * info )
2661+ expr_setup_walker (Node * node ,ExprSetupInfo * info )
26222662{
26232663if (node == NULL )
26242664return false;
@@ -2646,6 +2686,16 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
26462686return false;
26472687}
26482688
2689+ /* Collect all MULTIEXPR SubPlans, too */
2690+ if (IsA (node ,SubPlan ))
2691+ {
2692+ SubPlan * subplan = (SubPlan * )node ;
2693+
2694+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
2695+ info -> multiexpr_subplans = lappend (info -> multiexpr_subplans ,
2696+ subplan );
2697+ }
2698+
26492699/*
26502700 * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
26512701 * because those do not represent expressions to be evaluated within the
@@ -2658,7 +2708,7 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
26582708return false;
26592709if (IsA (node ,GroupingFunc ))
26602710return false;
2661- return expression_tree_walker (node ,get_last_attnums_walker ,
2711+ return expression_tree_walker (node ,expr_setup_walker ,
26622712 (void * )info );
26632713}
26642714
@@ -3277,7 +3327,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
32773327PlanState * parent = & aggstate -> ss .ps ;
32783328ExprEvalStep scratch = {0 };
32793329bool isCombine = DO_AGGSPLIT_COMBINE (aggstate -> aggsplit );
3280- LastAttnumInfo deform = {0 ,0 ,0 };
3330+ ExprSetupInfo deform = {0 ,0 ,0 , NIL };
32813331
32823332state -> expr = (Expr * )aggstate ;
32833333state -> parent = parent ;
@@ -3293,18 +3343,18 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
32933343{
32943344AggStatePerTrans pertrans = & aggstate -> pertrans [transno ];
32953345
3296- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3297- & deform );
3298- get_last_attnums_walker ((Node * )pertrans -> aggref -> args ,
3299- & deform );
3300- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggorder ,
3301- & deform );
3302- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3303- & deform );
3304- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggfilter ,
3305- & deform );
3346+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3347+ & deform );
3348+ expr_setup_walker ((Node * )pertrans -> aggref -> args ,
3349+ & deform );
3350+ expr_setup_walker ((Node * )pertrans -> aggref -> aggorder ,
3351+ & deform );
3352+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3353+ & deform );
3354+ expr_setup_walker ((Node * )pertrans -> aggref -> aggfilter ,
3355+ & deform );
33063356}
3307- ExecPushExprSlots (state ,& deform );
3357+ ExecPushExprSetupSteps (state ,& deform );
33083358
33093359/*
33103360 * Emit instructions for each transition value / grouping set combination.