diff options
| author | Tom Lane | 2016-09-27 15:38:33 +0000 |
|---|---|---|
| committer | Tom Lane | 2016-09-27 15:38:33 +0000 |
| commit | f31a931fade868d788ef4480c59753a2d5059246 (patch) | |
| tree | 614246ea47696b568ad5b7ea06f7c75d932802cf /contrib/cube/cubeparse.y | |
| parent | 51c3e9fade76c12e4aa37bffdf800bbf74fb3fb1 (diff) | |
Improve contrib/cube's handling of zero-D cubes, infinities, and NaNs.
It's always been possible to create a zero-dimensional cube by converting
from a zero-length float8 array, but cube_in failed to accept the '()'
representation that cube_out produced for that case, resulting in a
dump/reload hazard. Make it accept the case. Also fix a couple of
other places that didn't behave sanely for zero-dimensional cubes:
cube_size would produce 1.0 when surely the answer should be 0.0,
and g_cube_distance risked a divide-by-zero failure.
Likewise, it's always been possible to create cubes containing float8
infinity or NaN coordinate values, but cube_in couldn't parse such input,
and cube_out produced platform-dependent spellings of the values. Convert
them to use float8in_internal and float8out_internal so that the behavior
will be the same as for float8, as we recently did for the core geometric
types (cf commit 50861cd68). As in that commit, I don't pretend that this
patch fixes all insane corner-case behaviors that may exist for NaNs, but
it's a step forward.
(This change allows removal of the separate cube_1.out and cube_3.out
expected-files, as the platform dependency that previously required them
is now gone: an underflowing coordinate value will now produce an error
not plus or minus zero.)
Make errors from cube_in follow project conventions as to spelling
("invalid input syntax for cube" not "bad cube representation")
and errcode (INVALID_TEXT_REPRESENTATION not SYNTAX_ERROR).
Also a few marginal code cleanups and comment improvements.
Tom Lane, reviewed by Amul Sul
Discussion: <15085.1472494782@sss.pgh.pa.us>
Diffstat (limited to 'contrib/cube/cubeparse.y')
| -rw-r--r-- | contrib/cube/cubeparse.y | 148 |
1 files changed, 86 insertions, 62 deletions
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index 33606c741c..1b65fa967c 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -4,12 +4,13 @@ /* NdBox = [(lowerleft),(upperright)] */ /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ -#define YYSTYPE char * -#define YYDEBUG 1 - #include "postgres.h" #include "cubedata.h" +#include "utils/builtins.h" + +/* All grammar constructs return strings */ +#define YYSTYPE char * /* * Bison doesn't allocate anything that needs to live across parser calls, @@ -25,9 +26,9 @@ static char *scanbuf; static int scanbuflen; -static int delim_count(char *s, char delim); -static NDBOX * write_box(unsigned int dim, char *str1, char *str2); -static NDBOX * write_point_as_box(char *s, int dim); +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); %} @@ -46,47 +47,48 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET { int dim; - dim = delim_count($2, ',') + 1; - if ((delim_count($4, ',') + 1) != dim) + dim = item_count($2, ','); + if (item_count($4, ',') != dim) { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", $2, $4))); YYABORT; } - if (dim > CUBE_MAX_DIM) { + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } *result = write_box( dim, $2, $4 ); - } | paren_list COMMA paren_list { int dim; - dim = delim_count($1, ',') + 1; - - if ( (delim_count($3, ',') + 1) != dim ) { + dim = item_count($1, ','); + if (item_count($3, ',') != dim) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", $1, $3))); YYABORT; } - if (dim > CUBE_MAX_DIM) { + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; @@ -99,33 +101,36 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET { int dim; - dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } - *result = write_point_as_box($1, dim); + *result = write_point_as_box(dim, $1); } | list { int dim; - dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } - *result = write_point_as_box($1, dim); + + *result = write_point_as_box(dim, $1); } ; @@ -133,6 +138,10 @@ paren_list: O_PAREN list C_PAREN { $$ = $2; } + | O_PAREN C_PAREN + { + $$ = pstrdup(""); + } ; list: CUBEFLOAT @@ -151,24 +160,30 @@ list: CUBEFLOAT %% +/* This assumes the string has been normalized by productions above */ static int -delim_count(char *s, char delim) +item_count(const char *s, char delim) { - int ndelim = 0; + int nitems = 0; - while ((s = strchr(s, delim)) != NULL) + if (s[0] != '\0') { - ndelim++; - s++; + nitems++; + while ((s = strchr(s, delim)) != NULL) + { + nitems++; + s++; + } } - return (ndelim); + return nitems; } static NDBOX * -write_box(unsigned int dim, char *str1, char *str2) +write_box(int dim, char *str1, char *str2) { NDBOX *bp; char *s; + char *endptr; int i; int size = CUBE_SIZE(dim); bool point = true; @@ -178,50 +193,58 @@ write_box(unsigned int dim, char *str1, char *str2) SET_DIM(bp, dim); s = str1; - bp->x[i=0] = strtod(s, NULL); + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); while ((s = strchr(s, ',')) != NULL) { - s++; i++; - bp->x[i] = strtod(s, NULL); + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); } + Assert(i == dim); s = str2; - bp->x[i=dim] = strtod(s, NULL); - if (bp->x[dim] != bp->x[0]) - point = false; + if (dim > 0) + { + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + /* code this way to do right thing with NaN */ + point &= (bp->x[i] == bp->x[0]); + i++; + } while ((s = strchr(s, ',')) != NULL) { - s++; i++; - bp->x[i] = strtod(s, NULL); - if (bp->x[i] != bp->x[i-dim]) - point = false; + s++; + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + point &= (bp->x[i] == bp->x[i - dim]); + i++; } + Assert(i == dim * 2); if (point) { /* * The value turned out to be a point, ie. all the upper-right * coordinates were equal to the lower-left coordinates. Resize the - * the cube we constructed. Note: we don't bother to repalloc() it - * smaller, it's unlikely that the tiny amount of memory free'd that - * way would be useful. + * cube we constructed. Note: we don't bother to repalloc() it + * smaller, as it's unlikely that the tiny amount of memory freed + * that way would be useful, and the output is always short-lived. */ size = POINT_SIZE(dim); SET_VARSIZE(bp, size); SET_POINT_BIT(bp); } - return(bp); + return bp; } static NDBOX * -write_point_as_box(char *str, int dim) +write_point_as_box(int dim, char *str) { NDBOX *bp; int i, size; - double x; - char *s = str; + char *s; + char *endptr; size = POINT_SIZE(dim); bp = palloc0(size); @@ -229,17 +252,18 @@ write_point_as_box(char *str, int dim) SET_DIM(bp, dim); SET_POINT_BIT(bp); + s = str; i = 0; - x = strtod(s, NULL); - bp->x[0] = x; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); while ((s = strchr(s, ',')) != NULL) { - s++; i++; - x = strtod(s, NULL); - bp->x[i] = x; + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); } + Assert(i == dim); - return(bp); + return bp; } #include "cubescan.c" |
