summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a1f741f)
raw | patch | inline | side by side (parent: a1f741f)
author | Sebastian Harl <sh@tokkee.org> | |
Wed, 15 Apr 2015 09:38:26 +0000 (11:38 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Wed, 15 Apr 2015 09:38:26 +0000 (11:38 +0200) |
Call the analyzer from sdb_parser_parse().
src/Makefile.am | patch | blob | history | |
src/include/parser/parser.h | patch | blob | history | |
src/parser/analyzer.c | [new file with mode: 0644] | patch | blob |
src/parser/parser.c | patch | blob | history |
diff --git a/src/Makefile.am b/src/Makefile.am
index 5a3146af6f15a8037ddccd076ef006517f753356..ed81316a6e727dab7a482aca0f7fee46f4ba6561 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
frontend/session.c \
frontend/store.c \
frontend/query.c \
+ parser/analyzer.c \
parser/ast.c include/parser/ast.h \
parser/parser.c include/parser/parser.h \
utils/avltree.c include/utils/avltree.h \
index 9235ef5820267789cdb77005a6db04dafd602334..0a7c7206d24a156bb1706003641fadc217076f84 100644 (file)
sdb_ast_node_t *
sdb_parser_parse_arith(const char *expr, int len, sdb_strbuf_t *errbuf);
+/*
+ * sdb_parser_analyze:
+ * Semantical analysis of a parse-tree.
+ *
+ * Returns:
+ * - 0 on success
+ * - a negative value else; an error message will be written to the provided
+ * error buffer
+ */
+int
+sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
+
/*
* Low-level interface.
*/
diff --git a/src/parser/analyzer.c b/src/parser/analyzer.c
--- /dev/null
+++ b/src/parser/analyzer.c
@@ -0,0 +1,257 @@
+/*
+ * SysDB - src/parser/analyzer.c
+ * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysdb.h"
+
+#include "parser/ast.h"
+#include "parser/parser.h"
+#include "utils/error.h"
+#include "utils/strbuf.h"
+
+#include <assert.h>
+
+#define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
+
+/*
+ * private helper functions
+ */
+
+static int
+analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
+{
+ (void)context;
+ if (! node) {
+ sdb_strbuf_sprintf(errbuf, "Empty AST node");
+ return -1;
+ }
+ return 0;
+} /* analyze_node */
+
+/*
+ * top level / command nodes
+ */
+
+static int
+analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
+{
+ if (! VALID_OBJ_TYPE(fetch->obj_type)) {
+ sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
+ "in FETCH command", fetch->obj_type);
+ return -1;
+ }
+ if (! fetch->name) {
+ sdb_strbuf_sprintf(errbuf, "Missing object name in "
+ "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
+ return -1;
+ }
+
+ if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
+ sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
+ "in FETCH HOST command", fetch->hostname);
+ return -1;
+ }
+ else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
+ sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
+ "in FETCH %s command", fetch->name,
+ SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
+ return -1;
+ }
+
+ if (fetch->filter)
+ return analyze_node(-1, fetch->filter, errbuf);
+ return 0;
+}
+
+static int
+analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
+{
+ if (! VALID_OBJ_TYPE(list->obj_type)) {
+ sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
+ "in LIST command", list->obj_type);
+ return -1;
+ }
+ if (list->filter)
+ return analyze_node(-1, list->filter, errbuf);
+ return 0;
+}
+
+static int
+analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
+{
+ if (! VALID_OBJ_TYPE(lookup->obj_type)) {
+ sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
+ "in LOOKUP command", lookup->obj_type);
+ return -1;
+ }
+ if (lookup->matcher)
+ if (analyze_node(lookup->obj_type, lookup->matcher, errbuf))
+ return -1;
+ if (lookup->filter)
+ return analyze_node(-1, lookup->filter, errbuf);
+ return 0;
+}
+
+static int
+analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
+{
+ if ((st->obj_type != SDB_ATTRIBUTE)
+ && (! VALID_OBJ_TYPE(st->obj_type))) {
+ sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
+ "in STORE command", st->obj_type);
+ return -1;
+ }
+ if (! st->name) {
+ sdb_strbuf_sprintf(errbuf, "Missing object name in "
+ "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+
+ if ((st->obj_type == SDB_HOST) && st->hostname) {
+ sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
+ "in STORE HOST command", st->hostname);
+ return -1;
+ }
+ else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
+ sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
+ "in STORE %s command", st->name,
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+
+ if (st->obj_type == SDB_ATTRIBUTE) {
+ if ((st->parent_type <= 0) && st->parent) {
+ sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
+ "in STORE %s command", st->parent,
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+ else if (st->parent_type > 0) {
+ if (! VALID_OBJ_TYPE(st->parent_type)) {
+ sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
+ "in STORE %s command", st->parent_type,
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+ if (! st->parent) {
+ sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
+ "in STORE %s command",
+ SDB_STORE_TYPE_TO_NAME(st->parent_type),
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+ }
+ }
+ else if ((st->parent_type > 0) || st->parent) {
+ sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
+ "in STORE %s command",
+ SDB_STORE_TYPE_TO_NAME(st->parent_type),
+ st->parent ? st->parent : "<unknown>",
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+
+ if (st->obj_type == SDB_METRIC) {
+ if ((! st->store_type) != (! st->store_id)) {
+ sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
+ "in STORE METRIC command",
+ st->store_type ? st->store_type : "<unknown>",
+ st->store_id ? st->store_id : "<unknown>");
+ return -1;
+ }
+ }
+ else if (st->store_type || st->store_id) {
+ sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
+ "in STORE %s command",
+ st->store_type ? st->store_type : "<unknown>",
+ st->store_id ? st->store_id : "<unknown>",
+ SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+
+ if ((! (st->obj_type == SDB_ATTRIBUTE))
+ && (st->value.type != SDB_TYPE_NULL)) {
+ char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
+ sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
+ sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
+ v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
+{
+ if (! ts->hostname) {
+ sdb_strbuf_sprintf(errbuf, "Missing hostname in STORE command");
+ return -1;
+ }
+ if (! ts->metric) {
+ sdb_strbuf_sprintf(errbuf, "Missing metric name in STORE command");
+ return -1;
+ }
+ if (ts->end <= ts->start) {
+ char start_str[64], end_str[64];
+ sdb_strftime(start_str, sizeof(start_str), "%F %T Tz", ts->start);
+ sdb_strftime(end_str, sizeof(end_str), "%F %T Tz", ts->end);
+ sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
+ "end time (%s) in STORE command", start_str, end_str);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * public API
+ */
+
+int
+sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
+{
+ if (! node) {
+ sdb_strbuf_sprintf(errbuf, "Empty AST node");
+ return -1;
+ }
+
+ if (node->type == SDB_AST_TYPE_FETCH)
+ return analyze_fetch(SDB_AST_FETCH(node), errbuf);
+ else if (node->type == SDB_AST_TYPE_LIST)
+ return analyze_list(SDB_AST_LIST(node), errbuf);
+ else if (node->type == SDB_AST_TYPE_LOOKUP)
+ return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
+ else if (node->type == SDB_AST_TYPE_STORE)
+ return analyze_store(SDB_AST_STORE(node), errbuf);
+ else if (node->type == SDB_AST_TYPE_TIMESERIES)
+ return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
+
+ sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
+ "of type %#x", node->type);
+ return -1;
+} /* sdb_fe_analyze */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/parser/parser.c b/src/parser/parser.c
index d22ce5f3116ee4fc51fe35468b1c8be3911e2e51..de6085fd176b7ae346b9f61d71369d8d3b2d5750 100644 (file)
--- a/src/parser/parser.c
+++ b/src/parser/parser.c
iter = sdb_llist_get_iter(yyextra.parsetree);
while (sdb_llist_iter_has_next(iter)) {
- sdb_conn_node_t *node;
- node = SDB_CONN_NODE(sdb_llist_iter_get_next(iter));
- assert(node);
- /* TODO
- if (sdb_parser_analyze(node, errbuf)) {
+ sdb_ast_node_t *node;
+ node = SDB_AST_NODE(sdb_llist_iter_get_next(iter));
+ if (sdb_parser_analyze(node, errbuf) < 0) {
sdb_llist_iter_destroy(iter);
sdb_llist_destroy(yyextra.parsetree);
return NULL;
}
- */
}
sdb_llist_iter_destroy(iter);
return yyextra.parsetree;