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