--- include/db.h 2013-09-03 14:07:45.000000000 +0300 +++ include/db.h 2013-09-12 13:50:12.448927195 +0300 @@ -498,4 +498,6 @@ void DBget_item_from_db(DB_ITEM *item, DB_ROW row); +DB_ITEM *DBclone_item(DB_ITEM *item); +void DBfree_item(DB_ITEM *item); zbx_uint64_t DBadd_host(char *server, int port, int status, int useip, char *ip, int disable_until, int available); --- src/libs/zbxdbhigh/db.c 2013-09-03 14:07:45.000000000 +0300 +++ src/libs/zbxdbhigh/db.c 2013-09-12 21:39:46.689109302 +0300 @@ -1092,4 +1092,25 @@ } +DB_ITEM *DBclone_item(DB_ITEM *item) +{ + DB_ITEM *new_item; + + new_item = zbx_malloc(NULL, sizeof(*new_item)); + memcpy(new_item, item, sizeof(*new_item)); + new_item->key = zbx_strdup(NULL, item->key); + new_item->host_name = zbx_strdup(NULL, item->host_name); + if (item->units) new_item->units = zbx_strdup(NULL, item->units); + if (item->formula) new_item->formula = zbx_strdup(NULL, item->formula); + return new_item; +} + +void DBfree_item_from_db(DB_ITEM *item) +{ + zbx_free(item->key); + zbx_free(item->host_name); + zbx_free(item->units); + zbx_free(item->formula); +} + const ZBX_TABLE *DBget_table(const char *tablename) { --- src/libs/zbxserver/expression.c 2013-09-03 14:07:45.000000000 +0300 +++ src/libs/zbxserver/expression.c 2013-09-12 21:39:16.518698487 +0300 @@ -146,4 +146,43 @@ } +typedef struct +{ + zbx_uint64_t functionid; + zbx_uint64_t triggerid; + char function[FUNCTION_FUNCTION_LEN_MAX]; + char parameter[FUNCTION_PARAMETER_LEN_MAX]; + zbx_timespec_t timespec; + DB_ITEM *item; + char *value; + char *error; +} +zbx_func_t; + +typedef struct +{ + zbx_uint64_t itemid; + zbx_vector_ptr_t functions; +} +zbx_ifunc_t; + +static zbx_func_t *zbx_get_func_by_functionid(zbx_vector_ptr_t *ifuncs, zbx_uint64_t functionid) +{ + zbx_ifunc_t *ifunc; + int i, j; + + for (i = 0; i < ifuncs->values_num; i++) + { + ifunc = (zbx_ifunc_t *)ifuncs->values[i]; + + if (FAIL != (j = zbx_vector_ptr_bsearch(&ifunc->functions, &functionid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + return (zbx_func_t *)ifunc->functions.values[j]; + } + } + + return NULL; +} + /****************************************************************************** * * @@ -163,8 +202,7 @@ * * ******************************************************************************/ -static int evaluate_simple(double *result, char *expression, char *error, int maxerrlen) +static int evaluate_simple(double *result, char *expression, zbx_vector_ptr_t *ifuncs, char *error, int maxerrlen) { - double value1, value2; - char *p, c; + char *p; zbx_lrtrim(expression, " "); @@ -173,18 +211,4 @@ compress_signs(expression); - /* we should process negative prefix, i.e. N123 == -123 */ - if ('N' == *expression && SUCCEED == is_double_suffix(expression + 1)) - { - /* str2double supports suffixes */ - *result = -str2double(expression + 1); - return SUCCEED; - } - else if ('N' != *expression && SUCCEED == is_double_suffix(expression)) - { - /* str2double supports suffixes */ - *result = str2double(expression); - return SUCCEED; - } - /* operators with lowest priority come first */ /* HIGHEST / * - + < > # = & | LOWEST */ @@ -195,63 +219,158 @@ NULL != (p = strchr(expression, '*')) || NULL != (p = strrchr(expression, '/'))) { - c = *p; + double value1, value2; + int ret; + char c = *p; + *p = '\0'; + ret = evaluate_simple(&value1, expression, ifuncs, error, maxerrlen); + *p = c; + if ('&' == c || '|' == c) + { /* special case: "true | undef" is "true", "false | undef" is "false" */ + if (SUCCEED == ret) + { + if ('|' == c && SUCCEED != cmp_double(value1, 0)) + { + *result = -1; /* true */ + return SUCCEED; + } + if ('&' == c && SUCCEED == cmp_double(value1, 0)) + { + *result = 0; /* false */ + return SUCCEED; + } + } + else + { + if (SUCCEED != evaluate_simple(&value2, p + 1, ifuncs, error, maxerrlen)) + return FAIL; + if ('|' == c && SUCCEED != cmp_double(value2, 0)) + { + *result = -1; /* true */ + return SUCCEED; + } + if ('&' == c && SUCCEED == cmp_double(value2, 0)) + { + *result = 0; /* false */ + return SUCCEED; + } + } + } + else if (SUCCEED != ret) + return FAIL; - if (SUCCEED != evaluate_simple(&value1, expression, error, maxerrlen) || - SUCCEED != evaluate_simple(&value2, p + 1, error, maxerrlen)) - { - *p = c; + if (SUCCEED != evaluate_simple(&value2, p + 1, ifuncs, error, maxerrlen)) return FAIL; - } + switch (c) + { + case '|': + *result = (SUCCEED != cmp_double(value1, 0) || SUCCEED != cmp_double(value2, 0)); + break; + case '&': + *result = (SUCCEED != cmp_double(value1, 0) && SUCCEED != cmp_double(value2, 0)); + break; + case '=': + *result = (SUCCEED == cmp_double(value1, value2)); + break; + case '#': + *result = (SUCCEED != cmp_double(value1, value2)); + break; + case '>': + *result = (value1 >= value2 + TRIGGER_EPSILON); + break; + case '<': + *result = (value1 <= value2 - TRIGGER_EPSILON); + break; + case '+': + *result = value1 + value2; + break; + case '-': + *result = value1 - value2; + break; + case '*': + *result = value1 * value2; + break; + case '/': + if (SUCCEED == cmp_double(value2, 0)) + { + zbx_snprintf(error, maxerrlen, "Division by zero. Cannot evaluate expression [%s]", expression); + return FAIL; + } - *p = c; + *result = value1 / value2; + break; + } + return SUCCEED; } else { - zbx_snprintf(error, maxerrlen, "Format error or unsupported operator. Exp: [%s]", expression); - return FAIL; - } + /* Atom, number or function reference {123} */ + if ('{' == *expression && NULL != ifuncs) { + zbx_uint64_t functionid; + zbx_func_t *func; - switch (c) - { - case '|': - *result = (SUCCEED != cmp_double(value1, 0) || SUCCEED != cmp_double(value2, 0)); - break; - case '&': - *result = (SUCCEED != cmp_double(value1, 0) && SUCCEED != cmp_double(value2, 0)); - break; - case '=': - *result = (SUCCEED == cmp_double(value1, value2)); - break; - case '#': - *result = (SUCCEED != cmp_double(value1, value2)); - break; - case '>': - *result = (value1 >= value2 + TRIGGER_EPSILON); - break; - case '<': - *result = (value1 <= value2 - TRIGGER_EPSILON); - break; - case '+': - *result = value1 + value2; - break; - case '-': - *result = value1 - value2; - break; - case '*': - *result = value1 * value2; - break; - case '/': - if (SUCCEED == cmp_double(value2, 0)) + p = strchr(expression + 1, '}'); + if (NULL == p || p[1]) + { + zbx_snprintf(error, maxerrlen, "Format error or unsupported operator. Exp: [%s]", exp); + return FAIL; + } + ZBX_STR2UINT64(functionid, expression + 1); + /* evaluate function and substitute result */ + if (NULL == (func = zbx_get_func_by_functionid(ifuncs, functionid))) { - zbx_snprintf(error, maxerrlen, "Division by zero. Cannot evaluate expression [%s]", expression); + zbx_snprintf(error, maxerrlen, "Cannot obtain function" + "and item for functionid: " ZBX_FS_UI64, functionid); return FAIL; } - *result = value1 / value2; - break; - } + if (NULL != func->error) + { + zbx_snprintf(error, maxerrlen, "%s", func->error); + return FAIL; + } - return SUCCEED; + if (NULL == func->value) + { + /* evaluate function */ + char value[MAX_BUFFER_LEN]; + + if (SUCCEED != evaluate_function(value, func->item, func->function, func->parameter, func->timespec.sec)) + { + func->value = zbx_strdup(func->value, "Undef"); + zbx_snprintf(error, maxerrlen, "Undefined function. Exp: [%s]", exp); + return FAIL; + } + else + func->value = zbx_strdup(func->value, value); + } + + *result = str2double(func->value); + return SUCCEED; + + } + + /* we should process negative prefix, i.e. N123 == -123 */ + if ('N' == *expression && SUCCEED == is_double_suffix(expression + 1)) + { + /* str2double supports suffixes */ + *result = -str2double(expression + 1); + return SUCCEED; + } + else if ('N' != *expression && SUCCEED == is_double_suffix(expression)) + { + /* str2double supports suffixes */ + *result = str2double(expression); + return SUCCEED; + } + else if (0 == strcmp("Undef", expression)) + { + zbx_snprintf(error, maxerrlen, "Undefined function. Exp: [%s]", exp); + return FAIL; + } + + zbx_snprintf(error, maxerrlen, "Format error or unsupported operator. Exp: [%s]", expression); + return FAIL; + } } @@ -271,7 +390,7 @@ * * ******************************************************************************/ -int evaluate(double *value, char *expression, char *error, int maxerrlen) +static int zbx_evaluate(double *value, char *expression, zbx_vector_ptr_t *ifuncs, char *error, int maxerrlen) { - const char *__function_name = "evaluate"; + const char *__function_name = "zbx_evaluate"; char *res = NULL, simple[MAX_STRING_LEN], tmp[MAX_STRING_LEN], value_str[MAX_STRING_LEN], c; @@ -307,5 +426,5 @@ simple[r - l - 1] = '\0'; - if (SUCCEED != evaluate_simple(value, simple, error, maxerrlen)) + if (SUCCEED != evaluate_simple(value, simple, ifuncs, error, maxerrlen)) return FAIL; @@ -325,5 +444,5 @@ } - if (SUCCEED != evaluate_simple(value, tmp, error, maxerrlen)) + if (SUCCEED != evaluate_simple(value, tmp, ifuncs, error, maxerrlen)) return FAIL; @@ -333,4 +452,9 @@ } +int evaluate(double *value, char *expression, char *error, int maxerrlen) +{ + return zbx_evaluate(value, expression, NULL, error, maxerrlen); +} + /****************************************************************************** * * @@ -3618,23 +3742,4 @@ } -typedef struct -{ - zbx_uint64_t functionid; - zbx_uint64_t triggerid; - char function[FUNCTION_FUNCTION_LEN_MAX]; - char parameter[FUNCTION_PARAMETER_LEN_MAX]; - zbx_timespec_t timespec; - char *value; - char *error; -} -zbx_func_t; - -typedef struct -{ - zbx_uint64_t itemid; - zbx_vector_ptr_t functions; -} -zbx_ifunc_t; - static void zbx_populate_function_items(zbx_vector_uint64_t *functionids, zbx_vector_ptr_t *ifuncs, zbx_vector_ptr_t *triggers) @@ -3714,12 +3819,12 @@ } -static void zbx_evaluate_item_functions(zbx_vector_ptr_t *ifuncs) +static void zbx_get_items(zbx_vector_ptr_t *ifuncs, zbx_vector_ptr_t *items) { - const char *__function_name = "zbx_evaluate_item_functions"; + const char *__function_name = "zbx_get_items"; DB_RESULT result; DB_ROW row; DB_ITEM item; - char *sql = NULL, value[MAX_BUFFER_LEN]; + char *sql = NULL; size_t sql_alloc = 2 * ZBX_KIBIBYTE, sql_offset = 0; int i; @@ -3754,4 +3859,5 @@ { DBget_item_from_db(&item, row); + zbx_vector_ptr_append(items, DBclone_item(&item)); host_status = (unsigned char)atoi(row[ZBX_SQL_ITEM_FIELDS_NUM]); @@ -3770,4 +3876,6 @@ func = (zbx_func_t *)ifunc->functions.values[i]; + func->item = items->values[items->values_num-1]; + if (ITEM_STATUS_DISABLED == item_status) { @@ -3785,15 +3893,4 @@ item.host_name, item.key, func->function, func->parameter); } - - if (NULL != func->error) - continue; - - if (SUCCEED != evaluate_function(value, &item, func->function, func->parameter, func->timespec.sec)) - { - func->error = zbx_dsprintf(func->error, "Evaluation failed for function: {%s:%s.%s(%s)}", - item.host_name, item.key, func->function, func->parameter); - } - else - func->value = zbx_strdup(func->value, value); } } @@ -3803,21 +3900,13 @@ } -static zbx_func_t *zbx_get_func_by_functionid(zbx_vector_ptr_t *ifuncs, zbx_uint64_t functionid) +static void zbx_free_items(zbx_vector_ptr_t *items) { - zbx_ifunc_t *ifunc; - int i, j; + int i; - for (i = 0; i < ifuncs->values_num; i++) + for (i = 0; i < items->values_num; i++) { - ifunc = (zbx_ifunc_t *)ifuncs->values[i]; - - if (FAIL != (j = zbx_vector_ptr_bsearch(&ifunc->functions, &functionid, - ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) - { - return (zbx_func_t *)ifunc->functions.values[j]; - } + DBfree_item_from_db((DB_ITEM *)items->values[i]); /* free cached historical fields item.h_* */ + zbx_free(items->values[i]); } - - return NULL; } @@ -3999,4 +4088,7 @@ double expr_result; char err[MAX_STRING_LEN]; + zbx_vector_uint64_t functionids; + zbx_vector_ptr_t ifuncs; + zbx_vector_ptr_t items; zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __function_name, triggers->values_num); @@ -4029,5 +4121,11 @@ } - substitute_functions(triggers); + if (0 != functionids.values_num) + { + zbx_vector_ptr_create(&ifuncs); + zbx_vector_ptr_create(&items); + zbx_populate_function_items(&functionids, &ifuncs, triggers); + zbx_get_items(&ifuncs, &items); + } for (i = 0; i < triggers->values_num; i++) @@ -4038,5 +4136,5 @@ continue; - if (SUCCEED != evaluate(&expr_result, tr->expression, err, sizeof(err))) + if (SUCCEED != zbx_evaluate(&expr_result, tr->expression, &ifuncs, err, sizeof(err))) { tr->new_error = zbx_strdup(tr->new_error, err); @@ -4064,4 +4162,13 @@ } + if (0 != functionids.values_num) + { + zbx_free_items(&items); + zbx_vector_ptr_destroy(&items); + zbx_free_item_functions(&ifuncs); + zbx_vector_ptr_destroy(&ifuncs); + } + zbx_vector_uint64_destroy(&functionids); + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }