From: Sebastian Harl Date: Wed, 15 Oct 2014 13:36:29 +0000 (+0200) Subject: store: Added support for regex matchers. X-Git-Tag: sysdb-0.6.0~116 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=bd23ae3fbe9af45288d515bd5e85742f8766fcf1 store: Added support for regex matchers. 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. --- diff --git a/src/core/store-private.h b/src/core/store-private.h index b8f27e2..1633d42 100644 --- a/src/core/store-private.h +++ b/src/core/store-private.h @@ -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") diff --git a/src/core/store_expr.c b/src/core/store_expr.c index 4e8bae7..0a8757f 100644 --- a/src/core/store_expr.c +++ b/src/core/store_expr.c @@ -42,31 +42,6 @@ #include #include -/* - * 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 */ diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index 9968aba..a86743e 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -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(®ex, value, 0, NULL, 0)) + status = 1; + } + + if (free_regex) + regfree(®ex); + 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) { diff --git a/src/include/core/store.h b/src/include/core/store.h index 9304acf..1729f0c 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -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.