From: Peter Eisentraut Date: Mon, 30 Mar 2026 08:05:22 +0000 (+0200) Subject: Make cast functions to type money error safe X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b36b95640487b9dc70408e9078c30e80963efccb;p=thirdparty%2Fpostgresql.git Make cast functions to type money error safe This converts the cast functions from types integer, bigint, and numeric to type money to support soft errors. Note: Casting from type money to type numeric (the other way, function cash_numeric) is not yet error safe. Author: jian he Discussion: https://www.postgresql.org/message-id/flat/CADkLM%3Dfv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ%40mail.gmail.com --- diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 623f6eec056..f0487a60f00 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -24,6 +24,7 @@ #include "common/int.h" #include "libpq/pqformat.h" +#include "nodes/miscnodes.h" #include "utils/builtins.h" #include "utils/cash.h" #include "utils/float.h" @@ -1106,12 +1107,12 @@ cash_numeric(PG_FUNCTION_ARGS) Datum numeric_cash(PG_FUNCTION_ARGS) { - Datum amount = PG_GETARG_DATUM(0); + Numeric amount = PG_GETARG_NUMERIC(0); Cash result; int fpoint; int64 scale; int i; - Datum numeric_scale; + Numeric numeric_scale; struct lconv *lconvert = PGLC_localeconv(); /* see comments about frac_digits in cash_in() */ @@ -1125,11 +1126,16 @@ numeric_cash(PG_FUNCTION_ARGS) scale *= 10; /* multiply the input amount by scale factor */ - numeric_scale = NumericGetDatum(int64_to_numeric(scale)); - amount = DirectFunctionCall2(numeric_mul, amount, numeric_scale); + numeric_scale = int64_to_numeric(scale); + + amount = numeric_mul_safe(amount, numeric_scale, fcinfo->context); + if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context))) + PG_RETURN_NULL(); /* note that numeric_int8 will round to nearest integer for us */ - result = DatumGetInt64(DirectFunctionCall1(numeric_int8, amount)); + result = numeric_int8_safe(amount, fcinfo->context); + if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context))) + PG_RETURN_NULL(); PG_RETURN_CASH(result); } @@ -1158,8 +1164,10 @@ int4_cash(PG_FUNCTION_ARGS) scale *= 10; /* compute amount * scale, checking for overflow */ - result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount), - Int64GetDatum(scale))); + if (unlikely(pg_mul_s64_overflow(amount, scale, &result))) + ereturn(fcinfo->context, (Datum) 0, + errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range")); PG_RETURN_CASH(result); } @@ -1188,8 +1196,10 @@ int8_cash(PG_FUNCTION_ARGS) scale *= 10; /* compute amount * scale, checking for overflow */ - result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount), - Int64GetDatum(scale))); + if (unlikely(pg_mul_s64_overflow(amount, scale, &result))) + ereturn(fcinfo->context, (Datum) 0, + errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range")); PG_RETURN_CASH(result); }