Line data Source code
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 "nodes/miscnodes.h"
11 : #include "utils/float.h"
12 : #include "varatt.h"
13 :
14 : /* All grammar constructs return strings */
15 : #define YYSTYPE char *
16 :
17 : #include "cubeparse.h"
18 :
19 : /* silence -Wmissing-variable-declarations */
20 : extern int cube_yychar;
21 : extern int cube_yynerrs;
22 :
23 : /*
24 : * Bison doesn't allocate anything that needs to live across parser calls,
25 : * so we can easily have it use palloc instead of malloc. This prevents
26 : * memory leaks if we error out during parsing.
27 : */
28 : #define YYMALLOC palloc
29 : #define YYFREE pfree
30 :
31 : static int item_count(const char *s, char delim);
32 : static bool write_box(int dim, char *str1, char *str2,
33 : NDBOX **result, struct Node *escontext);
34 : static bool write_point_as_box(int dim, char *str,
35 : NDBOX **result, struct Node *escontext);
36 :
37 : %}
38 :
39 : /* BISON Declarations */
40 : %parse-param {NDBOX **result}
41 : %parse-param {Size scanbuflen}
42 : %parse-param {struct Node *escontext}
43 : %expect 0
44 : %name-prefix="cube_yy"
45 :
46 : %token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA
47 : %start box
48 :
49 : /* Grammar follows */
50 : %%
51 :
52 : box: O_BRACKET paren_list COMMA paren_list C_BRACKET
53 : {
54 : int dim;
55 :
56 32 : dim = item_count($2, ',');
57 32 : if (item_count($4, ',') != dim)
58 : {
59 4 : errsave(escontext,
60 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
61 : errmsg("invalid input syntax for cube"),
62 : errdetail("Different point dimensions in (%s) and (%s).",
63 : $2, $4)));
64 0 : YYABORT;
65 : }
66 28 : if (dim > CUBE_MAX_DIM)
67 : {
68 0 : errsave(escontext,
69 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
70 : errmsg("invalid input syntax for cube"),
71 : errdetail("A cube cannot have more than %d dimensions.",
72 : CUBE_MAX_DIM)));
73 0 : YYABORT;
74 : }
75 :
76 28 : if (!write_box(dim, $2, $4, result, escontext))
77 0 : YYABORT;
78 : }
79 :
80 : | paren_list COMMA paren_list
81 : {
82 : int dim;
83 :
84 6492 : dim = item_count($1, ',');
85 6492 : if (item_count($3, ',') != dim)
86 : {
87 4 : errsave(escontext,
88 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
89 : errmsg("invalid input syntax for cube"),
90 : errdetail("Different point dimensions in (%s) and (%s).",
91 : $1, $3)));
92 0 : YYABORT;
93 : }
94 6488 : if (dim > CUBE_MAX_DIM)
95 : {
96 2 : errsave(escontext,
97 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
98 : errmsg("invalid input syntax for cube"),
99 : errdetail("A cube cannot have more than %d dimensions.",
100 : CUBE_MAX_DIM)));
101 0 : YYABORT;
102 : }
103 :
104 6486 : if (!write_box(dim, $1, $3, result, escontext))
105 0 : YYABORT;
106 : }
107 :
108 : | paren_list
109 : {
110 : int dim;
111 :
112 138 : dim = item_count($1, ',');
113 138 : if (dim > CUBE_MAX_DIM)
114 : {
115 2 : errsave(escontext,
116 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
117 : errmsg("invalid input syntax for cube"),
118 : errdetail("A cube cannot have more than %d dimensions.",
119 : CUBE_MAX_DIM)));
120 0 : YYABORT;
121 : }
122 :
123 136 : if (!write_point_as_box(dim, $1, result, escontext))
124 0 : YYABORT;
125 : }
126 :
127 : | list
128 : {
129 : int dim;
130 :
131 178 : dim = item_count($1, ',');
132 178 : if (dim > CUBE_MAX_DIM)
133 : {
134 0 : errsave(escontext,
135 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
136 : errmsg("invalid input syntax for cube"),
137 : errdetail("A cube cannot have more than %d dimensions.",
138 : CUBE_MAX_DIM)));
139 0 : YYABORT;
140 : }
141 :
142 178 : if (!write_point_as_box(dim, $1, result, escontext))
143 4 : YYABORT;
144 : }
145 : ;
146 :
147 : paren_list: O_PAREN list C_PAREN
148 : {
149 13192 : $$ = $2;
150 : }
151 : | O_PAREN C_PAREN
152 : {
153 8 : $$ = pstrdup("");
154 : }
155 : ;
156 :
157 : list: CUBEFLOAT
158 : {
159 : /* alloc enough space to be sure whole list will fit */
160 13382 : $$ = palloc(scanbuflen + 1);
161 13382 : strcpy($$, $1);
162 : }
163 : | list COMMA CUBEFLOAT
164 : {
165 14736 : $$ = $1;
166 14736 : strcat($$, ",");
167 14736 : strcat($$, $3);
168 : }
169 : ;
170 :
171 : %%
172 :
173 : /* This assumes the string has been normalized by productions above */
174 : static int
175 13364 : item_count(const char *s, char delim)
176 : {
177 13364 : int nitems = 0;
178 :
179 13364 : if (s[0] != '\0')
180 : {
181 13358 : nitems++;
182 28090 : while ((s = strchr(s, delim)) != NULL)
183 : {
184 14732 : nitems++;
185 14732 : s++;
186 : }
187 : }
188 13364 : return nitems;
189 : }
190 :
191 : static bool
192 6514 : write_box(int dim, char *str1, char *str2,
193 : NDBOX **result, struct Node *escontext)
194 : {
195 : NDBOX *bp;
196 : char *s;
197 : char *endptr;
198 : int i;
199 6514 : int size = CUBE_SIZE(dim);
200 6514 : bool point = true;
201 :
202 6514 : bp = palloc0(size);
203 6514 : SET_VARSIZE(bp, size);
204 6514 : SET_DIM(bp, dim);
205 :
206 6514 : s = str1;
207 6514 : i = 0;
208 6514 : if (dim > 0)
209 : {
210 6512 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
211 6512 : if (SOFT_ERROR_OCCURRED(escontext))
212 0 : return false;
213 : }
214 13152 : while ((s = strchr(s, ',')) != NULL)
215 : {
216 6638 : s++;
217 6638 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
218 6638 : if (SOFT_ERROR_OCCURRED(escontext))
219 0 : return false;
220 : }
221 : Assert(i == dim);
222 :
223 6514 : s = str2;
224 6514 : if (dim > 0)
225 : {
226 6512 : bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
227 6512 : if (SOFT_ERROR_OCCURRED(escontext))
228 0 : return false;
229 : /* code this way to do right thing with NaN */
230 6512 : point &= (bp->x[i] == bp->x[0]);
231 6512 : i++;
232 : }
233 13152 : while ((s = strchr(s, ',')) != NULL)
234 : {
235 6638 : s++;
236 6638 : bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
237 6638 : if (SOFT_ERROR_OCCURRED(escontext))
238 0 : return false;
239 6638 : point &= (bp->x[i] == bp->x[i - dim]);
240 6638 : i++;
241 : }
242 : Assert(i == dim * 2);
243 :
244 6514 : if (point)
245 : {
246 : /*
247 : * The value turned out to be a point, ie. all the upper-right
248 : * coordinates were equal to the lower-left coordinates. Resize the
249 : * cube we constructed. Note: we don't bother to repalloc() it
250 : * smaller, as it's unlikely that the tiny amount of memory freed
251 : * that way would be useful, and the output is always short-lived.
252 : */
253 50 : size = POINT_SIZE(dim);
254 50 : SET_VARSIZE(bp, size);
255 50 : SET_POINT_BIT(bp);
256 : }
257 :
258 6514 : *result = bp;
259 6514 : return true;
260 : }
261 :
262 : static bool
263 314 : write_point_as_box(int dim, char *str,
264 : NDBOX **result, struct Node *escontext)
265 : {
266 : NDBOX *bp;
267 : int i,
268 : size;
269 : char *s;
270 : char *endptr;
271 :
272 314 : size = POINT_SIZE(dim);
273 314 : bp = palloc0(size);
274 314 : SET_VARSIZE(bp, size);
275 314 : SET_DIM(bp, dim);
276 314 : SET_POINT_BIT(bp);
277 :
278 314 : s = str;
279 314 : i = 0;
280 314 : if (dim > 0)
281 : {
282 312 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
283 310 : if (SOFT_ERROR_OCCURRED(escontext))
284 4 : return false;
285 : }
286 552 : while ((s = strchr(s, ',')) != NULL)
287 : {
288 244 : s++;
289 244 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
290 244 : if (SOFT_ERROR_OCCURRED(escontext))
291 0 : return false;
292 : }
293 : Assert(i == dim);
294 :
295 308 : *result = bp;
296 308 : return true;
297 : }
|