Code

frontend: Drop sdb_fe_exec_* in favor of sdb_store_query_execute.
[sysdb.git] / src / frontend / query.c
1 /*
2  * SysDB - src/frontend/query.c
3  * Copyright (C) 2013-2014 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 #ifdef HAVE_CONFIG_H
29 #       include "config.h"
30 #endif
32 #include "sysdb.h"
34 #include "core/store.h"
35 #include "frontend/connection-private.h"
36 #include "parser/ast.h"
37 #include "parser/parser.h"
38 #include "utils/error.h"
39 #include "utils/proto.h"
40 #include "utils/strbuf.h"
42 #include <errno.h>
43 #include <string.h>
45 /*
46  * private helper functions
47  */
49 static int
50 query_exec(sdb_conn_t *conn, sdb_ast_node_t *ast)
51 {
52         sdb_store_query_t *q;
53         sdb_strbuf_t *buf;
54         int status;
56         if (! ast) {
57                 sdb_strbuf_sprintf(conn->errbuf, "out of memory");
58                 return -1;
59         }
61         q = sdb_store_query_prepare(ast);
62         if (! q) {
63                 /* this shouldn't happen */
64                 sdb_strbuf_sprintf(conn->errbuf, "failed to compile AST");
65                 sdb_log(SDB_LOG_ERR, "frontend: failed to compile AST");
66                 return -1;
67         }
69         buf = sdb_strbuf_create(1024);
70         if (! buf) {
71                 sdb_strbuf_sprintf(conn->errbuf, "Out of memory");
72                 sdb_object_deref(SDB_OBJ(q));
73                 return -1;
74         }
75         status = sdb_store_query_execute(q, buf, conn->errbuf);
76         if (status < 0) {
77                 char query[conn->cmd_len + 1];
78                 strncpy(query, sdb_strbuf_string(conn->buf), conn->cmd_len);
79                 query[sizeof(query) - 1] = '\0';
80                 sdb_log(SDB_LOG_ERR, "frontend: failed to execute query '%s'", query);
81         }
82         else
83                 sdb_connection_send(conn, status,
84                                 (uint32_t)sdb_strbuf_len(buf), sdb_strbuf_string(buf));
86         sdb_strbuf_destroy(buf);
87         sdb_object_deref(SDB_OBJ(q));
88         return status < 0 ? status : 0;
89 } /* query_exec */
91 /*
92  * public API
93  */
95 int
96 sdb_fe_query(sdb_conn_t *conn)
97 {
98         sdb_llist_t *parsetree;
99         sdb_ast_node_t *ast = NULL;
100         int status = 0;
102         if ((! conn) || (conn->cmd != SDB_CONNECTION_QUERY))
103                 return -1;
105         parsetree = sdb_parser_parse(sdb_strbuf_string(conn->buf),
106                         (int)conn->cmd_len, conn->errbuf);
107         if (! parsetree) {
108                 char query[conn->cmd_len + 1];
109                 strncpy(query, sdb_strbuf_string(conn->buf), conn->cmd_len);
110                 query[sizeof(query) - 1] = '\0';
111                 sdb_log(SDB_LOG_ERR, "frontend: Failed to parse query '%s': %s",
112                                 query, sdb_strbuf_string(conn->errbuf));
113                 return -1;
114         }
116         switch (sdb_llist_len(parsetree)) {
117                 case 0:
118                         /* skipping empty command; send back an empty reply */
119                         sdb_connection_send(conn, SDB_CONNECTION_DATA, 0, NULL);
120                         break;
121                 case 1:
122                         ast = SDB_AST_NODE(sdb_llist_get(parsetree, 0));
123                         break;
125                 default:
126                         {
127                                 char query[conn->cmd_len + 1];
128                                 strncpy(query, sdb_strbuf_string(conn->buf), conn->cmd_len);
129                                 query[sizeof(query) - 1] = '\0';
130                                 sdb_log(SDB_LOG_WARNING, "frontend: Ignoring %zu command%s "
131                                                 "in multi-statement query '%s'",
132                                                 sdb_llist_len(parsetree) - 1,
133                                                 sdb_llist_len(parsetree) == 2 ? "" : "s",
134                                                 query);
135                                 ast = SDB_AST_NODE(sdb_llist_get(parsetree, 0));
136                         }
137         }
139         if (ast) {
140                 status = query_exec(conn, ast);
141                 sdb_object_deref(SDB_OBJ(ast));
142         }
143         sdb_llist_destroy(parsetree);
144         return status;
145 } /* sdb_fe_query */
147 int
148 sdb_fe_fetch(sdb_conn_t *conn)
150         sdb_ast_node_t *ast;
151         char hostname[conn->cmd_len + 1];
152         char name[conn->cmd_len + 1];
153         uint32_t type;
154         int status;
156         if ((! conn) || (conn->cmd != SDB_CONNECTION_FETCH))
157                 return -1;
159         if (conn->cmd_len < sizeof(uint32_t)) {
160                 sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for "
161                                 "FETCH command", conn->cmd_len);
162                 sdb_strbuf_sprintf(conn->errbuf, "FETCH: Invalid command length %d",
163                                 conn->cmd_len);
164                 return -1;
165         }
167         /* TODO: support other types besides hosts */
168         hostname[0] = '\0';
170         sdb_proto_unmarshal_int32(SDB_STRBUF_STR(conn->buf), &type);
171         strncpy(name, sdb_strbuf_string(conn->buf) + sizeof(uint32_t),
172                         conn->cmd_len - sizeof(uint32_t));
173         name[sizeof(name) - 1] = '\0';
175         ast = sdb_ast_fetch_create((int)type,
176                         hostname[0] ? strdup(hostname) : NULL,
177                         name[0] ? strdup(name) : NULL,
178                         /* filter = */ NULL);
179         status = query_exec(conn, ast);
180         sdb_object_deref(SDB_OBJ(ast));
181         return status;
182 } /* sdb_fe_fetch */
184 int
185 sdb_fe_list(sdb_conn_t *conn)
187         sdb_ast_node_t *ast;
188         uint32_t type = SDB_HOST;
189         int status;
191         if ((! conn) || (conn->cmd != SDB_CONNECTION_LIST))
192                 return -1;
194         if (conn->cmd_len == sizeof(uint32_t))
195                 sdb_proto_unmarshal_int32(SDB_STRBUF_STR(conn->buf), &type);
196         else if (conn->cmd_len) {
197                 sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for "
198                                 "LIST command", conn->cmd_len);
199                 sdb_strbuf_sprintf(conn->errbuf, "LIST: Invalid command length %d",
200                                 conn->cmd_len);
201                 return -1;
202         }
204         ast = sdb_ast_list_create((int)type, /* filter = */ NULL);
205         status = query_exec(conn, ast);
206         sdb_object_deref(SDB_OBJ(ast));
207         return status;
208 } /* sdb_fe_list */
210 int
211 sdb_fe_lookup(sdb_conn_t *conn)
213         sdb_ast_node_t *ast, *m;
214         const char *matcher;
215         size_t matcher_len;
217         uint32_t type;
218         int status;
220         if ((! conn) || (conn->cmd != SDB_CONNECTION_LOOKUP))
221                 return -1;
223         if (conn->cmd_len < sizeof(uint32_t)) {
224                 sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for "
225                                 "LOOKUP command", conn->cmd_len);
226                 sdb_strbuf_sprintf(conn->errbuf, "LOOKUP: Invalid command length %d",
227                                 conn->cmd_len);
228                 return -1;
229         }
230         sdb_proto_unmarshal_int32(SDB_STRBUF_STR(conn->buf), &type);
232         matcher = sdb_strbuf_string(conn->buf) + sizeof(uint32_t);
233         matcher_len = conn->cmd_len - sizeof(uint32_t);
234         m = sdb_parser_parse_conditional(matcher, (int)matcher_len, conn->errbuf);
235         if (! m) {
236                 char expr[matcher_len + 1];
237                 strncpy(expr, matcher, sizeof(expr));
238                 expr[sizeof(expr) - 1] = '\0';
239                 sdb_log(SDB_LOG_ERR, "frontend: Failed to parse lookup condition '%s': %s",
240                                 expr, sdb_strbuf_string(conn->errbuf));
241                 return -1;
242         }
244         ast = sdb_ast_lookup_create((int)type, m, /* filter = */ NULL);
245         /* run analyzer using the full context */
246         if (ast && sdb_parser_analyze(ast, conn->errbuf)) {
247                 char expr[matcher_len + 1];
248                 char err[sdb_strbuf_len(conn->errbuf) + sizeof(expr) + 64];
249                 strncpy(expr, matcher, sizeof(expr));
250                 expr[sizeof(expr) - 1] = '\0';
251                 snprintf(err, sizeof(err), "Failed to parse lookup condition '%s': %s",
252                                 expr, sdb_strbuf_string(conn->errbuf));
253                 sdb_strbuf_sprintf(conn->errbuf, "%s", err);
254                 status = -1;
255         }
256         else
257                 status = query_exec(conn, ast);
258         if (! ast)
259                 sdb_object_deref(SDB_OBJ(m));
260         sdb_object_deref(SDB_OBJ(ast));
261         return status;
262 } /* sdb_fe_lookup */
264 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */