%{ /* 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"