PolarDB-for-PostgreSQL
269 строк · 5.3 Кб
1%{
2/* contrib/cube/cubeparse.y */
3
4/* NdBox = [(lowerleft),(upperright)] */
5/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
6
7#include "postgres.h"
8
9#include "cubedata.h"
10#include "utils/builtins.h"
11
12/* All grammar constructs return strings */
13#define YYSTYPE char *
14
15/*
16* Bison doesn't allocate anything that needs to live across parser calls,
17* so we can easily have it use palloc instead of malloc. This prevents
18* memory leaks if we error out during parsing. Note this only works with
19* bison >= 2.0. However, in bison 1.875 the default is to use alloca()
20* if possible, so there's not really much problem anyhow, at least if
21* you're building with gcc.
22*/
23#define YYMALLOC palloc
24#define YYFREE pfree
25
26static char *scanbuf;
27static int scanbuflen;
28
29static int item_count(const char *s, char delim);
30static NDBOX *write_box(int dim, char *str1, char *str2);
31static NDBOX *write_point_as_box(int dim, char *str);
32
33%}
34
35/* BISON Declarations */
36%parse-param {NDBOX **result}
37%expect 0
38%name-prefix="cube_yy"
39
40%token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA
41%start box
42
43/* Grammar follows */
44%%
45
46box: O_BRACKET paren_list COMMA paren_list C_BRACKET
47{
48int dim;
49
50dim = item_count($2, ',');
51if (item_count($4, ',') != dim)
52{
53ereport(ERROR,
54(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
55errmsg("invalid input syntax for cube"),
56errdetail("Different point dimensions in (%s) and (%s).",
57$2, $4)));
58YYABORT;
59}
60if (dim > CUBE_MAX_DIM)
61{
62ereport(ERROR,
63(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
64errmsg("invalid input syntax for cube"),
65errdetail("A cube cannot have more than %d dimensions.",
66CUBE_MAX_DIM)));
67YYABORT;
68}
69
70*result = write_box( dim, $2, $4 );
71}
72
73| paren_list COMMA paren_list
74{
75int dim;
76
77dim = item_count($1, ',');
78if (item_count($3, ',') != dim)
79{
80ereport(ERROR,
81(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
82errmsg("invalid input syntax for cube"),
83errdetail("Different point dimensions in (%s) and (%s).",
84$1, $3)));
85YYABORT;
86}
87if (dim > CUBE_MAX_DIM)
88{
89ereport(ERROR,
90(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
91errmsg("invalid input syntax for cube"),
92errdetail("A cube cannot have more than %d dimensions.",
93CUBE_MAX_DIM)));
94YYABORT;
95}
96
97*result = write_box( dim, $1, $3 );
98}
99
100| paren_list
101{
102int dim;
103
104dim = item_count($1, ',');
105if (dim > CUBE_MAX_DIM)
106{
107ereport(ERROR,
108(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
109errmsg("invalid input syntax for cube"),
110errdetail("A cube cannot have more than %d dimensions.",
111CUBE_MAX_DIM)));
112YYABORT;
113}
114
115*result = write_point_as_box(dim, $1);
116}
117
118| list
119{
120int dim;
121
122dim = item_count($1, ',');
123if (dim > CUBE_MAX_DIM)
124{
125ereport(ERROR,
126(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
127errmsg("invalid input syntax for cube"),
128errdetail("A cube cannot have more than %d dimensions.",
129CUBE_MAX_DIM)));
130YYABORT;
131}
132
133*result = write_point_as_box(dim, $1);
134}
135;
136
137paren_list: O_PAREN list C_PAREN
138{
139$$ = $2;
140}
141| O_PAREN C_PAREN
142{
143$$ = pstrdup("");
144}
145;
146
147list: CUBEFLOAT
148{
149/* alloc enough space to be sure whole list will fit */
150$$ = palloc(scanbuflen + 1);
151strcpy($$, $1);
152}
153| list COMMA CUBEFLOAT
154{
155$$ = $1;
156strcat($$, ",");
157strcat($$, $3);
158}
159;
160
161%%
162
163/* This assumes the string has been normalized by productions above */
164static int
165item_count(const char *s, char delim)
166{
167int nitems = 0;
168
169if (s[0] != '\0')
170{
171nitems++;
172while ((s = strchr(s, delim)) != NULL)
173{
174nitems++;
175s++;
176}
177}
178return nitems;
179}
180
181static NDBOX *
182write_box(int dim, char *str1, char *str2)
183{
184NDBOX *bp;
185char *s;
186char *endptr;
187int i;
188int size = CUBE_SIZE(dim);
189bool point = true;
190
191bp = palloc0(size);
192SET_VARSIZE(bp, size);
193SET_DIM(bp, dim);
194
195s = str1;
196i = 0;
197if (dim > 0)
198bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
199while ((s = strchr(s, ',')) != NULL)
200{
201s++;
202bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
203}
204Assert(i == dim);
205
206s = str2;
207if (dim > 0)
208{
209bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
210/* code this way to do right thing with NaN */
211point &= (bp->x[i] == bp->x[0]);
212i++;
213}
214while ((s = strchr(s, ',')) != NULL)
215{
216s++;
217bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
218point &= (bp->x[i] == bp->x[i - dim]);
219i++;
220}
221Assert(i == dim * 2);
222
223if (point)
224{
225/*
226* The value turned out to be a point, ie. all the upper-right
227* coordinates were equal to the lower-left coordinates. Resize the
228* cube we constructed. Note: we don't bother to repalloc() it
229* smaller, as it's unlikely that the tiny amount of memory freed
230* that way would be useful, and the output is always short-lived.
231*/
232size = POINT_SIZE(dim);
233SET_VARSIZE(bp, size);
234SET_POINT_BIT(bp);
235}
236
237return bp;
238}
239
240static NDBOX *
241write_point_as_box(int dim, char *str)
242{
243NDBOX *bp;
244int i,
245size;
246char *s;
247char *endptr;
248
249size = POINT_SIZE(dim);
250bp = palloc0(size);
251SET_VARSIZE(bp, size);
252SET_DIM(bp, dim);
253SET_POINT_BIT(bp);
254
255s = str;
256i = 0;
257if (dim > 0)
258bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
259while ((s = strchr(s, ',')) != NULL)
260{
261s++;
262bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
263}
264Assert(i == dim);
265
266return bp;
267}
268
269#include "cubescan.c"
270