From 695324de797b55cf12d8a66bd3612e78bc1235af Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 1 Mar 2015 16:39:20 +0100 Subject: [PATCH] Add support for the 'NOT IN' operator. 'a NOT IN b' is the same as 'NOT a IN b'. --- doc/sysdbql.7.txt | 10 +++++----- src/core/store-private.h | 2 ++ src/core/store_lookup.c | 12 +++++++++++- src/frontend/analyzer.c | 1 + src/frontend/grammar.y | 7 +++++++ src/include/core/store.h | 8 ++++++++ t/unit/frontend/parser_test.c | 7 +++++++ 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/doc/sysdbql.7.txt b/doc/sysdbql.7.txt index c0cecba..7ed9a11 100644 --- a/doc/sysdbql.7.txt +++ b/doc/sysdbql.7.txt @@ -130,12 +130,12 @@ Boolean expressions may use the following operators: when accessing an attribute value). '' *IN* '':: +'' *NOT IN* '':: Checks whether the value of the first expression is included in the value - of the second expression which has to be an array value (e.g., *backend* - field). If the second value is not an array or if the type of the first - value does not match the array's element type, the expression always - evaluates to false. The first value may also be an array. In this case, - the expression evaluates to true if all elements of that array are + of the second expression (or not). The second value has to be an array + value (e.g., *backend* field) and the type of the first value has to match + the array's element type. The first value may also be an array. In this + case, the expression evaluates to true if all elements of that array are included in the second array where order does not matter. Parentheses ('()') may be used around subexpressions to group them and enforce diff --git a/src/core/store-private.h b/src/core/store-private.h index 97e8a6c..4ef11f9 100644 --- a/src/core/store-private.h +++ b/src/core/store-private.h @@ -147,6 +147,7 @@ enum { MATCHER_ANY, MATCHER_ALL, MATCHER_IN, + MATCHER_NIN, /* unary operators */ MATCHER_ISNULL, @@ -170,6 +171,7 @@ enum { : ((t) == MATCHER_ANY) ? "ANY" \ : ((t) == MATCHER_ALL) ? "ALL" \ : ((t) == MATCHER_IN) ? "IN" \ + : ((t) == MATCHER_NIN) ? "NOT IN" \ : ((t) == MATCHER_ISNULL) ? "IS NULL" \ : ((t) == MATCHER_ISNNULL) ? "IS NOT NULL" \ : ((t) == MATCHER_LT) ? "<" \ diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index a95f587..2d1b3ca 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -326,7 +326,7 @@ match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj, sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT; int status = 1; - assert(m->type == MATCHER_IN); + assert((m->type == MATCHER_IN) || (m->type == MATCHER_NIN)); if (expr_eval2(CMP_M(m)->left, &value, CMP_M(m)->right, &array, obj, filter)) @@ -336,6 +336,8 @@ match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj, status = sdb_data_inarray(&value, &array); expr_free_datum2(CMP_M(m)->left, &value, CMP_M(m)->right, &array); + if (m->type == MATCHER_NIN) + return !status; return status; } /* match_in */ @@ -401,6 +403,7 @@ matchers[] = { match_iter, match_iter, match_in, + match_in, /* unary operators */ match_isnull, @@ -633,6 +636,13 @@ sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right) MATCHER_IN, left, right)); } /* sdb_store_in_matcher */ +sdb_store_matcher_t * +sdb_store_nin_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("not-in-matcher", cmp_type, + MATCHER_NIN, left, right)); +} /* sdb_store_in_matcher */ + sdb_store_matcher_t * sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right) { diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c index 4e29fdf..96ffe62 100644 --- a/src/frontend/analyzer.c +++ b/src/frontend/analyzer.c @@ -251,6 +251,7 @@ analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) break; case MATCHER_IN: + case MATCHER_NIN: if (analyze_expr(context, CMP_M(m)->left, errbuf)) return -1; if (analyze_expr(context, CMP_M(m)->right, errbuf)) diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 87184a4..323fe4f 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -565,6 +565,13 @@ compare_matcher: sdb_object_deref(SDB_OBJ($1)); sdb_object_deref(SDB_OBJ($3)); } + | + expression NOT IN expression + { + $$ = sdb_store_nin_matcher($1, $4); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($4)); + } ; expression: diff --git a/src/include/core/store.h b/src/include/core/store.h index 30ad0ab..68f094b 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -471,6 +471,14 @@ sdb_store_all_matcher(int type, sdb_store_matcher_t *m); sdb_store_matcher_t * sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right); +/* + * sdb_store_nin_matcher: + * Like sdb_store_in_matcher but matches if the left value is not included in + * the right value. + */ +sdb_store_matcher_t * +sdb_store_nin_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right); + /* * sdb_store_lt_matcher, sdb_store_le_matcher, sdb_store_eq_matcher, * sdb_store_ge_matcher, sdb_store_gt_matcher: diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index 599ffe5..2bbf5cc 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -255,6 +255,8 @@ struct { /* array iteration */ { "LOOKUP hosts MATCHING " "'foo' IN backend", -1, 1, SDB_CONNECTION_LOOKUP }, + { "LOOKUP hosts MATCHING 'foo' " + "NOT IN backend", -1, 1, SDB_CONNECTION_LOOKUP }, { "LOOKUP hosts MATCHING " "['foo','bar'] " "IN backend ", -1, 1, SDB_CONNECTION_LOOKUP }, @@ -265,6 +267,8 @@ struct { /* type mismatch */ { "LOOKUP hosts MATCHING " "1 IN backend ", -1, -1, 0 }, + { "LOOKUP hosts MATCHING " + "1 NOT IN backend ", -1, -1, 0 }, { "LOOKUP hosts MATCHING " "ANY backend < 'b'", -1, 1, SDB_CONNECTION_LOOKUP }, { "LOOKUP hosts MATCHING " @@ -691,6 +695,9 @@ struct { { "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 " -- 2.30.2