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