mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
I don't like last minute patches before the final freeze, but I believe that
this one could be useful for people experiencing out-of-memory crashes while executing queries which retrieve or use a very large number of tuples. The problem happens when storage is allocated for functions results used in a large query, for example: select upper(name) from big_table; select big_table.array[1] from big_table; select count(upper(name)) from big_table; This patch is a dirty hack that fixes the out-of-memory problem for the most common cases, like the above ones. It is not the final solution for the problem but it can work for some people, so I'm posting it. The patch should be safe because all changes are under #ifdef. Furthermore the feature can be enabled or disabled at runtime by the `free_tuple_memory' options in the pg_options file. The option is disabled by default and must be explicitly enabled at runtime to have any effect. To enable the patch add the follwing line to Makefile.custom: CUSTOM_COPT += -DFREE_TUPLE_MEMORY To enable the option at runtime add the following line to pg_option: free_tuple_memory=1 Massimo
This commit is contained in:
@ -31,6 +31,11 @@
|
||||
#include "utils/syscache.h"
|
||||
#include "optimizer/clauses.h"
|
||||
|
||||
#ifdef FREE_TUPLE_MEMORY
|
||||
#include <utils/portal.h>
|
||||
#include <utils/trace.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AggFuncInfo -
|
||||
* keeps the transition functions information around
|
||||
@ -113,7 +118,9 @@ ExecAgg(Agg *node)
|
||||
isNull1 = FALSE,
|
||||
isNull2 = FALSE;
|
||||
bool qual_result;
|
||||
|
||||
#ifdef FREE_TUPLE_MEMORY
|
||||
bool free_tuple_memory = pg_options[OPT_FREE_TUPLE_MEMORY];
|
||||
#endif
|
||||
|
||||
/* ---------------------
|
||||
* get state info from node
|
||||
@ -241,6 +248,10 @@ ExecAgg(Agg *node)
|
||||
for (;;)
|
||||
{
|
||||
TupleTableSlot *outerslot;
|
||||
#ifdef FREE_TUPLE_MEMORY
|
||||
Oid valueType;
|
||||
bool isByValue = 0;
|
||||
#endif
|
||||
|
||||
isNull = isNull1 = isNull2 = 0;
|
||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
@ -293,6 +304,31 @@ ExecAgg(Agg *node)
|
||||
newVal = ExecEvalExpr(aggref->target, econtext,
|
||||
&isNull, &isDone);
|
||||
}
|
||||
#ifdef FREE_TUPLE_MEMORY
|
||||
if (free_tuple_memory) {
|
||||
switch (nodeTag(aggref->target)) {
|
||||
case T_Const:
|
||||
isByValue = ((Const*) (aggref->target))->constbyval;
|
||||
break;
|
||||
case T_Var:
|
||||
valueType = ((Var*) (aggref->target))->vartype;
|
||||
isByValue = typeByVal(typeidType(valueType));
|
||||
break;
|
||||
case T_Array:
|
||||
isByValue = ((Array*)(aggref->target))->arrayelembyval;
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
isByValue =((ArrayRef*)(aggref->target))->refelembyval;
|
||||
break;
|
||||
case T_Expr:
|
||||
valueType = ((Expr*) (aggref->target))->typeOid;
|
||||
isByValue = typeByVal(typeidType(valueType));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isNull && !aggref->usenulls)
|
||||
continue; /* ignore this tuple for this agg */
|
||||
@ -353,6 +389,16 @@ ExecAgg(Agg *node)
|
||||
(FmgrValues *) args, &isNull2);
|
||||
Assert(!isNull2);
|
||||
}
|
||||
|
||||
#ifdef FREE_TUPLE_MEMORY
|
||||
/* try to pfree newVal if not isByValue - dz */
|
||||
if (free_tuple_memory && !isByValue &&
|
||||
PortalHeapMemoryIsValid(CurrentMemoryContext,
|
||||
(Pointer) newVal))
|
||||
{
|
||||
pfree(newVal);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user