nested hstore
[hstore.git] / hstore_gram.y
1 %{
2 #define YYPARSE_PARAM result  /* need this to pass a pointer (void *) to yyparse */
3
4 #include "postgres.h"
5
6 #include "fmgr.h"
7 #include "utils/builtins.h"
8 #include "hstore.h"
9
10 /*
11  * Bison doesn't allocate anything that needs to live across parser calls,
12  * so we can easily have it use palloc instead of malloc.  This prevents
13  * memory leaks if we error out during parsing.  Note this only works with
14  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
15  * if possible, so there's not really much problem anyhow, at least if
16  * you're building with gcc.
17  */
18 #define YYMALLOC palloc
19 #define YYFREE   pfree
20
21 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
22 #undef fprintf
23 #define fprintf(file, fmt, msg)  fprintf_to_ereport(fmt, msg)
24
25 static void
26 fprintf_to_ereport(const char *fmt, const char *msg)
27 {
28         ereport(ERROR, (errmsg_internal("%s", msg)));
29 }
30
31 /* struct string is shared between scan and gram */
32 typedef struct string {
33         char    *val;
34         int     len;
35         int             total;
36 } string;
37 #include <hstore_gram.h>
38
39 /* flex 2.5.4 doesn't bother with a decl for this */
40 int hstore_yylex(YYSTYPE * yylval_param);
41 int hstore_yyparse(void *result);
42 void hstore_yyerror(const char *message);
43
44 static HStoreValue*
45 makeHStoreValueString(HStoreValue* v, string *s)
46 {
47         if (v == NULL)
48                 v = palloc(sizeof(*v));
49
50         if (s == NULL)
51         {
52                 v->type = hsvNull;
53                 v->size = sizeof(HEntry);
54         }
55         else if (s->len > HENTRY_POSMASK)
56         {
57                 elog(ERROR, "string is too long");
58         }
59         else
60         {
61                 v->type = hsvString;
62                 v->string.val = s->val;
63                 v->string.len = s->len;
64                 v->size = sizeof(HEntry) + s->len;
65
66         }
67
68         return v;
69 }
70
71 static HStoreValue*
72 makeHStoreValueNumeric(string *s)
73 {
74         Numeric                 n = NULL;
75         HStoreValue             *v;
76         MemoryContext   ccxt = CurrentMemoryContext;
77
78         /*
79          * ignore ERRCODE_INVALID_TEXT_REPRESENTATION in parse: our
80          * test stringIsNumber could be not agree with numeric_in
81          */
82
83         PG_TRY();
84         {
85                 n = DatumGetNumeric(DirectFunctionCall3(numeric_in, CStringGetDatum(s->val), 0, -1));
86         }
87         PG_CATCH();
88         {
89                 ErrorData               *errdata;
90                 MemoryContext   ecxt;
91
92                 ecxt = MemoryContextSwitchTo(ccxt);
93                 errdata = CopyErrorData();
94                 if (errdata->sqlerrcode == ERRCODE_INVALID_TEXT_REPRESENTATION)
95                 {
96                         FlushErrorState();
97                         n = NULL;
98                 }
99                 else
100                 {
101                         MemoryContextSwitchTo(ecxt);
102                         PG_RE_THROW();
103                 }
104         }
105         PG_END_TRY();
106
107         if (n != NULL)
108         {
109                 v = palloc(sizeof(*v));
110                 v->type = hsvNumeric;
111                 v->numeric = n;
112                 v->size = 2*sizeof(HEntry) + VARSIZE_ANY(n);
113         }
114         else
115         {
116                 v = makeHStoreValueString(NULL, s);
117         }
118
119         return v;
120 }
121
122 static HStoreValue*
123 makeHStoreValueBool(bool val) {
124         HStoreValue *v = palloc(sizeof(*v));
125
126         v->type = hsvBool;
127         v->boolean = val;
128         v->size = sizeof(HEntry);
129
130         return v;
131 }
132
133 static HStoreValue*
134 makeHStoreValueArray(List *list)
135 {
136         HStoreValue     *v = palloc(sizeof(*v));
137
138         v->type = hsvArray;
139         v->array.scalar = false;
140         v->array.nelems = list_length(list);
141         v->size = sizeof(uint32) /* header */ + sizeof(HEntry) /* parent's entry */ + sizeof(HEntry) - 1 /*alignment*/;
142
143         if (v->array.nelems > 0)
144         {
145                 ListCell        *cell;
146                 int                     i = 0;
147
148                 v->array.elems = palloc(sizeof(HStoreValue) * v->array.nelems);
149
150                 foreach(cell, list)
151                 {
152                         HStoreValue     *s = (HStoreValue*)lfirst(cell);
153
154                         v->size += s->size; 
155
156                         v->array.elems[i++] = *s;
157
158                         if (v->size > HENTRY_POSMASK)
159                                 elog(ERROR, "array is too long");
160                 }
161         }
162         else
163         {
164                 v->array.elems = NULL;
165         }
166
167         return v;
168 }
169
170 static HStoreValue*
171 makeHStoreValuePairs(List *list)
172 {
173         HStoreValue     *v = palloc(sizeof(*v));
174
175         v->type = hsvHash;
176         v->hash.npairs = list_length(list);
177         v->size = sizeof(uint32) /* header */ + sizeof(HEntry) /* parent's entry */ + sizeof(HEntry) - 1 /*alignment*/;
178
179         if (v->hash.npairs > 0)
180         {
181                 ListCell        *cell;
182                 int                     i = 0;
183
184                 v->hash.pairs = palloc(sizeof(HStorePair) * v->hash.npairs);
185
186                 foreach(cell, list)
187                 {
188                         HStorePair      *s = (HStorePair*)lfirst(cell);
189
190                         v->size += s->key.size + s->value.size; 
191                         v->hash.pairs[i].order = i;
192                         v->hash.pairs[i++] = *s;
193
194                         if (v->size > HENTRY_POSMASK)
195                                 elog(ERROR, "hstore is too long");
196                 }
197
198                 uniqueHStoreValue(v);
199         }
200         else
201         {
202                 v->hash.pairs = NULL;
203         }
204
205         return v;
206 }
207
208 static HStorePair*
209 makeHStorePair(string *key, HStoreValue *value) {
210         HStorePair      *v = palloc(sizeof(*v));
211
212         makeHStoreValueString(&v->key, key);
213         v->value = *value;
214
215         return v;
216 }
217
218 %}
219
220 /* BISON Declarations */
221 %pure-parser
222 %expect 0
223 %name-prefix="hstore_yy"
224 %error-verbose
225
226 %union {
227         string                  str;
228         Numeric                 numeric;
229         List                    *elems;                 /* list of HStoreValue */
230         List                    *pairs;                 /* list of HStorePair */
231
232         HStoreValue             *hvalue;
233         HStorePair              *pair;
234 }
235
236 %token  <str>                   DELIMITER_P NULL_P STRING_P TRUE_P FALSE_P
237                                                 NUMERIC_P
238
239 %type   <hvalue>                result hstore value scalar_value 
240 %type   <str>                   key
241
242 %type   <pair>                  pair
243
244 %type   <elems>                 value_list
245 %type   <pairs>                 pair_list
246
247 /* Grammar follows */
248 %%
249
250 result: 
251         pair_list                                               { *((HStoreValue**)result) = makeHStoreValuePairs($1); }
252         | hstore                                                {       
253                                                                                 if ($1->type == hsvNull)
254                                                                                         *((HStoreValue**)result) = NULL;
255                                                                                 else
256                                                                                         *((HStoreValue**)result) = $1;
257                                                                         }
258         | scalar_value                                  { 
259                                                                                 *((HStoreValue**)result) = makeHStoreValueArray(lappend(NIL, $1));
260                                                                                 (*((HStoreValue**)result))->array.scalar = true;
261                                                                         }
262         | /* EMPTY */                                   { *((HStoreValue**)result) = NULL; }
263         ;
264
265 hstore:
266         '{' pair_list '}'                               { $$ = makeHStoreValuePairs($2); }
267         | '{' value_list '}'                    { $$ = makeHStoreValueArray($2); }
268         | '[' value_list ']'                    { $$ = makeHStoreValueArray($2); }
269         | '{' value '}'                                 { $$ = makeHStoreValueArray(lappend(NIL, $2)); }
270         | '[' value ']'                                 { $$ = makeHStoreValueArray(lappend(NIL, $2)); }
271         | '{' '}'                                               { $$ = makeHStoreValueString(NULL, NULL); }
272         | '[' ']'                                               { $$ = makeHStoreValueString(NULL, NULL); }
273         ;
274
275 scalar_value:
276         NULL_P                                                  { $$ = makeHStoreValueString(NULL, NULL); }
277         | STRING_P                                              { $$ = makeHStoreValueString(NULL, &$1); }
278         | TRUE_P                                                { $$ = makeHStoreValueBool(true); }
279         | FALSE_P                                               { $$ = makeHStoreValueBool(false); }
280         | NUMERIC_P                                             { $$ = makeHStoreValueNumeric(&$1); }
281         ;
282
283 value:
284         scalar_value                                    { $$ = $1; }
285         | hstore                                                { $$ = $1; } 
286         ;
287
288 value_list:
289         value ',' value                                 { $$ = lappend(lappend(NIL, $1), $3); } 
290         | value_list ',' value                  { $$ = lappend($1, $3); } 
291         ;
292
293 /*
294  * key is always a string, not a bool or numeric
295  */
296 key:
297         STRING_P                                                { $$ = $1; }
298         | TRUE_P                                                { $$ = $1; }
299         | FALSE_P                                               { $$ = $1; }
300         | NUMERIC_P                                             { $$ = $1; }
301         | NULL_P                                                { $$ = $1; }
302         ;
303
304 pair:
305         key DELIMITER_P value                   { $$ = makeHStorePair(&$1, $3); }
306         ;
307
308 pair_list:
309         pair                                                    { $$ = lappend(NIL, $1); }
310         | pair_list ',' pair                    { $$ = lappend($1, $3); }
311         ;
312
313 %%
314
315 #include "hstore_scan.c"