From 24dce6d59414125f1f0fbe8434f5ed9f280d6872 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 19 May 2015 20:10:22 +0200 Subject: [PATCH] Drop the old frontend parser. It's fully replaced by the new parser module now. --- src/Makefile.am | 6 +- src/frontend/analyzer.c | 425 --------------- src/frontend/grammar.y | 882 ------------------------------ src/frontend/parser.c | 192 ------- src/frontend/scanner.l | 307 ----------- src/include/frontend/parser.h | 101 ---- src/include/parser/parser.h | 15 +- t/Makefile.am | 1 - t/unit/frontend/parser_test.c | 971 ---------------------------------- 9 files changed, 13 insertions(+), 2887 deletions(-) delete mode 100644 src/frontend/analyzer.c delete mode 100644 src/frontend/grammar.y delete mode 100644 src/frontend/parser.c delete mode 100644 src/frontend/scanner.l delete mode 100644 src/include/frontend/parser.h delete mode 100644 t/unit/frontend/parser_test.c diff --git a/src/Makefile.am b/src/Makefile.am index 48561c3..0dbd151 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ AM_CPPFLAGS += -DPKGLIBDIR='"${pkglibdir}"' AM_YFLAGS = -d BUILT_SOURCES = include/client/sysdb.h include/sysdb.h \ - frontend/grammar.h parser/grammar.h + parser/grammar.h EXTRA_DIST = include/client/sysdb.h.in include/sysdb.h.in pkginclude_HEADERS = include/sysdb.h @@ -27,7 +27,6 @@ pkgcoreinclude_HEADERS = \ pkgfeincludedir = $(pkgincludedir)/frontend pkgfeinclude_HEADERS = \ include/frontend/connection.h \ - include/frontend/parser.h \ include/frontend/proto.h \ include/frontend/sock.h pkgutilsincludedir = $(pkgincludedir)/utils @@ -68,7 +67,6 @@ libsysdbclient_la_LIBADD = $(LIBLTDL) @OPENSSL_LIBS@ # don't use strict CFLAGS for flex code noinst_LTLIBRARIES += libsysdb_fe_parser.la libsysdb_fe_parser_la_SOURCES = \ - frontend/grammar.y frontend/scanner.l \ parser/grammar.y parser/scanner.l libsysdb_fe_parser_la_CFLAGS = @COVERAGE_CFLAGS@ @PROFILING_CFLAGS@ \ -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" @@ -86,10 +84,8 @@ libsysdb_la_SOURCES = \ core/data.c include/core/data.h \ core/time.c include/core/time.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 \ frontend/sock.c include/frontend/sock.h \ frontend/session.c \ frontend/query.c \ diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c deleted file mode 100644 index 01e1ad3..0000000 --- a/src/frontend/analyzer.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * SysDB - src/frontend/analyzer.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * 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 "utils/error.h" -#include "utils/strbuf.h" - -#include - -/* - * private helper functions - */ - -static void -iter_error(sdb_strbuf_t *errbuf, int op, sdb_store_expr_t *iter, int context) -{ - sdb_strbuf_sprintf(errbuf, "Invalid %s iterator: %s %s " - "not iterable in %s context", MATCHER_SYM(op), - EXPR_TO_STRING(iter), SDB_STORE_TYPE_TO_NAME(iter->data_type), - context == -1 ? "generic" : SDB_STORE_TYPE_TO_NAME(context)); -} /* iter_error */ - -static void -iter_op_error(sdb_strbuf_t *errbuf, int op, - int iter_type, int cmp, int value_type) -{ - sdb_strbuf_sprintf(errbuf, "Invalid iterator %s %s %s %s", - MATCHER_SYM(op), SDB_TYPE_TO_STRING(iter_type), - MATCHER_SYM(cmp), SDB_TYPE_TO_STRING(value_type)); - if ((iter_type & 0xff) != value_type) - sdb_strbuf_append(errbuf, " (type mismatch)"); - else - sdb_strbuf_append(errbuf, " (invalid operator)"); -} /* iter_op_error */ - -static void -cmp_error(sdb_strbuf_t *errbuf, int op, int left, int right) -{ - sdb_strbuf_sprintf(errbuf, "Invalid operator %s for types %s and %s", - MATCHER_SYM(op), SDB_TYPE_TO_STRING(left), - SDB_TYPE_TO_STRING(right)); -} /* cmp_error */ - -static void -op_error(sdb_strbuf_t *errbuf, int op, int left, int right) -{ - sdb_strbuf_sprintf(errbuf, "Invalid operator %s for types %s and %s", - SDB_DATA_OP_TO_STRING(op), SDB_TYPE_TO_STRING(left), - SDB_TYPE_TO_STRING(right)); -} /* cmp_error */ - -static int -analyze_expr(int context, sdb_store_expr_t *e, sdb_strbuf_t *errbuf) -{ - if (! e) - return 0; - - if ((e->type < TYPED_EXPR) || (SDB_DATA_CONCAT < e->type)) { - sdb_strbuf_sprintf(errbuf, "Invalid expression of type %d", e->type); - return -1; - } - - switch (e->type) { - case TYPED_EXPR: - if (analyze_expr((int)e->data.data.integer, e->left, errbuf)) - return -1; - if (context == (int)e->data.data.integer) - return 0; - if ((e->data.data.integer == SDB_HOST) && - ((context == SDB_SERVICE) || (context == SDB_METRIC) - || (context < 0))) - return 0; - sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s " - "in %s context", - SDB_STORE_TYPE_TO_NAME(e->data.data.integer), - EXPR_TO_STRING(e->left), - context == -1 ? "generic" : SDB_STORE_TYPE_TO_NAME(context)); - return -1; - - case ATTR_VALUE: - case 0: - break; - - case FIELD_VALUE: - if ((e->data.data.integer == SDB_FIELD_VALUE) - && (context != SDB_ATTRIBUTE)) { - sdb_strbuf_sprintf(errbuf, "Invalid expression %s.value " - "(only attributes have a value)", - SDB_STORE_TYPE_TO_NAME(context)); - return -1; - } - break; - - default: - if (analyze_expr(context, e->left, errbuf)) - return -1; - if (analyze_expr(context, e->right, errbuf)) - return -1; - - if ((e->left->data_type > 0) && (e->right->data_type > 0)) { - if (sdb_data_expr_type(e->type, e->left->data_type, - e->right->data_type) < 0) { - op_error(errbuf, e->type, e->left->data_type, - e->right->data_type); - return -1; - } - } - break; - } - return 0; -} /* analyze_expr */ - -static int -analyze_matcher(int context, int parent_type, - sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) -{ - 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, m->type, OP_M(m)->left, errbuf)) - return -1; - if (analyze_matcher(context, m->type, OP_M(m)->right, errbuf)) - return -1; - break; - - case MATCHER_NOT: - assert(UOP_M(m)->op); - if (analyze_matcher(context, m->type, UOP_M(m)->op, errbuf)) - return -1; - break; - - case MATCHER_ANY: - case MATCHER_ALL: - { - int child_context = -1; - int left_type = -1; - int type = -1; - - assert(ITER_M(m)->m); - - if ((ITER_M(m)->iter->type == TYPED_EXPR) - || (ITER_M(m)->iter->type == FIELD_VALUE)) - type = (int)ITER_M(m)->iter->data.data.integer; - - if (context == -1) { /* inside a filter */ - /* attributes are always iterable */ - if ((ITER_M(m)->iter->type == TYPED_EXPR) - && (type != SDB_ATTRIBUTE)) { - iter_error(errbuf, m->type, ITER_M(m)->iter, context); - return -1; - } - /* backends are always iterable */ - if ((ITER_M(m)->iter->type == FIELD_VALUE) - && (! (type != SDB_FIELD_BACKEND))) { - iter_error(errbuf, m->type, ITER_M(m)->iter, context); - return -1; - } - } - else if (! sdb_store_expr_iterable(ITER_M(m)->iter, context)) { - iter_error(errbuf, m->type, ITER_M(m)->iter, context); - return -1; - } - - if (ITER_M(m)->iter->type == TYPED_EXPR) { - child_context = type; - left_type = ITER_M(m)->iter->data_type; - } - else if (ITER_M(m)->iter->type == FIELD_VALUE) { - child_context = context; - /* element type of the field */ - left_type = ITER_M(m)->iter->data_type & 0xff; - } - else if (! ITER_M(m)->iter->type) { - child_context = context; - /* elements of the array constant */ - left_type = ITER_M(m)->iter->data.type & 0xff; - } - else { - iter_error(errbuf, m->type, ITER_M(m)->iter, context); - return -1; - } - - /* any ary operator will do but these are the once - * we currently support */ - if ((ITER_M(m)->m->type != MATCHER_LT) - && (ITER_M(m)->m->type != MATCHER_LE) - && (ITER_M(m)->m->type != MATCHER_EQ) - && (ITER_M(m)->m->type != MATCHER_NE) - && (ITER_M(m)->m->type != MATCHER_GE) - && (ITER_M(m)->m->type != MATCHER_GT) - && (ITER_M(m)->m->type != MATCHER_REGEX) - && (ITER_M(m)->m->type != MATCHER_NREGEX)) { - iter_op_error(errbuf, m->type, - left_type, ITER_M(m)->m->type, - CMP_M(ITER_M(m)->m)->right->data_type); - return -1; - } - if ((left_type >= 0) - && (CMP_M(ITER_M(m)->m)->right->data_type >= 0)) { - if (left_type != CMP_M(ITER_M(m)->m)->right->data_type) { - iter_op_error(errbuf, m->type, - left_type, ITER_M(m)->m->type, - CMP_M(ITER_M(m)->m)->right->data_type); - return -1; - } - } - if (child_context <= 0) { - sdb_strbuf_sprintf(errbuf, "Unable to determine the context " - "(object type) of iterator %s %s %s %s", - MATCHER_SYM(m->type), SDB_TYPE_TO_STRING(left_type), - MATCHER_SYM(ITER_M(m)->m->type), - SDB_TYPE_TO_STRING(CMP_M(ITER_M(m)->m)->right->data_type)); - } - if (analyze_matcher(child_context, m->type, ITER_M(m)->m, errbuf)) - return -1; - break; - } - - case MATCHER_LT: - case MATCHER_LE: - case MATCHER_EQ: - case MATCHER_NE: - case MATCHER_GE: - case MATCHER_GT: - { - int left_type = -1; - - assert(CMP_M(m)->right); - if ((parent_type == MATCHER_ALL) - || (parent_type == MATCHER_ANY)) { - assert(! CMP_M(m)->left); - } - else { - assert(CMP_M(m)->left); - left_type = CMP_M(m)->left->data_type; - } - - if (analyze_expr(context, CMP_M(m)->left, errbuf)) - return -1; - if (analyze_expr(context, CMP_M(m)->right, errbuf)) - return -1; - - if ((left_type > 0) && (CMP_M(m)->right->data_type > 0)) { - if (left_type == CMP_M(m)->right->data_type) - return 0; - cmp_error(errbuf, m->type, left_type, - CMP_M(m)->right->data_type); - return -1; - } - if ((left_type > 0) && (left_type & SDB_TYPE_ARRAY)) { - cmp_error(errbuf, m->type, left_type, - CMP_M(m)->right->data_type); - return -1; - } - if ((CMP_M(m)->right->data_type > 0) - && (CMP_M(m)->right->data_type & SDB_TYPE_ARRAY)) { - cmp_error(errbuf, m->type, left_type, - CMP_M(m)->right->data_type); - return -1; - } - break; - } - - case MATCHER_IN: - case MATCHER_NIN: - if (analyze_expr(context, CMP_M(m)->left, errbuf)) - return -1; - if (analyze_expr(context, CMP_M(m)->right, errbuf)) - return -1; - - /* the left operand may be a scalar or an array but the element - * type has to match */ - if ((CMP_M(m)->right->data_type > 0) - && (! (CMP_M(m)->right->data_type & SDB_TYPE_ARRAY))) { - cmp_error(errbuf, m->type, CMP_M(m)->left->data_type, - CMP_M(m)->right->data_type); - return -1; - } - if ((CMP_M(m)->left->data_type > 0) - && (CMP_M(m)->right->data_type > 0)) { - if ((CMP_M(m)->left->data_type & 0xff) - != (CMP_M(m)->right->data_type & 0xff)) { - cmp_error(errbuf, m->type, CMP_M(m)->left->data_type, - CMP_M(m)->right->data_type); - return -1; - } - } - break; - - case MATCHER_REGEX: - case MATCHER_NREGEX: - if (analyze_expr(context, CMP_M(m)->left, errbuf)) - return -1; - if (analyze_expr(context, CMP_M(m)->right, errbuf)) - return -1; - - /* 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)) { - cmp_error(errbuf, m->type, CMP_M(m)->left->data_type, - CMP_M(m)->right->data_type); - return -1; - } - break; - - case MATCHER_ISNULL: - case MATCHER_ISNNULL: - if (analyze_expr(context, ISNULL_M(m)->expr, errbuf)) - return -1; - break; - - default: - sdb_strbuf_sprintf(errbuf, "Unknown matcher type %d", m->type); - return -1; - } - return 0; -} /* analyze_matcher */ - -/* - * public API - */ - -int -sdb_fe_analyze(sdb_conn_node_t *node, sdb_strbuf_t *errbuf) -{ - 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 == SDB_CONNECTION_FETCH) { - conn_fetch_t *fetch = CONN_FETCH(node); - if ((fetch->type == SDB_HOST) && fetch->name) { - sdb_strbuf_sprintf(errbuf, "Unexpected STRING '%s'", fetch->name); - return -1; - } - if ((fetch->type != SDB_HOST) && (! fetch->name)) { - sdb_strbuf_sprintf(errbuf, "Missing %s name", - SDB_STORE_TYPE_TO_NAME(fetch->type)); - return -1; - } - if (fetch->filter) - filter = fetch->filter->matcher; - context = fetch->type; - } - else if (node->cmd == SDB_CONNECTION_LIST) { - if (CONN_LIST(node)->filter) - filter = CONN_LIST(node)->filter->matcher; - context = CONN_LIST(node)->type; - } - else if (node->cmd == SDB_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 == SDB_CONNECTION_STORE_HOST) - || (node->cmd == SDB_CONNECTION_STORE_SERVICE) - || (node->cmd == SDB_CONNECTION_STORE_METRIC) - || (node->cmd == SDB_CONNECTION_STORE_ATTRIBUTE)) { - return 0; - } - else if (node->cmd == SDB_CONNECTION_TIMESERIES) { - return 0; - } - else { - sdb_strbuf_sprintf(errbuf, - "Don't know how to analyze %s command (id=%#x)", - SDB_CONN_MSGTYPE_TO_STRING(node->cmd), node->cmd); - return -1; - } - - if (context <= 0) { - sdb_strbuf_sprintf(errbuf, "Unable to determine the context " - "(object type) for %s command (id=%#x)", - SDB_CONN_MSGTYPE_TO_STRING(node->cmd), node->cmd); - return -1; - } - if (analyze_matcher(context, -1, m, errbuf)) - status = -1; - if (analyze_matcher(-1, -1, filter, errbuf)) - status = -1; - return status; -} /* sdb_fe_analyze */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y deleted file mode 100644 index 31b71a0..0000000 --- a/src/frontend/grammar.y +++ /dev/null @@ -1,882 +0,0 @@ -/* - * SysDB - src/frontend/grammar.y - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * 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 "frontend/connection-private.h" -#include "frontend/parser.h" -#include "frontend/grammar.h" - -#include "core/store.h" -#include "core/store-private.h" -#include "core/time.h" - -#include "utils/error.h" -#include "utils/llist.h" - -#include - -#include -#include - -/* - * private helper functions - */ - -static sdb_store_matcher_t * -name_iter_matcher(int m_type, sdb_store_expr_t *iter, const char *cmp, - sdb_store_expr_t *expr); - -/* - * public API - */ - -int -sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner); - -sdb_fe_yyextra_t * -sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner); - -void -sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); -void -sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...); - -/* quick access to the current parse tree */ -#define pt sdb_fe_yyget_extra(scanner)->parsetree - -/* quick access to the parser mode */ -#define parser_mode sdb_fe_yyget_extra(scanner)->mode - -/* quick access to the parser's error buffer */ -#define errbuf sdb_fe_yyget_extra(scanner)->errbuf - -#define MODE_TO_STRING(m) \ - (((m) == SDB_PARSE_DEFAULT) ? "statement" \ - : ((m) == SDB_PARSE_COND) ? "condition" \ - : ((m) == SDB_PARSE_ARITH) ? "arithmetic expression" \ - : "UNKNOWN") - -%} - -%pure-parser -%lex-param {sdb_fe_yyscan_t scanner} -%parse-param {sdb_fe_yyscan_t scanner} -%locations -%error-verbose -%expect 0 -%name-prefix "sdb_fe_yy" - -%union { - const char *sstr; /* static string */ - char *str; - int integer; - - sdb_data_t data; - sdb_time_t datetime; - - sdb_llist_t *list; - sdb_conn_node_t *node; - - sdb_store_matcher_t *m; - sdb_store_expr_t *expr; - - sdb_metric_store_t metric_store; -} - -%start statements - -%token SCANNER_ERROR - -%token AND OR IS NOT MATCHING FILTER -%token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX -%token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN -%token CONCAT - -%token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T -%token ATTRIBUTE_T ATTRIBUTES_T -%token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T VALUE_T - -%token LAST UPDATE - -%token START END - -/* NULL token */ -%token NULL_T - -%token FETCH LIST LOOKUP STORE TIMESERIES - -%token IDENTIFIER STRING - -%token INTEGER FLOAT - -%token DATE TIME - -/* Precedence (lowest first): */ -%left OR -%left AND -%right NOT -%left CMP_EQUAL CMP_NEQUAL -%left CMP_LT CMP_LE CMP_GE CMP_GT -%nonassoc CMP_REGEX CMP_NREGEX -%nonassoc IN -%left CONCAT -%nonassoc IS -%left '+' '-' -%left '*' '/' '%' -%left '[' ']' -%left '(' ')' -%left '.' - -%type statements -%type statement - fetch_statement - list_statement - lookup_statement - store_statement - timeseries_statement - matching_clause - filter_clause - condition - -%type matcher - compare_matcher - -%type expression arithmetic_expression object_expression - -%type object_type object_type_plural -%type field - -%type cmp - -%type data - interval interval_elem - array array_elem_list - -%type datetime - start_clause end_clause - last_update_clause - -%type metric_store_clause - -%destructor { free($$); } -%destructor { sdb_object_deref(SDB_OBJ($$)); } -%destructor { sdb_data_free_datum(&$$); } - -%% - -statements: - statements ';' statement - { - /* only accepted in default parse mode */ - if (parser_mode != SDB_PARSE_DEFAULT) { - sdb_fe_yyerrorf(&yylloc, scanner, - YY_("syntax error, unexpected statement, " - "expecting %s"), MODE_TO_STRING(parser_mode)); - sdb_object_deref(SDB_OBJ($3)); - YYABORT; - } - - if ($3) { - sdb_llist_append(pt, SDB_OBJ($3)); - sdb_object_deref(SDB_OBJ($3)); - } - } - | - statement - { - /* only accepted in default parse mode */ - if (parser_mode != SDB_PARSE_DEFAULT) { - sdb_fe_yyerrorf(&yylloc, scanner, - YY_("syntax error, unexpected statement, " - "expecting %s"), MODE_TO_STRING(parser_mode)); - sdb_object_deref(SDB_OBJ($1)); - YYABORT; - } - - if ($1) { - sdb_llist_append(pt, SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($1)); - } - } - | - condition - { - /* only accepted in condition parse mode */ - if (! (parser_mode & SDB_PARSE_COND)) { - sdb_fe_yyerrorf(&yylloc, scanner, - YY_("syntax error, unexpected condition, " - "expecting %s"), MODE_TO_STRING(parser_mode)); - sdb_object_deref(SDB_OBJ($1)); - YYABORT; - } - - if ($1) { - sdb_llist_append(pt, SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($1)); - } - } - | - expression - { - /* only accepted in expression parse mode */ - if (! (parser_mode & SDB_PARSE_ARITH)) { - sdb_fe_yyerrorf(&yylloc, scanner, - YY_("syntax error, unexpected expression, " - "expecting %s"), MODE_TO_STRING(parser_mode)); - sdb_object_deref(SDB_OBJ($1)); - YYABORT; - } - - if ($1) { - sdb_conn_node_t *n; - n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_expr_t, conn_expr_destroy)); - n->cmd = SDB_CONNECTION_EXPR; - CONN_EXPR(n)->expr = $1; - - sdb_llist_append(pt, SDB_OBJ(n)); - sdb_object_deref(SDB_OBJ(n)); - } - } - ; - -statement: - fetch_statement - | - list_statement - | - lookup_statement - | - store_statement - | - timeseries_statement - | - /* empty */ - { - $$ = NULL; - } - ; - -/* - * FETCH [FILTER ]; - * - * Retrieve detailed information about a single host. - */ -fetch_statement: - FETCH object_type STRING filter_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_fetch_t, conn_fetch_destroy)); - CONN_FETCH($$)->type = $2; - CONN_FETCH($$)->host = $3; - CONN_FETCH($$)->name = NULL; - CONN_FETCH($$)->filter = CONN_MATCHER($4); - $$->cmd = SDB_CONNECTION_FETCH; - } - | - FETCH object_type STRING '.' STRING filter_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_fetch_t, conn_fetch_destroy)); - CONN_FETCH($$)->type = $2; - CONN_FETCH($$)->host = $3; - CONN_FETCH($$)->name = $5; - CONN_FETCH($$)->filter = CONN_MATCHER($6); - $$->cmd = SDB_CONNECTION_FETCH; - } - ; - -/* - * LIST [FILTER ]; - * - * Returns a list of all hosts in the store. - */ -list_statement: - LIST object_type_plural filter_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_list_t, conn_list_destroy)); - CONN_LIST($$)->type = $2; - CONN_LIST($$)->filter = CONN_MATCHER($3); - $$->cmd = SDB_CONNECTION_LIST; - } - ; - -/* - * LOOKUP MATCHING [FILTER ]; - * - * Returns detailed information about matching condition. - */ -lookup_statement: - LOOKUP object_type_plural matching_clause filter_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_lookup_t, conn_lookup_destroy)); - CONN_LOOKUP($$)->type = $2; - CONN_LOOKUP($$)->matcher = CONN_MATCHER($3); - CONN_LOOKUP($$)->filter = CONN_MATCHER($4); - $$->cmd = SDB_CONNECTION_LOOKUP; - } - ; - -matching_clause: - MATCHING condition { $$ = $2; } - | - /* empty */ { $$ = NULL; } - -filter_clause: - FILTER condition { $$ = $2; } - | - /* empty */ { $$ = NULL; } - -/* - * STORE |. [LAST UPDATE ]; - * STORE METRIC . STORE [LAST UPDATE ]; - * STORE ATTRIBUTE . [LAST UPDATE ]; - * - * Store or update an object in the database. - */ -store_statement: - STORE HOST_T STRING last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_host_t, conn_store_host_destroy)); - CONN_STORE_HOST($$)->name = $3; - CONN_STORE_HOST($$)->last_update = $4; - $$->cmd = SDB_CONNECTION_STORE_HOST; - } - | - STORE SERVICE_T STRING '.' STRING last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_svc_t, conn_store_svc_destroy)); - CONN_STORE_SVC($$)->hostname = $3; - CONN_STORE_SVC($$)->name = $5; - CONN_STORE_SVC($$)->last_update = $6; - $$->cmd = SDB_CONNECTION_STORE_SERVICE; - } - | - STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_metric_t, conn_store_metric_destroy)); - CONN_STORE_METRIC($$)->hostname = $3; - CONN_STORE_METRIC($$)->name = $5; - CONN_STORE_METRIC($$)->store_type = $6.type; - CONN_STORE_METRIC($$)->store_id = $6.id; - CONN_STORE_METRIC($$)->last_update = $7; - $$->cmd = SDB_CONNECTION_STORE_METRIC; - } - | - STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_attr_t, conn_store_attr_destroy)); - CONN_STORE_ATTR($$)->parent_type = SDB_HOST; - CONN_STORE_ATTR($$)->hostname = NULL; - CONN_STORE_ATTR($$)->parent = $4; - CONN_STORE_ATTR($$)->key = $6; - CONN_STORE_ATTR($$)->value = $7; - CONN_STORE_ATTR($$)->last_update = $8; - $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; - } - | - STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_attr_t, conn_store_attr_destroy)); - CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE; - CONN_STORE_ATTR($$)->hostname = $4; - CONN_STORE_ATTR($$)->parent = $6; - CONN_STORE_ATTR($$)->key = $8; - CONN_STORE_ATTR($$)->value = $9; - CONN_STORE_ATTR($$)->last_update = $10; - $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; - } - | - STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_store_attr_t, conn_store_attr_destroy)); - CONN_STORE_ATTR($$)->parent_type = SDB_METRIC; - CONN_STORE_ATTR($$)->hostname = $4; - CONN_STORE_ATTR($$)->parent = $6; - CONN_STORE_ATTR($$)->key = $8; - CONN_STORE_ATTR($$)->value = $9; - CONN_STORE_ATTR($$)->last_update = $10; - $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; - } - ; - -last_update_clause: - LAST UPDATE datetime { $$ = $3; } - | - /* empty */ { $$ = sdb_gettime(); } - -metric_store_clause: - STORE STRING STRING { $$.type = $2; $$.id = $3; } - | - /* empty */ { $$.type = $$.id = NULL; } - -/* - * TIMESERIES . [START ] [END ]; - * - * Returns a time-series for the specified host's metric. - */ -timeseries_statement: - TIMESERIES STRING '.' STRING start_clause end_clause - { - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_ts_t, conn_ts_destroy)); - CONN_TS($$)->hostname = $2; - CONN_TS($$)->metric = $4; - CONN_TS($$)->opts.start = $5; - CONN_TS($$)->opts.end = $6; - $$->cmd = SDB_CONNECTION_TIMESERIES; - } - ; - -start_clause: - START datetime { $$ = $2; } - | - /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; } - -end_clause: - END datetime { $$ = $2; } - | - /* empty */ { $$ = sdb_gettime(); } - -/* - * Basic expressions. - */ - -condition: - matcher - { - if (! $1) { - /* TODO: improve error reporting */ - sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, invalid condition")); - YYABORT; - } - - $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_matcher_t, conn_matcher_destroy)); - $$->cmd = SDB_CONNECTION_MATCHER; - CONN_MATCHER($$)->matcher = $1; - } - ; - -matcher: - '(' matcher ')' - { - $$ = $2; - } - | - matcher AND matcher - { - $$ = sdb_store_con_matcher($1, $3); - sdb_object_deref(SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($3)); - } - | - matcher OR matcher - { - $$ = sdb_store_dis_matcher($1, $3); - sdb_object_deref(SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($3)); - } - | - NOT matcher - { - $$ = sdb_store_inv_matcher($2); - sdb_object_deref(SDB_OBJ($2)); - } - | - compare_matcher - { - $$ = $1; - } - ; - -compare_matcher: - expression cmp expression - { - sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2); - assert(cb); /* else, the grammar accepts invalid 'cmp' */ - $$ = cb($1, $3); - sdb_object_deref(SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($3)); - } - | - ANY expression cmp expression - { - $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4); - sdb_object_deref(SDB_OBJ($2)); - sdb_object_deref(SDB_OBJ($4)); - } - | - ALL expression cmp expression - { - $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4); - sdb_object_deref(SDB_OBJ($2)); - sdb_object_deref(SDB_OBJ($4)); - } - | - expression IS NULL_T - { - $$ = sdb_store_isnull_matcher($1); - sdb_object_deref(SDB_OBJ($1)); - } - | - expression IS NOT NULL_T - { - $$ = sdb_store_isnnull_matcher($1); - sdb_object_deref(SDB_OBJ($1)); - } - | - expression IN expression - { - $$ = sdb_store_in_matcher($1, $3); - sdb_object_deref(SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($3)); - } - | - expression NOT IN expression - { - $$ = sdb_store_nin_matcher($1, $4); - sdb_object_deref(SDB_OBJ($1)); - sdb_object_deref(SDB_OBJ($4)); - } - ; - -expression: - arithmetic_expression - { - if (! $1) { - /* we should have better error messages here - * TODO: maybe let the analyzer handle this instead */ - sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, invalid arithmetic expression")); - YYABORT; - } - $$ = $1; - } - | - object_expression - { - $$ = $1; - } - | - data - { - $$ = sdb_store_expr_constvalue(&$1); - sdb_data_free_datum(&$1); - } - ; - -arithmetic_expression: - '(' expression ')' - { - $$ = $2; - } - | - expression '+' expression - { - $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - | - expression '-' expression - { - $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - | - expression '*' expression - { - $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - | - expression '/' expression - { - $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - | - expression '%' expression - { - $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - | - expression CONCAT expression - { - $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3); - sdb_object_deref(SDB_OBJ($1)); $1 = NULL; - sdb_object_deref(SDB_OBJ($3)); $3 = NULL; - } - ; - -object_expression: - object_type '.' object_expression - { - $$ = sdb_store_expr_typed($1, $3); - sdb_object_deref(SDB_OBJ($3)); - } - | - ATTRIBUTE_T '.' object_expression - { - $$ = sdb_store_expr_typed(SDB_ATTRIBUTE, $3); - sdb_object_deref(SDB_OBJ($3)); - } - | - field - { - $$ = sdb_store_expr_fieldvalue($1); - } - | - ATTRIBUTE_T '[' STRING ']' - { - $$ = sdb_store_expr_attrvalue($3); - free($3); $3 = NULL; - } - ; - -object_type: - HOST_T { $$ = SDB_HOST; } - | - SERVICE_T { $$ = SDB_SERVICE; } - | - METRIC_T { $$ = SDB_METRIC; } - ; - -object_type_plural: - HOSTS_T { $$ = SDB_HOST; } - | - SERVICES_T { $$ = SDB_SERVICE; } - | - METRICS_T { $$ = SDB_METRIC; } - ; - -field: - NAME_T { $$ = SDB_FIELD_NAME; } - | - LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; } - | - AGE_T { $$ = SDB_FIELD_AGE; } - | - INTERVAL_T { $$ = SDB_FIELD_INTERVAL; } - | - BACKEND_T { $$ = SDB_FIELD_BACKEND; } - | - VALUE_T { $$ = SDB_FIELD_VALUE; } - ; - -cmp: - CMP_EQUAL { $$ = "="; } - | - CMP_NEQUAL { $$ = "!="; } - | - CMP_REGEX { $$ = "=~"; } - | - CMP_NREGEX { $$ = "!~"; } - | - CMP_LT { $$ = "<"; } - | - CMP_LE { $$ = "<="; } - | - CMP_GE { $$ = ">="; } - | - CMP_GT { $$ = ">"; } - ; - -data: - STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; } - | - INTEGER { $$ = $1; } - | - FLOAT { $$ = $1; } - | - datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; } - | - interval { $$ = $1; } - | - array { $$ = $1; } - ; - -datetime: - DATE TIME { $$ = $1 + $2; } - | - DATE { $$ = $1; } - | - TIME { $$ = $1; } - ; - -interval: - interval interval_elem - { - $$.data.datetime = $1.data.datetime + $2.data.datetime; - } - | - interval_elem { $$ = $1; } - ; - -interval_elem: - INTEGER IDENTIFIER - { - sdb_time_t unit = 1; - - unit = sdb_strpunit($2); - if (! unit) { - sdb_fe_yyerrorf(&yylloc, scanner, - YY_("syntax error, invalid time unit %s"), $2); - free($2); $2 = NULL; - YYABORT; - } - free($2); $2 = NULL; - - $$.type = SDB_TYPE_DATETIME; - $$.data.datetime = (sdb_time_t)$1.data.integer * unit; - - if ($1.data.integer < 0) { - sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, negative intervals not supported")); - YYABORT; - } - } - ; - -array: - '[' array_elem_list ']' - { - $$ = $2; - } - ; - -array_elem_list: - array_elem_list ',' data - { - size_t elem_size; - - if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) { - sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " - "cannot use element of type %s in array of type %s"), - SDB_TYPE_TO_STRING($3.type), - SDB_TYPE_TO_STRING($1.type)); - sdb_data_free_datum(&$1); - sdb_data_free_datum(&$3); - YYABORT; - } - - elem_size = sdb_data_sizeof($3.type); - $1.data.array.values = realloc($1.data.array.values, - ($1.data.array.length + 1) * elem_size); - if (! $1.data.array.values) { - sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); - YYABORT; - } - - memcpy((char *)$1.data.array.values - + $1.data.array.length * elem_size, - &$3.data, elem_size); - ++$1.data.array.length; - - $$ = $1; - } - | - data - { - size_t elem_size; - - if ($1.type & SDB_TYPE_ARRAY) { - sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " - "cannot construct array of type %s"), - SDB_TYPE_TO_STRING($1.type)); - sdb_data_free_datum(&$1); - YYABORT; - } - - $$ = $1; - $$.type = $1.type | SDB_TYPE_ARRAY; - $$.data.array.length = 1; - elem_size = sdb_data_sizeof($1.type); - $$.data.array.values = malloc(elem_size); - if (! $$.data.array.values ) { - sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); - YYABORT; - } - memcpy($$.data.array.values, &$1.data, elem_size); - } - ; - -%% - -void -sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg) -{ - sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg); - sdb_strbuf_sprintf(errbuf, "%s", msg); -} /* sdb_fe_yyerror */ - -void -sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...) -{ - va_list ap, aq; - va_start(ap, fmt); - va_copy(aq, ap); - sdb_vlog(SDB_LOG_ERR, fmt, ap); - sdb_strbuf_vsprintf(errbuf, fmt, aq); - va_end(ap); -} /* sdb_fe_yyerrorf */ - -static sdb_store_matcher_t * -name_iter_matcher(int type, sdb_store_expr_t *iter, const char *cmp, - sdb_store_expr_t *expr) -{ - sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp); - sdb_store_matcher_t *m, *tmp = NULL; - assert(cb); - - m = cb(NULL, expr); - if (type == MATCHER_ANY) - tmp = sdb_store_any_matcher(iter, m); - else if (type == MATCHER_ALL) - tmp = sdb_store_all_matcher(iter, m); - sdb_object_deref(SDB_OBJ(m)); - return tmp; -} /* name_iter_matcher */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/frontend/parser.c b/src/frontend/parser.c deleted file mode 100644 index 8d608d6..0000000 --- a/src/frontend/parser.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SysDB - src/frontend/parser.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * 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 "frontend/connection-private.h" -#include "frontend/parser.h" -#include "frontend/grammar.h" - -#include "core/store.h" - -#include "utils/llist.h" -#include "utils/strbuf.h" - -#include -#include - -/* - * private helper functions - */ - -static int -scanner_init(const char *input, int len, - sdb_fe_yyscan_t *scanner, sdb_fe_yyextra_t *extra, - sdb_strbuf_t *errbuf) -{ - if (! input) { - sdb_strbuf_sprintf(errbuf, "Missing scanner input"); - return -1; - } - - memset(extra, 0, sizeof(*extra)); - extra->parsetree = sdb_llist_create(); - extra->mode = SDB_PARSE_DEFAULT; - extra->errbuf = errbuf; - - if (! extra->parsetree) { - sdb_strbuf_sprintf(errbuf, "Failed to allocate parse-tree"); - return -1; - } - - *scanner = sdb_fe_scanner_init(input, len, extra); - if (! scanner) { - sdb_llist_destroy(extra->parsetree); - return -1; - } - return 0; -} /* scanner_init */ - -/* - * public API - */ - -sdb_llist_t * -sdb_fe_parse(const char *query, int len, sdb_strbuf_t *errbuf) -{ - sdb_fe_yyscan_t scanner; - sdb_fe_yyextra_t yyextra; - sdb_llist_iter_t *iter; - int yyres; - - if (scanner_init(query, len, &scanner, &yyextra, errbuf)) - return NULL; - - yyres = sdb_fe_yyparse(scanner); - sdb_fe_scanner_destroy(scanner); - - if (yyres) { - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - - 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)); - if (sdb_fe_analyze(node, errbuf)) { - sdb_llist_iter_destroy(iter); - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - } - sdb_llist_iter_destroy(iter); - return yyextra.parsetree; -} /* sdb_fe_parse */ - -sdb_store_matcher_t * -sdb_fe_parse_matcher(const char *cond, int len, sdb_strbuf_t *errbuf) -{ - sdb_fe_yyscan_t scanner; - sdb_fe_yyextra_t yyextra; - - sdb_conn_node_t *node; - sdb_store_matcher_t *m; - - int yyres; - - if (scanner_init(cond, len, &scanner, &yyextra, errbuf)) - return NULL; - - yyextra.mode = SDB_PARSE_COND; - - yyres = sdb_fe_yyparse(scanner); - sdb_fe_scanner_destroy(scanner); - - if (yyres) { - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - - node = SDB_CONN_NODE(sdb_llist_get(yyextra.parsetree, 0)); - if (! node) { - sdb_strbuf_sprintf(errbuf, "Empty matcher expression '%s'", cond); - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - - assert(node->cmd == SDB_CONNECTION_MATCHER); - m = CONN_MATCHER(node)->matcher; - CONN_MATCHER(node)->matcher = NULL; - - sdb_llist_destroy(yyextra.parsetree); - sdb_object_deref(SDB_OBJ(node)); - return m; -} /* sdb_fe_parse_matcher */ - -sdb_store_expr_t * -sdb_fe_parse_expr(const char *expr, int len, sdb_strbuf_t *errbuf) -{ - sdb_fe_yyscan_t scanner; - sdb_fe_yyextra_t yyextra; - - sdb_conn_node_t *node; - sdb_store_expr_t *e; - - int yyres; - - if (scanner_init(expr, len, &scanner, &yyextra, errbuf)) - return NULL; - - yyextra.mode = SDB_PARSE_ARITH; - - yyres = sdb_fe_yyparse(scanner); - sdb_fe_scanner_destroy(scanner); - - if (yyres) { - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - - node = SDB_CONN_NODE(sdb_llist_get(yyextra.parsetree, 0)); - if (! node) { - sdb_strbuf_sprintf(errbuf, "Empty expression '%s'", expr); - sdb_llist_destroy(yyextra.parsetree); - return NULL; - } - - assert(node->cmd == SDB_CONNECTION_EXPR); - e = CONN_EXPR(node)->expr; - CONN_EXPR(node)->expr = NULL; - - sdb_llist_destroy(yyextra.parsetree); - sdb_object_deref(SDB_OBJ(node)); - return e; -} /* sdb_fe_parse_expr */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l deleted file mode 100644 index ab8b80d..0000000 --- a/src/frontend/scanner.l +++ /dev/null @@ -1,307 +0,0 @@ -/* - * SysDB - src/frontend/scanner.l - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * 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. - */ - -%{ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "core/data.h" -#include "frontend/connection.h" -#include "frontend/parser.h" -#include "frontend/grammar.h" -#include "utils/error.h" - -#include -#include - -#include -#include - -#include - -#define YY_EXTRA_TYPE sdb_fe_yyextra_t * - -static struct { - const char *name; - int id; -} reserved_words[] = { - { "ALL", ALL }, - { "AND", AND }, - { "ANY", ANY }, - { "END", END }, - { "FETCH", FETCH }, - { "FILTER", FILTER }, - { "IN", IN }, - { "IS", IS }, - { "LAST", LAST }, - { "LIST", LIST }, - { "LOOKUP", LOOKUP }, - { "MATCHING", MATCHING }, - { "NOT", NOT }, - { "NULL", NULL_T }, - { "OR", OR }, - { "START", START }, - { "STORE", STORE }, - { "TIMESERIES", TIMESERIES }, - { "UPDATE", UPDATE }, - - /* object types */ - { "host", HOST_T }, - { "hosts", HOSTS_T }, - { "service", SERVICE_T }, - { "services", SERVICES_T }, - { "metric", METRIC_T }, - { "metrics", METRICS_T }, - { "attribute", ATTRIBUTE_T }, - { "attributes", ATTRIBUTES_T }, - /* queryable fields */ - { "name", NAME_T }, - { "last_update", LAST_UPDATE_T }, - { "age", AGE_T }, - { "interval", INTERVAL_T }, - { "backend", BACKEND_T }, - { "value", VALUE_T }, -}; - -void -sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); - -%} - -%option never-interactive -%option reentrant -%option bison-bridge -%option bison-locations -%option 8bit -%option yylineno -%option nodefault -%option noinput -%option nounput -%option noyywrap -%option verbose -%option warn -%option prefix="sdb_fe_yy" outfile="lex.yy.c" - -%x CSC - -whitespace ([ \t\n\r\f]+) -simple_comment ("--"[^\n\r]*) - -/* - * C style comments - */ -csc_start \/\* -csc_inside ([^*/]+|[^*]\/|\*[^/]) -csc_end \*\/ - -/* - * Strings and identifiers. - */ -identifier ([A-Za-z_][A-Za-z_0-9$]*) -/* TODO: fully support SQL strings */ -string ('([^']|'')*') - -/* - * Numeric constants. - */ -dec ([\+\-]?[0-9]+) -exp ([\+\-]?[0-9]+[Ee]\+?[0-9]+) -integer ({dec}|{exp}) -float1 ([\+\-]?[0-9]+\.[0-9]*([Ee][\+\-]?[0-9]+)?) -float2 ([\+\-]?[0-9]*\.[0-9]+([Ee][\+\-]?[0-9]+)?) -float3 ([\+\-]?[0-9]+[Ee]\-[0-9]+) -float4 ([\+\-]?[Ii][Nn][Ff]([Ii][Nn][Ii][Tt][Yy])?) -float5 ([Nn][Aa][Nn]) -float ({float1}|{float2}|{float3}|{float4}|{float5}) - -/* - * Time constants. - */ -date ([0-9]{4}-[0-9]{2}-[0-9]{2}) -time ([0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2}(\.[0-9]{1,9})?)?) - -%% - -{whitespace} | -{simple_comment} { /* ignore */ } - -{csc_start} { BEGIN(CSC); } -{csc_inside} { /* ignore */ } -{csc_end} { BEGIN(INITIAL); } -<> { - sdb_fe_yyerror(yylloc, yyscanner, "unterminated C-style comment"); - return SCANNER_ERROR; - } - -{identifier} { - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(reserved_words); ++i) - if (! strcasecmp(reserved_words[i].name, yytext)) - return reserved_words[i].id; - - yylval->str = strdup(yytext); - return IDENTIFIER; - } -{string} { - char *quot; - size_t len; - - /* remove the leading and trailing quote */ - yytext[yyleng - 1] = '\0'; - yylval->str = strdup(yytext + 1); - - quot = yylval->str; - len = yyleng - 2; - while ((quot = strstr(quot, "''")) != NULL) { - memmove(quot, quot + 1, len - (quot - yylval->str) - 1); - yylval->str[len - 1] = '\0'; - --len; - ++quot; - } - return STRING; - } -{integer} { - yylval->data.data.integer = (int64_t)strtoll(yytext, NULL, 10); - yylval->data.type = SDB_TYPE_INTEGER; - return INTEGER; - } -{float} { - yylval->data.data.decimal = strtod(yytext, NULL); - yylval->data.type = SDB_TYPE_DECIMAL; - return FLOAT; - } - -{date} { - struct tm tm; - memset(&tm, 0, sizeof(tm)); - if (! strptime(yytext, "%Y-%m-%d", &tm)) { - char errmsg[1024]; - snprintf(errmsg, sizeof(errmsg), - "Failed to parse '%s' as date", yytext); - sdb_fe_yyerror(yylloc, yyscanner, errmsg); - return SCANNER_ERROR; - } - yylval->datetime = SECS_TO_SDB_TIME(mktime(&tm)); - return DATE; - } -{time} { - struct tm tm; - char time[9], ns[10]; - char *tmp; - int t; - - memset(&tm, 0, sizeof(tm)); - memset(time, '\0', sizeof(time)); - memset(ns, '0', sizeof(ns)); - ns[sizeof(ns) - 1] = '\0'; - - tmp = strchr(yytext, '.'); - if (tmp) { - size_t i; - *tmp = '\0'; - ++tmp; - strncpy(ns, tmp, sizeof(ns)); - for (i = strlen(ns); i < 9; ++i) - ns[i] = '0'; - } - strncpy(time, yytext, sizeof(time)); - if (tmp) { - /* reset for better error messages */ - --tmp; - *tmp = '.'; - } - - tmp = strchr(time, ':'); - assert(tmp); - tmp = strchr(tmp + 1, ':'); - if (! tmp) - strncat(time, ":00", sizeof(time) - strlen(time) - 1); - - if (! strptime(time, "%H:%M:%S", &tm)) { - char errmsg[1024]; - snprintf(errmsg, sizeof(errmsg), - "Failed to parse '%s' as time", yytext); - sdb_fe_yyerror(yylloc, yyscanner, errmsg); - return SCANNER_ERROR; - } - - t = tm.tm_sec + 60 * tm.tm_min + 3600 * tm.tm_hour; - yylval->datetime = SECS_TO_SDB_TIME(t); - yylval->datetime += (sdb_time_t)strtoll(ns, NULL, 10); - return TIME; - } - -= { return CMP_EQUAL; } -!= { return CMP_NEQUAL; } -=~ { return CMP_REGEX; } -!~ { return CMP_NREGEX; } -\< { return CMP_LT; } -\<= { return CMP_LE; } -\>= { return CMP_GE; } -\> { return CMP_GT; } -\|\| { return CONCAT; } - -. { /* XXX: */ return yytext[0]; } - -%% - -sdb_fe_yyscan_t -sdb_fe_scanner_init(const char *str, int len, sdb_fe_yyextra_t *yyext) -{ - yyscan_t scanner; - - if (! str) - return NULL; - - if (sdb_fe_yylex_init(&scanner)) { - char errbuf[1024]; - sdb_strbuf_sprintf(yyext->errbuf, "yylex_init_failed: %s", - sdb_strerror(errno, errbuf, sizeof(errbuf))); - return NULL; - } - - sdb_fe_yyset_extra(yyext, scanner); - - if (len < 0) - len = strlen(str); - - /* the newly allocated buffer state (YY_BUFFER_STATE) is stored inside the - * scanner and, thus, will be freed by yylex_destroy */ - sdb_fe_yy_scan_bytes(str, len, scanner); - return scanner; -} /* sdb_fe_scanner_init */ - -void -sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner) -{ - sdb_fe_yylex_destroy(scanner); -} /* sdb_fe_scanner_destroy */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/include/frontend/parser.h b/src/include/frontend/parser.h deleted file mode 100644 index 7665701..0000000 --- a/src/include/frontend/parser.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SysDB - src/include/frontend/parser.h - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * 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. - */ - -#ifndef SDB_FRONTEND_PARSER_H -#define SDB_FRONTEND_PARSER_H 1 - -#include "core/store.h" -#include "frontend/connection.h" -#include "utils/llist.h" -#include "utils/strbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* parser modes */ -enum { - /* parser accepts any command statement */ - SDB_PARSE_DEFAULT = 0, - - /* parser accepts any conditional statement */ - SDB_PARSE_COND = 1 << 1, - - /* parser accepts any arithmetic expression */ - SDB_PARSE_ARITH = 1 << 2, -}; - -/* YY_EXTRA data */ -typedef struct { - /* list of sdb_conn_node_t objects */ - sdb_llist_t *parsetree; - - /* parser mode */ - int mode; - - /* buffer for parser error messages */ - sdb_strbuf_t *errbuf; -} sdb_fe_yyextra_t; - -/* see yyscan_t */ -typedef void *sdb_fe_yyscan_t; - -sdb_fe_yyscan_t -sdb_fe_scanner_init(const char *str, int len, sdb_fe_yyextra_t *yyext); - -void -sdb_fe_scanner_destroy(sdb_fe_yyscan_t scanner); - -int -sdb_fe_yyparse(sdb_fe_yyscan_t scanner); - -sdb_store_matcher_t * -sdb_fe_parse_matcher(const char *cond, int len, sdb_strbuf_t *errbuf); - -sdb_store_expr_t * -sdb_fe_parse_expr(const char *expr, int len, sdb_strbuf_t *errbuf); - -/* - * sdb_fe_analyze: - * Analyze a parsed node, checking for semantical errors. Error messages will - * be written to the string buffer, if provided. - * - * Returns: - * - 0 if the node is semantically correct - * - a negative value else - */ -int -sdb_fe_analyze(sdb_conn_node_t *node, sdb_strbuf_t *errbuf); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ! SDB_FRONTEND_PARSER_H */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 92e49bb..2830663 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -28,9 +28,6 @@ #ifndef SDB_PARSER_PARSER_H #define SDB_PARSER_PARSER_H 1 -/* TODO: move SDB_PARSE_* constants here as well */ -#include "frontend/parser.h" - #include "core/store.h" #include "parser/ast.h" #include "utils/llist.h" @@ -40,6 +37,18 @@ extern "C" { #endif +/* parser modes */ +enum { + /* parser accepts any command statement */ + SDB_PARSE_DEFAULT = 0, + + /* parser accepts any conditional statement */ + SDB_PARSE_COND = 1 << 1, + + /* parser accepts any arithmetic expression */ + SDB_PARSE_ARITH = 1 << 2, +}; + /* * sdb_parser_parse: * Parse the specified query of the specified length. If len is a negative diff --git a/t/Makefile.am b/t/Makefile.am index 173cc8f..3faaf94 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -38,7 +38,6 @@ UNIT_TESTS = \ unit/core/store_test \ unit/core/time_test \ unit/frontend/connection_test \ - unit/frontend/parser_test \ unit/frontend/query_test \ unit/frontend/sock_test \ unit/parser/ast_test \ diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c deleted file mode 100644 index 65ec6ca..0000000 --- a/t/unit/frontend/parser_test.c +++ /dev/null @@ -1,971 +0,0 @@ -/* - * SysDB - t/unit/frontend/parser_test.c - * Copyright (C) 2013-2015 Sebastian 'tokkee' Harl - * 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. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#include "frontend/connection.h" -#include "frontend/parser.h" -#include "core/store-private.h" -#include "core/object.h" -#include "testutils.h" - -#include -#include - -/* - * tests - */ - -struct { - const char *query; - int len; - int expected; - sdb_conn_state_t expected_cmd; -} parse_data[] = { - /* empty commands */ - { NULL, -1, -1, 0 }, - { "", -1, 0, 0 }, - { ";", -1, 0, 0 }, - { ";;", -1, 0, 0 }, - - /* FETCH commands */ - { "FETCH host 'host'", -1, 1, SDB_CONNECTION_FETCH }, - { "FETCH host 'host' FILTER " - "age > 60s", -1, 1, SDB_CONNECTION_FETCH }, - { "FETCH service " - "'host'.'service'", -1, 1, SDB_CONNECTION_FETCH }, - { "FETCH metric " - "'host'.'metric'", -1, 1, SDB_CONNECTION_FETCH }, - - /* LIST commands */ - { "LIST hosts", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts -- foo", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts;", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts; INVALID", 11, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "age > 60s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "age > 60s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "age > 60s", -1, 1, SDB_CONNECTION_LIST }, - /* field access */ - { "LIST hosts FILTER " - "name = 'a'", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "last_update > 1s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "age > 120s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "interval > 10s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "backend = ['b']", -1, 1, SDB_CONNECTION_LIST }, - { "LIST hosts FILTER " - "value = 'a'", -1, -1, 0 }, - { "LIST hosts FILTER ANY " - "attribute.value = 'a'", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "name = 'a'", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "last_update > 1s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "age > 120s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "interval > 10s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "backend = ['b']", -1, 1, SDB_CONNECTION_LIST }, - { "LIST services FILTER " - "value = 'a'", -1, -1, 0 }, - { "LIST services FILTER ANY " - "attribute.value = 'a'", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "name = 'a'", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "last_update > 1s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "age > 120s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "interval > 10s", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "backend = ['b']", -1, 1, SDB_CONNECTION_LIST }, - { "LIST metrics FILTER " - "value = 'a'", -1, -1, 0 }, - { "LIST metrics FILTER ANY " - "attribute.value = 'a'", -1, 1, SDB_CONNECTION_LIST }, - - /* LOOKUP commands */ - { "LOOKUP hosts", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = 'host'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING NOT " - "name = 'host'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' AND " - "ANY service.name =~ 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING NOT " - "name =~ 'p' AND " - "ANY service.name =~ 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' AND " - "ANY service.name =~ 'p' OR " - "ANY service.name =~ 'r'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING NOT " - "name =~ 'p' AND " - "ANY service.name =~ 'p' OR " - "ANY service.name =~ 'r'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' " - "FILTER age > 1D", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' " - "FILTER age > 1D AND " - "interval < 240s" , -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' " - "FILTER NOT age>1D", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name =~ 'p' " - "FILTER age>" - "interval", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "host.name =~ 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP services", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP services MATCHING ANY " - "attribute.name =~ 'a'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP services MATCHING " - "host.name = 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP services MATCHING " - "service.name = 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP metrics", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP metrics MATCHING ANY " - "attribute.name =~ 'a'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP metrics MATCHING " - "host.name = 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP metrics MATCHING " - "metric.name = 'p'", -1, 1, SDB_CONNECTION_LOOKUP }, - - /* TIMESERIES commands */ - { "TIMESERIES 'host'.'metric' " - "START 2014-01-01 " - "END 2014-12-31 " - "23:59:59", -1, 1, SDB_CONNECTION_TIMESERIES }, - { "TIMESERIES 'host'.'metric' " - "START 2014-02-02 " - "14:02", -1, 1, SDB_CONNECTION_TIMESERIES }, - { "TIMESERIES 'host'.'metric' " - "END 2014-02-02", -1, 1, SDB_CONNECTION_TIMESERIES }, - { "TIMESERIES " - "'host'.'metric'", -1, 1, SDB_CONNECTION_TIMESERIES }, - - /* STORE commands */ - { "STORE host 'host'", -1, 1, SDB_CONNECTION_STORE_HOST }, - { "STORE host 'host' " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_HOST }, - { "STORE host attribute " - "'host'.'key' 123", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - { "STORE host attribute " - "'host'.'key' 123 " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - { "STORE service " - "'host'.'svc'", -1, 1, SDB_CONNECTION_STORE_SERVICE }, - { "STORE service " - "'host'.'svc' " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_SERVICE }, - { "STORE service attribute " - "'host'.'svc'.'key' " - "123", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - { "STORE service attribute " - "'host'.'svc'.'key' " - "123 " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - { "STORE metric " - "'host'.'metric'", -1, 1, SDB_CONNECTION_STORE_METRIC }, - { "STORE metric " - "'host'.'metric' " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_METRIC }, - { "STORE metric " - "'host'.'metric' " - "STORE 'typ' 'id' " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_METRIC }, - { "STORE metric attribute " - "'host'.'metric'.'key' " - "123", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - { "STORE metric attribute " - "'host'.'metric'.'key' " - "123 " - "LAST UPDATE " - "2015-02-01", -1, 1, SDB_CONNECTION_STORE_ATTRIBUTE }, - - /* string constants */ - { "LOOKUP hosts MATCHING " - "name = ''''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = '''foo'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = 'f''oo'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = 'foo'''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = '''", -1, -1, 0 }, - - /* numeric constants */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "1234", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] != " - "+234", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] < " - "-234", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] > " - "12.4", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] <= " - "12. + .3", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] <= " - "'f' || 'oo'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] >= " - ".4", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "+12e3", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "+12e-3", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "-12e+3", -1, 1, SDB_CONNECTION_LOOKUP }, - - /* date, time, interval constants */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "1 Y 42D", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "1s 42D", -1, 1, SDB_CONNECTION_LOOKUP }, - /* - * TODO: Something like 1Y42D should work as well but it doesn't since - * the scanner will tokenize it into {digit}{identifier} :-/ - * - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "1Y42D", -1, 1, SDB_CONNECTION_LOOKUP }, - */ - - /* array constants */ - { "LOOKUP hosts MATCHING " - "backend = ['foo']", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "backend = ['a','b']", -1, 1, SDB_CONNECTION_LOOKUP }, - - /* array iteration */ - { "LOOKUP hosts MATCHING " - "'foo' IN backend", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING 'foo' " - "NOT IN backend", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "['foo','bar'] " - "IN backend ", -1, 1, SDB_CONNECTION_LOOKUP }, - /* attribute type is unknown */ - { "LOOKUP hosts MATCHING " - "attribute['backend'] " - "IN backend ", -1, 1, SDB_CONNECTION_LOOKUP }, - /* type mismatch */ - { "LOOKUP hosts MATCHING " - "1 IN backend ", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "1 NOT IN backend ", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "ANY backend < 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend <= 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend = 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend != 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend >= 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend > 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend =~ 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY backend !~ 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - /* right operand is an array */ - { "LOOKUP hosts MATCHING " - "ANY backend !~ backend", - -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "ALL backend < 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend <= 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend = 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend != 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend >= 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend > 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend =~ 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ALL backend !~ 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, - /* attribute type is unknown */ - { "LOOKUP hosts MATCHING " - "ANY backend = attribute['backend']", - -1, 1, SDB_CONNECTION_LOOKUP }, - /* type mismatch */ - { "LOOKUP hosts MATCHING " - "ANY backend = 1", -1, -1, 0 }, - - /* valid operand types */ - { "LOOKUP hosts MATCHING " - "age * 1 > 0s", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "age / 1 > 0s", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name > ''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name >= ''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name != ''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name = ''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name <= ''", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "name < ''", -1, 1, SDB_CONNECTION_LOOKUP }, - - /* NULL */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] " - "IS NULL", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] " - "IS NOT NULL", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "NOT attribute['foo'] " - "IS NULL", -1, 1, SDB_CONNECTION_LOOKUP }, - { "LOOKUP hosts MATCHING " - "ANY service.name IS NULL", -1, -1, 0 }, - - /* invalid numeric constants */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "+-12e+3", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "-12e-+3", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "e+3", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "3e", -1, -1, 0 }, - /* following SQL standard, we don't support hex numbers */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "0x12", -1, -1, 0 }, - - /* invalid expressions */ - { "LOOKUP hosts MATCHING " - "attribute['foo'] = " - "1.23 + 'foo'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attr['foo'] = 1.23", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attr['foo'] IS NULL", -1, -1, 0 }, - - /* type mismatches */ - { "LOOKUP hosts MATCHING " - "age > 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "NOT age > 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age >= 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age = 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age != 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age <= 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age < 0", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age + 1 > 0s", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age - 1 > 0s", -1, -1, 0 }, - /* datetime integer is allowed */ - { "LOOKUP hosts MATCHING " - "age || 1 > 0s", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name + 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name - 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name * 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name / 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name % 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "(name % 1) + 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "1 + (name % 1) = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "'' = 1 + (name % 1)", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age > 0 AND " - "age = 0s", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "age = 0s AND " - "age > 0", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "host.name > 0", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "backend > 'b'", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "'b' > backend", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "attribute['a'] > backend", - -1, -1, 0 }, - { "LOOKUP services MATCHING " - "backend > attribute['a']", - -1, -1, 0 }, - { "LOOKUP services MATCHING " - "host.name + 1 = ''", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "'a' + 1 IN 'b'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "'a' IN 'b' - 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name + 1 IN 'b'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "'a' IN name - 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "'b' IN 'abc'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "1 IN age", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name =~ 'a' + 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name =~ name + 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name + 1 =~ 'a'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name =~ 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "name + 1 IS NULL", -1, -1, 0 }, - { "LOOKUP hosts FILTER " - "name + 1 IS NULL", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "ANY 'patt' =~ 'p'", -1, -1, 0 }, - - /* comments */ - { "/* some comment */", -1, 0, 0 }, - { "-- another comment", -1, 0, 0 }, - - /* syntax errors */ - { "INVALID", -1, -1, 0 }, - { "FETCH host", -1, -1, 0 }, - { "FETCH 'host'", -1, -1, 0 }, - { "LIST hosts; INVALID", -1, -1, 0 }, - { "/* some incomplete", -1, -1, 0 }, - - /* invalid LIST commands */ - { "LIST", -1, -1, 0 }, - { "LIST foo", -1, -1, 0 }, - { "LIST hosts MATCHING " - "name = 'host'", -1, -1, 0 }, - { "LIST foo FILTER " - "age > 60s", -1, -1, 0 }, - - /* invalid FETCH commands */ - { "FETCH host 'host' MATCHING " - "name = 'host'", -1, -1, 0 }, - { "FETCH service 'host'",-1, -1, 0 }, - { "FETCH metric 'host'", -1, -1, 0 }, - { "FETCH host " - "'host'.'localhost'", -1, -1, 0 }, - { "FETCH foo 'host'", -1, -1, 0 }, - { "FETCH foo 'host' FILTER " - "age > 60s", -1, -1, 0 }, - - /* invalid LOOKUP commands */ - { "LOOKUP foo", -1, -1, 0 }, - { "LOOKUP foo MATCHING " - "name = 'host'", -1, -1, 0 }, - { "LOOKUP foo FILTER " - "age > 60s", -1, -1, 0 }, - { "LOOKUP foo MATCHING " - "name = 'host' FILTER " - "age > 60s", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] <= " - "f || 'oo'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "attribute['foo'] <= " - "'f' || oo", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "ANY host.name = 'host'", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "ANY service.name > 1", -1, -1, 0 }, - { "LOOKUP hosts MATCHING " - "service.name = 's'", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "ANY host.name = 'host'", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "ANY service.name = 'svc'", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "ANY metric.name = 'm'", -1, -1, 0 }, - { "LOOKUP services MATCHING " - "metric.name = 'm'", -1, -1, 0 }, - { "LOOKUP metrics MATCHING " - "ANY host.name = 'host'", -1, -1, 0 }, - { "LOOKUP metrics MATCHING " - "ANY service.name = 'svc'", -1, -1, 0 }, - { "LOOKUP metrics MATCHING " - "ANY metric.name = 'm'", -1, -1, 0 }, - { "LOOKUP metrics MATCHING " - "service.name = 'm'", -1, -1, 0 }, - - /* invalid STORE commands */ - { "STORE host " - "'obj'.'host'", -1, -1, 0 }, - { "STORE host attribute " - ".'key' 123", -1, -1, 0 }, - { "STORE host attribute " - "'o'.'h'.'key' 123", -1, -1, 0 }, - { "STORE service 'svc'", -1, -1, 0 }, - { "STORE service " - "'host'.'svc' " - "STORE 'typ' 'id' " - "LAST UPDATE " - "2015-02-01", -1, -1, 0 }, - { "STORE service attribute " - "'svc'.'key' 123", -1, -1, 0 }, - { "STORE metric 'm'", -1, -1, 0 }, - { "STORE metric " - "'host'.'metric' " - "STORE 'typ'.'id' " - "LAST UPDATE " - "2015-02-01", -1, -1, 0 }, - { "STORE metric attribute " - "'metric'.'key' 123", -1, -1, 0 }, -}; - -START_TEST(test_parse) -{ - sdb_strbuf_t *errbuf = sdb_strbuf_create(64); - sdb_llist_t *check; - sdb_object_t *obj; - _Bool ok; - - check = sdb_fe_parse(parse_data[_i].query, - parse_data[_i].len, errbuf); - if (parse_data[_i].expected < 0) - ok = check == 0; - else - ok = sdb_llist_len(check) == (size_t)parse_data[_i].expected; - - fail_unless(ok, "sdb_fe_parse(%s) = %p (len: %zu); expected: %d " - "(parser error: %s)", parse_data[_i].query, check, - sdb_llist_len(check), parse_data[_i].expected, - sdb_strbuf_string(errbuf)); - - if (! check) { - sdb_strbuf_destroy(errbuf); - return; - } - - if ((! parse_data[_i].expected_cmd) - || (parse_data[_i].expected <= 0)) { - sdb_llist_destroy(check); - sdb_strbuf_destroy(errbuf); - return; - } - - obj = sdb_llist_get(check, 0); - fail_unless(SDB_CONN_NODE(obj)->cmd == parse_data[_i].expected_cmd, - "sdb_fe_parse(%s)->cmd = %i; expected: %d", - parse_data[_i].query, SDB_CONN_NODE(obj)->cmd, - parse_data[_i].expected_cmd); - - sdb_object_deref(obj); - sdb_llist_destroy(check); - sdb_strbuf_destroy(errbuf); -} -END_TEST - -struct { - const char *expr; - int len; - int expected; -} parse_matcher_data[] = { - /* empty expressions */ - { NULL, -1, -1 }, - { "", -1, -1 }, - - /* match hosts by name */ - { "name < 'localhost'", -1, MATCHER_LT }, - { "name <= 'localhost'", -1, MATCHER_LE }, - { "name = 'localhost'", -1, MATCHER_EQ }, - { "name != 'localhost'", -1, MATCHER_NE }, - { "name >= 'localhost'", -1, MATCHER_GE }, - { "name > 'localhost'", -1, MATCHER_GT }, - { "name =~ 'host'", -1, MATCHER_REGEX }, - { "name !~ 'host'", -1, MATCHER_NREGEX }, - { "name = 'localhost' -- foo", -1, MATCHER_EQ }, - { "name = 'host' ", 13, MATCHER_EQ }, - { "name &^ 'localhost'", -1, -1 }, - /* match by backend */ - { "ANY backend < 'be'", -1, MATCHER_ANY }, - { "ANY backend <= 'be'", -1, MATCHER_ANY }, - { "ANY backend = 'be'", -1, MATCHER_ANY }, - { "ANY backend != 'be'", -1, MATCHER_ANY }, - { "ANY backend >= 'be'", -1, MATCHER_ANY }, - { "ANY backend > 'be'", -1, MATCHER_ANY }, - { "ALL backend < 'be'", -1, MATCHER_ALL }, - { "ALL backend <= 'be'", -1, MATCHER_ALL }, - { "ALL backend = 'be'", -1, MATCHER_ALL }, - { "ALL backend != 'be'", -1, MATCHER_ALL }, - { "ALL backend >= 'be'", -1, MATCHER_ALL }, - { "ALL backend > 'be'", -1, MATCHER_ALL }, - { "ANY backend &^ 'be'", -1, -1 }, - /* match hosts by service */ - { "ANY service.name < 'name'", -1, MATCHER_ANY }, - { "ANY service.name <= 'name'", -1, MATCHER_ANY }, - { "ANY service.name = 'name'", -1, MATCHER_ANY }, - { "ANY service.name != 'name'", -1, MATCHER_ANY }, - { "ANY service.name >= 'name'", -1, MATCHER_ANY }, - { "ANY service.name > 'name'", -1, MATCHER_ANY }, - { "ANY service.name =~ 'pattern'", -1, MATCHER_ANY }, - { "ANY service.name !~ 'pattern'", -1, MATCHER_ANY }, - { "ANY service.name &^ 'name'", -1, -1 }, - { "ALL service.name < 'name'", -1, MATCHER_ALL }, - { "ALL service.name <= 'name'", -1, MATCHER_ALL }, - { "ALL service.name = 'name'", -1, MATCHER_ALL }, - { "ALL service.name != 'name'", -1, MATCHER_ALL }, - { "ALL service.name >= 'name'", -1, MATCHER_ALL }, - { "ALL service.name > 'name'", -1, MATCHER_ALL }, - { "ALL service.name =~ 'pattern'", -1, MATCHER_ALL }, - { "ALL service.name !~ 'pattern'", -1, MATCHER_ALL }, - { "ALL service.name &^ 'name'", -1, -1 }, - { "ANY service < 'name'", -1, -1 }, - /* match hosts by metric */ - { "ANY metric.name < 'name'", -1, MATCHER_ANY }, - { "ANY metric.name <= 'name'", -1, MATCHER_ANY }, - { "ANY metric.name = 'name'", -1, MATCHER_ANY }, - { "ANY metric.name != 'name'", -1, MATCHER_ANY }, - { "ANY metric.name >= 'name'", -1, MATCHER_ANY }, - { "ANY metric.name > 'name'", -1, MATCHER_ANY }, - { "ANY metric.name =~ 'pattern'", -1, MATCHER_ANY }, - { "ANY metric.name !~ 'pattern'", -1, MATCHER_ANY }, - { "ANY metric.name &^ 'pattern'", -1, -1 }, - { "ALL metric.name < 'name'", -1, MATCHER_ALL }, - { "ALL metric.name <= 'name'", -1, MATCHER_ALL }, - { "ALL metric.name = 'name'", -1, MATCHER_ALL }, - { "ALL metric.name != 'name'", -1, MATCHER_ALL }, - { "ALL metric.name >= 'name'", -1, MATCHER_ALL }, - { "ALL metric.name > 'name'", -1, MATCHER_ALL }, - { "ALL metric.name =~ 'pattern'", -1, MATCHER_ALL }, - { "ALL metric.name !~ 'pattern'", -1, MATCHER_ALL }, - { "ALL metric.name &^ 'pattern'", -1, -1 }, - { "ANY metric <= 'name'", -1, -1 }, - /* match hosts by attribute */ - { "ANY attribute.name < 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name <= 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name = 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name != 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name >= 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name > 'name'", -1, MATCHER_ANY }, - { "ANY attribute.name =~ 'pattern'", -1, MATCHER_ANY }, - { "ANY attribute.name !~ 'pattern'", -1, MATCHER_ANY }, - { "ANY attribute.name &^ 'pattern'", -1, -1 }, - { "ALL attribute.name < 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name <= 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name = 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name != 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name >= 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name > 'name'", -1, MATCHER_ALL }, - { "ALL attribute.name =~ 'pattern'", -1, MATCHER_ALL }, - { "ALL attribute.name !~ 'pattern'", -1, MATCHER_ALL }, - { "ALL attribute.name &^ 'pattern'", -1, -1 }, - { "ANY attribute !~ 'pattern'", -1, -1 }, - /* composite expressions */ - { "name =~ 'pattern' AND " - "ANY service.name =~ 'pattern'", -1, MATCHER_AND }, - { "name =~ 'pattern' OR " - "ANY service.name =~ 'pattern'", -1, MATCHER_OR }, - { "NOT name = 'host'", -1, MATCHER_NOT }, - /* numeric expressions */ - { "attribute['foo'] < 123", -1, MATCHER_LT }, - { "attribute['foo'] <= 123", -1, MATCHER_LE }, - { "attribute['foo'] = 123", -1, MATCHER_EQ }, - { "attribute['foo'] >= 123", -1, MATCHER_GE }, - { "attribute['foo'] > 123", -1, MATCHER_GT }, - /* datetime expressions */ - { "attribute['foo'] = " - "2014-08-16", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "17:23", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "17:23:53", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "17:23:53.123", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "17:23:53.123456789", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "2014-08-16 17:23", -1, MATCHER_EQ }, - { "attribute['foo'] = " - "2014-08-16 17:23:53", -1, MATCHER_EQ }, - /* NULL; while this is an implementation detail, - * IS NULL currently maps to an equality matcher */ - { "attribute['foo'] IS NULL", -1, MATCHER_ISNULL }, - { "attribute['foo'] IS NOT NULL", -1, MATCHER_ISNNULL }, - /* array expressions */ - { "backend < ['a']", -1, MATCHER_LT }, - { "backend <= ['a']", -1, MATCHER_LE }, - { "backend = ['a']", -1, MATCHER_EQ }, - { "backend != ['a']", -1, MATCHER_NE }, - { "backend >= ['a']", -1, MATCHER_GE }, - { "backend > ['a']", -1, MATCHER_GT }, - { "backend &^ ['a']", -1, -1 }, - - /* object field matchers */ - { "name < 'a'", -1, MATCHER_LT }, - { "name <= 'a'", -1, MATCHER_LE }, - { "name = 'a'", -1, MATCHER_EQ }, - { "name != 'a'", -1, MATCHER_NE }, - { "name >= 'a'", -1, MATCHER_GE }, - { "name > 'a'", -1, MATCHER_GT }, - { "last_update < 2014-10-01", -1, MATCHER_LT }, - { "last_update <= 2014-10-01", -1, MATCHER_LE }, - { "last_update = 2014-10-01", -1, MATCHER_EQ }, - { "last_update != 2014-10-01", -1, MATCHER_NE }, - { "last_update >= 2014-10-01", -1, MATCHER_GE }, - { "last_update > 2014-10-01", -1, MATCHER_GT }, - { "Last_Update >= 24D", -1, MATCHER_GE }, - { "age < 20s", -1, MATCHER_LT }, - { "age <= 20s", -1, MATCHER_LE }, - { "age = 20s", -1, MATCHER_EQ }, - { "age != 20s", -1, MATCHER_NE }, - { "age >= 20s", -1, MATCHER_GE }, - { "age > 20s", -1, MATCHER_GT }, - { "AGE <= 1m", -1, MATCHER_LE }, - { "age > 1M", -1, MATCHER_GT }, - { "age != 20Y", -1, MATCHER_NE }, - { "age <= 2 * interval", -1, MATCHER_LE }, - { "interval < 20s", -1, MATCHER_LT }, - { "interval <= 20s", -1, MATCHER_LE }, - { "interval = 20s", -1, MATCHER_EQ }, - { "interval != 20s", -1, MATCHER_NE }, - { "interval >= 20s", -1, MATCHER_GE }, - { "interval > 20s", -1, MATCHER_GT }, - { "'be' IN backend", -1, MATCHER_IN }, - { "'be' NOT IN backend", -1, MATCHER_NIN }, - { "['a','b'] IN backend", -1, MATCHER_IN }, - { "['a','b'] NOT IN backend", -1, MATCHER_NIN }, - - /* check operator precedence */ - { "name = 'name' OR " - "ANY service.name = 'name' AND " - "ANY attribute.name = 'name' OR " - "attribute['foo'] = 'bar'", -1, MATCHER_OR }, - { "name = 'name' AND " - "ANY service.name = 'name' AND " - "ANY attribute.name = 'name' OR " - "attribute['foo'] = 'bar'", -1, MATCHER_OR }, - { "name = 'name' AND " - "ANY service.name = 'name' OR " - "ANY attribute.name = 'name' AND " - "attribute['foo'] = 'bar'", -1, MATCHER_OR }, - { "(name = 'name' OR " - "ANY service.name = 'name') AND " - "(ANY attribute.name = 'name' OR " - "attribute['foo'] = 'bar')", -1, MATCHER_AND }, - { "NOT name = 'name' OR " - "ANY service.name = 'name'", -1, MATCHER_OR }, - { "NOT name = 'name' OR " - "NOT ANY service.name = 'name'", -1, MATCHER_OR }, - { "NOT (name = 'name' OR " - "NOT ANY service.name = 'name')", -1, MATCHER_NOT }, - - /* syntax errors */ - { "LIST", -1, -1 }, - { "foo &^ bar", -1, -1 }, - { "invalid", -1, -1 }, -}; - -START_TEST(test_parse_matcher) -{ - sdb_strbuf_t *errbuf = sdb_strbuf_create(64); - sdb_store_matcher_t *m; - - m = sdb_fe_parse_matcher(parse_matcher_data[_i].expr, - parse_matcher_data[_i].len, errbuf); - - if (parse_matcher_data[_i].expected < 0) { - fail_unless(m == NULL, - "sdb_fe_parse_matcher(%s) = %p; expected: NULL", - parse_matcher_data[_i].expr, m); - sdb_object_deref(SDB_OBJ(m)); - sdb_strbuf_destroy(errbuf); - return; - } - - fail_unless(m != NULL, "sdb_fe_parse_matcher(%s) = NULL; " - "expected: (parser error: %s)", - parse_matcher_data[_i].expr, sdb_strbuf_string(errbuf)); - fail_unless(M(m)->type == parse_matcher_data[_i].expected, - "sdb_fe_parse_matcher(%s) returned matcher of type %d; " - "expected: %d", parse_matcher_data[_i].expr, M(m)->type, - parse_matcher_data[_i].expected); - - sdb_object_deref(SDB_OBJ(m)); - sdb_strbuf_destroy(errbuf); -} -END_TEST - -struct { - const char *expr; - int len; - int expected; -} parse_expr_data[] = { - /* empty expressions */ - { NULL, -1, INT_MAX }, - { "", -1, INT_MAX }, - - /* constant expressions */ - { "'localhost'", -1, 0 }, - { "123", -1, 0 }, - { "2014-08-16", -1, 0 }, - { "17:23", -1, 0 }, - { "17:23:53", -1, 0 }, - { "17:23:53.123", -1, 0 }, - { "17:23:53.123456789", -1, 0 }, - { "2014-08-16 17:23", -1, 0 }, - { "2014-08-16 17:23:53", -1, 0 }, - { "10s", -1, 0 }, - { "60m", -1, 0 }, - { "10Y 24D 1h", -1, 0 }, - - { "123 + 456", -1, 0 }, - { "'foo' || 'bar'", -1, 0 }, - { "456 - 123", -1, 0 }, - { "1.2 * 3.4", -1, 0 }, - { "1.2 / 3.4", -1, 0 }, - { "5 % 2", -1, 0 }, - - /* queryable fields */ - { "last_update", -1, FIELD_VALUE }, - { "AGE", -1, FIELD_VALUE }, - { "interval", -1, FIELD_VALUE }, - { "Last_Update", -1, FIELD_VALUE }, - { "backend", -1, FIELD_VALUE }, - - /* attributes */ - { "attribute['foo']", -1, ATTR_VALUE }, - - /* arithmetic expressions */ - { "age + age", -1, SDB_DATA_ADD }, - { "age - age", -1, SDB_DATA_SUB }, - { "age * age", -1, SDB_DATA_MUL }, - { "age / age", -1, SDB_DATA_DIV }, - { "age % age", -1, SDB_DATA_MOD }, - { "age || age", -1, SDB_DATA_CONCAT }, - - /* operator precedence */ - { "age + age * age", -1, SDB_DATA_ADD }, - { "age * age + age", -1, SDB_DATA_ADD }, - { "age + age - age", -1, SDB_DATA_SUB }, - { "age - age + age", -1, SDB_DATA_ADD }, - { "(age + age) * age", -1, SDB_DATA_MUL }, - { "age + (age * age)", -1, SDB_DATA_ADD }, - - /* syntax errors */ - { "LIST", -1, INT_MAX }, - { "foo &^ bar", -1, INT_MAX }, - { "invalid", -1, INT_MAX }, -}; - -START_TEST(test_parse_expr) -{ - sdb_strbuf_t *errbuf = sdb_strbuf_create(64); - sdb_store_expr_t *e; - - e = sdb_fe_parse_expr(parse_expr_data[_i].expr, - parse_expr_data[_i].len, errbuf); - - if (parse_expr_data[_i].expected == INT_MAX) { - fail_unless(e == NULL, - "sdb_fe_parse_expr(%s) = %p; expected: NULL", - parse_expr_data[_i].expr, e); - sdb_object_deref(SDB_OBJ(e)); - sdb_strbuf_destroy(errbuf); - return; - } - - fail_unless(e != NULL, "sdb_fe_parse_expr(%s) = NULL; " - "expected: (parser error: %s)", - parse_expr_data[_i].expr, sdb_strbuf_string(errbuf)); - fail_unless(e->type == parse_expr_data[_i].expected, - "sdb_fe_parse_expr(%s) returned expression of type %d; " - "expected: %d", parse_expr_data[_i].expr, e->type, - parse_expr_data[_i].expected); - - sdb_object_deref(SDB_OBJ(e)); - sdb_strbuf_destroy(errbuf); -} -END_TEST - -TEST_MAIN("frontend::parser") -{ - TCase *tc = tcase_create("core"); - TC_ADD_LOOP_TEST(tc, parse); - TC_ADD_LOOP_TEST(tc, parse_matcher); - TC_ADD_LOOP_TEST(tc, parse_expr); - ADD_TCASE(tc); -} -TEST_MAIN_END - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - -- 2.30.2