Code

store: Removed sdb_store_matcher_parse_field_cmp() and sdb_store_obj_cond().
[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 static sdb_attribute_t *
78 attr_get(sdb_host_t *host, const char *name, sdb_store_matcher_t *filter)
79 {
80         sdb_avltree_iter_t *iter = NULL;
81         sdb_attribute_t *attr = NULL;
83         iter = sdb_avltree_get_iter(host->attributes);
84         while (sdb_avltree_iter_has_next(iter)) {
85                 sdb_attribute_t *a = ATTR(sdb_avltree_iter_get_next(iter));
87                 if (strcasecmp(name, SDB_OBJ(a)->name))
88                         continue;
90                 assert(STORE_OBJ(a)->type == SDB_ATTRIBUTE);
91                 attr = a;
92                 break;
93         }
94         sdb_avltree_iter_destroy(iter);
96         if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(attr),
97                                         NULL)))
98                 return NULL;
99         return attr;
100 } /* attr_get */
102 /*
103  * conditional implementations
104  */
106 static int
107 attr_cmp(sdb_store_obj_t *obj, sdb_store_cond_t *cond,
108                 sdb_store_matcher_t *filter)
110         sdb_attribute_t *attr;
111         sdb_data_t value = SDB_DATA_INIT;
112         int status;
114         if (obj->type != SDB_HOST)
115                 return INT_MAX;
117         if (sdb_store_expr_eval(ATTR_C(cond)->expr, obj, &value, filter))
118                 return INT_MAX;
120         attr = attr_get(HOST(obj), ATTR_C(cond)->name, filter);
121         if (! attr)
122                 status = INT_MAX;
123         else if (attr->value.type != value.type)
124                 status = sdb_data_strcmp(&attr->value, &value);
125         else
126                 status = sdb_data_cmp(&attr->value, &value);
127         sdb_data_free_datum(&value);
128         return status;
129 } /* attr_cmp */
131 /*
132  * matcher implementations
133  */
135 static int
136 match_string(string_matcher_t *m, const char *name)
138         if ((! m->name) && (! m->name_re))
139                 return 1;
141         if (! name)
142                 name = "";
144         if (m->name && strcasecmp(m->name, name))
145                 return 0;
146         if (m->name_re && regexec(m->name_re, name,
147                                         /* matches */ 0, NULL, /* flags = */ 0))
148                 return 0;
149         return 1;
150 } /* match_string */
152 static int
153 match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
154                 sdb_store_matcher_t *filter)
156         int status;
158         assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
159         assert(OP_M(m)->left && OP_M(m)->right);
161         status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
163         /* lazy evaluation */
164         if ((! status) && (m->type == MATCHER_AND))
165                 return status;
166         else if (status && (m->type == MATCHER_OR))
167                 return status;
169         return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
170 } /* match_logical */
172 static int
173 match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
174                 sdb_store_matcher_t *filter)
176         assert(m->type == MATCHER_NOT);
177         assert(UOP_M(m)->op);
179         return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
180 } /* match_unary */
182 static int
183 match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
184                 sdb_store_matcher_t *filter)
186         sdb_avltree_iter_t *iter = NULL;
187         int status = 0;
189         assert(m->type == MATCHER_NAME);
191         if (obj->type == NAME_M(m)->obj_type)
192                 return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
193         else if (obj->type != SDB_HOST)
194                 return 0;
196         switch (NAME_M(m)->obj_type) {
197                 case SDB_SERVICE:
198                         iter = sdb_avltree_get_iter(HOST(obj)->services);
199                         break;
200                 case SDB_METRIC:
201                         iter = sdb_avltree_get_iter(HOST(obj)->metrics);
202                         break;
203                 case SDB_ATTRIBUTE:
204                         iter = sdb_avltree_get_iter(HOST(obj)->attributes);
205                         break;
206         }
208         while (sdb_avltree_iter_has_next(iter)) {
209                 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
210                 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(child),
211                                                 NULL)))
212                         continue;
213                 if (match_string(&NAME_M(m)->name, child->name)) {
214                         status = 1;
215                         break;
216                 }
217         }
218         sdb_avltree_iter_destroy(iter);
219         return status;
220 } /* match_name */
222 static int
223 match_attr(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
224                 sdb_store_matcher_t *filter)
226         sdb_attribute_t *attr;
228         assert(m->type == MATCHER_ATTR);
229         assert(ATTR_M(m)->name);
231         if (obj->type != SDB_HOST)
232                 return 0;
234         attr = attr_get(HOST(obj), ATTR_M(m)->name, filter);
235         if (attr) {
236                 char buf[sdb_data_strlen(&attr->value) + 1];
237                 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
238                         return 0;
239                 if (match_string(&ATTR_M(m)->value, buf))
240                         return 1;
241         }
242         return 0;
243 } /* match_attr */
245 static int
246 match_child(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
247                 sdb_store_matcher_t *filter)
249         sdb_avltree_iter_t *iter = NULL;
250         int status = 0;
252         assert((m->type == MATCHER_SERVICE)
253                         || (m->type == MATCHER_METRIC)
254                         || (m->type == MATCHER_ATTRIBUTE));
256         /* TODO: support all object types */
257         if (obj->type != SDB_HOST)
258                 return 0;
260         if (m->type == MATCHER_SERVICE)
261                 iter = sdb_avltree_get_iter(HOST(obj)->services);
262         else if (m->type == MATCHER_METRIC)
263                 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
264         else if (m->type == SDB_ATTRIBUTE)
265                 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
267         while (sdb_avltree_iter_has_next(iter)) {
268                 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
269                 if (filter && (! sdb_store_matcher_matches(filter,
270                                                 STORE_OBJ(child), NULL)))
271                         continue;
273                 if (sdb_store_matcher_matches(CHILD_M(m)->m, obj, filter)) {
274                         status = 1;
275                         break;
276                 }
277         }
278         sdb_avltree_iter_destroy(iter);
279         return status;
280 } /* match_child */
282 static int
283 match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
284                 sdb_store_matcher_t *filter)
286         int status;
287         assert(m->type == MATCHER_LT);
288         status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
289         return (status != INT_MAX) && (status < 0);
290 } /* match_lt */
292 static int
293 match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
294                 sdb_store_matcher_t *filter)
296         int status;
297         assert(m->type == MATCHER_LE);
298         status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
299         return (status != INT_MAX) && (status <= 0);
300 } /* match_le */
302 static int
303 match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
304                 sdb_store_matcher_t *filter)
306         int status;
307         assert(m->type == MATCHER_EQ);
308         status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
309         return (status != INT_MAX) && (! status);
310 } /* match_eq */
312 static int
313 match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
314                 sdb_store_matcher_t *filter)
316         int status;
317         assert(m->type == MATCHER_GE);
318         status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
319         return (status != INT_MAX) && (status >= 0);
320 } /* match_ge */
322 static int
323 match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
324                 sdb_store_matcher_t *filter)
326         int status;
327         assert(m->type == MATCHER_GT);
328         status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
329         return (status != INT_MAX) && (status > 0);
330 } /* match_gt */
332 /*
333  * cmp_expr:
334  * Compare the values of two expressions when evaluating them using the
335  * specified stored object and filter. Returns a value less than, equal to, or
336  * greater than zero if the value of the first expression compares less than,
337  * equal to, or greater than the value of the second expression. Returns
338  * INT_MAX if any of the expressions could not be evaluated or if any of them
339  * evaluated to NULL.
340  */
341 static int
342 cmp_expr(sdb_store_expr_t *e1, sdb_store_expr_t *e2,
343                 sdb_store_obj_t *obj, sdb_store_matcher_t *filter)
345         sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
346         int status;
348         if (sdb_store_expr_eval(e1, obj, &v1, filter))
349                 return INT_MAX;
350         if (sdb_store_expr_eval(e2, obj, &v2, filter)) {
351                 sdb_data_free_datum(&v1);
352                 return INT_MAX;
353         }
355         if (sdb_data_isnull(&v1) || (sdb_data_isnull(&v2)))
356                 status = INT_MAX;
357         else if (v1.type == v2.type)
358                 status = sdb_data_cmp(&v1, &v2);
359         else
360                 status = sdb_data_strcmp(&v1, &v2);
362         sdb_data_free_datum(&v1);
363         sdb_data_free_datum(&v2);
364         return status;
365 } /* cmp_expr */
367 static int
368 match_cmp_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
369                 sdb_store_matcher_t *filter)
371         int status;
372         assert(m->type == MATCHER_CMP_LT);
373         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
374         return (status != INT_MAX) && (status < 0);
375 } /* match_cmp_lt */
377 static int
378 match_cmp_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
379                 sdb_store_matcher_t *filter)
381         int status;
382         assert(m->type == MATCHER_CMP_LE);
383         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
384         return (status != INT_MAX) && (status <= 0);
385 } /* match_cmp_le */
387 static int
388 match_cmp_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
389                 sdb_store_matcher_t *filter)
391         int status;
392         assert(m->type == MATCHER_CMP_EQ);
393         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
394         return (status != INT_MAX) && (! status);
395 } /* match_cmp_eq */
397 static int
398 match_cmp_ne(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
399                 sdb_store_matcher_t *filter)
401         int status;
402         assert(m->type == MATCHER_CMP_NE);
403         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
404         return (status != INT_MAX) && status;
405 } /* match_cmp_ne */
407 static int
408 match_cmp_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
409                 sdb_store_matcher_t *filter)
411         int status;
412         assert(m->type == MATCHER_CMP_GE);
413         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
414         return (status != INT_MAX) && (status >= 0);
415 } /* match_cmp_ge */
417 static int
418 match_cmp_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
419                 sdb_store_matcher_t *filter)
421         int status;
422         assert(m->type == MATCHER_CMP_GT);
423         status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
424         return (status != INT_MAX) && (status > 0);
425 } /* match_cmp_gt */
427 static int
428 match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
429                 sdb_store_matcher_t *filter)
431         sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
432         int status = 1;
434         assert(m->type == MATCHER_IN);
436         if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &value, filter))
437                         || (sdb_store_expr_eval(CMP_M(m)->right, obj, &array, filter)))
438                 status = 0;
440         if (status)
441                 status = sdb_data_inarray(&value, &array);
443         sdb_data_free_datum(&value);
444         sdb_data_free_datum(&array);
445         return status;
446 } /* match_in */
448 static int
449 match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
450                 sdb_store_matcher_t *filter)
452         sdb_data_t v = SDB_DATA_INIT;
453         int status = 0;
455         regex_t regex;
456         _Bool free_regex = 0;
458         assert((m->type == MATCHER_REGEX)
459                         || (m->type == MATCHER_NREGEX));
461         if (! CMP_M(m)->right->type) {
462                 assert(CMP_M(m)->right->data.type == SDB_TYPE_REGEX);
463                 regex = CMP_M(m)->right->data.data.re.regex;
464         }
465         else {
466                 sdb_data_t tmp = SDB_DATA_INIT;
467                 char *raw;
469                 if (sdb_store_expr_eval(CMP_M(m)->right, obj, &tmp, filter))
470                         return 0;
472                 if (tmp.type != SDB_TYPE_STRING) {
473                         sdb_data_free_datum(&tmp);
474                         return 0;
475                 }
477                 raw = tmp.data.string;
478                 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &tmp)) {
479                         free(raw);
480                         return 0;
481                 }
483                 regex = tmp.data.re.regex;
484                 free_regex = 1;
485                 free(tmp.data.re.raw);
486                 free(raw);
487         }
489         if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &v, filter))
490                         || (sdb_data_isnull(&v)))
491                 status = 0;
492         else {
493                 char value[sdb_data_strlen(&v) + 1];
494                 if (sdb_data_format(&v, value, sizeof(value), SDB_UNQUOTED) < 0)
495                         status = 0;
496                 else if (! regexec(&regex, value, 0, NULL, 0))
497                         status = 1;
498         }
500         if (free_regex)
501                 regfree(&regex);
502         sdb_data_free_datum(&v);
503         if (m->type == MATCHER_NREGEX)
504                 return !status;
505         return status;
506 } /* match_regex */
508 static int
509 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
510                 sdb_store_matcher_t *filter)
512         sdb_data_t v = SDB_DATA_INIT;
513         int status;
515         assert((m->type == MATCHER_ISNULL) || (m->type == MATCHER_ISNNULL));
517         /* TODO: this might hide real errors;
518          * improve error reporting and propagation */
519         if (sdb_store_expr_eval(ISNULL_M(m)->expr, obj, &v, filter)
520                         || sdb_data_isnull(&v))
521                 status = 1;
522         else
523                 status = 0;
525         sdb_data_free_datum(&v);
526         if (m->type == MATCHER_ISNNULL)
527                 return !status;
528         return status;
529 } /* match_isnull */
531 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
532                 sdb_store_matcher_t *);
534 /* this array needs to be indexable by the matcher types;
535  * -> update the enum in store-private.h when updating this */
536 static matcher_cb
537 matchers[] = {
538         match_logical,
539         match_logical,
540         match_unary,
541         match_name,
542         match_attr,
543         match_child,
544         match_child,
545         match_child,
546         match_lt,
547         match_le,
548         match_eq,
549         match_ge,
550         match_gt,
551         match_cmp_lt,
552         match_cmp_le,
553         match_cmp_eq,
554         match_cmp_ne,
555         match_cmp_ge,
556         match_cmp_gt,
557         match_in,
558         match_regex,
559         match_regex,
560         match_isnull,
561         match_isnull,
562 };
564 /*
565  * private conditional types
566  */
568 static int
569 attr_cond_init(sdb_object_t *obj, va_list ap)
571         const char *name = va_arg(ap, const char *);
572         sdb_store_expr_t *expr = va_arg(ap, sdb_store_expr_t *);
574         if (! name)
575                 return -1;
577         SDB_STORE_COND(obj)->cmp = attr_cmp;
579         ATTR_C(obj)->name = strdup(name);
580         if (! ATTR_C(obj)->name)
581                 return -1;
582         ATTR_C(obj)->expr = expr;
583         sdb_object_ref(SDB_OBJ(expr));
584         return 0;
585 } /* attr_cond_init */
587 static void
588 attr_cond_destroy(sdb_object_t *obj)
590         if (ATTR_C(obj)->name)
591                 free(ATTR_C(obj)->name);
592         sdb_object_deref(SDB_OBJ(ATTR_C(obj)->expr));
593 } /* attr_cond_destroy */
595 static sdb_type_t attr_cond_type = {
596         /* size = */ sizeof(attr_cond_t),
597         /* init = */ attr_cond_init,
598         /* destroy = */ attr_cond_destroy,
599 };
601 /*
602  * private matcher types
603  */
605 /* initializes a string matcher consuming two elements from ap */
606 static int
607 string_matcher_init(string_matcher_t *m, va_list ap)
609         const char *name = va_arg(ap, const char *);
610         const char *name_re = va_arg(ap, const char *);
612         if (name) {
613                 m->name = strdup(name);
614                 if (! m->name)
615                         return -1;
616         }
617         if (name_re) {
618                 m->name_re = malloc(sizeof(*m->name_re));
619                 if (! m->name_re)
620                         return -1;
621                 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
622                         return -1;
623         }
624         return 0;
625 } /* string_matcher_init */
627 static void
628 string_matcher_destroy(string_matcher_t *m)
630         if (m->name)
631                 free(m->name);
632         if (m->name_re) {
633                 regfree(m->name_re);
634                 free(m->name_re);
635         }
636 } /* string_matcher_destroy */
638 /* initializes a name matcher */
639 static int
640 name_matcher_init(sdb_object_t *obj, va_list ap)
642         name_matcher_t *m = NAME_M(obj);
643         M(obj)->type = MATCHER_NAME;
644         return string_matcher_init(&m->name, ap);
645 } /* name_matcher_init */
647 static void
648 name_matcher_destroy(sdb_object_t *obj)
650         name_matcher_t *m = NAME_M(obj);
651         string_matcher_destroy(&m->name);
652 } /* name_matcher_destroy */
654 static int
655 attr_matcher_init(sdb_object_t *obj, va_list ap)
657         attr_matcher_t *attr = ATTR_M(obj);
658         const char *name = va_arg(ap, const char *);
660         M(obj)->type = MATCHER_ATTR;
661         if (name) {
662                 attr->name = strdup(name);
663                 if (! attr->name)
664                         return -1;
665         }
666         return string_matcher_init(&attr->value, ap);
667 } /* attr_matcher_init */
669 static void
670 attr_matcher_destroy(sdb_object_t *obj)
672         attr_matcher_t *attr = ATTR_M(obj);
673         if (attr->name)
674                 free(attr->name);
675         attr->name = NULL;
676         string_matcher_destroy(&attr->value);
677 } /* attr_matcher_destroy */
679 static int
680 cond_matcher_init(sdb_object_t *obj, va_list ap)
682         int type = va_arg(ap, int);
683         sdb_store_cond_t *cond = va_arg(ap, sdb_store_cond_t *);
685         if (! cond)
686                 return -1;
688         sdb_object_ref(SDB_OBJ(cond));
690         M(obj)->type = type;
691         COND_M(obj)->cond = cond;
692         return 0;
693 } /* cond_matcher_init */
695 static void
696 cond_matcher_destroy(sdb_object_t *obj)
698         sdb_object_deref(SDB_OBJ(COND_M(obj)->cond));
699 } /* cond_matcher_destroy */
701 static int
702 op_matcher_init(sdb_object_t *obj, va_list ap)
704         M(obj)->type = va_arg(ap, int);
705         if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
706                 return -1;
708         OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
709         sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
710         OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
711         sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
713         if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
714                 return -1;
715         return 0;
716 } /* op_matcher_init */
718 static void
719 op_matcher_destroy(sdb_object_t *obj)
721         if (OP_M(obj)->left)
722                 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
723         if (OP_M(obj)->right)
724                 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
725 } /* op_matcher_destroy */
727 static int
728 child_matcher_init(sdb_object_t *obj, va_list ap)
730         M(obj)->type = va_arg(ap, int);
731         CHILD_M(obj)->m = va_arg(ap, sdb_store_matcher_t *);
733         if (! CHILD_M(obj)->m)
734                 return -1;
736         sdb_object_ref(SDB_OBJ(CHILD_M(obj)->m));
737         return 0;
738 } /* child_matcher_init */
740 static void
741 child_matcher_destroy(sdb_object_t *obj)
743         sdb_object_deref(SDB_OBJ(CHILD_M(obj)->m));
744 } /* child_matcher_destroy */
746 static int
747 cmp_matcher_init(sdb_object_t *obj, va_list ap)
749         M(obj)->type = va_arg(ap, int);
751         CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *);
752         sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
753         CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *);
754         sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
756         if ((! CMP_M(obj)->left) || (! CMP_M(obj)->right))
757                 return -1;
758         return 0;
759 } /* cmp_matcher_init */
761 static void
762 cmp_matcher_destroy(sdb_object_t *obj)
764         sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
765         sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
766 } /* cmp_matcher_destroy */
768 static int
769 uop_matcher_init(sdb_object_t *obj, va_list ap)
771         M(obj)->type = va_arg(ap, int);
772         if (M(obj)->type != MATCHER_NOT)
773                 return -1;
775         UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
776         sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
778         if (! UOP_M(obj)->op)
779                 return -1;
780         return 0;
781 } /* uop_matcher_init */
783 static void
784 uop_matcher_destroy(sdb_object_t *obj)
786         if (UOP_M(obj)->op)
787                 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
788 } /* uop_matcher_destroy */
790 static int
791 isnull_matcher_init(sdb_object_t *obj, va_list ap)
793         M(obj)->type = va_arg(ap, int);
794         if ((M(obj)->type != MATCHER_ISNULL) && (M(obj)->type != MATCHER_ISNNULL))
795                 return -1;
797         ISNULL_M(obj)->expr = va_arg(ap, sdb_store_expr_t *);
798         sdb_object_ref(SDB_OBJ(ISNULL_M(obj)->expr));
799         return 0;
800 } /* isnull_matcher_init */
802 static void
803 isnull_matcher_destroy(sdb_object_t *obj)
805         sdb_object_deref(SDB_OBJ(ISNULL_M(obj)->expr));
806         ISNULL_M(obj)->expr = NULL;
807 } /* isnull_matcher_destroy */
809 static sdb_type_t name_type = {
810         /* size = */ sizeof(name_matcher_t),
811         /* init = */ name_matcher_init,
812         /* destroy = */ name_matcher_destroy,
813 };
815 static sdb_type_t attr_type = {
816         /* size = */ sizeof(attr_matcher_t),
817         /* init = */ attr_matcher_init,
818         /* destroy = */ attr_matcher_destroy,
819 };
821 static sdb_type_t cond_type = {
822         /* size = */ sizeof(cond_matcher_t),
823         /* init = */ cond_matcher_init,
824         /* destroy = */ cond_matcher_destroy,
825 };
827 static sdb_type_t op_type = {
828         /* size = */ sizeof(op_matcher_t),
829         /* init = */ op_matcher_init,
830         /* destroy = */ op_matcher_destroy,
831 };
833 static sdb_type_t uop_type = {
834         /* size = */ sizeof(uop_matcher_t),
835         /* init = */ uop_matcher_init,
836         /* destroy = */ uop_matcher_destroy,
837 };
839 static sdb_type_t child_type = {
840         /* size = */ sizeof(child_matcher_t),
841         /* init = */ child_matcher_init,
842         /* destroy = */ child_matcher_destroy,
843 };
845 static sdb_type_t cmp_type = {
846         /* size = */ sizeof(cmp_matcher_t),
847         /* init = */ cmp_matcher_init,
848         /* destroy = */ cmp_matcher_destroy,
849 };
851 static sdb_type_t isnull_type = {
852         /* size = */ sizeof(isnull_matcher_t),
853         /* init = */ isnull_matcher_init,
854         /* destroy = */ isnull_matcher_destroy,
855 };
857 /*
858  * public API
859  */
861 sdb_store_cond_t *
862 sdb_store_attr_cond(const char *name, sdb_store_expr_t *expr)
864         return SDB_STORE_COND(sdb_object_create("attr-cond", attr_cond_type,
865                                 name, expr));
866 } /* sdb_store_attr_cond */
868 sdb_store_matcher_t *
869 sdb_store_name_matcher(int type, const char *name, _Bool re)
871         sdb_store_matcher_t *m;
873         if (re)
874                 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
875         else
876                 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
878         if (! m)
879                 return NULL;
881         NAME_M(m)->obj_type = type;
882         return m;
883 } /* sdb_store_name_matcher */
885 sdb_store_matcher_t *
886 sdb_store_attr_matcher(const char *name, const char *value, _Bool re)
888         sdb_store_matcher_t *m;
890         if (! name)
891                 return NULL;
893         if (re)
894                 m = M(sdb_object_create("attr-matcher", attr_type,
895                                         name, NULL, value));
896         else
897                 m = M(sdb_object_create("attr-matcher", attr_type,
898                                         name, value, NULL));
899         return m;
900 } /* sdb_store_attr_matcher */
902 sdb_store_matcher_t *
903 sdb_store_child_matcher(int type, sdb_store_matcher_t *m)
905         if (type == SDB_SERVICE)
906                 type = MATCHER_SERVICE;
907         else if (type == SDB_METRIC)
908                 type = MATCHER_METRIC;
909         else if (type == SDB_ATTRIBUTE)
910                 type = MATCHER_ATTRIBUTE;
911         else
912                 return NULL;
913         return M(sdb_object_create("any-matcher", child_type, type, m));
914 } /* sdb_store_child_matcher */
916 sdb_store_matcher_t *
917 sdb_store_lt_matcher(sdb_store_cond_t *cond)
919         return M(sdb_object_create("lt-matcher", cond_type,
920                                 MATCHER_LT, cond));
921 } /* sdb_store_lt_matcher */
923 sdb_store_matcher_t *
924 sdb_store_le_matcher(sdb_store_cond_t *cond)
926         return M(sdb_object_create("le-matcher", cond_type,
927                                 MATCHER_LE, cond));
928 } /* sdb_store_le_matcher */
930 sdb_store_matcher_t *
931 sdb_store_eq_matcher(sdb_store_cond_t *cond)
933         return M(sdb_object_create("eq-matcher", cond_type,
934                                 MATCHER_EQ, cond));
935 } /* sdb_store_eq_matcher */
937 sdb_store_matcher_t *
938 sdb_store_ge_matcher(sdb_store_cond_t *cond)
940         return M(sdb_object_create("ge-matcher", cond_type,
941                                 MATCHER_GE, cond));
942 } /* sdb_store_ge_matcher */
944 sdb_store_matcher_t *
945 sdb_store_gt_matcher(sdb_store_cond_t *cond)
947         return M(sdb_object_create("gt-matcher", cond_type,
948                                 MATCHER_GT, cond));
949 } /* sdb_store_gt_matcher */
951 /*
952  * TODO: Rename sdb_store_cmp_* to sdb_store_* once the old code is unused and
953  * has been removed.
954  */
956 sdb_store_matcher_t *
957 sdb_store_cmp_lt(sdb_store_expr_t *left, sdb_store_expr_t *right)
959         return M(sdb_object_create("lt-matcher", cmp_type,
960                                 MATCHER_CMP_LT, left, right));
961 } /* sdb_store_cmp_lt */
963 sdb_store_matcher_t *
964 sdb_store_cmp_le(sdb_store_expr_t *left, sdb_store_expr_t *right)
966         return M(sdb_object_create("le-matcher", cmp_type,
967                                 MATCHER_CMP_LE, left, right));
968 } /* sdb_store_cmp_le */
970 sdb_store_matcher_t *
971 sdb_store_cmp_eq(sdb_store_expr_t *left, sdb_store_expr_t *right)
973         return M(sdb_object_create("eq-matcher", cmp_type,
974                                 MATCHER_CMP_EQ, left, right));
975 } /* sdb_store_cmp_eq */
977 sdb_store_matcher_t *
978 sdb_store_cmp_ne(sdb_store_expr_t *left, sdb_store_expr_t *right)
980         return M(sdb_object_create("ne-matcher", cmp_type,
981                                 MATCHER_CMP_NE, left, right));
982 } /* sdb_store_cmp_ne */
984 sdb_store_matcher_t *
985 sdb_store_cmp_ge(sdb_store_expr_t *left, sdb_store_expr_t *right)
987         return M(sdb_object_create("ge-matcher", cmp_type,
988                                 MATCHER_CMP_GE, left, right));
989 } /* sdb_store_cmp_ge */
991 sdb_store_matcher_t *
992 sdb_store_cmp_gt(sdb_store_expr_t *left, sdb_store_expr_t *right)
994         return M(sdb_object_create("gt-matcher", cmp_type,
995                                 MATCHER_CMP_GT, left, right));
996 } /* sdb_store_cmp_gt */
998 sdb_store_matcher_t *
999 sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1001         return M(sdb_object_create("in-matcher", cmp_type,
1002                                 MATCHER_IN, left, right));
1003 } /* sdb_store_in_matcher */
1005 sdb_store_matcher_t *
1006 sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1008         if (! right->type) {
1009                 if ((right->data.type != SDB_TYPE_STRING)
1010                                 && (right->data.type != SDB_TYPE_REGEX))
1011                         return NULL;
1013                 if (right->data.type == SDB_TYPE_STRING) {
1014                         char *raw = right->data.data.string;
1015                         if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
1016                                 return NULL;
1017                         free(raw);
1018                 }
1019         }
1020         return M(sdb_object_create("regex-matcher", cmp_type,
1021                                 MATCHER_REGEX, left, right));
1022 } /* sdb_store_regex_matcher */
1024 sdb_store_matcher_t *
1025 sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1027         sdb_store_matcher_t *m = sdb_store_regex_matcher(left, right);
1028         if (! m)
1029                 return NULL;
1030         m->type = MATCHER_NREGEX;
1031         return m;
1032 } /* sdb_store_nregex_matcher */
1034 sdb_store_matcher_t *
1035 sdb_store_isnull_matcher(sdb_store_expr_t *expr)
1037         return M(sdb_object_create("isnull-matcher", isnull_type,
1038                                 MATCHER_ISNULL, expr));
1039 } /* sdb_store_isnull_matcher */
1041 sdb_store_matcher_t *
1042 sdb_store_isnnull_matcher(sdb_store_expr_t *expr)
1044         return M(sdb_object_create("isnull-matcher", isnull_type,
1045                                 MATCHER_ISNNULL, expr));
1046 } /* sdb_store_isnnull_matcher */
1048 sdb_store_matcher_op_cb
1049 sdb_store_parse_matcher_op(const char *op)
1051         if (! strcasecmp(op, "<"))
1052                 return sdb_store_cmp_lt;
1053         else if (! strcasecmp(op, "<="))
1054                 return sdb_store_cmp_le;
1055         else if (! strcasecmp(op, "="))
1056                 return sdb_store_cmp_eq;
1057         else if (! strcasecmp(op, "!="))
1058                 return sdb_store_cmp_ne;
1059         else if (! strcasecmp(op, ">="))
1060                 return sdb_store_cmp_ge;
1061         else if (! strcasecmp(op, ">"))
1062                 return sdb_store_cmp_gt;
1063         else if (! strcasecmp(op, "=~"))
1064                 return sdb_store_regex_matcher;
1065         else if (! strcasecmp(op, "!~"))
1066                 return sdb_store_nregex_matcher;
1067         return NULL;
1068 } /* sdb_store_parse_matcher_op */
1070 int
1071 sdb_store_parse_object_type_plural(const char *name)
1073         if (! strcasecmp(name, "hosts"))
1074                 return SDB_HOST;
1075         else if (! strcasecmp(name, "services"))
1076                 return SDB_SERVICE;
1077         else if (! strcasecmp(name, "metrics"))
1078                 return SDB_METRIC;
1079         return -1;
1080 } /* sdb_store_parse_object_type_plural */
1082 int
1083 sdb_store_parse_field_name(const char *name)
1085         if (! strcasecmp(name, "name"))
1086                 return SDB_FIELD_NAME;
1087         else if (! strcasecmp(name, "last_update"))
1088                 return SDB_FIELD_LAST_UPDATE;
1089         else if (! strcasecmp(name, "age"))
1090                 return SDB_FIELD_AGE;
1091         else if (! strcasecmp(name, "interval"))
1092                 return SDB_FIELD_INTERVAL;
1093         else if (! strcasecmp(name, "backend"))
1094                 return SDB_FIELD_BACKEND;
1095         return -1;
1096 } /* sdb_store_parse_field_name */
1098 static sdb_store_matcher_t *
1099 maybe_inv_matcher(sdb_store_matcher_t *m, _Bool inv)
1101         sdb_store_matcher_t *tmp;
1103         if ((! m) || (! inv))
1104                 return m;
1106         tmp = sdb_store_inv_matcher(m);
1107         /* pass ownership to the inverse matcher */
1108         sdb_object_deref(SDB_OBJ(m));
1109         return tmp;
1110 } /* maybe_inv_matcher */
1112 static int
1113 parse_cond_op(const char *op,
1114                 sdb_store_matcher_t *(**matcher)(sdb_store_cond_t *), _Bool *inv)
1116         *inv = 0;
1117         if (! strcasecmp(op, "<"))
1118                 *matcher = sdb_store_lt_matcher;
1119         else if (! strcasecmp(op, "<="))
1120                 *matcher = sdb_store_le_matcher;
1121         else if (! strcasecmp(op, "="))
1122                 *matcher = sdb_store_eq_matcher;
1123         else if (! strcasecmp(op, ">="))
1124                 *matcher = sdb_store_ge_matcher;
1125         else if (! strcasecmp(op, ">"))
1126                 *matcher = sdb_store_gt_matcher;
1127         else if (! strcasecmp(op, "!=")) {
1128                 *matcher = sdb_store_eq_matcher;
1129                 *inv = 1;
1130         }
1131         else
1132                 return -1;
1133         return 0;
1134 } /* parse_cond_op */
1136 static sdb_store_matcher_t *
1137 parse_attr_cmp(const char *attr, const char *op, sdb_store_expr_t *expr)
1139         sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL;
1140         sdb_store_matcher_t *m;
1141         sdb_store_cond_t *cond;
1142         _Bool inv = 0;
1144         if (! attr)
1145                 return NULL;
1147         if (! expr)
1148                 return NULL;
1149         else if (parse_cond_op(op, &matcher, &inv))
1150                 return NULL;
1152         cond = sdb_store_attr_cond(attr, expr);
1153         if (! cond)
1154                 return NULL;
1156         m = matcher(cond);
1157         /* pass ownership to 'm' or destroy in case of an error */
1158         sdb_object_deref(SDB_OBJ(cond));
1159         return maybe_inv_matcher(m, inv);
1160 } /* parse_attr_cmp */
1162 sdb_store_matcher_t *
1163 sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr,
1164                 const char *op, sdb_store_expr_t *expr)
1166         int type = -1;
1167         _Bool inv = 0;
1168         _Bool re = 0;
1170         sdb_data_t value = SDB_DATA_INIT;
1171         sdb_store_matcher_t *m = NULL;
1173         if (! strcasecmp(obj_type, "host"))
1174                 type = SDB_HOST;
1175         else if (! strcasecmp(obj_type, "service"))
1176                 type = SDB_SERVICE;
1177         else if (! strcasecmp(obj_type, "metric"))
1178                 type = SDB_METRIC;
1179         else if (! strcasecmp(obj_type, "attribute"))
1180                 type = SDB_ATTRIBUTE;
1181         else
1182                 return NULL;
1184         /* XXX: this code sucks! */
1185         if (! strcasecmp(op, "=")) {
1186                 /* nothing to do */
1187         }
1188         else if (! strcasecmp(op, "!=")) {
1189                 inv = 1;
1190         }
1191         else if (! strcasecmp(op, "=~")) {
1192                 re = 1;
1193         }
1194         else if (! strcasecmp(op, "!~")) {
1195                 inv = 1;
1196                 re = 1;
1197         }
1198         else if (type == SDB_ATTRIBUTE)
1199                 return parse_attr_cmp(attr, op, expr);
1200         else
1201                 return NULL;
1203         if (! expr)
1204                 return NULL;
1206         if (sdb_store_expr_eval(expr, /* obj */ NULL, &value, /* filter */ NULL)
1207                         || (value.type != SDB_TYPE_STRING)) {
1208                 sdb_data_free_datum(&value);
1209                 if (type != SDB_ATTRIBUTE)
1210                         return NULL;
1211                 return parse_attr_cmp(attr, op, expr);
1212         }
1214         if (! attr)
1215                 m = sdb_store_name_matcher(type, value.data.string, re);
1216         else if (type == SDB_ATTRIBUTE)
1217                 m = sdb_store_attr_matcher(attr, value.data.string, re);
1219         sdb_data_free_datum(&value);
1220         return maybe_inv_matcher(m, inv);
1221 } /* sdb_store_matcher_parse_cmp */
1223 sdb_store_matcher_t *
1224 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1226         return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
1227                                 left, right));
1228 } /* sdb_store_dis_matcher */
1230 sdb_store_matcher_t *
1231 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1233         return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
1234                                 left, right));
1235 } /* sdb_store_con_matcher */
1237 sdb_store_matcher_t *
1238 sdb_store_inv_matcher(sdb_store_matcher_t *m)
1240         return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
1241 } /* sdb_store_inv_matcher */
1243 int
1244 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
1245                 sdb_store_matcher_t *filter)
1247         if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
1248                 return 0;
1250         /* "NULL" always matches */
1251         if ((! m) || (! obj))
1252                 return 1;
1254         if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
1255                 return 0;
1257         return matchers[m->type](m, obj, filter);
1258 } /* sdb_store_matcher_matches */
1260 int
1261 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
1262                 sdb_store_lookup_cb cb, void *user_data)
1264         scan_iter_data_t data = { m, filter, cb, user_data };
1266         if (! cb)
1267                 return -1;
1268         return sdb_store_iterate(scan_iter, &data);
1269 } /* sdb_store_scan */
1271 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */