Code

analyzer: Fixed some error messages.
[sysdb.git] / src / parser / analyzer.c
1 /*
2  * SysDB - src/parser/analyzer.c
3  * Copyright (C) 2014-2015 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 #include "sysdb.h"
30 #include "parser/ast.h"
31 #include "parser/parser.h"
32 #include "utils/error.h"
33 #include "utils/strbuf.h"
35 #include <assert.h>
36 #include <stdarg.h>
38 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
40 #define FILTER_CONTEXT -1
42 static int
43 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
45 /*
46  * error reporting
47  */
49 static void
50 op_error(sdb_strbuf_t *errbuf, sdb_ast_op_t *op, const char *reason)
51 {
52         sdb_strbuf_sprintf(errbuf, "Invalid operation %s %s %s (%s)",
53                         SDB_TYPE_TO_STRING(op->left->data_type),
54                         SDB_AST_OP_TO_STRING(op->kind),
55                         SDB_TYPE_TO_STRING(op->right->data_type),
56                         reason);
57 } /* op_error */
59 static void
60 __attribute__((format(printf, 3, 4)))
61 iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...)
62 {
63         char r[1024];
64         va_list ap;
66         va_start(ap, reason);
67         vsnprintf(r, sizeof(r), reason, ap);
68         va_end(ap);
70         assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
71                         && (! SDB_AST_OP(iter->expr)->left));
72         sdb_strbuf_sprintf(errbuf, "Invalid iterator %s %s %s %s (%s)",
73                         SDB_AST_OP_TO_STRING(iter->kind),
74                         SDB_TYPE_TO_STRING(iter->iter->data_type),
75                         SDB_AST_OP_TO_STRING(SDB_AST_OP(iter->expr)->kind),
76                         SDB_TYPE_TO_STRING(SDB_AST_OP(iter->expr)->right->data_type),
77                         r);
78 } /* iter_error */
80 /*
81  * expression nodes
82  */
84 static int
85 analyze_logical(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
86 {
87         switch (op->kind) {
88         case SDB_AST_OR:
89         case SDB_AST_AND:
90                 if (! SDB_AST_IS_LOGICAL(op->left)) {
91                         sdb_strbuf_sprintf(errbuf, "Invalid left operand (%s) "
92                                         "in %s expression", SDB_AST_TYPE_TO_STRING(op->left),
93                                         SDB_AST_OP_TO_STRING(op->kind));
94                         return -1;
95                 }
96                 if (analyze_node(context, op->left, errbuf))
97                         return -1;
98                 /* fallthrough */
99         case SDB_AST_NOT:
100                 if (! SDB_AST_IS_LOGICAL(op->right)) {
101                         sdb_strbuf_sprintf(errbuf, "Invalid right operand (%s) "
102                                         "in %s expression", SDB_AST_TYPE_TO_STRING(op->right),
103                                         SDB_AST_OP_TO_STRING(op->kind));
104                         return -1;
105                 }
106                 if (analyze_node(context, op->right, errbuf))
107                         return -1;
108                 break;
110         case SDB_AST_LT:
111         case SDB_AST_LE:
112         case SDB_AST_EQ:
113         case SDB_AST_NE:
114         case SDB_AST_GE:
115         case SDB_AST_GT:
116         {
117                 if (analyze_node(context, op->left, errbuf))
118                         return -1;
119                 if (analyze_node(context, op->right, errbuf))
120                         return -1;
122                 if ((op->left->data_type > 0) && (op->right->data_type > 0)) {
123                         if (op->left->data_type == op->right->data_type)
124                                 return 0;
125                         op_error(errbuf, op, "type mismatch");
126                         return -1;
127                 }
128                 if ((op->left->data_type > 0) && (op->left->data_type & SDB_TYPE_ARRAY)) {
129                         op_error(errbuf, op, "array not allowed");
130                         return -1;
131                 }
132                 if ((op->right->data_type > 0) && (op->right->data_type & SDB_TYPE_ARRAY)) {
133                         op_error(errbuf, op, "array not allowed");
134                         return -1;
135                 }
136                 break;
137         }
139         case SDB_AST_REGEX:
140         case SDB_AST_NREGEX:
141                 if (analyze_node(context, op->left, errbuf))
142                         return -1;
143                 if (analyze_node(context, op->right, errbuf))
144                         return -1;
146                 /* all types are supported for the left operand
147                  * TODO: introduce a cast operator if it's not a string */
148                 if ((op->right->data_type > 0)
149                                 && (op->right->data_type != SDB_TYPE_REGEX)
150                                 && (op->right->data_type != SDB_TYPE_STRING)) {
151                         op_error(errbuf, op, "invalid regex");
152                         return -1;
153                 }
154                 break;
156         case SDB_AST_ISNULL:
157         case SDB_AST_ISTRUE:
158         case SDB_AST_ISFALSE:
159                 if (analyze_node(context, op->right, errbuf))
160                         return -1;
161                 break;
163         case SDB_AST_IN:
164                 if (analyze_node(context, op->left, errbuf))
165                         return -1;
166                 if (analyze_node(context, op->right, errbuf))
167                         return -1;
169                 if ((op->right->data_type > 0) && (! (op->right->data_type & SDB_TYPE_ARRAY))) {
170                         op_error(errbuf, op, "array expected");
171                         return -1;
172                 }
173                 /* the left operand may be a scalar or an array but the element
174                  * type has to match */
175                 if ((op->left->data_type > 0) && (op->right->data_type > 0)
176                                 && ((op->left->data_type & 0xff) != (op->right->data_type & 0xff))) {
177                         op_error(errbuf, op, "type mismatch");
178                         return -1;
179                 }
180                 break;
182         default:
183                 sdb_strbuf_sprintf(errbuf, "Unknown operand type %d", op->kind);
184                 return -1;
185         }
186         return 0;
187 } /* analyze_logical */
189 static int
190 analyze_arith(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
192         if (analyze_node(context, op->left, errbuf))
193                 return -1;
194         if (analyze_node(context, op->right, errbuf))
195                 return -1;
196         SDB_AST_NODE(op)->data_type = sdb_data_expr_type(SDB_AST_OP_TO_DATA_OP(op->kind),
197                         op->left->data_type, op->right->data_type);
199         if ((op->left->data_type > 0) && (op->right->data_type > 0)
200                         && (SDB_AST_NODE(op)->data_type <= 0)) {
201                 op_error(errbuf, op, "type mismatch");
202                 return -1;
203         }
205         /* TODO: replace constant arithmetic operations with a constant value */
206         return 0;
207 } /* analyze_arith */
209 static int
210 analyze_iter(int context, sdb_ast_iter_t *iter, sdb_strbuf_t *errbuf)
212         sdb_ast_const_t c = SDB_AST_CONST_INIT;
213         int iter_context = context;
214         int status;
216         if (iter->iter->type == SDB_AST_TYPE_TYPED)
217                 iter_context = SDB_AST_TYPED(iter->iter)->type;
219         if (analyze_node(iter_context, iter->iter, errbuf))
220                 return -1;
221         /* TODO: support other setups as well */
222         assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
223                         && (! SDB_AST_OP(iter->expr)->left));
224         /* determine the data-type for better error messages */
225         analyze_node(iter_context, SDB_AST_OP(iter->expr)->right, NULL);
227         if (iter->iter->type == SDB_AST_TYPE_TYPED) {
228                 int iter_type = SDB_AST_TYPED(iter->iter)->type;
230                 c.value.type = iter->iter->data_type;
232                 if (iter_type == SDB_ATTRIBUTE) {
233                         /* attributes are always iterable */
234                 }
235                 else if ((context != SDB_HOST) && (context != SDB_SERVICE)
236                                 && (context != SDB_METRIC)) {
237                         iter_error(errbuf, iter, "%s not iterable in %s context",
238                                         SDB_STORE_TYPE_TO_NAME(iter_type),
239                                         SDB_STORE_TYPE_TO_NAME(context));
240                         return -1;
241                 }
243                 if ((context == iter_type)
244                                 || ((iter_type != SDB_SERVICE)
245                                         && (iter_type != SDB_METRIC)
246                                         && (iter_type != SDB_ATTRIBUTE))
247                                 || ((context == SDB_SERVICE)
248                                         && (iter_type == SDB_METRIC))
249                                 || ((context == SDB_METRIC)
250                                         && (iter_type == SDB_SERVICE))) {
251                         iter_error(errbuf, iter, "%s not iterable in %s context",
252                                         SDB_STORE_TYPE_TO_NAME(iter_type),
253                                         SDB_STORE_TYPE_TO_NAME(context));
254                         return -1;
255                 }
256         }
257         else if (iter->iter->type == SDB_AST_TYPE_VALUE) {
258                 int iter_type = SDB_AST_VALUE(iter->iter)->type;
260                 c.value.type = iter->iter->data_type & 0xff;
262                 if (iter_type != SDB_FIELD_BACKEND) {
263                         iter_error(errbuf, iter, "%s not iterable in %s context",
264                                         (iter_type == SDB_ATTRIBUTE)
265                                                 ? "attribute"
266                                                 : SDB_FIELD_TO_NAME(iter_type),
267                                         SDB_STORE_TYPE_TO_NAME(context));
268                         return -1;
269                 }
270         }
271         else if (iter->iter->type == SDB_AST_TYPE_CONST) {
272                 c.value.type = iter->iter->data_type & 0xff;
274                 if (! (SDB_AST_CONST(iter->iter)->value.type & SDB_TYPE_ARRAY)) {
275                         iter_error(errbuf, iter, "%s not iterable",
276                                         SDB_TYPE_TO_STRING(SDB_AST_CONST(iter->iter)->value.type));
277                         return -1;
278                 }
279         }
280         else {
281                 /* TODO: if we know the data-type of iter->iter and it's an array,
282                  * we should support an iterator for it as well */
283                 iter_error(errbuf, iter, "%s expression not iterable",
284                                 SDB_AST_TYPE_TO_STRING(iter->iter));
285                 return -1;
286         }
288         SDB_AST_OP(iter->expr)->left = SDB_AST_NODE(&c);
289         status = analyze_node(context, iter->expr, errbuf);
290         SDB_AST_OP(iter->expr)->left = NULL;
291         if (status)
292                 return -1;
293         return 0;
294 } /* analyze_iter */
296 static int
297 analyze_const(int __attribute__((unused)) context, sdb_ast_const_t *c,
298                 sdb_strbuf_t __attribute__((unused)) *errbuf)
300         SDB_AST_NODE(c)->data_type = c->value.type;
301         return 0;
302 } /* analyze_const */
304 static int
305 analyze_value(int context, sdb_ast_value_t *v, sdb_strbuf_t *errbuf)
307         if (v->type != SDB_ATTRIBUTE)
308                 SDB_AST_NODE(v)->data_type = SDB_FIELD_TYPE(v->type);
310         if ((v->type != SDB_ATTRIBUTE) && v->name) {
311                 sdb_strbuf_sprintf(errbuf, "Invalid expression %s[%s]",
312                                 SDB_FIELD_TO_NAME(v->type), v->name);
313                 return -1;
314         }
315         else if ((v->type == SDB_ATTRIBUTE) && (! v->name)) {
316                 sdb_strbuf_sprintf(errbuf, "Invalid expression attribute[] "
317                                 "(missing name)");
318                 return -1;
319         }
321         if ((context != SDB_ATTRIBUTE) && (v->type == SDB_FIELD_VALUE)) {
322                 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.value",
323                                 SDB_FIELD_TO_NAME(context));
324                 return -1;
325         }
326         if ((context != SDB_METRIC) && (v->type == SDB_FIELD_TIMESERIES)) {
327                 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.timeseries",
328                                 SDB_FIELD_TO_NAME(context));
329                 return -1;
330         }
331         return 0;
332 } /* analyze_value */
334 static int
335 analyze_typed(int context, sdb_ast_typed_t *t, sdb_strbuf_t *errbuf)
337         if ((t->expr->type != SDB_AST_TYPE_VALUE)
338                         && (t->expr->type != SDB_AST_TYPE_TYPED)) {
339                 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s",
340                                 SDB_STORE_TYPE_TO_NAME(t->type),
341                                 SDB_AST_TYPE_TO_STRING(t->expr));
342                 return -1;
343         }
344         if (analyze_node(t->type, t->expr, errbuf))
345                 return -1;
346         SDB_AST_NODE(t)->data_type = t->expr->data_type;
348         if ((t->type != SDB_ATTRIBUTE) && (! VALID_OBJ_TYPE(t->type))) {
349                 sdb_strbuf_sprintf(errbuf, "Invalid expression %#x.%s",
350                                 t->type, SDB_AST_TYPE_TO_STRING(t->expr));
351                 return -1;
352         }
354         /* self-references are allowed and services and metrics may reference
355          * their parent host; everything may reference attributes */
356         if ((context != t->type) && (context > 0)
357                         && (((context != SDB_SERVICE) && (context != SDB_METRIC))
358                                 || (t->type != SDB_HOST))
359                         && (t->type != SDB_ATTRIBUTE)) {
360                 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s in %s context",
361                                 SDB_STORE_TYPE_TO_NAME(t->type),
362                                 SDB_AST_TYPE_TO_STRING(t->expr),
363                                 context == -1 ? "generic" : SDB_STORE_TYPE_TO_NAME(context));
364                 return -1;
365         }
366         return 0;
367 } /* analyze_typed */
369 static int
370 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
372         if (! node) {
373                 sdb_strbuf_sprintf(errbuf, "Empty AST node");
374                 return -1;
375         }
377         /* unknown by default */
378         node->data_type = -1;
380         if ((node->type == SDB_AST_TYPE_OPERATOR)
381                         && (SDB_AST_IS_LOGICAL(node)))
382                 return analyze_logical(context, SDB_AST_OP(node), errbuf);
383         else if ((node->type == SDB_AST_TYPE_OPERATOR)
384                         && (SDB_AST_IS_ARITHMETIC(node)))
385                 return analyze_arith(context, SDB_AST_OP(node), errbuf);
386         else if (node->type == SDB_AST_TYPE_ITERATOR)
387                 return analyze_iter(context, SDB_AST_ITER(node), errbuf);
388         else if (node->type == SDB_AST_TYPE_CONST)
389                 return analyze_const(context, SDB_AST_CONST(node), errbuf);
390         else if (node->type == SDB_AST_TYPE_VALUE)
391                 return analyze_value(context, SDB_AST_VALUE(node), errbuf);
392         else if (node->type == SDB_AST_TYPE_TYPED)
393                 return analyze_typed(context, SDB_AST_TYPED(node), errbuf);
395         sdb_strbuf_sprintf(errbuf, "Invalid expression node "
396                         "of type %#x", node->type);
397         return -1;
398 } /* analyze_node */
400 /*
401  * top level / command nodes
402  */
404 static int
405 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
407         if (! VALID_OBJ_TYPE(fetch->obj_type)) {
408                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
409                                 "in FETCH command", fetch->obj_type);
410                 return -1;
411         }
412         if (! fetch->name) {
413                 sdb_strbuf_sprintf(errbuf, "Missing object name in "
414                                 "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
415                 return -1;
416         }
418         if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
419                 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
420                                 "in FETCH HOST command", fetch->hostname);
421                 return -1;
422         }
423         else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
424                 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
425                                 "in FETCH %s command", fetch->name,
426                                 SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
427                 return -1;
428         }
430         if (fetch->filter)
431                 return analyze_node(FILTER_CONTEXT, fetch->filter, errbuf);
432         return 0;
433 } /* analyze_fetch */
435 static int
436 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
438         if (! VALID_OBJ_TYPE(list->obj_type)) {
439                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
440                                 "in LIST command", list->obj_type);
441                 return -1;
442         }
443         if (list->filter)
444                 return analyze_node(FILTER_CONTEXT, list->filter, errbuf);
445         return 0;
446 } /* analyze_list */
448 static int
449 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
451         if (! VALID_OBJ_TYPE(lookup->obj_type)) {
452                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
453                                 "in LOOKUP command", lookup->obj_type);
454                 return -1;
455         }
456         if (lookup->matcher)
457                 if (analyze_node(lookup->obj_type, lookup->matcher, errbuf))
458                         return -1;
459         if (lookup->filter)
460                 return analyze_node(FILTER_CONTEXT, lookup->filter, errbuf);
461         return 0;
462 } /* analyze_lookup */
464 static int
465 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
467         if ((st->obj_type != SDB_ATTRIBUTE)
468                         && (! VALID_OBJ_TYPE(st->obj_type))) {
469                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
470                                 "in STORE command", st->obj_type);
471                 return -1;
472         }
473         if (! st->name) {
474                 sdb_strbuf_sprintf(errbuf, "Missing object name in "
475                                 "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
476                 return -1;
477         }
479         if ((st->obj_type == SDB_HOST) && st->hostname) {
480                 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
481                                 "in STORE HOST command", st->hostname);
482                 return -1;
483         }
484         else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
485                 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
486                                 "in STORE %s command", st->name,
487                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
488                 return -1;
489         }
491         if (st->obj_type == SDB_ATTRIBUTE) {
492                 if ((st->parent_type <= 0) && st->parent) {
493                         sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
494                                         "in STORE %s command", st->parent,
495                                         SDB_STORE_TYPE_TO_NAME(st->obj_type));
496                         return -1;
497                 }
498                 else if (st->parent_type > 0) {
499                         if (! VALID_OBJ_TYPE(st->parent_type)) {
500                                 sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
501                                                 "in STORE %s command", st->parent_type,
502                                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
503                                 return -1;
504                         }
505                         if (! st->parent) {
506                                 sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
507                                                 "in STORE %s command",
508                                                 SDB_STORE_TYPE_TO_NAME(st->parent_type),
509                                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
510                                 return -1;
511                         }
512                 }
513         }
514         else if ((st->parent_type > 0) || st->parent) {
515                 sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
516                                 "in STORE %s command",
517                                 SDB_STORE_TYPE_TO_NAME(st->parent_type),
518                                 st->parent ? st->parent : "<unknown>",
519                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
520                 return -1;
521         }
523         if (st->obj_type == SDB_METRIC) {
524                 if ((! st->store_type) != (! st->store_id)) {
525                         sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
526                                         "in STORE METRIC command",
527                                         st->store_type ? st->store_type : "<unknown>",
528                                         st->store_id ? st->store_id : "<unknown>");
529                         return -1;
530                 }
531         }
532         else if (st->store_type || st->store_id) {
533                 sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
534                                 "in STORE %s command",
535                                 st->store_type ? st->store_type : "<unknown>",
536                                 st->store_id ? st->store_id : "<unknown>",
537                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
538                 return -1;
539         }
541         if ((! (st->obj_type == SDB_ATTRIBUTE))
542                         && (st->value.type != SDB_TYPE_NULL)) {
543                 char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
544                 sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
545                 sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
546                                 v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
547                 return -1;
548         }
549         return 0;
550 } /* analyze_store */
552 static int
553 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
555         if (! ts->hostname) {
556                 sdb_strbuf_sprintf(errbuf, "Missing hostname in TIMESERIES command");
557                 return -1;
558         }
559         if (! ts->metric) {
560                 sdb_strbuf_sprintf(errbuf, "Missing metric name in TIMESERIES command");
561                 return -1;
562         }
563         if (ts->end <= ts->start) {
564                 char start_str[64], end_str[64];
565                 sdb_strftime(start_str, sizeof(start_str), ts->start);
566                 sdb_strftime(end_str, sizeof(end_str), ts->end);
567                 sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
568                                 "end time (%s) in TIMESERIES command", start_str, end_str);
569                 return -1;
570         }
571         return 0;
572 } /* analyze_timeseries */
574 /*
575  * public API
576  */
578 int
579 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
581         if (! node) {
582                 sdb_strbuf_sprintf(errbuf, "Empty AST node");
583                 return -1;
584         }
586         /* top-level nodes don't have a type */
587         node->data_type = -1;
589         if (node->type == SDB_AST_TYPE_FETCH)
590                 return analyze_fetch(SDB_AST_FETCH(node), errbuf);
591         else if (node->type == SDB_AST_TYPE_LIST)
592                 return analyze_list(SDB_AST_LIST(node), errbuf);
593         else if (node->type == SDB_AST_TYPE_LOOKUP)
594                 return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
595         else if (node->type == SDB_AST_TYPE_STORE)
596                 return analyze_store(SDB_AST_STORE(node), errbuf);
597         else if (node->type == SDB_AST_TYPE_TIMESERIES)
598                 return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
600         sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
601                         "of type %#x", node->type);
602         return -1;
603 } /* sdb_parser_analyze */
605 int
606 sdb_parser_analyze_conditional(int context,
607                 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
609         if (! VALID_OBJ_TYPE(context)) {
610                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
611                 return -1;
612         }
613         if (! node) {
614                 sdb_strbuf_sprintf(errbuf, "Empty conditional node");
615                 return -1;
616         }
617         if (! SDB_AST_IS_LOGICAL(node)) {
618                 sdb_strbuf_sprintf(errbuf, "Not a conditional node (got %s)",
619                                 SDB_AST_TYPE_TO_STRING(node));
620                 return -1;
621         }
622         return analyze_node(context, node, errbuf);
623 } /* sdb_parser_analyze_conditional */
625 int
626 sdb_parser_analyze_arith(int context,
627                 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
629         if (! VALID_OBJ_TYPE(context)) {
630                 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
631                 return -1;
632         }
633         if (! node) {
634                 sdb_strbuf_sprintf(errbuf, "Empty arithmetic node");
635                 return -1;
636         }
637         if (! SDB_AST_IS_ARITHMETIC(node)) {
638                 sdb_strbuf_sprintf(errbuf, "Not an arithmetic node (got %s)",
639                                 SDB_AST_TYPE_TO_STRING(node));
640                 return -1;
641         }
642         return analyze_node(context, node, errbuf);
643 } /* sdb_parser_analyze_arith */
645 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */