*** a/contrib/tsearch2/tsearch2.c --- b/contrib/tsearch2/tsearch2.c *************** *** 16,21 **** --- 16,22 ---- #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "commands/trigger.h" + #include "executor/nodeAgg.h" #include "fmgr.h" #include "tsearch/ts_utils.h" #include "utils/builtins.h" *************** *** 421,435 **** tsa_rewrite_accum(PG_FUNCTION_ARGS) int nelemsp; MemoryContext aggcontext; MemoryContext oldcontext; ! if (fcinfo->context && IsA(fcinfo->context, AggState)) ! aggcontext = ((AggState *) fcinfo->context)->aggcontext; ! else if (fcinfo->context && IsA(fcinfo->context, WindowAggState)) ! aggcontext = ((WindowAggState *) fcinfo->context)->wincontext; ! else { elog(ERROR, "tsa_rewrite_accum called in non-aggregate context"); - aggcontext = NULL; /* keep compiler quiet */ } if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL) --- 422,433 ---- int nelemsp; MemoryContext aggcontext; MemoryContext oldcontext; + bool iswindowagg; ! aggcontext = AggGetMemoryContext((Node *) fcinfo->context, &iswindowagg); ! if (!aggcontext) { elog(ERROR, "tsa_rewrite_accum called in non-aggregate context"); } if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL) *** a/src/backend/executor/nodeAgg.c --- b/src/backend/executor/nodeAgg.c *************** *** 1970,1975 **** ExecReScanAgg(AggState *node, ExprContext *exprCtxt) --- 1970,2002 ---- } /* + * AggGetMemoryContext - an API to expose temporary memory space + * + * Eventually, aggregate functions want its own memory space to + * store user variables or states during executions of transition functions. + * For those functions to do it, we abstract the operation so that + * future internal changes don't affect them. + */ + MemoryContext + AggGetMemoryContext(Node *node, bool *iswindowagg) + { + if (node && IsA(node, AggState)) + { + if (iswindowagg) + *iswindowagg = false; + return ((AggState *) node)->aggcontext; + } + else if (node && IsA(node, WindowAggState)) + { + if (iswindowagg) + *iswindowagg = true; + return ((WindowAggState *) node)->aggcontext; + } + + return NULL; + } + + /* * aggregate_dummy - dummy execution routine for aggregate functions * * This function is listed as the implementation (prosrc field) of pg_proc *** a/src/backend/executor/nodeWindowAgg.c --- b/src/backend/executor/nodeWindowAgg.c *************** *** 193,199 **** initialize_windowaggregate(WindowAggState *winstate, peraggstate->transValue = peraggstate->initValue; else { ! oldContext = MemoryContextSwitchTo(winstate->wincontext); peraggstate->transValue = datumCopy(peraggstate->initValue, peraggstate->transtypeByVal, peraggstate->transtypeLen); --- 193,199 ---- peraggstate->transValue = peraggstate->initValue; else { ! oldContext = MemoryContextSwitchTo(winstate->aggcontext); peraggstate->transValue = datumCopy(peraggstate->initValue, peraggstate->transtypeByVal, peraggstate->transtypeLen); *************** *** 258,267 **** advance_windowaggregate(WindowAggState *winstate, * already checked that the agg's input type is binary-compatible * with its transtype, so straight copy here is OK.) * ! * We must copy the datum into wincontext if it is pass-by-ref. We * do not need to pfree the old transValue, since it's NULL. */ ! MemoryContextSwitchTo(winstate->wincontext); peraggstate->transValue = datumCopy(fcinfo->arg[1], peraggstate->transtypeByVal, peraggstate->transtypeLen); --- 258,267 ---- * already checked that the agg's input type is binary-compatible * with its transtype, so straight copy here is OK.) * ! * We must copy the datum into aggcontext if it is pass-by-ref. We * do not need to pfree the old transValue, since it's NULL. */ ! MemoryContextSwitchTo(winstate->aggcontext); peraggstate->transValue = datumCopy(fcinfo->arg[1], peraggstate->transtypeByVal, peraggstate->transtypeLen); *************** *** 294,300 **** advance_windowaggregate(WindowAggState *winstate, newVal = FunctionCallInvoke(fcinfo); /* ! * If pass-by-ref datatype, must copy the new value into wincontext and * pfree the prior transValue. But if transfn returned a pointer to its * first input, we don't need to do anything. */ --- 294,300 ---- newVal = FunctionCallInvoke(fcinfo); /* ! * If pass-by-ref datatype, must copy the new value into aggcontext and * pfree the prior transValue. But if transfn returned a pointer to its * first input, we don't need to do anything. */ *************** *** 303,309 **** advance_windowaggregate(WindowAggState *winstate, { if (!fcinfo->isnull) { ! MemoryContextSwitchTo(winstate->wincontext); newVal = datumCopy(newVal, peraggstate->transtypeByVal, peraggstate->transtypeLen); --- 303,309 ---- { if (!fcinfo->isnull) { ! MemoryContextSwitchTo(winstate->aggcontext); newVal = datumCopy(newVal, peraggstate->transtypeByVal, peraggstate->transtypeLen); *************** *** 544,554 **** eval_windowaggregates(WindowAggState *winstate) pfree(DatumGetPointer(peraggstate->resultValue)); /* ! * If pass-by-ref, copy it into our global context. */ if (!*isnull) { ! oldContext = MemoryContextSwitchTo(winstate->wincontext); peraggstate->resultValue = datumCopy(*result, peraggstate->resulttypeByVal, --- 544,554 ---- pfree(DatumGetPointer(peraggstate->resultValue)); /* ! * If pass-by-ref, copy it into our aggregate context. */ if (!*isnull) { ! oldContext = MemoryContextSwitchTo(winstate->aggcontext); peraggstate->resultValue = datumCopy(*result, peraggstate->resulttypeByVal, *************** *** 789,795 **** release_partition(WindowAggState *winstate) * any aggregate temp data). We don't rely on retail pfree because some * aggregates might have allocated data we don't have direct pointers to. */ ! MemoryContextResetAndDeleteChildren(winstate->wincontext); if (winstate->buffer) tuplestore_end(winstate->buffer); --- 789,796 ---- * any aggregate temp data). We don't rely on retail pfree because some * aggregates might have allocated data we don't have direct pointers to. */ ! MemoryContextResetAndDeleteChildren(winstate->partition_context); ! MemoryContextResetAndDeleteChildren(winstate->aggcontext); if (winstate->buffer) tuplestore_end(winstate->buffer); *************** *** 1099,1112 **** ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winstate->tmpcontext = tmpcontext; ExecAssignExprContext(estate, &winstate->ss.ps); ! /* Create long-lived context for storage of aggregate transvalues etc */ ! winstate->wincontext = AllocSetContextCreate(CurrentMemoryContext, ! "WindowAggContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * tuple table initialization */ --- 1100,1120 ---- winstate->tmpcontext = tmpcontext; ExecAssignExprContext(estate, &winstate->ss.ps); ! /* Create long-lived context for storage of partition-local memory etc */ ! winstate->partition_context = AllocSetContextCreate(CurrentMemoryContext, ! "WindowAggContextWin", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); + /* Create mid-lived context for aggregate trans values etc */ + winstate->aggcontext = + AllocSetContextCreate(CurrentMemoryContext, + "WindowAggContextAgg", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); /* * tuple table initialization */ *************** *** 1297,1303 **** ExecEndWindowAgg(WindowAggState *node) node->ss.ps.ps_ExprContext = node->tmpcontext; ExecFreeExprContext(&node->ss.ps); ! MemoryContextDelete(node->wincontext); outerPlan = outerPlanState(node); ExecEndNode(outerPlan); --- 1305,1312 ---- node->ss.ps.ps_ExprContext = node->tmpcontext; ExecFreeExprContext(&node->ss.ps); ! MemoryContextDelete(node->partition_context); ! MemoryContextDelete(node->aggcontext); outerPlan = outerPlanState(node); ExecEndNode(outerPlan); *************** *** 1616,1622 **** WinGetPartitionLocalMemory(WindowObject winobj, Size sz) { Assert(WindowObjectIsValid(winobj)); if (winobj->localmem == NULL) ! winobj->localmem = MemoryContextAllocZero(winobj->winstate->wincontext, sz); return winobj->localmem; } --- 1625,1631 ---- { Assert(WindowObjectIsValid(winobj)); if (winobj->localmem == NULL) ! winobj->localmem = MemoryContextAllocZero(winobj->winstate->partition_context, sz); return winobj->localmem; } *** a/src/backend/utils/adt/array_userfuncs.c --- b/src/backend/utils/adt/array_userfuncs.c *************** *** 12,17 **** --- 12,18 ---- */ #include "postgres.h" + #include "executor/nodeAgg.h" #include "nodes/execnodes.h" #include "utils/array.h" #include "utils/builtins.h" *************** *** 476,481 **** array_agg_transfn(PG_FUNCTION_ARGS) --- 477,483 ---- { Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); MemoryContext aggcontext; + bool iswindowagg; ArrayBuildState *state; Datum elem; *************** *** 484,498 **** array_agg_transfn(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); ! if (fcinfo->context && IsA(fcinfo->context, AggState)) ! aggcontext = ((AggState *) fcinfo->context)->aggcontext; ! else if (fcinfo->context && IsA(fcinfo->context, WindowAggState)) ! aggcontext = ((WindowAggState *) fcinfo->context)->wincontext; ! else { /* cannot be called directly because of internal-type argument */ elog(ERROR, "array_agg_transfn called in non-aggregate context"); - aggcontext = NULL; /* keep compiler quiet */ } state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0); --- 486,496 ---- (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); ! aggcontext = AggGetMemoryContext((Node *) fcinfo->context, &iswindowagg); ! if (!aggcontext) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "array_agg_transfn called in non-aggregate context"); } state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0); *** a/src/include/executor/nodeAgg.h --- b/src/include/executor/nodeAgg.h *************** *** 23,28 **** extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt); --- 23,29 ---- extern Size hash_agg_entry_size(int numAggs); + extern MemoryContext AggGetMemoryContext(Node *node, bool *iswindowagg); extern Datum aggregate_dummy(PG_FUNCTION_ARGS); #endif /* NODEAGG_H */ *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 1601,1607 **** typedef struct WindowAggState int64 frametailpos; /* current frame tail position */ int64 aggregatedupto; /* rows before this one are aggregated */ ! MemoryContext wincontext; /* context for partition-lifespan data */ ExprContext *tmpcontext; /* short-term evaluation context */ bool all_done; /* true if the scan is finished */ --- 1601,1608 ---- int64 frametailpos; /* current frame tail position */ int64 aggregatedupto; /* rows before this one are aggregated */ ! MemoryContext partition_context; /* context for partition-lifespan data */ ! MemoryContext aggcontext; /* context for each aggregate data */ ExprContext *tmpcontext; /* short-term evaluation context */ bool all_done; /* true if the scan is finished */