Code

Build a more generic/powerful query API which writes to a store-writer.
[sysdb.git] / src / core / store_exec.c
1 /*
2  * SysDB - src/core/store_exec.c
3  * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "core/object.h"
29 #include "core/plugin.h"
30 #include "core/store-private.h"
31 #include "frontend/connection.h"
32 #include "parser/ast.h"
33 #include "utils/error.h"
35 #include <errno.h>
37 #include <arpa/inet.h>
38 #include <stdlib.h>
39 #include <string.h>
41 /*
42  * private helper functions
43  */
45 typedef struct {
46         sdb_store_obj_t *current_host;
48         sdb_store_writer_t *w;
49         sdb_object_t *wd;
50 } iter_t;
52 static int
53 maybe_emit_host(iter_t *iter, sdb_store_obj_t *obj)
54 {
55         if ((obj->type == SDB_HOST) || (obj->type == SDB_ATTRIBUTE))
56                 return 0;
57         if (iter->current_host == obj->parent)
58                 return 0;
59         iter->current_host = obj->parent;
60         return sdb_store_emit(obj->parent, iter->w, iter->wd);
61 } /* maybe_emit_host */
63 static int
64 list_tojson(sdb_store_obj_t *obj,
65                 sdb_store_matcher_t __attribute__((unused)) *filter,
66                 void *user_data)
67 {
68         iter_t *iter = user_data;
69         maybe_emit_host(iter, obj);
70         return sdb_store_emit(obj, iter->w, iter->wd);
71 } /* list_tojson */
73 static int
74 lookup_tojson(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
75                 void *user_data)
76 {
77         iter_t *iter = user_data;
78         maybe_emit_host(iter, obj);
79         return sdb_store_emit_full(obj, filter, iter->w, iter->wd);
80 } /* lookup_tojson */
82 /*
83  * query implementations
84  */
86 static int
87 exec_fetch(sdb_store_t *store,
88                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
89                 int type, const char *hostname, const char *name,
90                 sdb_store_matcher_t *filter)
91 {
92         sdb_store_obj_t *host;
93         sdb_store_obj_t *obj;
95         int status = 0;
97         if ((! name) || ((type == SDB_HOST) && hostname)
98                         || ((type != SDB_HOST) && (! hostname))) {
99                 /* This is a programming error, not something the client did wrong */
100                 sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
101                                 "arguments to FETCH(%s, %s, %s)",
102                                 SDB_STORE_TYPE_TO_NAME(type), hostname, name);
103                 return -1;
104         }
105         if (type == SDB_HOST)
106                 hostname = name;
108         host = sdb_store_get_host(store, hostname);
109         if ((! host)
110                         || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
111                 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
112                                 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
113                                 name, hostname);
114                 sdb_object_deref(SDB_OBJ(host));
115                 return -1;
116         }
117         if (type == SDB_HOST) {
118                 obj = host;
119         }
120         else {
121                 obj = sdb_store_get_child(host, type, name);
122                 if ((! obj)
123                                 || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
124                         sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
125                                         "%s not found", SDB_STORE_TYPE_TO_NAME(type),
126                                         hostname, name, name);
127                         if (obj)
128                                 sdb_object_deref(SDB_OBJ(obj));
129                         sdb_object_deref(SDB_OBJ(host));
130                         return -1;
131                 }
132                 sdb_object_deref(SDB_OBJ(host));
133         }
134         host = NULL;
136         if (type != SDB_HOST)
137                 status = sdb_store_emit(obj->parent, w, wd);
138         if (status || sdb_store_emit_full(obj, filter, w, wd)) {
139                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
140                                 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
141                                 hostname, name);
142                 sdb_strbuf_sprintf(errbuf, "Out of memory");
143                 sdb_object_deref(SDB_OBJ(obj));
144                 return -1;
145         }
147         sdb_object_deref(SDB_OBJ(obj));
148         return SDB_CONNECTION_DATA;
149 } /* exec_fetch */
151 static int
152 exec_list(sdb_store_t *store,
153                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
154                 int type, sdb_store_matcher_t *filter)
156         iter_t iter = { NULL, w, wd };
158         if (sdb_store_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) {
159                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
160                                 "store to JSON");
161                 sdb_strbuf_sprintf(errbuf, "Out of memory");
162                 return -1;
163         }
165         return SDB_CONNECTION_DATA;
166 } /* exec_list */
168 static int
169 exec_lookup(sdb_store_t *store,
170                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
171                 int type, sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
173         iter_t iter = { NULL, w, wd };
175         if (sdb_store_scan(store, type, m, filter, lookup_tojson, &iter)) {
176                 sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
177                                 SDB_STORE_TYPE_TO_NAME(type));
178                 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
179                                 SDB_STORE_TYPE_TO_NAME(type));
180                 return -1;
181         }
183         return SDB_CONNECTION_DATA;
184 } /* exec_lookup */
186 /*
187  * public API
188  */
190 int
191 sdb_store_query_execute(sdb_store_t *store, sdb_store_query_t *q,
192                 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf)
194         sdb_ast_node_t *ast;
196         if (! q)
197                 return -1;
198         if (! q->ast) {
199                 sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
200                 return -1;
201         }
203         ast = q->ast;
204         switch (ast->type) {
205         case SDB_AST_TYPE_FETCH:
206                 return exec_fetch(store, w, wd, errbuf, SDB_AST_FETCH(ast)->obj_type,
207                                 SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
208                                 q->filter);
210         case SDB_AST_TYPE_LIST:
211                 return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type,
212                                 q->filter);
214         case SDB_AST_TYPE_LOOKUP:
215                 return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
216                                 q->matcher, q->filter);
218         default:
219                 sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
220                                 SDB_AST_TYPE_TO_STRING(ast));
221                 return -1;
222         }
224         return 0;
225 } /* sdb_store_query_execute */
227 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */