Code

Add support for fetching arbitrary objects, including attributes.
authorSebastian Harl <sh@tokkee.org>
Tue, 13 Oct 2015 18:27:24 +0000 (20:27 +0200)
committerSebastian Harl <sh@tokkee.org>
Tue, 13 Oct 2015 18:27:24 +0000 (20:27 +0200)
That is, the backend now supports this. The functionality is not yet exposed
via SysQL.

src/core/memstore_exec.c
src/frontend/query.c
src/include/parser/ast.h
src/parser/analyzer.c
src/parser/ast.c
src/parser/grammar.y

index ce8f825..a489a66 100644 (file)
@@ -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,
index 28e1e31..4ae4f64 100644 (file)
@@ -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);
index 0736876..01446ab 100644 (file)
@@ -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:
index ecae40f..4adeafc 100644 (file)
@@ -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 : "<unknown>",
+                               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 : "<unknown>",
-                               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)) {
index 43fcd41..dcfe786 100644 (file)
@@ -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;
index b94300a..c350d54 100644 (file)
@@ -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($$);
                }
        ;