1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-19 23:22:23 +03:00

Replace EEOP_DONE with special steps for return/no return

Knowing when the side-effects of an expression is the intended result
of the execution, rather than the returnvalue, is important for being
able generate more efficient JITed code. This replaces EEOP_DONE with
two new steps: EEOP_DONE_RETURN and EEOP_DONE_NO_RETURN.  Expressions
which return a value should use the former step; expressions used for
their side-effects which don't return value should use the latter.

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
This commit is contained in:
Daniel Gustafsson
2025-03-11 12:02:38 +01:00
parent dabccf4513
commit 8dd7c7cd0a
7 changed files with 98 additions and 34 deletions

View File

@@ -133,9 +133,14 @@ is used by the function evaluation step, thus avoiding extra work to copy
the result values around.
The last entry in a completed ExprState->steps array is always an
EEOP_DONE step; this removes the need to test for end-of-array while
iterating. Also, if the expression contains any variable references (to
user columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
EEOP_DONE_RETURN or EEOP_DONE_NO_RETURN step; this removes the need to
test for end-of-array while iterating. The former is used when the
expression returns a value directly, the latter when side-effects of
expression initialization are the goal (e.g. for projection or
aggregate transition value computation).
Also, if the expression contains any variable references (to user
columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
array begins with EEOP_*_FETCHSOME steps that ensure that the relevant
tuples have been deconstructed to make the required columns directly
available (cf. slot_getsomeattrs()). This allows individual Var-fetching

View File

@@ -8,7 +8,7 @@
* using ExecInitExpr() et al. This converts the tree into a flat array
* of ExprEvalSteps, which may be thought of as instructions in a program.
* At runtime, we'll execute steps, starting with the first, until we reach
* an EEOP_DONE opcode.
* an EEOP_DONE_{RETURN|NO_RETURN} opcode.
*
* This file contains the "compilation" logic. It is independent of the
* specific execution technology we use (switch statement, computed goto,
@@ -162,7 +162,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
/* Finally, append a DONE step */
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -199,7 +199,7 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
/* Finally, append a DONE step */
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -291,7 +291,7 @@ ExecInitQual(List *qual, PlanState *parent)
* have yielded TRUE, and since its result is stored in the desired output
* location, we're done.
*/
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -503,7 +503,7 @@ ExecBuildProjectionInfo(List *targetList,
}
}
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_NO_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -742,7 +742,7 @@ ExecBuildUpdateProjection(List *targetList,
}
}
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_NO_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -1714,7 +1714,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
else
{
/* Not trivial, so append a DONE step */
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(elemstate, &scratch);
/* and ready the subexpression */
ExecReadyExpr(elemstate);
@@ -3991,7 +3991,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_NO_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -4258,7 +4258,7 @@ ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops,
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -4431,7 +4431,7 @@ ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops,
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -4586,7 +4586,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
@@ -4722,7 +4722,7 @@ ExecBuildParamSetEqual(TupleDesc desc,
scratch.resvalue = NULL;
scratch.resnull = NULL;
scratch.opcode = EEOP_DONE;
scratch.opcode = EEOP_DONE_RETURN;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);

View File

@@ -246,7 +246,8 @@ ExecReadyInterpretedExpr(ExprState *state)
/* Simple validity checks on expression */
Assert(state->steps_len >= 1);
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE_RETURN ||
state->steps[state->steps_len - 1].opcode == EEOP_DONE_NO_RETURN);
/*
* Don't perform redundant initialization. This is unreachable in current
@@ -469,7 +470,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
*/
#if defined(EEO_USE_COMPUTED_GOTO)
static const void *const dispatch_table[] = {
&&CASE_EEOP_DONE,
&&CASE_EEOP_DONE_RETURN,
&&CASE_EEOP_DONE_NO_RETURN,
&&CASE_EEOP_INNER_FETCHSOME,
&&CASE_EEOP_OUTER_FETCHSOME,
&&CASE_EEOP_SCAN_FETCHSOME,
@@ -612,9 +614,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_SWITCH()
{
EEO_CASE(EEOP_DONE)
EEO_CASE(EEOP_DONE_RETURN)
{
goto out;
*isnull = state->resnull;
return state->resvalue;
}
EEO_CASE(EEOP_DONE_NO_RETURN)
{
Assert(isnull == NULL);
return (Datum) 0;
}
EEO_CASE(EEOP_INNER_FETCHSOME)
@@ -2188,13 +2197,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
{
/* unreachable */
Assert(false);
goto out;
goto out_error;
}
}
out:
*isnull = state->resnull;
return state->resvalue;
out_error:
pg_unreachable();
return (Datum) 0;
}
/*

View File

@@ -816,11 +816,8 @@ advance_transition_function(AggState *aggstate,
static void
advance_aggregates(AggState *aggstate)
{
bool dummynull;
ExecEvalExprSwitchContext(aggstate->phase->evaltrans,
aggstate->tmpcontext,
&dummynull);
ExecEvalExprNoReturnSwitchContext(aggstate->phase->evaltrans,
aggstate->tmpcontext);
}
/*