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