float4in_internal
The attached patch factors out the guts of float4in so that the new
float4in_internal function is callable without going through the fmgr
call sequence. This will make adjusting the seg module's input function
to handle soft errors simpler. A similar operation was done for float8in
some years ago in commit 50861cd683e. The new function has an identical
argument structure to float8in_internal.
We could probably call these two internal functions directly in
numeric_float4() and numeric_float8() - not sure if it's worth it rght
now but we might end up wanting something like that for error-safe casts.
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com
Attachments:
0001-Introduce-float4in_internal.patchtext/x-patch; charset=UTF-8; name=0001-Introduce-float4in_internal.patchDownload
From be571575e54c1b24617c54dbcd3daa3826d7e15a Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <andrew@dunslane.net>
Date: Wed, 21 Dec 2022 08:37:17 -0500
Subject: [PATCH] Introduce float4in_internal
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.
---
src/backend/utils/adt/float.c | 52 ++++++++++++++++++++++++-----------
src/include/utils/float.h | 3 ++
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b02a19be24..5a9b7fbe5b 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -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,32 @@ float4in(PG_FUNCTION_ARGS)
(val >= HUGE_VALF || val <= -HUGE_VALF)
#endif
)
- ereturn(escontext, (Datum) 0,
+ ereturn(escontext, 0,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("\"%s\" is out of range for type real",
- orig_num)));
+ errmsg("\"%s\" is out of range for type %s",
+ orig_string, type_name)));
}
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;
}
/*
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index f92860b4a4..60e897be75 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -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);
--
2.34.1
Andrew Dunstan <andrew@dunslane.net> writes:
The attached patch factors out the guts of float4in so that the new
float4in_internal function is callable without going through the fmgr
call sequence. This will make adjusting the seg module's input function
to handle soft errors simpler. A similar operation was done for float8in
some years ago in commit 50861cd683e. The new function has an identical
argument structure to float8in_internal.
Looks reasonable except for one nitpick: the "out of range" message
in the ERANGE case should be kept mentioning real, not the passed
type_name, to be equivalent to the way float8in_internal does it.
I lack enough caffeine to recall exactly why float8in_internal
does it that way, but the comments are exceedingly clear that it was
intentional, and I'm sure the same rationale would apply here.
(float8in_internal also goes out of its way to show just the part of
the string that is the number in that case, but I'm willing to let
that pass for now.)
regards, tom lane
On 2022-12-21 We 10:33, Tom Lane wrote:
Andrew Dunstan <andrew@dunslane.net> writes:
The attached patch factors out the guts of float4in so that the new
float4in_internal function is callable without going through the fmgr
call sequence. This will make adjusting the seg module's input function
to handle soft errors simpler. A similar operation was done for float8in
some years ago in commit 50861cd683e. The new function has an identical
argument structure to float8in_internal.Looks reasonable except for one nitpick: the "out of range" message
in the ERANGE case should be kept mentioning real, not the passed
type_name, to be equivalent to the way float8in_internal does it.
I lack enough caffeine to recall exactly why float8in_internal
does it that way, but the comments are exceedingly clear that it was
intentional, and I'm sure the same rationale would apply here.(float8in_internal also goes out of its way to show just the part of
the string that is the number in that case, but I'm willing to let
that pass for now.)
Thanks for reviewing.
I made both these changes, to keep the two functions more closely aligned.
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com