Introduce float4in_internal
authorAndrew Dunstan <[email protected]>
Wed, 21 Dec 2022 13:37:17 +0000 (08:37 -0500)
committerAndrew Dunstan <[email protected]>
Wed, 21 Dec 2022 21:55:52 +0000 (16:55 -0500)
This is the guts of float4in, callable as a routine to input floats,
which will be useful in an upcoming patch for allowing soft errors in
the seg module's input function.

A similar operation was performed some years ago for float8in in
commit 50861cd683e.

Reviewed by Tom Lane

Discussion: https://postgr.es/m/cee4e426-d014-c0b7-aa22-a659f2cd9130@dunslane.net

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

index b02a19be24da13ccf512aad020e5849f84e67054..23e371c41304a285e49fd2f7b0b5ae7109ab467b 100644 (file)
@@ -163,17 +163,35 @@ Datum
 float4in(PG_FUNCTION_ARGS)
 {
        char       *num = PG_GETARG_CSTRING(0);
-       Node       *escontext = fcinfo->context;
-       char       *orig_num;
+
+       PG_RETURN_FLOAT4(float4in_internal(num, NULL, "real", num,
+                                                                          fcinfo->context));
+}
+
+/*
+ * float4in_internal - guts of float4in()
+ *
+ * This is exposed for use by functions that want a reasonably
+ * platform-independent way of inputting floats. The behavior is
+ * essentially like strtof + ereturn on error.
+ *
+ * Uses the same API as float8in_internal below, so most of its
+ * comments also apply here, except regarding use in geometric types.
+ */
+float4
+float4in_internal(char *num, char **endptr_p,
+                                 const char *type_name, const char *orig_string,
+                                 struct Node *escontext)
+{
        float           val;
        char       *endptr;
 
        /*
         * endptr points to the first character _after_ the sequence we recognized
-        * as a valid floating point number. orig_num points to the original input
+        * as a valid floating point number. orig_string points to the original
+        * input
         * string.
         */
-       orig_num = num;
 
        /* skip leading whitespace */
        while (*num != '\0' && isspace((unsigned char) *num))
@@ -184,10 +202,10 @@ float4in(PG_FUNCTION_ARGS)
         * strtod() on different platforms.
         */
        if (*num == '\0')
-               ereturn(escontext, (Datum) 0,
+               ereturn(escontext, 0,
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                 errmsg("invalid input syntax for type %s: \"%s\"",
-                                               "real", orig_num)));
+                                               type_name, orig_string)));
 
        errno = 0;
        val = strtof(num, &endptr);
@@ -258,30 +276,39 @@ float4in(PG_FUNCTION_ARGS)
                                (val >= HUGE_VALF || val <= -HUGE_VALF)
 #endif
                                )
-                               ereturn(escontext, (Datum) 0,
+                       {
+                               /* see comments in float8in_internal for rationale */
+                               char       *errnumber = pstrdup(num);
+
+                               errnumber[endptr - num] = '\0';
+
+                               ereturn(escontext, 0,
                                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                                 errmsg("\"%s\" is out of range for type real",
-                                                               orig_num)));
+                                                               errnumber)));
+                       }
                }
                else
-                       ereturn(escontext, (Datum) 0,
+                       ereturn(escontext, 0,
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                         errmsg("invalid input syntax for type %s: \"%s\"",
-                                                       "real", orig_num)));
+                                                       type_name, orig_string)));
        }
 
        /* skip trailing whitespace */
        while (*endptr != '\0' && isspace((unsigned char) *endptr))
                endptr++;
 
-       /* if there is any junk left at the end of the string, bail out */
-       if (*endptr != '\0')
-               ereturn(escontext, (Datum) 0,
+       /* report stopping point if wanted, else complain if not end of string */
+       if (endptr_p)
+               *endptr_p = endptr;
+       else if (*endptr != '\0')
+               ereturn(escontext, 0,
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                 errmsg("invalid input syntax for type %s: \"%s\"",
-                                               "real", orig_num)));
+                                               type_name, orig_string)));
 
-       PG_RETURN_FLOAT4(val);
+       return val;
 }
 
 /*
index f92860b4a4601e5bb0d33dc4e6a06ba525cd61bb..60e897be755d2861a51a2aafb12a4d9be689f331 100644 (file)
@@ -44,6 +44,9 @@ extern int    is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
                                                                const char *type_name, const char *orig_string,
                                                                struct Node *escontext);
+extern float4 float4in_internal(char *num, char **endptr_p,
+                                                               const char *type_name, const char *orig_string,
+                                                               struct Node *escontext);
 extern char *float8out_internal(float8 num);
 extern int     float4_cmp_internal(float4 a, float4 b);
 extern int     float8_cmp_internal(float8 a, float8 b);