From 992a5e21f7039825b12a6e800efb0265061bbe3a Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Tue, 2 Sep 2025 23:46:34 +0900 Subject: [PATCH v1 6/8] WIP: Add EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP Introduce a batch EEOP that runs plain aggregate transitions by looping over rows of a TupleBatch. This keeps transition logic in the interpreter while amortizing per-row costs. Gate with AggTransCanUseBatch(): plain, non-hashed, single-set aggregates with no DISTINCT/ORDER/FILTER, and simple Var args. Extend ExecBuildAggTrans() to prepare batch fetch/build steps and to return whether a batch path is used. --- src/backend/executor/execExpr.c | 228 ++++++++++++++++++++++++-- src/backend/executor/execExprInterp.c | 103 ++++++++++++ src/backend/executor/nodeAgg.c | 17 +- src/backend/jit/llvm/llvmjit_expr.c | 6 + src/backend/jit/llvm/llvmjit_types.c | 1 + src/include/executor/execBatch.h | 6 + src/include/executor/execExpr.h | 14 ++ src/include/executor/executor.h | 3 +- src/include/executor/nodeAgg.h | 2 + 9 files changed, 363 insertions(+), 17 deletions(-) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index f1569879b52..af5ed8b6368 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -95,7 +95,9 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, - bool nullcheck); + bool nullcheck, bool batch, + BatchVector *bv); + static void ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state, Datum *resv, bool *resnull, ExprEvalStep *scratch); @@ -104,6 +106,10 @@ static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, bool exists_coerce, Datum *resv, bool *resnull); +static BatchVector *BatchVectorCreate(Bitmapset *attnos, AttrNumber last_var); +static bool ExprListAllSimpleVars(const List *args, Bitmapset **allattnos); +static BatchVectorSlice *BatchVectorSliceFromExprArgs(const List *args, + const BatchVector *bv); /* * ExecInitExpr: prepare an expression tree for execution @@ -3659,6 +3665,33 @@ ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, } } +/* plain agg, single set, not hashed, no DISTINCT/ORDER/FILTER */ +static inline bool +AggTransCanUseBatch(AggState *as, AggStatePerTrans pt) +{ + Agg *aggnode = (Agg *) as->ss.ps.plan; + + if (!AggCanUsePlainBatch(as)) + return false; + if (as->aggstrategy == AGG_HASHED) + return false; + if (aggnode->groupingSets != NIL) + return false; + if (as->phase == NULL || as->phase->numsets > 0) + return false; + + /* per-aggregate complications */ + if (pt->aggsortrequired) + return false; + if (pt->aggref && + (pt->aggref->aggdistinct != NIL || + pt->aggref->aggorder != NIL || + pt->aggref->aggfilter != NULL)) + return false; + + return true; +} + /* * Build transition/combine function invocations for all aggregate transition * / combination function invocations in a grouping sets phase. This has to @@ -3675,13 +3708,17 @@ ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, */ ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, - bool doSort, bool doHash, bool nullcheck) + bool doSort, bool doHash, bool nullcheck, + bool *batch_trans) { ExprState *state = makeNode(ExprState); PlanState *parent = &aggstate->ss.ps; ExprEvalStep scratch = {0}; bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit); ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL}; + bool batch = AggCanUsePlainBatch(aggstate); + Bitmapset *allattnos = NULL; + BatchVector *bv = NULL; state->expr = (Expr *) aggstate; state->parent = parent; @@ -3707,8 +3744,36 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, &deform); expr_setup_walker((Node *) pertrans->aggref->aggfilter, &deform); + + if (!AggTransCanUseBatch(aggstate, pertrans) || + !ExprListAllSimpleVars(pertrans->aggref->args, &allattnos)) + batch = false; } - ExecPushExprSetupSteps(state, &deform); + + if (batch) + { + if (deform.last_outer > 0) + { + Assert(!bms_is_empty(allattnos)); + bv = BatchVectorCreate(allattnos, deform.last_outer); + + /* + * Deform all tuples upto last_outer in batch + */ + scratch.opcode = EEOP_OUTER_FETCHSOME_BATCH; + scratch.d.fetch_batch.last_var = deform.last_outer; + ExprEvalPushStep(state, &scratch); + + /* + * Put all arg Vars into vectors once per batch slice + */ + scratch.opcode = EEOP_BUILD_OUTER_BATCH_VECTOR; + scratch.d.batch_vector.bv = bv; + ExprEvalPushStep(state, &scratch); + } + } + else + ExecPushExprSetupSteps(state, &deform); /* * Emit instructions for each transition value / grouping set combination. @@ -3746,7 +3811,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, * Evaluate arguments to aggregate/combine function. */ argno = 0; - if (isCombine) + if (isCombine && !batch) { /* * Combining two aggregate transition values. Instead of directly @@ -3816,7 +3881,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, Assert(pertrans->numInputs == argno); } - else if (!pertrans->aggsortrequired) + else if (!pertrans->aggsortrequired && !batch) { ListCell *arg; @@ -3849,7 +3914,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, } Assert(pertrans->numTransInputs == argno); } - else if (pertrans->numInputs == 1) + else if (pertrans->numInputs == 1 && !batch) { /* * Non-presorted DISTINCT and/or ORDER BY case, with a single @@ -3868,7 +3933,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, Assert(pertrans->numInputs == argno); } - else + else if (!batch) { /* * Non-presorted DISTINCT and/or ORDER BY case, with multiple @@ -3896,7 +3961,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, * just keep the prior transValue. This is true for both plain and * sorted/distinct aggregates. */ - if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0) + if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0 && !batch) { if (strictnulls) scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS; @@ -3914,7 +3979,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, } /* Handle DISTINCT aggregates which have pre-sorted input */ - if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired) + if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired && !batch) { if (pertrans->numDistinctCols > 1) scratch.opcode = EEOP_AGG_PRESORTED_DISTINCT_MULTI; @@ -3942,7 +4007,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, { ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, pertrans, transno, setno, setoff, false, - nullcheck); + nullcheck, batch, bv); setoff++; } } @@ -3962,7 +4027,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, { ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, pertrans, transno, setno, setoff, true, - nullcheck); + nullcheck, false, NULL); setoff++; } } @@ -4007,6 +4072,9 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, ExecReadyExpr(state); + if (batch_trans) + *batch_trans = batch; + return state; } @@ -4020,10 +4088,11 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, - bool nullcheck) + bool nullcheck, bool batch, BatchVector *bv) { ExprContext *aggcontext; int adjust_jumpnull = -1; + BatchVectorSlice *bvs = NULL; if (ishash) aggcontext = aggstate->hashcontext; @@ -4077,7 +4146,13 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate, */ if (!pertrans->aggsortrequired) { - if (pertrans->transtypeByVal) + if (batch) + { + if (bv) + bvs = BatchVectorSliceFromExprArgs(pertrans->aggref->args, bv); + scratch->opcode = EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP; + } + else if (pertrans->transtypeByVal) { if (fcinfo->flinfo->fn_strict && pertrans->initValueIsNull) @@ -4108,6 +4183,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate, scratch->d.agg_trans.setoff = setoff; scratch->d.agg_trans.transno = transno; scratch->d.agg_trans.aggcontext = aggcontext; + scratch->d.agg_trans.bvs = bvs; ExprEvalPushStep(state, scratch); /* fix up jumpnull */ @@ -5070,3 +5146,129 @@ ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, DomainHasConstraints(returning->typid); ExprEvalPushStep(state, &scratch); } + +/* Is expr a Var node for a non-system attribute? */ +static bool +expr_is_simple_var(Expr *expr, AttrNumber *out_attno) +{ + if (expr == NULL) + return false; + + if (IsA(expr, TargetEntry)) + return expr_is_simple_var((Expr *) ((TargetEntry *) expr)->expr, + out_attno); + if (IsA(expr, RelabelType)) + return expr_is_simple_var((Expr *) ((RelabelType *) expr)->arg, + out_attno); + + if (IsA(expr, Var) && ((Var *) expr)->varattno > 0) + { + *out_attno = ((Var *) expr)->varattno; + return true; + } + + return false; +} + +/* Are all inputs plain Vars (optionally allow RelabelType->Var)? Collect attnos. */ +static bool +ExprListAllSimpleVars(const List *args, Bitmapset **allattnos) +{ + ListCell *lc; + + foreach(lc, args) + { + TargetEntry *tle = lfirst_node(TargetEntry, lc); + Expr *arg = tle->expr; + AttrNumber attno; + + if (!expr_is_simple_var(arg, &attno)) + return false; + + if (!IsA(arg, Var)) + return false; + + Assert(attno > 0); + *allattnos = bms_add_member(*allattnos, attno); + } + + return true; +} + +/* ---------- BatchVector stuff ------------- */ + +static BatchVector * +BatchVectorCreate(Bitmapset *attnos, AttrNumber last_var) +{ + int maxrows = EXEC_BATCH_ROWS; + BatchVector *bv; + AttrNumber attno; + int i; + + bv = palloc(sizeof(BatchVector)); + bv->ncols = bms_num_members(attnos); + bv->maxrows = maxrows; + bv->last_var = last_var; + bv->attnos = palloc(sizeof(AttrNumber) * bv->ncols); + attno = -1; + i = 0; + while ((attno = bms_next_member(attnos, attno)) > 0) + bv->attnos[i++] = attno; + bv->cols = palloc(sizeof(Datum *) * bv->ncols); + bv->nulls = palloc(sizeof(bool *) * bv->ncols); + + for (i =0; i < bv->ncols; i++) + { + bv->cols[i] = palloc(sizeof(Datum) * maxrows); + bv->nulls[i] = palloc(sizeof(bool) * maxrows); + } + + bv->nrows = 0; + bv->hasnull = false; + + return bv; +} + +static int16 +BatchVectorFindAttColno(const BatchVector *bv, AttrNumber attno) +{ + for (int i = 0; i < bv->ncols; i++) + if (bv->attnos[i] == attno) + return i; + + return -1; +} + +/* + * BatchVectorSliceFromExprArgs + * Build a BatchVectorSlice for a List of args. + * + * For Var args (possibly under RelabelType), store the col index. + * For non-Var args, store -1. Caller can handle Consts, etc. + */ +static BatchVectorSlice * +BatchVectorSliceFromExprArgs(const List *args, const BatchVector *bv) +{ + BatchVectorSlice *bvs = palloc(sizeof(BatchVectorSlice)); + int nargs = list_length(args); + int i = 0; + ListCell *lc; + + Assert(bv); + bvs->bv = bv; + bvs->nargs = nargs; + bvs->argoffs = (int16 *) palloc(sizeof(int16) * nargs); + + foreach (lc, args) + { + Expr *arg = (Expr *) lfirst(lc); + AttrNumber attno; + + if (expr_is_simple_var(arg, &attno)) + bvs->argoffs[i++] = BatchVectorFindAttColno(bv, attno); + else + bvs->argoffs[i++] = -1; /* non-Var */ + } + + return bvs; +} diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 68629ad7991..3176679b346 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -606,6 +606,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_BUILD_INNER_BATCH_VECTOR, &&CASE_EEOP_BUILD_OUTER_BATCH_VECTOR, &&CASE_EEOP_BUILD_SCAN_BATCH_VECTOR, + &&CASE_EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP, &&CASE_EEOP_LAST }; @@ -2336,6 +2337,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP) + { + /* too complex for an inline implementation */ + ExecAggPlainTransBatch(state, op, econtext); + + EEO_NEXT(); + } + EEO_CASE(EEOP_LAST) { /* unreachable */ @@ -6039,3 +6048,97 @@ ExecBuildBatchVector(ExprState *state, ExprEvalStep *op, ExprContext *econtext, } bv->nrows = i; } + +void +ExecAggPlainTransBatch(ExprState *state, ExprEvalStep *op, ExprContext *econtext) +{ + AggState *aggstate = castNode(AggState, state->parent); + AggStatePerTrans pertrans = op->d.agg_trans.pertrans; + AggStatePerGroup pergroup = + &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; + BatchVectorSlice *bvs = op->d.agg_trans.bvs; + FunctionCallInfo fcinfo = pertrans->transfn_fcinfo; + FmgrInfo *finfo = fcinfo->flinfo; + Datum newVal; + TupleBatch *batch = econtext->outer_batch; + int batch_nrows = bvs ? bvs->bv->nrows : batch->nvalid; + int start_row = 0; + + if (finfo->fn_strict) + { + if (pergroup->noTransValue && bvs) + { + const BatchVector *bv = bvs->bv; + bool found = false; + + Assert(bv); + for (int i = 0; i < batch_nrows; i++) + { + for (int j = 0; j < bvs->nargs; j++) + { + if (!bv->nulls[bvs->argoffs[j]][i]) + { + fcinfo->args[1].value = bv->cols[bvs->argoffs[j]][i]; + fcinfo->args[1].isnull = false; + if (j == bvs->nargs - 1) + { + found = true; + break; + } + } + } + if (found) + break; + } + /* If transValue has not yet been initialized, do so now. */ + ExecAggInitGroup(aggstate, pertrans, pergroup, + op->d.agg_trans.aggcontext); + start_row = 1; + } + else if (pergroup->transValueIsNull) + return; + } + + switch (ExecEvalStepOp(state, op)) + { + case EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP: + /* Loop rows, call the original transfn per element using vector cols. */ + for (int i = start_row; i < batch_nrows; i++) + { + bool hasnull = false; + + /* Set up fcinfo args 1..m from column vectors at row i. */ + if (bvs) + { + const BatchVector *bv = bvs->bv; + + for (int j = 0; j < bvs->nargs; j++) + { + int16 argoff = bvs->argoffs[j]; + + fcinfo->args[j+1].value = bv->cols[argoff][i]; + fcinfo->args[j+1].isnull = bv->nulls[argoff][i]; + if (!hasnull && bv->nulls[argoff][i]) + hasnull = true; + } + } + /* fcinfo->args[0] is the existing transition state */ + if (finfo->fn_strict && hasnull) + continue; + fcinfo->args[0].value = pergroup->transValue; + fcinfo->args[0].isnull = pergroup->transValueIsNull; + newVal = FunctionCallInvoke(fcinfo); + if (!pertrans->transtypeByVal && + DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue)) + newVal = ExecAggCopyTransValue(aggstate, pertrans, + newVal, fcinfo->isnull, + pergroup->transValue, + pergroup->transValueIsNull); + pergroup->transValue = newVal; + pergroup->transValueIsNull = fcinfo->isnull; + } + break; + default: + elog(ERROR, "invalid ExprEvalOp in ExecAggPlainTransBatch()"); + } +} diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 3ace6363509..662d8bef43b 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -825,6 +825,16 @@ advance_aggregates_batch(AggState *aggstate, TupleBatch *b) { ExprContext *tmpcontext = aggstate->tmpcontext; ExprState *evaltrans = aggstate->phase->evaltrans; + bool batch_trans = aggstate->phase->batch_trans; + + if (batch_trans) + { + tmpcontext->ecxt_outertuple = TupleBatchGetSlot(b, 0); + tmpcontext->outer_batch = b; + ExecEvalExprNoReturnSwitchContext(evaltrans, tmpcontext); + TupleBatchConsumeAll(b); + return; + } while (TupleBatchHasMore(b)) { @@ -1800,7 +1810,8 @@ hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck) phase->evaltrans_cache[i][j] = ExecBuildAggTrans(aggstate, phase, dosort, dohash, - nullcheck); + nullcheck, + NULL); /* change back */ aggstate->ss.ps.outerops = outerops; @@ -3367,7 +3378,7 @@ hashagg_reset_spill_state(AggState *aggstate) } } -static bool +bool AggCanUsePlainBatch(AggState *aggstate) { const Agg *aggnode = (const Agg *) aggstate->ss.ps.plan; @@ -4233,7 +4244,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) Assert(false); phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash, - false); + false, &phase->batch_trans); /* cache compiled expression for outer slot without NULL check */ phase->evaltrans_cache[0][0] = phase->evaltrans; diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index 848f0b52d6f..efb3ee639fc 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -3026,6 +3026,12 @@ llvm_compile_expr(ExprState *state) LLVMBuildBr(b, opblocks[opno + 1]); break; + case EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP: + build_EvalXFunc(b, mod, "ExecAggPlainTransBatch", + v_state, op, v_econtext); + LLVMBuildBr(b, opblocks[opno + 1]); + break; + case EEOP_LAST: Assert(false); break; diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c index 6bb527c3f6f..1b5e06f60cc 100644 --- a/src/backend/jit/llvm/llvmjit_types.c +++ b/src/backend/jit/llvm/llvmjit_types.c @@ -186,4 +186,5 @@ void *referenced_functions[] = ExecBuildInnerBatchVector, ExecBuildOuterBatchVector, ExecBuildScanBatchVector, + ExecAggPlainTransBatch, }; diff --git a/src/include/executor/execBatch.h b/src/include/executor/execBatch.h index 6f1a38d14bd..b50961fc0c9 100644 --- a/src/include/executor/execBatch.h +++ b/src/include/executor/execBatch.h @@ -99,4 +99,10 @@ TupleBatchMaterializeAll(TupleBatch *b) TupleBatchUseInput(b, b->ntuples); } +static inline void +TupleBatchConsumeAll(TupleBatch *b) +{ + b->next = b->nvalid; +} + #endif /* EXECBATCH_H */ diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 99c86bac702..1d33e084b69 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -302,6 +302,9 @@ typedef enum ExprEvalOp EEOP_BUILD_OUTER_BATCH_VECTOR, EEOP_BUILD_SCAN_BATCH_VECTOR, + /* Batched aggregate trans evaluation */ + EEOP_AGG_PLAIN_TRANS_BATCH_ROWLOOP, /* per-row fmgr calls */ + /* non-existent operation, used e.g. to check array lengths */ EEOP_LAST } ExprEvalOp; @@ -750,6 +753,7 @@ typedef struct ExprEvalStep /* for EEOP_AGG_PLAIN_TRANS_[INIT_][STRICT_]{BYVAL,BYREF} */ /* for EEOP_AGG_ORDERED_TRANS_{DATUM,TUPLE} */ + /* for EEOP_AGG_PLAIN_TRANS_{BATCH,BATCH_ROWLOOP}*/ struct { AggStatePerTrans pertrans; @@ -757,6 +761,7 @@ typedef struct ExprEvalStep int setno; int transno; int setoff; + struct BatchVectorSlice *bvs; } agg_trans; /* for EEOP_IS_JSON */ @@ -956,8 +961,17 @@ typedef struct BatchVector int nrows; /* #rows loaded into cols/nulls */ } BatchVector; +/* A slice of BatchVector that maps caller args to BatchVector columns. */ +typedef struct BatchVectorSlice +{ + const BatchVector *bv; + int nargs; /* number of args covered */ + int16 *argoffs; /* length nargs, -1 for non-Var entries */ +} BatchVectorSlice; + extern void ExecBuildInnerBatchVector(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecBuildOuterBatchVector(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecBuildScanBatchVector(ExprState *state, ExprEvalStep *op, ExprContext *econtext); +extern void ExecAggPlainTransBatch(ExprState *state, ExprEvalStep *op, ExprContext *econtext); #endif /* EXEC_EXPR_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index cf5b0c7e05c..5ba9a523970 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -336,7 +336,8 @@ extern ExprState *ExecInitQual(List *qual, PlanState *parent); extern ExprState *ExecInitCheck(List *qual, PlanState *parent); extern List *ExecInitExprList(List *nodes, PlanState *parent); extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase, - bool doSort, bool doHash, bool nullcheck); + bool doSort, bool doHash, bool nullcheck, + bool *batch_trans); extern ExprState *ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index 6c4891bbaeb..5c5ebfc73f2 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -289,6 +289,7 @@ typedef struct AggStatePerPhaseData Sort *sortnode; /* Sort node for input ordering for phase */ ExprState *evaltrans; /* evaluation of transition functions */ + bool batch_trans; /* true if evaltrans contains batch EEOPs */ /*---------- * Cached variants of the compiled expression. @@ -338,4 +339,5 @@ extern void ExecAggInitializeDSM(AggState *node, ParallelContext *pcxt); extern void ExecAggInitializeWorker(AggState *node, ParallelWorkerContext *pwcxt); extern void ExecAggRetrieveInstrumentation(AggState *node); +extern bool AggCanUsePlainBatch(AggState *aggstate); #endif /* NODEAGG_H */ -- 2.43.0