244966b9a651b4ad9c72a67fbedb5375d2ea7352
1 /*
2 * SysDB - src/parser/analyzer.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 "sysdb.h"
30 #include "parser/ast.h"
31 #include "parser/parser.h"
32 #include "utils/error.h"
33 #include "utils/strbuf.h"
35 #include <assert.h>
37 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
39 /*
40 * private helper functions
41 */
43 static int
44 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
45 {
46 (void)context;
47 if (! node) {
48 sdb_strbuf_sprintf(errbuf, "Empty AST node");
49 return -1;
50 }
51 return 0;
52 } /* analyze_node */
54 /*
55 * top level / command nodes
56 */
58 static int
59 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
60 {
61 if (! VALID_OBJ_TYPE(fetch->obj_type)) {
62 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
63 "in FETCH command", fetch->obj_type);
64 return -1;
65 }
66 if (! fetch->name) {
67 sdb_strbuf_sprintf(errbuf, "Missing object name in "
68 "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
69 return -1;
70 }
72 if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
73 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
74 "in FETCH HOST command", fetch->hostname);
75 return -1;
76 }
77 else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
78 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
79 "in FETCH %s command", fetch->name,
80 SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
81 return -1;
82 }
84 if (fetch->filter)
85 return analyze_node(-1, fetch->filter, errbuf);
86 return 0;
87 }
89 static int
90 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
91 {
92 if (! VALID_OBJ_TYPE(list->obj_type)) {
93 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
94 "in LIST command", list->obj_type);
95 return -1;
96 }
97 if (list->filter)
98 return analyze_node(-1, list->filter, errbuf);
99 return 0;
100 }
102 static int
103 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
104 {
105 if (! VALID_OBJ_TYPE(lookup->obj_type)) {
106 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
107 "in LOOKUP command", lookup->obj_type);
108 return -1;
109 }
110 if (lookup->matcher)
111 if (analyze_node(lookup->obj_type, lookup->matcher, errbuf))
112 return -1;
113 if (lookup->filter)
114 return analyze_node(-1, lookup->filter, errbuf);
115 return 0;
116 }
118 static int
119 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
120 {
121 if ((st->obj_type != SDB_ATTRIBUTE)
122 && (! VALID_OBJ_TYPE(st->obj_type))) {
123 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
124 "in STORE command", st->obj_type);
125 return -1;
126 }
127 if (! st->name) {
128 sdb_strbuf_sprintf(errbuf, "Missing object name in "
129 "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
130 return -1;
131 }
133 if ((st->obj_type == SDB_HOST) && st->hostname) {
134 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
135 "in STORE HOST command", st->hostname);
136 return -1;
137 }
138 else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
139 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
140 "in STORE %s command", st->name,
141 SDB_STORE_TYPE_TO_NAME(st->obj_type));
142 return -1;
143 }
145 if (st->obj_type == SDB_ATTRIBUTE) {
146 if ((st->parent_type <= 0) && st->parent) {
147 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
148 "in STORE %s command", st->parent,
149 SDB_STORE_TYPE_TO_NAME(st->obj_type));
150 return -1;
151 }
152 else if (st->parent_type > 0) {
153 if (! VALID_OBJ_TYPE(st->parent_type)) {
154 sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
155 "in STORE %s command", st->parent_type,
156 SDB_STORE_TYPE_TO_NAME(st->obj_type));
157 return -1;
158 }
159 if (! st->parent) {
160 sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
161 "in STORE %s command",
162 SDB_STORE_TYPE_TO_NAME(st->parent_type),
163 SDB_STORE_TYPE_TO_NAME(st->obj_type));
164 return -1;
165 }
166 }
167 }
168 else if ((st->parent_type > 0) || st->parent) {
169 sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
170 "in STORE %s command",
171 SDB_STORE_TYPE_TO_NAME(st->parent_type),
172 st->parent ? st->parent : "<unknown>",
173 SDB_STORE_TYPE_TO_NAME(st->obj_type));
174 return -1;
175 }
177 if (st->obj_type == SDB_METRIC) {
178 if ((! st->store_type) != (! st->store_id)) {
179 sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
180 "in STORE METRIC command",
181 st->store_type ? st->store_type : "<unknown>",
182 st->store_id ? st->store_id : "<unknown>");
183 return -1;
184 }
185 }
186 else if (st->store_type || st->store_id) {
187 sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
188 "in STORE %s command",
189 st->store_type ? st->store_type : "<unknown>",
190 st->store_id ? st->store_id : "<unknown>",
191 SDB_STORE_TYPE_TO_NAME(st->obj_type));
192 return -1;
193 }
195 if ((! (st->obj_type == SDB_ATTRIBUTE))
196 && (st->value.type != SDB_TYPE_NULL)) {
197 char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
198 sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
199 sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
200 v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
201 return -1;
202 }
203 return 0;
204 }
206 static int
207 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
208 {
209 if (! ts->hostname) {
210 sdb_strbuf_sprintf(errbuf, "Missing hostname in STORE command");
211 return -1;
212 }
213 if (! ts->metric) {
214 sdb_strbuf_sprintf(errbuf, "Missing metric name in STORE command");
215 return -1;
216 }
217 if (ts->end <= ts->start) {
218 char start_str[64], end_str[64];
219 sdb_strftime(start_str, sizeof(start_str), "%F %T Tz", ts->start);
220 sdb_strftime(end_str, sizeof(end_str), "%F %T Tz", ts->end);
221 sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
222 "end time (%s) in STORE command", start_str, end_str);
223 return -1;
224 }
225 return 0;
226 }
228 /*
229 * public API
230 */
232 int
233 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
234 {
235 if (! node) {
236 sdb_strbuf_sprintf(errbuf, "Empty AST node");
237 return -1;
238 }
240 if (node->type == SDB_AST_TYPE_FETCH)
241 return analyze_fetch(SDB_AST_FETCH(node), errbuf);
242 else if (node->type == SDB_AST_TYPE_LIST)
243 return analyze_list(SDB_AST_LIST(node), errbuf);
244 else if (node->type == SDB_AST_TYPE_LOOKUP)
245 return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
246 else if (node->type == SDB_AST_TYPE_STORE)
247 return analyze_store(SDB_AST_STORE(node), errbuf);
248 else if (node->type == SDB_AST_TYPE_TIMESERIES)
249 return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
251 sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
252 "of type %#x", node->type);
253 return -1;
254 } /* sdb_fe_analyze */
256 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */