Commit 616bceb8 authored by Tom Lane's avatar Tom Lane

Avoid integer overflow in the loop that extracts histogram entries from

ANALYZE's total sample.  The original coding is at risk of overflow for
statistics targets exceeding about 2675; this was not a problem before
8.4 but it is now.  Per bug #4793 from Dennis Noordsij.
parent 5d540add
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.135 2009/03/31 22:12:46 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.136 2009/05/05 18:02:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2260,6 +2260,10 @@ compute_scalar_stats(VacAttrStatsP stats, ...@@ -2260,6 +2260,10 @@ compute_scalar_stats(VacAttrStatsP stats,
MemoryContext old_context; MemoryContext old_context;
Datum *hist_values; Datum *hist_values;
int nvals; int nvals;
int pos,
posfrac,
delta,
deltafrac;
/* Sort the MCV items into position order to speed next loop */ /* Sort the MCV items into position order to speed next loop */
qsort((void *) track, num_mcv, qsort((void *) track, num_mcv,
...@@ -2313,15 +2317,35 @@ compute_scalar_stats(VacAttrStatsP stats, ...@@ -2313,15 +2317,35 @@ compute_scalar_stats(VacAttrStatsP stats,
/* Must copy the target values into anl_context */ /* Must copy the target values into anl_context */
old_context = MemoryContextSwitchTo(stats->anl_context); old_context = MemoryContextSwitchTo(stats->anl_context);
hist_values = (Datum *) palloc(num_hist * sizeof(Datum)); hist_values = (Datum *) palloc(num_hist * sizeof(Datum));
/*
* The object of this loop is to copy the first and last values[]
* entries along with evenly-spaced values in between. So the
* i'th value is values[(i * (nvals - 1)) / (num_hist - 1)]. But
* computing that subscript directly risks integer overflow when
* the stats target is more than a couple thousand. Instead we
* add (nvals - 1) / (num_hist - 1) to pos at each step, tracking
* the integral and fractional parts of the sum separately.
*/
delta = (nvals - 1) / (num_hist - 1);
deltafrac = (nvals - 1) % (num_hist - 1);
pos = posfrac = 0;
for (i = 0; i < num_hist; i++) for (i = 0; i < num_hist; i++)
{ {
int pos;
pos = (i * (nvals - 1)) / (num_hist - 1);
hist_values[i] = datumCopy(values[pos].value, hist_values[i] = datumCopy(values[pos].value,
stats->attr->attbyval, stats->attr->attbyval,
stats->attr->attlen); stats->attr->attlen);
pos += delta;
posfrac += deltafrac;
if (posfrac >= (num_hist - 1))
{
/* fractional part exceeds 1, carry to integer part */
pos++;
posfrac -= (num_hist - 1);
}
} }
MemoryContextSwitchTo(old_context); MemoryContextSwitchTo(old_context);
stats->stakind[slot_idx] = STATISTIC_KIND_HISTOGRAM; stats->stakind[slot_idx] = STATISTIC_KIND_HISTOGRAM;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment