From 33dd895ef3316bd1896def6882e9075359d7e9af Mon Sep 17 00:00:00 2001 From: Andrew Dunstan 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. Reviewed by Tom Lane Discussion: https://postgr.es/m/cee4e426-d014-c0b7-aa22-a659f2cd9130@dunslane.net --- src/backend/utils/adt/float.c | 57 ++++++++++++++++++++++++++--------- src/include/utils/float.h | 3 ++ 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index b02a19be24..23e371c413 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,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; } /* 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);