From 5558c75ac6876a83e739a4a219f4f166f3fa8a06 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 9 Oct 2025 18:41:55 +0800
Subject: [PATCH v7 12/20] error safe for casting float8 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 = 'float8'::regtype
order by castsource::regtype;

    castsource    | casttarget | castfunc | castcontext | castmethod |     prosrc     | proname
------------------+------------+----------+-------------+------------+----------------+---------
 double precision | bigint     |      483 | a           | f          | dtoi8          | int8
 double precision | smallint   |      237 | a           | f          | dtoi2          | int2
 double precision | integer    |      317 | a           | f          | dtoi4          | int4
 double precision | real       |      312 | a           | f          | dtof           | float4
 double precision | numeric    |     1743 | a           | f          | float8_numeric | numeric
(5 rows)

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

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index dd8a2ff378b..6747544b679 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1199,9 +1199,22 @@ dtof(PG_FUNCTION_ARGS)
 
 	result = (float4) num;
 	if (unlikely(isinf(result)) && !isinf(num))
-		float_overflow_error();
+	{
+		errsave(fcinfo->context,
+				errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				errmsg("value out of range: overflow"));
+
+		PG_RETURN_NULL();
+	}
+
 	if (unlikely(result == 0.0f) && num != 0.0)
-		float_underflow_error();
+	{
+		errsave(fcinfo->context,
+				errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				errmsg("value out of range: underflow"));
+
+		PG_RETURN_NULL();
+	}
 
 	PG_RETURN_FLOAT4(result);
 }
@@ -1224,10 +1237,14 @@ dtoi4(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT8_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);
 }
 
@@ -1249,10 +1266,14 @@ dtoi2(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT8_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 bcdb020a91c..437dbbccd4a 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -1268,10 +1268,14 @@ dtoi8(PG_FUNCTION_ARGS)
 
 	/* Range check */
 	if (unlikely(isnan(num) || !FLOAT8_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 8839b095f60..76cd9800c2a 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -4570,7 +4570,8 @@ float8_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

