Skip to content

Commit 8dd7c7c

Browse files
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
1 parent dabccf4 commit 8dd7c7c

File tree

7 files changed

+98
-34
lines changed

7 files changed

+98
-34
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: 12 additions & 12 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);
@@ -3991,7 +3991,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
39913991

39923992
scratch.resvalue = NULL;
39933993
scratch.resnull = NULL;
3994-
scratch.opcode = EEOP_DONE;
3994+
scratch.opcode = EEOP_DONE_NO_RETURN;
39953995
ExprEvalPushStep(state, &scratch);
39963996

39973997
ExecReadyExpr(state);
@@ -4258,7 +4258,7 @@ ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops,
42584258

42594259
scratch.resvalue = NULL;
42604260
scratch.resnull = NULL;
4261-
scratch.opcode = EEOP_DONE;
4261+
scratch.opcode = EEOP_DONE_RETURN;
42624262
ExprEvalPushStep(state, &scratch);
42634263

42644264
ExecReadyExpr(state);
@@ -4431,7 +4431,7 @@ ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops,
44314431

44324432
scratch.resvalue = NULL;
44334433
scratch.resnull = NULL;
4434-
scratch.opcode = EEOP_DONE;
4434+
scratch.opcode = EEOP_DONE_RETURN;
44354435
ExprEvalPushStep(state, &scratch);
44364436

44374437
ExecReadyExpr(state);
@@ -4586,7 +4586,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
45864586

45874587
scratch.resvalue = NULL;
45884588
scratch.resnull = NULL;
4589-
scratch.opcode = EEOP_DONE;
4589+
scratch.opcode = EEOP_DONE_RETURN;
45904590
ExprEvalPushStep(state, &scratch);
45914591

45924592
ExecReadyExpr(state);
@@ -4722,7 +4722,7 @@ ExecBuildParamSetEqual(TupleDesc desc,
47224722

47234723
scratch.resvalue = NULL;
47244724
scratch.resnull = NULL;
4725-
scratch.opcode = EEOP_DONE;
4725+
scratch.opcode = EEOP_DONE_RETURN;
47264726
ExprEvalPushStep(state, &scratch);
47274727

47284728
ExecReadyExpr(state);

src/backend/executor/execExprInterp.c

Lines changed: 17 additions & 8 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
@@ -469,7 +470,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
469470
*/
470471
#if defined(EEO_USE_COMPUTED_GOTO)
471472
static const void *const dispatch_table[] = {
472-
&&CASE_EEOP_DONE,
473+
&&CASE_EEOP_DONE_RETURN,
474+
&&CASE_EEOP_DONE_NO_RETURN,
473475
&&CASE_EEOP_INNER_FETCHSOME,
474476
&&CASE_EEOP_OUTER_FETCHSOME,
475477
&&CASE_EEOP_SCAN_FETCHSOME,
@@ -612,9 +614,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
612614

613615
EEO_SWITCH()
614616
{
615-
EEO_CASE(EEOP_DONE)
617+
EEO_CASE(EEOP_DONE_RETURN)
616618
{
617-
goto out;
619+
*isnull = state->resnull;
620+
return state->resvalue;
621+
}
622+
623+
EEO_CASE(EEOP_DONE_NO_RETURN)
624+
{
625+
Assert(isnull == NULL);
626+
return (Datum) 0;
618627
}
619628

620629
EEO_CASE(EEOP_INNER_FETCHSOME)
@@ -2188,13 +2197,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
21882197
{
21892198
/* unreachable */
21902199
Assert(false);
2191-
goto out;
2200+
goto out_error;
21922201
}
21932202
}
21942203

2195-
out:
2196-
*isnull = state->resnull;
2197-
return state->resvalue;
2204+
out_error:
2205+
pg_unreachable();
2206+
return (Datum) 0;
21982207
}
21992208

22002209
/*

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
/*

src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ llvm_compile_expr(ExprState *state)
321321

322322
switch (opcode)
323323
{
324-
case EEOP_DONE:
324+
case EEOP_DONE_RETURN:
325325
{
326326
LLVMValueRef v_tmpisnull;
327327
LLVMValueRef v_tmpvalue;
@@ -335,6 +335,10 @@ llvm_compile_expr(ExprState *state)
335335
break;
336336
}
337337

338+
case EEOP_DONE_NO_RETURN:
339+
LLVMBuildRet(b, l_sizet_const(0));
340+
break;
341+
338342
case EEOP_INNER_FETCHSOME:
339343
case EEOP_OUTER_FETCHSOME:
340344
case EEOP_SCAN_FETCHSOME:

src/include/executor/execExpr.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ typedef struct ExprEvalRowtypeCache
6565
*/
6666
typedef enum ExprEvalOp
6767
{
68-
/* entire expression has been evaluated completely, return */
69-
EEOP_DONE,
68+
/* entire expression has been evaluated, return value */
69+
EEOP_DONE_RETURN,
70+
71+
/* entire expression has been evaluated, no return value */
72+
EEOP_DONE_NO_RETURN,
7073

7174
/* apply slot_getsomeattrs on corresponding tuple slot */
7275
EEOP_INNER_FETCHSOME,

src/include/executor/executor.h

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,34 @@ ExecEvalExpr(ExprState *state,
379379
}
380380
#endif
381381

382+
/*
383+
* ExecEvalExprNoReturn
384+
*
385+
* Like ExecEvalExpr(), but for cases where no return value is expected,
386+
* because the side-effects of expression evaluation are what's desired. This
387+
* is e.g. used for projection and aggregate transition computation.
388+
389+
* Evaluate expression identified by "state" in the execution context
390+
* given by "econtext".
391+
*
392+
* The caller should already have switched into the temporary memory context
393+
* econtext->ecxt_per_tuple_memory. The convenience entry point
394+
* ExecEvalExprNoReturnSwitchContext() is provided for callers who don't
395+
* prefer to do the switch in an outer loop.
396+
*/
397+
#ifndef FRONTEND
398+
static inline void
399+
ExecEvalExprNoReturn(ExprState *state,
400+
ExprContext *econtext)
401+
{
402+
PG_USED_FOR_ASSERTS_ONLY Datum retDatum;
403+
404+
retDatum = state->evalfunc(state, econtext, NULL);
405+
406+
Assert(retDatum == (Datum) 0);
407+
}
408+
#endif
409+
382410
/*
383411
* ExecEvalExprSwitchContext
384412
*
@@ -400,6 +428,25 @@ ExecEvalExprSwitchContext(ExprState *state,
400428
}
401429
#endif
402430

431+
/*
432+
* ExecEvalExprNoReturnSwitchContext
433+
*
434+
* Same as ExecEvalExprNoReturn, but get into the right allocation context
435+
* explicitly.
436+
*/
437+
#ifndef FRONTEND
438+
static inline void
439+
ExecEvalExprNoReturnSwitchContext(ExprState *state,
440+
ExprContext *econtext)
441+
{
442+
MemoryContext oldContext;
443+
444+
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
445+
ExecEvalExprNoReturn(state, econtext);
446+
MemoryContextSwitchTo(oldContext);
447+
}
448+
#endif
449+
403450
/*
404451
* ExecProject
405452
*
@@ -419,16 +466,15 @@ ExecProject(ProjectionInfo *projInfo)
419466
ExprContext *econtext = projInfo->pi_exprContext;
420467
ExprState *state = &projInfo->pi_state;
421468
TupleTableSlot *slot = state->resultslot;
422-
bool isnull;
423469

424470
/*
425471
* Clear any former contents of the result slot. This makes it safe for
426472
* us to use the slot's Datum/isnull arrays as workspace.
427473
*/
428474
ExecClearTuple(slot);
429475

430-
/* Run the expression, discarding scalar result from the last column. */
431-
(void) ExecEvalExprSwitchContext(state, econtext, &isnull);
476+
/* Run the expression */
477+
ExecEvalExprNoReturnSwitchContext(state, econtext);
432478

433479
/*
434480
* Successfully formed a result row. Mark the result slot as containing a

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