TLA 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 CBC 16 : dim = item_count($2, ',');
51 16 : if (item_count($4, ',') != dim)
52 : {
53 GNC 2 : 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 UBC 0 : YYABORT;
59 : }
60 CBC 14 : if (dim > CUBE_MAX_DIM)
61 : {
62 UNC 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 UBC 0 : YYABORT;
68 : }
69 :
70 GNC 14 : if (!write_box(dim, $2, $4, result, escontext))
71 UNC 0 : YYABORT;
72 EUB : }
73 :
74 : | paren_list COMMA paren_list
75 : {
76 : int dim;
77 :
78 GIC 3246 : dim = item_count($1, ',');
79 CBC 3246 : if (item_count($3, ',') != dim)
80 ECB : {
81 GNC 2 : errsave(escontext,
82 ECB : (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 UIC 0 : YYABORT;
87 EUB : }
88 GIC 3244 : if (dim > CUBE_MAX_DIM)
89 ECB : {
90 GNC 1 : errsave(escontext,
91 ECB : (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 UIC 0 : YYABORT;
96 EUB : }
97 :
98 GNC 3243 : if (!write_box(dim, $1, $3, result, escontext))
99 UNC 0 : YYABORT;
100 ECB : }
101 EUB :
102 : | paren_list
103 : {
104 : int dim;
105 :
106 GIC 69 : dim = item_count($1, ',');
107 69 : if (dim > CUBE_MAX_DIM)
108 ECB : {
109 GNC 1 : errsave(escontext,
110 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
111 ECB : errmsg("invalid input syntax for cube"),
112 : errdetail("A cube cannot have more than %d dimensions.",
113 : CUBE_MAX_DIM)));
114 UIC 0 : YYABORT;
115 : }
116 EUB :
117 GNC 68 : if (!write_point_as_box(dim, $1, result, escontext))
118 UNC 0 : YYABORT;
119 : }
120 ECB :
121 EUB : | list
122 : {
123 : int dim;
124 :
125 GIC 89 : dim = item_count($1, ',');
126 89 : if (dim > CUBE_MAX_DIM)
127 : {
128 UNC 0 : errsave(escontext,
129 ECB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
130 : errmsg("invalid input syntax for cube"),
131 EUB : errdetail("A cube cannot have more than %d dimensions.",
132 : CUBE_MAX_DIM)));
133 UIC 0 : YYABORT;
134 : }
135 :
136 GNC 89 : if (!write_point_as_box(dim, $1, result, escontext))
137 2 : YYABORT;
138 : }
139 : ;
140 ECB :
141 : paren_list: O_PAREN list C_PAREN
142 : {
143 GIC 6596 : $$ = $2;
144 : }
145 : | O_PAREN C_PAREN
146 : {
147 CBC 4 : $$ = pstrdup("");
148 : }
149 : ;
150 :
151 ECB : list: CUBEFLOAT
152 : {
153 : /* alloc enough space to be sure whole list will fit */
154 GIC 6691 : $$ = palloc(scanbuflen + 1);
155 6691 : strcpy($$, $1);
156 : }
157 : | list COMMA CUBEFLOAT
158 ECB : {
159 CBC 7368 : $$ = $1;
160 GIC 7368 : strcat($$, ",");
161 7368 : strcat($$, $3);
162 : }
163 ECB : ;
164 :
165 : %%
166 :
167 : /* This assumes the string has been normalized by productions above */
168 : static int
169 GIC 6682 : item_count(const char *s, char delim)
170 : {
171 6682 : int nitems = 0;
172 :
173 CBC 6682 : if (s[0] != '\0')
174 : {
175 6679 : nitems++;
176 GIC 14045 : while ((s = strchr(s, delim)) != NULL)
177 ECB : {
178 GIC 7366 : nitems++;
179 CBC 7366 : s++;
180 ECB : }
181 : }
182 CBC 6682 : return nitems;
183 ECB : }
184 :
185 : static bool
186 GNC 3257 : write_box(int dim, char *str1, char *str2,
187 : NDBOX **result, struct Node *escontext)
188 : {
189 : NDBOX *bp;
190 : char *s;
191 ECB : char *endptr;
192 : int i;
193 GIC 3257 : int size = CUBE_SIZE(dim);
194 3257 : bool point = true;
195 :
196 3257 : bp = palloc0(size);
197 3257 : SET_VARSIZE(bp, size);
198 CBC 3257 : SET_DIM(bp, dim);
199 ECB :
200 GIC 3257 : s = str1;
201 CBC 3257 : i = 0;
202 3257 : if (dim > 0)
203 : {
204 GNC 3256 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
205 3256 : if (SOFT_ERROR_OCCURRED(escontext))
206 UNC 0 : return false;
207 : }
208 GIC 6576 : while ((s = strchr(s, ',')) != NULL)
209 ECB : {
210 CBC 3319 : s++;
211 GNC 3319 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str1, escontext);
212 3319 : if (SOFT_ERROR_OCCURRED(escontext))
213 UNC 0 : return false;
214 : }
215 CBC 3257 : Assert(i == dim);
216 ECB :
217 GBC 3257 : s = str2;
218 GIC 3257 : if (dim > 0)
219 ECB : {
220 GNC 3256 : bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
221 3256 : if (SOFT_ERROR_OCCURRED(escontext))
222 UNC 0 : return false;
223 ECB : /* code this way to do right thing with NaN */
224 CBC 3256 : point &= (bp->x[i] == bp->x[0]);
225 3256 : i++;
226 EUB : }
227 GIC 6576 : while ((s = strchr(s, ',')) != NULL)
228 ECB : {
229 GIC 3319 : s++;
230 GNC 3319 : bp->x[i] = float8in_internal(s, &endptr, "cube", str2, escontext);
231 3319 : if (SOFT_ERROR_OCCURRED(escontext))
232 UNC 0 : return false;
233 CBC 3319 : point &= (bp->x[i] == bp->x[i - dim]);
234 GIC 3319 : i++;
235 ECB : }
236 CBC 3257 : Assert(i == dim * 2);
237 EUB :
238 GIC 3257 : if (point)
239 ECB : {
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 GBC 25 : size = POINT_SIZE(dim);
248 CBC 25 : SET_VARSIZE(bp, size);
249 25 : SET_POINT_BIT(bp);
250 : }
251 ECB :
252 GNC 3257 : *result = bp;
253 3257 : return true;
254 ECB : }
255 :
256 : static bool
257 GNC 157 : 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 ECB : char *endptr;
265 :
266 CBC 157 : size = POINT_SIZE(dim);
267 GIC 157 : bp = palloc0(size);
268 157 : SET_VARSIZE(bp, size);
269 CBC 157 : SET_DIM(bp, dim);
270 157 : SET_POINT_BIT(bp);
271 :
272 GIC 157 : s = str;
273 157 : i = 0;
274 CBC 157 : if (dim > 0)
275 : {
276 GNC 156 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
277 155 : if (SOFT_ERROR_OCCURRED(escontext))
278 2 : return false;
279 : }
280 GIC 276 : while ((s = strchr(s, ',')) != NULL)
281 : {
282 122 : s++;
283 GNC 122 : bp->x[i++] = float8in_internal(s, &endptr, "cube", str, escontext);
284 122 : if (SOFT_ERROR_OCCURRED(escontext))
285 UNC 0 : return false;
286 : }
287 GIC 154 : Assert(i == dim);
288 :
289 GNC 154 : *result = bp;
290 154 : return true;
291 ECB : }
|