aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r--src/backend/utils/adt/numeric.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index a83feea3967..3c3184f15b5 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -1907,7 +1907,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
}
/*
- * If 'operand' is not outside the bucket range, determine the correct
+ * 'operand' is inside the bucket range, so determine the correct
* bucket for it to go. The calculations performed by this function
* are derived directly from the SQL2003 spec. Note however that we
* multiply by count before dividing, to avoid unnecessary roundoff error.
@@ -1940,8 +1940,19 @@ compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
operand_var.dscale + count_var->dscale);
div_var(&operand_var, &bound2_var, result_var,
select_div_scale(&operand_var, &bound2_var), true);
- add_var(result_var, &const_one, result_var);
- floor_var(result_var, result_var);
+
+ /*
+ * Roundoff in the division could give us a quotient exactly equal to
+ * "count", which is too large. Clamp so that we do not emit a result
+ * larger than "count".
+ */
+ if (cmp_var(result_var, count_var) >= 0)
+ set_var_from_var(count_var, result_var);
+ else
+ {
+ add_var(result_var, &const_one, result_var);
+ floor_var(result_var, result_var);
+ }
free_var(&bound1_var);
free_var(&bound2_var);