From d4a8da24750a0547a6b6af29853f519869bb9a53 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 14 Oct 2014 23:07:43 +0200 Subject: [PATCH] store: Added matchers comparing two expressions. This is much more powerful than the old conditional matchers and will replace those once all code has been migrated to the new compare matchers. --- src/core/store-private.h | 15 ++++ src/core/store_lookup.c | 174 +++++++++++++++++++++++++++++++++++++++ src/include/core/store.h | 11 +++ 3 files changed, 200 insertions(+) diff --git a/src/core/store-private.h b/src/core/store-private.h index 6dc68c0..4f9b9b5 100644 --- a/src/core/store-private.h +++ b/src/core/store-private.h @@ -148,6 +148,11 @@ enum { MATCHER_EQ, MATCHER_GE, MATCHER_GT, + MATCHER_CMP_LT, + MATCHER_CMP_LE, + MATCHER_CMP_EQ, + MATCHER_CMP_GE, + MATCHER_CMP_GT, MATCHER_ISNULL, }; @@ -198,6 +203,16 @@ typedef struct { } uop_matcher_t; #define UOP_M(m) ((uop_matcher_t *)(m)) +/* compare operator matcher */ +typedef struct { + sdb_store_matcher_t super; + + /* left and right hand expressions */ + sdb_store_expr_t *left; + sdb_store_expr_t *right; +} cmp_matcher_t; +#define CMP_M(m) ((cmp_matcher_t *)(m)) + /* match any type of object by it's name */ typedef struct { sdb_store_matcher_t super; diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index dc3e499..4e777d8 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -336,6 +336,88 @@ match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj, return (status != INT_MAX) && (status > 0); } /* match_gt */ +/* + * cmp_expr: + * Compare the values of two expressions when evaluating them using the + * specified stored object and filter. Returns a value less than, equal to, or + * greater than zero if the value of the first expression compares less than, + * equal to, or greater than the value of the second expression. Returns + * INT_MAX if any of the expressions could not be evaluated. + */ +static int +cmp_expr(sdb_store_expr_t *e1, sdb_store_expr_t *e2, + sdb_store_obj_t *obj, sdb_store_matcher_t *filter) +{ + sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT; + int status; + + if (sdb_store_expr_eval(e1, obj, &v1, filter)) + return INT_MAX; + if (sdb_store_expr_eval(e2, obj, &v2, filter)) { + sdb_data_free_datum(&v1); + return INT_MAX; + } + + if (v1.type == v2.type) + status = sdb_data_cmp(&v1, &v2); + else + status = sdb_data_strcmp(&v1, &v2); + + sdb_data_free_datum(&v1); + sdb_data_free_datum(&v2); + return status; +} /* cmp_expr */ + +static int +match_cmp_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + int status; + assert(m->type == MATCHER_CMP_LT); + status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter); + return (status != INT_MAX) && (status < 0); +} /* match_cmp_lt */ + +static int +match_cmp_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + int status; + assert(m->type == MATCHER_CMP_LE); + status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter); + return (status != INT_MAX) && (status <= 0); +} /* match_cmp_le */ + +static int +match_cmp_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + int status; + assert(m->type == MATCHER_CMP_EQ); + status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter); + return (status != INT_MAX) && (! status); +} /* match_cmp_eq */ + +static int +match_cmp_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + int status; + assert(m->type == MATCHER_CMP_GE); + status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter); + return (status != INT_MAX) && (status >= 0); +} /* match_cmp_ge */ + +static int +match_cmp_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj, + sdb_store_matcher_t *filter) +{ + int status; + assert(m->type == MATCHER_CMP_GT); + status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter); + return (status != INT_MAX) && (status > 0); +} /* match_cmp_gt */ + static int match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj, sdb_store_matcher_t *filter) @@ -363,6 +445,11 @@ matchers[] = { match_eq, match_ge, match_gt, + match_cmp_lt, + match_cmp_le, + match_cmp_eq, + match_cmp_ge, + match_cmp_gt, match_isnull, }; @@ -644,6 +731,42 @@ op_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) return buf; } /* op_tostring */ +static int +cmp_matcher_init(sdb_object_t *obj, va_list ap) +{ + M(obj)->type = va_arg(ap, int); + + CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *); + sdb_object_ref(SDB_OBJ(CMP_M(obj)->left)); + CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *); + sdb_object_ref(SDB_OBJ(CMP_M(obj)->right)); + + if ((! CMP_M(obj)->left) || (! CMP_M(obj)->right)) + return -1; + return 0; +} /* cmp_matcher_init */ + +static void +cmp_matcher_destroy(sdb_object_t *obj) +{ + sdb_object_deref(SDB_OBJ(CMP_M(obj)->left)); + sdb_object_deref(SDB_OBJ(CMP_M(obj)->right)); +} /* cmp_matcher_destroy */ + +static char * +cmp_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + if (! m) { + /* this should not happen */ + snprintf(buf, buflen, "()"); + return buf; + } + + /* TODO */ + snprintf(buf, buflen, "CMP_MATCHER(%d)", m->type); + return buf; +} /* cmp_tostring */ + static int uop_matcher_init(sdb_object_t *obj, va_list ap) { @@ -746,6 +869,12 @@ static sdb_type_t uop_type = { /* destroy = */ uop_matcher_destroy, }; +static sdb_type_t cmp_type = { + /* size = */ sizeof(cmp_matcher_t), + /* init = */ cmp_matcher_init, + /* destroy = */ cmp_matcher_destroy, +}; + static sdb_type_t isnull_type = { /* size = */ sizeof(isnull_matcher_t), /* init = */ isnull_matcher_init, @@ -768,6 +897,11 @@ matchers_tostring[] = { cond_tostring, cond_tostring, cond_tostring, + cmp_tostring, + cmp_tostring, + cmp_tostring, + cmp_tostring, + cmp_tostring, isnull_tostring, }; @@ -858,6 +992,46 @@ sdb_store_gt_matcher(sdb_store_cond_t *cond) MATCHER_GT, cond)); } /* sdb_store_gt_matcher */ +/* + * TODO: Rename sdb_store_cmp_* to sdb_store_* once the old code is unused and + * has been removed. + */ + +sdb_store_matcher_t * +sdb_store_cmp_lt(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("lt-matcher", cmp_type, + MATCHER_CMP_LT, left, right)); +} /* sdb_store_cmp_lt */ + +sdb_store_matcher_t * +sdb_store_cmp_le(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("le-matcher", cmp_type, + MATCHER_CMP_LE, left, right)); +} /* sdb_store_cmp_le */ + +sdb_store_matcher_t * +sdb_store_cmp_eq(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("eq-matcher", cmp_type, + MATCHER_CMP_EQ, left, right)); +} /* sdb_store_cmp_eq */ + +sdb_store_matcher_t * +sdb_store_cmp_ge(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("ge-matcher", cmp_type, + MATCHER_CMP_GE, left, right)); +} /* sdb_store_cmp_ge */ + +sdb_store_matcher_t * +sdb_store_cmp_gt(sdb_store_expr_t *left, sdb_store_expr_t *right) +{ + return M(sdb_object_create("gt-matcher", cmp_type, + MATCHER_CMP_GT, left, right)); +} /* sdb_store_cmp_gt */ + 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 c0a9849..e3b3387 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -430,6 +430,17 @@ sdb_store_ge_matcher(sdb_store_cond_t *cond); sdb_store_matcher_t * sdb_store_gt_matcher(sdb_store_cond_t *cond); +sdb_store_matcher_t * +sdb_store_cmp_lt(sdb_store_expr_t *left, sdb_store_expr_t *right); +sdb_store_matcher_t * +sdb_store_cmp_le(sdb_store_expr_t *left, sdb_store_expr_t *right); +sdb_store_matcher_t * +sdb_store_cmp_eq(sdb_store_expr_t *left, sdb_store_expr_t *right); +sdb_store_matcher_t * +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_parse_object_type_plural: * Parse the type name (plural) of a stored object. -- 2.30.2