Code

frontend: Added 'FILTER' support to the 'LOOKUP' command.
authorSebastian Harl <sh@tokkee.org>
Wed, 30 Jul 2014 19:02:35 +0000 (21:02 +0200)
committerSebastian Harl <sh@tokkee.org>
Wed, 30 Jul 2014 19:02:35 +0000 (21:02 +0200)
The new syntax is 'LOOKUP <obj> MATCHING <cond> [FILTER <cond>]'.

src/frontend/connection-private.h
src/frontend/grammar.y
src/frontend/query.c
src/frontend/scanner.l
t/integration/simple_query.sh
t/unit/frontend/parser_test.c

index ae9cbbc91ba0cfa2dd532cb55795de95164a96fe..1d4e019a01fe45db4d464c9bd387a2258d04b83d 100644 (file)
@@ -88,12 +88,13 @@ typedef struct {
 typedef struct {
        sdb_conn_node_t super;
        sdb_store_matcher_t *matcher;
 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;
 
 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))
 
 } 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)->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
 } /* conn_lookup_destroy */
 
 #ifdef __cplusplus
index 57174290b00dc97c00aa50d9e1d6841ff45f3dad..92bfd1f5c60d2ab24d5e0b6f82b90e7e4ce73c71 100644 (file)
@@ -82,7 +82,7 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
 
 %token SCANNER_ERROR
 
 
 %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
 %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 <type> MATCHING <condition>;
+ * LOOKUP <type> MATCHING <condition> [FILTER <condition>];
  *
  * Returns detailed information about <type> matching condition.
  */
  *
  * Returns detailed information about <type> matching condition.
  */
@@ -253,6 +253,27 @@ lookup_statement:
                        $$->cmd = CONNECTION_LOOKUP;
                        free($2); $2 = NULL;
                }
                        $$->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:
        ;
 
 condition:
@@ -266,7 +287,7 @@ condition:
                        }
 
                        $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
                        }
 
                        $$ = 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;
                }
                        $$->cmd = CONNECTION_EXPR;
                        CONN_MATCHER($$)->matcher = $1;
                }
index d83ffd82ca76ab34bd03d0a18359baeaab194c1c..6fa2a619dcaa3d635dc3201b5cbe85f6698c0139 100644 (file)
@@ -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:
                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);
 
                default:
                        sdb_log(SDB_LOG_ERR, "frontend: Unknown command %i", node->cmd);
index f70f60f84dab33618a7ae84a67771ec33e0a022f..4bd5655e04bd9d870ccadcafa5da15d9c7c3ba74 100644 (file)
@@ -50,6 +50,7 @@ static struct {
 } reserved_words[] = {
        { "AND",      AND },
        { "FETCH",    FETCH },
 } reserved_words[] = {
        { "AND",      AND },
        { "FETCH",    FETCH },
+       { "FILTER",   FILTER },
        { "IS",       IS },
        { "LIST",     LIST },
        { "LOOKUP",   LOOKUP },
        { "IS",       IS },
        { "LIST",     LIST },
        { "LOOKUP",   LOOKUP },
index 8f9e3753fa7924d4cae67127a098201ee3d02269..86ac03fd80962dae080dc08c7425ee4319f172c3 100755 (executable)
@@ -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
 
 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"'
 output="$( run_sysdb -H "$SOCKET_FILE" \
        -c "LOOKUP hosts MATCHING service = 'sysdbd'" )"
 echo "$output" | grep -F '"localhost"'
index a0826070ed958a6e864998af1eecf3890e944906..a10185469f2397accd253425025dbf9fe097c62c 100644 (file)
@@ -76,6 +76,16 @@ START_TEST(test_parse)
                  "host =~ 'p' AND "
                  "service =~ 'p' OR "
                  "service =~ 'r'",      -1,  1, CONNECTION_LOOKUP },
                  "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 "
 
                /* 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 },
 
                { "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 "
                /* check operator precedence */
                { "host = 'name' OR "
                  "service = 'name' AND "