X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ffrontend%2Fgrammar.y;h=93616ac07caa9bf7c9419577e89a559b3f6e38dd;hb=0862576c7a992044c91788265ea964dfee8d6217;hp=ce313310b918f9c6011410d2e9e9c60e430ab67d;hpb=a5bd3248d00810f3e576de71aa5ac2ebfb2f001a;p=sysdb.git diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index ce31331..93616ac 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -32,6 +32,8 @@ #include "frontend/grammar.h" #include "core/store.h" +#include "core/store-private.h" +#include "core/time.h" #include "utils/error.h" #include "utils/llist.h" @@ -62,27 +64,84 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %locations %error-verbose %expect 0 -%name-prefix="sdb_fe_yy" +%name-prefix "sdb_fe_yy" %union { + const char *sstr; /* static string */ char *str; + sdb_data_t data; + sdb_time_t datetime; + sdb_llist_t *list; sdb_conn_node_t *node; + + sdb_store_matcher_t *m; + sdb_store_expr_t *expr; } %start statements %token SCANNER_ERROR +%token AND OR IS NOT MATCHING FILTER +%token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX +%token CMP_LT CMP_LE CMP_GE CMP_GT +%token CONCAT + +%token START END + +/* NULL token */ +%token NULL_T + +%token FETCH LIST LOOKUP TIMESERIES + %token IDENTIFIER STRING -%token FETCH LIST + +%token INTEGER FLOAT + +%token DATE TIME + +/* Precedence (lowest first): */ +%left OR +%left AND +%right NOT +%left CMP_EQUAL CMP_NEQUAL +%left CMP_LT CMP_LE CMP_GE CMP_GT +%nonassoc CMP_REGEX CMP_NREGEX +%left CONCAT +%nonassoc IS +%left '+' '-' +%left '*' '/' '%' +%left '[' ']' +%left '(' ')' +%left '.' %type statements %type statement fetch_statement list_statement - expression + lookup_statement + timeseries_statement + matching_clause + filter_clause + condition + +%type matcher + compare_matcher + +%type expression + +%type cmp + +%type data + interval interval_elem + +%type datetime + start_clause end_clause + +%destructor { free($$); } +%destructor { sdb_object_deref(SDB_OBJ($$)); } %% @@ -93,7 +152,8 @@ statements: if (parser_mode != SDB_PARSE_DEFAULT) { sdb_fe_yyerror(&yylloc, scanner, YY_("syntax error, unexpected statement, " - "expecting expression")); + "expecting condition")); + sdb_object_deref(SDB_OBJ($3)); YYABORT; } @@ -109,7 +169,8 @@ statements: if (parser_mode != SDB_PARSE_DEFAULT) { sdb_fe_yyerror(&yylloc, scanner, YY_("syntax error, unexpected statement, " - "expecting expression")); + "expecting condition")); + sdb_object_deref(SDB_OBJ($1)); YYABORT; } @@ -119,13 +180,14 @@ statements: } } | - expression + condition { - /* only accept this in expression parse mode */ - if (! (parser_mode & SDB_PARSE_EXPR)) { + /* only accept this in condition parse mode */ + if (! (parser_mode & SDB_PARSE_COND)) { sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, unexpected expression, " + YY_("syntax error, unexpected condition, " "expecting statement")); + sdb_object_deref(SDB_OBJ($1)); YYABORT; } @@ -141,45 +203,376 @@ statement: | list_statement | + lookup_statement + | + timeseries_statement + | /* empty */ { $$ = NULL; } ; +/* + * FETCH [FILTER ]; + * + * Retrieve detailed information about a single host. + */ fetch_statement: - FETCH STRING + FETCH IDENTIFIER STRING filter_clause { + /* TODO: support other types as well */ + if (strcasecmp($2, "host")) { + char errmsg[strlen($2) + 32]; + snprintf(errmsg, sizeof(errmsg), + YY_("unknown data-source %s"), $2); + sdb_fe_yyerror(&yylloc, scanner, errmsg); + free($2); $2 = NULL; + free($3); $3 = NULL; + sdb_object_deref(SDB_OBJ($4)); + YYABORT; + } + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, conn_fetch_t, conn_fetch_destroy)); - CONN_FETCH($$)->name = strdup($2); + CONN_FETCH($$)->type = SDB_HOST; + CONN_FETCH($$)->name = $3; + CONN_FETCH($$)->filter = CONN_MATCHER($4); $$->cmd = CONNECTION_FETCH; - free($2); - $2 = NULL; + free($2); $2 = NULL; } ; +/* + * LIST [FILTER ]; + * + * Returns a list of all hosts in the store. + */ list_statement: - LIST + LIST IDENTIFIER filter_clause { - $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL, - sdb_conn_node_t)); + int type = sdb_store_parse_object_type_plural($2); + if (type < 0) { + char errmsg[strlen($2) + 32]; + snprintf(errmsg, sizeof(errmsg), + YY_("unknown data-source %s"), $2); + sdb_fe_yyerror(&yylloc, scanner, errmsg); + free($2); $2 = NULL; + sdb_object_deref(SDB_OBJ($3)); + YYABORT; + } + + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_list_t, conn_list_destroy)); + CONN_LIST($$)->type = type; + CONN_LIST($$)->filter = CONN_MATCHER($3); $$->cmd = CONNECTION_LIST; + free($2); $2 = NULL; } ; -expression: - STRING +/* + * LOOKUP MATCHING [FILTER ]; + * + * Returns detailed information about matching condition. + */ +lookup_statement: + LOOKUP IDENTIFIER matching_clause filter_clause + { + /* TODO: support other types as well */ + if (strcasecmp($2, "hosts")) { + char errmsg[strlen($2) + 32]; + snprintf(errmsg, sizeof(errmsg), + YY_("unknown data-source %s"), $2); + sdb_fe_yyerror(&yylloc, scanner, errmsg); + free($2); $2 = NULL; + sdb_object_deref(SDB_OBJ($3)); + sdb_object_deref(SDB_OBJ($4)); + YYABORT; + } + + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_lookup_t, conn_lookup_destroy)); + CONN_LOOKUP($$)->type = SDB_HOST; + CONN_LOOKUP($$)->matcher = CONN_MATCHER($3); + CONN_LOOKUP($$)->filter = CONN_MATCHER($4); + $$->cmd = CONNECTION_LOOKUP; + free($2); $2 = NULL; + } + ; + +matching_clause: + MATCHING condition { $$ = $2; } + | + /* empty */ { $$ = NULL; } + +filter_clause: + FILTER condition { $$ = $2; } + | + /* empty */ { $$ = NULL; } + +/* + * TIMESERIES . [START ] [END ]; + * + * Returns a time-series for the specified host's metric. + */ +timeseries_statement: + TIMESERIES STRING '.' STRING start_clause end_clause { - $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL, - conn_node_matcher_t)); + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_ts_t, conn_ts_destroy)); + CONN_TS($$)->hostname = $2; + CONN_TS($$)->metric = $4; + CONN_TS($$)->opts.start = $5; + CONN_TS($$)->opts.end = $6; + $$->cmd = CONNECTION_TIMESERIES; + } + ; + +start_clause: + START datetime { $$ = $2; } + | + /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; } + +end_clause: + END datetime { $$ = $2; } + | + /* empty */ { $$ = sdb_gettime(); } + +/* + * Basic expressions. + */ + +condition: + matcher + { + if (! $1) { + /* TODO: improve error reporting */ + sdb_fe_yyerror(&yylloc, scanner, + YY_("syntax error, invalid condition")); + YYABORT; + } + + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_matcher_t, conn_matcher_destroy)); $$->cmd = CONNECTION_EXPR; - /* XXX: this is just a placeholder for now */ - CONN_MATCHER($$)->matcher = sdb_store_host_matcher($1, - /* name_re = */ NULL, /* service = */ NULL, - /* attr = */ NULL); - free($1); - $1 = NULL; + CONN_MATCHER($$)->matcher = $1; + } + ; + +matcher: + '(' matcher ')' + { + $$ = $2; + } + | + matcher AND matcher + { + $$ = sdb_store_con_matcher($1, $3); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($3)); + } + | + matcher OR matcher + { + $$ = sdb_store_dis_matcher($1, $3); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($3)); + } + | + NOT matcher + { + $$ = sdb_store_inv_matcher($2); + sdb_object_deref(SDB_OBJ($2)); + } + | + compare_matcher + { + $$ = $1; + } + ; + +/* + * . + * + * Parse matchers comparing object attributes with a value. + */ +compare_matcher: + '.' IDENTIFIER cmp expression + { + $$ = sdb_store_matcher_parse_field_cmp($2, $3, $4); + free($2); $2 = NULL; + sdb_object_deref(SDB_OBJ($4)); + } + | + IDENTIFIER cmp expression + { + $$ = sdb_store_matcher_parse_cmp($1, NULL, $2, $3); + free($1); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); + } + | + IDENTIFIER '[' IDENTIFIER ']' cmp expression + { + $$ = sdb_store_matcher_parse_cmp($1, $3, $5, $6); + free($1); $1 = NULL; + free($3); $3 = NULL; + sdb_object_deref(SDB_OBJ($6)); + } + | + IDENTIFIER '[' IDENTIFIER ']' IS NULL_T + { + $$ = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL); + free($1); $1 = NULL; + free($3); $3 = NULL; + } + | + IDENTIFIER '[' IDENTIFIER ']' IS NOT NULL_T + { + sdb_store_matcher_t *m; + m = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL); + free($1); $1 = NULL; + free($3); $3 = NULL; + + /* sdb_store_inv_matcher return NULL if m==NULL */ + $$ = sdb_store_inv_matcher(m); + sdb_object_deref(SDB_OBJ(m)); + } + ; + +expression: + '(' expression ')' + { + $$ = $2; + } + | + expression '+' expression + { + $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '-' expression + { + $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '*' expression + { + $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '/' expression + { + $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '%' expression + { + $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression CONCAT expression + { + $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + '.' IDENTIFIER + { + int field = sdb_store_parse_field_name($2); + free($2); $2 = NULL; + $$ = sdb_store_expr_fieldvalue(field); + } + | + data + { + $$ = sdb_store_expr_constvalue(&$1); + sdb_data_free_datum(&$1); + } + ; + +cmp: + CMP_EQUAL { $$ = "="; } + | + CMP_NEQUAL { $$ = "!="; } + | + 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; } + | + datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; } + | + interval { $$ = $1; } + ; + +datetime: + DATE TIME { $$ = $1 + $2; } + | + DATE { $$ = $1; } + | + TIME { $$ = $1; } + ; + +interval: + interval interval_elem + { + $$.data.datetime = $1.data.datetime + $2.data.datetime; + } + | + interval_elem { $$ = $1; } + ; + +interval_elem: + INTEGER IDENTIFIER + { + sdb_time_t unit = 1; + + unit = sdb_strpunit($2); + if (! unit) { + char errmsg[strlen($2) + 32]; + snprintf(errmsg, sizeof(errmsg), + YY_("invalid time unit %s"), $2); + sdb_fe_yyerror(&yylloc, scanner, errmsg); + free($2); $2 = NULL; + YYABORT; + } + free($2); $2 = NULL; + + $$.type = SDB_TYPE_DATETIME; + $$.data.datetime = (sdb_time_t)$1.data.integer * unit; + + if ($1.data.integer < 0) { + sdb_fe_yyerror(&yylloc, scanner, + YY_("syntax error, negative intervals not supported")); + YYABORT; + } } ;