summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-05-05 18:02:11 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-05-05 18:02:11 +0000
commit616bceb8cb67c4f7641d933d0963373963e7492e (patch)
tree6a24cb7b66b832b6325b1b66ac41edb21eeb0043 /src
parent5d540add340040373364cec82caa288e6cc22533 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/analyze.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 47581ab705f..6285a578889 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
*
*
* 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,
MemoryContext old_context;
Datum *hist_values;
int nvals;
+ int pos,
+ posfrac,
+ delta,
+ deltafrac;
/* Sort the MCV items into position order to speed next loop */
qsort((void *) track, num_mcv,
@@ -2313,15 +2317,35 @@ compute_scalar_stats(VacAttrStatsP stats,
/* Must copy the target values into anl_context */
old_context = MemoryContextSwitchTo(stats->anl_context);
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++)
{
- int pos;
-
- pos = (i * (nvals - 1)) / (num_hist - 1);
hist_values[i] = datumCopy(values[pos].value,
stats->attr->attbyval,
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);
stats->stakind[slot_idx] = STATISTIC_KIND_HISTOGRAM;