summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 02293b5)
raw | patch | inline | side by side (parent: 02293b5)
author | Sebastian Harl <sh@tokkee.org> | |
Sun, 20 Jul 2014 18:55:44 +0000 (20:55 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sun, 20 Jul 2014 18:55:44 +0000 (20:55 +0200) |
This matches any hosts which are missing the specified attribute.
index c7d99f9b910ee2abee60b4318c198db39f8ace1e..a2121f45c211dad50003007e6a438f9958725638 100644 (file)
--- a/src/core/store-private.h
+++ b/src/core/store-private.h
MATCHER_EQ,
MATCHER_GE,
MATCHER_GT,
+ MATCHER_ISNULL,
};
#define MATCHER_SYM(t) \
: ((t) == MATCHER_EQ) ? "=" \
: ((t) == MATCHER_GE) ? ">=" \
: ((t) == MATCHER_GT) ? ">" \
+ : ((t) == MATCHER_ISNULL) ? "IS NULL" \
: "UNKNOWN")
/* match the name of something */
} attr_matcher_t;
#define ATTR_M(m) ((attr_matcher_t *)(m))
+typedef struct {
+ sdb_store_matcher_t super;
+ char *attr_name; /* we only support matching attributes */
+} isnull_matcher_t;
+#define ISNULL_M(m) ((isnull_matcher_t *)(m))
+
/* match using conditionals */
typedef struct {
sdb_store_matcher_t super;
index 7e2acefd12208c5d276dc73fdef3569a48cc45e2..557b93662f55d0ce4a83329112c98a2382b74a85 100644 (file)
--- a/src/core/store_lookup.c
+++ b/src/core/store_lookup.c
return (status != INT_MAX) && (status > 0);
} /* match_gt */
+static int
+match_isnull(sdb_store_matcher_t *m, sdb_host_t *host)
+{
+ assert(m->type == MATCHER_ISNULL);
+ return attr_get(host, ISNULL_M(m)->attr_name) == NULL;
+} /* match_isnull */
+
typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_host_t *);
/* this array needs to be indexable by the matcher types;
* -> update the enum in store-private.h when updating this */
-static matcher_cb matchers[] = {
+static matcher_cb
+matchers[] = {
match_logical,
match_logical,
match_unary,
match_eq,
match_ge,
match_gt,
+ match_isnull,
};
/*
return buf;
} /* uop_tostring */
+static int
+isnull_matcher_init(sdb_object_t *obj, va_list ap)
+{
+ const char *name;
+
+ M(obj)->type = va_arg(ap, int);
+ if (M(obj)->type != MATCHER_ISNULL)
+ return -1;
+
+ name = va_arg(ap, const char *);
+ if (! name)
+ return -1;
+ ISNULL_M(obj)->attr_name = strdup(name);
+ if (! ISNULL_M(obj)->attr_name)
+ return -1;
+ return 0;
+} /* isnull_matcher_init */
+
+static void
+isnull_matcher_destroy(sdb_object_t *obj)
+{
+ if (ISNULL_M(obj)->attr_name)
+ free(ISNULL_M(obj)->attr_name);
+ ISNULL_M(obj)->attr_name = NULL;
+} /* isnull_matcher_destroy */
+
+static char *
+isnull_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ snprintf(buf, buflen, "(IS NULL, attr.%s)", ISNULL_M(m)->attr_name);
+ return buf;
+} /* isnull_tostring */
+
static sdb_type_t name_type = {
/* size = */ sizeof(name_matcher_t),
/* init = */ name_matcher_init,
/* destroy = */ uop_matcher_destroy,
};
+static sdb_type_t isnull_type = {
+ /* size = */ sizeof(isnull_matcher_t),
+ /* init = */ isnull_matcher_init,
+ /* destroy = */ isnull_matcher_destroy,
+};
+
typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
/* this array needs to be indexable by the matcher types;
* -> update the enum in store-private.h when updating this */
-static matcher_tostring_cb matchers_tostring[] = {
+static matcher_tostring_cb
+matchers_tostring[] = {
op_tostring,
op_tostring,
uop_tostring,
cond_tostring,
cond_tostring,
cond_tostring,
+ isnull_tostring,
};
/*
MATCHER_GT, cond));
} /* sdb_store_gt_matcher */
+sdb_store_matcher_t *
+sdb_store_isnull_matcher(const char *attr_name)
+{
+ return M(sdb_object_create("isnull-matcher", isnull_type,
+ MATCHER_ISNULL, attr_name));
+} /* sdb_store_isnull_matcher */
+
static sdb_store_matcher_t *
parse_attr_cmp(const char *attr, const char *op, const sdb_data_t *value)
{
if (! strcasecmp(attr, "name"))
return NULL;
- if (! strcasecmp(op, "<"))
+ if (! strcasecmp(op, "IS"))
+ return sdb_store_isnull_matcher(attr);
+ else if (! value)
+ return NULL;
+ else if (! strcasecmp(op, "<"))
matcher = sdb_store_lt_matcher;
else if (! strcasecmp(op, "<="))
matcher = sdb_store_le_matcher;
diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y
index 34a9c6b6474502d9fc059df45a6ed93a79890567..2173e6df1b383f1ce2ce58f849cb70c37aa021c2 100644 (file)
--- a/src/frontend/grammar.y
+++ b/src/frontend/grammar.y
%token SCANNER_ERROR
-%token AND OR NOT WHERE
+%token AND OR IS NOT WHERE
%token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
%token CMP_LT CMP_LE CMP_GE CMP_GT
+/* NULL token */
+%token NULL_T
+
%token FETCH LIST LOOKUP
%token <str> IDENTIFIER STRING
%right NOT
%left CMP_EQUAL CMP_NEQUAL
%left CMP_LT CMP_LE CMP_GE CMP_GT
-%left CMP_REGEX CMP_NREGEX
+%nonassoc CMP_REGEX CMP_NREGEX
+%nonassoc IS
%left '(' ')'
%left '.'
free($3); $3 = NULL;
sdb_data_free_datum(&$5);
}
+ |
+ IDENTIFIER '.' IDENTIFIER IS NULL_T
+ {
+ $$ = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL);
+ free($1); $1 = NULL;
+ free($3); $3 = NULL;
+ }
+ |
+ IDENTIFIER '.' IDENTIFIER IS NOT NULL_T
+ {
+ sdb_store_matcher_t *m;
+ m = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL);
+ free($1); $1 = NULL;
+ free($3); $3 = NULL;
+
+ /* sdb_store_inv_matcher return NULL if m==NULL */
+ $$ = sdb_store_inv_matcher(m);
+ sdb_object_deref(SDB_OBJ(m));
+ }
;
op:
diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l
index 0396db53e0d742f17ca12de0fcec788da4c24045..a7b72b43794541985e722ca2f2c6ea3a61848e12 100644 (file)
--- a/src/frontend/scanner.l
+++ b/src/frontend/scanner.l
return AND;
else if (! strcasecmp(yytext, "FETCH"))
return FETCH;
+ else if (! strcasecmp(yytext, "IS"))
+ return IS;
else if (! strcasecmp(yytext, "LIST"))
return LIST;
else if (! strcasecmp(yytext, "LOOKUP"))
return LOOKUP;
else if (! strcasecmp(yytext, "NOT"))
return NOT;
+ else if (! strcasecmp(yytext, "NULL"))
+ return NULL_T;
else if (! strcasecmp(yytext, "OR"))
return OR;
else if (! strcasecmp(yytext, "WHERE"))
index aa28c96d1be99c57806dd79965ccc38ccf3ae2ce..7a9dc44bbc887cd00583675ed841d8c9c70ec30f 100644 (file)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
sdb_store_matcher_t *
sdb_store_attr_matcher(const char *name, const char *value, _Bool re);
+/*
+ * sdb_store_isnull_matcher:
+ * Creates a matcher matching "missing" attributes.
+ */
+sdb_store_matcher_t *
+sdb_store_isnull_matcher(const char *attr_name);
+
/*
* sdb_store_lt_matcher, sdb_store_le_matcher, sdb_store_eq_matcher,
* sdb_store_ge_matcher, sdb_store_gt_matcher:
index 8c626606c3c2d1900aa580a6f721a180fd66c382..4b9b6728d00ebb7bece003f7dc47de1f4ad3c236 100644 (file)
"attribute.foo = "
"-12e+3", -1, 1, CONNECTION_LOOKUP },
+ /* NULL */
+ { "LOOKUP hosts WHERE "
+ "attribute.foo "
+ "IS NULL", -1, 1, CONNECTION_LOOKUP },
+ { "LOOKUP hosts WHERE "
+ "attribute.foo "
+ "IS NOT NULL", -1, 1, CONNECTION_LOOKUP },
+ { "LOOKUP hosts WHERE "
+ "NOT attribute.foo "
+ "IS NULL", -1, 1, CONNECTION_LOOKUP },
+ { "LOOKUP hosts WHERE "
+ "host.name IS NULL", -1, -1, 0 },
+ { "LOOKUP hosts WHERE "
+ "service.name "
+ "IS NULL", -1, -1, 0 },
+
/* invalid numeric constants */
{ "LOOKUP hosts WHERE "
"attribute.foo = "
{ "host.name =~ 'pattern' OR "
"service.name =~ 'pattern'", -1, MATCHER_OR },
{ "NOT host.name = 'host'", -1, MATCHER_NOT },
+ /* numeric expressions */
+ { "attribute.foo < 123", -1, MATCHER_LT },
+ { "attribute.foo <= 123", -1, MATCHER_LE },
+ { "attribute.foo = 123", -1, MATCHER_EQ },
+ { "attribute.foo >= 123", -1, MATCHER_GE },
+ { "attribute.foo > 123", -1, MATCHER_GT },
+ /* NULL; while this is an implementation detail,
+ * IS NULL currently maps to an equality matcher */
+ { "attribute.foo IS NULL", -1, MATCHER_ISNULL },
+ { "attribute.foo IS NOT NULL", -1, MATCHER_NOT },
/* check operator precedence */
{ "host.name = 'name' OR "