mirror of https://github.com/postgres/postgres
292 lines
5.9 KiB
Plaintext
292 lines
5.9 KiB
Plaintext
%{
|
|
/* contrib/cube/cubeparse.y */
|
|
|
|
/* NdBox = [(lowerleft),(upperright)] */
|
|
/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "cubedata.h"
|
|
#include "nodes/miscnodes.h"
|
|
#include "utils/float.h"
|
|
#include "varatt.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.
|
|
*/
|
|
#define YYMALLOC palloc
|
|
#define YYFREE pfree
|
|
|
|
static int item_count(const char *s, char delim);
|
|
static bool write_box(int dim, char *str1, char *str2,
|
|
NDBOX **result, struct Node *escontext);
|
|
static bool write_point_as_box(int dim, char *str,
|
|
NDBOX **result, struct Node *escontext);
|
|
|
|
%}
|
|
|
|
/* BISON Declarations */
|
|
%parse-param {NDBOX **result}
|
|
%parse-param {Size scanbuflen}
|
|
%parse-param {struct Node *escontext}
|
|
%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)
|
|
{
|
|
errsave(escontext,
|
|
(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)
|
|
{
|
|
errsave(escontext,
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
errmsg("invalid input syntax for cube"),
|
|
errdetail("A cube cannot have more than %d dimensions.",
|
|
CUBE_MAX_DIM)));
|
|
YYABORT;
|
|
}
|
|
|
|
if (!write_box(dim, $2, $4, result, escontext))
|
|
YYABORT;
|
|
}
|
|
|
|
| paren_list COMMA paren_list
|
|
{
|
|
int dim;
|
|
|
|
dim = item_count($1, ',');
|
|
if (item_count($3, ',') != dim)
|
|
{
|
|
errsave(escontext,
|
|
(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)
|
|
{
|
|
errsave(escontext,
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
errmsg("invalid input syntax for cube"),
|
|
errdetail("A cube cannot have more than %d dimensions.",
|
|
CUBE_MAX_DIM)));
|
|
YYABORT;
|
|
}
|
|
|
|
if (!write_box(dim, $1, $3, result, escontext))
|
|
YYABORT;
|
|
}
|
|
|
|
| paren_list
|
|
{
|
|
int dim;
|
|
|
|
dim = item_count($1, ',');
|
|
if (dim > CUBE_MAX_DIM)
|
|
{
|
|
errsave(escontext,
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
errmsg("invalid input syntax for cube"),
|
|
errdetail("A cube cannot have more than %d dimensions.",
|
|
CUBE_MAX_DIM)));
|
|
YYABORT;
|
|
}
|
|
|
|
if (!write_point_as_box(dim, $1, result, escontext))
|
|
YYABORT;
|
|
}
|
|
|
|
| list
|
|
{
|
|
int dim;
|
|
|
|
dim = item_count($1, ',');
|
|
if (dim > CUBE_MAX_DIM)
|
|
{
|
|
errsave(escontext,
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
errmsg("invalid input syntax for cube"),
|
|
errdetail("A cube cannot have more than %d dimensions.",
|
|
CUBE_MAX_DIM)));
|
|
YYABORT;
|
|
}
|
|
|
|
if (!write_point_as_box(dim, $1, result, escontext))
|
|
YYABORT;
|
|
}
|
|
;
|
|
|
|
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 bool
|
|
write_box(int dim, char *str1, char *str2,
|
|
NDBOX **result, struct Node *escontext)
|
|
{
|
|
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, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
}
|
|
while ((s = strchr(s, ',')) != NULL)
|
|
{
|
|
s++;
|
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
}
|
|
Assert(i == dim);
|
|
|
|
s = str2;
|
|
if (dim > 0)
|
|
{
|
|
bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
/* 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, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
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);
|
|
}
|
|
|
|
*result = bp;
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
write_point_as_box(int dim, char *str,
|
|
NDBOX **result, struct Node *escontext)
|
|
{
|
|
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, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
}
|
|
while ((s = strchr(s, ',')) != NULL)
|
|
{
|
|
s++;
|
|
bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
|
|
if (SOFT_ERROR_OCCURRED(escontext))
|
|
return false;
|
|
}
|
|
Assert(i == dim);
|
|
|
|
*result = bp;
|
|
return true;
|
|
}
|