aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/dbsize.c14
-rw-r--r--src/backend/utils/adt/numeric.c21
-rw-r--r--src/include/utils/numeric.h5
-rw-r--r--src/interfaces/ecpg/pgtypeslib/numeric.c3
-rw-r--r--src/test/regress/expected/dbsize.out2
5 files changed, 20 insertions, 25 deletions
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 0776f3bf6cf..0e8a82d6f4d 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -759,23 +759,15 @@ pg_size_bytes(PG_FUNCTION_ARGS)
/* Part (4): optional exponent */
if (*endptr == 'e' || *endptr == 'E')
{
- long exponent;
char *cp;
/*
- * Note we might one day support EB units, so if what follows isn't a
- * number, just treat it all as a unit to be parsed.
+ * Note we might one day support EB units, so if what follows 'E'
+ * isn't a number, just treat it all as a unit to be parsed.
*/
- exponent = strtol(endptr + 1, &cp, 10);
+ (void) strtol(endptr + 1, &cp, 10);
if (cp > endptr + 1)
- {
- if (exponent > NUMERIC_MAX_PRECISION ||
- exponent < -NUMERIC_MAX_PRECISION)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid size: \"%s\"", str)));
endptr = cp;
- }
}
/*
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 2fbdfe07582..620226cea11 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -753,10 +753,6 @@ numeric_recv(PG_FUNCTION_ARGS)
init_var(&value);
len = (uint16) pq_getmsgint(buf, sizeof(uint16));
- if (len < 0 || len > NUMERIC_MAX_PRECISION + NUMERIC_MAX_RESULT_SCALE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
- errmsg("invalid length in external \"numeric\" value")));
alloc_var(&value, len);
@@ -5456,12 +5452,19 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest)
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
cp = endptr;
- if (exponent > NUMERIC_MAX_PRECISION ||
- exponent < -NUMERIC_MAX_PRECISION)
+
+ /*
+ * At this point, dweight and dscale can't be more than about
+ * INT_MAX/2 due to the MaxAllocSize limit on string length, so
+ * constraining the exponent similarly should be enough to prevent
+ * integer overflow in this function. If the value is too large to
+ * fit in storage format, make_result() will complain about it later;
+ * for consistency use the same ereport errcode/text as make_result().
+ */
+ if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
ereport(ERROR,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type numeric: \"%s\"",
- str)));
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value overflows numeric format")));
dweight += (int) exponent;
dscale -= (int) exponent;
if (dscale < 0)
diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h
index 7fd5d240c66..6c1808ec717 100644
--- a/src/include/utils/numeric.h
+++ b/src/include/utils/numeric.h
@@ -17,8 +17,9 @@
#include "fmgr.h"
/*
- * Hardcoded precision limit - arbitrary, but must be small enough that
- * dscale values will fit in 14 bits.
+ * Limit on the precision (and hence scale) specifiable in a NUMERIC typmod.
+ * Note that the implementation limit on the length of a numeric value is
+ * much larger --- beware of what you use this for!
*/
#define NUMERIC_MAX_PRECISION 1000
diff --git a/src/interfaces/ecpg/pgtypeslib/numeric.c b/src/interfaces/ecpg/pgtypeslib/numeric.c
index d061616787e..120794550d6 100644
--- a/src/interfaces/ecpg/pgtypeslib/numeric.c
+++ b/src/interfaces/ecpg/pgtypeslib/numeric.c
@@ -263,8 +263,7 @@ set_var_from_str(char *str, char **ptr, numeric *dest)
return -1;
}
(*ptr) = endptr;
- if (exponent > NUMERIC_MAX_PRECISION ||
- exponent < -NUMERIC_MAX_PRECISION)
+ if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
{
errno = PGTYPES_NUM_BAD_NUMERIC;
return -1;
diff --git a/src/test/regress/expected/dbsize.out b/src/test/regress/expected/dbsize.out
index 20d8cb56893..e901a2c92a1 100644
--- a/src/test/regress/expected/dbsize.out
+++ b/src/test/regress/expected/dbsize.out
@@ -119,7 +119,7 @@ ERROR: bigint out of range
SELECT pg_size_bytes('1e100');
ERROR: bigint out of range
SELECT pg_size_bytes('1e1000000000000000000');
-ERROR: invalid size: "1e1000000000000000000"
+ERROR: value overflows numeric format
SELECT pg_size_bytes('1 byte'); -- the singular "byte" is not supported
ERROR: invalid size: "1 byte"
DETAIL: Invalid size unit: "byte".