Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita7f107d

Browse files
committed
Evaluate arguments of correlated SubPlans in the referencing ExprState
Until now we generated an ExprState for each parameter to a SubPlan andevaluated them one-by-one ExecScanSubPlan. That's sub-optimal as creating lotsof small ExprStatesa) makes JIT compilation more expensiveb) wastes memoryc) is a bit slower to executeThis commit arranges to evaluate parameters to a SubPlan as part of theExprState referencing a SubPlan, using the new EEOP_PARAM_SET expressionstep. We emit one EEOP_PARAM_SET for each argument to a subplan, just beforethe EEOP_SUBPLAN step.It likely is worth using EEOP_PARAM_SET in other places as well, e.g. forSubPlan outputs, nestloop parameters and - more ambitiously - to get rid ofExprContext->domainValue/caseValue/ecxt_agg*. But that's for later.Author: Andres Freund <andres@anarazel.de>Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>Reviewed-by: Alena Rybakina <lena.ribackina@yandex.ru>Discussion:https://postgr.es/m/20230225214401.346ancgjqc3zmvek@awork3.anarazel.de
1 parente6a9637 commita7f107d

File tree

8 files changed

+125
-52
lines changed

8 files changed

+125
-52
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ static void ExecInitExprRec(Expr *node, ExprState *state,
6969
staticvoidExecInitFunc(ExprEvalStep*scratch,Expr*node,List*args,
7070
Oidfuncid,Oidinputcollid,
7171
ExprState*state);
72+
staticvoidExecInitSubPlanExpr(SubPlan*subplan,
73+
ExprState*state,
74+
Datum*resv,bool*resnull);
7275
staticvoidExecCreateExprSetupSteps(ExprState*state,Node*node);
7376
staticvoidExecPushExprSetupSteps(ExprState*state,ExprSetupInfo*info);
7477
staticboolexpr_setup_walker(Node*node,ExprSetupInfo*info);
@@ -1406,7 +1409,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
14061409
caseT_SubPlan:
14071410
{
14081411
SubPlan*subplan= (SubPlan*)node;
1409-
SubPlanState*sstate;
14101412

14111413
/*
14121414
* Real execution of a MULTIEXPR SubPlan has already been
@@ -1423,19 +1425,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
14231425
break;
14241426
}
14251427

1426-
if (!state->parent)
1427-
elog(ERROR,"SubPlan found with no parent plan");
1428-
1429-
sstate=ExecInitSubPlan(subplan,state->parent);
1430-
1431-
/* add SubPlanState nodes to state->parent->subPlan */
1432-
state->parent->subPlan=lappend(state->parent->subPlan,
1433-
sstate);
1434-
1435-
scratch.opcode=EEOP_SUBPLAN;
1436-
scratch.d.subplan.sstate=sstate;
1437-
1438-
ExprEvalPushStep(state,&scratch);
1428+
ExecInitSubPlanExpr(subplan,state,resv,resnull);
14391429
break;
14401430
}
14411431

@@ -2715,6 +2705,70 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
27152705
}
27162706
}
27172707

2708+
/*
2709+
* Append the steps necessary for the evaluation of a SubPlan node to
2710+
* ExprState->steps.
2711+
*
2712+
* subplan - SubPlan expression to evaluate
2713+
* state - ExprState to whose ->steps to append the necessary operations
2714+
* resv / resnull - where to store the result of the node into
2715+
*/
2716+
staticvoid
2717+
ExecInitSubPlanExpr(SubPlan*subplan,
2718+
ExprState*state,
2719+
Datum*resv,bool*resnull)
2720+
{
2721+
ExprEvalStepscratch= {0};
2722+
SubPlanState*sstate;
2723+
ListCell*pvar;
2724+
ListCell*l;
2725+
2726+
if (!state->parent)
2727+
elog(ERROR,"SubPlan found with no parent plan");
2728+
2729+
/*
2730+
* Generate steps to evaluate input arguments for the subplan.
2731+
*
2732+
* We evaluate the argument expressions into ExprState's resvalue/resnull,
2733+
* and then use PARAM_SET to update the parameter. We do that, instead of
2734+
* evaluating directly into the param, to avoid depending on the pointer
2735+
* value remaining stable / being included in the generated expression. No
2736+
* danger of conflicts with other uses of resvalue/resnull as storing and
2737+
* using the value always is in subsequent steps.
2738+
*
2739+
* Any calculation we have to do can be done in the parent econtext, since
2740+
* the Param values don't need to have per-query lifetime.
2741+
*/
2742+
Assert(list_length(subplan->parParam)==list_length(subplan->args));
2743+
forboth(l,subplan->parParam,pvar,subplan->args)
2744+
{
2745+
intparamid=lfirst_int(l);
2746+
Expr*arg= (Expr*)lfirst(pvar);
2747+
2748+
ExecInitExprRec(arg,state,
2749+
&state->resvalue,&state->resnull);
2750+
2751+
scratch.opcode=EEOP_PARAM_SET;
2752+
scratch.d.param.paramid=paramid;
2753+
/* paramtype's not actually used, but we might as well fill it */
2754+
scratch.d.param.paramtype=exprType((Node*)arg);
2755+
ExprEvalPushStep(state,&scratch);
2756+
}
2757+
2758+
sstate=ExecInitSubPlan(subplan,state->parent);
2759+
2760+
/* add SubPlanState nodes to state->parent->subPlan */
2761+
state->parent->subPlan=lappend(state->parent->subPlan,
2762+
sstate);
2763+
2764+
scratch.opcode=EEOP_SUBPLAN;
2765+
scratch.resvalue=resv;
2766+
scratch.resnull=resnull;
2767+
scratch.d.subplan.sstate=sstate;
2768+
2769+
ExprEvalPushStep(state,&scratch);
2770+
}
2771+
27182772
/*
27192773
* Add expression steps performing setup that's needed before any of the
27202774
* main execution of the expression.
@@ -2789,29 +2843,12 @@ ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
27892843
foreach(lc,info->multiexpr_subplans)
27902844
{
27912845
SubPlan*subplan= (SubPlan*)lfirst(lc);
2792-
SubPlanState*sstate;
27932846

27942847
Assert(subplan->subLinkType==MULTIEXPR_SUBLINK);
27952848

2796-
/* This should match what ExecInitExprRec does for other SubPlans: */
2797-
2798-
if (!state->parent)
2799-
elog(ERROR,"SubPlan found with no parent plan");
2800-
2801-
sstate=ExecInitSubPlan(subplan,state->parent);
2802-
2803-
/* add SubPlanState nodes to state->parent->subPlan */
2804-
state->parent->subPlan=lappend(state->parent->subPlan,
2805-
sstate);
2806-
2807-
scratch.opcode=EEOP_SUBPLAN;
2808-
scratch.d.subplan.sstate=sstate;
2809-
28102849
/* The result can be ignored, but we better put it somewhere */
2811-
scratch.resvalue=&state->resvalue;
2812-
scratch.resnull=&state->resnull;
2813-
2814-
ExprEvalPushStep(state,&scratch);
2850+
ExecInitSubPlanExpr(subplan,state,
2851+
&state->resvalue,&state->resnull);
28152852
}
28162853
}
28172854

‎src/backend/executor/execExprInterp.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
450450
&&CASE_EEOP_PARAM_EXEC,
451451
&&CASE_EEOP_PARAM_EXTERN,
452452
&&CASE_EEOP_PARAM_CALLBACK,
453+
&&CASE_EEOP_PARAM_SET,
453454
&&CASE_EEOP_CASE_TESTVAL,
454455
&&CASE_EEOP_MAKE_READONLY,
455456
&&CASE_EEOP_IOCOERCE,
@@ -1093,6 +1094,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
10931094
EEO_NEXT();
10941095
}
10951096

1097+
EEO_CASE(EEOP_PARAM_SET)
1098+
{
1099+
/* out of line, unlikely to matter performancewise */
1100+
ExecEvalParamSet(state,op,econtext);
1101+
EEO_NEXT();
1102+
}
1103+
10961104
EEO_CASE(EEOP_CASE_TESTVAL)
10971105
{
10981106
/*
@@ -2555,6 +2563,24 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
25552563
errmsg("no value found for parameter %d",paramId)));
25562564
}
25572565

2566+
/*
2567+
* Set value of a param (currently always PARAM_EXEC) from
2568+
* state->res{value,null}.
2569+
*/
2570+
void
2571+
ExecEvalParamSet(ExprState*state,ExprEvalStep*op,ExprContext*econtext)
2572+
{
2573+
ParamExecData*prm;
2574+
2575+
prm=&(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
2576+
2577+
/* Shouldn't have a pending evaluation anymore */
2578+
Assert(prm->execPlan==NULL);
2579+
2580+
prm->value=state->resvalue;
2581+
prm->isnull=state->resnull;
2582+
}
2583+
25582584
/*
25592585
* Evaluate a CoerceViaIO node in soft-error mode.
25602586
*

‎src/backend/executor/execProcnode.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
393393
/*
394394
* Initialize any initPlans present in this node. The planner put them in
395395
* a separate list for us.
396+
*
397+
* The defining characteristic of initplans is that they don't have
398+
* arguments, so we don't need to evaluate them (in contrast to
399+
* ExecInitSubPlanExpr()).
396400
*/
397401
subps=NIL;
398402
foreach(l,node->initPlan)
@@ -401,6 +405,7 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
401405
SubPlanState*sstate;
402406

403407
Assert(IsA(subplan,SubPlan));
408+
Assert(subplan->args==NIL);
404409
sstate=ExecInitSubPlan(subplan,result);
405410
subps=lappend(subps,sstate);
406411
}

‎src/backend/executor/nodeSubplan.c

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ ExecHashSubPlan(SubPlanState *node,
107107
TupleTableSlot*slot;
108108

109109
/* Shouldn't have any direct correlation Vars */
110-
if (subplan->parParam!=NIL||node->args!=NIL)
110+
if (subplan->parParam!=NIL||subplan->args!=NIL)
111111
elog(ERROR,"hashed subplan with direct correlation not supported");
112112

113113
/*
@@ -231,7 +231,6 @@ ExecScanSubPlan(SubPlanState *node,
231231
TupleTableSlot*slot;
232232
Datumresult;
233233
boolfound= false;/* true if got at least one subplan tuple */
234-
ListCell*pvar;
235234
ListCell*l;
236235
ArrayBuildStateAny*astate=NULL;
237236

@@ -248,26 +247,19 @@ ExecScanSubPlan(SubPlanState *node,
248247
oldcontext=MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
249248

250249
/*
251-
* Set Params of this plan from parent plan correlation values. (Any
252-
* calculation we have to do is done in the parent econtext, since the
253-
* Param values don't need to have per-query lifetime.)
250+
* We rely on the caller to evaluate plan correlation values, if
251+
* necessary. However we still need to record the fact that the values
252+
* (might have) changed, otherwise the ExecReScan() below won't know that
253+
* nodes need to be rescanned.
254254
*/
255-
Assert(list_length(subplan->parParam)==list_length(node->args));
256-
257-
forboth(l,subplan->parParam,pvar,node->args)
255+
foreach(l,subplan->parParam)
258256
{
259257
intparamid=lfirst_int(l);
260-
ParamExecData*prm=&(econtext->ecxt_param_exec_vals[paramid]);
261258

262-
prm->value=ExecEvalExprSwitchContext((ExprState*)lfirst(pvar),
263-
econtext,
264-
&(prm->isnull));
265259
planstate->chgParam=bms_add_member(planstate->chgParam,paramid);
266260
}
267261

268-
/*
269-
* Now that we've set up its parameters, we can reset the subplan.
270-
*/
262+
/* with that done, we can reset the subplan */
271263
ExecReScan(planstate);
272264

273265
/*
@@ -817,6 +809,10 @@ slotNoNulls(TupleTableSlot *slot)
817809
* as well as regular SubPlans. Note that we don't link the SubPlan into
818810
* the parent's subPlan list, because that shouldn't happen for InitPlans.
819811
* Instead, ExecInitExpr() does that one part.
812+
*
813+
* We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
814+
* evaluate input parameters, as that allows them to be evaluated as part of
815+
* the expression referencing the SubPlan.
820816
* ----------------------------------------------------------------
821817
*/
822818
SubPlanState*
@@ -844,7 +840,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
844840

845841
/* Initialize subexpressions */
846842
sstate->testexpr=ExecInitExpr((Expr*)subplan->testexpr,parent);
847-
sstate->args=ExecInitExprList(subplan->args,parent);
848843

849844
/*
850845
* initialize my state
@@ -1107,7 +1102,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
11071102
elog(ERROR,"ANY/ALL subselect unsupported as initplan");
11081103
if (subLinkType==CTE_SUBLINK)
11091104
elog(ERROR,"CTE subplans should not be executed via ExecSetParamPlan");
1110-
if (subplan->parParam||node->args)
1105+
if (subplan->parParam||subplan->args)
11111106
elog(ERROR,"correlated subplans should not be executed via ExecSetParamPlan");
11121107

11131108
/*

‎src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,12 @@ llvm_compile_expr(ExprState *state)
11451145
break;
11461146
}
11471147

1148+
caseEEOP_PARAM_SET:
1149+
build_EvalXFunc(b,mod,"ExecEvalParamSet",
1150+
v_state,op,v_econtext);
1151+
LLVMBuildBr(b,opblocks[opno+1]);
1152+
break;
1153+
11481154
caseEEOP_SBSREF_SUBSCRIPTS:
11491155
{
11501156
intjumpdone=op->d.sbsref_subscript.jumpdone;

‎src/backend/jit/llvm/llvmjit_types.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ void *referenced_functions[] =
160160
ExecEvalNextValueExpr,
161161
ExecEvalParamExec,
162162
ExecEvalParamExtern,
163+
ExecEvalParamSet,
163164
ExecEvalRow,
164165
ExecEvalRowNotNull,
165166
ExecEvalRowNull,

‎src/include/executor/execExpr.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ typedef enum ExprEvalOp
160160
EEOP_PARAM_EXEC,
161161
EEOP_PARAM_EXTERN,
162162
EEOP_PARAM_CALLBACK,
163+
/* set PARAM_EXEC value */
164+
EEOP_PARAM_SET,
163165

164166
/* return CaseTestExpr value */
165167
EEOP_CASE_TESTVAL,
@@ -384,7 +386,7 @@ typedef struct ExprEvalStep
384386
ExprEvalRowtypeCacherowcache;
385387
}nulltest_row;
386388

387-
/* for EEOP_PARAM_EXEC/EXTERN */
389+
/* for EEOP_PARAM_EXEC/EXTERNand EEOP_PARAM_SET*/
388390
struct
389391
{
390392
intparamid;/* numeric ID for parameter */
@@ -800,6 +802,8 @@ extern void ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
800802
ExprContext*econtext);
801803
externvoidExecEvalParamExec(ExprState*state,ExprEvalStep*op,
802804
ExprContext*econtext);
805+
externvoidExecEvalParamSet(ExprState*state,ExprEvalStep*op,
806+
ExprContext*econtext);
803807
externvoidExecEvalParamExtern(ExprState*state,ExprEvalStep*op,
804808
ExprContext*econtext);
805809
externvoidExecEvalCoerceViaIOSafe(ExprState*state,ExprEvalStep*op);

‎src/include/nodes/execnodes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,6 @@ typedef struct SubPlanState
961961
structPlanState*planstate;/* subselect plan's state tree */
962962
structPlanState*parent;/* parent plan node's state tree */
963963
ExprState*testexpr;/* state of combining expression */
964-
List*args;/* states of argument expression(s) */
965964
HeapTuplecurTuple;/* copy of most recent tuple from subplan */
966965
DatumcurArray;/* most recent array from ARRAY() subplan */
967966
/* these are used when hashing the subselect's output: */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp