From 07dada8e5c614f0ef90fed8e86183ba7acd0e6e8 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 13 Oct 2015 20:27:24 +0200 Subject: [PATCH] Add support for fetching arbitrary objects, including attributes. That is, the backend now supports this. The functionality is not yet exposed via SysQL. --- src/core/memstore_exec.c | 99 +++++++++++++------------ src/frontend/query.c | 1 + src/include/parser/ast.h | 9 ++- src/parser/analyzer.c | 156 +++++++++++++++++++++------------------ src/parser/ast.c | 9 ++- src/parser/grammar.y | 4 +- 6 files changed, 152 insertions(+), 126 deletions(-) diff --git a/src/core/memstore_exec.c b/src/core/memstore_exec.c index ce8f825..a489a66 100644 --- a/src/core/memstore_exec.c +++ b/src/core/memstore_exec.c @@ -86,22 +86,12 @@ lookup_tojson(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, static int exec_fetch(sdb_memstore_t *store, sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf, - int type, const char *hostname, const char *name, bool full, - sdb_memstore_matcher_t *filter) + int type, const char *hostname, int parent_type, const char *parent, + const char *name, bool full, sdb_memstore_matcher_t *filter) { - sdb_memstore_obj_t *host; - sdb_memstore_obj_t *obj; - + sdb_memstore_obj_t *host, *p = NULL, *obj; int status = 0; - if ((! name) || ((type == SDB_HOST) && hostname) - || ((type != SDB_HOST) && (! hostname))) { - /* This is a programming error, not something the client did wrong */ - sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid " - "arguments to FETCH(%s, %s, %s)", - SDB_STORE_TYPE_TO_NAME(type), hostname, name); - return -1; - } if (type == SDB_HOST) hostname = name; @@ -114,43 +104,59 @@ exec_fetch(sdb_memstore_t *store, sdb_object_deref(SDB_OBJ(host)); return -1; } - if (type == SDB_HOST) { - obj = host; - } - else { - obj = sdb_memstore_get_child(host, type, name); - if ((! obj) - || (filter && (! sdb_memstore_matcher_matches(filter, obj, NULL)))) { - sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: " - "%s not found", SDB_STORE_TYPE_TO_NAME(type), - hostname, name, name); - if (obj) - sdb_object_deref(SDB_OBJ(obj)); - sdb_object_deref(SDB_OBJ(host)); - return -1; + obj = host; + if (type != SDB_HOST) { + if (parent) { + p = sdb_memstore_get_child(obj, parent_type, parent); + if ((! p) || (filter + && (! sdb_memstore_matcher_matches(filter, p, NULL)))) { + sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s.%s: " + "%s not found", SDB_STORE_TYPE_TO_NAME(type), + hostname, parent, name, parent); + status = -1; + } + obj = p; + } + if (! status) { + obj = sdb_memstore_get_child(obj, type, name); + if ((! obj) || (filter + && (! sdb_memstore_matcher_matches(filter, obj, NULL)))) { + sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: " + "%s not found", SDB_STORE_TYPE_TO_NAME(type), + hostname, name, name); + status = -1; + } } - sdb_object_deref(SDB_OBJ(host)); } - host = NULL; - if (type != SDB_HOST) - status = sdb_memstore_emit(obj->parent, w, wd); if (! status) { - if (full) - status = sdb_memstore_emit_full(obj, filter, w, wd); - else - status = sdb_memstore_emit(obj, w, wd); - } - if (status) { - sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize " - "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type), - hostname, name); - sdb_strbuf_sprintf(errbuf, "Out of memory"); - sdb_object_deref(SDB_OBJ(obj)); - return -1; + if (type != SDB_HOST) + status = sdb_memstore_emit(host, w, wd); + if ((! status) && parent) + status = sdb_memstore_emit(p, w, wd); + if (! status) { + if (full) + status = sdb_memstore_emit_full(obj, filter, w, wd); + else + status = sdb_memstore_emit(obj, w, wd); + } + if (status) { + sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize " + "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type), + hostname, name); + sdb_strbuf_sprintf(errbuf, "Out of memory"); + status = -1; + } } + if (host != obj) + sdb_object_deref(SDB_OBJ(host)); + if (p != obj) + sdb_object_deref(SDB_OBJ(p)); sdb_object_deref(SDB_OBJ(obj)); + + if (status) + return status; return SDB_CONNECTION_DATA; } /* exec_fetch */ @@ -209,9 +215,10 @@ sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *q, ast = q->ast; switch (ast->type) { case SDB_AST_TYPE_FETCH: - return exec_fetch(store, w, wd, errbuf, SDB_AST_FETCH(ast)->obj_type, - SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name, - SDB_AST_FETCH(ast)->full, q->filter); + return exec_fetch(store, w, wd, errbuf, + SDB_AST_FETCH(ast)->obj_type, SDB_AST_FETCH(ast)->hostname, + SDB_AST_FETCH(ast)->parent_type, SDB_AST_FETCH(ast)->parent, + SDB_AST_FETCH(ast)->name, SDB_AST_FETCH(ast)->full, q->filter); case SDB_AST_TYPE_LIST: return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type, diff --git a/src/frontend/query.c b/src/frontend/query.c index 28e1e31..4ae4f64 100644 --- a/src/frontend/query.c +++ b/src/frontend/query.c @@ -394,6 +394,7 @@ sdb_conn_fetch(sdb_conn_t *conn) ast = sdb_ast_fetch_create((int)type, hostname[0] ? strdup(hostname) : NULL, + -1, NULL, name[0] ? strdup(name) : NULL, /* full */ 1, /* filter = */ NULL); status = exec_cmd(conn, ast); diff --git a/src/include/parser/ast.h b/src/include/parser/ast.h index 0736876..01446ab 100644 --- a/src/include/parser/ast.h +++ b/src/include/parser/ast.h @@ -257,6 +257,8 @@ typedef struct { sdb_ast_node_t super; int obj_type; char *hostname; /* optional */ + int parent_type; /* optional */ + char *parent; /* optional */ char *name; /* whether to include the full object, that is, * including all attributes and all children */ @@ -265,7 +267,7 @@ typedef struct { } sdb_ast_fetch_t; #define SDB_AST_FETCH(obj) ((sdb_ast_fetch_t *)(obj)) #define SDB_AST_FETCH_INIT \ - { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH, -1 }, -1, NULL, NULL, 0, NULL } + { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH, -1 }, -1, NULL, -1, NULL, NULL, 0, NULL } /* * sdb_ast_list_t represents a LIST command. @@ -387,8 +389,9 @@ sdb_ast_value_create(int type, char *name); * takes ownership of the strings and the filter node. */ sdb_ast_node_t * -sdb_ast_fetch_create(int obj_type, char *hostname, char *name, bool full, - sdb_ast_node_t *filter); +sdb_ast_fetch_create(int obj_type, char *hostname, + int parent_type, char *parent, char *name, + bool full, sdb_ast_node_t *filter); /* * sdb_ast_list_create: diff --git a/src/parser/analyzer.c b/src/parser/analyzer.c index ecae40f..4adeafc 100644 --- a/src/parser/analyzer.c +++ b/src/parser/analyzer.c @@ -85,6 +85,79 @@ iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...) r); } /* iter_error */ +/* + * generic checks + */ + +typedef struct { + int obj_type; + const char *hostname; + int parent_type; + const char *parent; + const char *name; +} parent_child_t; + +static int +analyze_parent_child(const char *cmd, parent_child_t *pc, sdb_strbuf_t *errbuf) +{ + if ((pc->obj_type != SDB_ATTRIBUTE) + && (! VALID_OBJ_TYPE(pc->obj_type))) { + sdb_strbuf_sprintf(errbuf, "Invalid object type %#x " + "in %s command", pc->obj_type, cmd); + return -1; + } + if (! pc->name) { + sdb_strbuf_sprintf(errbuf, "Missing object name in " + "%s %s command", cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + + if ((pc->obj_type == SDB_HOST) && pc->hostname) { + sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' " + "in %s HOST command", pc->hostname, cmd); + return -1; + } + else if ((pc->obj_type != SDB_HOST) && (! pc->hostname)) { + sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' " + "in %s %s command", pc->name, + cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + + if (pc->obj_type == SDB_ATTRIBUTE) { + if ((pc->parent_type <= 0) && pc->parent) { + sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' " + "in %s %s command", pc->parent, + cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + else if (pc->parent_type > 0) { + if (! VALID_OBJ_TYPE(pc->parent_type)) { + sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x " + "in %s %s command", pc->parent_type, + cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + if (! pc->parent) { + sdb_strbuf_sprintf(errbuf, "Missing %s parent name " + "in %s %s command", + SDB_STORE_TYPE_TO_NAME(pc->parent_type), + cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + } + } + else if ((pc->parent_type > 0) || pc->parent) { + sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' " + "in %s %s command", + SDB_STORE_TYPE_TO_NAME(pc->parent_type), + pc->parent ? pc->parent : "", + cmd, SDB_STORE_TYPE_TO_NAME(pc->obj_type)); + return -1; + } + return 0; +} /* analyze_parent_child */ + /* * expression nodes */ @@ -426,28 +499,13 @@ analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf) static int analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf) { - if (! VALID_OBJ_TYPE(fetch->obj_type)) { - sdb_strbuf_sprintf(errbuf, "Invalid object type %#x " - "in FETCH command", fetch->obj_type); - return -1; - } - if (! fetch->name) { - sdb_strbuf_sprintf(errbuf, "Missing object name in " - "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type)); - return -1; - } + parent_child_t pc = { + fetch->obj_type, fetch->hostname, + fetch->parent_type, fetch->parent, fetch->name, + }; - if ((fetch->obj_type == SDB_HOST) && fetch->hostname) { - sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' " - "in FETCH HOST command", fetch->hostname); + if (analyze_parent_child("FETCH", &pc, errbuf)) return -1; - } - else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) { - sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' " - "in FETCH %s command", fetch->name, - SDB_STORE_TYPE_TO_NAME(fetch->obj_type)); - return -1; - } if (fetch->filter) return analyze_node(FILTER_CTX, fetch->filter, errbuf); @@ -488,61 +546,13 @@ analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf) static int analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf) { - if ((st->obj_type != SDB_ATTRIBUTE) - && (! VALID_OBJ_TYPE(st->obj_type))) { - sdb_strbuf_sprintf(errbuf, "Invalid object type %#x " - "in STORE command", st->obj_type); - return -1; - } - if (! st->name) { - sdb_strbuf_sprintf(errbuf, "Missing object name in " - "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type)); - return -1; - } - - if ((st->obj_type == SDB_HOST) && st->hostname) { - sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' " - "in STORE HOST command", st->hostname); - return -1; - } - else if ((st->obj_type != SDB_HOST) && (! st->hostname)) { - sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' " - "in STORE %s command", st->name, - SDB_STORE_TYPE_TO_NAME(st->obj_type)); - return -1; - } + parent_child_t pc = { + st->obj_type, st->hostname, + st->parent_type, st->parent, st->name, + }; - if (st->obj_type == SDB_ATTRIBUTE) { - if ((st->parent_type <= 0) && st->parent) { - sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' " - "in STORE %s command", st->parent, - SDB_STORE_TYPE_TO_NAME(st->obj_type)); - return -1; - } - else if (st->parent_type > 0) { - if (! VALID_OBJ_TYPE(st->parent_type)) { - sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x " - "in STORE %s command", st->parent_type, - SDB_STORE_TYPE_TO_NAME(st->obj_type)); - return -1; - } - if (! st->parent) { - sdb_strbuf_sprintf(errbuf, "Missing %s parent name " - "in STORE %s command", - SDB_STORE_TYPE_TO_NAME(st->parent_type), - SDB_STORE_TYPE_TO_NAME(st->obj_type)); - return -1; - } - } - } - else if ((st->parent_type > 0) || st->parent) { - sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' " - "in STORE %s command", - SDB_STORE_TYPE_TO_NAME(st->parent_type), - st->parent ? st->parent : "", - SDB_STORE_TYPE_TO_NAME(st->obj_type)); + if (analyze_parent_child("STORE", &pc, errbuf)) return -1; - } if (st->obj_type == SDB_METRIC) { if ((! st->store_type) != (! st->store_id)) { diff --git a/src/parser/ast.c b/src/parser/ast.c index 43fcd41..dcfe786 100644 --- a/src/parser/ast.c +++ b/src/parser/ast.c @@ -85,6 +85,8 @@ fetch_destroy(sdb_object_t *obj) sdb_ast_fetch_t *fetch = SDB_AST_FETCH(obj); if (fetch->hostname) free(fetch->hostname); + if (fetch->parent) + free(fetch->parent); if (fetch->name) free(fetch->name); fetch->hostname = fetch->name = NULL; @@ -289,8 +291,9 @@ sdb_ast_value_create(int type, char *name) } /* sdb_ast_value_create */ sdb_ast_node_t * -sdb_ast_fetch_create(int obj_type, char *hostname, char *name, bool full, - sdb_ast_node_t *filter) +sdb_ast_fetch_create(int obj_type, char *hostname, + int parent_type, char *parent, char *name, + bool full, sdb_ast_node_t *filter) { sdb_ast_fetch_t *fetch; fetch = SDB_AST_FETCH(sdb_object_create("FETCH", fetch_type)); @@ -301,6 +304,8 @@ sdb_ast_fetch_create(int obj_type, char *hostname, char *name, bool full, fetch->obj_type = obj_type; fetch->hostname = hostname; + fetch->parent_type = parent_type; + fetch->parent = parent; fetch->name = name; fetch->full = full; fetch->filter = filter; diff --git a/src/parser/grammar.y b/src/parser/grammar.y index b94300a..c350d54 100644 --- a/src/parser/grammar.y +++ b/src/parser/grammar.y @@ -281,13 +281,13 @@ statement: fetch_statement: FETCH object_type STRING filter_clause { - $$ = sdb_ast_fetch_create($2, NULL, $3, 1, $4); + $$ = sdb_ast_fetch_create($2, NULL, -1, NULL, $3, 1, $4); CK_OOM($$); } | FETCH object_type STRING '.' STRING filter_clause { - $$ = sdb_ast_fetch_create($2, $3, $5, 1, $6); + $$ = sdb_ast_fetch_create($2, $3, -1, NULL, $5, 1, $6); CK_OOM($$); } ; -- 2.30.2