1 /*
2 * SysDB - src/core/memstore_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/memstore-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_memstore_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_memstore_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_memstore_emit(obj->parent, iter->w, iter->wd);
61 } /* maybe_emit_host */
63 static int
64 list_tojson(sdb_memstore_obj_t *obj,
65 sdb_memstore_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_memstore_emit(obj, iter->w, iter->wd);
71 } /* list_tojson */
73 static int
74 lookup_tojson(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
75 void *user_data)
76 {
77 iter_t *iter = user_data;
78 maybe_emit_host(iter, obj);
79 return sdb_memstore_emit_full(obj, filter, iter->w, iter->wd);
80 } /* lookup_tojson */
82 /*
83 * query implementations
84 */
86 static int
87 exec_fetch(sdb_memstore_t *store,
88 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
89 int type, const char *hostname, int parent_type, const char *parent,
90 const char *name, bool full, sdb_memstore_matcher_t *filter)
91 {
92 sdb_memstore_obj_t *host, *p = NULL, *obj;
93 int status = 0;
95 if (type == SDB_HOST)
96 hostname = name;
98 host = sdb_memstore_get_host(store, hostname);
99 if ((! host)
100 || (filter && (! sdb_memstore_matcher_matches(filter, host, NULL)))) {
101 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
102 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
103 name, hostname);
104 sdb_object_deref(SDB_OBJ(host));
105 return -1;
106 }
107 obj = host;
108 if (type != SDB_HOST) {
109 if (parent) {
110 p = sdb_memstore_get_child(obj, parent_type, parent);
111 if ((! p) || (filter
112 && (! sdb_memstore_matcher_matches(filter, p, NULL)))) {
113 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s.%s: "
114 "%s not found", SDB_STORE_TYPE_TO_NAME(type),
115 hostname, parent, name, parent);
116 status = -1;
117 }
118 obj = p;
119 }
120 if (! status) {
121 obj = sdb_memstore_get_child(obj, type, name);
122 if ((! obj) || (filter
123 && (! sdb_memstore_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 status = -1;
128 }
129 }
130 }
132 if (! status) {
133 if (type != SDB_HOST)
134 status = sdb_memstore_emit(host, w, wd);
135 if ((! status) && parent)
136 status = sdb_memstore_emit(p, w, wd);
137 if (! status) {
138 if (full)
139 status = sdb_memstore_emit_full(obj, filter, w, wd);
140 else
141 status = sdb_memstore_emit(obj, w, wd);
142 }
143 if (status) {
144 sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize "
145 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
146 hostname, name);
147 sdb_strbuf_sprintf(errbuf, "Out of memory");
148 status = -1;
149 }
150 }
152 if (host != obj)
153 sdb_object_deref(SDB_OBJ(host));
154 if (p != obj)
155 sdb_object_deref(SDB_OBJ(p));
156 sdb_object_deref(SDB_OBJ(obj));
158 if (status)
159 return status;
160 return SDB_CONNECTION_DATA;
161 } /* exec_fetch */
163 static int
164 exec_list(sdb_memstore_t *store,
165 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
166 int type, sdb_memstore_matcher_t *filter)
167 {
168 iter_t iter = { NULL, w, wd };
170 if (sdb_memstore_scan(store, type, /* m = */ NULL, filter, list_tojson, &iter)) {
171 sdb_log(SDB_LOG_ERR, "memstore: Failed to serialize "
172 "store to JSON");
173 sdb_strbuf_sprintf(errbuf, "Out of memory");
174 return -1;
175 }
177 return SDB_CONNECTION_DATA;
178 } /* exec_list */
180 static int
181 exec_lookup(sdb_memstore_t *store,
182 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf,
183 int type, sdb_memstore_matcher_t *m, sdb_memstore_matcher_t *filter)
184 {
185 iter_t iter = { NULL, w, wd };
187 if (sdb_memstore_scan(store, type, m, filter, lookup_tojson, &iter)) {
188 sdb_log(SDB_LOG_ERR, "memstore: Failed to lookup %ss",
189 SDB_STORE_TYPE_TO_NAME(type));
190 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
191 SDB_STORE_TYPE_TO_NAME(type));
192 return -1;
193 }
195 return SDB_CONNECTION_DATA;
196 } /* exec_lookup */
198 /*
199 * public API
200 */
202 int
203 sdb_memstore_query_execute(sdb_memstore_t *store, sdb_memstore_query_t *q,
204 sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf)
205 {
206 sdb_ast_node_t *ast;
208 if (! q)
209 return -1;
210 if (! q->ast) {
211 sdb_log(SDB_LOG_ERR, "memstore: Invalid empty query");
212 return -1;
213 }
215 ast = q->ast;
216 switch (ast->type) {
217 case SDB_AST_TYPE_FETCH:
218 return exec_fetch(store, w, wd, errbuf,
219 SDB_AST_FETCH(ast)->obj_type, SDB_AST_FETCH(ast)->hostname,
220 SDB_AST_FETCH(ast)->parent_type, SDB_AST_FETCH(ast)->parent,
221 SDB_AST_FETCH(ast)->name, SDB_AST_FETCH(ast)->full, q->filter);
223 case SDB_AST_TYPE_LIST:
224 return exec_list(store, w, wd, errbuf, SDB_AST_LIST(ast)->obj_type,
225 q->filter);
227 case SDB_AST_TYPE_LOOKUP:
228 return exec_lookup(store, w, wd, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
229 q->matcher, q->filter);
231 default:
232 sdb_log(SDB_LOG_ERR, "memstore: Invalid query of type %s",
233 SDB_AST_TYPE_TO_STRING(ast));
234 return -1;
235 }
237 return 0;
238 } /* sdb_memstore_query_execute */
240 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */