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