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.
@@ -1402,6 +1390,21 @@ ExecInitExprRec(Expr *node, ExprState *state,
14021390SubPlan * subplan = (SubPlan * )node ;
14031391SubPlanState * sstate ;
14041392
1393+ /*
1394+ * Real execution of a MULTIEXPR SubPlan has already been
1395+ * done. What we have to do here is return a dummy NULL record
1396+ * value in case this targetlist element is assigned
1397+ * someplace.
1398+ */
1399+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
1400+ {
1401+ scratch .opcode = EEOP_CONST ;
1402+ scratch .d .constval .value = (Datum )0 ;
1403+ scratch .d .constval .isnull = true;
1404+ ExprEvalPushStep (state ,& scratch );
1405+ break ;
1406+ }
1407+
14051408if (!state -> parent )
14061409elog (ERROR ,"SubPlan found with no parent plan" );
14071410
@@ -2553,36 +2556,38 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
25532556}
25542557
25552558/*
2556- * Add expression stepsdeforming the ExprState 'sinner/outer/scan slots
2557- *as much as required by the expression.
2559+ * Add expression stepsperforming setup that 'sneeded before any of the
2560+ *main execution of the expression.
25582561 */
25592562static void
2560- ExecInitExprSlots (ExprState * state ,Node * node )
2563+ ExecCreateExprSetupSteps (ExprState * state ,Node * node )
25612564{
2562- LastAttnumInfo info = {0 ,0 ,0 };
2565+ ExprSetupInfo info = {0 ,0 ,0 , NIL };
25632566
2564- /*
2565- * Figure out which attributes we're going to need.
2566- */
2567- get_last_attnums_walker (node ,& info );
2567+ /* Prescan to find out what we need. */
2568+ expr_setup_walker (node ,& info );
25682569
2569- ExecPushExprSlots (state ,& info );
2570+ /* And generate those steps. */
2571+ ExecPushExprSetupSteps (state ,& info );
25702572}
25712573
25722574/*
2573- * Add steps deforming the ExprState's inner/out/scan slots as much as
2574- * indicated by info. This is useful when building an ExprState covering more
2575- * than one expression.
2575+ * Add steps performing expression setup as indicated by "info".
2576+ * This is useful when building an ExprState covering more than one expression.
25762577 */
25772578static void
2578- ExecPushExprSlots (ExprState * state ,LastAttnumInfo * info )
2579+ ExecPushExprSetupSteps (ExprState * state ,ExprSetupInfo * info )
25792580{
25802581ExprEvalStep scratch = {0 };
2582+ ListCell * lc ;
25812583
25822584scratch .resvalue = NULL ;
25832585scratch .resnull = NULL ;
25842586
2585- /* Emit steps as needed */
2587+ /*
2588+ * Add steps deforming the ExprState's inner/outer/scan slots as much as
2589+ * required by any Vars appearing in the expression.
2590+ */
25862591if (info -> last_inner > 0 )
25872592{
25882593scratch .opcode = EEOP_INNER_FETCHSOME ;
@@ -2613,13 +2618,48 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
26132618if (ExecComputeSlotInfo (state ,& scratch ))
26142619ExprEvalPushStep (state ,& scratch );
26152620}
2621+
2622+ /*
2623+ * Add steps to execute any MULTIEXPR SubPlans appearing in the
2624+ * expression. We need to evaluate these before any of the Params
2625+ * referencing their outputs are used, but after we've prepared for any
2626+ * Var references they may contain. (There cannot be cross-references
2627+ * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2628+ */
2629+ foreach (lc ,info -> multiexpr_subplans )
2630+ {
2631+ SubPlan * subplan = (SubPlan * )lfirst (lc );
2632+ SubPlanState * sstate ;
2633+
2634+ Assert (subplan -> subLinkType == MULTIEXPR_SUBLINK );
2635+
2636+ /* This should match what ExecInitExprRec does for other SubPlans: */
2637+
2638+ if (!state -> parent )
2639+ elog (ERROR ,"SubPlan found with no parent plan" );
2640+
2641+ sstate = ExecInitSubPlan (subplan ,state -> parent );
2642+
2643+ /* add SubPlanState nodes to state->parent->subPlan */
2644+ state -> parent -> subPlan = lappend (state -> parent -> subPlan ,
2645+ sstate );
2646+
2647+ scratch .opcode = EEOP_SUBPLAN ;
2648+ scratch .d .subplan .sstate = sstate ;
2649+
2650+ /* The result can be ignored, but we better put it somewhere */
2651+ scratch .resvalue = & state -> resvalue ;
2652+ scratch .resnull = & state -> resnull ;
2653+
2654+ ExprEvalPushStep (state ,& scratch );
2655+ }
26162656}
26172657
26182658/*
2619- *get_last_attnums_walker : expression walker forExecInitExprSlots
2659+ *expr_setup_walker : expression walker forExecCreateExprSetupSteps
26202660 */
26212661static bool
2622- get_last_attnums_walker (Node * node ,LastAttnumInfo * info )
2662+ expr_setup_walker (Node * node ,ExprSetupInfo * info )
26232663{
26242664if (node == NULL )
26252665return false;
@@ -2647,6 +2687,16 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
26472687return false;
26482688}
26492689
2690+ /* Collect all MULTIEXPR SubPlans, too */
2691+ if (IsA (node ,SubPlan ))
2692+ {
2693+ SubPlan * subplan = (SubPlan * )node ;
2694+
2695+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
2696+ info -> multiexpr_subplans = lappend (info -> multiexpr_subplans ,
2697+ subplan );
2698+ }
2699+
26502700/*
26512701 * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
26522702 * because those do not represent expressions to be evaluated within the
@@ -2659,7 +2709,7 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
26592709return false;
26602710if (IsA (node ,GroupingFunc ))
26612711return false;
2662- return expression_tree_walker (node ,get_last_attnums_walker ,
2712+ return expression_tree_walker (node ,expr_setup_walker ,
26632713 (void * )info );
26642714}
26652715
@@ -3278,7 +3328,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
32783328PlanState * parent = & aggstate -> ss .ps ;
32793329ExprEvalStep scratch = {0 };
32803330bool isCombine = DO_AGGSPLIT_COMBINE (aggstate -> aggsplit );
3281- LastAttnumInfo deform = {0 ,0 ,0 };
3331+ ExprSetupInfo deform = {0 ,0 ,0 , NIL };
32823332
32833333state -> expr = (Expr * )aggstate ;
32843334state -> parent = parent ;
@@ -3294,18 +3344,18 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
32943344{
32953345AggStatePerTrans pertrans = & aggstate -> pertrans [transno ];
32963346
3297- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3298- & deform );
3299- get_last_attnums_walker ((Node * )pertrans -> aggref -> args ,
3300- & deform );
3301- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggorder ,
3302- & deform );
3303- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3304- & deform );
3305- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggfilter ,
3306- & deform );
3347+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3348+ & deform );
3349+ expr_setup_walker ((Node * )pertrans -> aggref -> args ,
3350+ & deform );
3351+ expr_setup_walker ((Node * )pertrans -> aggref -> aggorder ,
3352+ & deform );
3353+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3354+ & deform );
3355+ expr_setup_walker ((Node * )pertrans -> aggref -> aggfilter ,
3356+ & deform );
33073357}
3308- ExecPushExprSlots (state ,& deform );
3358+ ExecPushExprSetupSteps (state ,& deform );
33093359
33103360/*
33113361 * Emit instructions for each transition value / grouping set combination.