Code

store: Added support for regex matchers.
authorSebastian Harl <sh@tokkee.org>
Wed, 15 Oct 2014 13:36:29 +0000 (15:36 +0200)
committerSebastian Harl <sh@tokkee.org>
Wed, 15 Oct 2014 13:36:29 +0000 (15:36 +0200)
A regex matcher matches the string value an expression evaluates to against a
regular expression. Dynamic regular expressions are supported as well through
expressions evaluating to a string which is then dynamically compiled into a
regular expression when executing the matcher.

src/core/store-private.h
src/core/store_expr.c
src/core/store_lookup.c
src/include/core/store.h

index b8f27e25e20ff0f7af2c34f7a98ba9df93f4728c..1633d42c5672e867bec3de21b10153b6c7931274 100644 (file)
@@ -103,6 +103,27 @@ typedef struct {
 #define _last_update super.last_update
 #define _interval super.interval
 
+/*
+ * expressions
+ */
+enum {
+       ATTR_VALUE  = -2, /* attr name stored in data.data.string */
+       FIELD_VALUE = -1, /* field type stored in data.data.integer */
+       /*  0: const value (stored in data) */
+       /* >0: operator id */
+};
+
+struct sdb_store_expr {
+       sdb_object_t super;
+
+       int type; /* see above */
+
+       sdb_store_expr_t *left;
+       sdb_store_expr_t *right;
+
+       sdb_data_t data;
+};
+
 /*
  * conditionals
  */
@@ -135,8 +156,8 @@ typedef struct {
  * matchers
  */
 
-/* when adding to this, also update 'matchers' and 'matchers_tostring'
- * in store_lookup.c */
+/* when adding to this, also update 'MATCHER_SYM' below as well as 'matchers'
+ * and 'matchers_tostring' in store_lookup.c */
 enum {
        MATCHER_OR,
        MATCHER_AND,
@@ -156,6 +177,7 @@ enum {
        MATCHER_CMP_EQ,
        MATCHER_CMP_GE,
        MATCHER_CMP_GT,
+       MATCHER_REGEX,
        MATCHER_ISNULL,
 };
 
@@ -173,6 +195,7 @@ enum {
                : ((t) == MATCHER_EQ) ? "=" \
                : ((t) == MATCHER_GE) ? ">=" \
                : ((t) == MATCHER_GT) ? ">" \
+               : ((t) == MATCHER_REGEX) ? "=~" \
                : ((t) == MATCHER_ISNULL) ? "IS NULL" \
                : "UNKNOWN")
 
index 4e8bae7cad7c980941145938597be86e1bb770f3..0a8757f0911568b5b9b2cf8c66ad1fcc0ade62cd 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-/*
- * private data types
- */
-
-/*
- * expression types:
- */
-enum {
-       ATTR_VALUE  = -2, /* attr name stored in data.data.string */
-       FIELD_VALUE = -1, /* field type stored in data.data.integer */
-       /*  0: const value (stored in data) */
-       /* >0: operator id */
-};
-
-struct sdb_store_expr {
-       sdb_object_t super;
-
-       int type; /* see above */
-
-       sdb_store_expr_t *left;
-       sdb_store_expr_t *right;
-
-       sdb_data_t data;
-};
-
 /*
  * private data types
  */
index 9968aba468eab75c8dfc8b4da86c915504c1c3e9..a86743e7cedc4d2fff72c950f580bce0925dc00d 100644 (file)
@@ -455,6 +455,62 @@ match_cmp_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
        return (status != INT_MAX) && (status > 0);
 } /* match_cmp_gt */
 
+static int
+match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
+               sdb_store_matcher_t *filter)
+{
+       sdb_data_t v = SDB_DATA_INIT;
+       int status = 0;
+
+       regex_t regex;
+       _Bool free_regex = 0;
+
+       assert(m->type == MATCHER_REGEX);
+
+       if (! CMP_M(m)->right->type) {
+               assert(CMP_M(m)->right->data.type == SDB_TYPE_REGEX);
+               regex = CMP_M(m)->right->data.data.re.regex;
+       }
+       else {
+               sdb_data_t tmp = SDB_DATA_INIT;
+               char *raw;
+
+               if (sdb_store_expr_eval(CMP_M(m)->right, obj, &tmp, filter))
+                       return 0;
+
+               if (tmp.type != SDB_TYPE_STRING) {
+                       sdb_data_free_datum(&tmp);
+                       return 0;
+               }
+
+               raw = tmp.data.string;
+               if (sdb_data_parse(raw, SDB_TYPE_REGEX, &tmp)) {
+                       free(raw);
+                       return 0;
+               }
+
+               regex = tmp.data.re.regex;
+               free_regex = 1;
+               free(tmp.data.re.raw);
+               free(raw);
+       }
+
+       if (sdb_store_expr_eval(CMP_M(m)->left, obj, &v, filter))
+               status = 0;
+       else {
+               char value[sdb_data_strlen(&v) + 1];
+               if (sdb_data_format(&v, value, sizeof(value), SDB_UNQUOTED) < 0)
+                       status = 0;
+               else if (! regexec(&regex, value, 0, NULL, 0))
+                       status = 1;
+       }
+
+       if (free_regex)
+               regfree(&regex);
+       sdb_data_free_datum(&v);
+       return status;
+} /* match_regex */
+
 static int
 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
                sdb_store_matcher_t *filter)
@@ -490,6 +546,7 @@ matchers[] = {
        match_cmp_eq,
        match_cmp_ge,
        match_cmp_gt,
+       match_regex,
        match_isnull,
 };
 
@@ -980,6 +1037,7 @@ matchers_tostring[] = {
        cmp_tostring,
        cmp_tostring,
        cmp_tostring,
+       cmp_tostring,
        isnull_tostring,
 };
 
@@ -1124,6 +1182,25 @@ sdb_store_cmp_gt(sdb_store_expr_t *left, sdb_store_expr_t *right)
                                MATCHER_CMP_GT, left, right));
 } /* sdb_store_cmp_gt */
 
+sdb_store_matcher_t *
+sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
+{
+       if (! right->type) {
+               if ((right->data.type != SDB_TYPE_STRING)
+                               && (right->data.type != SDB_TYPE_REGEX))
+                       return NULL;
+
+               if (right->data.type == SDB_TYPE_STRING) {
+                       char *raw = right->data.data.string;
+                       if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
+                               return NULL;
+                       free(raw);
+               }
+       }
+       return M(sdb_object_create("regex-matcher", cmp_type,
+                               MATCHER_REGEX, left, right));
+} /* sdb_store_regex_matcher */
+
 sdb_store_matcher_t *
 sdb_store_isnull_matcher(const char *attr_name)
 {
index 9304acfa79e1f7761928a76dad17e161d02db09f..1729f0c8bcbcedcac1dbc21f773d5d0195bd47fd 100644 (file)
@@ -449,6 +449,17 @@ sdb_store_cmp_ge(sdb_store_expr_t *left, sdb_store_expr_t *right);
 sdb_store_matcher_t *
 sdb_store_cmp_gt(sdb_store_expr_t *left, sdb_store_expr_t *right);
 
+/*
+ * sdb_store_regex_matcher:
+ * Creates a matcher which matches the string value the left expression
+ * evaluates to against the regular expression the right expression evaluates
+ * to. The right expression may either be a constant value regular expression
+ * or string or a dynamic value evaluating to a string. In the latter case,
+ * the string is compiled to a regex every time the matcher is executed.
+ */
+sdb_store_matcher_t *
+sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right);
+
 /*
  * sdb_store_parse_object_type_plural:
  * Parse the type name (plural) of a stored object.