From 4e74eb428baff34133cc6e5462e8d43edfc256c7 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Mon, 8 Dec 2025 10:02:08 +0800
Subject: [PATCH v14 18/19] error safe for casting geometry data type

select castsource::regtype, casttarget::regtype, pp.prosrc
from pg_cast pc join pg_proc pp on pp.oid = pc.castfunc
join pg_type pt on pt.oid = castsource
join pg_type pt1 on pt1.oid = casttarget
and pc.castfunc > 0 and  pt.typarray <> 0
and pt.typnamespace = 'pg_catalog'::regnamespace
and pt1.typnamespace = 'pg_catalog'::regnamespace
and (pt.typcategory  = 'G' or pt1.typcategory  = 'G')
order by castsource::regtype, casttarget::regtype;

 castsource | casttarget |    prosrc
------------+------------+---------------
 point      | box        | point_box
 lseg       | point      | lseg_center
 path       | polygon    | path_poly
 box        | point      | box_center
 box        | lseg       | box_diagonal
 box        | polygon    | box_poly
 box        | circle     | box_circle
 polygon    | point      | poly_center
 polygon    | path       | poly_path
 polygon    | box        | poly_box
 polygon    | circle     | poly_circle
 circle     | point      | circle_center
 circle     | box        | circle_box
 circle     | polygon    |
(14 rows)

already error safe: point_box, box_diagonal, box_poly, poly_path, poly_box, circle_center
almost error safe: path_poly
patch make these functions error safe: lseg_center, box_center, box_circle, poly_center, poly_circle
circle_box

can not error safe: cast circle to polygon, because it's a SQL function
discussion: https://postgr.es/m/CACJufxHCMzrHOW=wRe8L30rMhB3sjwAv1LE928Fa7sxMu1Tx-g@mail.gmail.com
---
 contrib/btree_gist/btree_float4.c |   2 +-
 contrib/btree_gist/btree_float8.c |   4 +-
 src/backend/utils/adt/float.c     | 104 ++++++------
 src/backend/utils/adt/geo_ops.c   | 268 ++++++++++++++++++++++--------
 src/include/utils/float.h         | 110 ++++++++----
 5 files changed, 330 insertions(+), 158 deletions(-)

diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index d9c859835da..a7325a7bb29 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -101,7 +101,7 @@ float4_dist(PG_FUNCTION_ARGS)
 
 	r = a - b;
 	if (unlikely(isinf(r)) && !isinf(a) && !isinf(b))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT4(fabsf(r));
 }
diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c
index 567beede178..7c99b84de35 100644
--- a/contrib/btree_gist/btree_float8.c
+++ b/contrib/btree_gist/btree_float8.c
@@ -79,7 +79,7 @@ gbt_float8_dist(const void *a, const void *b, FmgrInfo *flinfo)
 
 	r = arg1 - arg2;
 	if (unlikely(isinf(r)) && !isinf(arg1) && !isinf(arg2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	return fabs(r);
 }
 
@@ -109,7 +109,7 @@ float8_dist(PG_FUNCTION_ARGS)
 
 	r = a - b;
 	if (unlikely(isinf(r)) && !isinf(a) && !isinf(b))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(fabs(r));
 }
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 55c7030ba81..2710e42f5bb 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -83,25 +83,25 @@ static void init_degree_constants(void);
  * This does mean that you don't get a useful error location indicator.
  */
 pg_noinline void
-float_overflow_error(void)
+float_overflow_error(struct Node *escontext)
 {
-	ereport(ERROR,
+	errsave(escontext,
 			(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 			 errmsg("value out of range: overflow")));
 }
 
 pg_noinline void
-float_underflow_error(void)
+float_underflow_error(struct Node *escontext)
 {
-	ereport(ERROR,
+	errsave(escontext,
 			(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 			 errmsg("value out of range: underflow")));
 }
 
 pg_noinline void
-float_zero_divide_error(void)
+float_zero_divide_error(struct Node *escontext)
 {
-	ereport(ERROR,
+	errsave(escontext,
 			(errcode(ERRCODE_DIVISION_BY_ZERO),
 			 errmsg("division by zero")));
 }
@@ -1460,9 +1460,9 @@ dsqrt(PG_FUNCTION_ARGS)
 
 	result = sqrt(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 0.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1479,9 +1479,9 @@ dcbrt(PG_FUNCTION_ARGS)
 
 	result = cbrt(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 0.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1617,24 +1617,24 @@ dpow(PG_FUNCTION_ARGS)
 				if (absx == 1.0)
 					result = 1.0;
 				else if (arg2 >= 0.0 ? (absx > 1.0) : (absx < 1.0))
-					float_overflow_error();
+					float_overflow_error(NULL);
 				else
-					float_underflow_error();
+					float_underflow_error(NULL);
 			}
 		}
 		else if (errno == ERANGE)
 		{
 			if (result != 0.0)
-				float_overflow_error();
+				float_overflow_error(NULL);
 			else
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 		else
 		{
 			if (unlikely(isinf(result)))
-				float_overflow_error();
+				float_overflow_error(NULL);
 			if (unlikely(result == 0.0) && arg1 != 0.0)
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 	}
 
@@ -1674,14 +1674,14 @@ dexp(PG_FUNCTION_ARGS)
 		if (unlikely(errno == ERANGE))
 		{
 			if (result != 0.0)
-				float_overflow_error();
+				float_overflow_error(NULL);
 			else
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 		else if (unlikely(isinf(result)))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		else if (unlikely(result == 0.0))
-			float_underflow_error();
+			float_underflow_error(NULL);
 	}
 
 	PG_RETURN_FLOAT8(result);
@@ -1712,9 +1712,9 @@ dlog1(PG_FUNCTION_ARGS)
 
 	result = log(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 1.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1745,9 +1745,9 @@ dlog10(PG_FUNCTION_ARGS)
 
 	result = log10(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 1.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1778,7 +1778,7 @@ dacos(PG_FUNCTION_ARGS)
 
 	result = acos(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1809,7 +1809,7 @@ dasin(PG_FUNCTION_ARGS)
 
 	result = asin(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1835,7 +1835,7 @@ datan(PG_FUNCTION_ARGS)
 	 */
 	result = atan(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1861,7 +1861,7 @@ datan2(PG_FUNCTION_ARGS)
 	 */
 	result = atan2(arg1, arg2);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1902,7 +1902,7 @@ dcos(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1957,7 +1957,7 @@ dsin(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2137,7 +2137,7 @@ dacosd(PG_FUNCTION_ARGS)
 		result = 90.0 + asind_q1(-arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2174,7 +2174,7 @@ dasind(PG_FUNCTION_ARGS)
 		result = -asind_q1(-arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2206,7 +2206,7 @@ datand(PG_FUNCTION_ARGS)
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2242,7 +2242,7 @@ datan2d(PG_FUNCTION_ARGS)
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2365,7 +2365,7 @@ dcosd(PG_FUNCTION_ARGS)
 	result = sign * cosd_q1(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2487,7 +2487,7 @@ dsind(PG_FUNCTION_ARGS)
 	result = sign * sind_q1(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2645,7 +2645,7 @@ dcosh(PG_FUNCTION_ARGS)
 		result = get_float8_infinity();
 
 	if (unlikely(result == 0.0))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2665,7 +2665,7 @@ dtanh(PG_FUNCTION_ARGS)
 	result = tanh(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2765,7 +2765,7 @@ derf(PG_FUNCTION_ARGS)
 	result = erf(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2785,7 +2785,7 @@ derfc(PG_FUNCTION_ARGS)
 	result = erfc(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2814,7 +2814,7 @@ dgamma(PG_FUNCTION_ARGS)
 		/* Per POSIX, an input of -Inf causes a domain error */
 		if (arg1 < 0)
 		{
-			float_overflow_error();
+			float_overflow_error(NULL);
 			result = get_float8_nan();	/* keep compiler quiet */
 		}
 		else
@@ -2836,12 +2836,12 @@ dgamma(PG_FUNCTION_ARGS)
 		if (errno != 0 || isinf(result) || isnan(result))
 		{
 			if (result != 0.0)
-				float_overflow_error();
+				float_overflow_error(NULL);
 			else
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 		else if (result == 0.0)
-			float_underflow_error();
+			float_underflow_error(NULL);
 	}
 
 	PG_RETURN_FLOAT8(result);
@@ -2873,7 +2873,7 @@ dlgamma(PG_FUNCTION_ARGS)
 	 * to report overflow, but it should never underflow.
 	 */
 	if (errno == ERANGE || (isinf(result) && !isinf(arg1)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -3013,7 +3013,7 @@ float8_combine(PG_FUNCTION_ARGS)
 		tmp = Sx1 / N1 - Sx2 / N2;
 		Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N;
 		if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 	}
 
 	/*
@@ -3080,7 +3080,7 @@ float8_accum(PG_FUNCTION_ARGS)
 		if (isinf(Sx) || isinf(Sxx))
 		{
 			if (!isinf(transvalues[1]) && !isinf(newval))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			Sxx = get_float8_nan();
 		}
@@ -3163,7 +3163,7 @@ float4_accum(PG_FUNCTION_ARGS)
 		if (isinf(Sx) || isinf(Sxx))
 		{
 			if (!isinf(transvalues[1]) && !isinf(newval))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			Sxx = get_float8_nan();
 		}
@@ -3430,7 +3430,7 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 				(isinf(Sxy) &&
 				 !isinf(transvalues[1]) && !isinf(newvalX) &&
 				 !isinf(transvalues[3]) && !isinf(newvalY)))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			if (isinf(Sxx))
 				Sxx = get_float8_nan();
@@ -3603,15 +3603,15 @@ float8_regr_combine(PG_FUNCTION_ARGS)
 		tmp1 = Sx1 / N1 - Sx2 / N2;
 		Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N;
 		if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		Sy = float8_pl(Sy1, Sy2);
 		tmp2 = Sy1 / N1 - Sy2 / N2;
 		Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N;
 		if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N;
 		if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		if (float8_eq(Cx1, Cx2))
 			Cx = Cx1;
 		else
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 9101a720744..19f75e59a6d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -77,12 +77,13 @@ enum path_delim
 
 /* Routines for points */
 static inline void point_construct(Point *result, float8 x, float8 y);
-static inline void point_add_point(Point *result, Point *pt1, Point *pt2);
+static inline void point_add_point(Point *result, Point *pt1, Point *pt2,
+								   Node *escontext);
 static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
 static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
 static inline bool point_eq_point(Point *pt1, Point *pt2);
-static inline float8 point_dt(Point *pt1, Point *pt2);
+static inline float8 point_dt(Point *pt1, Point *pt2, Node *escontext);
 static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
@@ -108,7 +109,7 @@ static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg);
 
 /* Routines for boxes */
 static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
-static void box_cn(Point *center, BOX *box);
+static void box_cn(Point *center, BOX *box, Node* escontext);
 static bool box_ov(BOX *box1, BOX *box2);
 static float8 box_ar(BOX *box);
 static float8 box_ht(BOX *box);
@@ -125,7 +126,7 @@ static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
-static void poly_to_circle(CIRCLE *result, POLYGON *poly);
+static bool poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static bool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly);
 static bool plist_same(int npts, Point *p1, Point *p2);
@@ -836,10 +837,10 @@ box_distance(PG_FUNCTION_ARGS)
 	Point		a,
 				b;
 
-	box_cn(&a, box1);
-	box_cn(&b, box2);
+	box_cn(&a, box1, NULL);
+	box_cn(&b, box2, NULL);
 
-	PG_RETURN_FLOAT8(point_dt(&a, &b));
+	PG_RETURN_FLOAT8(point_dt(&a, &b, NULL));
 }
 
 
@@ -851,7 +852,9 @@ box_center(PG_FUNCTION_ARGS)
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	Point	   *result = (Point *) palloc(sizeof(Point));
 
-	box_cn(result, box);
+	box_cn(result, box, fcinfo->context);
+	if ((SOFT_ERROR_OCCURRED(fcinfo->context)))
+		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
 }
@@ -869,13 +872,26 @@ box_ar(BOX *box)
 /*		box_cn	-		stores the centerpoint of the box into *center.
  */
 static void
-box_cn(Point *center, BOX *box)
+box_cn(Point *center, BOX *box, Node *escontext)
 {
-	center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
-	center->y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
+	float8		x;
+	float8		y;
+
+	x = float8_pl_safe(box->high.x, box->low.x, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
+
+	center->x = float8_div_safe(x, 2.0, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
+
+	y = float8_pl_safe(box->high.y, box->low.y, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
+
+	center->y = float8_div_safe(y, 2.0, escontext);
 }
 
-
 /*		box_wd	-		returns the width (length) of the box
  *								  (horizontal magnitude).
  */
@@ -1808,7 +1824,7 @@ path_length(PG_FUNCTION_ARGS)
 			iprev = path->npts - 1; /* include the closure segment */
 		}
 
-		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i]));
+		result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i], NULL));
 	}
 
 	PG_RETURN_FLOAT8(result);
@@ -1995,13 +2011,24 @@ point_distance(PG_FUNCTION_ARGS)
 	Point	   *pt1 = PG_GETARG_POINT_P(0);
 	Point	   *pt2 = PG_GETARG_POINT_P(1);
 
-	PG_RETURN_FLOAT8(point_dt(pt1, pt2));
+	PG_RETURN_FLOAT8(point_dt(pt1, pt2, NULL));
 }
 
 static inline float8
-point_dt(Point *pt1, Point *pt2)
+point_dt(Point *pt1, Point *pt2, Node *escontext)
 {
-	return hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
+	float8		x;
+	float8		y;
+
+	x = float8_mi_safe(pt1->x, pt2->x, escontext);
+	if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
+		return 0.0;
+
+	y  = float8_mi_safe(pt1->y, pt2->y, escontext);
+	if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
+		return 0.0;
+
+	return hypot(x, y);
 }
 
 Datum
@@ -2173,7 +2200,7 @@ lseg_length(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 
-	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
+	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1], NULL));
 }
 
 /*----------------------------------------------------------
@@ -2258,8 +2285,8 @@ lseg_lt(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
-						point_dt(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1], NULL),
+						point_dt(&l2->p[0], &l2->p[1], NULL)));
 }
 
 Datum
@@ -2268,8 +2295,8 @@ lseg_le(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1]),
-						point_dt(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1], NULL),
+						point_dt(&l2->p[0], &l2->p[1], NULL)));
 }
 
 Datum
@@ -2278,8 +2305,8 @@ lseg_gt(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1]),
-						point_dt(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1], NULL),
+						point_dt(&l2->p[0], &l2->p[1], NULL)));
 }
 
 Datum
@@ -2288,8 +2315,8 @@ lseg_ge(PG_FUNCTION_ARGS)
 	LSEG	   *l1 = PG_GETARG_LSEG_P(0);
 	LSEG	   *l2 = PG_GETARG_LSEG_P(1);
 
-	PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1]),
-						point_dt(&l2->p[0], &l2->p[1])));
+	PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1], NULL),
+						point_dt(&l2->p[0], &l2->p[1], NULL)));
 }
 
 
@@ -2317,13 +2344,31 @@ lseg_center(PG_FUNCTION_ARGS)
 {
 	LSEG	   *lseg = PG_GETARG_LSEG_P(0);
 	Point	   *result;
+	float8		x;
+	float8		y;
 
 	result = (Point *) palloc(sizeof(Point));
 
-	result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0);
-	result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0);
+	x = float8_pl_safe(lseg->p[0].x, lseg->p[1].x, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	result->x = float8_div_safe(x, 2.0, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	y = float8_pl_safe(lseg->p[0].y, lseg->p[1].y, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	result->y = float8_div_safe(y, 2.0, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
 
 	PG_RETURN_POINT_P(result);
+
+fail:
+	PG_RETURN_NULL();
 }
 
 
@@ -2743,7 +2788,7 @@ line_closept_point(Point *result, LINE *line, Point *point)
 	if (result != NULL)
 		*result = closept;
 
-	return point_dt(&closept, point);
+	return point_dt(&closept, point, NULL);
 }
 
 Datum
@@ -2784,7 +2829,7 @@ lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
 	if (result != NULL)
 		*result = closept;
 
-	return point_dt(&closept, pt);
+	return point_dt(&closept, pt, NULL);
 }
 
 Datum
@@ -3108,9 +3153,9 @@ on_pl(PG_FUNCTION_ARGS)
 static bool
 lseg_contain_point(LSEG *lseg, Point *pt)
 {
-	return FPeq(point_dt(pt, &lseg->p[0]) +
-				point_dt(pt, &lseg->p[1]),
-				point_dt(&lseg->p[0], &lseg->p[1]));
+	return FPeq(point_dt(pt, &lseg->p[0], NULL) +
+				point_dt(pt, &lseg->p[1], NULL),
+				point_dt(&lseg->p[0], &lseg->p[1], NULL));
 }
 
 Datum
@@ -3176,11 +3221,11 @@ on_ppath(PG_FUNCTION_ARGS)
 	if (!path->closed)
 	{
 		n = path->npts - 1;
-		a = point_dt(pt, &path->p[0]);
+		a = point_dt(pt, &path->p[0], NULL);
 		for (i = 0; i < n; i++)
 		{
-			b = point_dt(pt, &path->p[i + 1]);
-			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])))
+			b = point_dt(pt, &path->p[i + 1], NULL);
+			if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1], NULL)))
 				PG_RETURN_BOOL(true);
 			a = b;
 		}
@@ -3277,7 +3322,7 @@ box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
 
 	if (result != NULL)
 	{
-		box_cn(&point, box);
+		box_cn(&point, box, NULL);
 		lseg_closept_point(result, lseg, &point);
 	}
 
@@ -4108,11 +4153,20 @@ construct_point(PG_FUNCTION_ARGS)
 
 
 static inline void
-point_add_point(Point *result, Point *pt1, Point *pt2)
+point_add_point(Point *result, Point *pt1, Point *pt2, Node *escontext)
 {
-	point_construct(result,
-					float8_pl(pt1->x, pt2->x),
-					float8_pl(pt1->y, pt2->y));
+	float8		x;
+	float8		y;
+
+	x = float8_pl_safe(pt1->x, pt2->x, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
+
+	y = float8_pl_safe(pt1->y, pt2->y, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return;
+
+	point_construct(result, x, y);
 }
 
 Datum
@@ -4124,7 +4178,7 @@ point_add(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	point_add_point(result, p1, p2);
+	point_add_point(result, p1, p2, NULL);
 
 	PG_RETURN_POINT_P(result);
 }
@@ -4236,8 +4290,8 @@ box_add(PG_FUNCTION_ARGS)
 
 	result = (BOX *) palloc(sizeof(BOX));
 
-	point_add_point(&result->high, &box->high, p);
-	point_add_point(&result->low, &box->low, p);
+	point_add_point(&result->high, &box->high, p, NULL);
+	point_add_point(&result->low, &box->low, p, NULL);
 
 	PG_RETURN_BOX_P(result);
 }
@@ -4400,7 +4454,7 @@ path_add_pt(PG_FUNCTION_ARGS)
 	int			i;
 
 	for (i = 0; i < path->npts; i++)
-		point_add_point(&path->p[i], &path->p[i], point);
+		point_add_point(&path->p[i], &path->p[i], point, NULL);
 
 	PG_RETURN_PATH_P(path);
 }
@@ -4458,7 +4512,7 @@ path_poly(PG_FUNCTION_ARGS)
 
 	/* This is not very consistent --- other similar cases return NULL ... */
 	if (!path->closed)
-		ereport(ERROR,
+		ereturn(fcinfo->context, (Datum) 0,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("open path cannot be converted to polygon")));
 
@@ -4508,7 +4562,9 @@ poly_center(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	poly_to_circle(&circle, poly);
+	if (!poly_to_circle(&circle, poly, fcinfo->context))
+		PG_RETURN_NULL();
+
 	*result = circle.center;
 
 	PG_RETURN_POINT_P(result);
@@ -4766,7 +4822,7 @@ circle_overlap(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
 						float8_pl(circle1->radius, circle2->radius)));
 }
 
@@ -4828,7 +4884,7 @@ circle_contained(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
 						float8_mi(circle2->radius, circle1->radius)));
 }
 
@@ -4840,7 +4896,7 @@ circle_contain(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
-	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
+	PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
 						float8_mi(circle1->radius, circle2->radius)));
 }
 
@@ -4970,7 +5026,7 @@ circle_add_pt(PG_FUNCTION_ARGS)
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	point_add_point(&result->center, &circle->center, point);
+	point_add_point(&result->center, &circle->center, point, NULL);
 	result->radius = circle->radius;
 
 	PG_RETURN_CIRCLE_P(result);
@@ -5069,7 +5125,7 @@ circle_distance(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = float8_mi(point_dt(&circle1->center, &circle2->center),
+	result = float8_mi(point_dt(&circle1->center, &circle2->center, NULL),
 					   float8_pl(circle1->radius, circle2->radius));
 	if (result < 0.0)
 		result = 0.0;
@@ -5085,7 +5141,7 @@ circle_contain_pt(PG_FUNCTION_ARGS)
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		d;
 
-	d = point_dt(&circle->center, point);
+	d = point_dt(&circle->center, point, NULL);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
@@ -5097,7 +5153,7 @@ pt_contained_circle(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		d;
 
-	d = point_dt(&circle->center, point);
+	d = point_dt(&circle->center, point, NULL);
 	PG_RETURN_BOOL(d <= circle->radius);
 }
 
@@ -5112,7 +5168,7 @@ dist_pc(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	float8		result;
 
-	result = float8_mi(point_dt(point, &circle->center),
+	result = float8_mi(point_dt(point, &circle->center, NULL),
 					   circle->radius);
 	if (result < 0.0)
 		result = 0.0;
@@ -5130,7 +5186,7 @@ dist_cpoint(PG_FUNCTION_ARGS)
 	Point	   *point = PG_GETARG_POINT_P(1);
 	float8		result;
 
-	result = float8_mi(point_dt(point, &circle->center), circle->radius);
+	result = float8_mi(point_dt(point, &circle->center, NULL), circle->radius);
 	if (result < 0.0)
 		result = 0.0;
 
@@ -5191,14 +5247,30 @@ circle_box(PG_FUNCTION_ARGS)
 
 	box = (BOX *) palloc(sizeof(BOX));
 
-	delta = float8_div(circle->radius, sqrt(2.0));
+	delta = float8_div_safe(circle->radius, sqrt(2.0), fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
 
-	box->high.x = float8_pl(circle->center.x, delta);
-	box->low.x = float8_mi(circle->center.x, delta);
-	box->high.y = float8_pl(circle->center.y, delta);
-	box->low.y = float8_mi(circle->center.y, delta);
+	box->high.x = float8_pl_safe(circle->center.x, delta, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	box->low.x = float8_mi_safe(circle->center.x, delta, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	box->high.y = float8_pl_safe(circle->center.y, delta, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	box->low.y = float8_mi_safe(circle->center.y, delta, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
 
 	PG_RETURN_BOX_P(box);
+
+fail:
+	PG_RETURN_NULL();
 }
 
 /* box_circle()
@@ -5209,15 +5281,35 @@ box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
+	float8		x;
+	float8		y;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0);
-	circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 2.0);
+	x = float8_pl_safe(box->high.x, box->low.x, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
 
-	circle->radius = point_dt(&circle->center, &box->high);
+	circle->center.x = float8_div_safe(x, 2.0, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	y = float8_pl_safe(box->high.y, box->low.y, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	circle->center.y = float8_div_safe(y, 2.0, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
+
+	circle->radius = point_dt(&circle->center, &box->high, fcinfo->context);
+	if (SOFT_ERROR_OCCURRED(fcinfo->context))
+		goto fail;
 
 	PG_RETURN_CIRCLE_P(circle);
+
+fail:
+	PG_RETURN_NULL();
 }
 
 
@@ -5281,10 +5373,11 @@ circle_poly(PG_FUNCTION_ARGS)
  * XXX This algorithm should use weighted means of line segments
  *	rather than straight average values of points - tgl 97/01/21.
  */
-static void
-poly_to_circle(CIRCLE *result, POLYGON *poly)
+static bool
+poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext)
 {
 	int			i;
+	float8		x;
 
 	Assert(poly->npts > 0);
 
@@ -5293,14 +5386,44 @@ poly_to_circle(CIRCLE *result, POLYGON *poly)
 	result->radius = 0;
 
 	for (i = 0; i < poly->npts; i++)
-		point_add_point(&result->center, &result->center, &poly->p[i]);
-	result->center.x = float8_div(result->center.x, poly->npts);
-	result->center.y = float8_div(result->center.y, poly->npts);
+	{
+		point_add_point(&result->center,
+						&result->center,
+						&poly->p[i],
+						escontext);
+
+		if (SOFT_ERROR_OCCURRED(escontext))
+			return false;
+	}
+
+	result->center.x = float8_div_safe(result->center.x,
+									   poly->npts,
+									   escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
+
+	result->center.y = float8_div_safe(result->center.y,
+									   poly->npts,
+									   escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
 
 	for (i = 0; i < poly->npts; i++)
-		result->radius = float8_pl(result->radius,
-								   point_dt(&poly->p[i], &result->center));
-	result->radius = float8_div(result->radius, poly->npts);
+	{
+		x = point_dt(&poly->p[i], &result->center, escontext);
+		if (SOFT_ERROR_OCCURRED(escontext))
+			return false;
+
+		result->radius = float8_pl_safe(result->radius, x, escontext);
+		if (SOFT_ERROR_OCCURRED(escontext))
+			return false;
+	}
+
+	result->radius = float8_div_safe(result->radius, poly->npts, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
+
+	return true;
 }
 
 Datum
@@ -5311,7 +5434,8 @@ poly_circle(PG_FUNCTION_ARGS)
 
 	result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
-	poly_to_circle(result, poly);
+	if (!poly_to_circle(result, poly, fcinfo->context))
+		PG_RETURN_NULL();
 
 	PG_RETURN_CIRCLE_P(result);
 }
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index fc2a9cf6475..1b37e17defc 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -30,9 +30,9 @@ extern PGDLLIMPORT int extra_float_digits;
 /*
  * Utility functions in float.c
  */
-pg_noreturn extern void float_overflow_error(void);
-pg_noreturn extern void float_underflow_error(void);
-pg_noreturn extern void float_zero_divide_error(void);
+extern void float_overflow_error(struct Node *escontext);
+extern void float_underflow_error(struct Node *escontext);
+extern void float_zero_divide_error(struct Node *escontext);
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
 								const char *type_name, const char *orig_string,
@@ -104,7 +104,22 @@ float4_pl(const float4 val1, const float4 val2)
 
 	result = val1 + val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
+
+	return result;
+}
+
+static inline float8
+float8_pl_safe(const float8 val1, const float8 val2, struct Node *escontext)
+{
+	float8		result;
+
+	result = val1 + val2;
+	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
+	{
+		float_overflow_error(escontext);
+		return 0.0;
+	}
 
 	return result;
 }
@@ -112,13 +127,7 @@ float4_pl(const float4 val1, const float4 val2)
 static inline float8
 float8_pl(const float8 val1, const float8 val2)
 {
-	float8		result;
-
-	result = val1 + val2;
-	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
-
-	return result;
+	return float8_pl_safe(val1, val2, NULL);
 }
 
 static inline float4
@@ -128,7 +137,22 @@ float4_mi(const float4 val1, const float4 val2)
 
 	result = val1 - val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
+
+	return result;
+}
+
+static inline float8
+float8_mi_safe(const float8 val1, const float8 val2, struct Node *escontext)
+{
+	float8		result;
+
+	result = val1 - val2;
+	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
+	{
+		float_overflow_error(escontext);
+		return 0.0;
+	}
 
 	return result;
 }
@@ -136,13 +160,7 @@ float4_mi(const float4 val1, const float4 val2)
 static inline float8
 float8_mi(const float8 val1, const float8 val2)
 {
-	float8		result;
-
-	result = val1 - val2;
-	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
-
-	return result;
+	return float8_mi_safe(val1, val2, NULL);
 }
 
 static inline float4
@@ -152,59 +170,89 @@ float4_mul(const float4 val1, const float4 val2)
 
 	result = val1 * val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
 
 static inline float8
-float8_mul(const float8 val1, const float8 val2)
+float8_mul_safe(const float8 val1, const float8 val2, struct Node *escontext)
 {
 	float8		result;
 
 	result = val1 * val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+	{
+		float_overflow_error(escontext);
+		return 0.0;
+	}
+
 	if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
-		float_underflow_error();
+	{
+		float_underflow_error(escontext);
+		return 0.0;
+	}
 
 	return result;
 }
 
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	return float8_mul_safe(val1, val2, NULL);
+}
+
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
 	float4		result;
 
 	if (unlikely(val2 == 0.0f) && !isnan(val1))
-		float_zero_divide_error();
+		float_zero_divide_error(NULL);
 	result = val1 / val2;
 	if (unlikely(isinf(result)) && !isinf(val1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
 
 static inline float8
-float8_div(const float8 val1, const float8 val2)
+float8_div_safe(const float8 val1, const float8 val2, struct Node *escontext)
 {
 	float8		result;
 
 	if (unlikely(val2 == 0.0) && !isnan(val1))
-		float_zero_divide_error();
+	{
+		float_zero_divide_error(escontext);
+		return 0.0;
+	}
+
 	result = val1 / val2;
 	if (unlikely(isinf(result)) && !isinf(val1))
-		float_overflow_error();
+	{
+		float_overflow_error(escontext);
+		return 0.0;
+	}
+
 	if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
-		float_underflow_error();
+	{
+		float_underflow_error(escontext);
+		return 0.0;
+	}
 
 	return result;
 }
 
+static inline float8
+float8_div(const float8 val1, const float8 val2)
+{
+	return float8_div_safe(val1, val2, NULL);
+}
+
 /*
  * Routines for NaN-aware comparisons
  *
-- 
2.34.1

