From 518059384a38dbf5b4384c77dc859689ce80cc9d Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 19 May 2015 23:11:35 +0200 Subject: [PATCH] parser: Add support for IS [NOT] TRUE / FALSE queries. --- src/core/store_query.c | 6 ++++ src/include/parser/ast.h | 50 ++++++++++++++++++--------------- src/parser/analyzer.c | 2 ++ src/parser/grammar.y | 30 ++++++++++++++++++++ src/parser/scanner.l | 2 ++ t/unit/core/store_lookup_test.c | 5 ++++ t/unit/parser/parser_test.c | 34 ++++++++++++++++++++-- 7 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/core/store_query.c b/src/core/store_query.c index 17ee17f..ff7089c 100644 --- a/src/core/store_query.c +++ b/src/core/store_query.c @@ -177,6 +177,12 @@ cmp_to_matcher(sdb_ast_node_t *n) case SDB_AST_ISNULL: m = sdb_store_isnull_matcher(right); break; + case SDB_AST_ISTRUE: + m = sdb_store_istrue_matcher(right); + break; + case SDB_AST_ISFALSE: + m = sdb_store_isfalse_matcher(right); + break; case SDB_AST_IN: m = sdb_store_in_matcher(left, right); break; diff --git a/src/include/parser/ast.h b/src/include/parser/ast.h index 80b5a53..8533fc7 100644 --- a/src/include/parser/ast.h +++ b/src/include/parser/ast.h @@ -76,20 +76,22 @@ typedef enum { || (((n)->type == SDB_AST_TYPE_ITERATOR) \ && ((SDB_AST_ALL <= SDB_AST_ITER(n)->kind) \ && (SDB_AST_ITER(n)->kind <= SDB_AST_ANY)))) - SDB_AST_AND = 1000, - SDB_AST_OR = 1001, - SDB_AST_NOT = 1002, - - SDB_AST_LT = 1010, - SDB_AST_LE = 1011, - SDB_AST_EQ = 1012, - SDB_AST_NE = 1013, - SDB_AST_GE = 1014, - SDB_AST_GT = 1015, - SDB_AST_REGEX = 1016, - SDB_AST_NREGEX = 1017, - SDB_AST_ISNULL = 1018, - SDB_AST_IN = 1019, + SDB_AST_AND = 1000, + SDB_AST_OR = 1001, + SDB_AST_NOT = 1002, + + SDB_AST_LT = 1010, + SDB_AST_LE = 1011, + SDB_AST_EQ = 1012, + SDB_AST_NE = 1013, + SDB_AST_GE = 1014, + SDB_AST_GT = 1015, + SDB_AST_REGEX = 1016, + SDB_AST_NREGEX = 1017, + SDB_AST_ISNULL = 1018, + SDB_AST_ISTRUE = 1019, + SDB_AST_ISFALSE = 1020, + SDB_AST_IN = 1021, /* arithmetic expressions */ #define SDB_AST_IS_ARITHMETIC(n) \ @@ -99,20 +101,20 @@ typedef enum { || (((n)->type == SDB_AST_TYPE_OPERATOR) \ && ((SDB_AST_ADD <= SDB_AST_OP(n)->kind) \ && (SDB_AST_OP(n)->kind <= SDB_AST_CONCAT)))) - SDB_AST_ADD = 2000, - SDB_AST_SUB = 2001, - SDB_AST_MUL = 2002, - SDB_AST_DIV = 2003, - SDB_AST_MOD = 2004, - SDB_AST_CONCAT = 2005, + SDB_AST_ADD = 2000, + SDB_AST_SUB = 2001, + SDB_AST_MUL = 2002, + SDB_AST_DIV = 2003, + SDB_AST_MOD = 2004, + SDB_AST_CONCAT = 2005, /* iterators */ #define SDB_AST_IS_ITERATOR(n) \ (((n)->type == SDB_AST_TYPE_ITERATOR) \ && ((SDB_AST_ALL <= SDB_AST_ITER(n)->kind) \ && (SDB_AST_ITER(n)->kind <= SDB_AST_ANY))) - SDB_AST_ALL = 3000, - SDB_AST_ANY = 3001, + SDB_AST_ALL = 3000, + SDB_AST_ANY = 3001, } sdb_ast_operator_t; #define SDB_AST_OP_TO_STRING(op) \ @@ -127,7 +129,9 @@ typedef enum { : ((op) == SDB_AST_GT) ? "GT" \ : ((op) == SDB_AST_REGEX) ? "REGEX" \ : ((op) == SDB_AST_NREGEX) ? "NREGEX" \ - : ((op) == SDB_AST_ISNULL) ? "ISNULL" \ + : ((op) == SDB_AST_ISNULL) ? "IS NULL" \ + : ((op) == SDB_AST_ISTRUE) ? "IS TRUE" \ + : ((op) == SDB_AST_ISFALSE) ? "IS FALSE" \ : ((op) == SDB_AST_IN) ? "IN" \ : ((op) == SDB_AST_ADD) ? "ADD" \ : ((op) == SDB_AST_SUB) ? "SUB" \ diff --git a/src/parser/analyzer.c b/src/parser/analyzer.c index e03cbdb..f352a0d 100644 --- a/src/parser/analyzer.c +++ b/src/parser/analyzer.c @@ -155,6 +155,8 @@ analyze_logical(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf) break; case SDB_AST_ISNULL: + case SDB_AST_ISTRUE: + case SDB_AST_ISFALSE: if (analyze_node(context, op->right, errbuf)) return -1; break; diff --git a/src/parser/grammar.y b/src/parser/grammar.y index 8014626..339f17a 100644 --- a/src/parser/grammar.y +++ b/src/parser/grammar.y @@ -127,6 +127,8 @@ sdb_parser_yyerrorf(YYLTYPE *lval, sdb_parser_yyscan_t scanner, const char *fmt, /* NULL token */ %token NULL_T +%token TRUE FALSE + %token FETCH LIST LOOKUP STORE TIMESERIES %token IDENTIFIER STRING @@ -481,6 +483,34 @@ comparison: CK_OOM($$); } | + expression IS TRUE + { + $$ = sdb_ast_op_create(SDB_AST_ISTRUE, NULL, $1); + CK_OOM($$); + } + | + expression IS NOT TRUE + { + $$ = sdb_ast_op_create(SDB_AST_ISTRUE, NULL, $1); + CK_OOM($$); + $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$); + CK_OOM($$); + } + | + expression IS FALSE + { + $$ = sdb_ast_op_create(SDB_AST_ISFALSE, NULL, $1); + CK_OOM($$); + } + | + expression IS NOT FALSE + { + $$ = sdb_ast_op_create(SDB_AST_ISFALSE, NULL, $1); + CK_OOM($$); + $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$); + CK_OOM($$); + } + | expression IN expression { $$ = sdb_ast_op_create(SDB_AST_IN, $1, $3); diff --git a/src/parser/scanner.l b/src/parser/scanner.l index 43ec844..8fce7d9 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -56,6 +56,7 @@ static struct { { "AND", AND }, { "ANY", ANY }, { "END", END }, + { "FALSE", FALSE }, { "FETCH", FETCH }, { "FILTER", FILTER }, { "IN", IN }, @@ -70,6 +71,7 @@ static struct { { "START", START }, { "STORE", STORE }, { "TIMESERIES", TIMESERIES }, + { "TRUE", TRUE }, { "UPDATE", UPDATE }, /* object types */ diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c index 14d2209..33c9268 100644 --- a/t/unit/core/store_lookup_test.c +++ b/t/unit/core/store_lookup_test.c @@ -592,8 +592,13 @@ struct { { "attribute['x1'] !~ 'v'", NULL, 0 }, { "attribute['k1'] IS NULL", NULL, 1 }, { "attribute['x1'] IS NULL", NULL, 3 }, + { "attribute['k1'] IS TRUE", NULL, 0 }, + { "attribute['x1'] IS TRUE", NULL, 0 }, + { "attribute['k1'] IS FALSE", NULL, 0 }, + { "attribute['x1'] IS FALSE", NULL, 0 }, { "attribute['k1'] IS NOT NULL", NULL, 2 }, { "attribute['x1'] IS NOT NULL", NULL, 0 }, + { "attribute['x1'] IS NOT TRUE", NULL, 3 }, { "attribute['k2'] < 123", NULL, 0 }, { "attribute['k2'] <= 123", NULL, 1 }, { "attribute['k2'] >= 123", NULL, 1 }, diff --git a/t/unit/parser/parser_test.c b/t/unit/parser/parser_test.c index cbcbe2c..4dcf684 100644 --- a/t/unit/parser/parser_test.c +++ b/t/unit/parser/parser_test.c @@ -372,7 +372,7 @@ struct { "ANY service.service.name = 's'", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, - /* NULL */ + /* NULL / TRUE / FALSE */ { "LOOKUP hosts MATCHING " "attribute['foo'] " "IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, @@ -384,6 +384,24 @@ struct { "IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, { "LOOKUP hosts MATCHING " "ANY service.name IS NULL", -1, -1, 0, 0 }, + { "LOOKUP hosts MATCHING " + "attribute['foo'] " + "IS TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "attribute['foo'] " + "IS NOT TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "NOT attribute['foo'] " + "IS TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "attribute['foo'] " + "IS FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "attribute['foo'] " + "IS NOT FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, + { "LOOKUP hosts MATCHING " + "NOT attribute['foo'] " + "IS FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST }, /* invalid numeric constants */ { "LOOKUP hosts MATCHING " @@ -530,6 +548,14 @@ struct { "name + 1 IS NULL", -1, -1, 0, 0 }, { "LOOKUP hosts FILTER " "name + 1 IS NULL", -1, -1, 0, 0 }, + { "LOOKUP hosts MATCHING " + "name + 1 IS TRUE", -1, -1, 0, 0 }, + { "LOOKUP hosts FILTER " + "name + 1 IS TRUE", -1, -1, 0, 0 }, + { "LOOKUP hosts MATCHING " + "name + 1 IS FALSE", -1, -1, 0, 0 }, + { "LOOKUP hosts FILTER " + "name + 1 IS FALSE", -1, -1, 0, 0 }, /* invalid iterators */ { "LOOKUP hosts MATCHING " @@ -832,9 +858,13 @@ struct { "2014-08-16 17:23", -1, SDB_AST_EQ }, { "attribute['foo'] = " "2014-08-16 17:23:53", -1, SDB_AST_EQ }, - /* NULL */ + /* NULL / TRUE / FALSE */ { "attribute['foo'] IS NULL", -1, SDB_AST_ISNULL }, { "attribute['foo'] IS NOT NULL", -1, SDB_AST_NOT }, + { "attribute['foo'] IS TRUE", -1, SDB_AST_ISTRUE }, + { "attribute['foo'] IS NOT TRUE", -1, SDB_AST_NOT }, + { "attribute['foo'] IS FALSE", -1, SDB_AST_ISFALSE }, + { "attribute['foo'] IS NOT FALSE", -1, SDB_AST_NOT }, /* array expressions */ { "backend < ['a']", -1, SDB_AST_LT }, { "backend <= ['a']", -1, SDB_AST_LE }, -- 2.30.2