summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2a5aff7)
raw | patch | inline | side by side (parent: 2a5aff7)
author | Sebastian Harl <sh@tokkee.org> | |
Fri, 15 May 2015 08:03:47 +0000 (10:03 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Fri, 15 May 2015 08:03:47 +0000 (10:03 +0200) |
This function prepares a query, represented by its AST, for execution in a
store by generating a store matcher.
store by generating a store matcher.
src/Makefile.am | patch | blob | history | |
src/core/store-private.h | patch | blob | history | |
src/core/store_lookup.c | patch | blob | history | |
src/core/store_query.c | [new file with mode: 0644] | patch | blob |
src/include/core/store.h | patch | blob | history | |
t/unit/parser/parser_test.c | patch | blob | history |
diff --git a/src/Makefile.am b/src/Makefile.am
index ed81316a6e727dab7a482aca0f7fee46f4ba6561..6b560df7b8b2bc6c56d6615c7b7e516dc8129fd2 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
core/store_expr.c \
core/store_json.c \
core/store_lookup.c \
+ core/store_query.c \
core/data.c include/core/data.h \
core/time.c include/core/time.h \
core/timeseries.c include/core/timeseries.h \
index 874dc0577a9fe030e64fa7d59b1cfb2c4ac5d709..060ec7bccf02c7b19acfccc7a6d29b5058986c01 100644 (file)
--- a/src/core/store-private.h
+++ b/src/core/store-private.h
MATCHER_GT,
MATCHER_REGEX,
MATCHER_NREGEX,
+
+ /* a generic query */
+ MATCHER_QUERY,
};
#define MATCHER_SYM(t) \
: ((t) == MATCHER_GT) ? ">" \
: ((t) == MATCHER_REGEX) ? "=~" \
: ((t) == MATCHER_NREGEX) ? "!~" \
+ : ((t) == MATCHER_QUERY) ? "QUERY" \
: "UNKNOWN")
/* matcher base type */
} isnull_matcher_t;
#define ISNULL_M(m) ((isnull_matcher_t *)(m))
+typedef struct {
+ sdb_store_matcher_t super;
+ sdb_ast_node_t *ast;
+ sdb_store_matcher_t *matcher;
+ sdb_store_matcher_t *filter;
+} query_matcher_t;
+#define QUERY_M(m) ((query_matcher_t *)(m))
+
#ifdef __cplusplus
} /* extern "C" */
#endif
index 18a0235536e3f154128ff576cbc624c9dfa49a5f..4862905b3366d4fa4455a95ddc80a5bedd8ee652 100644 (file)
--- a/src/core/store_lookup.c
+++ b/src/core/store_lookup.c
match_cmp,
match_regex,
match_regex,
+
+ NULL, /* QUERY */
};
/*
if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
return 0;
+ if (! matchers[m->type])
+ return 0;
return matchers[m->type](m, obj, filter);
} /* sdb_store_matcher_matches */
diff --git a/src/core/store_query.c b/src/core/store_query.c
--- /dev/null
+++ b/src/core/store_query.c
@@ -0,0 +1,344 @@
+/*
+ * SysDB - src/core/store_lookup.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 "core/object.h"
+#include "core/store-private.h"
+#include "parser/ast.h"
+#include "utils/error.h"
+
+#include <assert.h>
+
+static sdb_store_matcher_t *
+node_to_matcher(sdb_ast_node_t *n);
+
+static sdb_store_expr_t *
+node_to_expr(sdb_ast_node_t *n)
+{
+ sdb_store_expr_t *left = NULL, *right = NULL;
+ sdb_store_expr_t *e;
+ int op;
+
+ if (! n) {
+ sdb_log(SDB_LOG_ERR, "store: Encountered empty AST expression node");
+ return NULL;
+ }
+
+ switch (n->type) {
+ case SDB_AST_TYPE_OPERATOR:
+ if (! SDB_AST_IS_ARITHMETIC(n)) {
+ sdb_log(SDB_LOG_ERR, "store: Invalid arithmetic operator of "
+ "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
+ return NULL;
+ }
+
+ left = node_to_expr(SDB_AST_OP(n)->left);
+ if (! left)
+ return NULL;
+ right = node_to_expr(SDB_AST_OP(n)->right);
+ if (! right) {
+ sdb_object_deref(SDB_OBJ(left));
+ return NULL;
+ }
+ op = SDB_AST_OP_TO_DATA_OP(SDB_AST_OP(n)->kind);
+ e = sdb_store_expr_create(op, left, right);
+ break;
+
+ case SDB_AST_TYPE_CONST:
+ return sdb_store_expr_constvalue(&SDB_AST_CONST(n)->value);
+
+ case SDB_AST_TYPE_VALUE:
+ if (SDB_AST_VALUE(n)->type == SDB_ATTRIBUTE)
+ return sdb_store_expr_attrvalue(SDB_AST_VALUE(n)->name);
+ return sdb_store_expr_fieldvalue(SDB_AST_VALUE(n)->type);
+
+ case SDB_AST_TYPE_TYPED:
+ right = node_to_expr(SDB_AST_TYPED(n)->expr);
+ if (! right)
+ return NULL;
+ e = sdb_store_expr_typed(SDB_AST_TYPED(n)->type, right);
+ break;
+
+ default:
+ sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
+ SDB_AST_TYPE_TO_STRING(n), n->type);
+ e = NULL;
+ }
+
+ /* expressions take a reference */
+ sdb_object_deref(SDB_OBJ(left));
+ sdb_object_deref(SDB_OBJ(right));
+ return e;
+} /* node_to_expr */
+
+static sdb_store_matcher_t *
+logical_to_matcher(sdb_ast_node_t *n)
+{
+ sdb_store_matcher_t *left = NULL, *right;
+ sdb_store_matcher_t *m;
+
+ if (SDB_AST_OP(n)->left) {
+ left = node_to_matcher(SDB_AST_OP(n)->left);
+ if (! left)
+ return NULL;
+ }
+ right = node_to_matcher(SDB_AST_OP(n)->right);
+ if (! right) {
+ sdb_object_deref(SDB_OBJ(left));
+ return NULL;
+ }
+
+ switch (SDB_AST_OP(n)->kind) {
+ case SDB_AST_AND:
+ m = sdb_store_con_matcher(left, right);
+ break;
+ case SDB_AST_OR:
+ m = sdb_store_dis_matcher(left, right);
+ break;
+ case SDB_AST_NOT:
+ m = sdb_store_inv_matcher(right);
+ break;
+
+ default:
+ m = NULL;
+ }
+
+ /* matchers take a reference */
+ sdb_object_deref(SDB_OBJ(left));
+ sdb_object_deref(SDB_OBJ(right));
+ return m;
+} /* logical_to_matcher */
+
+static sdb_store_matcher_t *
+cmp_to_matcher(sdb_ast_node_t *n)
+{
+ sdb_store_expr_t *left = NULL, *right;
+ sdb_store_matcher_t *m;
+
+ if (SDB_AST_OP(n)->left) {
+ left = node_to_expr(SDB_AST_OP(n)->left);
+ if (! left)
+ return NULL;
+ }
+ right = node_to_expr(SDB_AST_OP(n)->right);
+ if (! right) {
+ sdb_object_deref(SDB_OBJ(left));
+ return NULL;
+ }
+
+ switch (SDB_AST_OP(n)->kind) {
+ case SDB_AST_LT:
+ m = sdb_store_lt_matcher(left, right);
+ break;
+ case SDB_AST_LE:
+ m = sdb_store_le_matcher(left, right);
+ break;
+ case SDB_AST_EQ:
+ m = sdb_store_eq_matcher(left, right);
+ break;
+ case SDB_AST_NE:
+ m = sdb_store_ne_matcher(left, right);
+ break;
+ case SDB_AST_GE:
+ m = sdb_store_ge_matcher(left, right);
+ break;
+ case SDB_AST_GT:
+ m = sdb_store_gt_matcher(left, right);
+ break;
+ case SDB_AST_REGEX:
+ m = sdb_store_regex_matcher(left, right);
+ break;
+ case SDB_AST_NREGEX:
+ m = sdb_store_nregex_matcher(left, right);
+ break;
+ case SDB_AST_ISNULL:
+ m = sdb_store_isnull_matcher(right);
+ break;
+ case SDB_AST_IN:
+ m = sdb_store_in_matcher(left, right);
+ break;
+
+ default:
+ sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
+ SDB_AST_TYPE_TO_STRING(n), n->type);
+ m = NULL;
+ }
+
+ /* matchers take a reference */
+ sdb_object_deref(SDB_OBJ(left));
+ sdb_object_deref(SDB_OBJ(right));
+ return m;
+} /* cmp_to_matcher */
+
+static sdb_store_matcher_t *
+iter_to_matcher(sdb_ast_node_t *n)
+{
+ sdb_store_expr_t *iter;
+ sdb_store_matcher_t *expr, *m;
+
+ assert((SDB_AST_ITER(n)->expr->type == SDB_AST_TYPE_OPERATOR)
+ && (! SDB_AST_OP(SDB_AST_ITER(n)->expr)->left));
+
+ iter = node_to_expr(SDB_AST_ITER(n)->iter);
+ if (! iter)
+ return NULL;
+ expr = cmp_to_matcher(SDB_AST_ITER(n)->expr);
+ if (! expr) {
+ sdb_object_deref(SDB_OBJ(iter));
+ return NULL;
+ }
+
+ switch (SDB_AST_ITER(n)->kind) {
+ case SDB_AST_ALL:
+ m = sdb_store_all_matcher(iter, expr);
+ break;
+ case SDB_AST_ANY:
+ m = sdb_store_any_matcher(iter, expr);
+ break;
+
+ default:
+ sdb_log(SDB_LOG_ERR, "store: Invalid iterator node of type %s (%#x)",
+ SDB_AST_OP_TO_STRING(SDB_AST_ITER(n)->kind), SDB_AST_ITER(n)->kind);
+ m = NULL;
+ }
+
+ /* matchers take a reference */
+ sdb_object_deref(SDB_OBJ(iter));
+ sdb_object_deref(SDB_OBJ(expr));
+ return m;
+} /* iter_to_matcher */
+
+static sdb_store_matcher_t *
+node_to_matcher(sdb_ast_node_t *n)
+{
+ int kind;
+
+ if (! n) {
+ sdb_log(SDB_LOG_ERR, "store: Encountered empty AST matcher node");
+ return NULL;
+ }
+
+ switch (n->type) {
+ case SDB_AST_TYPE_OPERATOR:
+ if (! SDB_AST_IS_LOGICAL(n)) {
+ sdb_log(SDB_LOG_ERR, "store: Invalid logical operator of "
+ "type %s (%#x)", SDB_AST_TYPE_TO_STRING(n), n->type);
+ return NULL;
+ }
+
+ kind = SDB_AST_OP(n)->kind;
+ if ((kind == SDB_AST_AND) || (kind == SDB_AST_OR) || (kind == SDB_AST_NOT))
+ return logical_to_matcher(n);
+ else
+ return cmp_to_matcher(n);
+
+ case SDB_AST_TYPE_ITERATOR:
+ return iter_to_matcher(n);
+ }
+
+ sdb_log(SDB_LOG_ERR, "store: Invalid matcher node of type %s (%#x)",
+ SDB_AST_TYPE_TO_STRING(n), n->type);
+ return NULL;
+} /* node_to_matcher */
+
+/*
+ * matcher type
+ */
+
+static int
+query_matcher_init(sdb_object_t *obj, va_list ap)
+{
+ sdb_ast_node_t *ast = va_arg(ap, sdb_ast_node_t *);
+ sdb_ast_node_t *matcher = NULL, *filter = NULL;
+
+ M(obj)->type = MATCHER_QUERY;
+
+ QUERY_M(obj)->ast = ast;
+ sdb_object_ref(SDB_OBJ(ast));
+
+ switch (ast->type) {
+ case SDB_AST_TYPE_FETCH:
+ filter = SDB_AST_FETCH(ast)->filter;
+ break;
+ case SDB_AST_TYPE_LIST:
+ filter = SDB_AST_LIST(ast)->filter;
+ break;
+ case SDB_AST_TYPE_LOOKUP:
+ matcher = SDB_AST_LOOKUP(ast)->matcher;
+ filter = SDB_AST_LOOKUP(ast)->filter;
+ break;
+ case SDB_AST_TYPE_STORE:
+ case SDB_AST_TYPE_TIMESERIES:
+ /* nothing to do */
+ break;
+
+ default:
+ sdb_log(SDB_LOG_ERR, "store: Invalid top-level AST node "
+ "of type %#x", ast->type);
+ return -1;
+ }
+
+ if (matcher) {
+ QUERY_M(obj)->matcher = node_to_matcher(matcher);
+ if (! QUERY_M(obj)->matcher)
+ return -1;
+ }
+ if (filter) {
+ QUERY_M(obj)->filter = node_to_matcher(filter);
+ if (! QUERY_M(obj)->filter)
+ return -1;
+ }
+
+ return 0;
+} /* query_matcher_init */
+
+static void
+query_matcher_destroy(sdb_object_t *obj)
+{
+ sdb_object_deref(SDB_OBJ(QUERY_M(obj)->ast));
+ sdb_object_deref(SDB_OBJ(QUERY_M(obj)->matcher));
+ sdb_object_deref(SDB_OBJ(QUERY_M(obj)->filter));
+} /* query_matcher_destroy */
+
+static sdb_type_t query_type = {
+ /* size = */ sizeof(query_matcher_t),
+ /* init = */ query_matcher_init,
+ /* destroy = */ query_matcher_destroy,
+};
+
+/*
+ * public API
+ */
+
+sdb_store_matcher_t *
+sdb_store_query_prepare(sdb_ast_node_t *ast)
+{
+ if (! ast)
+ return NULL;
+ return M(sdb_object_create(SDB_AST_TYPE_TO_STRING(ast), query_type, ast));
+} /* sdb_store_query_prepare */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
index 94a571345852481b89479fd6664f2fc484c103b9..0abf0cb467d3d0a66fb3f99008537bce2f8848de 100644 (file)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
#include "core/data.h"
#include "core/time.h"
#include "core/timeseries.h"
+#include "parser/ast.h"
#include "utils/strbuf.h"
#include <stdbool.h>
sdb_store_get_attr(sdb_store_obj_t *obj, const char *name, sdb_data_t *res,
sdb_store_matcher_t *filter);
+/*
+ * sdb_store_query_prepare:
+ * Prepare the query described by 'ast' for execution in a store.
+ *
+ * Returns:
+ * - a store matcher on success
+ * - NULL else
+ */
+sdb_store_matcher_t *
+sdb_store_query_prepare(sdb_ast_node_t *ast);
+
/*
* sdb_store_expr_create:
* Creates an arithmetic expression implementing the specified operator on the
index cfc36fc36417610175455f3e7bef2a8cc844b7c6..f363dc2b6d3e9f51ca87780026b8ec051bd918e7 100644 (file)
#include "parser/parser.h"
#include "core/object.h"
+#include "core/store.h"
#include "testutils.h"
#include <check.h>
sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
sdb_llist_t *check;
sdb_ast_node_t *node;
+ sdb_store_matcher_t *m;
_Bool ok;
check = sdb_parser_parse(parse_data[_i].query,
SDB_STORE_TYPE_TO_NAME(parse_data[_i].expected_extra));
}
+ /* TODO: this should move into front-end specific tests */
+ m = sdb_store_query_prepare(node);
+ fail_unless(m != NULL,
+ "sdb_store_query_prepare(AST<%s>) = NULL; expected: <m>",
+ parse_data[_i].query);
+
sdb_object_deref(SDB_OBJ(node));
+ sdb_object_deref(SDB_OBJ(m));
sdb_llist_destroy(check);
sdb_strbuf_destroy(errbuf);
}