diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-09 10:14:53 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-09 10:14:53 -0500 |
commit | ccff2d20ed9622815df2a7deffce8a7b14830965 (patch) | |
tree | ef8439338d811e3c3b4fd6413f42662c128c70c2 /src/backend/utils/adt/float.c | |
parent | 1939d26282b27b4b264c6930830a7991ed83917a (diff) | |
download | postgresql-ccff2d20ed9622815df2a7deffce8a7b14830965.tar.gz postgresql-ccff2d20ed9622815df2a7deffce8a7b14830965.zip |
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r-- | src/backend/utils/adt/float.c | 96 |
1 files changed, 34 insertions, 62 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index da97538ebe3..b02a19be24d 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -163,6 +163,7 @@ Datum float4in(PG_FUNCTION_ARGS) { char *num = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; char *orig_num; float val; char *endptr; @@ -183,7 +184,7 @@ float4in(PG_FUNCTION_ARGS) * strtod() on different platforms. */ if (*num == '\0') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "real", orig_num))); @@ -257,13 +258,13 @@ float4in(PG_FUNCTION_ARGS) (val >= HUGE_VALF || val <= -HUGE_VALF) #endif ) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("\"%s\" is out of range for type real", orig_num))); } else - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "real", orig_num))); @@ -275,7 +276,7 @@ float4in(PG_FUNCTION_ARGS) /* if there is any junk left at the end of the string, bail out */ if (*endptr != '\0') - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "real", orig_num))); @@ -337,52 +338,40 @@ float8in(PG_FUNCTION_ARGS) { char *num = PG_GETARG_CSTRING(0); - PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num)); + PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num, + fcinfo->context)); } -/* Convenience macro: set *have_error flag (if provided) or throw error */ -#define RETURN_ERROR(throw_error, have_error) \ -do { \ - if (have_error) { \ - *have_error = true; \ - return 0.0; \ - } else { \ - throw_error; \ - } \ -} while (0) - /* - * float8in_internal_opt_error - guts of float8in() + * float8in_internal - guts of float8in() * * This is exposed for use by functions that want a reasonably * platform-independent way of inputting doubles. The behavior is - * essentially like strtod + ereport on error, but note the following + * essentially like strtod + ereturn on error, but note the following * differences: * 1. Both leading and trailing whitespace are skipped. - * 2. If endptr_p is NULL, we throw error if there's trailing junk. + * 2. If endptr_p is NULL, we report error if there's trailing junk. * Otherwise, it's up to the caller to complain about trailing junk. * 3. In event of a syntax error, the report mentions the given type_name * and prints orig_string as the input; this is meant to support use of * this function with types such as "box" and "point", where what we are * parsing here is just a substring of orig_string. * + * If escontext points to an ErrorSaveContext node, that is filled instead + * of throwing an error; the caller must check SOFT_ERROR_OCCURRED() + * to detect errors. + * * "num" could validly be declared "const char *", but that results in an * unreasonable amount of extra casting both here and in callers, so we don't. - * - * When "*have_error" flag is provided, it's set instead of throwing an - * error. This is helpful when caller need to handle errors by itself. */ -double -float8in_internal_opt_error(char *num, char **endptr_p, - const char *type_name, const char *orig_string, - bool *have_error) +float8 +float8in_internal(char *num, char **endptr_p, + const char *type_name, const char *orig_string, + struct Node *escontext) { double val; char *endptr; - if (have_error) - *have_error = false; - /* skip leading whitespace */ while (*num != '\0' && isspace((unsigned char) *num)) num++; @@ -392,11 +381,10 @@ float8in_internal_opt_error(char *num, char **endptr_p, * strtod() on different platforms. */ if (*num == '\0') - RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", - type_name, orig_string))), - have_error); + ereturn(escontext, 0, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + type_name, orig_string))); errno = 0; val = strtod(num, &endptr); @@ -469,20 +457,17 @@ float8in_internal_opt_error(char *num, char **endptr_p, char *errnumber = pstrdup(num); errnumber[endptr - num] = '\0'; - RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("\"%s\" is out of range for type double precision", - errnumber))), - have_error); + ereturn(escontext, 0, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("\"%s\" is out of range for type double precision", + errnumber))); } } else - RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type " - "%s: \"%s\"", - type_name, orig_string))), - have_error); + ereturn(escontext, 0, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + type_name, orig_string))); } /* skip trailing whitespace */ @@ -493,27 +478,14 @@ float8in_internal_opt_error(char *num, char **endptr_p, if (endptr_p) *endptr_p = endptr; else if (*endptr != '\0') - RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type " - "%s: \"%s\"", - type_name, orig_string))), - have_error); + ereturn(escontext, 0, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + type_name, orig_string))); return val; } -/* - * Interface to float8in_internal_opt_error() without "have_error" argument. - */ -double -float8in_internal(char *num, char **endptr_p, - const char *type_name, const char *orig_string) -{ - return float8in_internal_opt_error(num, endptr_p, type_name, - orig_string, NULL); -} - /* * float8out - converts float8 number to a string |