From 816b2d5239c9d9dd55bea8a3684f55d7a17bf380 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Mon, 23 Jun 2014 22:47:01 +0200 Subject: [PATCH] store/frontend: Added support for integer and float comparison. This is supported only for comparing attribute values. --- src/core/store_lookup.c | 21 +++++++++++++-- src/frontend/grammar.y | 18 ++++++++++++- src/frontend/scanner.l | 26 ++++++++++++++++++ t/unit/core/store_lookup_test.c | 12 +++++++++ t/unit/frontend/parser_test.c | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index 658f931..3920b80 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -673,6 +673,7 @@ parse_attr_cmp(const char *attr, const char *op, const sdb_data_t *value) sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL; sdb_store_matcher_t *m; sdb_store_cond_t *cond; + _Bool inv = 0; /* TODO: this will reject any attributes called "name"; * use a different syntax for querying objects by name */ @@ -684,12 +685,15 @@ parse_attr_cmp(const char *attr, const char *op, const sdb_data_t *value) else if (! strcasecmp(op, "<=")) matcher = sdb_store_le_matcher; else if (! strcasecmp(op, "=")) - /* XXX: this is still handled by sdb_store_matcher_parse_cmp */ matcher = sdb_store_eq_matcher; else if (! strcasecmp(op, ">=")) matcher = sdb_store_ge_matcher; else if (! strcasecmp(op, ">")) matcher = sdb_store_gt_matcher; + else if (! strcasecmp(op, "!=")) { + matcher = sdb_store_eq_matcher; + inv = 1; + } else return NULL; @@ -700,6 +704,16 @@ parse_attr_cmp(const char *attr, const char *op, const sdb_data_t *value) m = matcher(cond); /* pass ownership to 'm' or destroy in case of an error */ sdb_object_deref(SDB_OBJ(cond)); + if (! m) + return NULL; + + if (inv) { + sdb_store_matcher_t *tmp; + tmp = sdb_store_inv_matcher(m); + /* pass ownership to the inverse matcher */ + sdb_object_deref(SDB_OBJ(m)); + m = tmp; + } return m; } /* parse_attr_cmp */ @@ -741,8 +755,11 @@ sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr, else return NULL; - if (value->type != SDB_TYPE_STRING) + if (value->type != SDB_TYPE_STRING) { + if (type == SDB_ATTRIBUTE) + return parse_attr_cmp(attr, op, value); return NULL; + } if (! strcasecmp(attr, "name")) m = sdb_store_name_matcher(type, value->data.string, re); diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index c4c4775..34a9c6b 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -83,16 +83,20 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %token AND OR NOT WHERE %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX +%token CMP_LT CMP_LE CMP_GE CMP_GT %token FETCH LIST LOOKUP %token IDENTIFIER STRING +%token INTEGER FLOAT + /* Precedence (lowest first): */ %left OR %left AND -%left NOT +%right NOT %left CMP_EQUAL CMP_NEQUAL +%left CMP_LT CMP_LE CMP_GE CMP_GT %left CMP_REGEX CMP_NREGEX %left '(' ')' %left '.' @@ -311,10 +315,22 @@ op: CMP_REGEX { $$ = "=~"; } | CMP_NREGEX { $$ = "!~"; } + | + CMP_LT { $$ = "<"; } + | + CMP_LE { $$ = "<="; } + | + CMP_GE { $$ = ">="; } + | + CMP_GT { $$ = ">"; } ; data: STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; } + | + INTEGER { $$ = $1; } + | + FLOAT { $$ = $1; } ; %% diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index dd2a86c..0396db5 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -31,6 +31,7 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ +#include "core/data.h" #include "frontend/connection.h" #include "frontend/parser.h" #include "frontend/grammar.h" @@ -39,6 +40,7 @@ #include #include +#include #define YY_EXTRA_TYPE sdb_fe_yyextra_t * @@ -77,6 +79,16 @@ identifier ([A-Za-z_][A-Za-z_0-9$]*) /* TODO: fully support SQL strings */ string ('[^']*') +dec ([\+\-]?[0-9]+) +exp ([\+\-]?[0-9]+[Ee]\+?[0-9]+) +integer ({dec}|{exp}) +float1 ([\+\-]?[0-9]+\.[0-9]*([Ee][\+\-]?[0-9]+)?) +float2 ([\+\-]?[0-9]*\.[0-9]+([Ee][\+\-]?[0-9]+)?) +float3 ([\+\-]?[0-9]+[Ee]\-[0-9]+) +float4 ([\+\-]?[Ii][Nn][Ff]([Ii][Nn][Ii][Tt][Yy])?) +float5 ([Nn][Aa][Nn]) +float ({float1}|{float2}|{float3}|{float4}|{float5}) + %% {whitespace} | @@ -115,11 +127,25 @@ string ('[^']*') yylval->str = strdup(yytext + 1); return STRING; } +{integer} { + yylval->data.data.integer = (int64_t)strtoll(yytext, NULL, 10); + yylval->data.type = SDB_TYPE_INTEGER; + return INTEGER; + } +{float} { + yylval->data.data.decimal = strtod(yytext, NULL); + yylval->data.type = SDB_TYPE_DECIMAL; + return FLOAT; + } = { return CMP_EQUAL; } != { return CMP_NEQUAL; } =~ { return CMP_REGEX; } !~ { return CMP_NREGEX; } +\< { return CMP_LT; } +\<= { return CMP_LE; } +\>= { return CMP_GE; } +\> { return CMP_GT; } . { /* XXX: */ return yytext[0]; } diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c index 4a93542..6dd7bb3 100644 --- a/t/unit/core/store_lookup_test.c +++ b/t/unit/core/store_lookup_test.c @@ -534,6 +534,18 @@ START_TEST(test_lookup) "OBJ\\[attribute\\]\\{ NAME\\{ 'x', \\(nil\\) \\}" }, { "attribute.k1 = 'v1'", 1, "ATTR\\[k1\\]\\{ VALUE\\{ 'v1', \\(nil\\) \\} \\}" }, + { "attribute.k2 < 123", 0, + "ATTR\\[k2\\]\\{ < 123 \\}" }, + { "attribute.k2 <= 123", 1, + "ATTR\\[k2\\]\\{ <= 123 \\}" }, + { "attribute.k2 >= 123", 1, + "ATTR\\[k2\\]\\{ >= 123 \\}" }, + { "attribute.k2 > 123", 0, + "ATTR\\[k2\\]\\{ > 123 \\}" }, + { "attribute.k2 = 123", 1, + "ATTR\\[k2\\]\\{ = 123 \\}" }, + { "attribute.k2 != 123", 2, + "\\(NOT, ATTR\\[k2\\]\\{ = 123 \\}\\)" }, { "attribute.k1 != 'v1'", 2, "\\(NOT, ATTR\\[k1\\]\\{ VALUE\\{ 'v1', \\(nil\\) \\} \\}\\)" }, { "attribute.k1 != 'v2'", 3, diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c index e245c29..8c62660 100644 --- a/t/unit/frontend/parser_test.c +++ b/t/unit/frontend/parser_test.c @@ -77,6 +77,53 @@ START_TEST(test_parse) "service.name =~ 'p' OR " "service.name =~ 'r'", -1, 1, CONNECTION_LOOKUP }, + /* numeric constants */ + { "LOOKUP hosts WHERE " + "attribute.foo = " + "1234", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo != " + "+234", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo < " + "-234", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo > " + "12.4", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo <= " + "12.", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo >= " + ".4", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "+12e3", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "+12e-3", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "-12e+3", -1, 1, CONNECTION_LOOKUP }, + + /* invalid numeric constants */ + { "LOOKUP hosts WHERE " + "attribute.foo = " + "+-12e+3", -1, -1, 0 }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "-12e-+3", -1, -1, 0 }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "e+3", -1, -1, 0 }, + { "LOOKUP hosts WHERE " + "attribute.foo = " + "3e", -1, -1, 0 }, + /* following SQL standard, we don't support hex numbers */ + { "LOOKUP hosts WHERE " + "attribute.foo = " + "0x12", -1, -1, 0 }, + /* comments */ { "/* some comment */", -1, 0, 0 }, { "-- another comment", -1, 0, 0 }, -- 2.30.2