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:
parent
eb706fde83
commit
33dd895ef3
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user