Skip to content

Commit 616bceb

Browse files
committed
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.
1 parent 5d540ad commit 616bceb

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

src/backend/commands/analyze.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.135 2009/03/31 22:12:46 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.136 2009/05/05 18:02:11 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -2260,6 +2260,10 @@ compute_scalar_stats(VacAttrStatsP stats,
22602260
MemoryContext old_context;
22612261
Datum *hist_values;
22622262
int nvals;
2263+
int pos,
2264+
posfrac,
2265+
delta,
2266+
deltafrac;
22632267

22642268
/* Sort the MCV items into position order to speed next loop */
22652269
qsort((void *) track, num_mcv,
@@ -2313,15 +2317,35 @@ compute_scalar_stats(VacAttrStatsP stats,
23132317
/* Must copy the target values into anl_context */
23142318
old_context = MemoryContextSwitchTo(stats->anl_context);
23152319
hist_values = (Datum *) palloc(num_hist * sizeof(Datum));
2320+
2321+
/*
2322+
* The object of this loop is to copy the first and last values[]
2323+
* entries along with evenly-spaced values in between. So the
2324+
* i'th value is values[(i * (nvals - 1)) / (num_hist - 1)]. But
2325+
* computing that subscript directly risks integer overflow when
2326+
* the stats target is more than a couple thousand. Instead we
2327+
* add (nvals - 1) / (num_hist - 1) to pos at each step, tracking
2328+
* the integral and fractional parts of the sum separately.
2329+
*/
2330+
delta = (nvals - 1) / (num_hist - 1);
2331+
deltafrac = (nvals - 1) % (num_hist - 1);
2332+
pos = posfrac = 0;
2333+
23162334
for (i = 0; i < num_hist; i++)
23172335
{
2318-
int pos;
2319-
2320-
pos = (i * (nvals - 1)) / (num_hist - 1);
23212336
hist_values[i] = datumCopy(values[pos].value,
23222337
stats->attr->attbyval,
23232338
stats->attr->attlen);
2339+
pos += delta;
2340+
posfrac += deltafrac;
2341+
if (posfrac >= (num_hist - 1))
2342+
{
2343+
/* fractional part exceeds 1, carry to integer part */
2344+
pos++;
2345+
posfrac -= (num_hist - 1);
2346+
}
23242347
}
2348+
23252349
MemoryContextSwitchTo(old_context);
23262350

23272351
stats->stakind[slot_idx] = STATISTIC_KIND_HISTOGRAM;

0 commit comments

Comments
 (0)