diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index d61af920cda2dde4ea4ed78ba5fdf684d2be2c3e..c73f9bc005aece79b96b55faefee46fc359e4712 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -717,6 +717,8 @@ numeric_recv(PG_FUNCTION_ARGS) alloc_var(&value, len); value.weight = (int16) pq_getmsgint(buf, sizeof(int16)); + /* we allow any int16 for weight --- OK? */ + value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16)); if (!(value.sign == NUMERIC_POS || value.sign == NUMERIC_NEG || @@ -726,6 +728,11 @@ numeric_recv(PG_FUNCTION_ARGS) errmsg("invalid sign in external \"numeric\" value"))); value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16)); + if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid scale in external \"numeric\" value"))); + for (i = 0; i < len; i++) { NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit)); @@ -737,6 +744,14 @@ numeric_recv(PG_FUNCTION_ARGS) value.digits[i] = d; } + /* + * If the given dscale would hide any digits, truncate those digits away. + * We could alternatively throw an error, but that would take a bunch of + * extra code (about as much as trunc_var involves), and it might cause + * client compatibility issues. + */ + trunc_var(&value, value.dscale); + apply_typmod(&value, typmod); res = make_result(&value);