diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/cube/cubeparse.y | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y new file mode 100644 index 0000000..deb2efd --- /dev/null +++ b/contrib/cube/cubeparse.y @@ -0,0 +1,269 @@ +%{ +/* contrib/cube/cubeparse.y */ + +/* NdBox = [(lowerleft),(upperright)] */ +/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ + +#include "postgres.h" + +#include "cubedata.h" +#include "utils/float.h" + +/* All grammar constructs return strings */ +#define YYSTYPE char * + +/* + * Bison doesn't allocate anything that needs to live across parser calls, + * so we can easily have it use palloc instead of malloc. This prevents + * memory leaks if we error out during parsing. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYMALLOC palloc +#define YYFREE pfree + +static char *scanbuf; +static int scanbuflen; + +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); + +%} + +/* BISON Declarations */ +%parse-param {NDBOX **result} +%expect 0 +%name-prefix="cube_yy" + +%token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA +%start box + +/* Grammar follows */ +%% + +box: O_BRACKET paren_list COMMA paren_list C_BRACKET + { + int dim; + + dim = item_count($2, ','); + if (item_count($4, ',') != dim) + { + ereport(ERROR, + (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) + { + ereport(ERROR, + (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 = item_count($1, ','); + if (item_count($3, ',') != dim) + { + ereport(ERROR, + (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) + { + ereport(ERROR, + (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, $1, $3 ); + } + + | paren_list + { + int dim; + + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (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(dim, $1); + } + + | list + { + int dim; + + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (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(dim, $1); + } + ; + +paren_list: O_PAREN list C_PAREN + { + $$ = $2; + } + | O_PAREN C_PAREN + { + $$ = pstrdup(""); + } + ; + +list: CUBEFLOAT + { + /* alloc enough space to be sure whole list will fit */ + $$ = palloc(scanbuflen + 1); + strcpy($$, $1); + } + | list COMMA CUBEFLOAT + { + $$ = $1; + strcat($$, ","); + strcat($$, $3); + } + ; + +%% + +/* This assumes the string has been normalized by productions above */ +static int +item_count(const char *s, char delim) +{ + int nitems = 0; + + if (s[0] != '\0') + { + nitems++; + while ((s = strchr(s, delim)) != NULL) + { + nitems++; + s++; + } + } + return nitems; +} + +static NDBOX * +write_box(int dim, char *str1, char *str2) +{ + NDBOX *bp; + char *s; + char *endptr; + int i; + int size = CUBE_SIZE(dim); + bool point = true; + + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + + s = str1; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + } + Assert(i == dim); + + s = str2; + 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++; + 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 + * 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; +} + +static NDBOX * +write_point_as_box(int dim, char *str) +{ + NDBOX *bp; + int i, + size; + char *s; + char *endptr; + + size = POINT_SIZE(dim); + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + SET_POINT_BIT(bp); + + s = str; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + } + Assert(i == dim); + + return bp; +} + +#include "cubescan.c" |