]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make cast function from circle to polygon error safe
authorPeter Eisentraut <peter@eisentraut.org>
Mon, 30 Mar 2026 07:06:27 +0000 (09:06 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Mon, 30 Mar 2026 07:11:08 +0000 (09:11 +0200)
Previously, the function casting type circle to type polygon could not
be made error safe, because it is an SQL language function.

This refactors it as a C/internal function, by sharing code with the
C/internal function that the SQL function previously wrapped, and soft
error support is added.

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

src/backend/catalog/system_functions.sql
src/backend/utils/adt/geo_ops.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat

index 1c5b6d6df05dff4406450777a74d84938567ba43..c3c0a6e84ed7c3c87921d2047ee994d7063f0425 100644 (file)
@@ -99,12 +99,6 @@ CREATE OR REPLACE FUNCTION path_contain_pt(path, point)
  IMMUTABLE PARALLEL SAFE STRICT COST 1
 RETURN on_ppath($2, $1);
 
-CREATE OR REPLACE FUNCTION polygon(circle)
- RETURNS polygon
- LANGUAGE sql
- IMMUTABLE PARALLEL SAFE STRICT COST 1
-RETURN polygon(12, $1);
-
 CREATE OR REPLACE FUNCTION age(timestamptz)
  RETURNS interval
  LANGUAGE sql
index cbc4621e9b20d397f7beadeda999bcf7a1a22df9..cc5ce013d0f0741aa0abff5cf34fdf685f898d2c 100644 (file)
@@ -125,6 +125,7 @@ static float8 circle_ar(CIRCLE *circle);
 
 /* Routines for polygons */
 static void make_bound_box(POLYGON *poly);
+static POLYGON *circle_poly_internal(int32 npts, const CIRCLE *circle, FunctionCallInfo fcinfo);
 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);
@@ -5317,11 +5318,9 @@ fail:
 }
 
 
-Datum
-circle_poly(PG_FUNCTION_ARGS)
+static POLYGON *
+circle_poly_internal(int32 npts, const CIRCLE *circle, FunctionCallInfo fcinfo)
 {
-       int32           npts = PG_GETARG_INT32(0);
-       CIRCLE     *circle = PG_GETARG_CIRCLE_P(1);
        POLYGON    *poly;
        int                     base_size,
                                size;
@@ -5330,12 +5329,12 @@ circle_poly(PG_FUNCTION_ARGS)
        float8          anglestep;
 
        if (FPzero(circle->radius))
-               ereport(ERROR,
+               ereturn(fcinfo->context, NULL,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("cannot convert circle with radius zero to polygon")));
 
        if (npts < 2)
-               ereport(ERROR,
+               ereturn(fcinfo->context, NULL,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("must request at least 2 points")));
 
@@ -5344,7 +5343,7 @@ circle_poly(PG_FUNCTION_ARGS)
 
        /* Check for integer overflow */
        if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
-               ereport(ERROR,
+               ereturn(fcinfo->context, NULL,
                                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                 errmsg("too many points requested")));
 
@@ -5356,17 +5355,51 @@ circle_poly(PG_FUNCTION_ARGS)
 
        for (i = 0; i < npts; i++)
        {
-               angle = float8_mul(anglestep, i);
+               float8          temp;
 
-               poly->p[i].x = float8_mi(circle->center.x,
-                                                                float8_mul(circle->radius, cos(angle)));
-               poly->p[i].y = float8_pl(circle->center.y,
-                                                                float8_mul(circle->radius, sin(angle)));
+               angle = float8_mul_safe(anglestep, i, fcinfo->context);
+               if (SOFT_ERROR_OCCURRED(fcinfo->context))
+                       return NULL;
+
+               temp = float8_mul_safe(circle->radius, cos(angle), fcinfo->context);
+               if (SOFT_ERROR_OCCURRED(fcinfo->context))
+                       return NULL;
+
+               poly->p[i].x = float8_mi_safe(circle->center.x, temp, fcinfo->context);
+               if (SOFT_ERROR_OCCURRED(fcinfo->context))
+                       return NULL;
+
+               temp = float8_mul_safe(circle->radius, sin(angle), fcinfo->context);
+               if (SOFT_ERROR_OCCURRED(fcinfo->context))
+                       return NULL;
+
+               poly->p[i].y = float8_pl_safe(circle->center.y, temp, fcinfo->context);
+               if (SOFT_ERROR_OCCURRED(fcinfo->context))
+                       return NULL;
        }
 
        make_bound_box(poly);
 
-       PG_RETURN_POLYGON_P(poly);
+       return poly;
+}
+
+Datum
+circle_poly(PG_FUNCTION_ARGS)
+{
+       int32           npts = PG_GETARG_INT32(0);
+       CIRCLE     *circle = PG_GETARG_CIRCLE_P(1);
+
+       PG_RETURN_POLYGON_P(circle_poly_internal(npts, circle, fcinfo));
+}
+
+/* convert circle to 12-vertex polygon */
+Datum
+circle_to_poly(PG_FUNCTION_ARGS)
+{
+       int32           npts = 12;
+       CIRCLE     *circle = PG_GETARG_CIRCLE_P(0);
+
+       PG_RETURN_POLYGON_P(circle_poly_internal(npts, circle, fcinfo));
 }
 
 /*
index 4d9ccc5789c4d2825bdd0062d2e19b483c628a91..81b2bf39b3f80b1a54f6419948e0f811dd3b5847 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202603241
+#define CATALOG_VERSION_NO     202603301
 
 #endif
index 0118e970ddafebfdccb6edec10666c9181206996..3579cec5744cba63b140ba4af80c331c4df2ffd1 100644 (file)
   proname => 'center', prorettype => 'point', proargtypes => 'circle',
   prosrc => 'circle_center' },
 { oid => '1544', descr => 'convert circle to 12-vertex polygon',
-  proname => 'polygon', prolang => 'sql', prorettype => 'polygon',
-  proargtypes => 'circle', prosrc => 'see system_functions.sql' },
+  proname => 'polygon', prorettype => 'polygon',
+  proargtypes => 'circle', prosrc => 'circle_to_poly' },
 { oid => '1545', descr => 'number of points',
   proname => 'npoints', prorettype => 'int4', proargtypes => 'path',
   prosrc => 'path_npoints' },