From 3f0db5bd32f136de9e7cfa8250f0c20469261241 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 30 Jul 2014 21:02:35 +0200 Subject: [PATCH] frontend: Added 'FILTER' support to the 'LOOKUP' command. The new syntax is 'LOOKUP MATCHING [FILTER ]'. --- src/frontend/connection-private.h | 9 ++++++--- src/frontend/grammar.y | 27 ++++++++++++++++++++++++--- src/frontend/query.c | 10 ++++++++-- src/frontend/scanner.l | 1 + t/integration/simple_query.sh | 15 +++++++++++++++ t/unit/frontend/parser_test.c | 19 +++++++++++++++++++ 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/frontend/connection-private.h b/src/frontend/connection-private.h index ae9cbbc..1d4e019 100644 --- a/src/frontend/connection-private.h +++ b/src/frontend/connection-private.h @@ -88,12 +88,13 @@ typedef struct { typedef struct { sdb_conn_node_t super; sdb_store_matcher_t *matcher; -} conn_node_matcher_t; -#define CONN_MATCHER(obj) ((conn_node_matcher_t *)(obj)) +} conn_matcher_t; +#define CONN_MATCHER(obj) ((conn_matcher_t *)(obj)) typedef struct { sdb_conn_node_t super; - conn_node_matcher_t *matcher; + conn_matcher_t *matcher; + conn_matcher_t *filter; } conn_lookup_t; #define CONN_LOOKUP(obj) ((conn_lookup_t *)(obj)) @@ -119,6 +120,8 @@ conn_lookup_destroy(sdb_object_t *obj) { if (CONN_LOOKUP(obj)->matcher) sdb_object_deref(SDB_OBJ(CONN_LOOKUP(obj)->matcher)); + if (CONN_LOOKUP(obj)->filter) + sdb_object_deref(SDB_OBJ(CONN_LOOKUP(obj)->filter)); } /* conn_lookup_destroy */ #ifdef __cplusplus diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 5717429..92bfd1f 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -82,7 +82,7 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %token SCANNER_ERROR -%token AND OR IS NOT MATCHING +%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 %token CONCAT @@ -229,7 +229,7 @@ list_statement: ; /* - * LOOKUP MATCHING ; + * LOOKUP MATCHING [FILTER ]; * * Returns detailed information about matching condition. */ @@ -253,6 +253,27 @@ lookup_statement: $$->cmd = CONNECTION_LOOKUP; free($2); $2 = NULL; } + | + LOOKUP IDENTIFIER MATCHING condition FILTER condition + { + /* TODO: support other types as well */ + if (strcasecmp($2, "hosts")) { + char errmsg[strlen($2) + 32]; + snprintf(errmsg, sizeof(errmsg), + YY_("unknown table %s"), $2); + sdb_fe_yyerror(&yylloc, scanner, errmsg); + free($2); $2 = NULL; + sdb_object_deref(SDB_OBJ($4)); + YYABORT; + } + + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_lookup_t, conn_lookup_destroy)); + CONN_LOOKUP($$)->matcher = CONN_MATCHER($4); + CONN_LOOKUP($$)->filter = CONN_MATCHER($6); + $$->cmd = CONNECTION_LOOKUP; + free($2); $2 = NULL; + } ; condition: @@ -266,7 +287,7 @@ condition: } $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_node_matcher_t, conn_matcher_destroy)); + conn_matcher_t, conn_matcher_destroy)); $$->cmd = CONNECTION_EXPR; CONN_MATCHER($$)->matcher = $1; } diff --git a/src/frontend/query.c b/src/frontend/query.c index d83ffd8..6fa2a61 100644 --- a/src/frontend/query.c +++ b/src/frontend/query.c @@ -79,8 +79,14 @@ sdb_fe_exec(sdb_conn_t *conn, sdb_conn_node_t *node) case CONNECTION_LIST: return sdb_fe_list(conn, /* filter = */ NULL); case CONNECTION_LOOKUP: - return sdb_fe_lookup(conn, CONN_LOOKUP(node)->matcher->matcher, - /* filter = */ NULL); + { + sdb_store_matcher_t *m = NULL, *filter = NULL; + if (CONN_LOOKUP(node)->matcher) + m = CONN_LOOKUP(node)->matcher->matcher; + if (CONN_LOOKUP(node)->filter) + filter = CONN_LOOKUP(node)->filter->matcher; + return sdb_fe_lookup(conn, m, filter); + } default: sdb_log(SDB_LOG_ERR, "frontend: Unknown command %i", node->cmd); diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index f70f60f..4bd5655 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -50,6 +50,7 @@ static struct { } reserved_words[] = { { "AND", AND }, { "FETCH", FETCH }, + { "FILTER", FILTER }, { "IS", IS }, { "LIST", LIST }, { "LOOKUP", LOOKUP }, diff --git a/t/integration/simple_query.sh b/t/integration/simple_query.sh index 8f9e375..86ac03f 100755 --- a/t/integration/simple_query.sh +++ b/t/integration/simple_query.sh @@ -106,6 +106,21 @@ echo "$output" | grep -F 'other.host.name' && exit 1 echo "$output" | grep -F 'host1.example.com' && exit 1 echo "$output" | grep -F 'host2.example.com' && exit 1 +output="$( run_sysdb -H "$SOCKET_FILE" \ + -c "LOOKUP hosts MATCHING attribute != 'architecture' + FILTER :age >= 0s" )" +echo "$output" \ + | grep -F '"some.host.name"' \ + | grep -F '"localhost"' +echo "$output" | grep -F 'other.host.name' && exit 1 +echo "$output" | grep -F 'host1.example.com' && exit 1 +echo "$output" | grep -F 'host2.example.com' && exit 1 + +output="$( run_sysdb -H "$SOCKET_FILE" \ + -c "LOOKUP hosts MATCHING attribute != 'architecture' + FILTER :last_update < 2Y" )" +echo $output | grep -E '^\[\]$' + output="$( run_sysdb -H "$SOCKET_FILE" \ -c "LOOKUP hosts MATCHING service = 'sysdbd'" )" echo "$output" | grep -F '"localhost"' diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index a082607..a101854 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -76,6 +76,16 @@ START_TEST(test_parse) "host =~ 'p' AND " "service =~ 'p' OR " "service =~ 'r'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts MATCHING " + "host =~ 'p' " + "FILTER :age > 1D", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts MATCHING " + "host =~ 'p' " + "FILTER :age > 1D AND " + ":interval < 240s" , -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts MATCHING " + "host =~ 'p' " + "FILTER NOT :age>1D", -1, 1, CONNECTION_LOOKUP }, /* numeric constants */ { "LOOKUP hosts MATCHING " @@ -257,6 +267,15 @@ START_TEST(test_parse_matcher) { "attribute.foo IS NULL", -1, MATCHER_ISNULL }, { "attribute.foo IS NOT NULL", -1, MATCHER_NOT }, + /* object field matchers */ + { ":last_update < 10s", -1, MATCHER_LT }, + { ":AGE <= 1m", -1, MATCHER_LE }, + { ":interval = 10h", -1, MATCHER_EQ }, + { ":Last_Update >= 24D", -1, MATCHER_GE }, + { ":age > 1M", -1, MATCHER_GT }, + { ":age != 20Y", -1, MATCHER_NOT }, + { ":backend != 'be'", -1, MATCHER_NOT }, + /* check operator precedence */ { "host = 'name' OR " "service = 'name' AND " -- 2.30.2