From dbb44df103a821bf9769549447ee98313803a1f6 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 9 Oct 2025 18:33:57 +0800
Subject: [PATCH v9 11/19] error safe for casting float4 to other types per
 pg_cast

select castsource::regtype, casttarget::regtype, castfunc,
castcontext,castmethod, pp.prosrc, pp.proname from pg_cast pc join pg_proc pp on
pp.oid = pc.castfunc and pc.castfunc > 0
and castsource::regtype = 'float4'::regtype
order by castsource::regtype;

 castsource |    casttarget    | castfunc | castcontext | castmethod |     prosrc     | proname
------------+------------------+----------+-------------+------------+----------------+---------
 real       | bigint           |      653 | a           | f          | ftoi8          | int8
 real       | smallint         |      238 | a           | f          | ftoi2          | int2
 real       | integer          |      319 | a           | f          | ftoi4          | int4
 real       | double precision |      311 | i           | f          | ftod           | float8
 real       | numeric          |     1742 | a           | f          | float4_numeric | numeric
(5 rows)

discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
---
 src/backend/utils/adt/float.c   | 12 ++++++++++--
 src/backend/utils/adt/int8.c    |  6 +++++-
 src/backend/utils/adt/numeric.c |  3 ++-
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 7b97d2be6ca..dd8a2ff378b 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1298,10 +1298,14 @@ ftoi4(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num)))
-		ereport(ERROR,
+	{
+		errsave(fcinfo->context,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
 
+		PG_RETURN_NULL();
+	}
+
 	PG_RETURN_INT32((int32) num);
 }
 
@@ -1323,10 +1327,14 @@ ftoi2(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num)))
-		ereport(ERROR,
+	{
+		errsave(fcinfo->context,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
 
+		PG_RETURN_NULL();
+	}
+
 	PG_RETURN_INT16((int16) num);
 }
 
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 3b2d100be92..bcdb020a91c 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -1303,10 +1303,14 @@ ftoi8(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT64(num)))
-		ereport(ERROR,
+	{
+		errsave(fcinfo->context,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
 
+		PG_RETURN_NULL();
+	}
+
 	PG_RETURN_INT64((int64) num);
 }
 
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index ce5f71109e7..8839b095f60 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -4668,7 +4668,8 @@ float4_numeric(PG_FUNCTION_ARGS)
 	init_var(&result);
 
 	/* Assume we need not worry about leading/trailing spaces */
-	(void) set_var_from_str(buf, buf, &result, &endptr, NULL);
+	if (!set_var_from_str(buf, buf, &result, &endptr, fcinfo->context))
+		PG_RETURN_NULL();
 
 	res = make_result(&result);
 
-- 
2.34.1

