summaryrefslogtreecommitdiffstats
path: root/contrib/cube/cubeparse.y
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cube/cubeparse.y')
-rw-r--r--contrib/cube/cubeparse.y269
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..7577c45
--- /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"