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
This commit is contained in:
Andrew Dunstan 2022-12-21 08:37:17 -05:00
parent eb706fde83
commit 33dd895ef3
2 changed files with 45 additions and 15 deletions

View File

@ -163,17 +163,35 @@ Datum
float4in(PG_FUNCTION_ARGS) float4in(PG_FUNCTION_ARGS)
{ {
char *num = PG_GETARG_CSTRING(0); 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; float val;
char *endptr; char *endptr;
/* /*
* endptr points to the first character _after_ the sequence we recognized * 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. * string.
*/ */
orig_num = num;
/* skip leading whitespace */ /* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num)) while (*num != '\0' && isspace((unsigned char) *num))
@ -184,10 +202,10 @@ float4in(PG_FUNCTION_ARGS)
* strtod() on different platforms. * strtod() on different platforms.
*/ */
if (*num == '\0') if (*num == '\0')
ereturn(escontext, (Datum) 0, ereturn(escontext, 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num))); type_name, orig_string)));
errno = 0; errno = 0;
val = strtof(num, &endptr); val = strtof(num, &endptr);
@ -258,30 +276,39 @@ float4in(PG_FUNCTION_ARGS)
(val >= HUGE_VALF || val <= -HUGE_VALF) (val >= HUGE_VALF || val <= -HUGE_VALF)
#endif #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), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type real", errmsg("\"%s\" is out of range for type real",
orig_num))); errnumber)));
}
} }
else else
ereturn(escontext, (Datum) 0, ereturn(escontext, 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num))); type_name, orig_string)));
} }
/* skip trailing whitespace */ /* skip trailing whitespace */
while (*endptr != '\0' && isspace((unsigned char) *endptr)) while (*endptr != '\0' && isspace((unsigned char) *endptr))
endptr++; endptr++;
/* if there is any junk left at the end of the string, bail out */ /* report stopping point if wanted, else complain if not end of string */
if (*endptr != '\0') if (endptr_p)
ereturn(escontext, (Datum) 0, *endptr_p = endptr;
else if (*endptr != '\0')
ereturn(escontext, 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num))); type_name, orig_string)));
PG_RETURN_FLOAT4(val); return val;
} }
/* /*

View File

@ -44,6 +44,9 @@ extern int is_infinite(float8 val);
extern float8 float8in_internal(char *num, char **endptr_p, extern float8 float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string, const char *type_name, const char *orig_string,
struct Node *escontext); 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 char *float8out_internal(float8 num);
extern int float4_cmp_internal(float4 a, float4 b); extern int float4_cmp_internal(float4 a, float4 b);
extern int float8_cmp_internal(float8 a, float8 b); extern int float8_cmp_internal(float8 a, float8 b);