From: Sebastian Harl Date: Wed, 12 Nov 2014 21:10:47 +0000 (+0100) Subject: frontend: Added support for array constants. X-Git-Tag: sysdb-0.6.0~6 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=dc2d1452757100a63024c23307f31ddc935fe5f7;p=sysdb.git frontend: Added support for array constants. --- diff --git a/src/frontend/analyzer.c b/src/frontend/analyzer.c index c1b9d01..2de9bef 100644 --- a/src/frontend/analyzer.c +++ b/src/frontend/analyzer.c @@ -165,6 +165,10 @@ analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf) case MATCHER_GE: case MATCHER_GT: assert(CMP_M(m)->left && CMP_M(m)->right); + if ((CMP_M(m)->left->data_type > 0) + && (CMP_M(m)->right->data_type > 0) + && (CMP_M(m)->left->data_type == CMP_M(m)->right->data_type)) + return 0; if ((CMP_M(m)->left->data_type > 0) && (CMP_M(m)->left->data_type & SDB_TYPE_ARRAY)) { cmp_error(errbuf, m->type, CMP_M(m)->left->data_type, diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 80fb249..d4e54a9 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -171,6 +171,7 @@ sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...); %type data interval interval_elem + array array_elem_list %type datetime start_clause end_clause @@ -599,6 +600,8 @@ data: datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; } | interval { $$ = $1; } + | + array { $$ = $1; } ; datetime: @@ -626,7 +629,7 @@ interval_elem: unit = sdb_strpunit($2); if (! unit) { sdb_fe_yyerrorf(&yylloc, scanner, - YY_("invalid time unit %s"), $2); + YY_("syntax error, invalid time unit %s"), $2); free($2); $2 = NULL; YYABORT; } @@ -643,6 +646,69 @@ interval_elem: } ; +array: + '[' array_elem_list ']' + { + $$ = $2; + } + ; + +array_elem_list: + array_elem_list ',' data + { + size_t elem_size; + + if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) { + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " + "cannot use element of type %s in array of type %s"), + SDB_TYPE_TO_STRING($3.type), + SDB_TYPE_TO_STRING($1.type)); + sdb_data_free_datum(&$1); + sdb_data_free_datum(&$3); + YYABORT; + } + + elem_size = sdb_data_sizeof($3.type); + $1.data.array.values = realloc($1.data.array.values, + ($1.data.array.length + 1) * elem_size); + if (! $1.data.array.values) { + sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); + YYABORT; + } + + memcpy((char *)$1.data.array.values + + $1.data.array.length * elem_size, + &$3.data, elem_size); + ++$1.data.array.length; + + $$ = $1; + } + | + data + { + size_t elem_size; + + if ($1.type & SDB_TYPE_ARRAY) { + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " + "cannot construct array of type %s"), + SDB_TYPE_TO_STRING($1.type)); + sdb_data_free_datum(&$1); + YYABORT; + } + + $$ = $1; + $$.type = $1.type | SDB_TYPE_ARRAY; + $$.data.array.length = 1; + elem_size = sdb_data_sizeof($1.type); + $$.data.array.values = malloc(elem_size); + if (! $$.data.array.values ) { + sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); + YYABORT; + } + memcpy($$.data.array.values, &$1.data, elem_size); + } + ; + %% void diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c index 18d811f..49f9125 100644 --- a/t/unit/core/store_lookup_test.c +++ b/t/unit/core/store_lookup_test.c @@ -534,6 +534,12 @@ START_TEST(test_scan) { "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'", diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index 17c1032..c377f78 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -186,6 +186,12 @@ START_TEST(test_parse) "1Y42D", -1, 1, CONNECTION_LOOKUP }, */ + /* array constants */ + { "LOOKUP hosts MATCHING " + "backend = ['foo']", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts MATCHING " + "backend = ['a','b']", -1, 1, CONNECTION_LOOKUP }, + /* NULL */ { "LOOKUP hosts MATCHING " "attribute['foo'] " @@ -452,6 +458,14 @@ START_TEST(test_parse_matcher) * IS NULL currently maps to an equality matcher */ { "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 }, /* object field matchers */ { "name < 'a'", -1, MATCHER_LT },