diff options
author | Tom Lane | 2022-12-09 15:14:53 +0000 |
---|---|---|
committer | Tom Lane | 2022-12-09 15:14:53 +0000 |
commit | ccff2d20ed9622815df2a7deffce8a7b14830965 (patch) | |
tree | ef8439338d811e3c3b4fd6413f42662c128c70c2 /contrib/cube | |
parent | 1939d26282b27b4b264c6930830a7991ed83917a (diff) |
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 'contrib/cube')
-rw-r--r-- | contrib/cube/cube.c | 3 | ||||
-rw-r--r-- | contrib/cube/cubedata.h | 7 | ||||
-rw-r--r-- | contrib/cube/cubeparse.y | 76 | ||||
-rw-r--r-- | contrib/cube/cubescan.l | 8 | ||||
-rw-r--r-- | contrib/cube/expected/cube.out | 25 | ||||
-rw-r--r-- | contrib/cube/sql/cube.sql | 6 |
6 files changed, 95 insertions, 30 deletions
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 4f32c5dc1d5..1fc447511a1 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -123,8 +123,9 @@ cube_in(PG_FUNCTION_ARGS) cube_scanner_init(str, &scanbuflen); - cube_yyparse(&result, scanbuflen); + cube_yyparse(&result, scanbuflen, fcinfo->context); + /* We might as well run this even on failure. */ cube_scanner_finish(); PG_RETURN_NDBOX_P(result); diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h index 640a7ca5800..96fa41a04e7 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -61,9 +61,12 @@ typedef struct NDBOX /* in cubescan.l */ extern int cube_yylex(void); -extern void cube_yyerror(NDBOX **result, Size scanbuflen, const char *message) pg_attribute_noreturn(); +extern void cube_yyerror(NDBOX **result, Size scanbuflen, + struct Node *escontext, + const char *message); extern void cube_scanner_init(const char *str, Size *scanbuflen); extern void cube_scanner_finish(void); /* in cubeparse.y */ -extern int cube_yyparse(NDBOX **result, Size scanbuflen); +extern int cube_yyparse(NDBOX **result, Size scanbuflen, + struct Node *escontext); diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index 977dcba9650..44450d10274 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -7,6 +7,7 @@ #include "postgres.h" #include "cubedata.h" +#include "nodes/miscnodes.h" #include "utils/float.h" /* All grammar constructs return strings */ @@ -21,14 +22,17 @@ #define YYFREE pfree static int item_count(const char *s, char delim); -static NDBOX *write_box(int dim, char *str1, char *str2); -static NDBOX *write_point_as_box(int dim, char *str); +static bool write_box(int dim, char *str1, char *str2, + NDBOX **result, struct Node *escontext); +static bool write_point_as_box(int dim, char *str, + NDBOX **result, struct Node *escontext); %} /* BISON Declarations */ %parse-param {NDBOX **result} %parse-param {Size scanbuflen} +%parse-param {struct Node *escontext} %expect 0 %name-prefix="cube_yy" @@ -45,7 +49,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET dim = item_count($2, ','); if (item_count($4, ',') != dim) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", @@ -54,7 +58,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET } if (dim > CUBE_MAX_DIM) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", @@ -62,7 +66,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET YYABORT; } - *result = write_box( dim, $2, $4 ); + if (!write_box(dim, $2, $4, result, escontext)) + YYABORT; } | paren_list COMMA paren_list @@ -72,7 +77,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET dim = item_count($1, ','); if (item_count($3, ',') != dim) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", @@ -81,7 +86,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET } if (dim > CUBE_MAX_DIM) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", @@ -89,7 +94,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET YYABORT; } - *result = write_box( dim, $1, $3 ); + if (!write_box(dim, $1, $3, result, escontext)) + YYABORT; } | paren_list @@ -99,7 +105,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET dim = item_count($1, ','); if (dim > CUBE_MAX_DIM) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", @@ -107,7 +113,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET YYABORT; } - *result = write_point_as_box(dim, $1); + if (!write_point_as_box(dim, $1, result, escontext)) + YYABORT; } | list @@ -117,7 +124,7 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET dim = item_count($1, ','); if (dim > CUBE_MAX_DIM) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", @@ -125,7 +132,8 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET YYABORT; } - *result = write_point_as_box(dim, $1); + if (!write_point_as_box(dim, $1, result, escontext)) + YYABORT; } ; @@ -173,8 +181,9 @@ item_count(const char *s, char delim) return nitems; } -static NDBOX * -write_box(int dim, char *str1, char *str2) +static bool +write_box(int dim, char *str1, char *str2, + NDBOX **result, struct Node *escontext) { NDBOX *bp; char *s; @@ -190,18 +199,26 @@ write_box(int dim, char *str1, char *str2) s = str1; i = 0; if (dim > 0) - bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + { + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; + } while ((s = strchr(s, ',')) != NULL) { s++; - bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; } Assert(i == dim); s = str2; if (dim > 0) { - bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; /* code this way to do right thing with NaN */ point &= (bp->x[i] == bp->x[0]); i++; @@ -209,7 +226,9 @@ write_box(int dim, char *str1, char *str2) while ((s = strchr(s, ',')) != NULL) { s++; - bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; point &= (bp->x[i] == bp->x[i - dim]); i++; } @@ -229,11 +248,13 @@ write_box(int dim, char *str1, char *str2) SET_POINT_BIT(bp); } - return bp; + *result = bp; + return true; } -static NDBOX * -write_point_as_box(int dim, char *str) +static bool +write_point_as_box(int dim, char *str, + NDBOX **result, struct Node *escontext) { NDBOX *bp; int i, @@ -250,13 +271,20 @@ write_point_as_box(int dim, char *str) s = str; i = 0; if (dim > 0) - bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + { + bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; + } while ((s = strchr(s, ',')) != NULL) { s++; - bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext); + if (SOFT_ERROR_OCCURRED(escontext)) + return false; } Assert(i == dim); - return bp; + *result = bp; + return true; } diff --git a/contrib/cube/cubescan.l b/contrib/cube/cubescan.l index 6b316f2d545..49cb6992165 100644 --- a/contrib/cube/cubescan.l +++ b/contrib/cube/cubescan.l @@ -72,11 +72,13 @@ NaN [nN][aA][nN] /* result and scanbuflen are not used, but Bison expects this signature */ void -cube_yyerror(NDBOX **result, Size scanbuflen, const char *message) +cube_yyerror(NDBOX **result, Size scanbuflen, + struct Node *escontext, + const char *message) { if (*yytext == YY_END_OF_BUFFER_CHAR) { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), /* translator: %s is typically "syntax error" */ @@ -84,7 +86,7 @@ cube_yyerror(NDBOX **result, Size scanbuflen, const char *message) } else { - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for cube"), /* translator: first %s is typically "syntax error" */ diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out index 5b89cb1a26b..dc23e5ccc01 100644 --- a/contrib/cube/expected/cube.out +++ b/contrib/cube/expected/cube.out @@ -325,6 +325,31 @@ SELECT '-1e-700'::cube AS cube; -- out of range ERROR: "-1e-700" is out of range for type double precision LINE 1: SELECT '-1e-700'::cube AS cube; ^ +-- Also try it with non-error-throwing API +SELECT pg_input_is_valid('(1,2)', 'cube'); + pg_input_is_valid +------------------- + t +(1 row) + +SELECT pg_input_is_valid('[(1),]', 'cube'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_is_valid('-1e-700', 'cube'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_error_message('-1e-700', 'cube'); + pg_input_error_message +----------------------------------------------------- + "-1e-700" is out of range for type double precision +(1 row) + -- -- Testing building cubes from float8 values -- diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index 7f8b2e39799..384883d16e9 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -79,6 +79,12 @@ SELECT '1,2a'::cube AS cube; -- 7 SELECT '1..2'::cube AS cube; -- 7 SELECT '-1e-700'::cube AS cube; -- out of range +-- Also try it with non-error-throwing API +SELECT pg_input_is_valid('(1,2)', 'cube'); +SELECT pg_input_is_valid('[(1),]', 'cube'); +SELECT pg_input_is_valid('-1e-700', 'cube'); +SELECT pg_input_error_message('-1e-700', 'cube'); + -- -- Testing building cubes from float8 values -- |