From 026ce2bb377f4055e3a0a1d20a2f91e5a73a49b0 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 2 Sep 2015 23:49:20 +0200 Subject: [PATCH] Allow and implement iterating arbitrary (non-constant) array values. That is, iterators may now work with arithmetic expressions that evaluate to an array. --- src/core/store_expr.c | 24 +++++++++++++++++++--- src/core/store_lookup.c | 4 +++- src/parser/analyzer.c | 5 ----- t/unit/frontend/query_test.c | 39 ++++++++++++++++++++++++++++++++++++ t/unit/parser/parser_test.c | 9 +++++---- 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/core/store_expr.c b/src/core/store_expr.c index 80c1f4a..5e15f53 100644 --- a/src/core/store_expr.c +++ b/src/core/store_expr.c @@ -39,6 +39,7 @@ #include "core/object.h" #include +#include #include #include @@ -55,6 +56,7 @@ struct sdb_store_expr_iter { sdb_data_t array; size_t array_idx; + bool free_array; sdb_store_matcher_t *filter; }; @@ -306,6 +308,7 @@ sdb_store_expr_iter(sdb_store_expr_t *expr, sdb_store_obj_t *obj, sdb_store_expr_iter_t *iter; sdb_avltree_iter_t *tree = NULL; sdb_data_t array = SDB_DATA_INIT; + bool free_array = 0; if (! expr) return NULL; @@ -345,15 +348,27 @@ sdb_store_expr_iter(sdb_store_expr_t *expr, sdb_store_obj_t *obj, if (expr->data.type & SDB_TYPE_ARRAY) array = expr->data; } - else - return NULL; + else { + sdb_data_t value = SDB_DATA_INIT; + if (sdb_store_expr_eval(expr, obj, &value, filter)) + return NULL; + if (! (value.type & SDB_TYPE_ARRAY)) { + sdb_data_free_datum(&value); + return NULL; + } + array = value; + free_array = 1; + } if ((! tree) && (array.type == SDB_TYPE_NULL)) return NULL; iter = calloc(1, sizeof(*iter)); - if (! iter) + if (! iter) { + if (free_array) + sdb_data_free_datum(&array); return NULL; + } sdb_object_ref(SDB_OBJ(obj)); sdb_object_ref(SDB_OBJ(expr)); @@ -363,6 +378,7 @@ sdb_store_expr_iter(sdb_store_expr_t *expr, sdb_store_obj_t *obj, iter->expr = expr; iter->tree = tree; iter->array = array; + iter->free_array = free_array; iter->filter = filter; return iter; } /* sdb_store_expr_iter */ @@ -379,6 +395,8 @@ sdb_store_expr_iter_destroy(sdb_store_expr_iter_t *iter) sdb_avltree_iter_destroy(iter->tree); iter->tree = NULL; + if (iter->free_array) + sdb_data_free_datum(&iter->array); iter->array = null; iter->array_idx = 0; diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index b43b1ef..06151a8 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -196,8 +196,10 @@ match_iter(sdb_store_matcher_t *m, sdb_store_obj_t *obj, assert((! CMP_M(ITER_M(m)->m)->left) && CMP_M(ITER_M(m)->m)->right); iter = sdb_store_expr_iter(ITER_M(m)->iter, obj, filter); - if (! iter) + if (! iter) { + sdb_log(SDB_LOG_WARNING, "store: Invalid iterator"); return 0; + } status = all; while (sdb_store_expr_iter_has_next(iter)) { diff --git a/src/parser/analyzer.c b/src/parser/analyzer.c index f12dff2..ecae40f 100644 --- a/src/parser/analyzer.c +++ b/src/parser/analyzer.c @@ -202,11 +202,6 @@ analyze_logical(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf) static int analyze_arith(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf) { - if (ctx.iter) { - op_error(errbuf, op, "cannot evaluate in iterator context"); - return -1; - } - if (analyze_node(ctx, op->left, errbuf)) return -1; if (analyze_node(ctx, op->right, errbuf)) diff --git a/t/unit/frontend/query_test.c b/t/unit/frontend/query_test.c index e36c302..7640511 100644 --- a/t/unit/frontend/query_test.c +++ b/t/unit/frontend/query_test.c @@ -124,7 +124,38 @@ turndown(void) "{\"name\": \"hostname\", \"value\": \"h1\", " \ "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \ "\"update_interval\": \"0s\", \"backends\": []}]}]}" +#define HOST_H2 \ + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": [], " \ + "\"metrics\": [" \ + "{\"name\": \"m1\", \"timeseries\": false, " \ + "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": [], " \ + "\"attributes\": [" \ + "{\"name\": \"hostname\", \"value\": \"h2\", " \ + "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": []}]}], " \ + "\"services\": [" \ + "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": [], " \ + "\"attributes\": [" \ + "{\"name\": \"hostname\", \"value\": \"h2\", " \ + "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": []}]}," \ + "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:02 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": [], " \ + "\"attributes\": [" \ + "{\"name\": \"hostname\", \"value\": \"h2\", " \ + "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": []}," \ + "{\"name\": \"k1\", \"value\": 123, " \ + "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": []}," \ + "{\"name\": \"k2\", \"value\": 4711, " \ + "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \ + "\"update_interval\": \"0s\", \"backends\": []}]}]}" #define HOST_H1_ARRAY "["HOST_H1"]" +#define HOST_H12_ARRAY "["HOST_H1","HOST_H2"]" #define HOST_H1_LISTING \ "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \ "\"update_interval\": \"0s\", \"backends\": []}" @@ -371,6 +402,14 @@ static struct { SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age >= 0s", -1, /* always matches */ 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY, }, + { + SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend = 'b'", -1, + 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]", + }, + { + SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend || 'b' = 'b'", -1, + 0, SDB_CONNECTION_DATA, 2205, SDB_CONNECTION_LOOKUP, HOST_H12_ARRAY, + }, { SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age < 0s", -1, /* never matches */ -1, UINT32_MAX, 0, 0, NULL, /* FETCH fails if the object doesn't exist */ diff --git a/t/unit/parser/parser_test.c b/t/unit/parser/parser_test.c index 89ee2e6..8da4ef0 100644 --- a/t/unit/parser/parser_test.c +++ b/t/unit/parser/parser_test.c @@ -339,6 +339,9 @@ struct { "ALL backend =~ 'b'", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, { "LOOKUP hosts MATCHING " "ALL backend !~ 'b'", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "ANY backend || 'a' = 'b'", + -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, /* attribute type is unknown */ { "LOOKUP hosts MATCHING " "ANY backend = attribute['backend']", @@ -579,16 +582,14 @@ struct { "ALL 1 || '2' < '3'", -1, -1, 0, 0 }, { "LOOKUP hosts MATCHING " "ALL name =~ 'a'", -1, -1, 0, 0 }, - /* this could work in theory but is not supported atm */ - { "LOOKUP hosts MATCHING " - "ANY backend || 'a' = 'b'", - -1, -1, 0, 0 }, { "LOOKUP hosts MATCHING ANY " "host.name = 'h'", -1, -1, 0, 0 }, { "LOOKUP services MATCHING ANY " "host.name = 'h'", -1, -1, 0, 0 }, { "LOOKUP metrics MATCHING ANY " "host.name = 'h'", -1, -1, 0, 0 }, + { "LOOKUP hosts MATCHING ANY " + "name || 'a' = 'b'", -1, -1, 0, 0 }, /* invalid LIST commands */ { "LIST", -1, -1, 0, 0 }, -- 2.30.2