diff options
-rw-r--r-- | src/backend/utils/adt/dbsize.c | 14 | ||||
-rw-r--r-- | src/backend/utils/adt/numeric.c | 21 | ||||
-rw-r--r-- | src/include/utils/numeric.h | 5 | ||||
-rw-r--r-- | src/interfaces/ecpg/pgtypeslib/numeric.c | 3 | ||||
-rw-r--r-- | src/test/regress/expected/dbsize.out | 2 |
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". |