summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ffd344c)
raw | patch | inline | side by side (parent: ffd344c)
author | Sebastian Harl <sh@tokkee.org> | |
Mon, 27 Oct 2014 23:08:07 +0000 (00:08 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Mon, 27 Oct 2014 23:11:33 +0000 (00:11 +0100) |
For now, the analyzer checks the types of all matcher operands.
src/Makefile.am | patch | blob | history | |
src/frontend/analyzer.c | [new file with mode: 0644] | patch | blob |
src/frontend/query.c | patch | blob | history | |
src/include/frontend/parser.h | patch | blob | history |
diff --git a/src/Makefile.am b/src/Makefile.am
index a69769d72dd21f159fea34daee3b6d540cae1bb3..c8ad524c12f6809cd01f7b37b7bac6f1df7128ab 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
core/store_lookup.c \
core/data.c include/core/data.h \
core/timeseries.c include/core/timeseries.h \
+ frontend/analyzer.c \
frontend/connection.c include/frontend/connection.h \
frontend/connection-private.h \
frontend/parser.c include/frontend/parser.h \
diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c
--- /dev/null
+++ b/src/frontend/analyzer.c
@@ -0,0 +1,176 @@
+/*
+ * SysDB - src/frontend/analyzer.c
+ * Copyright (C) 2014 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 <core/store-private.h>
+#include <frontend/connection-private.h>
+#include <frontend/parser.h>
+
+#include <assert.h>
+
+/*
+ * private helper functions
+ */
+
+static int
+analyze_matcher(int context, sdb_store_matcher_t *m)
+{
+ int status = 0;
+
+ if (! m)
+ return 0;
+
+ switch (m->type) {
+ case MATCHER_OR:
+ case MATCHER_AND:
+ assert(OP_M(m)->left && OP_M(m)->right);
+ if (analyze_matcher(context, OP_M(m)->left))
+ status = -1;
+ if (analyze_matcher(context, OP_M(m)->right))
+ status = -1;
+ break;
+
+ case MATCHER_NOT:
+ assert(UOP_M(m)->op);
+ if (analyze_matcher(context, UOP_M(m)->op))
+ status = -1;
+ break;
+
+ case MATCHER_ANY:
+ case MATCHER_ALL:
+ assert(ITER_M(m)->m);
+ if (ITER_M(m)->type == context)
+ status = -1;
+ if ((context != SDB_HOST)
+ && (context != SDB_SERVICE)
+ && (context != SDB_METRIC))
+ status = -1;
+ if ((ITER_M(m)->type != SDB_SERVICE)
+ && (ITER_M(m)->type != SDB_METRIC)
+ && (ITER_M(m)->type != SDB_ATTRIBUTE))
+ status = -1;
+ if ((context == SDB_SERVICE)
+ && (ITER_M(m)->type == SDB_METRIC))
+ status = -1;
+ else if ((context == SDB_METRIC)
+ && (ITER_M(m)->type == SDB_SERVICE))
+ status = -1;
+ if (analyze_matcher(ITER_M(m)->type, ITER_M(m)->m))
+ status = -1;
+ break;
+
+ case MATCHER_LT:
+ case MATCHER_LE:
+ case MATCHER_EQ:
+ case MATCHER_NE:
+ case MATCHER_GE:
+ case MATCHER_GT:
+ assert(CMP_M(m)->left && CMP_M(m)->right);
+ if ((CMP_M(m)->left->data_type > 0)
+ && (CMP_M(m)->left->data_type & SDB_TYPE_ARRAY))
+ status = -1;
+ if ((CMP_M(m)->right->data_type > 0)
+ && (CMP_M(m)->right->data_type & SDB_TYPE_ARRAY))
+ status = -1;
+ break;
+
+ case MATCHER_IN:
+ if ((CMP_M(m)->left->data_type > 0)
+ && (CMP_M(m)->left->data_type & SDB_TYPE_ARRAY))
+ status = -1;
+ if ((CMP_M(m)->right->data_type > 0)
+ && (! (CMP_M(m)->right->data_type & SDB_TYPE_ARRAY)))
+ status = -1;
+ break;
+
+ case MATCHER_REGEX:
+ case MATCHER_NREGEX:
+ /* all types are supported for the left operand */
+ if ((CMP_M(m)->right->data_type > 0)
+ && (CMP_M(m)->right->data_type != SDB_TYPE_REGEX)
+ && (CMP_M(m)->right->data_type != SDB_TYPE_STRING))
+ status = -1;
+ break;
+
+ case MATCHER_ISNULL:
+ case MATCHER_ISNNULL:
+ break;
+
+ default:
+ return -1;
+ }
+ return status;
+} /* analyze_matcher */
+
+/*
+ * public API
+ */
+
+int
+sdb_fe_analyze(sdb_conn_node_t *node)
+{
+ sdb_store_matcher_t *m = NULL, *filter = NULL;
+ int context = -1;
+ int status = 0;
+
+ if (! node)
+ return -1;
+
+ /* For now, this function checks basic matcher attributes only;
+ * later, this may be turned into one of multiple AST visitors. */
+ if (node->cmd == CONNECTION_FETCH) {
+ if (CONN_FETCH(node)->filter)
+ filter = CONN_FETCH(node)->filter->matcher;
+ context = CONN_FETCH(node)->type;
+ }
+ else if (node->cmd == CONNECTION_LIST) {
+ if (CONN_LIST(node)->filter)
+ filter = CONN_LIST(node)->filter->matcher;
+ context = CONN_LIST(node)->type;
+ }
+ else if (node->cmd == CONNECTION_LOOKUP) {
+ if (CONN_LOOKUP(node)->matcher)
+ m = CONN_LOOKUP(node)->matcher->matcher;
+ if (CONN_LOOKUP(node)->filter)
+ filter = CONN_LOOKUP(node)->filter->matcher;
+ context = CONN_LOOKUP(node)->type;
+ }
+ else if (node->cmd == CONNECTION_TIMESERIES)
+ return 0;
+ else
+ return -1;
+
+ if (analyze_matcher(context, m))
+ status = -1;
+ if (analyze_matcher(-1, filter))
+ status = -1;
+ return status;
+} /* sdb_fe_analyze */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/frontend/query.c b/src/frontend/query.c
index 39b5d53004da6774ad6395ade472e22cc33971b7..d6bd76a95ebb3c23ba06c291f324215233801ff2 100644 (file)
--- a/src/frontend/query.c
+++ b/src/frontend/query.c
}
if (node) {
- status = sdb_fe_exec(conn, node);
+ if (sdb_fe_analyze(node)) {
+ char query[conn->cmd_len + 1];
+ strncpy(query, sdb_strbuf_string(conn->buf), conn->cmd_len);
+ query[sizeof(query) - 1] = '\0';
+ sdb_log(SDB_LOG_ERR, "frontend: Failed to verify query '%s'",
+ query);
+ status = -1;
+ }
+ else
+ status = sdb_fe_exec(conn, node);
sdb_object_deref(SDB_OBJ(node));
}
uint32_t type;
int status;
+ conn_matcher_t m_node = {
+ { SDB_OBJECT_INIT, CONNECTION_MATCHER }, NULL
+ };
+ conn_lookup_t node = {
+ { SDB_OBJECT_INIT, CONNECTION_LOOKUP },
+ -1, &m_node, NULL
+ };
+
if ((! conn) || (conn->cmd != CONNECTION_LOOKUP))
return -1;
return -1;
}
- status = sdb_fe_exec_lookup(conn, type, m, /* filter = */ NULL);
+ node.type = type;
+ m_node.matcher = m;
+
+ if (sdb_fe_analyze(SDB_CONN_NODE(&node))) {
+ char expr[matcher_len + 1];
+ strncpy(expr, matcher, sizeof(expr));
+ expr[sizeof(expr) - 1] = '\0';
+ sdb_log(SDB_LOG_ERR, "frontend: Failed to verify "
+ "lookup condition '%s'", expr);
+ status = -1;
+ }
+ else
+ status = sdb_fe_exec_lookup(conn, type, m, /* filter = */ NULL);
sdb_object_deref(SDB_OBJ(m));
return status;
} /* sdb_fe_lookup */
index d78ab20bade0e726e769fc595ec9c7bc0599306d..e1c9c6fa81e5d3b4e2b6eef91d14b8ed0fc3b3f9 100644 (file)
#define SDB_FRONTEND_PARSER_H 1
#include "core/store.h"
+#include "frontend/connection.h"
#include "utils/llist.h"
#ifdef __cplusplus
sdb_store_expr_t *
sdb_fe_parse_expr(const char *expr, int len);
+/*
+ * sdb_fe_analyze:
+ * Analyze a parsed node, checking for semantical errors.
+ *
+ * Returns:
+ * - 0 if the node is semantically correct
+ * - a negative value else
+ */
+int
+sdb_fe_analyze(sdb_conn_node_t *node);
+
#ifdef __cplusplus
} /* extern "C" */
#endif