Code

frontend/grammar: Added 'STORE host|service|metric [attribute]' commands.
[sysdb.git] / src / frontend / grammar.y
1 /*
2  * SysDB - src/frontend/grammar.y
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 %{
30 #include "frontend/connection-private.h"
31 #include "frontend/parser.h"
32 #include "frontend/grammar.h"
34 #include "core/store.h"
35 #include "core/store-private.h"
36 #include "core/time.h"
38 #include "utils/error.h"
39 #include "utils/llist.h"
41 #include <assert.h>
43 #include <stdio.h>
44 #include <string.h>
46 /*
47  * private helper functions
48  */
50 static sdb_store_matcher_t *
51 name_iter_matcher(int m_type, int type, const char *cmp,
52                 sdb_store_expr_t *expr);
54 /*
55  * public API
56  */
58 int
59 sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner);
61 sdb_fe_yyextra_t *
62 sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner);
64 void
65 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
66 void
67 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...);
69 /* quick access to the current parse tree */
70 #define pt sdb_fe_yyget_extra(scanner)->parsetree
72 /* quick access to the parser mode */
73 #define parser_mode sdb_fe_yyget_extra(scanner)->mode
75 /* quick access to the parser's error buffer */
76 #define errbuf sdb_fe_yyget_extra(scanner)->errbuf
78 #define MODE_TO_STRING(m) \
79         (((m) == SDB_PARSE_DEFAULT) ? "statement" \
80                 : ((m) == SDB_PARSE_COND) ? "condition" \
81                 : ((m) == SDB_PARSE_EXPR) ? "expression" \
82                 : "UNKNOWN")
84 %}
86 %pure-parser
87 %lex-param {sdb_fe_yyscan_t scanner}
88 %parse-param {sdb_fe_yyscan_t scanner}
89 %locations
90 %error-verbose
91 %expect 0
92 %name-prefix "sdb_fe_yy"
94 %union {
95         const char *sstr; /* static string */
96         char *str;
97         int integer;
99         sdb_data_t data;
100         sdb_time_t datetime;
102         sdb_llist_t     *list;
103         sdb_conn_node_t *node;
105         sdb_store_matcher_t *m;
106         sdb_store_expr_t *expr;
108         sdb_metric_store_t metric_store;
111 %start statements
113 %token SCANNER_ERROR
115 %token AND OR IS NOT MATCHING FILTER
116 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
117 %token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN
118 %token CONCAT
120 %token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T
121 %token ATTRIBUTE_T ATTRIBUTES_T
122 %token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T
124 %token LAST UPDATE
126 %token START END
128 /* NULL token */
129 %token NULL_T
131 %token FETCH LIST LOOKUP STORE TIMESERIES
133 %token <str> IDENTIFIER STRING
135 %token <data> INTEGER FLOAT
137 %token <datetime> DATE TIME
139 /* Precedence (lowest first): */
140 %left OR
141 %left AND
142 %right NOT
143 %left CMP_EQUAL CMP_NEQUAL
144 %left CMP_LT CMP_LE CMP_GE CMP_GT
145 %nonassoc CMP_REGEX CMP_NREGEX
146 %nonassoc IN
147 %left CONCAT
148 %nonassoc IS
149 %left '+' '-'
150 %left '*' '/' '%'
151 %left '[' ']'
152 %left '(' ')'
153 %left '.'
155 %type <list> statements
156 %type <node> statement
157         fetch_statement
158         list_statement
159         lookup_statement
160         store_statement
161         timeseries_statement
162         matching_clause
163         filter_clause
164         condition
166 %type <m> matcher
167         compare_matcher
169 %type <expr> expression object_expression
171 %type <integer> object_type object_type_plural
172 %type <integer> iterable
173 %type <integer> field
175 %type <sstr> cmp
177 %type <data> data
178         interval interval_elem
179         array array_elem_list
181 %type <datetime> datetime
182         start_clause end_clause
183         last_update_clause
185 %type <metric_store> metric_store_clause
187 %destructor { free($$); } <str>
188 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
189 %destructor { sdb_data_free_datum(&$$); } <data>
191 %%
193 statements:
194         statements ';' statement
195                 {
196                         /* only accepted in default parse mode */
197                         if (parser_mode != SDB_PARSE_DEFAULT) {
198                                 sdb_fe_yyerrorf(&yylloc, scanner,
199                                                 YY_("syntax error, unexpected statement, "
200                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
201                                 sdb_object_deref(SDB_OBJ($3));
202                                 YYABORT;
203                         }
205                         if ($3) {
206                                 sdb_llist_append(pt, SDB_OBJ($3));
207                                 sdb_object_deref(SDB_OBJ($3));
208                         }
209                 }
210         |
211         statement
212                 {
213                         /* only accepted in default parse mode */
214                         if (parser_mode != SDB_PARSE_DEFAULT) {
215                                 sdb_fe_yyerrorf(&yylloc, scanner,
216                                                 YY_("syntax error, unexpected statement, "
217                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
218                                 sdb_object_deref(SDB_OBJ($1));
219                                 YYABORT;
220                         }
222                         if ($1) {
223                                 sdb_llist_append(pt, SDB_OBJ($1));
224                                 sdb_object_deref(SDB_OBJ($1));
225                         }
226                 }
227         |
228         condition
229                 {
230                         /* only accepted in condition parse mode */
231                         if (! (parser_mode & SDB_PARSE_COND)) {
232                                 sdb_fe_yyerrorf(&yylloc, scanner,
233                                                 YY_("syntax error, unexpected condition, "
234                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
235                                 sdb_object_deref(SDB_OBJ($1));
236                                 YYABORT;
237                         }
239                         if ($1) {
240                                 sdb_llist_append(pt, SDB_OBJ($1));
241                                 sdb_object_deref(SDB_OBJ($1));
242                         }
243                 }
244         |
245         expression
246                 {
247                         /* only accepted in expression parse mode */
248                         if (! (parser_mode & SDB_PARSE_EXPR)) {
249                                 sdb_fe_yyerrorf(&yylloc, scanner,
250                                                 YY_("syntax error, unexpected expression, "
251                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
252                                 sdb_object_deref(SDB_OBJ($1));
253                                 YYABORT;
254                         }
256                         if ($1) {
257                                 sdb_conn_node_t *n;
258                                 n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
259                                                         conn_expr_t, conn_expr_destroy));
260                                 n->cmd = SDB_CONNECTION_EXPR;
261                                 CONN_EXPR(n)->expr = $1;
263                                 sdb_llist_append(pt, SDB_OBJ(n));
264                                 sdb_object_deref(SDB_OBJ(n));
265                         }
266                 }
267         ;
269 statement:
270         fetch_statement
271         |
272         list_statement
273         |
274         lookup_statement
275         |
276         store_statement
277         |
278         timeseries_statement
279         |
280         /* empty */
281                 {
282                         $$ = NULL;
283                 }
284         ;
286 /*
287  * FETCH <type> <hostname> [FILTER <condition>];
288  *
289  * Retrieve detailed information about a single host.
290  */
291 fetch_statement:
292         FETCH object_type STRING filter_clause
293                 {
294                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
295                                                 conn_fetch_t, conn_fetch_destroy));
296                         CONN_FETCH($$)->type = $2;
297                         CONN_FETCH($$)->host = $3;
298                         CONN_FETCH($$)->name = NULL;
299                         CONN_FETCH($$)->filter = CONN_MATCHER($4);
300                         $$->cmd = SDB_CONNECTION_FETCH;
301                 }
302         |
303         FETCH object_type STRING '.' STRING filter_clause
304                 {
305                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
306                                                 conn_fetch_t, conn_fetch_destroy));
307                         CONN_FETCH($$)->type = $2;
308                         CONN_FETCH($$)->host = $3;
309                         CONN_FETCH($$)->name = $5;
310                         CONN_FETCH($$)->filter = CONN_MATCHER($6);
311                         $$->cmd = SDB_CONNECTION_FETCH;
312                 }
313         ;
315 /*
316  * LIST <type> [FILTER <condition>];
317  *
318  * Returns a list of all hosts in the store.
319  */
320 list_statement:
321         LIST object_type_plural filter_clause
322                 {
323                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
324                                                 conn_list_t, conn_list_destroy));
325                         CONN_LIST($$)->type = $2;
326                         CONN_LIST($$)->filter = CONN_MATCHER($3);
327                         $$->cmd = SDB_CONNECTION_LIST;
328                 }
329         ;
331 /*
332  * LOOKUP <type> MATCHING <condition> [FILTER <condition>];
333  *
334  * Returns detailed information about <type> matching condition.
335  */
336 lookup_statement:
337         LOOKUP object_type_plural matching_clause filter_clause
338                 {
339                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
340                                                 conn_lookup_t, conn_lookup_destroy));
341                         CONN_LOOKUP($$)->type = $2;
342                         CONN_LOOKUP($$)->matcher = CONN_MATCHER($3);
343                         CONN_LOOKUP($$)->filter = CONN_MATCHER($4);
344                         $$->cmd = SDB_CONNECTION_LOOKUP;
345                 }
346         ;
348 matching_clause:
349         MATCHING condition { $$ = $2; }
350         |
351         /* empty */ { $$ = NULL; }
353 filter_clause:
354         FILTER condition { $$ = $2; }
355         |
356         /* empty */ { $$ = NULL; }
358 /*
359  * STORE <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
360  * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
361  * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
362  *
363  * Store or update an object in the database.
364  */
365 store_statement:
366         STORE HOST_T STRING last_update_clause
367                 {
368                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
369                                                 conn_store_host_t, conn_store_host_destroy));
370                         CONN_STORE_HOST($$)->name = $3;
371                         CONN_STORE_HOST($$)->last_update = $4;
372                         $$->cmd = SDB_CONNECTION_STORE_HOST;
373                 }
374         |
375         STORE SERVICE_T STRING '.' STRING last_update_clause
376                 {
377                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
378                                                 conn_store_svc_t, conn_store_svc_destroy));
379                         CONN_STORE_SVC($$)->hostname = $3;
380                         CONN_STORE_SVC($$)->name = $5;
381                         CONN_STORE_SVC($$)->last_update = $6;
382                         $$->cmd = SDB_CONNECTION_STORE_SERVICE;
383                 }
384         |
385         STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause
386                 {
387                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
388                                                 conn_store_metric_t, conn_store_metric_destroy));
389                         CONN_STORE_METRIC($$)->hostname = $3;
390                         CONN_STORE_METRIC($$)->name = $5;
391                         CONN_STORE_METRIC($$)->store_type = $6.type;
392                         CONN_STORE_METRIC($$)->store_id = $6.id;
393                         CONN_STORE_METRIC($$)->last_update = $7;
394                         $$->cmd = SDB_CONNECTION_STORE_METRIC;
395                 }
396         |
397         STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause
398                 {
399                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
400                                                 conn_store_attr_t, conn_store_attr_destroy));
401                         CONN_STORE_ATTR($$)->parent_type = SDB_HOST;
402                         CONN_STORE_ATTR($$)->hostname = NULL;
403                         CONN_STORE_ATTR($$)->parent = $4;
404                         CONN_STORE_ATTR($$)->key = $6;
405                         CONN_STORE_ATTR($$)->value = $7;
406                         CONN_STORE_ATTR($$)->last_update = $8;
407                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
408                 }
409         |
410         STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
411                 {
412                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
413                                                 conn_store_attr_t, conn_store_attr_destroy));
414                         CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE;
415                         CONN_STORE_ATTR($$)->hostname = $4;
416                         CONN_STORE_ATTR($$)->parent = $6;
417                         CONN_STORE_ATTR($$)->key = $8;
418                         CONN_STORE_ATTR($$)->value = $9;
419                         CONN_STORE_ATTR($$)->last_update = $10;
420                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
421                 }
422         |
423         STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
424                 {
425                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
426                                                 conn_store_attr_t, conn_store_attr_destroy));
427                         CONN_STORE_ATTR($$)->parent_type = SDB_METRIC;
428                         CONN_STORE_ATTR($$)->hostname = $4;
429                         CONN_STORE_ATTR($$)->parent = $6;
430                         CONN_STORE_ATTR($$)->key = $8;
431                         CONN_STORE_ATTR($$)->value = $9;
432                         CONN_STORE_ATTR($$)->last_update = $10;
433                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
434                 }
435         ;
437 last_update_clause:
438         LAST UPDATE datetime { $$ = $3; }
439         |
440         /* empty */ { $$ = sdb_gettime(); }
442 metric_store_clause:
443         STORE STRING STRING { $$.type = $2; $$.id = $3; }
444         |
445         /* empty */ { $$.type = $$.id = NULL; }
447 /*
448  * TIMESERIES <host>.<metric> [START <datetime>] [END <datetime>];
449  *
450  * Returns a time-series for the specified host's metric.
451  */
452 timeseries_statement:
453         TIMESERIES STRING '.' STRING start_clause end_clause
454                 {
455                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
456                                                 conn_ts_t, conn_ts_destroy));
457                         CONN_TS($$)->hostname = $2;
458                         CONN_TS($$)->metric = $4;
459                         CONN_TS($$)->opts.start = $5;
460                         CONN_TS($$)->opts.end = $6;
461                         $$->cmd = SDB_CONNECTION_TIMESERIES;
462                 }
463         ;
465 start_clause:
466         START datetime { $$ = $2; }
467         |
468         /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; }
470 end_clause:
471         END datetime { $$ = $2; }
472         |
473         /* empty */ { $$ = sdb_gettime(); }
475 /*
476  * Basic expressions.
477  */
479 condition:
480         matcher
481                 {
482                         if (! $1) {
483                                 /* TODO: improve error reporting */
484                                 sdb_fe_yyerror(&yylloc, scanner,
485                                                 YY_("syntax error, invalid condition"));
486                                 YYABORT;
487                         }
489                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
490                                                 conn_matcher_t, conn_matcher_destroy));
491                         $$->cmd = SDB_CONNECTION_MATCHER;
492                         CONN_MATCHER($$)->matcher = $1;
493                 }
494         ;
496 matcher:
497         '(' matcher ')'
498                 {
499                         $$ = $2;
500                 }
501         |
502         matcher AND matcher
503                 {
504                         $$ = sdb_store_con_matcher($1, $3);
505                         sdb_object_deref(SDB_OBJ($1));
506                         sdb_object_deref(SDB_OBJ($3));
507                 }
508         |
509         matcher OR matcher
510                 {
511                         $$ = sdb_store_dis_matcher($1, $3);
512                         sdb_object_deref(SDB_OBJ($1));
513                         sdb_object_deref(SDB_OBJ($3));
514                 }
515         |
516         NOT matcher
517                 {
518                         $$ = sdb_store_inv_matcher($2);
519                         sdb_object_deref(SDB_OBJ($2));
520                 }
521         |
522         compare_matcher
523                 {
524                         $$ = $1;
525                 }
526         ;
528 compare_matcher:
529         expression cmp expression
530                 {
531                         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2);
532                         assert(cb); /* else, the grammar accepts invalid 'cmp' */
533                         $$ = cb($1, $3);
534                         sdb_object_deref(SDB_OBJ($1));
535                         sdb_object_deref(SDB_OBJ($3));
536                 }
537         |
538         ANY iterable cmp expression
539                 {
540                         $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4);
541                         sdb_object_deref(SDB_OBJ($4));
542                 }
543         |
544         ALL iterable cmp expression
545                 {
546                         $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4);
547                         sdb_object_deref(SDB_OBJ($4));
548                 }
549         |
550         expression IS NULL_T
551                 {
552                         $$ = sdb_store_isnull_matcher($1);
553                         sdb_object_deref(SDB_OBJ($1));
554                 }
555         |
556         expression IS NOT NULL_T
557                 {
558                         $$ = sdb_store_isnnull_matcher($1);
559                         sdb_object_deref(SDB_OBJ($1));
560                 }
561         |
562         expression IN expression
563                 {
564                         $$ = sdb_store_in_matcher($1, $3);
565                         sdb_object_deref(SDB_OBJ($1));
566                         sdb_object_deref(SDB_OBJ($3));
567                 }
568         ;
570 expression:
571         '(' expression ')'
572                 {
573                         $$ = $2;
574                 }
575         |
576         expression '+' expression
577                 {
578                         $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
579                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
580                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
581                 }
582         |
583         expression '-' expression
584                 {
585                         $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
586                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
587                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
588                 }
589         |
590         expression '*' expression
591                 {
592                         $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
593                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
594                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
595                 }
596         |
597         expression '/' expression
598                 {
599                         $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
600                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
601                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
602                 }
603         |
604         expression '%' expression
605                 {
606                         $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
607                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
608                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
609                 }
610         |
611         expression CONCAT expression
612                 {
613                         $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
614                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
615                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
616                 }
617         |
618         object_expression
619                 {
620                         $$ = $1;
621                 }
622         |
623         data
624                 {
625                         $$ = sdb_store_expr_constvalue(&$1);
626                         sdb_data_free_datum(&$1);
627                 }
628         ;
630 object_expression:
631         object_type '.' object_expression
632                 {
633                         $$ = sdb_store_expr_typed($1, $3);
634                         sdb_object_deref(SDB_OBJ($3));
635                 }
636         |
637         field
638                 {
639                         $$ = sdb_store_expr_fieldvalue($1);
640                 }
641         |
642         ATTRIBUTE_T '[' STRING ']'
643                 {
644                         $$ = sdb_store_expr_attrvalue($3);
645                         free($3); $3 = NULL;
646                 }
647         ;
649 object_type:
650         HOST_T { $$ = SDB_HOST; }
651         |
652         SERVICE_T { $$ = SDB_SERVICE; }
653         |
654         METRIC_T { $$ = SDB_METRIC; }
655         ;
657 object_type_plural:
658         HOSTS_T { $$ = SDB_HOST; }
659         |
660         SERVICES_T { $$ = SDB_SERVICE; }
661         |
662         METRICS_T { $$ = SDB_METRIC; }
663         ;
665 iterable:
666         SERVICE_T { $$ = SDB_SERVICE; }
667         |
668         METRIC_T { $$ = SDB_METRIC; }
669         |
670         ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; }
671         |
672         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
673         ;
675 field:
676         NAME_T { $$ = SDB_FIELD_NAME; }
677         |
678         LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
679         |
680         AGE_T { $$ = SDB_FIELD_AGE; }
681         |
682         INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
683         |
684         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
685         ;
687 cmp:
688         CMP_EQUAL { $$ = "="; }
689         |
690         CMP_NEQUAL { $$ = "!="; }
691         |
692         CMP_REGEX { $$ = "=~"; }
693         |
694         CMP_NREGEX { $$ = "!~"; }
695         |
696         CMP_LT { $$ = "<"; }
697         |
698         CMP_LE { $$ = "<="; }
699         |
700         CMP_GE { $$ = ">="; }
701         |
702         CMP_GT { $$ = ">"; }
703         ;
705 data:
706         STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
707         |
708         INTEGER { $$ = $1; }
709         |
710         FLOAT { $$ = $1; }
711         |
712         datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
713         |
714         interval { $$ = $1; }
715         |
716         array { $$ = $1; }
717         ;
719 datetime:
720         DATE TIME { $$ = $1 + $2; }
721         |
722         DATE { $$ = $1; }
723         |
724         TIME { $$ = $1; }
725         ;
727 interval:
728         interval interval_elem
729                 {
730                         $$.data.datetime = $1.data.datetime + $2.data.datetime;
731                 }
732         |
733         interval_elem { $$ = $1; }
734         ;
736 interval_elem:
737         INTEGER IDENTIFIER
738                 {
739                         sdb_time_t unit = 1;
741                         unit = sdb_strpunit($2);
742                         if (! unit) {
743                                 sdb_fe_yyerrorf(&yylloc, scanner,
744                                                 YY_("syntax error, invalid time unit %s"), $2);
745                                 free($2); $2 = NULL;
746                                 YYABORT;
747                         }
748                         free($2); $2 = NULL;
750                         $$.type = SDB_TYPE_DATETIME;
751                         $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
753                         if ($1.data.integer < 0) {
754                                 sdb_fe_yyerror(&yylloc, scanner,
755                                                 YY_("syntax error, negative intervals not supported"));
756                                 YYABORT;
757                         }
758                 }
759         ;
761 array:
762         '[' array_elem_list ']'
763                 {
764                         $$ = $2;
765                 }
766         ;
768 array_elem_list:
769         array_elem_list ',' data
770                 {
771                         size_t elem_size;
773                         if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
774                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
775                                                 "cannot use element of type %s in array of type %s"),
776                                                 SDB_TYPE_TO_STRING($3.type),
777                                                 SDB_TYPE_TO_STRING($1.type));
778                                 sdb_data_free_datum(&$1);
779                                 sdb_data_free_datum(&$3);
780                                 YYABORT;
781                         }
783                         elem_size = sdb_data_sizeof($3.type);
784                         $1.data.array.values = realloc($1.data.array.values,
785                                         ($1.data.array.length + 1) * elem_size);
786                         if (! $1.data.array.values) {
787                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
788                                 YYABORT;
789                         }
791                         memcpy((char *)$1.data.array.values
792                                                 + $1.data.array.length * elem_size,
793                                         &$3.data, elem_size);
794                         ++$1.data.array.length;
796                         $$ = $1;
797                 }
798         |
799         data
800                 {
801                         size_t elem_size;
803                         if ($1.type & SDB_TYPE_ARRAY) {
804                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
805                                                 "cannot construct array of type %s"),
806                                                 SDB_TYPE_TO_STRING($1.type));
807                                 sdb_data_free_datum(&$1);
808                                 YYABORT;
809                         }
811                         $$ = $1;
812                         $$.type = $1.type | SDB_TYPE_ARRAY;
813                         $$.data.array.length = 1;
814                         elem_size = sdb_data_sizeof($1.type);
815                         $$.data.array.values = malloc(elem_size);
816                         if (! $$.data.array.values ) {
817                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
818                                 YYABORT;
819                         }
820                         memcpy($$.data.array.values, &$1.data, elem_size);
821                 }
822         ;
824 %%
826 void
827 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
829         sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
830         sdb_strbuf_sprintf(errbuf, "%s", msg);
831 } /* sdb_fe_yyerror */
833 void
834 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
836         va_list ap, aq;
837         va_start(ap, fmt);
838         va_copy(aq, ap);
839         sdb_vlog(SDB_LOG_ERR, fmt, ap);
840         sdb_strbuf_vsprintf(errbuf, "%s", aq);
841         va_end(ap);
842 } /* sdb_fe_yyerrorf */
844 static sdb_store_matcher_t *
845 name_iter_matcher(int m_type, int type, const char *cmp,
846                 sdb_store_expr_t *expr)
848         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
849         sdb_store_expr_t *e;
850         sdb_store_matcher_t *m, *tmp = NULL;
851         assert(cb);
853         /* hosts are never iterable */
854         if (type == SDB_HOST) {
855                 return NULL;
856         }
858         if (type == SDB_FIELD_BACKEND)
859                 e = sdb_store_expr_fieldvalue(type);
860         else
861                 e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
862         m = cb(e, expr);
863         if (m_type == MATCHER_ANY)
864                 tmp = sdb_store_any_matcher(type, m);
865         else if (m_type == MATCHER_ALL)
866                 tmp = sdb_store_all_matcher(type, m);
867         sdb_object_deref(SDB_OBJ(m));
868         sdb_object_deref(SDB_OBJ(e));
869         return tmp;
870 } /* name_iter_matcher */
872 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */