aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-11-09 11:28:18 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2010-11-09 11:56:23 -0500
commitf0e4331d04fa007830666c5baa2c3e37cce9c3ff (patch)
tree9b1252330295a882ef87a7fa5101cdd2f9a9e35e
parent7c0af833c64cb9ab7fd78b10ec7b04e0b0874bcd (diff)
downloadpostgresql-f0e4331d04fa007830666c5baa2c3e37cce9c3ff.tar.gz
postgresql-f0e4331d04fa007830666c5baa2c3e37cce9c3ff.zip
Repair memory leakage while ANALYZE-ing complex index expressions.
The general design of memory management in Postgres is that intermediate results computed by an expression are not freed until the end of the tuple cycle. For expression indexes, ANALYZE has to re-evaluate each expression for each of its sample rows, and it wasn't bothering to free intermediate results until the end of processing of that index. This could lead to very substantial leakage if the intermediate results were large, as in a recent example from Jakub Ouhrabka. Fix by doing ResetExprContext for each sample row. This necessitates adding a datumCopy step to ensure that the final expression value isn't recycled too. Some quick testing suggests that this change adds at worst about 10% to the time needed to analyze a table with an expression index; which is annoying, but seems a tolerable price to pay to avoid unexpected out-of-memory problems. Back-patch to all supported branches.
-rw-r--r--src/backend/commands/analyze.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index baddc650a62..7b18fadc1a9 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -625,6 +625,12 @@ compute_index_stats(Relation onerel, double totalrows,
{
HeapTuple heapTuple = rows[rowno];
+ /*
+ * Reset the per-tuple context each time, to reclaim any cruft
+ * left behind by evaluating the predicate or index expressions.
+ */
+ ResetExprContext(econtext);
+
/* Set up for predicate or expression evaluation */
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
@@ -649,15 +655,26 @@ compute_index_stats(Relation onerel, double totalrows,
isnull);
/*
- * Save just the columns we care about.
+ * Save just the columns we care about. We copy the values
+ * into ind_context from the estate's per-tuple context.
*/
for (i = 0; i < attr_cnt; i++)
{
VacAttrStats *stats = thisdata->vacattrstats[i];
int attnum = stats->attr->attnum;
- exprvals[tcnt] = values[attnum - 1];
- exprnulls[tcnt] = isnull[attnum - 1];
+ if (isnull[attnum - 1])
+ {
+ exprvals[tcnt] = (Datum) 0;
+ exprnulls[tcnt] = true;
+ }
+ else
+ {
+ exprvals[tcnt] = datumCopy(values[attnum - 1],
+ stats->attrtype->typbyval,
+ stats->attrtype->typlen);
+ exprnulls[tcnt] = false;
+ }
tcnt++;
}
}