summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5ced2b9)
raw | patch | inline | side by side (parent: 5ced2b9)
author | Sebastian Harl <sh@tokkee.org> | |
Tue, 19 May 2015 18:10:22 +0000 (20:10 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Tue, 19 May 2015 18:10:22 +0000 (20:10 +0200) |
It's fully replaced by the new parser module now.
src/Makefile.am | patch | blob | history | |
src/frontend/analyzer.c | [deleted file] | patch | blob | history |
src/frontend/grammar.y | [deleted file] | patch | blob | history |
src/frontend/parser.c | [deleted file] | patch | blob | history |
src/frontend/scanner.l | [deleted file] | patch | blob | history |
src/include/frontend/parser.h | [deleted file] | patch | blob | history |
src/include/parser/parser.h | patch | blob | history | |
t/Makefile.am | patch | blob | history | |
t/unit/frontend/parser_test.c | [deleted file] | patch | blob | history |
diff --git a/src/Makefile.am b/src/Makefile.am
index 48561c344ac23664299cedb2a65a7b59688526eb..0dbd1511cf58321432a1b55ee21e2d06b61b01f2 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
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
pkgfeincludedir = $(pkgincludedir)/frontend
pkgfeinclude_HEADERS = \
include/frontend/connection.h \
- include/frontend/parser.h \
include/frontend/proto.h \
include/frontend/sock.h
pkgutilsincludedir = $(pkgincludedir)/utils
# 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)\""
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
--- a/src/frontend/analyzer.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * SysDB - src/frontend/analyzer.c
- * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "sysdb.h"
-
-#include "core/store-private.h"
-#include "frontend/connection-private.h"
-#include "frontend/parser.h"
-#include "utils/error.h"
-#include "utils/strbuf.h"
-
-#include <assert.h>
-
-/*
- * 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
--- a/src/frontend/grammar.y
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * SysDB - src/frontend/grammar.y
- * Copyright (C) 2013 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 "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 <assert.h>
-
-#include <stdio.h>
-#include <string.h>
-
-/*
- * 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 <str> IDENTIFIER STRING
-
-%token <data> INTEGER FLOAT
-
-%token <datetime> 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 <list> statements
-%type <node> statement
- fetch_statement
- list_statement
- lookup_statement
- store_statement
- timeseries_statement
- matching_clause
- filter_clause
- condition
-
-%type <m> matcher
- compare_matcher
-
-%type <expr> expression arithmetic_expression object_expression
-
-%type <integer> object_type object_type_plural
-%type <integer> field
-
-%type <sstr> cmp
-
-%type <data> data
- interval interval_elem
- array array_elem_list
-
-%type <datetime> datetime
- start_clause end_clause
- last_update_clause
-
-%type <metric_store> metric_store_clause
-
-%destructor { free($$); } <str>
-%destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
-%destructor { sdb_data_free_datum(&$$); } <data>
-
-%%
-
-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 <type> <hostname> [FILTER <condition>];
- *
- * 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 <type> [FILTER <condition>];
- *
- * 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 <type> MATCHING <condition> [FILTER <condition>];
- *
- * Returns detailed information about <type> 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 <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
- * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
- * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
- *
- * 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 <host>.<metric> [START <datetime>] [END <datetime>];
- *
- * 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
--- a/src/frontend/parser.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * SysDB - src/frontend/parser.c
- * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "sysdb.h"
-
-#include "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 <assert.h>
-#include <string.h>
-
-/*
- * 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
--- a/src/frontend/scanner.l
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * SysDB - src/frontend/scanner.l
- * Copyright (C) 2013 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.
- */
-
-%{
-
-#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 <assert.h>
-#include <errno.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <time.h>
-
-#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>{csc_inside} { /* ignore */ }
-<CSC>{csc_end} { BEGIN(INITIAL); }
-<CSC><<EOF>> {
- 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
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SysDB - src/include/frontend/parser.h
- * Copyright (C) 2013 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.
- */
-
-#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 : */
-
index 92e49bbd39c5db674f5208c6259baffe5037e2d8..2830663f03d8f13843eaa7543e1c18c50ebeccc5 100644 (file)
#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"
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 173cc8fbb2ecee6cfc0b725e0e704ae8d3d83f8c..3faaf94e89d6d27dcbe5c894678da13c87009a2f 100644 (file)
--- a/t/Makefile.am
+++ b/t/Makefile.am
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
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * SysDB - t/unit/frontend/parser_test.c
- * Copyright (C) 2013-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.
- */
-
-#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 <check.h>
-#include <limits.h>
-
-/*
- * 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 <mul/div> 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' <garbage>", 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: <matcher> (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: <expr> (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 : */
-