diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 84d71761c1b..febc7cc2b93 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -43,6 +43,8 @@ #include "optimizer/optimizer.h" #include "port/pg_bitutils.h" #include "utils/builtins.h" +#include "utils/float.h" +#include "utils/numeric.h" #include "utils/date.h" #include "utils/lsyscache.h" #include "utils/rangetypes.h" @@ -1872,15 +1874,31 @@ int8range_subdiff(PG_FUNCTION_ARGS) Datum numrange_subdiff(PG_FUNCTION_ARGS) { - Datum v1 = PG_GETARG_DATUM(0); - Datum v2 = PG_GETARG_DATUM(1); - Datum numresult; + Numeric v1 = PG_GETARG_NUMERIC(0); + Numeric v2 = PG_GETARG_NUMERIC(1); + Numeric numresult; float8 floatresult; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - numresult = DirectFunctionCall2(numeric_sub, v1, v2); + /* + * The difference can exceed numeric's range, or be unrepresentable + * in float8. Neither caller is prepared to handle an error, so + * saturate to infinity (or round to zero) instead. + */ + numresult = numeric_sub_safe(v1, v2, (Node *) &escontext); + if (SOFT_ERROR_OCCURRED(&escontext)) + floatresult = get_float8_infinity(); + else + { + floatresult = DatumGetFloat8(DirectFunctionCall1( + numeric_float8_no_overflow, NumericGetDatum(numresult))); + pfree(numresult); + } - floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8, - numresult)); + PG_FREE_IF_COPY(v1, 0); + PG_FREE_IF_COPY(v2, 1); PG_RETURN_FLOAT8(floatresult); }