Code

query language: Change iterator syntax to ANY/ALL <iter>.<field> <op> <v>.
authorSebastian Harl <sh@tokkee.org>
Sat, 7 Mar 2015 13:14:56 +0000 (14:14 +0100)
committerSebastian Harl <sh@tokkee.org>
Sat, 7 Mar 2015 13:14:56 +0000 (14:14 +0100)
That is, make it explicit that iterators access the object name and make it
easier to support other fields as well.

src/frontend/grammar.y
t/integration/filter.sh
t/integration/matching.sh
t/unit/core/store_lookup_test.c
t/unit/frontend/parser_test.c

index e36df3b490abc041421c617f11a80b1df1b03313..4021031d4e8f3dd29e39e03634decfe98e1b22cc 100644 (file)
@@ -684,11 +684,11 @@ object_type_plural:
        ;
 
 iterable:
-       SERVICE_T { $$ = SDB_SERVICE; }
+       SERVICE_T '.' NAME_T { $$ = SDB_SERVICE; }
        |
-       METRIC_T { $$ = SDB_METRIC; }
+       METRIC_T '.' NAME_T { $$ = SDB_METRIC; }
        |
-       ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; }
+       ATTRIBUTE_T '.' NAME_T { $$ = SDB_ATTRIBUTE; }
        |
        BACKEND_T { $$ = SDB_FIELD_BACKEND; }
        ;
index ddcf78532bbee17d85852c367b95f0155a15ab14..9738fa6d59749a2b390256b26ceb1217058c98c1 100755 (executable)
@@ -49,7 +49,7 @@ wait_for_sysdbd
 sleep 3
 
 output="$( run_sysdb -H "$SOCKET_FILE" \
-       -c "LOOKUP hosts MATCHING ANY attribute != 'architecture' 
+       -c "LOOKUP hosts MATCHING ANY attribute.name != 'architecture'
                FILTER age >= 0s" )"
 echo "$output" \
        | grep -F '"localhost"'
@@ -59,7 +59,7 @@ echo "$output" | grep -F 'some.host.name' && exit 1
 #echo "$output" | grep -F 'host2.example.com' && exit 1
 
 output="$( run_sysdb -H "$SOCKET_FILE" \
-       -c "LOOKUP hosts MATCHING ANY attribute != 'architecture' 
+       -c "LOOKUP hosts MATCHING ANY attribute.name != 'architecture'
                FILTER last_update < 2Y" )"
 echo $output | grep -E '^\[\]$'
 
index 34e7c549b9005a067bb9f643981e749089614f03..95dea02147d903f21c3ecc07afc3802aba9f94ec 100755 (executable)
@@ -49,7 +49,7 @@ wait_for_sysdbd
 sleep 3
 
 output="$( run_sysdb -H "$SOCKET_FILE" \
-       -c "LOOKUP hosts MATCHING ANY metric = 'foo/bar/qux'" )"
+       -c "LOOKUP hosts MATCHING ANY metric.name = 'foo/bar/qux'" )"
 echo "$output" \
        | grep -F '"some.host.name"' \
        | grep -F '"other.host.name"'
@@ -58,7 +58,7 @@ 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 ANY service = 'mock service'" )"
+       -c "LOOKUP hosts MATCHING ANY service.name = 'mock service'" )"
 echo "$output" \
        | grep -F '"some.host.name"' \
        | grep -F '"host1.example.com"' \
@@ -76,7 +76,7 @@ echo "$output" | grep -F 'other.host.name' && exit 1
 echo "$output" | grep -F 'some.host.name' && exit 1
 
 output="$( run_sysdb -H "$SOCKET_FILE" \
-       -c "LOOKUP hosts MATCHING ANY attribute != 'architecture'" )"
+       -c "LOOKUP hosts MATCHING ANY attribute.name != 'architecture'" )"
 echo "$output" \
        | grep -F '"localhost"' \
        | grep -F '"other.host.name"' \
@@ -85,7 +85,7 @@ echo "$output" \
 echo "$output" | grep -F 'some.host.name' && exit 1
 
 output="$( run_sysdb -H "$SOCKET_FILE" \
-       -c "LOOKUP hosts MATCHING ALL attribute != 'architecture'" )"
+       -c "LOOKUP hosts MATCHING ALL attribute.name != 'architecture'" )"
 echo "$output" \
        | grep -F '"some.host.name"' \
        | grep -F '"localhost"'
@@ -94,7 +94,7 @@ 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 ANY service = 'sysdbd'" )"
+       -c "LOOKUP hosts MATCHING ANY service.name = 'sysdbd'" )"
 echo "$output" | grep -F '"localhost"'
 echo "$output" | grep -F 'some.host.name' && exit 1
 echo "$output" | grep -F 'other.host.name' && exit 1
index c55184f63670bc00c85b48ffadf4f8f6a1501789..f202c6ba463ffd291f8da2b6a95071b6ca2a6c07 100644 (file)
@@ -511,56 +511,56 @@ struct {
        int expected;
 } scan_data[] = {
        /* TODO: check the name of the expected hosts */
-       { "name = 'a'", NULL,                  1 },
-       { "name = 'a'", "name = 'x'",          0 }, /* filter never matches */
+       { "name = 'a'", NULL,                        1 },
+       { "name = 'a'", "name = 'x'",                0 }, /* filter never matches */
        { "name = 'a'",
-               "NOT attribute['x'] = ''",         1 }, /* filter always matches */
-       { "name =~ 'a|b'", NULL,               2 },
-       { "name =~ 'host'", NULL,              0 },
-       { "name =~ '.'", NULL,                 3 },
-       { "ANY backend = 'backend'", NULL,     0 },
-       { "ALL backend = ''", NULL,            3 }, /* backend is empty */
-       { "backend = ['backend']", NULL,       0 },
-       { "backend != ['backend']", NULL,      3 },
-       { "backend < ['backend']", NULL,       3 },
-       { "backend <= ['backend']", NULL,      3 },
-       { "backend >= ['backend']", NULL,      0 },
-       { "backend > ['backend']", NULL,       0 },
-       { "ANY metric = 'm1'", NULL,           2 },
-       { "ANY metric= 'm1'", "name = 'x'",    0 }, /* filter never matches */
-       { "ANY metric = 'm1'",
+               "NOT attribute['x'] = ''",               1 }, /* filter always matches */
+       { "name =~ 'a|b'", NULL,                     2 },
+       { "name =~ 'host'", NULL,                    0 },
+       { "name =~ '.'", NULL,                       3 },
+       { "ANY backend = 'backend'", NULL,           0 },
+       { "ALL backend = ''", NULL,                  3 }, /* backend is empty */
+       { "backend = ['backend']", NULL,             0 },
+       { "backend != ['backend']", NULL,            3 },
+       { "backend < ['backend']", NULL,             3 },
+       { "backend <= ['backend']", NULL,            3 },
+       { "backend >= ['backend']", NULL,            0 },
+       { "backend > ['backend']", NULL,             0 },
+       { "ANY metric.name = 'm1'", NULL,            2 },
+       { "ANY metric.name = 'm1'", "name = 'x'",    0 }, /* filter never matches */
+       { "ANY metric.name = 'm1'",
+               "NOT attribute['x'] = ''",               2 }, /* filter always matches */
+       { "ANY metric.name =~ 'm'", NULL,            2 },
+       { "ALL metric.name =~ 'm'", NULL,            3 },
+       { "ANY metric.name =~ 'm'", "name !~ '1'",   1 },
+       { "ANY metric.name =~ 'm'", "name !~ 'm'",   0 },
+       { "ALL metric.name =~ '1'", NULL,            2 },
+       { "ALL metric.name =~ '2'", NULL,            1 },
+       { "ANY metric.name !~ 'm'", NULL,            0 },
+       { "ALL metric.name !~ 'm'", NULL,            1 },
+       { "ANY metric.name =~ 'x'", NULL,            0 },
+       { "ANY service.name = 's1'", NULL,           2 },
+       { "ANY service.name = 's1'", "name = 'x'",   0 }, /* filter never matches */
+       { "ANY service.name = 's1'",
+               "NOT attribute['x'] = ''",               2 }, /* filter always matches */
+       { "ANY service.name =~ 's'", NULL,           2 },
+       { "ANY service.name =~ 's'", "name !~ 's'",  0 },
+       { "ANY service.name =~ 's'", "name !~ '1'",  2 },
+       { "ANY service.name !~ 's'", NULL,           0 },
+       { "ANY attribute.name = 'k1'", NULL,         2 },
+       { "ANY attribute.name = 'k1'", "name = 'x'", 0 }, /* filter never matches */
+       { "ANY attribute.name = 'k1'",
                "NOT attribute['x'] = ''",         2 }, /* filter always matches */
-       { "ANY metric =~ 'm'", NULL,           2 },
-       { "ALL metric =~ 'm'", NULL,           3 },
-       { "ANY metric =~ 'm'", "name !~ '1'",  1 },
-       { "ANY metric =~ 'm'", "name !~ 'm'",  0 },
-       { "ALL metric =~ '1'", NULL,           2 },
-       { "ALL metric =~ '2'", NULL,           1 },
-       { "ANY metric !~ 'm'", NULL,           0 },
-       { "ALL metric !~ 'm'", NULL,           1 },
-       { "ANY metric =~ 'x'", NULL,           0 },
-       { "ANY service = 's1'", NULL,          2 },
-       { "ANY service = 's1'", "name = 'x'",  0 }, /* filter never matches */
-       { "ANY service = 's1'",
-               "NOT attribute['x'] = ''",         2 }, /* filter always matches */
-       { "ANY service =~ 's'", NULL,          2 },
-       { "ANY service =~ 's'", "name !~ 's'", 0 },
-       { "ANY service =~ 's'", "name !~ '1'", 2 },
-       { "ANY service !~ 's'", NULL,          0 },
-       { "ANY attribute = 'k1'", NULL,        2 },
-       { "ANY attribute = 'k1'", "name = 'x'",0 }, /* filter never matches */
-       { "ANY attribute = 'k1'",
-               "NOT attribute['x'] = ''",         2 }, /* filter always matches */
-       { "ANY attribute =~ 'k'", NULL,        2 },
-       { "ANY attribute =~ 'k'",
+       { "ANY attribute.name =~ 'k'", NULL,   2 },
+       { "ANY attribute.name =~ 'k'",
                "name !~ '1'",                     1 },
-       { "ANY attribute =~ 'k'",
+       { "ANY attribute.name =~ 'k'",
                "name !~ 'k'",                     0 },
-       { "ANY attribute =~ '1'", NULL,        2 },
-       { "ANY attribute =~ '2'", NULL,        1 },
-       { "ANY attribute = 'x'", NULL,         0 },
-       { "ANY attribute =~ 'x'", NULL,        0 },
-       { "ALL attribute = 'k1'", NULL,        2 },
+       { "ANY attribute.name =~ '1'", NULL,   2 },
+       { "ANY attribute.name =~ '2'", NULL,   1 },
+       { "ANY attribute.name = 'x'", NULL,    0 },
+       { "ANY attribute.name =~ 'x'", NULL,   0 },
+       { "ALL attribute.name = 'k1'", NULL,   2 },
        { "host.name = 'a'", NULL,             1 },
        { "host.attribute['k1'] =~ 'v1'",
                NULL,                              1 },
@@ -591,7 +591,7 @@ struct {
        { "attribute['k2'] != 123", NULL,      0 },
        { "attribute['k1'] != 'v1'", NULL,     1 },
        { "attribute['k1'] != 'v2'", NULL,     1 },
-       { "ANY attribute != 'x' "
+       { "ANY attribute.name != 'x' "
          "AND attribute['k1'] !~ 'x'", NULL,  2 },
 };
 
index 3f426cecde0a5d9d874446da80d03be2c5169f75..e64da004450359056136f61d79ae8351f2da3200 100644 (file)
@@ -85,48 +85,48 @@ struct {
          "name = 'host'",       -1,  1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
          "name =~ 'p' AND "
-         "ANY service =~ 'p'",  -1,  1, SDB_CONNECTION_LOOKUP },
+         "ANY service.name =~ 'p'", -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING NOT "
          "name =~ 'p' AND "
-         "ANY service =~ 'p'",  -1,  1, SDB_CONNECTION_LOOKUP },
+         "ANY service.name =~ 'p'", -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
          "name =~ 'p' AND "
-         "ANY service =~ 'p' OR "
-         "ANY service =~ 'r'",  -1,  1, SDB_CONNECTION_LOOKUP },
+         "ANY service.name =~ 'p' OR "
+         "ANY service.name =~ 'r'", -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING NOT "
          "name =~ 'p' AND "
-         "ANY service =~ 'p' OR "
-         "ANY service =~ 'r'",  -1,  1, SDB_CONNECTION_LOOKUP },
+         "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 },
+         "FILTER age > 1D",         -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
          "name =~ 'p' "
          "FILTER age > 1D AND "
-         "interval < 240s" ,   -1,   1, SDB_CONNECTION_LOOKUP },
+         "interval < 240s" ,        -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
          "name =~ 'p' "
-         "FILTER NOT age>1D",  -1,   1, SDB_CONNECTION_LOOKUP },
+         "FILTER NOT age>1D",       -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
          "name =~ 'p' "
          "FILTER age>"
-         "interval",           -1,   1, SDB_CONNECTION_LOOKUP },
+         "interval",                -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
-         "host.name =~ 'p'",   -1,   1, SDB_CONNECTION_LOOKUP },
-       { "LOOKUP services",    -1,   1, SDB_CONNECTION_LOOKUP },
+         "host.name =~ 'p'",        -1,   1, SDB_CONNECTION_LOOKUP },
+       { "LOOKUP services",         -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP services MATCHING ANY "
-         "attribute =~ 'a'",   -1,   1, SDB_CONNECTION_LOOKUP },
+         "attribute.name =~ 'a'",   -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP services MATCHING "
-         "host.name = 'p'",    -1,   1, SDB_CONNECTION_LOOKUP },
+         "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 },
+         "service.name = 'p'",      -1,   1, SDB_CONNECTION_LOOKUP },
+       { "LOOKUP metrics",          -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP metrics MATCHING ANY "
-         "attribute =~ 'a'",   -1,   1, SDB_CONNECTION_LOOKUP },
+         "attribute.name =~ 'a'",   -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP metrics MATCHING "
-         "host.name = 'p'",    -1,   1, SDB_CONNECTION_LOOKUP },
+         "host.name = 'p'",         -1,   1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP metrics MATCHING "
-         "metric.name = 'p'",  -1,   1, SDB_CONNECTION_LOOKUP },
+         "metric.name = 'p'",       -1,   1, SDB_CONNECTION_LOOKUP },
 
        /* TIMESERIES commands */
        { "TIMESERIES 'host'.'metric' "
@@ -342,7 +342,7 @@ struct {
          "NOT attribute['foo'] "
          "IS NULL",             -1,  1, SDB_CONNECTION_LOOKUP },
        { "LOOKUP hosts MATCHING "
-         "ANY service IS NULL", -1, -1, 0 },
+         "ANY service.name IS NULL", -1, -1, 0 },
 
        /* invalid numeric constants */
        { "LOOKUP hosts MATCHING "
@@ -500,27 +500,27 @@ struct {
          "attribute['foo'] <= "
          "'f' || oo",           -1, -1, 0 },
        { "LOOKUP hosts MATCHING "
-         "ANY host = 'host'",   -1, -1, 0 },
+         "ANY host.name = 'host'",   -1, -1, 0 },
        { "LOOKUP hosts MATCHING "
-         "ANY service > 1",     -1, -1, 0 },
+         "ANY service.name > 1",     -1, -1, 0 },
        { "LOOKUP hosts MATCHING "
-         "service.name = 's'",  -1, -1, 0 },
+         "service.name = 's'",       -1, -1, 0 },
        { "LOOKUP services MATCHING "
-         "ANY host = 'host'",   -1, -1, 0 },
+         "ANY host.name = 'host'",   -1, -1, 0 },
        { "LOOKUP services MATCHING "
-         "ANY service = 'svc'", -1, -1, 0 },
+         "ANY service.name = 'svc'", -1, -1, 0 },
        { "LOOKUP services MATCHING "
-         "ANY metric = 'm'",    -1, -1, 0 },
+         "ANY metric.name = 'm'",    -1, -1, 0 },
        { "LOOKUP services MATCHING "
-         "metric.name = 'm'",   -1, -1, 0 },
+         "metric.name = 'm'",        -1, -1, 0 },
        { "LOOKUP metrics MATCHING "
-         "ANY host = 'host'",   -1, -1, 0 },
+         "ANY host.name = 'host'",   -1, -1, 0 },
        { "LOOKUP metrics MATCHING "
-         "ANY service = 'svc'", -1, -1, 0 },
+         "ANY service.name = 'svc'", -1, -1, 0 },
        { "LOOKUP metrics MATCHING "
-         "ANY metric = 'm'",    -1, -1, 0 },
+         "ANY metric.name = 'm'",    -1, -1, 0 },
        { "LOOKUP metrics MATCHING "
-         "service.name = 'm'",  -1, -1, 0 },
+         "service.name = 'm'",       -1, -1, 0 },
 
        /* invalid STORE commands */
        { "STORE host "
@@ -626,165 +626,168 @@ struct {
        { "ALL backend > 'be'",           -1,  MATCHER_ALL },
        { "ANY backend &^ 'be'",          -1,  -1 },
        /* match hosts by service */
-       { "ANY service < 'name'",         -1,  MATCHER_ANY },
-       { "ANY service <= 'name'",        -1,  MATCHER_ANY },
-       { "ANY service = 'name'",         -1,  MATCHER_ANY },
-       { "ANY service != 'name'",        -1,  MATCHER_ANY },
-       { "ANY service >= 'name'",        -1,  MATCHER_ANY },
-       { "ANY service > 'name'",         -1,  MATCHER_ANY },
-       { "ANY service =~ 'pattern'",     -1,  MATCHER_ANY },
-       { "ANY service !~ 'pattern'",     -1,  MATCHER_ANY },
-       { "ANY service &^ 'name'",        -1,  -1 },
-       { "ALL service < 'name'",         -1,  MATCHER_ALL },
-       { "ALL service <= 'name'",        -1,  MATCHER_ALL },
-       { "ALL service = 'name'",         -1,  MATCHER_ALL },
-       { "ALL service != 'name'",        -1,  MATCHER_ALL },
-       { "ALL service >= 'name'",        -1,  MATCHER_ALL },
-       { "ALL service > 'name'",         -1,  MATCHER_ALL },
-       { "ALL service =~ 'pattern'",     -1,  MATCHER_ALL },
-       { "ALL service !~ 'pattern'",     -1,  MATCHER_ALL },
-       { "ALL service &^ 'name'",        -1,  -1 },
+       { "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'",          -1,  MATCHER_ANY },
-       { "ANY metric <= 'name'",         -1,  MATCHER_ANY },
-       { "ANY metric = 'name'",          -1,  MATCHER_ANY },
-       { "ANY metric != 'name'",         -1,  MATCHER_ANY },
-       { "ANY metric >= 'name'",         -1,  MATCHER_ANY },
-       { "ANY metric > 'name'",          -1,  MATCHER_ANY },
-       { "ANY metric =~ 'pattern'",      -1,  MATCHER_ANY },
-       { "ANY metric !~ 'pattern'",      -1,  MATCHER_ANY },
-       { "ANY metric &^ 'pattern'",      -1,  -1 },
-       { "ALL metric < 'name'",          -1,  MATCHER_ALL },
-       { "ALL metric <= 'name'",         -1,  MATCHER_ALL },
-       { "ALL metric = 'name'",          -1,  MATCHER_ALL },
-       { "ALL metric != 'name'",         -1,  MATCHER_ALL },
-       { "ALL metric >= 'name'",         -1,  MATCHER_ALL },
-       { "ALL metric > 'name'",          -1,  MATCHER_ALL },
-       { "ALL metric =~ 'pattern'",      -1,  MATCHER_ALL },
-       { "ALL metric !~ 'pattern'",      -1,  MATCHER_ALL },
-       { "ALL metric &^ 'pattern'",      -1,  -1 },
+       { "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'",       -1,  MATCHER_ANY },
-       { "ANY attribute <= 'name'",      -1,  MATCHER_ANY },
-       { "ANY attribute = 'name'",       -1,  MATCHER_ANY },
-       { "ANY attribute != 'name'",      -1,  MATCHER_ANY },
-       { "ANY attribute >= 'name'",      -1,  MATCHER_ANY },
-       { "ANY attribute > 'name'",       -1,  MATCHER_ANY },
-       { "ANY attribute =~ 'pattern'",   -1,  MATCHER_ANY },
-       { "ANY attribute !~ 'pattern'",   -1,  MATCHER_ANY },
-       { "ANY attribute &^ 'pattern'",   -1,  -1 },
-       { "ALL attribute < 'name'",       -1,  MATCHER_ALL },
-       { "ALL attribute <= 'name'",      -1,  MATCHER_ALL },
-       { "ALL attribute = 'name'",       -1,  MATCHER_ALL },
-       { "ALL attribute != 'name'",      -1,  MATCHER_ALL },
-       { "ALL attribute >= 'name'",      -1,  MATCHER_ALL },
-       { "ALL attribute > 'name'",       -1,  MATCHER_ALL },
-       { "ALL attribute =~ 'pattern'",   -1,  MATCHER_ALL },
-       { "ALL attribute !~ 'pattern'",   -1,  MATCHER_ALL },
-       { "ALL attribute &^ 'pattern'",   -1,  -1 },
+       { "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 =~ 'pattern'",     -1,  MATCHER_AND },
+         "ANY service.name =~ 'pattern'",     -1,  MATCHER_AND },
        { "name =~ 'pattern' OR "
-         "ANY service =~ 'pattern'",     -1,  MATCHER_OR },
-       { "NOT name = 'host'",            -1,  MATCHER_NOT },
+         "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 },
+       { "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 },
+         "2014-08-16",                     -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "17:23",                        -1,  MATCHER_EQ },
+         "17:23",                          -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "17:23:53",                     -1,  MATCHER_EQ },
+         "17:23:53",                       -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "17:23:53.123",                 -1,  MATCHER_EQ },
+         "17:23:53.123",                   -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "17:23:53.123456789",           -1,  MATCHER_EQ },
+         "17:23:53.123456789",             -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "2014-08-16 17:23",             -1,  MATCHER_EQ },
+         "2014-08-16 17:23",               -1,  MATCHER_EQ },
        { "attribute['foo'] = "
-         "2014-08-16 17:23:53",          -1,  MATCHER_EQ },
+         "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 },
+       { "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 },
+       { "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 },
+       { "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' AND "
-         "ANY attribute = 'name' OR "
-         "attribute['foo'] = 'bar'",     -1,  MATCHER_OR },
+         "ANY service.name = 'name' AND "
+         "ANY attribute.name = 'name' OR "
+         "attribute['foo'] = 'bar'",       -1,  MATCHER_OR },
        { "name = 'name' AND "
-         "ANY service = 'name' AND "
-         "ANY attribute = 'name' OR "
-         "attribute['foo'] = 'bar'",     -1,  MATCHER_OR },
+         "ANY service.name = 'name' AND "
+         "ANY attribute.name = 'name' OR "
+         "attribute['foo'] = 'bar'",       -1,  MATCHER_OR },
        { "name = 'name' AND "
-         "ANY service = 'name' OR "
-         "ANY attribute = 'name' AND "
-         "attribute['foo'] = 'bar'",     -1,  MATCHER_OR },
+         "ANY service.name = 'name' OR "
+         "ANY attribute.name = 'name' AND "
+         "attribute['foo'] = 'bar'",       -1,  MATCHER_OR },
        { "(name = 'name' OR "
-         "ANY service = 'name') AND "
-         "(ANY attribute = 'name' OR "
-         "attribute['foo'] = 'bar')",    -1,  MATCHER_AND },
+         "ANY service.name = 'name') AND "
+         "(ANY attribute.name = 'name' OR "
+         "attribute['foo'] = 'bar')",      -1,  MATCHER_AND },
        { "NOT name = 'name' OR "
-         "ANY service = 'name'",         -1,  MATCHER_OR },
+         "ANY service.name = 'name'",      -1,  MATCHER_OR },
        { "NOT name = 'name' OR "
-         "NOT ANY service = 'name'",     -1,  MATCHER_OR },
+         "NOT ANY service.name = 'name'",  -1,  MATCHER_OR },
        { "NOT (name = 'name' OR "
-         "NOT ANY service = 'name')",    -1,  MATCHER_NOT },
+         "NOT ANY service.name = 'name')", -1,  MATCHER_NOT },
 
        /* syntax errors */
-       { "LIST",                         -1, -1 },
-       { "foo &^ bar",                   -1, -1 },
-       { "invalid",                      -1, -1 },
+       { "LIST",                           -1, -1 },
+       { "foo &^ bar",                     -1, -1 },
+       { "invalid",                        -1, -1 },
 };
 
 START_TEST(test_parse_matcher)