Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5bdd18e

Browse files
author
Commitfest Bot
committed
[CF 4627] v4 - Special-case executor expression steps for common combinations
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/4627 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/E58D7259-CFCF-4430-A71D-A6E909A590EF@yesql.se Author(s): Andres Freund, Daniel Gustafsson
2 parents dabccf4 + da16b2b commit 5bdd18e

File tree

7 files changed

+194
-39
lines changed

7 files changed

+194
-39
lines changed

src/backend/executor/README

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,14 @@ is used by the function evaluation step, thus avoiding extra work to copy
133133
the result values around.
134134

135135
The last entry in a completed ExprState->steps array is always an
136-
EEOP_DONE step; this removes the need to test for end-of-array while
137-
iterating. Also, if the expression contains any variable references (to
138-
user columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
136+
EEOP_DONE_RETURN or EEOP_DONE_NO_RETURN step; this removes the need to
137+
test for end-of-array while iterating. The former is used when the
138+
expression returns a value directly, the latter when side-effects of
139+
expression initialization are the goal (e.g. for projection or
140+
aggregate transition value computation).
141+
142+
Also, if the expression contains any variable references (to user
143+
columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
139144
array begins with EEOP_*_FETCHSOME steps that ensure that the relevant
140145
tuples have been deconstructed to make the required columns directly
141146
available (cf. slot_getsomeattrs()). This allows individual Var-fetching

src/backend/executor/execExpr.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* using ExecInitExpr() et al. This converts the tree into a flat array
99
* of ExprEvalSteps, which may be thought of as instructions in a program.
1010
* At runtime, we'll execute steps, starting with the first, until we reach
11-
* an EEOP_DONE opcode.
11+
* an EEOP_DONE_{RETURN|NO_RETURN} opcode.
1212
*
1313
* This file contains the "compilation" logic. It is independent of the
1414
* specific execution technology we use (switch statement, computed goto,
@@ -162,7 +162,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
162162
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
163163

164164
/* Finally, append a DONE step */
165-
scratch.opcode = EEOP_DONE;
165+
scratch.opcode = EEOP_DONE_RETURN;
166166
ExprEvalPushStep(state, &scratch);
167167

168168
ExecReadyExpr(state);
@@ -199,7 +199,7 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
199199
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
200200

201201
/* Finally, append a DONE step */
202-
scratch.opcode = EEOP_DONE;
202+
scratch.opcode = EEOP_DONE_RETURN;
203203
ExprEvalPushStep(state, &scratch);
204204

205205
ExecReadyExpr(state);
@@ -291,7 +291,7 @@ ExecInitQual(List *qual, PlanState *parent)
291291
* have yielded TRUE, and since its result is stored in the desired output
292292
* location, we're done.
293293
*/
294-
scratch.opcode = EEOP_DONE;
294+
scratch.opcode = EEOP_DONE_RETURN;
295295
ExprEvalPushStep(state, &scratch);
296296

297297
ExecReadyExpr(state);
@@ -503,7 +503,7 @@ ExecBuildProjectionInfo(List *targetList,
503503
}
504504
}
505505

506-
scratch.opcode = EEOP_DONE;
506+
scratch.opcode = EEOP_DONE_NO_RETURN;
507507
ExprEvalPushStep(state, &scratch);
508508

509509
ExecReadyExpr(state);
@@ -742,7 +742,7 @@ ExecBuildUpdateProjection(List *targetList,
742742
}
743743
}
744744

745-
scratch.opcode = EEOP_DONE;
745+
scratch.opcode = EEOP_DONE_NO_RETURN;
746746
ExprEvalPushStep(state, &scratch);
747747

748748
ExecReadyExpr(state);
@@ -1714,7 +1714,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
17141714
else
17151715
{
17161716
/* Not trivial, so append a DONE step */
1717-
scratch.opcode = EEOP_DONE;
1717+
scratch.opcode = EEOP_DONE_RETURN;
17181718
ExprEvalPushStep(elemstate, &scratch);
17191719
/* and ready the subexpression */
17201720
ExecReadyExpr(elemstate);
@@ -2788,7 +2788,15 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
27882788
if (pgstat_track_functions <= flinfo->fn_stats)
27892789
{
27902790
if (flinfo->fn_strict && nargs > 0)
2791-
scratch->opcode = EEOP_FUNCEXPR_STRICT;
2791+
{
2792+
/* Choose nargs optimized implementation if available. */
2793+
if (nargs == 1)
2794+
scratch->opcode = EEOP_FUNCEXPR_STRICT_1;
2795+
else if (nargs == 2)
2796+
scratch->opcode = EEOP_FUNCEXPR_STRICT_2;
2797+
else
2798+
scratch->opcode = EEOP_FUNCEXPR_STRICT;
2799+
}
27922800
else
27932801
scratch->opcode = EEOP_FUNCEXPR;
27942802
}
@@ -3892,6 +3900,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
38923900
{
38933901
if (strictnulls)
38943902
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS;
3903+
else if (strictargs && pertrans->numTransInputs == 1)
3904+
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1;
38953905
else
38963906
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS;
38973907
scratch.d.agg_strict_input_check.nulls = strictnulls;
@@ -3968,6 +3978,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
39683978
as->d.jump.jumpdone = state->steps_len;
39693979
}
39703980
else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3981+
as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 ||
39713982
as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
39723983
{
39733984
Assert(as->d.agg_strict_input_check.jumpnull == -1);
@@ -3991,7 +4002,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
39914002

39924003
scratch.resvalue = NULL;
39934004
scratch.resnull = NULL;
3994-
scratch.opcode = EEOP_DONE;
4005+
scratch.opcode = EEOP_DONE_NO_RETURN;
39954006
ExprEvalPushStep(state, &scratch);
39964007

39974008
ExecReadyExpr(state);
@@ -4258,7 +4269,7 @@ ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops,
42584269

42594270
scratch.resvalue = NULL;
42604271
scratch.resnull = NULL;
4261-
scratch.opcode = EEOP_DONE;
4272+
scratch.opcode = EEOP_DONE_RETURN;
42624273
ExprEvalPushStep(state, &scratch);
42634274

42644275
ExecReadyExpr(state);
@@ -4431,7 +4442,7 @@ ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops,
44314442

44324443
scratch.resvalue = NULL;
44334444
scratch.resnull = NULL;
4434-
scratch.opcode = EEOP_DONE;
4445+
scratch.opcode = EEOP_DONE_RETURN;
44354446
ExprEvalPushStep(state, &scratch);
44364447

44374448
ExecReadyExpr(state);
@@ -4586,7 +4597,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
45864597

45874598
scratch.resvalue = NULL;
45884599
scratch.resnull = NULL;
4589-
scratch.opcode = EEOP_DONE;
4600+
scratch.opcode = EEOP_DONE_RETURN;
45904601
ExprEvalPushStep(state, &scratch);
45914602

45924603
ExecReadyExpr(state);
@@ -4722,7 +4733,7 @@ ExecBuildParamSetEqual(TupleDesc desc,
47224733

47234734
scratch.resvalue = NULL;
47244735
scratch.resnull = NULL;
4725-
scratch.opcode = EEOP_DONE;
4736+
scratch.opcode = EEOP_DONE_RETURN;
47264737
ExprEvalPushStep(state, &scratch);
47274738

47284739
ExecReadyExpr(state);

src/backend/executor/execExprInterp.c

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ ExecReadyInterpretedExpr(ExprState *state)
246246

247247
/* Simple validity checks on expression */
248248
Assert(state->steps_len >= 1);
249-
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
249+
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE_RETURN ||
250+
state->steps[state->steps_len - 1].opcode == EEOP_DONE_NO_RETURN);
250251

251252
/*
252253
* Don't perform redundant initialization. This is unreachable in current
@@ -365,7 +366,9 @@ ExecReadyInterpretedExpr(ExprState *state)
365366
return;
366367
}
367368
else if (step0 == EEOP_CASE_TESTVAL &&
368-
step1 == EEOP_FUNCEXPR_STRICT)
369+
(step1 == EEOP_FUNCEXPR_STRICT ||
370+
step1 == EEOP_FUNCEXPR_STRICT_1 ||
371+
step1 == EEOP_FUNCEXPR_STRICT_2))
369372
{
370373
state->evalfunc_private = ExecJustApplyFuncToCase;
371374
return;
@@ -469,7 +472,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
469472
*/
470473
#if defined(EEO_USE_COMPUTED_GOTO)
471474
static const void *const dispatch_table[] = {
472-
&&CASE_EEOP_DONE,
475+
&&CASE_EEOP_DONE_RETURN,
476+
&&CASE_EEOP_DONE_NO_RETURN,
473477
&&CASE_EEOP_INNER_FETCHSOME,
474478
&&CASE_EEOP_OUTER_FETCHSOME,
475479
&&CASE_EEOP_SCAN_FETCHSOME,
@@ -496,6 +500,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
496500
&&CASE_EEOP_CONST,
497501
&&CASE_EEOP_FUNCEXPR,
498502
&&CASE_EEOP_FUNCEXPR_STRICT,
503+
&&CASE_EEOP_FUNCEXPR_STRICT_1,
504+
&&CASE_EEOP_FUNCEXPR_STRICT_2,
499505
&&CASE_EEOP_FUNCEXPR_FUSAGE,
500506
&&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
501507
&&CASE_EEOP_BOOL_AND_STEP_FIRST,
@@ -573,6 +579,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
573579
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
574580
&&CASE_EEOP_AGG_DESERIALIZE,
575581
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
582+
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,
576583
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
577584
&&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
578585
&&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
@@ -612,9 +619,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
612619

613620
EEO_SWITCH()
614621
{
615-
EEO_CASE(EEOP_DONE)
622+
EEO_CASE(EEOP_DONE_RETURN)
616623
{
617-
goto out;
624+
*isnull = state->resnull;
625+
return state->resvalue;
626+
}
627+
628+
EEO_CASE(EEOP_DONE_NO_RETURN)
629+
{
630+
Assert(isnull == NULL);
631+
return (Datum) 0;
618632
}
619633

620634
EEO_CASE(EEOP_INNER_FETCHSOME)
@@ -916,13 +930,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
916930
EEO_NEXT();
917931
}
918932

933+
/* strict function call with more than two arguments */
919934
EEO_CASE(EEOP_FUNCEXPR_STRICT)
920935
{
921936
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
922937
NullableDatum *args = fcinfo->args;
923938
int nargs = op->d.func.nargs;
924939
Datum d;
925940

941+
Assert(nargs > 2);
942+
926943
/* strict function, so check for NULL args */
927944
for (int argno = 0; argno < nargs; argno++)
928945
{
@@ -941,6 +958,54 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
941958
EEO_NEXT();
942959
}
943960

961+
/* strict function call with one argument */
962+
EEO_CASE(EEOP_FUNCEXPR_STRICT_1)
963+
{
964+
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
965+
NullableDatum *args = fcinfo->args;
966+
967+
Assert(op->d.func.nargs == 1);
968+
969+
/* strict function, so check for NULL args */
970+
if (args[0].isnull)
971+
*op->resnull = true;
972+
else
973+
{
974+
Datum d;
975+
976+
fcinfo->isnull = false;
977+
d = op->d.func.fn_addr(fcinfo);
978+
*op->resvalue = d;
979+
*op->resnull = fcinfo->isnull;
980+
}
981+
982+
EEO_NEXT();
983+
}
984+
985+
/* strict function call with two arguments */
986+
EEO_CASE(EEOP_FUNCEXPR_STRICT_2)
987+
{
988+
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
989+
NullableDatum *args = fcinfo->args;
990+
991+
Assert(op->d.func.nargs == 2);
992+
993+
/* strict function, so check for NULL args */
994+
if (args[0].isnull || args[1].isnull)
995+
*op->resnull = true;
996+
else
997+
{
998+
Datum d;
999+
1000+
fcinfo->isnull = false;
1001+
d = op->d.func.fn_addr(fcinfo);
1002+
*op->resvalue = d;
1003+
*op->resnull = fcinfo->isnull;
1004+
}
1005+
1006+
EEO_NEXT();
1007+
}
1008+
9441009
EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
9451010
{
9461011
/* not common enough to inline */
@@ -1973,11 +2038,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
19732038
* input is not NULL.
19742039
*/
19752040

2041+
/* when checking more than one argument */
19762042
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
19772043
{
19782044
NullableDatum *args = op->d.agg_strict_input_check.args;
19792045
int nargs = op->d.agg_strict_input_check.nargs;
19802046

2047+
Assert(nargs > 1);
2048+
19812049
for (int argno = 0; argno < nargs; argno++)
19822050
{
19832051
if (args[argno].isnull)
@@ -1986,6 +2054,19 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
19862054
EEO_NEXT();
19872055
}
19882056

2057+
/* special case for just one argument */
2058+
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1)
2059+
{
2060+
NullableDatum *args = op->d.agg_strict_input_check.args;
2061+
PG_USED_FOR_ASSERTS_ONLY int nargs = op->d.agg_strict_input_check.nargs;
2062+
2063+
Assert(nargs == 1);
2064+
2065+
if (args[0].isnull)
2066+
EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
2067+
EEO_NEXT();
2068+
}
2069+
19892070
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
19902071
{
19912072
bool *nulls = op->d.agg_strict_input_check.nulls;
@@ -2188,13 +2269,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
21882269
{
21892270
/* unreachable */
21902271
Assert(false);
2191-
goto out;
2272+
goto out_error;
21922273
}
21932274
}
21942275

2195-
out:
2196-
*isnull = state->resnull;
2197-
return state->resvalue;
2276+
out_error:
2277+
pg_unreachable();
2278+
return (Datum) 0;
21982279
}
21992280

22002281
/*

src/backend/executor/nodeAgg.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -816,11 +816,8 @@ advance_transition_function(AggState *aggstate,
816816
static void
817817
advance_aggregates(AggState *aggstate)
818818
{
819-
bool dummynull;
820-
821-
ExecEvalExprSwitchContext(aggstate->phase->evaltrans,
822-
aggstate->tmpcontext,
823-
&dummynull);
819+
ExecEvalExprNoReturnSwitchContext(aggstate->phase->evaltrans,
820+
aggstate->tmpcontext);
824821
}
825822

826823
/*

0 commit comments

Comments
 (0)