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
From be571575e54c1b24617c54dbcd3daa3826d7e15a Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@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

Reply via email to