Skip to content

Commit d35d32d

Browse files
Add special case fast-paths for strict functions
Many STRICT function calls will have one or two arguments, in which case we can speed up checking for NULL input by avoiding setting up a loop over the arguments. This adds EEOP_FUNCEXPR_STRICT_1 and the corresponding EEOP_FUNCEXPR_STRICT_2 for functions with one and two arguments respectively. Author: Andres Freund <andres@anarazel.de> Co-authored-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Andreas Karlsson <andreas@proxel.se> Discussion: https://postgr.es/m/415721CE-7D2E-4B74-B5D9-1950083BA03E@yesql.se Discussion: https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de
1 parent 8dd7c7c commit d35d32d

File tree

4 files changed

+96
-5
lines changed

4 files changed

+96
-5
lines changed

src/backend/executor/execExpr.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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);

src/backend/executor/execExprInterp.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,9 @@ ExecReadyInterpretedExpr(ExprState *state)
366366
return;
367367
}
368368
else if (step0 == EEOP_CASE_TESTVAL &&
369-
step1 == EEOP_FUNCEXPR_STRICT)
369+
(step1 == EEOP_FUNCEXPR_STRICT ||
370+
step1 == EEOP_FUNCEXPR_STRICT_1 ||
371+
step1 == EEOP_FUNCEXPR_STRICT_2))
370372
{
371373
state->evalfunc_private = ExecJustApplyFuncToCase;
372374
return;
@@ -498,6 +500,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
498500
&&CASE_EEOP_CONST,
499501
&&CASE_EEOP_FUNCEXPR,
500502
&&CASE_EEOP_FUNCEXPR_STRICT,
503+
&&CASE_EEOP_FUNCEXPR_STRICT_1,
504+
&&CASE_EEOP_FUNCEXPR_STRICT_2,
501505
&&CASE_EEOP_FUNCEXPR_FUSAGE,
502506
&&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
503507
&&CASE_EEOP_BOOL_AND_STEP_FIRST,
@@ -575,6 +579,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
575579
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
576580
&&CASE_EEOP_AGG_DESERIALIZE,
577581
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
582+
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,
578583
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
579584
&&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
580585
&&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
@@ -925,13 +930,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
925930
EEO_NEXT();
926931
}
927932

933+
/* strict function call with more than two arguments */
928934
EEO_CASE(EEOP_FUNCEXPR_STRICT)
929935
{
930936
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
931937
NullableDatum *args = fcinfo->args;
932938
int nargs = op->d.func.nargs;
933939
Datum d;
934940

941+
Assert(nargs > 2);
942+
935943
/* strict function, so check for NULL args */
936944
for (int argno = 0; argno < nargs; argno++)
937945
{
@@ -950,6 +958,54 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
950958
EEO_NEXT();
951959
}
952960

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+
9531009
EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
9541010
{
9551011
/* not common enough to inline */
@@ -1982,11 +2038,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
19822038
* input is not NULL.
19832039
*/
19842040

2041+
/* when checking more than one argument */
19852042
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
19862043
{
19872044
NullableDatum *args = op->d.agg_strict_input_check.args;
19882045
int nargs = op->d.agg_strict_input_check.nargs;
19892046

2047+
Assert(nargs > 1);
2048+
19902049
for (int argno = 0; argno < nargs; argno++)
19912050
{
19922051
if (args[argno].isnull)
@@ -1995,6 +2054,19 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
19952054
EEO_NEXT();
19962055
}
19972056

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+
19982070
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
19992071
{
20002072
bool *nulls = op->d.agg_strict_input_check.nulls;

src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,12 +662,16 @@ llvm_compile_expr(ExprState *state)
662662

663663
case EEOP_FUNCEXPR:
664664
case EEOP_FUNCEXPR_STRICT:
665+
case EEOP_FUNCEXPR_STRICT_1:
666+
case EEOP_FUNCEXPR_STRICT_2:
665667
{
666668
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
667669
LLVMValueRef v_fcinfo_isnull;
668670
LLVMValueRef v_retval;
669671

670-
if (opcode == EEOP_FUNCEXPR_STRICT)
672+
if (opcode == EEOP_FUNCEXPR_STRICT ||
673+
opcode == EEOP_FUNCEXPR_STRICT_1 ||
674+
opcode == EEOP_FUNCEXPR_STRICT_2)
671675
{
672676
LLVMBasicBlockRef b_nonull;
673677
LLVMBasicBlockRef *b_checkargnulls;
@@ -2482,6 +2486,7 @@ llvm_compile_expr(ExprState *state)
24822486
}
24832487

24842488
case EEOP_AGG_STRICT_INPUT_CHECK_ARGS:
2489+
case EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1:
24852490
case EEOP_AGG_STRICT_INPUT_CHECK_NULLS:
24862491
{
24872492
int nargs = op->d.agg_strict_input_check.nargs;

src/include/executor/execExpr.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ typedef enum ExprEvalOp
116116

117117
/*
118118
* Evaluate function call (including OpExprs etc). For speed, we
119-
* distinguish in the opcode whether the function is strict and/or
120-
* requires usage stats tracking.
119+
* distinguish in the opcode whether the function is strict with 1, 2, or
120+
* more arguments and/or requires usage stats tracking.
121121
*/
122122
EEOP_FUNCEXPR,
123123
EEOP_FUNCEXPR_STRICT,
124+
EEOP_FUNCEXPR_STRICT_1,
125+
EEOP_FUNCEXPR_STRICT_2,
124126
EEOP_FUNCEXPR_FUSAGE,
125127
EEOP_FUNCEXPR_STRICT_FUSAGE,
126128

@@ -276,6 +278,7 @@ typedef enum ExprEvalOp
276278
EEOP_AGG_STRICT_DESERIALIZE,
277279
EEOP_AGG_DESERIALIZE,
278280
EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
281+
EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,
279282
EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
280283
EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
281284
EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy