]> granicus.if.org Git - postgresql/commitdiff
Remove bogus dependencies on NUMERIC_MAX_PRECISION.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Aug 2016 19:06:02 +0000 (15:06 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Aug 2016 19:06:02 +0000 (15:06 -0400)
NUMERIC_MAX_PRECISION is a purely arbitrary constraint on the precision
and scale you can write in a numeric typmod.  It might once have had
something to do with the allowed range of a typmod-less numeric value,
but at least since 9.1 we've allowed, and documented that we allowed,
any value that would physically fit in the numeric storage format;
which is something over 100000 decimal digits, not 1000.

Hence, get rid of numeric_in()'s use of NUMERIC_MAX_PRECISION as a limit
on the allowed range of the exponent in scientific-format input.  That was
especially silly in view of the fact that you can enter larger numbers as
long as you don't use 'e' to do it.  Just constrain the value enough to
avoid localized overflow, and let make_result be the final arbiter of what
is too large.  Likewise adjust ecpg's equivalent of this code.

Also get rid of numeric_recv()'s use of NUMERIC_MAX_PRECISION to limit the
number of base-NBASE digits it would accept.  That created a dump/restore
hazard for binary COPY without doing anything useful; the wire-format
limit on number of digits (65535) is about as tight as we would want.

In HEAD, also get rid of pg_size_bytes()'s unnecessary intimacy with what
the numeric range limit is.  That code doesn't exist in the back branches.

Per gripe from Aravind Kumar.  Back-patch to all supported branches,
since they all contain the documentation claim about allowed range of
NUMERIC (cf commit cabf5d84b).

Discussion: <2895.1471195721@sss.pgh.pa.us>

src/backend/utils/adt/numeric.c
src/include/utils/numeric.h
src/interfaces/ecpg/pgtypeslib/numeric.c

index ba1f6c272fc2158a6e4fe0f103e0dd9a4871c65b..6f6f469e88ee972b741976a0434743f24675ae85 100644 (file)
@@ -648,10 +648,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);
 
@@ -3338,12 +3334,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)
index 229c2c0606aaaaa57782c793b8a738e624bb23b4..76b367aa36020619771a0adeed9d6af2d1b287fb 100644 (file)
@@ -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
 
index d4806771b346da3e77a8ae650b6138b1a63557ef..e286aac94c5fed40553e0e2f3e31da912b3c9530 100644 (file)
@@ -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;