50
50
#include "utils/typcache.h"
51
51
52
52
53
- typedef struct LastAttnumInfo
53
+ typedef struct ExprSetupInfo
54
54
{
55
+ /* Highest attribute numbers fetched from inner/outer/scan tuple slots: */
55
56
AttrNumber last_inner ;
56
57
AttrNumber last_outer ;
57
58
AttrNumber last_scan ;
58
- }LastAttnumInfo ;
59
+ /* MULTIEXPR SubPlan nodes appearing in the expression: */
60
+ List * multiexpr_subplans ;
61
+ }ExprSetupInfo ;
59
62
60
63
static void ExecReadyExpr (ExprState * state );
61
64
static void ExecInitExprRec (Expr * node ,ExprState * state ,
62
65
Datum * resv ,bool * resnull );
63
66
static void ExecInitFunc (ExprEvalStep * scratch ,Expr * node ,List * args ,
64
67
Oid funcid ,Oid inputcollid ,
65
68
ExprState * state );
66
- static void ExecInitExprSlots (ExprState * state ,Node * node );
67
- static void ExecPushExprSlots (ExprState * state ,LastAttnumInfo * info );
68
- static bool get_last_attnums_walker (Node * node ,LastAttnumInfo * info );
69
+ static void ExecCreateExprSetupSteps (ExprState * state ,Node * node );
70
+ static void ExecPushExprSetupSteps (ExprState * state ,ExprSetupInfo * info );
71
+ static bool expr_setup_walker (Node * node ,ExprSetupInfo * info );
69
72
static bool ExecComputeSlotInfo (ExprState * state ,ExprEvalStep * op );
70
73
static void ExecInitWholeRowVar (ExprEvalStep * scratch ,Var * variable ,
71
74
ExprState * state );
@@ -135,8 +138,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
135
138
state -> parent = parent ;
136
139
state -> ext_params = NULL ;
137
140
138
- /* InsertEEOP_*_FETCHSOME steps as needed */
139
- ExecInitExprSlots (state , (Node * )node );
141
+ /* Insertsetup steps as needed */
142
+ ExecCreateExprSetupSteps (state , (Node * )node );
140
143
141
144
/* Compile the expression proper */
142
145
ExecInitExprRec (node ,state ,& state -> resvalue ,& state -> resnull );
@@ -172,8 +175,8 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
172
175
state -> parent = NULL ;
173
176
state -> ext_params = ext_params ;
174
177
175
- /* InsertEEOP_*_FETCHSOME steps as needed */
176
- ExecInitExprSlots (state , (Node * )node );
178
+ /* Insertsetup steps as needed */
179
+ ExecCreateExprSetupSteps (state , (Node * )node );
177
180
178
181
/* Compile the expression proper */
179
182
ExecInitExprRec (node ,state ,& state -> resvalue ,& state -> resnull );
@@ -227,8 +230,8 @@ ExecInitQual(List *qual, PlanState *parent)
227
230
/* mark expression as to be used with ExecQual() */
228
231
state -> flags = EEO_FLAG_IS_QUAL ;
229
232
230
- /* InsertEEOP_*_FETCHSOME steps as needed */
231
- ExecInitExprSlots (state , (Node * )qual );
233
+ /* Insertsetup steps as needed */
234
+ ExecCreateExprSetupSteps (state , (Node * )qual );
232
235
233
236
/*
234
237
* ExecQual() needs to return false for an expression returning NULL. That
@@ -397,8 +400,8 @@ ExecBuildProjectionInfoExt(List *targetList,
397
400
398
401
state -> resultslot = slot ;
399
402
400
- /* InsertEEOP_*_FETCHSOME steps as needed */
401
- ExecInitExprSlots (state , (Node * )targetList );
403
+ /* Insertsetup steps as needed */
404
+ ExecCreateExprSetupSteps (state , (Node * )targetList );
402
405
403
406
/* Now compile each tlist column */
404
407
foreach (lc ,targetList )
@@ -1119,6 +1122,21 @@ ExecInitExprRec(Expr *node, ExprState *state,
1119
1122
SubPlan * subplan = (SubPlan * )node ;
1120
1123
SubPlanState * sstate ;
1121
1124
1125
+ /*
1126
+ * Real execution of a MULTIEXPR SubPlan has already been
1127
+ * done. What we have to do here is return a dummy NULL record
1128
+ * value in case this targetlist element is assigned
1129
+ * someplace.
1130
+ */
1131
+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
1132
+ {
1133
+ scratch .opcode = EEOP_CONST ;
1134
+ scratch .d .constval .value = (Datum )0 ;
1135
+ scratch .d .constval .isnull = true;
1136
+ ExprEvalPushStep (state ,& scratch );
1137
+ break ;
1138
+ }
1139
+
1122
1140
if (!state -> parent )
1123
1141
elog (ERROR ,"SubPlan found with no parent plan" );
1124
1142
@@ -2287,36 +2305,38 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
2287
2305
}
2288
2306
2289
2307
/*
2290
- * Add expression stepsdeforming the ExprState 'sinner/outer/scan slots
2291
- *as much as required by the expression.
2308
+ * Add expression stepsperforming setup that 'sneeded before any of the
2309
+ *main execution of the expression.
2292
2310
*/
2293
2311
static void
2294
- ExecInitExprSlots (ExprState * state ,Node * node )
2312
+ ExecCreateExprSetupSteps (ExprState * state ,Node * node )
2295
2313
{
2296
- LastAttnumInfo info = {0 ,0 ,0 };
2314
+ ExprSetupInfo info = {0 ,0 ,0 , NIL };
2297
2315
2298
- /*
2299
- * Figure out which attributes we're going to need.
2300
- */
2301
- get_last_attnums_walker (node ,& info );
2316
+ /* Prescan to find out what we need. */
2317
+ expr_setup_walker (node ,& info );
2302
2318
2303
- ExecPushExprSlots (state ,& info );
2319
+ /* And generate those steps. */
2320
+ ExecPushExprSetupSteps (state ,& info );
2304
2321
}
2305
2322
2306
2323
/*
2307
- * Add steps deforming the ExprState's inner/out/scan slots as much as
2308
- * indicated by info. This is useful when building an ExprState covering more
2309
- * than one expression.
2324
+ * Add steps performing expression setup as indicated by "info".
2325
+ * This is useful when building an ExprState covering more than one expression.
2310
2326
*/
2311
2327
static void
2312
- ExecPushExprSlots (ExprState * state ,LastAttnumInfo * info )
2328
+ ExecPushExprSetupSteps (ExprState * state ,ExprSetupInfo * info )
2313
2329
{
2314
2330
ExprEvalStep scratch = {0 };
2331
+ ListCell * lc ;
2315
2332
2316
2333
scratch .resvalue = NULL ;
2317
2334
scratch .resnull = NULL ;
2318
2335
2319
- /* Emit steps as needed */
2336
+ /*
2337
+ * Add steps deforming the ExprState's inner/outer/scan slots as much as
2338
+ * required by any Vars appearing in the expression.
2339
+ */
2320
2340
if (info -> last_inner > 0 )
2321
2341
{
2322
2342
scratch .opcode = EEOP_INNER_FETCHSOME ;
@@ -2347,13 +2367,48 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
2347
2367
if (ExecComputeSlotInfo (state ,& scratch ))
2348
2368
ExprEvalPushStep (state ,& scratch );
2349
2369
}
2370
+
2371
+ /*
2372
+ * Add steps to execute any MULTIEXPR SubPlans appearing in the
2373
+ * expression. We need to evaluate these before any of the Params
2374
+ * referencing their outputs are used, but after we've prepared for any
2375
+ * Var references they may contain. (There cannot be cross-references
2376
+ * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2377
+ */
2378
+ foreach (lc ,info -> multiexpr_subplans )
2379
+ {
2380
+ SubPlan * subplan = (SubPlan * )lfirst (lc );
2381
+ SubPlanState * sstate ;
2382
+
2383
+ Assert (subplan -> subLinkType == MULTIEXPR_SUBLINK );
2384
+
2385
+ /* This should match what ExecInitExprRec does for other SubPlans: */
2386
+
2387
+ if (!state -> parent )
2388
+ elog (ERROR ,"SubPlan found with no parent plan" );
2389
+
2390
+ sstate = ExecInitSubPlan (subplan ,state -> parent );
2391
+
2392
+ /* add SubPlanState nodes to state->parent->subPlan */
2393
+ state -> parent -> subPlan = lappend (state -> parent -> subPlan ,
2394
+ sstate );
2395
+
2396
+ scratch .opcode = EEOP_SUBPLAN ;
2397
+ scratch .d .subplan .sstate = sstate ;
2398
+
2399
+ /* The result can be ignored, but we better put it somewhere */
2400
+ scratch .resvalue = & state -> resvalue ;
2401
+ scratch .resnull = & state -> resnull ;
2402
+
2403
+ ExprEvalPushStep (state ,& scratch );
2404
+ }
2350
2405
}
2351
2406
2352
2407
/*
2353
- *get_last_attnums_walker : expression walker forExecInitExprSlots
2408
+ *expr_setup_walker : expression walker forExecCreateExprSetupSteps
2354
2409
*/
2355
2410
static bool
2356
- get_last_attnums_walker (Node * node ,LastAttnumInfo * info )
2411
+ expr_setup_walker (Node * node ,ExprSetupInfo * info )
2357
2412
{
2358
2413
if (node == NULL )
2359
2414
return false;
@@ -2381,6 +2436,16 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
2381
2436
return false;
2382
2437
}
2383
2438
2439
+ /* Collect all MULTIEXPR SubPlans, too */
2440
+ if (IsA (node ,SubPlan ))
2441
+ {
2442
+ SubPlan * subplan = (SubPlan * )node ;
2443
+
2444
+ if (subplan -> subLinkType == MULTIEXPR_SUBLINK )
2445
+ info -> multiexpr_subplans = lappend (info -> multiexpr_subplans ,
2446
+ subplan );
2447
+ }
2448
+
2384
2449
/*
2385
2450
* Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2386
2451
* because those do not represent expressions to be evaluated within the
@@ -2393,7 +2458,7 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
2393
2458
return false;
2394
2459
if (IsA (node ,GroupingFunc ))
2395
2460
return false;
2396
- return expression_tree_walker (node ,get_last_attnums_walker ,
2461
+ return expression_tree_walker (node ,expr_setup_walker ,
2397
2462
(void * )info );
2398
2463
}
2399
2464
@@ -2985,7 +3050,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
2985
3050
PlanState * parent = & aggstate -> ss .ps ;
2986
3051
ExprEvalStep scratch = {0 };
2987
3052
bool isCombine = DO_AGGSPLIT_COMBINE (aggstate -> aggsplit );
2988
- LastAttnumInfo deform = {0 ,0 ,0 };
3053
+ ExprSetupInfo deform = {0 ,0 ,0 , NIL };
2989
3054
2990
3055
state -> expr = (Expr * )aggstate ;
2991
3056
state -> parent = parent ;
@@ -3001,18 +3066,18 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
3001
3066
{
3002
3067
AggStatePerTrans pertrans = & aggstate -> pertrans [transno ];
3003
3068
3004
- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3005
- & deform );
3006
- get_last_attnums_walker ((Node * )pertrans -> aggref -> args ,
3007
- & deform );
3008
- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggorder ,
3009
- & deform );
3010
- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3011
- & deform );
3012
- get_last_attnums_walker ((Node * )pertrans -> aggref -> aggfilter ,
3013
- & deform );
3069
+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdirectargs ,
3070
+ & deform );
3071
+ expr_setup_walker ((Node * )pertrans -> aggref -> args ,
3072
+ & deform );
3073
+ expr_setup_walker ((Node * )pertrans -> aggref -> aggorder ,
3074
+ & deform );
3075
+ expr_setup_walker ((Node * )pertrans -> aggref -> aggdistinct ,
3076
+ & deform );
3077
+ expr_setup_walker ((Node * )pertrans -> aggref -> aggfilter ,
3078
+ & deform );
3014
3079
}
3015
- ExecPushExprSlots (state ,& deform );
3080
+ ExecPushExprSetupSteps (state ,& deform );
3016
3081
3017
3082
/*
3018
3083
* Emit instructions for each transition value / grouping set combination.