1 %{
2 /* contrib/cube/cubeparse.y */
3
4 /* NdBox = [(lowerleft),(upperright)] */
5 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
6
7 #define YYSTYPE char *
8 #define YYDEBUG 1
9
10 #include "postgres.h"
11
12 #include "cubedata.h"
13
14 /*
15 * Bison doesn't allocate anything that needs to live across parser calls,
16 * so we can easily have it use palloc instead of malloc. This prevents
17 * memory leaks if we error out during parsing. Note this only works with
18 * bison >= 2.0. However, in bison 1.875 the default is to use alloca()
19 * if possible, so there's not really much problem anyhow, at least if
20 * you're building with gcc.
21 */
22 #define YYMALLOC palloc
23 #define YYFREE pfree
24
25 static char *scanbuf;
26 static int scanbuflen;
27
28 static int delim_count(char *s, char delim);
29 static NDBOX * write_box(unsigned int dim, char *str1, char *str2);
30 static NDBOX * write_point_as_box(char *s, int dim);
31
32 %}
33
34 /* BISON Declarations */
35 %parse-param {NDBOX **result}
36 %expect 0
37 %name-prefix="cube_yy"
38
39 %token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA
40 %start box
41
42 /* Grammar follows */
43 %%
44
45 box: O_BRACKET paren_list COMMA paren_list C_BRACKET
46 {
47 int dim;
48
49 dim = delim_count($2, ',') + 1;
50 if ((delim_count($4, ',') + 1) != dim)
51 {
52 ereport(ERROR,
53 (errcode(ERRCODE_SYNTAX_ERROR),
54 errmsg("bad cube representation"),
55 errdetail("Different point dimensions in (%s) and (%s).",
56 $2, $4)));
57 YYABORT;
58 }
59 if (dim > CUBE_MAX_DIM) {
60 ereport(ERROR,
61 (errcode(ERRCODE_SYNTAX_ERROR),
62 errmsg("bad cube representation"),
63 errdetail("A cube cannot have more than %d dimensions.",
64 CUBE_MAX_DIM)));
65 YYABORT;
66 }
67
68 *result = write_box( dim, $2, $4 );
69
70 }
71
72 | paren_list COMMA paren_list
73 {
74 int dim;
75
76 dim = delim_count($1, ',') + 1;
77
78 if ( (delim_count($3, ',') + 1) != dim ) {
79 ereport(ERROR,
80 (errcode(ERRCODE_SYNTAX_ERROR),
81 errmsg("bad cube representation"),
82 errdetail("Different point dimensions in (%s) and (%s).",
83 $1, $3)));
84 YYABORT;
85 }
86 if (dim > CUBE_MAX_DIM) {
87 ereport(ERROR,
88 (errcode(ERRCODE_SYNTAX_ERROR),
89 errmsg("bad cube representation"),
90 errdetail("A cube cannot have more than %d dimensions.",
91 CUBE_MAX_DIM)));
92 YYABORT;
93 }
94
95 *result = write_box( dim, $1, $3 );
96 }
97
98 | paren_list
99 {
100 int dim;
101
102 dim = delim_count($1, ',') + 1;
103 if (dim > CUBE_MAX_DIM) {
104 ereport(ERROR,
105 (errcode(ERRCODE_SYNTAX_ERROR),
106 errmsg("bad cube representation"),
107 errdetail("A cube cannot have more than %d dimensions.",
108 CUBE_MAX_DIM)));
109 YYABORT;
110 }
111
112 *result = write_point_as_box($1, dim);
113 }
114
115 | list
116 {
117 int dim;
118
119 dim = delim_count($1, ',') + 1;
120 if (dim > CUBE_MAX_DIM) {
121 ereport(ERROR,
122 (errcode(ERRCODE_SYNTAX_ERROR),
123 errmsg("bad cube representation"),
124 errdetail("A cube cannot have more than %d dimensions.",
125 CUBE_MAX_DIM)));
126 YYABORT;
127 }
128 *result = write_point_as_box($1, dim);
129 }
130 ;
131
132 paren_list: O_PAREN list C_PAREN
133 {
134 $$ = $2;
135 }
136 ;
137
138 list: CUBEFLOAT
139 {
140 /* alloc enough space to be sure whole list will fit */
141 $$ = palloc(scanbuflen + 1);
142 strcpy($$, $1);
143 }
144 | list COMMA CUBEFLOAT
145 {
146 $$ = $1;
147 strcat($$, ",");
148 strcat($$, $3);
149 }
150 ;
151
152 %%
153
154 static int
155 delim_count(char *s, char delim)
156 {
157 int ndelim = 0;
158
159 while ((s = strchr(s, delim)) != NULL)
160 {
161 ndelim++;
162 s++;
163 }
164 return (ndelim);
165 }
166
167 static NDBOX *
write_box(unsigned int dim,char * str1,char * str2)168 write_box(unsigned int dim, char *str1, char *str2)
169 {
170 NDBOX *bp;
171 char *s;
172 int i;
173 int size = CUBE_SIZE(dim);
174 bool point = true;
175
176 bp = palloc0(size);
177 SET_VARSIZE(bp, size);
178 SET_DIM(bp, dim);
179
180 s = str1;
181 bp->x[i=0] = strtod(s, NULL);
182 while ((s = strchr(s, ',')) != NULL)
183 {
184 s++; i++;
185 bp->x[i] = strtod(s, NULL);
186 }
187
188 s = str2;
189 bp->x[i=dim] = strtod(s, NULL);
190 if (bp->x[dim] != bp->x[0])
191 point = false;
192 while ((s = strchr(s, ',')) != NULL)
193 {
194 s++; i++;
195 bp->x[i] = strtod(s, NULL);
196 if (bp->x[i] != bp->x[i-dim])
197 point = false;
198 }
199
200 if (point)
201 {
202 /*
203 * The value turned out to be a point, ie. all the upper-right
204 * coordinates were equal to the lower-left coordinates. Resize the
205 * the cube we constructed. Note: we don't bother to repalloc() it
206 * smaller, it's unlikely that the tiny amount of memory free'd that
207 * way would be useful.
208 */
209 size = POINT_SIZE(dim);
210 SET_VARSIZE(bp, size);
211 SET_POINT_BIT(bp);
212 }
213
214 return(bp);
215 }
216
217 static NDBOX *
write_point_as_box(char * str,int dim)218 write_point_as_box(char *str, int dim)
219 {
220 NDBOX *bp;
221 int i,
222 size;
223 double x;
224 char *s = str;
225
226 size = POINT_SIZE(dim);
227 bp = palloc0(size);
228 SET_VARSIZE(bp, size);
229 SET_DIM(bp, dim);
230 SET_POINT_BIT(bp);
231
232 i = 0;
233 x = strtod(s, NULL);
234 bp->x[0] = x;
235 while ((s = strchr(s, ',')) != NULL)
236 {
237 s++; i++;
238 x = strtod(s, NULL);
239 bp->x[i] = x;
240 }
241
242 return(bp);
243 }
244
245 #include "cubescan.c"
246