Code

Migrate top-level checks to the new parser/analyzer.
[sysdb.git] / src / parser / analyzer.c
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;
102 static int
103 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
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;
118 static int
119 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
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;
206 static int
207 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
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;
228 /*
229  * public API
230  */
232 int
233 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
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 : */