Code

store: Let child matcher actually match the child.
[sysdb.git] / src / core / store_lookup.c
1 /*
2  * SysDB - src/core/store_lookup.c
3  * Copyright (C) 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 /*
29  * This module implements operators which may be used to select contents of
30  * the store by matching various attributes of the stored objects. For now, a
31  * simple full table scan is supported only.
32  */
34 #if HAVE_CONFIG_H
35 #       include "config.h"
36 #endif /* HAVE_CONFIG_H */
38 #include "sysdb.h"
39 #include "core/store-private.h"
40 #include "core/object.h"
42 #include <assert.h>
44 #include <sys/types.h>
45 #include <regex.h>
47 #include <stdlib.h>
48 #include <string.h>
50 #include <limits.h>
52 /*
53  * private data types
54  */
56 typedef struct {
57         sdb_store_matcher_t *m;
58         sdb_store_matcher_t *filter;
59         sdb_store_lookup_cb  cb;
60         void *user_data;
61 } scan_iter_data_t;
63 /*
64  * private helper functions
65  */
67 static int
68 scan_iter(sdb_store_obj_t *obj, void *user_data)
69 {
70         scan_iter_data_t *d = user_data;
72         if (sdb_store_matcher_matches(d->m, obj, d->filter))
73                 return d->cb(obj, d->user_data);
74         return 0;
75 } /* scan_iter */
77 /*
78  * matcher implementations
79  */
81 static int
82 match_string(string_matcher_t *m, const char *name)
83 {
84         if ((! m->name) && (! m->name_re))
85                 return 1;
87         if (! name)
88                 name = "";
90         if (m->name && strcasecmp(m->name, name))
91                 return 0;
92         if (m->name_re && regexec(m->name_re, name,
93                                         /* matches */ 0, NULL, /* flags = */ 0))
94                 return 0;
95         return 1;
96 } /* match_string */
98 static int
99 match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
100                 sdb_store_matcher_t *filter)
102         int status;
104         assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
105         assert(OP_M(m)->left && OP_M(m)->right);
107         status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
109         /* lazy evaluation */
110         if ((! status) && (m->type == MATCHER_AND))
111                 return status;
112         else if (status && (m->type == MATCHER_OR))
113                 return status;
115         return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
116 } /* match_logical */
118 static int
119 match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
120                 sdb_store_matcher_t *filter)
122         assert(m->type == MATCHER_NOT);
123         assert(UOP_M(m)->op);
125         return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
126 } /* match_unary */
128 static int
129 match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
130                 sdb_store_matcher_t *filter)
132         sdb_avltree_iter_t *iter = NULL;
133         int status = 0;
135         assert(m->type == MATCHER_NAME);
137         if (obj->type == NAME_M(m)->obj_type)
138                 return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
139         else if (obj->type != SDB_HOST)
140                 return 0;
142         switch (NAME_M(m)->obj_type) {
143                 case SDB_SERVICE:
144                         iter = sdb_avltree_get_iter(HOST(obj)->services);
145                         break;
146                 case SDB_METRIC:
147                         iter = sdb_avltree_get_iter(HOST(obj)->metrics);
148                         break;
149                 case SDB_ATTRIBUTE:
150                         iter = sdb_avltree_get_iter(HOST(obj)->attributes);
151                         break;
152         }
154         while (sdb_avltree_iter_has_next(iter)) {
155                 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
156                 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(child),
157                                                 NULL)))
158                         continue;
159                 if (match_string(&NAME_M(m)->name, child->name)) {
160                         status = 1;
161                         break;
162                 }
163         }
164         sdb_avltree_iter_destroy(iter);
165         return status;
166 } /* match_name */
168 static int
169 match_child(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
170                 sdb_store_matcher_t *filter)
172         sdb_avltree_iter_t *iter = NULL;
173         int status = 0;
175         assert((m->type == MATCHER_SERVICE)
176                         || (m->type == MATCHER_METRIC)
177                         || (m->type == MATCHER_ATTRIBUTE));
179         /* TODO: support all object types */
180         if (obj->type != SDB_HOST)
181                 return 0;
183         if (m->type == MATCHER_SERVICE)
184                 iter = sdb_avltree_get_iter(HOST(obj)->services);
185         else if (m->type == MATCHER_METRIC)
186                 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
187         else if (m->type == MATCHER_ATTRIBUTE)
188                 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
190         while (sdb_avltree_iter_has_next(iter)) {
191                 sdb_store_obj_t *child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
192                 if (filter && (! sdb_store_matcher_matches(filter, child, NULL)))
193                         continue;
195                 if (sdb_store_matcher_matches(CHILD_M(m)->m, child, filter)) {
196                         status = 1;
197                         break;
198                 }
199         }
200         sdb_avltree_iter_destroy(iter);
201         return status;
202 } /* match_child */
204 /*
205  * cmp_expr:
206  * Compare the values of two expressions when evaluating them using the
207  * specified stored object and filter. Returns a value less than, equal to, or
208  * greater than zero if the value of the first expression compares less than,
209  * equal to, or greater than the value of the second expression. Returns
210  * INT_MAX if any of the expressions could not be evaluated or if any of them
211  * evaluated to NULL.
212  */
213 static int
214 cmp_expr(sdb_store_expr_t *e1, sdb_store_expr_t *e2,
215                 sdb_store_obj_t *obj, sdb_store_matcher_t *filter)
217         sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
218         int status;
220         if (sdb_store_expr_eval(e1, obj, &v1, filter))
221                 return INT_MAX;
222         if (sdb_store_expr_eval(e2, obj, &v2, filter)) {
223                 sdb_data_free_datum(&v1);
224                 return INT_MAX;
225         }
227         if (sdb_data_isnull(&v1) || (sdb_data_isnull(&v2)))
228                 status = INT_MAX;
229         else if (v1.type == v2.type)
230                 status = sdb_data_cmp(&v1, &v2);
231         else
232                 status = sdb_data_strcmp(&v1, &v2);
234         sdb_data_free_datum(&v1);
235         sdb_data_free_datum(&v2);
236         return status;
237 } /* cmp_expr */
239 static int
240 match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
241                 sdb_store_matcher_t *filter)
243         int status;
244         assert(m->type == MATCHER_LT);
245         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
246         return (status != INT_MAX) && (status < 0);
247 } /* match_lt */
249 static int
250 match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
251                 sdb_store_matcher_t *filter)
253         int status;
254         assert(m->type == MATCHER_LE);
255         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
256         return (status != INT_MAX) && (status <= 0);
257 } /* match_le */
259 static int
260 match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
261                 sdb_store_matcher_t *filter)
263         int status;
264         assert(m->type == MATCHER_EQ);
265         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
266         return (status != INT_MAX) && (! status);
267 } /* match_eq */
269 static int
270 match_ne(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
271                 sdb_store_matcher_t *filter)
273         int status;
274         assert(m->type == MATCHER_NE);
275         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
276         return (status != INT_MAX) && status;
277 } /* match_ne */
279 static int
280 match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
281                 sdb_store_matcher_t *filter)
283         int status;
284         assert(m->type == MATCHER_GE);
285         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
286         return (status != INT_MAX) && (status >= 0);
287 } /* match_ge */
289 static int
290 match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
291                 sdb_store_matcher_t *filter)
293         int status;
294         assert(m->type == MATCHER_GT);
295         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
296         return (status != INT_MAX) && (status > 0);
297 } /* match_gt */
299 static int
300 match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
301                 sdb_store_matcher_t *filter)
303         sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
304         int status = 1;
306         assert(m->type == MATCHER_IN);
308         if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &value, filter))
309                         || (sdb_store_expr_eval(CMP_M(m)->right, obj, &array, filter)))
310                 status = 0;
312         if (status)
313                 status = sdb_data_inarray(&value, &array);
315         sdb_data_free_datum(&value);
316         sdb_data_free_datum(&array);
317         return status;
318 } /* match_in */
320 static int
321 match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
322                 sdb_store_matcher_t *filter)
324         sdb_data_t v = SDB_DATA_INIT;
325         int status = 0;
327         regex_t regex;
328         _Bool free_regex = 0;
330         assert((m->type == MATCHER_REGEX)
331                         || (m->type == MATCHER_NREGEX));
333         if (! CMP_M(m)->right->type) {
334                 assert(CMP_M(m)->right->data.type == SDB_TYPE_REGEX);
335                 regex = CMP_M(m)->right->data.data.re.regex;
336         }
337         else {
338                 sdb_data_t tmp = SDB_DATA_INIT;
339                 char *raw;
341                 if (sdb_store_expr_eval(CMP_M(m)->right, obj, &tmp, filter))
342                         return 0;
344                 if (tmp.type != SDB_TYPE_STRING) {
345                         sdb_data_free_datum(&tmp);
346                         return 0;
347                 }
349                 raw = tmp.data.string;
350                 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &tmp)) {
351                         free(raw);
352                         return 0;
353                 }
355                 regex = tmp.data.re.regex;
356                 free_regex = 1;
357                 free(tmp.data.re.raw);
358                 free(raw);
359         }
361         if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &v, filter))
362                         || (sdb_data_isnull(&v)))
363                 status = 0;
364         else {
365                 char value[sdb_data_strlen(&v) + 1];
366                 if (sdb_data_format(&v, value, sizeof(value), SDB_UNQUOTED) < 0)
367                         status = 0;
368                 else if (! regexec(&regex, value, 0, NULL, 0))
369                         status = 1;
370         }
372         if (free_regex)
373                 regfree(&regex);
374         sdb_data_free_datum(&v);
375         if (m->type == MATCHER_NREGEX)
376                 return !status;
377         return status;
378 } /* match_regex */
380 static int
381 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
382                 sdb_store_matcher_t *filter)
384         sdb_data_t v = SDB_DATA_INIT;
385         int status;
387         assert((m->type == MATCHER_ISNULL) || (m->type == MATCHER_ISNNULL));
389         /* TODO: this might hide real errors;
390          * improve error reporting and propagation */
391         if (sdb_store_expr_eval(ISNULL_M(m)->expr, obj, &v, filter)
392                         || sdb_data_isnull(&v))
393                 status = 1;
394         else
395                 status = 0;
397         sdb_data_free_datum(&v);
398         if (m->type == MATCHER_ISNNULL)
399                 return !status;
400         return status;
401 } /* match_isnull */
403 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
404                 sdb_store_matcher_t *);
406 /* this array needs to be indexable by the matcher types;
407  * -> update the enum in store-private.h when updating this */
408 static matcher_cb
409 matchers[] = {
410         match_logical,
411         match_logical,
412         match_unary,
413         match_name,
414         match_child,
415         match_child,
416         match_child,
417         match_lt,
418         match_le,
419         match_eq,
420         match_ne,
421         match_ge,
422         match_gt,
423         match_in,
424         match_regex,
425         match_regex,
426         match_isnull,
427         match_isnull,
428 };
430 /*
431  * private matcher types
432  */
434 /* initializes a string matcher consuming two elements from ap */
435 static int
436 string_matcher_init(string_matcher_t *m, va_list ap)
438         const char *name = va_arg(ap, const char *);
439         const char *name_re = va_arg(ap, const char *);
441         if (name) {
442                 m->name = strdup(name);
443                 if (! m->name)
444                         return -1;
445         }
446         if (name_re) {
447                 m->name_re = malloc(sizeof(*m->name_re));
448                 if (! m->name_re)
449                         return -1;
450                 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
451                         return -1;
452         }
453         return 0;
454 } /* string_matcher_init */
456 static void
457 string_matcher_destroy(string_matcher_t *m)
459         if (m->name)
460                 free(m->name);
461         if (m->name_re) {
462                 regfree(m->name_re);
463                 free(m->name_re);
464         }
465 } /* string_matcher_destroy */
467 /* initializes a name matcher */
468 static int
469 name_matcher_init(sdb_object_t *obj, va_list ap)
471         name_matcher_t *m = NAME_M(obj);
472         M(obj)->type = MATCHER_NAME;
473         return string_matcher_init(&m->name, ap);
474 } /* name_matcher_init */
476 static void
477 name_matcher_destroy(sdb_object_t *obj)
479         name_matcher_t *m = NAME_M(obj);
480         string_matcher_destroy(&m->name);
481 } /* name_matcher_destroy */
483 static int
484 op_matcher_init(sdb_object_t *obj, va_list ap)
486         M(obj)->type = va_arg(ap, int);
487         if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
488                 return -1;
490         OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
491         sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
492         OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
493         sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
495         if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
496                 return -1;
497         return 0;
498 } /* op_matcher_init */
500 static void
501 op_matcher_destroy(sdb_object_t *obj)
503         if (OP_M(obj)->left)
504                 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
505         if (OP_M(obj)->right)
506                 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
507 } /* op_matcher_destroy */
509 static int
510 child_matcher_init(sdb_object_t *obj, va_list ap)
512         M(obj)->type = va_arg(ap, int);
513         CHILD_M(obj)->m = va_arg(ap, sdb_store_matcher_t *);
515         if (! CHILD_M(obj)->m)
516                 return -1;
518         sdb_object_ref(SDB_OBJ(CHILD_M(obj)->m));
519         return 0;
520 } /* child_matcher_init */
522 static void
523 child_matcher_destroy(sdb_object_t *obj)
525         sdb_object_deref(SDB_OBJ(CHILD_M(obj)->m));
526 } /* child_matcher_destroy */
528 static int
529 cmp_matcher_init(sdb_object_t *obj, va_list ap)
531         M(obj)->type = va_arg(ap, int);
533         CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *);
534         sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
535         CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *);
536         sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
538         if ((! CMP_M(obj)->left) || (! CMP_M(obj)->right))
539                 return -1;
540         return 0;
541 } /* cmp_matcher_init */
543 static void
544 cmp_matcher_destroy(sdb_object_t *obj)
546         sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
547         sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
548 } /* cmp_matcher_destroy */
550 static int
551 uop_matcher_init(sdb_object_t *obj, va_list ap)
553         M(obj)->type = va_arg(ap, int);
554         if (M(obj)->type != MATCHER_NOT)
555                 return -1;
557         UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
558         sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
560         if (! UOP_M(obj)->op)
561                 return -1;
562         return 0;
563 } /* uop_matcher_init */
565 static void
566 uop_matcher_destroy(sdb_object_t *obj)
568         if (UOP_M(obj)->op)
569                 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
570 } /* uop_matcher_destroy */
572 static int
573 isnull_matcher_init(sdb_object_t *obj, va_list ap)
575         M(obj)->type = va_arg(ap, int);
576         if ((M(obj)->type != MATCHER_ISNULL) && (M(obj)->type != MATCHER_ISNNULL))
577                 return -1;
579         ISNULL_M(obj)->expr = va_arg(ap, sdb_store_expr_t *);
580         sdb_object_ref(SDB_OBJ(ISNULL_M(obj)->expr));
581         return 0;
582 } /* isnull_matcher_init */
584 static void
585 isnull_matcher_destroy(sdb_object_t *obj)
587         sdb_object_deref(SDB_OBJ(ISNULL_M(obj)->expr));
588         ISNULL_M(obj)->expr = NULL;
589 } /* isnull_matcher_destroy */
591 static sdb_type_t name_type = {
592         /* size = */ sizeof(name_matcher_t),
593         /* init = */ name_matcher_init,
594         /* destroy = */ name_matcher_destroy,
595 };
597 static sdb_type_t op_type = {
598         /* size = */ sizeof(op_matcher_t),
599         /* init = */ op_matcher_init,
600         /* destroy = */ op_matcher_destroy,
601 };
603 static sdb_type_t uop_type = {
604         /* size = */ sizeof(uop_matcher_t),
605         /* init = */ uop_matcher_init,
606         /* destroy = */ uop_matcher_destroy,
607 };
609 static sdb_type_t child_type = {
610         /* size = */ sizeof(child_matcher_t),
611         /* init = */ child_matcher_init,
612         /* destroy = */ child_matcher_destroy,
613 };
615 static sdb_type_t cmp_type = {
616         /* size = */ sizeof(cmp_matcher_t),
617         /* init = */ cmp_matcher_init,
618         /* destroy = */ cmp_matcher_destroy,
619 };
621 static sdb_type_t isnull_type = {
622         /* size = */ sizeof(isnull_matcher_t),
623         /* init = */ isnull_matcher_init,
624         /* destroy = */ isnull_matcher_destroy,
625 };
627 /*
628  * public API
629  */
631 sdb_store_matcher_t *
632 sdb_store_name_matcher(int type, const char *name, _Bool re)
634         sdb_store_matcher_t *m;
636         if (re)
637                 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
638         else
639                 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
641         if (! m)
642                 return NULL;
644         NAME_M(m)->obj_type = type;
645         return m;
646 } /* sdb_store_name_matcher */
648 sdb_store_matcher_t *
649 sdb_store_child_matcher(int type, sdb_store_matcher_t *m)
651         if (type == SDB_SERVICE)
652                 type = MATCHER_SERVICE;
653         else if (type == SDB_METRIC)
654                 type = MATCHER_METRIC;
655         else if (type == SDB_ATTRIBUTE)
656                 type = MATCHER_ATTRIBUTE;
657         else
658                 return NULL;
659         return M(sdb_object_create("any-matcher", child_type, type, m));
660 } /* sdb_store_child_matcher */
662 sdb_store_matcher_t *
663 sdb_store_lt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
665         return M(sdb_object_create("lt-matcher", cmp_type,
666                                 MATCHER_LT, left, right));
667 } /* sdb_store_lt_matcher */
669 sdb_store_matcher_t *
670 sdb_store_le_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
672         return M(sdb_object_create("le-matcher", cmp_type,
673                                 MATCHER_LE, left, right));
674 } /* sdb_store_le_matcher */
676 sdb_store_matcher_t *
677 sdb_store_eq_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
679         return M(sdb_object_create("eq-matcher", cmp_type,
680                                 MATCHER_EQ, left, right));
681 } /* sdb_store_eq_matcher */
683 sdb_store_matcher_t *
684 sdb_store_ne_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
686         return M(sdb_object_create("ne-matcher", cmp_type,
687                                 MATCHER_NE, left, right));
688 } /* sdb_store_ne_matcher */
690 sdb_store_matcher_t *
691 sdb_store_ge_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
693         return M(sdb_object_create("ge-matcher", cmp_type,
694                                 MATCHER_GE, left, right));
695 } /* sdb_store_ge_matcher */
697 sdb_store_matcher_t *
698 sdb_store_gt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
700         return M(sdb_object_create("gt-matcher", cmp_type,
701                                 MATCHER_GT, left, right));
702 } /* sdb_store_gt_matcher */
704 sdb_store_matcher_t *
705 sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
707         return M(sdb_object_create("in-matcher", cmp_type,
708                                 MATCHER_IN, left, right));
709 } /* sdb_store_in_matcher */
711 sdb_store_matcher_t *
712 sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
714         if (! right->type) {
715                 if ((right->data.type != SDB_TYPE_STRING)
716                                 && (right->data.type != SDB_TYPE_REGEX))
717                         return NULL;
719                 if (right->data.type == SDB_TYPE_STRING) {
720                         char *raw = right->data.data.string;
721                         if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
722                                 return NULL;
723                         free(raw);
724                 }
725         }
726         return M(sdb_object_create("regex-matcher", cmp_type,
727                                 MATCHER_REGEX, left, right));
728 } /* sdb_store_regex_matcher */
730 sdb_store_matcher_t *
731 sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
733         sdb_store_matcher_t *m = sdb_store_regex_matcher(left, right);
734         if (! m)
735                 return NULL;
736         m->type = MATCHER_NREGEX;
737         return m;
738 } /* sdb_store_nregex_matcher */
740 sdb_store_matcher_t *
741 sdb_store_isnull_matcher(sdb_store_expr_t *expr)
743         return M(sdb_object_create("isnull-matcher", isnull_type,
744                                 MATCHER_ISNULL, expr));
745 } /* sdb_store_isnull_matcher */
747 sdb_store_matcher_t *
748 sdb_store_isnnull_matcher(sdb_store_expr_t *expr)
750         return M(sdb_object_create("isnull-matcher", isnull_type,
751                                 MATCHER_ISNNULL, expr));
752 } /* sdb_store_isnnull_matcher */
754 sdb_store_matcher_op_cb
755 sdb_store_parse_matcher_op(const char *op)
757         if (! strcasecmp(op, "<"))
758                 return sdb_store_lt_matcher;
759         else if (! strcasecmp(op, "<="))
760                 return sdb_store_le_matcher;
761         else if (! strcasecmp(op, "="))
762                 return sdb_store_eq_matcher;
763         else if (! strcasecmp(op, "!="))
764                 return sdb_store_ne_matcher;
765         else if (! strcasecmp(op, ">="))
766                 return sdb_store_ge_matcher;
767         else if (! strcasecmp(op, ">"))
768                 return sdb_store_gt_matcher;
769         else if (! strcasecmp(op, "=~"))
770                 return sdb_store_regex_matcher;
771         else if (! strcasecmp(op, "!~"))
772                 return sdb_store_nregex_matcher;
773         return NULL;
774 } /* sdb_store_parse_matcher_op */
776 int
777 sdb_store_parse_object_type_plural(const char *name)
779         if (! strcasecmp(name, "hosts"))
780                 return SDB_HOST;
781         else if (! strcasecmp(name, "services"))
782                 return SDB_SERVICE;
783         else if (! strcasecmp(name, "metrics"))
784                 return SDB_METRIC;
785         return -1;
786 } /* sdb_store_parse_object_type_plural */
788 int
789 sdb_store_parse_field_name(const char *name)
791         if (! strcasecmp(name, "name"))
792                 return SDB_FIELD_NAME;
793         else if (! strcasecmp(name, "last_update"))
794                 return SDB_FIELD_LAST_UPDATE;
795         else if (! strcasecmp(name, "age"))
796                 return SDB_FIELD_AGE;
797         else if (! strcasecmp(name, "interval"))
798                 return SDB_FIELD_INTERVAL;
799         else if (! strcasecmp(name, "backend"))
800                 return SDB_FIELD_BACKEND;
801         return -1;
802 } /* sdb_store_parse_field_name */
804 static sdb_store_matcher_t *
805 maybe_inv_matcher(sdb_store_matcher_t *m, _Bool inv)
807         sdb_store_matcher_t *tmp;
809         if ((! m) || (! inv))
810                 return m;
812         tmp = sdb_store_inv_matcher(m);
813         /* pass ownership to the inverse matcher */
814         sdb_object_deref(SDB_OBJ(m));
815         return tmp;
816 } /* maybe_inv_matcher */
818 sdb_store_matcher_t *
819 sdb_store_matcher_parse_cmp(const char *obj_type,
820                 const char *op, sdb_store_expr_t *expr)
822         int type = -1;
823         _Bool inv = 0;
824         _Bool re = 0;
826         sdb_data_t value = SDB_DATA_INIT;
827         sdb_store_matcher_t *m = NULL;
829         if (! strcasecmp(obj_type, "host"))
830                 type = SDB_HOST;
831         else if (! strcasecmp(obj_type, "service"))
832                 type = SDB_SERVICE;
833         else if (! strcasecmp(obj_type, "metric"))
834                 type = SDB_METRIC;
835         else if (! strcasecmp(obj_type, "attribute"))
836                 type = SDB_ATTRIBUTE;
837         else
838                 return NULL;
840         /* XXX: this code sucks! */
841         if (! strcasecmp(op, "=")) {
842                 /* nothing to do */
843         }
844         else if (! strcasecmp(op, "!=")) {
845                 inv = 1;
846         }
847         else if (! strcasecmp(op, "=~")) {
848                 re = 1;
849         }
850         else if (! strcasecmp(op, "!~")) {
851                 inv = 1;
852                 re = 1;
853         }
854         else
855                 return NULL;
857         if (! expr)
858                 return NULL;
860         if (sdb_store_expr_eval(expr, /* obj */ NULL, &value, /* filter */ NULL)
861                         || (value.type != SDB_TYPE_STRING)) {
862                 sdb_data_free_datum(&value);
863                 return NULL;
864         }
866         m = sdb_store_name_matcher(type, value.data.string, re);
867         sdb_data_free_datum(&value);
868         return maybe_inv_matcher(m, inv);
869 } /* sdb_store_matcher_parse_cmp */
871 sdb_store_matcher_t *
872 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
874         return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
875                                 left, right));
876 } /* sdb_store_dis_matcher */
878 sdb_store_matcher_t *
879 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
881         return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
882                                 left, right));
883 } /* sdb_store_con_matcher */
885 sdb_store_matcher_t *
886 sdb_store_inv_matcher(sdb_store_matcher_t *m)
888         return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
889 } /* sdb_store_inv_matcher */
891 int
892 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
893                 sdb_store_matcher_t *filter)
895         if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
896                 return 0;
898         /* "NULL" always matches */
899         if ((! m) || (! obj))
900                 return 1;
902         if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
903                 return 0;
905         return matchers[m->type](m, obj, filter);
906 } /* sdb_store_matcher_matches */
908 int
909 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
910                 sdb_store_lookup_cb cb, void *user_data)
912         scan_iter_data_t data = { m, filter, cb, user_data };
914         if (! cb)
915                 return -1;
916         return sdb_store_iterate(scan_iter, &data);
917 } /* sdb_store_scan */
919 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */