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/float.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
26 static char *scanbuf;
27 static int scanbuflen;
28
29 static int item_count(const char *s, char delim);
30 static NDBOX *write_box(int dim, char *str1, char *str2);
31 static 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
46 box: O_BRACKET paren_list COMMA paren_list C_BRACKET
47 {
48 int dim;
49
50 dim = item_count($2, ',');
51 if (item_count($4, ',') != dim)
52 {
53 ereport(ERROR,
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 YYABORT;
59 }
60 if (dim > CUBE_MAX_DIM)
61 {
62 ereport(ERROR,
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 YYABORT;
68 }
69
70 *result = write_box( dim, $2, $4 );
71 }
72
73 | paren_list COMMA paren_list
74 {
75 int dim;
76
77 dim = item_count($1, ',');
78 if (item_count($3, ',') != dim)
79 {
80 ereport(ERROR,
81 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
82 errmsg("invalid input syntax for cube"),
83 errdetail("Different point dimensions in (%s) and (%s).",
84 $1, $3)));
85 YYABORT;
86 }
87 if (dim > CUBE_MAX_DIM)
88 {
89 ereport(ERROR,
90 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
91 errmsg("invalid input syntax for cube"),
92 errdetail("A cube cannot have more than %d dimensions.",
93 CUBE_MAX_DIM)));
94 YYABORT;
95 }
96
97 *result = write_box( dim, $1, $3 );
98 }
99
100 | paren_list
101 {
102 int dim;
103
104 dim = item_count($1, ',');
105 if (dim > CUBE_MAX_DIM)
106 {
107 ereport(ERROR,
108 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
109 errmsg("invalid input syntax for cube"),
110 errdetail("A cube cannot have more than %d dimensions.",
111 CUBE_MAX_DIM)));
112 YYABORT;
113 }
114
115 *result = write_point_as_box(dim, $1);
116 }
117
118 | list
119 {
120 int dim;
121
122 dim = item_count($1, ',');
123 if (dim > CUBE_MAX_DIM)
124 {
125 ereport(ERROR,
126 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
127 errmsg("invalid input syntax for cube"),
128 errdetail("A cube cannot have more than %d dimensions.",
129 CUBE_MAX_DIM)));
130 YYABORT;
131 }
132
133 *result = write_point_as_box(dim, $1);
134 }
135 ;
136
137 paren_list: O_PAREN list C_PAREN
138 {
139 $$ = $2;
140 }
141 | O_PAREN C_PAREN
142 {
143 $$ = pstrdup("");
144 }
145 ;
146
147 list: CUBEFLOAT
148 {
149 /* alloc enough space to be sure whole list will fit */
150 $$ = palloc(scanbuflen + 1);
151 strcpy($$, $1);
152 }
153 | list COMMA CUBEFLOAT
154 {
155 $$ = $1;
156 strcat($$, ",");
157 strcat($$, $3);
158 }
159 ;
160
161 %%
162
163 /* This assumes the string has been normalized by productions above */
164 static int
165 item_count(const char *s, char delim)
166 {
167 int nitems = 0;
168
169 if (s[0] != '\0')
170 {
171 nitems++;
172 while ((s = strchr(s, delim)) != NULL)
173 {
174 nitems++;
175 s++;
176 }
177 }
178 return nitems;
179 }
180
181 static NDBOX *
write_box(int dim,char * str1,char * str2)182 write_box(int dim, char *str1, char *str2)
183 {
184 NDBOX *bp;
185 char *s;
186 char *endptr;
187 int i;
188 int size = CUBE_SIZE(dim);
189 bool point = true;
190
191 bp = palloc0(size);
192 SET_VARSIZE(bp, size);
193 SET_DIM(bp, dim);
194
195 s = str1;
196 i = 0;
197 if (dim > 0)
198 bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
199 while ((s = strchr(s, ',')) != NULL)
200 {
201 s++;
202 bp->x[i++] = float8in_internal(s, &endptr, "cube", str1);
203 }
204 Assert(i == dim);
205
206 s = str2;
207 if (dim > 0)
208 {
209 bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
210 /* code this way to do right thing with NaN */
211 point &= (bp->x[i] == bp->x[0]);
212 i++;
213 }
214 while ((s = strchr(s, ',')) != NULL)
215 {
216 s++;
217 bp->x[i] = float8in_internal(s, &endptr, "cube", str2);
218 point &= (bp->x[i] == bp->x[i - dim]);
219 i++;
220 }
221 Assert(i == dim * 2);
222
223 if (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 */
232 size = POINT_SIZE(dim);
233 SET_VARSIZE(bp, size);
234 SET_POINT_BIT(bp);
235 }
236
237 return bp;
238 }
239
240 static NDBOX *
write_point_as_box(int dim,char * str)241 write_point_as_box(int dim, char *str)
242 {
243 NDBOX *bp;
244 int i,
245 size;
246 char *s;
247 char *endptr;
248
249 size = POINT_SIZE(dim);
250 bp = palloc0(size);
251 SET_VARSIZE(bp, size);
252 SET_DIM(bp, dim);
253 SET_POINT_BIT(bp);
254
255 s = str;
256 i = 0;
257 if (dim > 0)
258 bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
259 while ((s = strchr(s, ',')) != NULL)
260 {
261 s++;
262 bp->x[i++] = float8in_internal(s, &endptr, "cube", str);
263 }
264 Assert(i == dim);
265
266 return bp;
267 }
268
269 #include "cubescan.c"
270