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>
37 #include <stdbool.h>
38 #include <string.h>
40 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
42 typedef struct {
43 int type;
44 bool iter;
45 } context_t;
47 #define FILTER_CONTEXT -1
48 static const context_t FILTER_CTX = { FILTER_CONTEXT, 0 };
50 static int
51 analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
53 /*
54 * error reporting
55 */
57 static void
58 op_error(sdb_strbuf_t *errbuf, sdb_ast_op_t *op, const char *reason)
59 {
60 sdb_strbuf_sprintf(errbuf, "Invalid operation %s %s %s (%s)",
61 SDB_TYPE_TO_STRING(op->left->data_type),
62 SDB_AST_OP_TO_STRING(op->kind),
63 SDB_TYPE_TO_STRING(op->right->data_type),
64 reason);
65 } /* op_error */
67 static void
68 __attribute__((format(printf, 3, 4)))
69 iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...)
70 {
71 char r[1024];
72 va_list ap;
74 va_start(ap, reason);
75 vsnprintf(r, sizeof(r), reason, ap);
76 va_end(ap);
78 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
79 && (! SDB_AST_OP(iter->expr)->left));
80 sdb_strbuf_sprintf(errbuf, "Invalid iterator %s %s %s %s (%s)",
81 SDB_AST_OP_TO_STRING(iter->kind),
82 SDB_TYPE_TO_STRING(iter->iter->data_type),
83 SDB_AST_OP_TO_STRING(SDB_AST_OP(iter->expr)->kind),
84 SDB_TYPE_TO_STRING(SDB_AST_OP(iter->expr)->right->data_type),
85 r);
86 } /* iter_error */
88 /*
89 * generic checks
90 */
92 typedef struct {
93 int obj_type;
94 const char *hostname;
95 int parent_type;
96 const char *parent;
97 const char *name;
98 } parent_child_t;
100 static int
101 analyze_parent_child(const char *cmd, parent_child_t *pc, sdb_strbuf_t *errbuf)
102 {
103 if ((pc->obj_type != SDB_ATTRIBUTE)
104 && (! VALID_OBJ_TYPE(pc->obj_type))) {
105 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
106 "in %s command", pc->obj_type, cmd);
107 return -1;
108 }
109 if (! pc->name) {
110 sdb_strbuf_sprintf(errbuf, "Missing object name in "
111 "%s %s command", cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
112 return -1;
113 }
115 if ((pc->obj_type == SDB_HOST) && pc->hostname) {
116 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
117 "in %s HOST command", pc->hostname, cmd);
118 return -1;
119 }
120 else if ((pc->obj_type != SDB_HOST) && (! pc->hostname)) {
121 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
122 "in %s %s command", pc->name,
123 cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
124 return -1;
125 }
127 if (pc->obj_type == SDB_ATTRIBUTE) {
128 if ((pc->parent_type <= 0) && pc->parent) {
129 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
130 "in %s %s command", pc->parent,
131 cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
132 return -1;
133 }
134 else if (pc->parent_type > 0) {
135 if (! VALID_OBJ_TYPE(pc->parent_type)) {
136 sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
137 "in %s %s command", pc->parent_type,
138 cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
139 return -1;
140 }
141 if (! pc->parent) {
142 sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
143 "in %s %s command",
144 SDB_STORE_TYPE_TO_NAME(pc->parent_type),
145 cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
146 return -1;
147 }
148 }
149 }
150 else if ((pc->parent_type > 0) || pc->parent) {
151 sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
152 "in %s %s command",
153 SDB_STORE_TYPE_TO_NAME(pc->parent_type),
154 pc->parent ? pc->parent : "<unknown>",
155 cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type));
156 return -1;
157 }
158 return 0;
159 } /* analyze_parent_child */
161 /*
162 * expression nodes
163 */
165 static int
166 analyze_logical(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
167 {
168 if (ctx.iter) {
169 op_error(errbuf, op, "cannot evaluate in iterator context");
170 return -1;
171 }
173 switch (op->kind) {
174 case SDB_AST_OR:
175 case SDB_AST_AND:
176 if (! SDB_AST_IS_LOGICAL(op->left)) {
177 sdb_strbuf_sprintf(errbuf, "Invalid left operand (%s) "
178 "in %s expression", SDB_AST_TYPE_TO_STRING(op->left),
179 SDB_AST_OP_TO_STRING(op->kind));
180 return -1;
181 }
182 if (analyze_node(ctx, op->left, errbuf))
183 return -1;
184 /* fallthrough */
185 case SDB_AST_NOT:
186 if (! SDB_AST_IS_LOGICAL(op->right)) {
187 sdb_strbuf_sprintf(errbuf, "Invalid right operand (%s) "
188 "in %s expression", SDB_AST_TYPE_TO_STRING(op->right),
189 SDB_AST_OP_TO_STRING(op->kind));
190 return -1;
191 }
192 if (analyze_node(ctx, op->right, errbuf))
193 return -1;
194 break;
196 case SDB_AST_LT:
197 case SDB_AST_LE:
198 case SDB_AST_EQ:
199 case SDB_AST_NE:
200 case SDB_AST_GE:
201 case SDB_AST_GT:
202 {
203 if (analyze_node(ctx, op->left, errbuf))
204 return -1;
205 if (analyze_node(ctx, op->right, errbuf))
206 return -1;
208 if ((op->left->data_type > 0) && (op->right->data_type > 0)) {
209 if (op->left->data_type == op->right->data_type)
210 return 0;
211 op_error(errbuf, op, "type mismatch");
212 return -1;
213 }
214 if ((op->left->data_type > 0) && (op->left->data_type & SDB_TYPE_ARRAY)) {
215 op_error(errbuf, op, "array not allowed");
216 return -1;
217 }
218 if ((op->right->data_type > 0) && (op->right->data_type & SDB_TYPE_ARRAY)) {
219 op_error(errbuf, op, "array not allowed");
220 return -1;
221 }
222 break;
223 }
225 case SDB_AST_REGEX:
226 case SDB_AST_NREGEX:
227 if (analyze_node(ctx, op->left, errbuf))
228 return -1;
229 if (analyze_node(ctx, op->right, errbuf))
230 return -1;
232 /* all types are supported for the left operand
233 * TODO: introduce a cast operator if it's not a string */
234 if ((op->right->data_type > 0)
235 && (op->right->data_type != SDB_TYPE_REGEX)
236 && (op->right->data_type != SDB_TYPE_STRING)) {
237 op_error(errbuf, op, "invalid regex");
238 return -1;
239 }
240 break;
242 case SDB_AST_ISNULL:
243 case SDB_AST_ISTRUE:
244 case SDB_AST_ISFALSE:
245 if (analyze_node(ctx, op->right, errbuf))
246 return -1;
247 break;
249 case SDB_AST_IN:
250 if (analyze_node(ctx, op->left, errbuf))
251 return -1;
252 if (analyze_node(ctx, op->right, errbuf))
253 return -1;
255 if ((op->right->data_type > 0) && (! (op->right->data_type & SDB_TYPE_ARRAY))) {
256 op_error(errbuf, op, "array expected");
257 return -1;
258 }
259 /* the left operand may be a scalar or an array but the element
260 * type has to match */
261 if ((op->left->data_type > 0) && (op->right->data_type > 0)
262 && ((op->left->data_type & 0xff) != (op->right->data_type & 0xff))) {
263 op_error(errbuf, op, "type mismatch");
264 return -1;
265 }
266 break;
268 default:
269 sdb_strbuf_sprintf(errbuf, "Unknown operand type %d", op->kind);
270 return -1;
271 }
272 return 0;
273 } /* analyze_logical */
275 static int
276 analyze_arith(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
277 {
278 if (analyze_node(ctx, op->left, errbuf))
279 return -1;
280 if (analyze_node(ctx, op->right, errbuf))
281 return -1;
282 SDB_AST_NODE(op)->data_type = sdb_data_expr_type(SDB_AST_OP_TO_DATA_OP(op->kind),
283 op->left->data_type, op->right->data_type);
285 if ((op->left->data_type > 0) && (op->right->data_type > 0)
286 && (SDB_AST_NODE(op)->data_type <= 0)) {
287 op_error(errbuf, op, "type mismatch");
288 return -1;
289 }
291 /* TODO: replace constant arithmetic operations with a constant value */
292 return 0;
293 } /* analyze_arith */
295 static int
296 analyze_iter(context_t ctx, sdb_ast_iter_t *iter, sdb_strbuf_t *errbuf)
297 {
298 sdb_ast_const_t c = SDB_AST_CONST_INIT;
299 context_t iter_ctx = ctx;
300 int status;
302 if (ctx.iter) {
303 iter_error(errbuf, iter, "nested iterators are not supported");
304 return -1;
305 }
307 iter_ctx.iter = 1;
308 if (analyze_node(iter_ctx, iter->iter, errbuf))
309 return -1;
311 if (iter->iter->data_type > 0) {
312 if (! (iter->iter->data_type & SDB_TYPE_ARRAY)) {
313 iter_error(errbuf, iter, "cannot iterate values of type %s",
314 SDB_TYPE_TO_STRING(iter->iter->data_type));
315 return -1;
316 }
317 c.value.type = iter->iter->data_type & 0xff;
318 }
320 /* TODO: support other setups as well */
321 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
322 && (! SDB_AST_OP(iter->expr)->left));
324 SDB_AST_OP(iter->expr)->left = SDB_AST_NODE(&c);
325 status = analyze_node(ctx, iter->expr, errbuf);
326 SDB_AST_OP(iter->expr)->left = NULL;
327 if (status)
328 return -1;
329 return 0;
330 } /* analyze_iter */
332 static int
333 analyze_const(context_t __attribute__((unused)) ctx, sdb_ast_const_t *c,
334 sdb_strbuf_t __attribute__((unused)) *errbuf)
335 {
336 SDB_AST_NODE(c)->data_type = c->value.type;
337 return 0;
338 } /* analyze_const */
340 static int
341 analyze_value(context_t ctx, sdb_ast_value_t *v, sdb_strbuf_t *errbuf)
342 {
343 if (v->type != SDB_ATTRIBUTE)
344 SDB_AST_NODE(v)->data_type = SDB_FIELD_TYPE(v->type);
346 if ((v->type != SDB_ATTRIBUTE) && v->name) {
347 sdb_strbuf_sprintf(errbuf, "Invalid expression %s[%s]",
348 SDB_FIELD_TO_NAME(v->type), v->name);
349 return -1;
350 }
351 else if ((v->type == SDB_ATTRIBUTE) && (! v->name)) {
352 sdb_strbuf_sprintf(errbuf, "Invalid expression attribute[] "
353 "(missing name)");
354 return -1;
355 }
357 /* this would be caught by the type check in analyze_iter but we're able
358 * to provide a more specific error message here */
359 if (ctx.iter && (v->type != SDB_FIELD_BACKEND)) {
360 /* only backend values are iterable */
361 char value_str[64 + (v->name ? strlen(v->name) : 0)];
362 if (v->type == SDB_ATTRIBUTE)
363 snprintf(value_str, sizeof(value_str), "attribute[%s]", v->name);
364 else
365 snprintf(value_str, sizeof(value_str), "'%s'", SDB_FIELD_TO_NAME(v->type));
366 sdb_strbuf_sprintf(errbuf, "Cannot iterate %s (scalar value)", value_str);
367 return -1;
368 }
370 if ((ctx.type != SDB_ATTRIBUTE) && (v->type == SDB_FIELD_VALUE)) {
371 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.value",
372 SDB_FIELD_TO_NAME(ctx.type));
373 return -1;
374 }
375 if ((ctx.type != SDB_METRIC) && (v->type == SDB_FIELD_TIMESERIES)) {
376 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.timeseries",
377 SDB_FIELD_TO_NAME(ctx.type));
378 return -1;
379 }
380 return 0;
381 } /* analyze_value */
383 static int
384 analyze_typed(context_t ctx, sdb_ast_typed_t *t, sdb_strbuf_t *errbuf)
385 {
386 context_t child_ctx = ctx;
387 bool needs_iter = 0;
388 bool valid = 1;
390 if ((t->expr->type != SDB_AST_TYPE_VALUE)
391 && (t->expr->type != SDB_AST_TYPE_TYPED)) {
392 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s",
393 SDB_STORE_TYPE_TO_NAME(t->type),
394 SDB_AST_TYPE_TO_STRING(t->expr));
395 return -1;
396 }
397 if ((t->type != SDB_ATTRIBUTE) && (! VALID_OBJ_TYPE(t->type))) {
398 sdb_strbuf_sprintf(errbuf, "Invalid expression %#x.%s",
399 t->type, SDB_AST_TYPE_TO_STRING(t->expr));
400 return -1;
401 }
403 if (ctx.type > 0) {
404 if ((ctx.type == t->type)
405 || ((t->type == SDB_HOST) && (ctx.type != SDB_ATTRIBUTE))) {
406 /* self-references and references to the parent host are always fine */
407 }
408 else if (t->type == SDB_ATTRIBUTE) {
409 /* references to attributes are always fine */
410 needs_iter = 1;
411 }
412 else if ((ctx.type == SDB_HOST)
413 && ((t->type == SDB_SERVICE) || (t->type == SDB_METRIC))) {
414 /* only hosts may reference services and metrics */
415 needs_iter = 1;
416 }
417 else {
418 valid = 0;
419 }
420 }
421 else if (ctx.type == FILTER_CONTEXT) {
422 if (t->type == SDB_ATTRIBUTE) {
423 /* all objects have attributes */
424 needs_iter = 1;
425 }
426 else if ((t->type == SDB_SERVICE) || (t->type == SDB_METRIC)) {
427 /* these will be iterators for *some* operations;
428 * better forbid this altogether */
429 valid = 0;
430 }
431 }
433 if (needs_iter) {
434 if (! ctx.iter)
435 valid = 0;
436 else
437 child_ctx.iter = 0;
438 } /* else: push ctx.iter down to the child node */
440 if (! valid) {
441 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s in %s context",
442 SDB_STORE_TYPE_TO_NAME(t->type),
443 SDB_AST_TYPE_TO_STRING(t->expr),
444 SDB_STORE_TYPE_TO_NAME(ctx.type));
445 return -1;
446 }
448 child_ctx.type = t->type;
449 if (analyze_node(child_ctx, t->expr, errbuf))
450 return -1;
451 SDB_AST_NODE(t)->data_type = t->expr->data_type;
453 if (needs_iter && (SDB_AST_NODE(t)->data_type > 0)) {
454 if (SDB_AST_NODE(t)->data_type & SDB_TYPE_ARRAY) {
455 sdb_strbuf_sprintf(errbuf, "Cannot access array inside iterator");
456 return -1;
457 }
458 /* Tell the caller that we're accessing an iterator. */
459 SDB_AST_NODE(t)->data_type |= SDB_TYPE_ARRAY;
460 }
461 return 0;
462 } /* analyze_typed */
464 static int
465 analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
466 {
467 if (! node) {
468 sdb_strbuf_sprintf(errbuf, "Empty AST node");
469 return -1;
470 }
472 /* unknown by default */
473 node->data_type = -1;
475 if ((node->type == SDB_AST_TYPE_OPERATOR)
476 && (SDB_AST_IS_LOGICAL(node)))
477 return analyze_logical(ctx, SDB_AST_OP(node), errbuf);
478 else if ((node->type == SDB_AST_TYPE_OPERATOR)
479 && (SDB_AST_IS_ARITHMETIC(node)))
480 return analyze_arith(ctx, SDB_AST_OP(node), errbuf);
481 else if (node->type == SDB_AST_TYPE_ITERATOR)
482 return analyze_iter(ctx, SDB_AST_ITER(node), errbuf);
483 else if (node->type == SDB_AST_TYPE_CONST)
484 return analyze_const(ctx, SDB_AST_CONST(node), errbuf);
485 else if (node->type == SDB_AST_TYPE_VALUE)
486 return analyze_value(ctx, SDB_AST_VALUE(node), errbuf);
487 else if (node->type == SDB_AST_TYPE_TYPED)
488 return analyze_typed(ctx, SDB_AST_TYPED(node), errbuf);
490 sdb_strbuf_sprintf(errbuf, "Invalid expression node "
491 "of type %#x", node->type);
492 return -1;
493 } /* analyze_node */
495 /*
496 * top level / command nodes
497 */
499 static int
500 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
501 {
502 parent_child_t pc = {
503 fetch->obj_type, fetch->hostname,
504 fetch->parent_type, fetch->parent, fetch->name,
505 };
507 if (analyze_parent_child("FETCH", &pc, errbuf))
508 return -1;
510 if (fetch->filter)
511 return analyze_node(FILTER_CTX, fetch->filter, errbuf);
512 return 0;
513 } /* analyze_fetch */
515 static int
516 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
517 {
518 if (! VALID_OBJ_TYPE(list->obj_type)) {
519 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
520 "in LIST command", list->obj_type);
521 return -1;
522 }
523 if (list->filter)
524 return analyze_node(FILTER_CTX, list->filter, errbuf);
525 return 0;
526 } /* analyze_list */
528 static int
529 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
530 {
531 if (! VALID_OBJ_TYPE(lookup->obj_type)) {
532 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
533 "in LOOKUP command", lookup->obj_type);
534 return -1;
535 }
536 if (lookup->matcher) {
537 context_t ctx = { lookup->obj_type, 0 };
538 if (analyze_node(ctx, lookup->matcher, errbuf))
539 return -1;
540 }
541 if (lookup->filter)
542 return analyze_node(FILTER_CTX, lookup->filter, errbuf);
543 return 0;
544 } /* analyze_lookup */
546 static int
547 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
548 {
549 parent_child_t pc = {
550 st->obj_type, st->hostname,
551 st->parent_type, st->parent, st->name,
552 };
554 if (analyze_parent_child("STORE", &pc, errbuf))
555 return -1;
557 if (st->obj_type == SDB_METRIC) {
558 if ((! st->store_type) != (! st->store_id)) {
559 sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
560 "in STORE METRIC command",
561 st->store_type ? st->store_type : "<unknown>",
562 st->store_id ? st->store_id : "<unknown>");
563 return -1;
564 }
565 }
566 else if (st->store_type || st->store_id) {
567 sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
568 "in STORE %s command",
569 st->store_type ? st->store_type : "<unknown>",
570 st->store_id ? st->store_id : "<unknown>",
571 SDB_STORE_TYPE_TO_NAME(st->obj_type));
572 return -1;
573 }
575 if ((! (st->obj_type == SDB_ATTRIBUTE))
576 && (st->value.type != SDB_TYPE_NULL)) {
577 char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
578 sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
579 sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
580 v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
581 return -1;
582 }
583 return 0;
584 } /* analyze_store */
586 static int
587 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
588 {
589 if (! ts->hostname) {
590 sdb_strbuf_sprintf(errbuf, "Missing hostname in TIMESERIES command");
591 return -1;
592 }
593 if (! ts->metric) {
594 sdb_strbuf_sprintf(errbuf, "Missing metric name in TIMESERIES command");
595 return -1;
596 }
597 if (ts->end <= ts->start) {
598 char start_str[64], end_str[64];
599 sdb_strftime(start_str, sizeof(start_str), ts->start);
600 sdb_strftime(end_str, sizeof(end_str), ts->end);
601 sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
602 "end time (%s) in TIMESERIES command", start_str, end_str);
603 return -1;
604 }
605 return 0;
606 } /* analyze_timeseries */
608 /*
609 * public API
610 */
612 int
613 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
614 {
615 if (! node) {
616 sdb_strbuf_sprintf(errbuf, "Empty AST node");
617 return -1;
618 }
620 /* top-level nodes don't have a type */
621 node->data_type = -1;
623 if (node->type == SDB_AST_TYPE_FETCH)
624 return analyze_fetch(SDB_AST_FETCH(node), errbuf);
625 else if (node->type == SDB_AST_TYPE_LIST)
626 return analyze_list(SDB_AST_LIST(node), errbuf);
627 else if (node->type == SDB_AST_TYPE_LOOKUP)
628 return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
629 else if (node->type == SDB_AST_TYPE_STORE)
630 return analyze_store(SDB_AST_STORE(node), errbuf);
631 else if (node->type == SDB_AST_TYPE_TIMESERIES)
632 return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
634 sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
635 "of type %#x", node->type);
636 return -1;
637 } /* sdb_parser_analyze */
639 int
640 sdb_parser_analyze_conditional(int context,
641 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
642 {
643 context_t ctx = { context, 0 };
644 if (! VALID_OBJ_TYPE(context)) {
645 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
646 return -1;
647 }
648 if (! node) {
649 sdb_strbuf_sprintf(errbuf, "Empty conditional node");
650 return -1;
651 }
652 if (! SDB_AST_IS_LOGICAL(node)) {
653 sdb_strbuf_sprintf(errbuf, "Not a conditional node (got %s)",
654 SDB_AST_TYPE_TO_STRING(node));
655 return -1;
656 }
657 return analyze_node(ctx, node, errbuf);
658 } /* sdb_parser_analyze_conditional */
660 int
661 sdb_parser_analyze_arith(int context,
662 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
663 {
664 context_t ctx = { context, 0 };
665 if (! VALID_OBJ_TYPE(context)) {
666 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
667 return -1;
668 }
669 if (! node) {
670 sdb_strbuf_sprintf(errbuf, "Empty arithmetic node");
671 return -1;
672 }
673 if (! SDB_AST_IS_ARITHMETIC(node)) {
674 sdb_strbuf_sprintf(errbuf, "Not an arithmetic node (got %s)",
675 SDB_AST_TYPE_TO_STRING(node));
676 return -1;
677 }
678 return analyze_node(ctx, node, errbuf);
679 } /* sdb_parser_analyze_arith */
681 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */