From da760b7c730635befe5d3876641dd826f7abf9d3 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 15 Mar 2015 10:54:21 -0400 Subject: [PATCH] query language: Add support for attribute.value access. --- src/frontend/analyzer.c | 16 +++++++-- src/frontend/grammar.y | 4 ++- src/frontend/scanner.l | 1 + t/unit/core/store_lookup_test.c | 3 ++ t/unit/frontend/parser_test.c | 61 ++++++++++++++++++++++++++++----- 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c index cf077de..4bd3702 100644 --- a/src/frontend/analyzer.c +++ b/src/frontend/analyzer.c @@ -100,14 +100,24 @@ analyze_expr(int context, sdb_store_expr_t *e, sdb_strbuf_t *errbuf) 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), SDB_STORE_TYPE_TO_NAME(context)); + EXPR_TO_STRING(e->left), + context == -1 ? "generic" : SDB_STORE_TYPE_TO_NAME(context)); return -1; case ATTR_VALUE: - case FIELD_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; @@ -161,7 +171,7 @@ analyze_matcher(int context, int parent_type, if ((ITER_M(m)->iter->type == TYPED_EXPR) || (ITER_M(m)->iter->type == FIELD_VALUE)) - type = ITER_M(m)->iter->data.data.integer; + type = (int)ITER_M(m)->iter->data.data.integer; if (context == -1) { /* inside a filter */ /* attributes are always iterable */ diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index a573b2b..70e6c3c 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -119,7 +119,7 @@ sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...); %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 +%token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T VALUE_T %token LAST UPDATE @@ -700,6 +700,8 @@ field: INTERVAL_T { $$ = SDB_FIELD_INTERVAL; } | BACKEND_T { $$ = SDB_FIELD_BACKEND; } + | + VALUE_T { $$ = SDB_FIELD_VALUE; } ; cmp: diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index 3985bf8..ab8b80d 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -86,6 +86,7 @@ static struct { { "age", AGE_T }, { "interval", INTERVAL_T }, { "backend", BACKEND_T }, + { "value", VALUE_T }, }; void diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c index 923ce06..3555495 100644 --- a/t/unit/core/store_lookup_test.c +++ b/t/unit/core/store_lookup_test.c @@ -569,6 +569,9 @@ struct { { "ANY attribute.name = 'x'", NULL, 0 }, { "ANY attribute.name =~ 'x'", NULL, 0 }, { "ALL attribute.name = 'k1'", NULL, 2 }, + { "ANY attribute.value = 'v1'", NULL, 1 }, + { "ANY attribute.value =~ 'v'", NULL, 2 }, + { "ANY attribute.value = 123", NULL, 1 }, { "host.name = 'a'", NULL, 1 }, { "host.attribute['k1'] =~ 'v1'", NULL, 1 }, diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index b67b133..65ec6ca 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -64,18 +64,61 @@ struct { "'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", -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 }, + "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 }, + "age > 60s", -1, 1, SDB_CONNECTION_LIST }, + { "LIST metrics", -1, 1, SDB_CONNECTION_LIST }, { "LIST metrics FILTER " - "age > 60s", -1, 1, SDB_CONNECTION_LIST }, + "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 }, -- 2.30.2