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