summaryrefslogtreecommitdiff
path: root/contrib/cube/cubeparse.y
diff options
context:
space:
mode:
authorTom Lane2016-09-27 15:38:33 +0000
committerTom Lane2016-09-27 15:38:33 +0000
commitf31a931fade868d788ef4480c59753a2d5059246 (patch)
tree614246ea47696b568ad5b7ea06f7c75d932802cf /contrib/cube/cubeparse.y
parent51c3e9fade76c12e4aa37bffdf800bbf74fb3fb1 (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.y148
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"