]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make geometry cast functions error safe
authorPeter Eisentraut <peter@eisentraut.org>
Sun, 29 Mar 2026 18:40:50 +0000 (20:40 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Sun, 29 Mar 2026 18:40:50 +0000 (20:40 +0200)
This adjusts cast functions of the geometry types to support soft
errors.  This requires refactoring of various helper functions to
support error contexts.  Also make the float8 to float4 cast error
safe.  It requires some of the same helper functions.

This is in preparation for a future feature where conversion errors in
casts can be caught.

(The function casting type circle to type polygon is not yet made error
safe, because it is an SQL language function.)

Author: jian he <jian.universality@gmail.com>
Reviewed-by: Amul Sul <sulamul@gmail.com>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CADkLM%3Dfv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ%40mail.gmail.com

src/backend/utils/adt/float.c
src/backend/utils/adt/geo_ops.c
src/include/utils/float.h

index a06fef4290122c71232edbe1bfc8e1452355e48c..362c29ab80356c42faf4afc3401470b2449862e8 100644 (file)
@@ -123,6 +123,30 @@ float_zero_divide_error(void)
                         errmsg("division by zero")));
 }
 
+float8
+float_overflow_error_ext(struct Node *escontext)
+{
+       ereturn(escontext, 0.0,
+                       errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                       errmsg("value out of range: overflow"));
+}
+
+float8
+float_underflow_error_ext(struct Node *escontext)
+{
+       ereturn(escontext, 0.0,
+                       errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                       errmsg("value out of range: underflow"));
+}
+
+float8
+float_zero_divide_error_ext(struct Node *escontext)
+{
+       ereturn(escontext, 0.0,
+                       (errcode(ERRCODE_DIVISION_BY_ZERO),
+                        errmsg("division by zero")));
+}
+
 
 /*
  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
@@ -1216,9 +1240,9 @@ dtof(PG_FUNCTION_ARGS)
 
        result = (float4) num;
        if (unlikely(isinf(result)) && !isinf(num))
-               float_overflow_error();
+               float_overflow_error_ext(fcinfo->context);
        if (unlikely(result == 0.0f) && num != 0.0)
-               float_underflow_error();
+               float_underflow_error_ext(fcinfo->context);
 
        PG_RETURN_FLOAT4(result);
 }
index bfb4859b4cb635caf7d04b7216fb7c2852b61286..cbc4621e9b20d397f7beadeda999bcf7a1a22df9 100644 (file)
@@ -77,12 +77,12 @@ 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 +108,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 +125,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 void 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 +836,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 +851,9 @@ box_center(PG_FUNCTION_ARGS)
        BOX                *box = PG_GETARG_BOX_P(0);
        Point      *result = palloc_object(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,12 +871,27 @@ 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);
+       if (SOFT_ERROR_OCCURRED(escontext))
+               return;
+}
 
 /*             box_wd  -               returns the width (length) of the box
  *                                                               (horizontal magnitude).
@@ -1808,7 +1825,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 +2012,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 +2201,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 +2286,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 +2296,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 +2306,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 +2316,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 +2345,31 @@ lseg_center(PG_FUNCTION_ARGS)
 {
        LSEG       *lseg = PG_GETARG_LSEG_P(0);
        Point      *result;
+       float8          x;
+       float8          y;
 
        result = palloc_object(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 +2789,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 +2830,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 +3154,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 +3222,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 +3323,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 +4154,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 +4179,7 @@ point_add(PG_FUNCTION_ARGS)
 
        result = palloc_object(Point);
 
-       point_add_point(result, p1, p2);
+       point_add_point(result, p1, p2, NULL);
 
        PG_RETURN_POINT_P(result);
 }
@@ -4236,8 +4291,8 @@ box_add(PG_FUNCTION_ARGS)
 
        result = palloc_object(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 +4455,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 +4513,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 +4563,10 @@ poly_center(PG_FUNCTION_ARGS)
 
        result = palloc_object(Point);
 
-       poly_to_circle(&circle, poly);
+       poly_to_circle(&circle, poly, fcinfo->context);
+       if (SOFT_ERROR_OCCURRED(fcinfo->context))
+               PG_RETURN_NULL();
+
        *result = circle.center;
 
        PG_RETURN_POINT_P(result);
@@ -4766,7 +4824,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 +4886,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 +4898,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 +5028,7 @@ circle_add_pt(PG_FUNCTION_ARGS)
 
        result = palloc_object(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 +5127,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 +5143,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 +5155,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 +5170,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 +5188,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 +5249,30 @@ circle_box(PG_FUNCTION_ARGS)
 
        box = palloc_object(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_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->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->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 +5283,37 @@ box_circle(PG_FUNCTION_ARGS)
 {
        BOX                *box = PG_GETARG_BOX_P(0);
        CIRCLE     *circle;
+       float8          x;
+       float8          y;
 
        circle = palloc_object(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->center.x = float8_div_safe(x, 2.0, fcinfo->context);
+       if (SOFT_ERROR_OCCURRED(fcinfo->context))
+               goto fail;
 
-       circle->radius = point_dt(&circle->center, &box->high);
+       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();
 }
 
 
@@ -5282,9 +5378,10 @@ circle_poly(PG_FUNCTION_ARGS)
  *     rather than straight average values of points - tgl 97/01/21.
  */
 static void
-poly_to_circle(CIRCLE *result, POLYGON *poly)
+poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext)
 {
        int                     i;
+       float8          x;
 
        Assert(poly->npts > 0);
 
@@ -5293,14 +5390,34 @@ 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;
+       }
+
+       result->center.x = float8_div_safe(result->center.x, poly->npts, escontext);
+       if (SOFT_ERROR_OCCURRED(escontext))
+               return;
+
+       result->center.y = float8_div_safe(result->center.y, poly->npts, escontext);
+       if (SOFT_ERROR_OCCURRED(escontext))
+               return;
 
        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;
+
+               result->radius = float8_pl_safe(result->radius, x, escontext);
+               if (SOFT_ERROR_OCCURRED(escontext))
+                       return;
+       }
+
+       result->radius = float8_div_safe(result->radius, poly->npts, escontext);
+       if (SOFT_ERROR_OCCURRED(escontext))
+               return;
 }
 
 Datum
@@ -5311,7 +5428,9 @@ poly_circle(PG_FUNCTION_ARGS)
 
        result = palloc_object(CIRCLE);
 
-       poly_to_circle(result, poly);
+       poly_to_circle(result, poly, fcinfo->context);
+       if (SOFT_ERROR_OCCURRED(fcinfo->context))
+               PG_RETURN_NULL();
 
        PG_RETURN_CIRCLE_P(result);
 }
index b340678ca92b9f7411d6d1083ab2ab311c3d51c2..ffa743d6273104efdf6dcd92501bdaa8420aef47 100644 (file)
@@ -33,6 +33,9 @@ extern PGDLLIMPORT int extra_float_digits;
 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 float8 float_overflow_error_ext(struct Node *escontext);
+extern float8 float_underflow_error_ext(struct Node *escontext);
+extern float8 float_zero_divide_error_ext(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,
@@ -110,17 +113,23 @@ float4_pl(const float4 val1, const float4 val2)
 }
 
 static inline float8
-float8_pl(const float8 val1, const float8 val2)
+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();
+               return float_overflow_error_ext(escontext);
 
        return result;
 }
 
+static inline float8
+float8_pl(const float8 val1, const float8 val2)
+{
+       return float8_pl_safe(val1, val2, NULL);
+}
+
 static inline float4
 float4_mi(const float4 val1, const float4 val2)
 {
@@ -134,17 +143,23 @@ float4_mi(const float4 val1, const float4 val2)
 }
 
 static inline float8
-float8_mi(const float8 val1, const float8 val2)
+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();
+               return float_overflow_error_ext(escontext);
 
        return result;
 }
 
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+       return float8_mi_safe(val1, val2, NULL);
+}
+
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
@@ -160,19 +175,25 @@ float4_mul(const float4 val1, const float4 val2)
 }
 
 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();
+               return float_overflow_error_ext(escontext);
        if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
-               float_underflow_error();
+               return float_underflow_error_ext(escontext);
 
        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)
 {
@@ -190,21 +211,27 @@ float4_div(const float4 val1, const float4 val2)
 }
 
 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();
+               return float_zero_divide_error_ext(escontext);
        result = val1 / val2;
        if (unlikely(isinf(result)) && !isinf(val1))
-               float_overflow_error();
+               return float_overflow_error_ext(escontext);
        if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
-               float_underflow_error();
+               return float_underflow_error_ext(escontext);
 
        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
  *