diff options
author | Andris Zeila <andris.zeila@zabbix.com> | 2021-01-27 01:50:34 +0300 |
---|---|---|
committer | Andris Zeila <andris.zeila@zabbix.com> | 2021-01-27 01:55:43 +0300 |
commit | ffc0868ad96ffef7cbe1156c25f65d36388a6bfe (patch) | |
tree | b03857921b67494a119b65a60b95e6a7ea66a0bc | |
parent | 477f6cf0ec943b422d571b256d4fb45160bb7744 (diff) |
........S. [ZBXNEXT-6451] updated trigger expression processing to use new expression syntax
(trigger recalculation, macro resolving, etc - all places that parsed
trigger expression to extract functionids).
29 files changed, 1825 insertions, 1230 deletions
diff --git a/include/common.h b/include/common.h index a501e46711d..13beaf1acd8 100644 --- a/include/common.h +++ b/include/common.h @@ -1684,6 +1684,6 @@ int zbx_open_xml(char *data, int options, int maxerrlen, void **xml_doc, void ** int zbx_check_xml_memory(char *mem, int maxerrlen, char **errmsg); #endif -char *zbx_strloc_unquote_dyn(const char *src, const zbx_strloc_t *loc); +char *zbx_strloc_get(const char *src, const zbx_strloc_t *loc); #endif diff --git a/include/db.h b/include/db.h index fbdd8006e84..f9d469b3826 100644 --- a/include/db.h +++ b/include/db.h @@ -24,6 +24,7 @@ #include "zbxalgo.h" #include "zbxdb.h" #include "dbschema.h" +#include "zbxeval.h" extern char *CONFIG_DBHOST; extern char *CONFIG_DBNAME; @@ -307,6 +308,11 @@ typedef struct } DB_DSERVICE; +#define ZBX_DB_TRIGGER_EVAL_NONE 0x0000 +#define ZBX_DB_TRIGGER_EVAL_EXPRESSION 0x0001 +#define ZBX_DB_TRIGGER_EVAL_EXPRESSION_USERMACRO 0x0002 +#define ZBX_DB_TRIGGER_EVAL_RECOVERY_EXPRESSION 0x0004 + typedef struct { zbx_uint64_t triggerid; @@ -323,6 +329,9 @@ typedef struct unsigned char type; unsigned char recovery_mode; unsigned char correlation_mode; + + /* temporary trigger cache for related data */ + void *cache; } DB_TRIGGER; @@ -871,6 +880,11 @@ void zbx_lld_override_operation_free(zbx_lld_override_operation_t *override_oper void zbx_load_lld_override_operations(const zbx_vector_uint64_t *overrideids, char **sql, size_t *sql_alloc, zbx_vector_ptr_t *ops); - +void zbx_db_trigger_get_all_functionids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *functionids); +void zbx_db_trigger_get_functionids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *functionids); +int zbx_db_trigger_get_all_hostids(const DB_TRIGGER *trigger, const zbx_vector_uint64_t **hostids); +int zbx_db_trigger_get_constant(const DB_TRIGGER *trigger, int index, char **out); +int zbx_db_trigger_get_itemid(const DB_TRIGGER *trigger, int index, zbx_uint64_t *itemid); +void zbx_db_trigger_get_itemids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *itemids); #endif diff --git a/include/dbcache.h b/include/dbcache.h index e9c07adf576..b67930b2487 100644 --- a/include/dbcache.h +++ b/include/dbcache.h @@ -230,9 +230,6 @@ typedef struct _DC_TRIGGER { zbx_uint64_t triggerid; char *description; - char *expression_orig; - char *recovery_expression_orig; - /* temporary values, allocated during processing and freed right after */ char *expression; char *recovery_expression; @@ -750,7 +747,6 @@ void DCget_autoregistration_psk(char *psk_identity_buf, size_t psk_identity_buf_ #define ZBX_MACRO_SECRET_MASK "******" void DCget_user_macro(const zbx_uint64_t *hostids, int hostids_num, const char *macro, char **replace_to); -char *DCexpression_expand_user_macros(const char *expression); char *zbx_dc_expand_func_params_user_macros(zbx_uint64_t hostid, const char *params); int DCinterface_activate(zbx_uint64_t interfaceid, const zbx_timespec_t *ts, zbx_agent_availability_t *in, @@ -990,10 +986,10 @@ typedef struct { zbx_uint64_t objectid; zbx_uint64_t triggerid; - zbx_function_type_t type; + zbx_uint32_t type; zbx_time_unit_t trend_base; unsigned char lock; /* 1 if the timer has locked trigger, 0 otherwise */ - int revision; /* function revision */ + int revision; /* revision */ zbx_timespec_t eval_ts; /* the history time for which trigger must be recalculated */ zbx_timespec_t exec_ts; /* real time when the timer must be executed */ const char *parameter; /* function parameters (for trend functions) */ @@ -1012,4 +1008,6 @@ void zbx_db_trigger_queue_unlock(void); void zbx_get_host_interfaces_availability(zbx_uint64_t hostid, zbx_agent_availability_t *agents); +void zbx_dc_eval_expand_user_macros(zbx_eval_context_t *ctx); + #endif diff --git a/include/zbxeval.h b/include/zbxeval.h index c9482108acd..1ff895c8cc9 100644 --- a/include/zbxeval.h +++ b/include/zbxeval.h @@ -107,6 +107,7 @@ #define ZBX_EVAL_TRIGGER_EXPRESSION (ZBX_EVAL_PARSE_TRIGGER_EXPRESSSION | \ ZBX_EVAL_COMPOSE_TRIGGER_EXPRESSION | \ + ZBX_EVAL_PARSE_CONST_INDEX | \ ZBX_EVAL_PROCESS_ERROR) typedef zbx_uint32_t zbx_token_type_t; @@ -160,6 +161,7 @@ typedef char *(*zbx_macro_resolve_func_t)(const char *str, size_t length, zbx_ui int hostids_num); int zbx_eval_parse_expression(zbx_eval_context_t *ctx, const char *expression, zbx_uint64_t rules, char **error); +zbx_eval_context_t *zbx_eval_parse_expression_dyn(const char *expression, zbx_uint64_t rules, char **error); void zbx_eval_clear(zbx_eval_context_t *ctx); size_t zbx_eval_serialize(const zbx_eval_context_t *ctx, zbx_mem_malloc_func_t malloc_func, unsigned char **data); void zbx_eval_deserialize(zbx_eval_context_t *ctx, const char *expression, zbx_uint64_t rules, @@ -168,9 +170,23 @@ void zbx_eval_compose_expression(const zbx_eval_context_t *ctx, char **expressio int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_variant_t *value, char **error); int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t function_cb, zbx_variant_t *value, char **error); -void zbx_eval_get_functionids(const zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids); +void zbx_eval_get_functionids(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids); +void zbx_eval_get_functionids_ordered(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids); void zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *hostids, int hostids_num, zbx_macro_resolve_func_t resolver_cb); void zbx_eval_set_exception(zbx_eval_context_t *ctx, char *message); +#define ZBX_EVAL_EXTRACT_FUNCTIONID 0x0001 +#define ZBX_EVAL_EXTRACT_VAR_STR 0x0002 +#define ZBX_EVAL_EXTRACT_VAR_MACRO 0x0004 + +#define ZBX_EVAL_EXCTRACT_ALL (ZBX_EVAL_EXTRACT_FUNCTIONID | ZBX_EVAL_EXTRACT_VAR_STR | ZBX_EVAL_EXTRACT_VAR_MACRO) + +zbx_eval_context_t *zbx_eval_deserialize_dyn(const unsigned char *data, const char *expression, + zbx_uint64_t mask); +int zbx_eval_check_timer_functions(const zbx_eval_context_t *ctx); +void zbx_get_serialized_expression_functionids(const char *expression, const unsigned char *data, + zbx_vector_uint64_t *functionids); +void zbx_eval_get_constant(const zbx_eval_context_t *ctx, int index, char **value); + #endif diff --git a/include/zbxserver.h b/include/zbxserver.h index 29999ee4490..da0778313cf 100644 --- a/include/zbxserver.h +++ b/include/zbxserver.h @@ -74,6 +74,7 @@ int substitute_simple_macros_unmasked(zbx_uint64_t *actionid, const DB_EVENT *ev int maxerrlen); void evaluate_expressions(zbx_vector_ptr_t *triggers); +void prepare_triggers(DC_TRIGGER **triggers, int triggers_num); void zbx_format_value(char *value, size_t max_len, zbx_uint64_t valuemapid, const char *units, unsigned char value_type); diff --git a/src/libs/zbxcommon/misc.c b/src/libs/zbxcommon/misc.c index 29288fe0d24..2f8f29ebc9a 100644 --- a/src/libs/zbxcommon/misc.c +++ b/src/libs/zbxcommon/misc.c @@ -3569,7 +3569,7 @@ zbx_function_type_t zbx_get_function_type(const char *func) if (0 == strncmp(func, "trend", 5)) return ZBX_FUNCTION_TYPE_TRENDS; - if (SUCCEED == str_in_list("nodata,date,dayofmonth,dayofweek,time,now", func, ',')) + if (0 == strcmp(func, "nodata")) return ZBX_FUNCTION_TYPE_TIMER; return ZBX_FUNCTION_TYPE_HISTORY; diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c index a88f16a33c7..aa5aeea7bf0 100644 --- a/src/libs/zbxcommon/str.c +++ b/src/libs/zbxcommon/str.c @@ -4296,7 +4296,7 @@ int zbx_token_find(const char *expression, int pos, zbx_token_t *token, zbx_toke for (; '{' != *ptr || 0 != quoted; ptr++) { if ('\0' == *ptr) - return FAIL; + break; if (0 != (token_search & ZBX_TOKEN_SEARCH_FUNCTIONID)) { @@ -4337,7 +4337,7 @@ int zbx_token_find(const char *expression, int pos, zbx_token_t *token, zbx_toke token_search &= ~ZBX_TOKEN_SEARCH_REFERENCES; } - if (NULL == ptr) + if (NULL == ptr || '\0' == *ptr) return FAIL; if ('\0' == ptr[1]) @@ -6097,7 +6097,7 @@ const char *zbx_print_double(char *buffer, size_t size, double val) /****************************************************************************** * * - * Function: zbx_strloc_unquote_dyn * + * Function: zbx_strloc_unquote * * * * Purpose: unquotes substring at the specified location * * * @@ -6107,34 +6107,41 @@ const char *zbx_print_double(char *buffer, size_t size, double val) * Return value: The unquoted and copied substring. * * * ******************************************************************************/ -char *zbx_strloc_unquote_dyn(const char *src, const zbx_strloc_t *loc) +char *zbx_strloc_get(const char *src, const zbx_strloc_t *loc) { - char *str, *ptr; - - src += loc->l + 1; + char *str, *ptr; - str = ptr = zbx_malloc(NULL, loc->r - loc->l); - - while ('"' != *src) + if ('"' == src[loc->l]) { - if ('\\' == *src) + src += loc->l + 1; + str = ptr = zbx_malloc(NULL, loc->r - loc->l); + + while ('"' != *src) { - switch (*(++src)) + if ('\\' == *src) { - case '\\': - *ptr++ = '\\'; - break; - case '"': - *ptr++ = '"'; - break; + switch (*(++src)) + { + case '\\': + *ptr++ = '\\'; + break; + case '"': + *ptr++ = '"'; + break; + } } + else + *ptr++ = *src; + src++; } - else - *ptr++ = *src; - src++; + *ptr = '\0'; + } + else + { + str = zbx_malloc(NULL, loc->r - loc->l + 2); + memcpy(str, src + loc->l, loc->r - loc->l + 1); + str[loc->r - loc->l + 1] = '\0'; } - *ptr = '\0'; return str; } - diff --git a/src/libs/zbxdbcache/dbcache.c b/src/libs/zbxdbcache/dbcache.c index db6889b4089..882d3c364fd 100644 --- a/src/libs/zbxdbcache/dbcache.c +++ b/src/libs/zbxdbcache/dbcache.c @@ -1603,12 +1603,23 @@ static void recalculate_triggers(const ZBX_DC_HISTORY *history, int history_num, if (0 != item_num) { DCconfig_get_triggers_by_itemids(&trigger_info, &trigger_order, itemids, timespecs, item_num); + prepare_triggers((DC_TRIGGER **)trigger_order.values, trigger_order.values_num); zbx_determine_items_in_expressions(&trigger_order, itemids, item_num); } if (0 != timers_num) + { + int offset = trigger_order.values_num; + zbx_dc_get_triggers_by_timers(&trigger_info, &trigger_order, timers); + if (offset != trigger_order.values_num) + { + prepare_triggers((DC_TRIGGER **)trigger_order.values + offset, + trigger_order.values_num - offset); + } + } + zbx_vector_ptr_sort(&trigger_order, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); evaluate_expressions(&trigger_order); zbx_process_triggers(&trigger_order, trigger_diff); diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c index 9b90a3e822e..64b074dae0e 100644 --- a/src/libs/zbxdbcache/dbconfig.c +++ b/src/libs/zbxdbcache/dbconfig.c @@ -3597,7 +3597,6 @@ static unsigned char *dup_serialized_expression(const unsigned char *src) return NULL; offset = zbx_deserialize_uint31_compact(src, &len); - zabbix_log(LOG_LEVEL_DEBUG, "[WDN] dup: offset:%d len:%d", offset, len); if (0 == len) return NULL; @@ -3681,6 +3680,8 @@ static void DCsync_triggers(zbx_dbsync_t *sync) trigger->expression_bin = config_decode_serialized_expression(row[16]); trigger->recovery_expression_bin = config_decode_serialized_expression(row[17]); + trigger->timer = atoi(row[18]); + trigger->revision = config->sync_start_ts; } /* remove deleted triggers from buffer */ @@ -3700,10 +3701,14 @@ static void DCsync_triggers(zbx_dbsync_t *sync) /* force trigger list update for items used in removed trigger */ - get_functionids(&functionids, trigger->expression); + zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin, + &functionids); if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode) - get_functionids(&functionids, trigger->recovery_expression); + { + zbx_get_serialized_expression_functionids(trigger->recovery_expression, + trigger->recovery_expression_bin, &functionids); + } for (i = 0; i < functionids.values_num; i++) { @@ -3904,7 +3909,7 @@ static int dc_function_calculate_trends_nextcheck(time_t from, const char *perio static int dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, time_t from, zbx_uint64_t seed) { - if (ZBX_FUNCTION_TYPE_TIMER == timer->type) + if (ZBX_TRIGGER_TIMER_FUNCTION_TIME == timer->type || ZBX_TRIGGER_TIMER_TRIGGER == timer->type) { int nextcheck; @@ -3916,7 +3921,7 @@ static int dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, tim return nextcheck; } - else if (ZBX_FUNCTION_TYPE_TRENDS == timer->type) + else if (ZBX_TRIGGER_TIMER_FUNCTION_TREND == timer->type) { struct tm tm; time_t nextcheck; @@ -3942,15 +3947,17 @@ static int dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, tim } else { - int ret; + int ret = FAIL; char *error = NULL, *period_shift; - period_shift = zbx_function_get_param_dyn(timer->parameter, 2); - - ret = dc_function_calculate_trends_nextcheck(from, period_shift, timer->trend_base, &nextcheck, - &error); - - zbx_free(period_shift); + if (NULL != (period_shift = strchr(timer->parameter, ':'))) + { + period_shift++; + ret = dc_function_calculate_trends_nextcheck(from, period_shift, timer->trend_base, + &nextcheck, &error); + } + else + error = zbx_dsprintf(NULL, "invalid first parameter"); if (FAIL == ret) { @@ -3972,21 +3979,22 @@ static int dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, tim /****************************************************************************** * * - * Function: dc_trigger_timer_create * + * Function: dc_trigger_function_timer_create * * * - * Purpose: create trigger timer based on the specified function * + * Purpose: create trigger timer based on the trend function * * * * Return value: Created timer or NULL in the case of error. * * * ******************************************************************************/ -static zbx_trigger_timer_t *dc_trigger_timer_create(ZBX_DC_FUNCTION *function) +static zbx_trigger_timer_t *dc_trigger_function_timer_create(ZBX_DC_FUNCTION *function) { zbx_trigger_timer_t *timer; zbx_time_unit_t trend_base; + zbx_uint32_t type; if (ZBX_FUNCTION_TYPE_TRENDS == function->type) { - char *error = NULL; + char *error = NULL; if (FAIL == zbx_trends_parse_base(function->parameter, &trend_base, &error)) { @@ -3995,17 +4003,22 @@ static zbx_trigger_timer_t *dc_trigger_timer_create(ZBX_DC_FUNCTION *function) zbx_free(error); return NULL; } + type = ZBX_TRIGGER_TIMER_FUNCTION_TREND; } else + { trend_base = ZBX_TIME_UNIT_UNKNOWN; + type = ZBX_TRIGGER_TIMER_FUNCTION_TIME; + } timer = (zbx_trigger_timer_t *)__config_mem_malloc_func(NULL, sizeof(zbx_trigger_timer_t)); - timer->type = function->type; + timer->objectid = function->functionid; timer->triggerid = function->triggerid; timer->revision = function->revision; timer->trend_base = trend_base; timer->lock = 0; + timer->type = type; function->timer_revision = function->revision; @@ -4017,6 +4030,32 @@ static zbx_trigger_timer_t *dc_trigger_timer_create(ZBX_DC_FUNCTION *function) return timer; } +/****************************************************************************** + * * + * Function: dc_trigger_timer_create * + * * + * Purpose: create trigger timer based on the specified trigger * + * * + * Return value: Created timer or NULL in the case of error. * + * * + ******************************************************************************/ +static zbx_trigger_timer_t *dc_trigger_timer_create(ZBX_DC_TRIGGER *trigger) +{ + zbx_trigger_timer_t *timer; + + timer = (zbx_trigger_timer_t *)__config_mem_malloc_func(NULL, sizeof(zbx_trigger_timer_t)); + timer->type = ZBX_TRIGGER_TIMER_TRIGGER; + timer->objectid = trigger->triggerid; + timer->triggerid = trigger->triggerid; + timer->revision = trigger->revision; + timer->trend_base = ZBX_TIME_UNIT_UNKNOWN; + timer->lock = 0; + timer->parameter = NULL; + + trigger->timer_revision = trigger->revision; + + return timer; +} /****************************************************************************** * * @@ -4095,7 +4134,7 @@ static void dc_schedule_trigger_timers(zbx_hashset_t *trend_queue, int now) if (TRIGGER_STATUS_ENABLED != trigger->status || TRIGGER_FUNCTIONAL_TRUE != trigger->functional) continue; - if (NULL == (timer = dc_trigger_timer_create(function))) + if (NULL == (timer = dc_trigger_function_timer_create(function))) continue; if (NULL != trend_queue && NULL != (old = (zbx_trigger_timer_t *)zbx_hashset_search(trend_queue, @@ -4121,6 +4160,25 @@ static void dc_schedule_trigger_timers(zbx_hashset_t *trend_queue, int now) dc_schedule_trigger_timer(timer, NULL, &ts); } } + + zbx_hashset_iter_reset(&config->triggers, &iter); + while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter))) + { + if (ZBX_TRIGGER_TIMER_DEFAULT == trigger->timer) + continue; + + if (NULL == (timer = dc_trigger_timer_create(trigger))) + continue; + + if (0 == (ts.sec = dc_function_calculate_nextcheck(timer, now, timer->triggerid))) + { + dc_trigger_timer_free(timer); + trigger->timer_revision = 0; + } + else + dc_schedule_trigger_timer(timer, NULL, &ts); + + } } static void DCsync_functions(zbx_dbsync_t *sync) @@ -7754,8 +7812,6 @@ static void DCget_trigger(DC_TRIGGER *dst_trigger, const ZBX_DC_TRIGGER *src_tri dst_trigger->triggerid = src_trigger->triggerid; dst_trigger->description = zbx_strdup(NULL, src_trigger->description); - dst_trigger->expression_orig = zbx_strdup(NULL, src_trigger->expression); - dst_trigger->recovery_expression_orig = zbx_strdup(NULL, src_trigger->recovery_expression); dst_trigger->error = zbx_strdup(NULL, src_trigger->error); dst_trigger->timespec.sec = 0; dst_trigger->timespec.ns = 0; @@ -7825,8 +7881,6 @@ static void DCclean_trigger(DC_TRIGGER *trigger) { zbx_free(trigger->new_error); zbx_free(trigger->error); - zbx_free(trigger->expression_orig); - zbx_free(trigger->recovery_expression_orig); zbx_free(trigger->expression); zbx_free(trigger->recovery_expression); zbx_free(trigger->description); @@ -7838,6 +7892,19 @@ static void DCclean_trigger(DC_TRIGGER *trigger) zbx_vector_ptr_clear_ext(&trigger->tags, (zbx_clean_func_t)zbx_free_tag); zbx_vector_ptr_destroy(&trigger->tags); + + if (NULL != trigger->eval_ctx) + { + zbx_eval_clear(trigger->eval_ctx); + zbx_free(trigger->eval_ctx); + } + + if (NULL != trigger->eval_ctx_r) + { + zbx_eval_clear(trigger->eval_ctx_r); + zbx_free(trigger->eval_ctx_r); + } + } /****************************************************************************** @@ -8439,22 +8506,35 @@ void DCconfig_get_triggers_by_itemids(zbx_hashset_t *trigger_info, zbx_vector_pt * * * Function: DCconfig_find_active_time_function * * * - * Purpose: checks if the expression contains time based functions * + * Purpose: check if the expression contains time based functions * + * * + * Parameters: expression - [IN] the original expression * + * data - [IN] the parsed and serialized expression * + * trigger_timer - [IN] the trigger time function flags * * * ******************************************************************************/ -static int DCconfig_find_active_time_function(const char *expression) +static int DCconfig_find_active_time_function(const char *expression, const unsigned char *data, + unsigned char trigger_timer) { - zbx_uint64_t functionid; + int i, ret = SUCCEED; const ZBX_DC_FUNCTION *dc_function; const ZBX_DC_HOST *dc_host; const ZBX_DC_ITEM *dc_item; + zbx_vector_uint64_t functionids; + + zbx_vector_uint64_create(&functionids); + zbx_get_serialized_expression_functionids(expression, data, &functionids); - while (SUCCEED == get_N_functionid(expression, 1, &functionid, &expression)) + for (i = 0; i < functionids.values_num; i++) { - if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid))) + if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, + &functionids.values[i]))) + { continue; + } - if (ZBX_FUNCTION_TYPE_TIMER == dc_function->type || ZBX_FUNCTION_TYPE_TRENDS == dc_function->type) + if (ZBX_TRIGGER_TIMER_DEFAULT != trigger_timer || ZBX_FUNCTION_TYPE_TRENDS == dc_function->type || + ZBX_FUNCTION_TYPE_TIMER == dc_function->type) { if (NULL == (dc_item = zbx_hashset_search(&config->items, &dc_function->itemid))) continue; @@ -8463,11 +8543,15 @@ static int DCconfig_find_active_time_function(const char *expression) continue; if (SUCCEED != DCin_maintenance_without_data_collection(dc_host, dc_item)) - return SUCCEED; + goto out; } } - return FAIL; + ret = FAIL; +out: + zbx_vector_uint64_destroy(&functionids); + + return ret; } /****************************************************************************** @@ -8502,7 +8586,8 @@ void zbx_dc_get_triggers_by_timers(zbx_hashset_t *trigger_info, zbx_vector_ptr_t DC_TRIGGER *trigger, trigger_local; unsigned char flags; - if (SUCCEED == DCconfig_find_active_time_function(dc_trigger->expression)) + if (SUCCEED == DCconfig_find_active_time_function(dc_trigger->expression, + dc_trigger->expression_bin, dc_trigger->timer & ZBX_TRIGGER_TIMER_EXPRESSION)) { flags = ZBX_DC_TRIGGER_PROBLEM_EXPRESSION; } @@ -8514,8 +8599,12 @@ void zbx_dc_get_triggers_by_timers(zbx_hashset_t *trigger_info, zbx_vector_ptr_t if (TRIGGER_VALUE_PROBLEM != dc_trigger->value) continue; - if (SUCCEED != DCconfig_find_active_time_function(dc_trigger->recovery_expression)) + if (SUCCEED != DCconfig_find_active_time_function(dc_trigger->recovery_expression, + dc_trigger->recovery_expression_bin, + dc_trigger->timer & ZBX_TRIGGER_TIMER_RECOVERY_EXPRESSION)) + { continue; + } flags = 0; } @@ -8536,6 +8625,58 @@ void zbx_dc_get_triggers_by_timers(zbx_hashset_t *trigger_info, zbx_vector_ptr_t /****************************************************************************** * * + * Function: trigger_timer_validate * + * * + * Purpose: validate trigger timer * + * * + * Parameters: timer - [IN] trigger timer * + * dc_trigger - [OUT] the trigger data * + * * + * Return value: SUCCEED - the timer is valid * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int trigger_timer_validate(zbx_trigger_timer_t *timer, ZBX_DC_TRIGGER **dc_trigger) +{ + ZBX_DC_FUNCTION *dc_function; + + *dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &timer->triggerid); + + if (0 != (timer->type & ZBX_TRIGGER_TIMER_FUNCTION)) + { + if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &timer->objectid))) + return FAIL; + + if (dc_function->revision > timer->revision || + NULL == *dc_trigger || + TRIGGER_STATUS_ENABLED != (*dc_trigger)->status || + TRIGGER_FUNCTIONAL_TRUE != (*dc_trigger)->functional) + { + if (dc_function->timer_revision == timer->revision) + dc_function->timer_revision = 0; + return FAIL; + } + } + else + { + if (NULL == dc_trigger) + return FAIL; + + if ((*dc_trigger)->revision > timer->revision || + TRIGGER_STATUS_ENABLED != (*dc_trigger)->status || + TRIGGER_FUNCTIONAL_TRUE != (*dc_trigger)->functional) + { + if ((*dc_trigger)->timer_revision == timer->revision) + (*dc_trigger)->timer_revision = 0; + return FAIL; + } + } + + return SUCCEED; +} + +/****************************************************************************** + * * * Function: zbx_dc_get_trigger_timers * * * * Purpose: gets timers from trigger queue * @@ -8565,7 +8706,6 @@ void zbx_dc_get_trigger_timers(zbx_vector_ptr_t *timers, int now, int soft_limit zbx_binary_heap_elem_t *elem; zbx_trigger_timer_t *timer; ZBX_DC_TRIGGER *dc_trigger; - ZBX_DC_FUNCTION *dc_function; elem = zbx_binary_heap_find_min(&config->trigger_queue); timer = (zbx_trigger_timer_t *)elem->data; @@ -8588,17 +8728,8 @@ void zbx_dc_get_trigger_timers(zbx_vector_ptr_t *timers, int now, int soft_limit zbx_binary_heap_remove_min(&config->trigger_queue); - /* check if function exists and trigger should be calculated */ - if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &timer->objectid)) || - dc_function->revision > timer->revision || - NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, - &timer->triggerid)) || - TRIGGER_STATUS_ENABLED != dc_trigger->status || - TRIGGER_FUNCTIONAL_TRUE != dc_trigger->functional) + if (SUCCEED != trigger_timer_validate(timer, &dc_trigger)) { - if (NULL != dc_function && dc_function->revision == timer->revision) - dc_function->timer_revision = 0; - dc_trigger_timer_free(timer); continue; } @@ -8612,7 +8743,7 @@ void zbx_dc_get_trigger_timers(zbx_vector_ptr_t *timers, int now, int soft_limit /* 1) time functions uses current time, so trigger evaluation time does not affect their results */ /* 2) trend function of the same trigger with the same evaluation timestamp is being */ /* evaluated by the same process */ - if (0 == dc_trigger->locked || ZBX_FUNCTION_TYPE_TRENDS != timer->type || + if (0 == dc_trigger->locked || ZBX_TRIGGER_TIMER_FUNCTION_TREND != timer->type || (NULL != first_timer && 1 == first_timer->lock)) { /* resetting execution timer will cause a new execution time to be set */ @@ -8653,12 +8784,25 @@ static void dc_reschedule_trigger_timers(zbx_vector_ptr_t *timers) /* schedule calculation error can result in 0 execution time */ if (0 == timer->exec_ts.sec) { - ZBX_DC_FUNCTION *function; + if (0 != (timer->type & ZBX_TRIGGER_TIMER_FUNCTION)) + { + ZBX_DC_FUNCTION *function; - if (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, - &timer->objectid)) && function->timer_revision == timer->revision) + if (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, + &timer->objectid)) && function->timer_revision == timer->revision) + { + function->timer_revision = 0; + } + } + else if (ZBX_TRIGGER_TIMER_TRIGGER == timer->type) { - function->timer_revision = 0; + ZBX_DC_TRIGGER *trigger; + + if (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, + &timer->objectid)) && trigger->timer_revision == timer->revision) + { + trigger->timer_revision = 0; + } } dc_trigger_timer_free(timer); } @@ -8718,7 +8862,7 @@ void zbx_dc_clear_timer_queue(zbx_vector_ptr_t *timers) { zbx_trigger_timer_t *timer = (zbx_trigger_timer_t *)config->trigger_queue.elems[i].data; - if (ZBX_FUNCTION_TYPE_TRENDS == timer->type && + if (ZBX_TRIGGER_TIMER_FUNCTION_TREND == timer->type && NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &timer->objectid)) && function->timer_revision == timer->revision) @@ -10697,9 +10841,9 @@ out: char *dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num) { zbx_token_t token; - int pos = 0, len, last_pos = 0; + int len; char *str = NULL, *name = NULL, *context = NULL, *value = NULL; - size_t str_alloc = 0, str_offset = 0; + size_t str_alloc = 0, str_offset = 0, pos = 0, last_pos = 0; if ('\0' == *text) return zbx_strdup(NULL, text); @@ -10712,7 +10856,9 @@ char *dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t if (SUCCEED != zbx_user_macro_parse_dyn(text + token.loc.l, &name, &context, &len, NULL)) continue; - zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos); + if (last_pos < token.loc.l) + zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos); + dc_get_user_macro(hostids, hostids_num, name, context, &value); if (NULL != value) @@ -10733,7 +10879,8 @@ char *dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t last_pos = pos + 1; } - zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, text_len - last_pos); + if (last_pos < text_len) + zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, text_len - last_pos); return str; } @@ -10943,75 +11090,6 @@ char *dc_expand_user_macros_in_expression(const char *text, zbx_uint64_t *hostid /****************************************************************************** * * - * Function: dc_expression_expand_user_macros * - * * - * Purpose: expand user macros in trigger expression * - * * - * Parameters: expression - [IN] the expression to expand * - * error - [OUT] the error message * - * * - * Return value: The expanded expression or NULL in the case of error. * - * If NULL is returned the error message is set. * - * * - * Comments: The returned expression must be freed by the caller. * - * * - ******************************************************************************/ -static char *dc_expression_expand_user_macros(const char *expression) -{ - zbx_vector_uint64_t functionids, hostids; - char *out; - - zbx_vector_uint64_create(&functionids); - zbx_vector_uint64_create(&hostids); - - get_functionids(&functionids, expression); - dc_get_hostids_by_functionids(functionids.values, functionids.values_num, &hostids); - - out = dc_expand_user_macros_in_expression(expression, hostids.values, hostids.values_num); - - if (NULL != strstr(out, "{$")) - { - zabbix_log(LOG_LEVEL_DEBUG, "cannot evaluate expression: invalid macro value"); - zbx_free(out); - } - - zbx_vector_uint64_destroy(&hostids); - zbx_vector_uint64_destroy(&functionids); - - return out; -} - -/****************************************************************************** - * * - * Function: DCexpression_expand_user_macros * - * * - * Purpose: expand user macros in trigger expression * - * * - * Parameters: expression - [IN] the expression to expand * - * * - * Return value: The expanded expression or NULL in the case of error. * - * If NULL is returned the error message is set. * - * * - * Comments: The returned expression must be freed by the caller. * - * This function is a locking wrapper of * - * dc_expression_expand_user_macros() function for external usage. * - * * - ******************************************************************************/ -char *DCexpression_expand_user_macros(const char *expression) -{ - char *expression_ex; - - RDLOCK_CACHE; - - expression_ex = dc_expression_expand_user_macros(expression); - - UNLOCK_CACHE; - - return expression_ex; -} - -/****************************************************************************** - * * * Function: DCfree_item_queue * * * * Purpose: frees the item queue data vector created by DCget_item_queue() * @@ -11126,59 +11204,52 @@ int DCget_item_queue(zbx_vector_ptr_t *queue, int from, int to) * Function: dc_trigger_items_hosts_enabled * * * * Purpose: check that functionids in trigger (recovery) expression * - * correspond to enabled items and hosts * * * * Parameters: expression - [IN] trigger (recovery) expression * + * data - [IN] parsed and serialized expression * * * * Return value: SUCCEED - all functionids correspond to enabled items and * * enabled hosts * * FAIL - at least one item or host is disabled * * * ******************************************************************************/ -static int dc_trigger_items_hosts_enabled(const char *expression) +static int dc_trigger_items_hosts_enabled(const char *expression, const unsigned char *data) { zbx_uint64_t functionid; const ZBX_DC_ITEM *dc_item; const ZBX_DC_FUNCTION *dc_function; const ZBX_DC_HOST *dc_host; - const char *p, *q; - - for (p = expression; '\0' != *p; p++) - { - if ('{' != *p) - continue; + int i, ret = FAIL; + zbx_vector_uint64_t functionids; - if ('$' == p[1]) - { - int macro_r, context_l, context_r; + zbx_vector_uint64_create(&functionids); + zbx_get_serialized_expression_functionids(expression, data, &functionids); - if (SUCCEED == zbx_user_macro_parse(p, ¯o_r, &context_l, &context_r, NULL)) - p += macro_r; - else - p++; + for (i = 0; i < functionids.values_num; i++) + { + functionid = functionids.values[i]; - continue; - } + if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid))) + goto out; - if (NULL == (q = strchr(p + 1, '}'))) - return FAIL; + if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid))) + goto out; - if (SUCCEED != is_uint64_n(p + 1, q - p - 1, &functionid)) - continue; + if (ITEM_STATUS_ACTIVE != dc_item->status) + goto out; - if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid)) || - NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid)) || - ITEM_STATUS_ACTIVE != dc_item->status || - NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)) || - HOST_STATUS_MONITORED != dc_host->status) - { - return FAIL; - } + if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid))) + goto out; - p = q; + if (HOST_STATUS_MONITORED != dc_host->status) + goto out; } - return SUCCEED; + ret = SUCCEED; +out: + zbx_vector_uint64_destroy(&functionids); + + return ret; } /****************************************************************************** @@ -11356,9 +11427,11 @@ static void dc_status_update(void) switch (dc_trigger->status) { case TRIGGER_STATUS_ENABLED: - if (SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->expression) && + if (SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->expression, + dc_trigger->expression_bin) && (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION != dc_trigger->recovery_mode || - SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->recovery_expression))) + SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->recovery_expression, + dc_trigger->recovery_expression_bin))) { switch (dc_trigger->value) { @@ -13909,7 +13982,37 @@ void zbx_get_host_interfaces_availability(zbx_uint64_t hostid, zbx_agent_availab } +/********************************************************************************* + * * + * Function: zbx_dc_eval_expand_user_macros * + * * + * Purpose: resolve user macros in parsed expression * + * * + * Parameters: ctx - [IN] the expression evalution context * + * * + ********************************************************************************/ +void zbx_dc_eval_expand_user_macros(zbx_eval_context_t *ctx) +{ + zbx_vector_uint64_t hostids, functionids; + + zbx_vector_uint64_create(&hostids); + zbx_vector_uint64_create(&functionids); + + zbx_eval_get_functionids(ctx, &functionids); + + RDLOCK_CACHE; + + dc_get_hostids_by_functionids(functionids.values, functionids.values_num, &hostids); + zbx_eval_expand_user_macros(ctx, hostids.values, hostids.values_num, dc_expand_user_macros_len); + + UNLOCK_CACHE; + + zbx_vector_uint64_destroy(&functionids); + zbx_vector_uint64_destroy(&hostids); +} + #ifdef HAVE_TESTS # include "../../../tests/libs/zbxdbcache/dc_item_poller_type_update_test.c" # include "../../../tests/libs/zbxdbcache/dc_function_calculate_nextcheck_test.c" #endif + diff --git a/src/libs/zbxdbcache/dbconfig.h b/src/libs/zbxdbcache/dbconfig.h index 7bb56a4d7fb..f3d674695b1 100644 --- a/src/libs/zbxdbcache/dbconfig.h +++ b/src/libs/zbxdbcache/dbconfig.h @@ -37,6 +37,8 @@ typedef struct const unsigned char *expression_bin; const unsigned char *recovery_expression_bin; int lastchange; + int revision; + int timer_revision; unsigned char topoindex; unsigned char priority; unsigned char type; @@ -47,11 +49,18 @@ typedef struct unsigned char functional; /* see TRIGGER_FUNCTIONAL_* defines */ unsigned char recovery_mode; /* see TRIGGER_RECOVERY_MODE_* defines */ unsigned char correlation_mode; /* see ZBX_TRIGGER_CORRELATION_* defines */ + unsigned char timer; zbx_vector_ptr_t tags; } ZBX_DC_TRIGGER; +/* specifies if trigger expression/recovery expression has timer functions */ +/* (date, time, now, dayofweek or dayofmonth) */ +#define ZBX_TRIGGER_TIMER_DEFAULT 0x00 +#define ZBX_TRIGGER_TIMER_EXPRESSION 0x01 +#define ZBX_TRIGGER_TIMER_RECOVERY_EXPRESSION 0x02 + typedef struct zbx_dc_trigger_deplist { zbx_uint64_t triggerid; @@ -913,4 +922,10 @@ char *dc_expand_user_macros_in_calcitem(const char *formula, zbx_uint64_t hostid char *dc_expand_user_macros(const char *text, zbx_uint64_t *hostids, int hostids_num); char *dc_expand_user_macros_len(const char *text, size_t len, zbx_uint64_t *hostids, int hostids_num); +#define ZBX_TRIGGER_TIMER_NONE 0x0000 +#define ZBX_TRIGGER_TIMER_TRIGGER 0x0001 +#define ZBX_TRIGGER_TIMER_FUNCTION_TIME 0x0002 +#define ZBX_TRIGGER_TIMER_FUNCTION_TREND 0x0004 +#define ZBX_TRIGGER_TIMER_FUNCTION (ZBX_TRIGGER_TIMER_FUNCTION_TIME | ZBX_TRIGGER_TIMER_FUNCTION_TREND) + #endif diff --git a/src/libs/zbxdbcache/dbconfig_maintenance.c b/src/libs/zbxdbcache/dbconfig_maintenance.c index fde177b3e2c..43dccd68331 100644 --- a/src/libs/zbxdbcache/dbconfig_maintenance.c +++ b/src/libs/zbxdbcache/dbconfig_maintenance.c @@ -1532,8 +1532,15 @@ int zbx_dc_get_event_maintenances(zbx_vector_ptr_t *event_queries, const zbx_vec { continue; } - get_functionids(&query->functionids, trigger->expression); - get_functionids(&query->functionids, trigger->recovery_expression); + + zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin, + &query->functionids); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode) + { + zbx_get_serialized_expression_functionids(trigger->recovery_expression, + trigger->recovery_expression_bin, &query->functionids); + } } for (j = 0; j < query->functionids.values_num; j++) diff --git a/src/libs/zbxdbcache/dbsync.c b/src/libs/zbxdbcache/dbsync.c index f3cde1454fd..b0ab54a1d12 100644 --- a/src/libs/zbxdbcache/dbsync.c +++ b/src/libs/zbxdbcache/dbsync.c @@ -2206,7 +2206,7 @@ static char **dbsync_trigger_preproc_row(char **row) zbx_vector_uint64_t hostids, functionids; zbx_eval_context_t ctx, ctx_r; char *error; - unsigned char mode; + unsigned char mode, timer = ZBX_TRIGGER_TIMER_DEFAULT; zbx_vector_uint64_create(&hostids); zbx_vector_uint64_create(&functionids); @@ -2217,20 +2217,30 @@ static char **dbsync_trigger_preproc_row(char **row) zbx_free(error); } else + { zbx_eval_get_functionids(&ctx, &functionids); + if (SUCCEED == zbx_eval_check_timer_functions(&ctx)) + timer |= ZBX_TRIGGER_TIMER_EXPRESSION; + } + ZBX_STR2UCHAR(mode, row[10]); if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == mode) { - if (FAIL == zbx_eval_parse_expression(&ctx_r, row[2], ZBX_EVAL_TRIGGER_EXPRESSION, &error)) + if (FAIL == zbx_eval_parse_expression(&ctx_r, row[11], ZBX_EVAL_TRIGGER_EXPRESSION, &error)) { zbx_eval_set_exception(&ctx_r, zbx_dsprintf(NULL, "cannot parse trigger recovery" " expression: %s", error)); zbx_free(error); } else + { zbx_eval_get_functionids(&ctx, &functionids); + + if (SUCCEED == zbx_eval_check_timer_functions(&ctx)) + timer |= ZBX_TRIGGER_TIMER_RECOVERY_EXPRESSION; + } } dc_get_hostids_by_functionids(functionids.values, functionids.values_num, &hostids); @@ -2252,6 +2262,8 @@ static char **dbsync_trigger_preproc_row(char **row) zbx_eval_clear(&ctx_r); } + row[18] = zbx_dsprintf(NULL, "%d", timer); + zbx_vector_uint64_destroy(&functionids); zbx_vector_uint64_destroy(&hostids); @@ -2270,7 +2282,9 @@ static char **dbsync_trigger_preproc_row(char **row) * FAIL - otherwise * * * * Comment: The 16th and 17th fields (starting with 0) are placeholders for * - * serialized expression/recovery expression * + * serialized expression/recovery expression. * + * The 18th field is placeholder for trigger timer flag (set if * + * expression/recovery expression contains timer functions). * * * ******************************************************************************/ int zbx_dbsync_compare_triggers(zbx_dbsync_t *sync) @@ -2286,7 +2300,7 @@ int zbx_dbsync_compare_triggers(zbx_dbsync_t *sync) if (NULL == (result = DBselect( "select distinct t.triggerid,t.description,t.expression,t.error,t.priority,t.type,t.value," "t.state,t.lastchange,t.status,t.recovery_mode,t.recovery_expression," - "t.correlation_mode,t.correlation_tag,t.opdata,t.event_name,null,null" + "t.correlation_mode,t.correlation_tag,t.opdata,t.event_name,null,null,null" " from hosts h,items i,functions f,triggers t" " where h.hostid=i.hostid" " and i.itemid=f.itemid" @@ -2299,7 +2313,7 @@ int zbx_dbsync_compare_triggers(zbx_dbsync_t *sync) return FAIL; } - dbsync_prepare(sync, 18, dbsync_trigger_preproc_row); + dbsync_prepare(sync, 19, dbsync_trigger_preproc_row); if (ZBX_DBSYNC_INIT == sync->mode) { diff --git a/src/libs/zbxdbhigh/event.c b/src/libs/zbxdbhigh/event.c index 4a3bfa131c8..5771cbc7eaa 100644 --- a/src/libs/zbxdbhigh/event.c +++ b/src/libs/zbxdbhigh/event.c @@ -198,6 +198,7 @@ void zbx_db_get_events_by_eventids(zbx_vector_uint64_t *eventids, zbx_vector_ptr event->trigger.opdata = zbx_strdup(NULL, row[9]); event->trigger.event_name = ('\0' != *row[10] ? zbx_strdup(NULL, row[10]) : NULL); + event->trigger.cache = NULL; } } } @@ -212,26 +213,6 @@ void zbx_db_get_events_by_eventids(zbx_vector_uint64_t *eventids, zbx_vector_ptr /****************************************************************************** * * - * Function: zbx_db_trigger_clean * - * * - * Purpose: frees resources allocated to store trigger data * - * * - * Parameters: trigger - * - * * - ******************************************************************************/ -void zbx_db_trigger_clean(DB_TRIGGER *trigger) -{ - zbx_free(trigger->description); - zbx_free(trigger->expression); - zbx_free(trigger->recovery_expression); - zbx_free(trigger->comments); - zbx_free(trigger->url); - zbx_free(trigger->opdata); - zbx_free(trigger->event_name); -} - -/****************************************************************************** - * * * Function: zbx_free_event * * * * Purpose: deallocate memory allocated in function 'get_db_events_info' * diff --git a/src/libs/zbxdbhigh/trigger.c b/src/libs/zbxdbhigh/trigger.c index 772b85e9f3d..82078904c9d 100644 --- a/src/libs/zbxdbhigh/trigger.c +++ b/src/libs/zbxdbhigh/trigger.c @@ -32,6 +32,14 @@ #define ZBX_FLAGS_TRIGGER_CREATE_EVENT \ (ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT | ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT) +/* DB_TRIGGER cached objects */ +typedef enum +{ + ZBX_DB_TRIGGER_CACHE_EVAL_CTX, + ZBX_DB_TRIGGER_CACHE_EVAL_CTX_R, + ZBX_DB_TRIGGER_CACHE_EVAL_CTX_MACROS, +} +zbx_db_trigger_cache_t; /****************************************************************************** * * @@ -119,7 +127,7 @@ static int zbx_process_trigger(struct _DC_TRIGGER *trigger, zbx_vector_ptr_t *di { zbx_add_event(EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER, trigger->triggerid, &trigger->timespec, new_value, trigger->description, - trigger->expression_orig, trigger->recovery_expression_orig, + trigger->expression, trigger->recovery_expression, trigger->priority, trigger->type, &trigger->tags, trigger->correlation_mode, trigger->correlation_tag, trigger->value, trigger->opdata, trigger->event_name, NULL); @@ -303,3 +311,377 @@ void zbx_append_trigger_diff(zbx_vector_ptr_t *trigger_diff, zbx_uint64_t trigge zbx_vector_ptr_append(trigger_diff, diff); } + + +/* temporary cache of trigger related data */ +typedef struct +{ + zbx_uint64_t flags; + zbx_eval_context_t eval_ctx; + zbx_eval_context_t eval_ctx_r; + zbx_vector_uint64_t hostids; +} +zbx_trigger_cache_t; + +/* related trigger data caching states */ +typedef enum +{ + ZBX_TRIGGER_CACHE_EVAL_CTX, + ZBX_TRIGGER_CACHE_EVAL_CTX_R, + ZBX_TRIGGER_CACHE_EVAL_CTX_MACROS, + ZBX_TRIGGER_CACHE_HOSTIDS, +} +zbx_trigger_cache_state_t; + +/****************************************************************************** + * * + * Function: db_trigger_get_cache * + * * + * Purpose: get trigger cache with the requested data cached * + * * + * Parameters: trigger - [IN] the trigger * + * state - [IN] the required cache state * + * * + ******************************************************************************/ +static zbx_trigger_cache_t *db_trigger_get_cache(const DB_TRIGGER *trigger, zbx_trigger_cache_state_t state) +{ + zbx_trigger_cache_t *cache; + char *error = NULL; + zbx_uint64_t flag = __UINT64_C(1) << state; + zbx_vector_uint64_t functionids; + + if (NULL == trigger->cache) + { + cache = (zbx_trigger_cache_t *)zbx_malloc(NULL, sizeof(zbx_trigger_cache_t)); + cache->flags = 0; + ((DB_TRIGGER *)trigger)->cache = cache; + } + else + cache = (zbx_trigger_cache_t *)trigger->cache; + + if (0 != (cache->flags & flag)) + return 0 != (cache->flags & (flag << 32)) ? cache : NULL; + + cache->flags |= flag; + + switch (state) + { + case ZBX_TRIGGER_CACHE_EVAL_CTX: + if ('\0' == *trigger->expression) + return NULL; + + if (FAIL == zbx_eval_parse_expression(&cache->eval_ctx, trigger->expression, + ZBX_EVAL_TRIGGER_EXPRESSION, &error)) + { + zbx_free(error); + return NULL; + } + break; + case ZBX_TRIGGER_CACHE_EVAL_CTX_R: + if ('\0' == *trigger->recovery_expression) + return NULL; + + if (FAIL == zbx_eval_parse_expression(&cache->eval_ctx_r, trigger->recovery_expression, + ZBX_EVAL_TRIGGER_EXPRESSION, &error)) + { + zbx_free(error); + return NULL; + } + break; + case ZBX_DB_TRIGGER_CACHE_EVAL_CTX_MACROS: + if (NULL == db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX)) + return NULL; + zbx_dc_eval_expand_user_macros(&cache->eval_ctx); + break; + case ZBX_TRIGGER_CACHE_HOSTIDS: + zbx_vector_uint64_create(&cache->hostids); + zbx_vector_uint64_create(&functionids); + zbx_db_trigger_get_all_functionids(trigger, &functionids); + DCget_hostids_by_functionids(&functionids, &cache->hostids); + zbx_vector_uint64_destroy(&functionids); + break; + default: + return NULL; + } + + cache->flags |= (flag << 32); + + return cache; +} + +/****************************************************************************** + * * + * Function: trigger_cache_free * + * * + * Purpose: free trigger cache * + * * + * Parameters: cache - [IN] the trigger cache * + * * + ******************************************************************************/ +static void trigger_cache_free(zbx_trigger_cache_t *cache) +{ + if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_EVAL_CTX << 32))) + zbx_eval_clear(&cache->eval_ctx); + + if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_EVAL_CTX_R << 32))) + zbx_eval_clear(&cache->eval_ctx_r); + + if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_HOSTIDS << 32))) + zbx_vector_uint64_destroy(&cache->hostids); + + zbx_free(cache); +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_all_functionids * + * * + * Purpose: get functionids from trigger expression and recovery expression * + * * + * Parameters: trigger - [IN] the trigger * + * functionids - [OUT] the extracted functionids * + * * + * Comments: This function will cache parsed expressions in the trigger. * + * * + ******************************************************************************/ +void zbx_db_trigger_get_all_functionids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *functionids) +{ + zbx_trigger_cache_t *cache; + + if (NULL != (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX))) + zbx_eval_get_functionids(&cache->eval_ctx, functionids); + + if (NULL != (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX_R))) + zbx_eval_get_functionids(&cache->eval_ctx_r, functionids); + + zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_functionids * + * * + * Purpose: get functionids from trigger expression * + * * + * Parameters: trigger - [IN] the trigger * + * functionids - [OUT] the extracted functionids * + * * + * Comments: This function will cache parsed expressions in the trigger. * + * * + ******************************************************************************/ +void zbx_db_trigger_get_functionids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *functionids) +{ + zbx_trigger_cache_t *cache; + + if (NULL != (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX))) + zbx_eval_get_functionids(&cache->eval_ctx, functionids); + + zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_constant * + * * + * Purpose: get trigger expression constant at the specified location * + * * + * Parameters: trigger - [IN] the trigger * + * index - [IN] the constant index, starting with 1 * + * out - [IN] the constant value, if exists * + * * + * Return value: SUCCEED - the expression was parsed and constant extracted * + * (if the index was valid) * + * FAIL - the expression failed to parse * + * * + * Comments: This function will cache parsed expressions in the trigger. * + * * + ******************************************************************************/ +int zbx_db_trigger_get_constant(const DB_TRIGGER *trigger, int index, char **out) +{ + zbx_trigger_cache_t *cache; + + if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX_MACROS))) + return FAIL; + + zbx_eval_get_constant(&cache->eval_ctx, index, out); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_itemid * + * * + * Purpose: get the Nth function item from trigger expression * + * * + * Parameters: trigger - [IN] the trigger * + * index - [IN] the function index * + * itemid - [IN] the function itemid * + * * + * Comments: SUCCEED - the itemid was extracted successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_db_trigger_get_itemid(const DB_TRIGGER *trigger, int index, zbx_uint64_t *itemid) +{ + int i, ret = FAIL; + zbx_trigger_cache_t *cache; + + if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX))) + return FAIL; + + for (i = 0; i < cache->eval_ctx.stack.values_num; i++) + { + zbx_eval_token_t *token = &cache->eval_ctx.stack.values[i]; + zbx_uint64_t functionid; + DC_FUNCTION function; + int errcode; + + if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type || (int)token->opt + 1 != index) + continue; + + switch (token->value.type) + { + case ZBX_VARIANT_UI64: + functionid = token->value.data.ui64; + break; + case ZBX_VARIANT_NONE: + if (SUCCEED != is_uint64_n(cache->eval_ctx.expression + token->loc.l + 1, + token->loc.r - token->loc.l - 1, &functionid)) + { + return FAIL; + } + zbx_variant_set_ui64(&token->value, functionid); + break; + default: + return FAIL; + } + + DCconfig_get_functions_by_functionids(&function, &functionid, &errcode, 1); + + if (SUCCEED == errcode) + { + *itemid = function.itemid; + ret = SUCCEED; + } + + DCconfig_clean_functions(&function, &errcode, 1); + break; + } + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_itemids * + * * + * Purpose: get unique itemids of trigger functions in the order at they are * + * written in expression * + * * + * Parameters: trigger - [IN] the trigger * + * itemids - [IN] the function itemids * + * * + ******************************************************************************/ +void zbx_db_trigger_get_itemids(const DB_TRIGGER *trigger, zbx_vector_uint64_t *itemids) +{ + zbx_vector_uint64_t functionids, functionids_ordered; + zbx_trigger_cache_t *cache; + + if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX))) + return; + + zbx_vector_uint64_create(&functionids); + zbx_vector_uint64_create(&functionids_ordered); + + zbx_eval_get_functionids_ordered(&cache->eval_ctx, &functionids_ordered); + + if (0 != functionids_ordered.values_num) + { + DC_FUNCTION *function, *functions; + int i, *errcodes; + + zbx_vector_uint64_append_array(&functionids, functionids_ordered.values, + functionids_ordered.values_num); + + zbx_vector_uint64_sort(&functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + functions = (DC_FUNCTION *)zbx_malloc(NULL, sizeof(DC_FUNCTION) * functionids.values_num); + errcodes = (int *)zbx_malloc(NULL, sizeof(int) * functionids.values_num); + + DCconfig_get_functions_by_functionids(functions, functionids.values, errcodes, + functionids.values_num); + + for (i = 0; i < functionids_ordered.values_num; i++) + { + if (NULL != (function = bsearch(&functionids_ordered.values[i], functions, + functionids.values_num, sizeof(DC_FUNCTION), + ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + if (FAIL == zbx_vector_uint64_search(itemids, function->itemid, + ZBX_DEFAULT_UINT64_COMPARE_FUNC)) + { + zbx_vector_uint64_append(itemids, function->itemid); + } + } + } + + DCconfig_clean_functions(functions, errcodes, functionids.values_num); + zbx_free(functions); + zbx_free(errcodes); + } + + zbx_vector_uint64_destroy(&functionids_ordered); + zbx_vector_uint64_destroy(&functionids); +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_get_all_hostids * + * * + * Purpose: get hostids from trigger expression and recovery expression * + * * + * Parameters: trigger - [IN] the trigger * + * hostids - [OUT] the extracted hostids * + * * + * Return value: SUCCEED - the hostids vector was returned (but can be empty * + * FAIL - otherwise * + * * + * Comments: This function will cache parsed expressions in the trigger. * + * * + ******************************************************************************/ +int zbx_db_trigger_get_all_hostids(const DB_TRIGGER *trigger, const zbx_vector_uint64_t **hostids) +{ + zbx_trigger_cache_t *cache; + + if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_HOSTIDS))) + return FAIL; + + *hostids = &cache->hostids; + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_db_trigger_clean * + * * + * Purpose: frees resources allocated to store trigger data * + * * + * Parameters: trigger - * + * * + ******************************************************************************/ +void zbx_db_trigger_clean(DB_TRIGGER *trigger) +{ + zbx_free(trigger->description); + zbx_free(trigger->expression); + zbx_free(trigger->recovery_expression); + zbx_free(trigger->comments); + zbx_free(trigger->url); + zbx_free(trigger->opdata); + zbx_free(trigger->event_name); + + if (NULL != trigger->cache) + trigger_cache_free((zbx_trigger_cache_t *)trigger->cache); +} diff --git a/src/libs/zbxeval/execute.c b/src/libs/zbxeval/execute.c index 649578de985..e1431ffc742 100644 --- a/src/libs/zbxeval/execute.c +++ b/src/libs/zbxeval/execute.c @@ -22,6 +22,7 @@ #include "zbxalgo.h" #include "zbxserver.h" +#include "eval.h" static zbx_variant_t var_zero = {.type = ZBX_VARIANT_DBL, .data = {.dbl = 0}}; @@ -360,7 +361,7 @@ static int eval_execute_push_value(const zbx_eval_context_t *ctx, const zbx_eval * FAIL - otherwise * * * ******************************************************************************/ -static int eval_compare_token(const zbx_eval_context_t *ctx, const zbx_strloc_t *loc, const char *text, +int eval_compare_token(const zbx_eval_context_t *ctx, const zbx_strloc_t *loc, const char *text, size_t len) { if (loc->r - loc->l + 1 != len) diff --git a/src/libs/zbxeval/misc.c b/src/libs/zbxeval/misc.c index d2fb08e2d5d..1641d592d00 100644 --- a/src/libs/zbxeval/misc.c +++ b/src/libs/zbxeval/misc.c @@ -25,36 +25,393 @@ #include "zbxvariant.h" #include "zbxserialize.h" #include "zbxserver.h" +#include "eval.h" + +#define ZBX_EVAL_STATIC_BUFFER_SIZE 4096 /****************************************************************************** * * - * Function: zbx_eval_get_functionids * + * Function: reserve_buffer * + * * + * Purpose: reserve number of bytes in the specified buffer, reallocating if * + * necessary * + * * + * Parameters: buffer - [IN/OUT] the buffer * + * buffer_size - [INT/OUT] the deserialized value * + * reserve - [IN] the number of bytes to reserve * + * ptr - [IN/OUT] a pointer to an offset in buffer * + * * + * Comments: Initially static buffer is used, allocating dynamic buffer when * + * static buffer is too small. * + * * + ******************************************************************************/ +static void reserve_buffer(unsigned char **buffer, size_t *buffer_size, size_t reserve, unsigned char **ptr) +{ + size_t offset = *ptr - *buffer, new_size; + + if (offset + reserve <= *buffer_size) + return; + + new_size = *buffer_size * 1.5; + + if (ZBX_EVAL_STATIC_BUFFER_SIZE == *buffer_size) + { + unsigned char *old = *buffer; + + *buffer = zbx_malloc(NULL, new_size); + memcpy(*buffer, old, offset); + } + else + *buffer = zbx_realloc(*buffer, new_size); + + *buffer_size = new_size; + *ptr = *buffer + offset; +} + +static void serialize_variant(unsigned char **buffer, size_t *size, const zbx_variant_t *value, + unsigned char **ptr) +{ + size_t len; + + reserve_buffer(buffer, size, 1, ptr); + **ptr = value->type; + (*ptr)++; + + switch (value->type) + { + case ZBX_VARIANT_UI64: + reserve_buffer(buffer, size, sizeof(value->data.ui64), ptr); + *ptr += zbx_serialize_uint64(*ptr, value->data.ui64); + break; + case ZBX_VARIANT_DBL: + reserve_buffer(buffer, size, sizeof(value->data.dbl), ptr); + *ptr += zbx_serialize_double(*ptr, value->data.dbl) + 1; + break; + case ZBX_VARIANT_STR: + len = strlen(value->data.str) + 1; + reserve_buffer(buffer, size, len, ptr); + memcpy(*ptr, value->data.str, len); + *ptr += len; + break; + case ZBX_VARIANT_NONE: + break; + default: + zabbix_log(LOG_LEVEL_DEBUG, "TYPE: %d", value->type); + THIS_SHOULD_NEVER_HAPPEN; + (*ptr)[-1] = ZBX_VARIANT_NONE; + break; + } +} + +static zbx_uint32_t deserialize_variant(const unsigned char *ptr, zbx_variant_t *value) +{ + const unsigned char *start = ptr; + unsigned char type; + zbx_uint64_t ui64; + double dbl; + char *str; + size_t len; + + ptr += zbx_deserialize_char(ptr, &type); + + switch (type) + { + case ZBX_VARIANT_UI64: + ptr += zbx_deserialize_uint64(ptr, &ui64); + zbx_variant_set_ui64(value, ui64); + break; + case ZBX_VARIANT_DBL: + ptr += zbx_deserialize_double(ptr, &dbl); + zbx_variant_set_dbl(value, dbl); + break; + case ZBX_VARIANT_STR: + len = strlen((const char *)ptr) + 1; + str = zbx_malloc(NULL, len); + memcpy(str, ptr, len); + zbx_variant_set_str(value, str); + ptr += len; + break; + case ZBX_VARIANT_NONE: + zbx_variant_set_none(value); + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + zbx_variant_set_none(value); + break; + } + + return ptr - start; +} + +/****************************************************************************** + * * + * Function: zbx_eval_serialize * * * - * Purpose: extract functionids from the parsed expression * + * Purpose: serialize evaluation context into buffer * * * * Parameters: ctx - [IN] the evaluation context * - * functionids - [OUT] the extracted functionids * + * malloc_func - [IN] the buffer memory allocation function, * + * optional (by default the buffer is * + * allocated in heap) * + * data - [OUT] the buffer with serialized evaluation context * + * * + * Comments: Location of the replaced tokens (with token.value set) are not * + * serialized, making it impossible to reconstruct the expression * + * text with replaced tokens. * + * Context serialization/deserialization must be used for * + * context caching. * + * * + * Return value: The size of serialized data. * * * ******************************************************************************/ -void zbx_eval_get_functionids(const zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids) +size_t zbx_eval_serialize(const zbx_eval_context_t *ctx, zbx_mem_malloc_func_t malloc_func, + unsigned char **data) { - int i; + int i; + unsigned char buffer_static[ZBX_EVAL_STATIC_BUFFER_SIZE], *buffer = buffer_static, *ptr = buffer, len_buff[4]; + size_t buffer_size = ZBX_EVAL_STATIC_BUFFER_SIZE; + zbx_uint32_t len, len_offset; + + if (NULL == malloc_func) + malloc_func = ZBX_DEFAULT_MEM_MALLOC_FUNC; + + ptr += zbx_serialize_uint31_compact(ptr, ctx->stack.values_num); for (i = 0; i < ctx->stack.values_num; i++) { + const zbx_eval_token_t *token = &ctx->stack.values[i]; + + reserve_buffer(&buffer, &buffer_size, 20, &ptr); + + ptr += zbx_serialize_value(ptr, token->type); + ptr += zbx_serialize_uint31_compact(ptr, token->opt); + + serialize_variant(&buffer, &buffer_size, &token->value, &ptr); + + ptr += zbx_serialize_uint31_compact(ptr, token->loc.l); + ptr += zbx_serialize_uint31_compact(ptr, token->loc.r); + } + + len = ptr - buffer; + + len_offset = zbx_serialize_uint31_compact(len_buff, len); + + *data = malloc_func(NULL, len + len_offset); + memcpy(*data, len_buff, len_offset); + memcpy(*data + len_offset, buffer, len); + + if (buffer != buffer_static) + zbx_free(buffer); + + return len + len_offset; +} + +/****************************************************************************** + * * + * Function: zbx_eval_deserialize * + * * + * Purpose: deserialize evaluation context from buffer * + * * + * Parameters: ctx - [OUT] the evaluation context * + * expression - [IN] the expression the evaluation context was * + * created from * + * rules - [IN] the composition and evaluation rules * + * data - [IN] the buffer with serialized context * + * * + ******************************************************************************/ +void zbx_eval_deserialize(zbx_eval_context_t *ctx, const char *expression, zbx_uint64_t rules, + const unsigned char *data) +{ + zbx_uint32_t i, tokens_num, len, pos; + + memset(ctx, 0, sizeof(zbx_eval_context_t)); + ctx->expression = expression; + ctx->rules = rules; + + data += zbx_deserialize_uint31_compact(data, &len); + data += zbx_deserialize_uint31_compact(data, &tokens_num); + zbx_vector_eval_token_create(&ctx->stack); + zbx_vector_eval_token_reserve(&ctx->stack, tokens_num); + ctx->stack.values_num = tokens_num; + + for (i = 0; i < tokens_num; i++) + { zbx_eval_token_t *token = &ctx->stack.values[i]; - if (ZBX_EVAL_TOKEN_FUNCTIONID == token->type) + data += zbx_deserialize_value(data, &token->type); + data += zbx_deserialize_uint31_compact(data, &token->opt); + data += deserialize_variant(data, &token->value); + + data += zbx_deserialize_uint31_compact(data, &pos); + token->loc.l = pos; + data += zbx_deserialize_uint31_compact(data, &pos); + token->loc.r = pos; + } +} + +static int compare_tokens_by_loc(const void *d1, const void *d2) +{ + const zbx_eval_token_t *t1 = *(const zbx_eval_token_t **)d1; + const zbx_eval_token_t *t2 = *(const zbx_eval_token_t **)d2; + + ZBX_RETURN_IF_NOT_EQUAL(t1->loc.l, t2->loc.l); + return 0; +} + +/****************************************************************************** + * * + * Function: eval_token_print_alloc * + * * + * Purpose: print token into string quoting/escaping if necessary * + * * + * Parameters: ctx - [IN] the evaluation context * + * str - [IN/OUT] the output buffer * + * str_alloc - [IN/OUT] the output buffer size * + * str_offset - [IN/OUT] the output buffer offset * + * token - [IN] the token to print * + * * + ******************************************************************************/ +static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, size_t *str_alloc, size_t *str_offset, + const zbx_eval_token_t *token) +{ + int quoted = 0, len, check_value = 0; + const char *src, *value_str; + char *dst; + size_t size; + + if (ZBX_VARIANT_NONE == token->value.type) + return; + + switch (token->type) + { + case ZBX_EVAL_TOKEN_VAR_STR: + quoted = 1; + break; + case ZBX_EVAL_TOKEN_VAR_MACRO: + if (0 != (ctx->rules & ZBX_EVAL_QUOTE_MACRO)) + check_value = 1; + break; + case ZBX_EVAL_TOKEN_VAR_USERMACRO: + if (0 != (ctx->rules & ZBX_EVAL_QUOTE_USERMACRO)) + check_value = 1; + break; + case ZBX_EVAL_TOKEN_VAR_LLDMACRO: + if (0 != (ctx->rules & ZBX_EVAL_QUOTE_LLDMACRO)) + check_value = 1; + break; + case ZBX_EVAL_TOKEN_FUNCTIONID: + check_value = 1; + break; + } + + if (0 != check_value) + { + if (ZBX_VARIANT_STR == token->value.type && (SUCCEED != zbx_number_parse(token->value.data.str, &len) || + strlen(token->value.data.str) != (size_t)len)) { - zbx_uint64_t functionid; + quoted = 1; + } + } - if (SUCCEED == is_uint64_n(ctx->expression + token->loc.l + 1, token->loc.r - token->loc.l - 1, - &functionid)) - { - zbx_vector_uint64_append(functionids, functionid); - } + value_str = zbx_variant_value_desc(&token->value); + + if (0 == quoted) + { + zbx_strcpy_alloc(str, str_alloc, str_offset, value_str); + return; + } + + for (size = 2, src = value_str; '\0' != *src; src++) + { + switch (*src) + { + case '\\': + case '"': + size++; + } + size++; + } + + if (*str_alloc <= *str_offset + size) + { + if (0 == *str_alloc) + *str_alloc = size; + + do + { + *str_alloc *= 2; + } + while (*str_alloc - *str_offset <= size); + + *str = zbx_realloc(*str, *str_alloc); + } + + dst = *str + *str_offset; + *dst++ = '"'; + + for (src = value_str; '\0' != *src; src++, dst++) + { + switch (*src) + { + case '\\': + case '"': + *dst++ = '\\'; + break; + } + + *dst = *src; + } + + *dst++ = '"'; + *dst = '\0'; + *str_offset += size; +} + +/****************************************************************************** + * * + * Function: zbx_eval_compose_expression * + * * + * Purpose: compose expression by replacing processed tokens (with values) in * + * the original expression * + * * + * Parameters: ctx - [IN] the evaluation context * + * expression - [OUT] the composed expression * + * * + ******************************************************************************/ +void zbx_eval_compose_expression(const zbx_eval_context_t *ctx, char **expression) +{ + zbx_vector_ptr_t tokens; + const zbx_eval_token_t *token; + int i; + size_t pos = 0, expression_alloc = 0, expression_offset = 0; + + zbx_vector_ptr_create(&tokens); + + for (i = 0; i < ctx->stack.values_num; i++) + { + if (ZBX_VARIANT_NONE != ctx->stack.values[i].value.type) + zbx_vector_ptr_append(&tokens, &ctx->stack.values[i]); + } + + zbx_vector_ptr_sort(&tokens, compare_tokens_by_loc); + + for (i = 0; i < tokens.values_num; i++) + { + token = (const zbx_eval_token_t *)tokens.values[i]; + + if (0 != token->loc.l) + { + zbx_strncpy_alloc(expression, &expression_alloc, &expression_offset, ctx->expression + pos, + token->loc.l - pos); } + pos = token->loc.r + 1; + eval_token_print_alloc(ctx, expression, &expression_alloc, &expression_offset, token); } + + if ('\0' != ctx->expression[pos]) + zbx_strcpy_alloc(expression, &expression_alloc, &expression_offset, ctx->expression + pos); + + zbx_vector_ptr_destroy(&tokens); } /****************************************************************************** @@ -93,7 +450,7 @@ void zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *ho continue; } - tmp = zbx_strloc_unquote_dyn(ctx->expression, &token->loc); + tmp = zbx_strloc_get(ctx->expression, &token->loc); value = resolver_cb(tmp, strlen(tmp), hostids, hostids_num); zbx_free(tmp); break; @@ -130,3 +487,308 @@ void zbx_eval_set_exception(zbx_eval_context_t *ctx, char *message) zbx_variant_set_str(&token->value, message); (++token)->type = ZBX_EVAL_TOKEN_EXCEPTION; } + +/****************************************************************************** + * * + * Function: expression_extract_functionid * + * * + * Purpose: extract functionid from token * + * * + * Parameters: expression - [IN] the original expression * + * token - [IN] the token * + * functionid - [OUT] the extracted functionid * + * expression - [IN] the original expression * + * * + * Return value: SUCCEED - functionid was extracted successfully * + * FAIL - otherwise (incorrect token or invalid data) * + * * + * Comment: The extracted functionid will be cached as token value, so the * + * next time it can be used without extracting the value from * + * expression. * + * * + ******************************************************************************/ +static int expression_extract_functionid(const char *expression, zbx_eval_token_t *token, zbx_uint64_t *functionid) +{ + if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type) + return FAIL; + + switch (token->value.type) + { + case ZBX_VARIANT_UI64: + *functionid = token->value.data.ui64; + return SUCCEED; + case ZBX_VARIANT_NONE: + if (SUCCEED != is_uint64_n(expression + token->loc.l + 1, token->loc.r - token->loc.l - 1, + functionid)) + { + THIS_SHOULD_NEVER_HAPPEN; + break; + } + zbx_variant_set_ui64(&token->value, *functionid); + return SUCCEED; + } + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_deserialize_dyn * + * * + * Purpose: deserialize expression and extract specified tokens into values * + * * + * Parameters: data - [IN] serialized expression * + * expression - [IN] the original expression * + * triggerids * + * * + * Return value: Expression evaluation context. * + * * + ******************************************************************************/ +zbx_eval_context_t *zbx_eval_deserialize_dyn(const unsigned char *data, const char *expression, + zbx_uint64_t mask) +{ + zbx_eval_context_t *ctx; + int i; + zbx_uint64_t functionid; + char *value; + + ctx = (zbx_eval_context_t *)zbx_malloc(NULL, sizeof(zbx_eval_context_t)); + zbx_eval_deserialize(ctx, expression, ZBX_EVAL_TRIGGER_EXPRESSION, data); + + for (i = 0; i < ctx->stack.values_num; i++) + { + zbx_eval_token_t *token = &ctx->stack.values[i]; + + switch (token->type) + { + case ZBX_EVAL_TOKEN_FUNCTIONID: + if (0 == (mask & ZBX_EVAL_EXTRACT_FUNCTIONID)) + continue; + expression_extract_functionid(expression, token, &functionid); + break; + case ZBX_EVAL_TOKEN_VAR_STR: + if (0 != (mask & ZBX_EVAL_EXTRACT_VAR_STR) && ZBX_VARIANT_NONE == token->value.type) + { + /* extract string variable value for macro resolving */ + value = zbx_strloc_get(expression, &token->loc); + zbx_variant_set_str(&token->value, value); + } + break; + case ZBX_EVAL_TOKEN_VAR_MACRO: + if (0 != (mask & ZBX_EVAL_EXTRACT_VAR_MACRO) && ZBX_VARIANT_NONE == token->value.type) + { + /* extract macro for resolving */ + value = zbx_strloc_get(expression, &token->loc); + zbx_variant_set_str(&token->value, value); + } + break; + } + } + + return ctx; +} + +/****************************************************************************** + * * + * Function: zbx_eval_get_functionids * + * * + * Purpose: get functionids from parsed expression * + * * + * Parameters: ctx - [IN] the evaluation context * + * functionids - [OUT] the extracted functionids * + * * + ******************************************************************************/ +void zbx_eval_get_functionids(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids) +{ + int i; + + for (i = 0; i < ctx->stack.values_num; i++) + { + zbx_eval_token_t *token = &ctx->stack.values[i]; + zbx_uint64_t functionid; + + if (SUCCEED == expression_extract_functionid(ctx->expression, token, &functionid)) + zbx_vector_uint64_append(functionids, functionid); + } + + zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Function: zbx_eval_get_functionids_ordered * + * * + * Purpose: get functionids from parsed expression in the order as they * + * were written + * * + * Parameters: ctx - [IN] the evaluation context * + * functionids - [OUT] the extracted functionids * + * * + ******************************************************************************/ +void zbx_eval_get_functionids_ordered(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids) +{ + int i; + zbx_vector_ptr_t tokens; + + zbx_vector_ptr_create(&tokens); + + for (i = 0; i < ctx->stack.values_num; i++) + { + if (ZBX_EVAL_TOKEN_FUNCTIONID == ctx->stack.values[i].type) + zbx_vector_ptr_append(&tokens, &ctx->stack.values[i]); + } + + zbx_vector_ptr_sort(&tokens, compare_tokens_by_loc); + + for (i = 0; i < tokens.values_num; i++) + { + zbx_eval_token_t *token = (zbx_eval_token_t *)tokens.values[i]; + zbx_uint64_t functionid; + + if (SUCCEED == expression_extract_functionid(ctx->expression, token, &functionid)) + zbx_vector_uint64_append(functionids, functionid); + } + + zbx_vector_ptr_destroy(&tokens); +} + +/****************************************************************************** + * * + * Function: zbx_eval_check_timer_functions * + * * + * Purpose: check if expression contains timer function calls (date, time, * + * now, dayofweek, dayofmonth) * + * * + * Parameters: ctx - [IN] the evaluation context * + * * + * Return value: SUCCEED - expression contains timer function call(s) * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_eval_check_timer_functions(const zbx_eval_context_t *ctx) +{ + int i; + + for (i = 0; i < ctx->stack.values_num; i++) + { + zbx_eval_token_t *token = &ctx->stack.values[i]; + + if (ZBX_EVAL_TOKEN_FUNCTION != token->type) + continue; + + if (SUCCEED == eval_compare_token(ctx, &token->loc, "date", ZBX_CONST_STRLEN("date"))) + return SUCCEED; + if (SUCCEED == eval_compare_token(ctx, &token->loc, "time", ZBX_CONST_STRLEN("time"))) + return SUCCEED; + if (SUCCEED == eval_compare_token(ctx, &token->loc, "now", ZBX_CONST_STRLEN("now"))) + return SUCCEED; + if (SUCCEED == eval_compare_token(ctx, &token->loc, "dayofmonth", ZBX_CONST_STRLEN("dayofmonth"))) + return SUCCEED; + if (SUCCEED == eval_compare_token(ctx, &token->loc, "dayofweek", ZBX_CONST_STRLEN("dayofweek"))) + return SUCCEED; + } + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_get_serialized_expression_functionids * + * * + * Purpose: extract functionids from serialized expression * + * * + * Parameters: expression - [IN] the original expression * + * data - [IN] the serialized expression * + * functionids - [OUT] the extracted functionids * + * * + ******************************************************************************/ +void zbx_get_serialized_expression_functionids(const char *expression, const unsigned char *data, + zbx_vector_uint64_t *functionids) +{ + zbx_uint32_t i, tokens_num, len, loc_l, loc_r, opt; + zbx_token_type_t type; + zbx_uint64_t functionid; + unsigned char var_type; + + data += zbx_deserialize_uint31_compact(data, &len); + data += zbx_deserialize_uint31_compact(data, &tokens_num); + + for (i = 0; i < tokens_num; i++) + { + data += zbx_deserialize_value(data, &type); + data += zbx_deserialize_uint31_compact(data, &opt); + + data += zbx_deserialize_char(data, &var_type); + + switch (var_type) + { + case ZBX_VARIANT_UI64: + data += sizeof(zbx_uint64_t); + break; + case ZBX_VARIANT_DBL: + data += sizeof(double); + break; + case ZBX_VARIANT_STR: + data += strlen((char *)data) + 1; + break; + case ZBX_VARIANT_NONE: + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + return; + } + + data += zbx_deserialize_uint31_compact(data, &loc_l); + data += zbx_deserialize_uint31_compact(data, &loc_r); + + if (ZBX_EVAL_TOKEN_FUNCTIONID == type) + { + if (SUCCEED == is_uint64_n(expression + loc_l + 1, loc_r - loc_l - 1, &functionid)) + zbx_vector_uint64_append(functionids, functionid); + else + THIS_SHOULD_NEVER_HAPPEN; + } + } + + zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Function: zbx_eval_get_constant * + * * + * Purpose: the the Nth constant in expression * + * * + * Parameters: ctx - [IN] the evaluation context * + * index - [IN] the constant index * + * value - [OUT] the constant value * + * * + ******************************************************************************/ +void zbx_eval_get_constant(const zbx_eval_context_t *ctx, int index, char **value) +{ + int i; + + for (i = 0; i < ctx->stack.values_num; i++) + { + zbx_eval_token_t *token = &ctx->stack.values[i]; + + switch (token->type) + { + case ZBX_EVAL_TOKEN_VAR_STR: + case ZBX_EVAL_TOKEN_VAR_NUM: + case ZBX_EVAL_TOKEN_VAR_USERMACRO: + if (index == (int)token->opt + 1) + { + zbx_free(*value); + if (ZBX_VARIANT_NONE != token->value.type) + *value = zbx_strdup(NULL, zbx_variant_value_desc(&token->value)); + else + *value = zbx_strloc_get(ctx->expression, &token->loc); + return; + } + break; + } + } +} diff --git a/src/libs/zbxeval/parse.c b/src/libs/zbxeval/parse.c index d3a22c85902..8730c1cd193 100644 --- a/src/libs/zbxeval/parse.c +++ b/src/libs/zbxeval/parse.c @@ -677,14 +677,14 @@ static void eval_append_arg_null(zbx_eval_context_t *ctx) /****************************************************************************** * * - * Function: eval_clean * + * Function: eval_clear * * * * Purpose: free resources allocated by evaluation context * * * * Parameters: ctx - [IN] the evaluation context * * * ******************************************************************************/ -static void eval_clean(zbx_eval_context_t *ctx) +static void eval_clear(zbx_eval_context_t *ctx) { int i; @@ -902,210 +902,13 @@ out: zbx_vector_eval_token_destroy(&ctx->ops); if (SUCCEED != ret) - eval_clean(ctx); + eval_clear(ctx); return ret; } /****************************************************************************** * * - * Function: serialize_uint31_compact * - * * - * Purpose: serialize 31 bit unsigned integer into utf-8 like byte stream * - * * - * Parameters: ptr - [OUT] the output buffer * - * value - [IN] the value to serialize * - * * - * Return value: The number of bytes written to the buffer. * - * * - * Comments: This serialization method should be used with variables usually * - * having small value while still supporting larger values. * - * * - ******************************************************************************/ -static zbx_uint32_t serialize_uint31_compact(unsigned char *ptr, zbx_uint32_t value) -{ - if (0x7f >= value) - { - ptr[0] = (unsigned char)value; - return 1; - } - else - { - unsigned char buf[6]; - int pos = sizeof(buf) - 1; - zbx_uint32_t len; - - while (value > (zbx_uint32_t)(0x3f >> (sizeof(buf) - pos))) - { - buf[pos] = 0x80 | (value & 0x3f); - value >>= 6; - pos--; - } - - buf[pos] = value | (0xfe << (pos + 1)); - - len = sizeof(buf) - pos; - memcpy(ptr, buf + pos, len); - return len; - } -} - -/****************************************************************************** - * * - * Function: deserialize_uint31_compact * - * * - * Purpose: deserialize 31 bit unsigned integer from utf-8 like byte stream * - * * - * Parameters: ptr - [IN] the byte strem * - * value - [OUT] the deserialized value * - * * - * Return value: The number of bytes read from byte strean. * - * * - ******************************************************************************/ -static zbx_uint32_t deserialize_uint31_compact(const unsigned char *ptr, zbx_uint32_t *value) -{ - if (0 == (*ptr & 0x80)) - { - *value = *ptr; - return 1; - } - else - { - int pos = 2, i; - - while (0 != (*ptr & (0x80 >> pos))) - pos++; - - *value = *ptr & (0xff >> (pos + 1)); - - for (i = 1; i < pos; i++) - { - *value <<= 6; - *value |= (*(++ptr)) & 0x3f; - } - - return pos; - } -} - -#define ZBX_EVAL_STATIC_BUFFER_SIZE 4096 - -/****************************************************************************** - * * - * Function: reserve_buffer * - * * - * Purpose: reserve number of bytes in the specified buffer, reallocating if * - * necessary * - * * - * Parameters: buffer - [IN/OUT] the buffer * - * buffer_size - [INT/OUT] the deserialized value * - * reserve - [IN] the number of bytes to reserve * - * ptr - [IN/OUT] a pointer to an offset in buffer * - * * - * Comments: Initially static buffer is used, allocating dynamic buffer when * - * static buffer is too small. * - * * - ******************************************************************************/ -static void reserve_buffer(unsigned char **buffer, size_t *buffer_size, size_t reserve, unsigned char **ptr) -{ - size_t offset = *ptr - *buffer, new_size; - - if (offset + reserve <= *buffer_size) - return; - - new_size = *buffer_size * 1.5; - - if (ZBX_EVAL_STATIC_BUFFER_SIZE == *buffer_size) - { - unsigned char *old = *buffer; - - *buffer = zbx_malloc(NULL, new_size); - memcpy(*buffer, old, offset); - } - else - *buffer = zbx_realloc(*buffer, new_size); - - *buffer_size = new_size; - *ptr = *buffer + offset; -} - -static void serialize_variant(unsigned char **buffer, size_t *size, const zbx_variant_t *value, - unsigned char **ptr) -{ - size_t len; - - reserve_buffer(buffer, size, 1, ptr); - **ptr = value->type; - (*ptr)++; - - switch (value->type) - { - case ZBX_VARIANT_UI64: - reserve_buffer(buffer, size, sizeof(value->data.ui64), ptr); - *ptr += zbx_serialize_uint64(*ptr, value->data.ui64); - break; - case ZBX_VARIANT_DBL: - reserve_buffer(buffer, size, sizeof(value->data.dbl), ptr); - *ptr += zbx_serialize_double(*ptr, value->data.dbl) + 1; - break; - case ZBX_VARIANT_STR: - len = strlen(value->data.str) + 1; - reserve_buffer(buffer, size, len, ptr); - memcpy(*ptr, value->data.str, len); - *ptr += len; - break; - case ZBX_VARIANT_NONE: - break; - default: - zabbix_log(LOG_LEVEL_DEBUG, "TYPE: %d", value->type); - THIS_SHOULD_NEVER_HAPPEN; - (*ptr)[-1] = ZBX_VARIANT_NONE; - break; - } -} - -static zbx_uint32_t deserialize_variant(const unsigned char *ptr, zbx_variant_t *value) -{ - const unsigned char *start = ptr; - unsigned char type; - zbx_uint64_t ui64; - double dbl; - char *str; - size_t len; - - ptr += zbx_deserialize_char(ptr, &type); - - switch (type) - { - case ZBX_VARIANT_UI64: - ptr += zbx_deserialize_uint64(ptr, &ui64); - zbx_variant_set_ui64(value, ui64); - break; - case ZBX_VARIANT_DBL: - ptr += zbx_deserialize_uint64(ptr, &dbl); - zbx_variant_set_dbl(value, dbl); - break; - case ZBX_VARIANT_STR: - len = strlen((const char *)ptr) + 1; - str = zbx_malloc(NULL, len); - memcpy(str, ptr, len); - zbx_variant_set_str(value, str); - ptr += len; - break; - case ZBX_VARIANT_NONE: - zbx_variant_set_none(value); - break; - default: - THIS_SHOULD_NEVER_HAPPEN; - zbx_variant_set_none(value); - break; - } - - return ptr - start; -} - -/****************************************************************************** - * * * Function: zbx_eval_parse_expression * * * * Purpose: parse expression into tokens in postfix notation order * @@ -1126,291 +929,38 @@ int zbx_eval_parse_expression(zbx_eval_context_t *ctx, const char *expression, z /****************************************************************************** * * - * Function: zbx_eval_clear * - * * - * Purpose: free resources allocated by evaluation context * - * * - * Parameters: ctx - [IN] the evaluation context * - * * - ******************************************************************************/ -void zbx_eval_clear(zbx_eval_context_t *ctx) -{ - eval_clean(ctx); -} - -/****************************************************************************** - * * - * Function: zbx_eval_serialize * - * * - * Purpose: serialize evaluation context into buffer * - * * - * Parameters: ctx - [IN] the evaluation context * - * malloc_func - [IN] the buffer memory allocation function, * - * optional (by default the buffer is * - * allocated in heap) * - * data - [OUT] the buffer with serialized evaluation context * - * * - * Comments: Location of the replaced tokens (with token.value set) are not * - * serialized, making it impossible to reconstruct the expression * - * text with replaced tokens. * - * Context serialization/deserialization must be used for * - * context caching. * - * * - * Return value: The size of serialized data. * - * * - ******************************************************************************/ -size_t zbx_eval_serialize(const zbx_eval_context_t *ctx, zbx_mem_malloc_func_t malloc_func, - unsigned char **data) -{ - int i; - unsigned char buffer_static[ZBX_EVAL_STATIC_BUFFER_SIZE], *buffer = buffer_static, *ptr = buffer, len_buff[4]; - size_t buffer_size = ZBX_EVAL_STATIC_BUFFER_SIZE; - zbx_uint32_t len, len_offset; - - if (NULL == malloc_func) - malloc_func = ZBX_DEFAULT_MEM_MALLOC_FUNC; - - ptr += serialize_uint31_compact(ptr, ctx->stack.values_num); - - for (i = 0; i < ctx->stack.values_num; i++) - { - const zbx_eval_token_t *token = &ctx->stack.values[i]; - - reserve_buffer(&buffer, &buffer_size, 20, &ptr); - - ptr += zbx_serialize_value(ptr, token->type); - ptr += serialize_uint31_compact(ptr, token->opt); - - serialize_variant(&buffer, &buffer_size, &token->value, &ptr); - - if (ZBX_VARIANT_NONE == token->value.type) - { - ptr += serialize_uint31_compact(ptr, token->loc.l); - ptr += serialize_uint31_compact(ptr, token->loc.r); - } - } - - len = ptr - buffer; - - len_offset = serialize_uint31_compact(len_buff, len); - - *data = malloc_func(NULL, len + len_offset); - memcpy(*data, len_buff, len_offset); - memcpy(*data + len_offset, buffer, len); - - if (buffer != buffer_static) - zbx_free(buffer); - - return len + len_offset; -} - -/****************************************************************************** - * * - * Function: zbx_eval_deserialize * - * * - * Purpose: deserialize evaluation context from buffer * - * * - * Parameters: ctx - [OUT] the evaluation context * - * expression - [IN] the expression the evaluation context was * - * created from * - * rules - [IN] the composition and evaluation rules * - * data - [IN] the buffer with serialized context * - * * - ******************************************************************************/ -void zbx_eval_deserialize(zbx_eval_context_t *ctx, const char *expression, zbx_uint64_t rules, - const unsigned char *data) -{ - zbx_uint32_t i, tokens_num, len; - - memset(ctx, 0, sizeof(zbx_eval_context_t)); - ctx->expression = expression; - ctx->rules = rules; - - data += deserialize_uint31_compact(data, &len); - data += deserialize_uint31_compact(data, &tokens_num); - zbx_vector_eval_token_create(&ctx->stack); - zbx_vector_eval_token_reserve(&ctx->stack, tokens_num); - ctx->stack.values_num = tokens_num; - - for (i = 0; i < tokens_num; i++) - { - zbx_eval_token_t *token = &ctx->stack.values[i]; - - data += zbx_deserialize_value(data, &token->type); - data += deserialize_uint31_compact(data, &token->opt); - data += deserialize_variant(data, &token->value); - - if (ZBX_VARIANT_NONE == token->value.type) - { - zbx_uint32_t pos; - - data += deserialize_uint31_compact(data, &pos); - token->loc.l = pos; - data += deserialize_uint31_compact(data, &pos); - token->loc.r = pos; - } - else - token->loc.l = token->loc.r = 0; - } -} - -static int compare_tokens_by_loc(const void *d1, const void *d2) -{ - const zbx_eval_token_t *t1 = *(const zbx_eval_token_t **)d1; - const zbx_eval_token_t *t2 = *(const zbx_eval_token_t **)d2; - - ZBX_RETURN_IF_NOT_EQUAL(t1->loc.l, t2->loc.l); - return 0; -} - -/****************************************************************************** + * Function: zbx_eval_parse_expression * * * - * Function: eval_token_print_alloc * + * Purpose: parse expression into tokens in postfix notation order * * * - * Purpose: print token into string quoting/escaping if necessary * + * Parameters: expression - [IN] the expression to parse * + * rules - [IN] the parsing rules * + * error - [OUT] the error message in the case of failure * * * - * Parameters: ctx - [IN] the evaluation context * - * str - [IN/OUT] the output buffer * - * str_alloc - [IN/OUT] the output buffer size * - * str_offset - [IN/OUT] the output buffer offset * - * token - [IN] the token to print * + * Return value: The evaluation context or NULL in the case of error. * * * ******************************************************************************/ -static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, size_t *str_alloc, size_t *str_offset, - const zbx_eval_token_t *token) +zbx_eval_context_t *zbx_eval_parse_expression_dyn(const char *expression, zbx_uint64_t rules, char **error) { - int quoted = 0, len, check_value = 0; - const char *src, *value_str; - char *dst; - size_t size; + zbx_eval_context_t *ctx; - if (ZBX_VARIANT_NONE == token->value.type) - return; + ctx = (zbx_eval_context_t *)zbx_malloc(NULL, sizeof(zbx_eval_context_t)); + if (SUCCEED != zbx_eval_parse_expression(ctx, expression, rules, error)) + zbx_free(ctx); - switch (token->type) - { - case ZBX_EVAL_TOKEN_VAR_STR: - quoted = 1; - break; - case ZBX_EVAL_TOKEN_VAR_MACRO: - if (0 != (ctx->rules & ZBX_EVAL_QUOTE_MACRO)) - check_value = 1; - break; - case ZBX_EVAL_TOKEN_VAR_USERMACRO: - if (0 != (ctx->rules & ZBX_EVAL_QUOTE_USERMACRO)) - check_value = 1; - break; - case ZBX_EVAL_TOKEN_VAR_LLDMACRO: - if (0 != (ctx->rules & ZBX_EVAL_QUOTE_LLDMACRO)) - check_value = 1; - break; - } - - if (0 != check_value) - { - if (ZBX_VARIANT_STR == token->value.type && (SUCCEED != zbx_number_parse(token->value.data.str, &len) || - strlen(token->value.data.str) != (size_t)len)) - { - quoted = 1; - } - } - - value_str = zbx_variant_value_desc(&token->value); - - if (0 == quoted) - { - zbx_strcpy_alloc(str, str_alloc, str_offset, value_str); - return; - } - - for (size = 2, src = value_str; '\0' != *src; src++) - { - switch (*src) - { - case '\\': - case '"': - size++; - } - size++; - } - - if (*str_alloc - *str_offset <= size) - { - do - { - *str_alloc *= 2; - } - while (*str_alloc - *str_offset <= size); - - *str = zbx_realloc(*str, *str_alloc); - } - - dst = *str + *str_offset; - *dst++ = '"'; - - for (src = value_str; '\0' != *src; src++, dst++) - { - switch (*src) - { - case '\\': - case '"': - *dst++ = '\\'; - break; - } - - *dst = *src; - } - - *dst++ = '"'; - *dst = '\0'; - *str_offset += size; + return ctx; } /****************************************************************************** * * - * Function: zbx_eval_compose_expression * + * Function: zbx_eval_clear * * * - * Purpose: compose expression by replacing processed tokens (with values) in * - * the original expression * + * Purpose: free resources allocated by evaluation context * * * - * Parameters: ctx - [IN] the evaluation context * - * expression - [OUT] the composed expression * + * Parameters: ctx - [IN] the evaluation context * * * ******************************************************************************/ -void zbx_eval_compose_expression(const zbx_eval_context_t *ctx, char **expression) +void zbx_eval_clear(zbx_eval_context_t *ctx) { - zbx_vector_ptr_t tokens; - const zbx_eval_token_t *token; - int i; - size_t pos = 0, expression_alloc = 0, expression_offset = 0; - - zbx_vector_ptr_create(&tokens); - - for (i = 0; i < ctx->stack.values_num; i++) - { - if (ZBX_VARIANT_NONE != ctx->stack.values[i].value.type) - zbx_vector_ptr_append(&tokens, &ctx->stack.values[i]); - } - - zbx_vector_ptr_sort(&tokens, compare_tokens_by_loc); - - for (i = 0; i < tokens.values_num; i++) - { - token = (const zbx_eval_token_t *)tokens.values[i]; - - if (0 != token->loc.l) - { - zbx_strncpy_alloc(expression, &expression_alloc, &expression_offset, ctx->expression + pos, - token->loc.l - pos); - } - pos = token->loc.r + 1; - eval_token_print_alloc(ctx, expression, &expression_alloc, &expression_offset, token); - } - - if ('\0' != ctx->expression[pos]) - zbx_strcpy_alloc(expression, &expression_alloc, &expression_offset, ctx->expression + pos); - - zbx_vector_ptr_destroy(&tokens); + eval_clear(ctx); } - - diff --git a/src/libs/zbxserver/evalfunc.c b/src/libs/zbxserver/evalfunc.c index cf30dd560d5..812aa9e3a99 100644 --- a/src/libs/zbxserver/evalfunc.c +++ b/src/libs/zbxserver/evalfunc.c @@ -3487,21 +3487,12 @@ int evaluate_macro_function(char **result, const char *host, const char *key, co * FAIL - don't evaluate the function for NOTSUPPORTED items * * * ******************************************************************************/ -int evaluatable_for_notsupported(const char *fn) +int zbx_evaluatable_for_notsupported(const char *fn) { - /* functions date(), dayofmonth(), dayofweek(), now(), time() and nodata() are exceptions, */ - /* they should be evaluated for NOTSUPPORTED items, too */ + /* function nodata() are exceptions, */ + /* and should be evaluated for NOTSUPPORTED items, too */ - if ('n' != *fn && 'd' != *fn && 't' != *fn) - return FAIL; - - if (('n' == *fn) && (0 == strcmp(fn, "nodata") || 0 == strcmp(fn, "now"))) - return SUCCEED; - - if (('d' == *fn) && (0 == strcmp(fn, "dayofweek") || 0 == strcmp(fn, "dayofmonth") || 0 == strcmp(fn, "date"))) - return SUCCEED; - - if (0 == strcmp(fn, "time")) + if (0 == strcmp(fn, "nodata")) return SUCCEED; return FAIL; diff --git a/src/libs/zbxserver/evalfunc.h b/src/libs/zbxserver/evalfunc.h index 0de78f499d1..919da491f19 100644 --- a/src/libs/zbxserver/evalfunc.h +++ b/src/libs/zbxserver/evalfunc.h @@ -29,6 +29,6 @@ zbx_output_format_t; int evaluate_macro_function(char **result, const char *host, const char *key, const char *function, const char *parameter, zbx_output_format_t format); -int evaluatable_for_notsupported(const char *fn); +int zbx_evaluatable_for_notsupported(const char *fn); #endif diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c index fafa74250ce..93ad8c92b22 100644 --- a/src/libs/zbxserver/expression.c +++ b/src/libs/zbxserver/expression.c @@ -21,6 +21,7 @@ #include "evalfunc.h" #include "log.h" #include "zbxregexp.h" +#include "zbxvariant.h" #include "valuecache.h" #include "macrofunc.h" @@ -141,103 +142,6 @@ int get_N_functionid(const char *expression, int N_functionid, zbx_uint64_t *fun /****************************************************************************** * * - * Function: get_functionids * - * * - * Purpose: get identifiers of the functions used in expression * - * * - * Parameters: functionids - [OUT] the resulting vector of function ids * - * expression - [IN] null terminated trigger expression * - * '{11}=1 & {2346734}>5' * - * * - ******************************************************************************/ -void get_functionids(zbx_vector_uint64_t *functionids, const char *expression) -{ - zbx_token_t token; - int pos = 0; - zbx_uint64_t functionid; - - if ('\0' == *expression) - return; - - for (; SUCCEED == zbx_token_find(expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++) - { - switch (token.type) - { - case ZBX_TOKEN_OBJECTID: - is_uint64_n(expression + token.loc.l + 1, token.loc.r - token.loc.l - 1, - &functionid); - zbx_vector_uint64_append(functionids, functionid); - ZBX_FALLTHROUGH; - case ZBX_TOKEN_USER_MACRO: - case ZBX_TOKEN_SIMPLE_MACRO: - case ZBX_TOKEN_MACRO: - pos = token.loc.r; - break; - } - } - - zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); - zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); -} - -/****************************************************************************** - * * - * Function: get_N_itemid * - * * - * Parameters: expression - [IN] null terminated trigger expression * - * '{11}=1 & {2346734}>5' * - * N_functionid - [IN] number of function in trigger expression * - * itemid - [OUT] ID of an item of N-th function in * - * expression * - * * - ******************************************************************************/ -static int get_N_itemid(const char *expression, int N_functionid, zbx_uint64_t *itemid) -{ - zbx_uint64_t functionid; - DC_FUNCTION function; - int errcode, ret = FAIL; - - zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s' N_functionid:%d", __func__, expression, N_functionid); - - if (SUCCEED == get_N_functionid(expression, N_functionid, &functionid, NULL)) - { - DCconfig_get_functions_by_functionids(&function, &functionid, &errcode, 1); - - if (SUCCEED == errcode) - { - *itemid = function.itemid; - ret = SUCCEED; - } - - DCconfig_clean_functions(&function, &errcode, 1); - } - - zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); - - return ret; -} - -/****************************************************************************** - * * - * Function: get_expanded_expression * - * * - * Purpose: get trigger expression with expanded user macros * - * * - * Comments: removes ' ', '\r', '\n' and '\t' for easier number search * - * * - ******************************************************************************/ -static char *get_expanded_expression(const char *expression) -{ - char *expression_ex; - - if (NULL != (expression_ex = DCexpression_expand_user_macros(expression))) - zbx_remove_whitespace(expression_ex); - - return expression_ex; -} - -/****************************************************************************** - * * * Function: get_trigger_expression_constant * * * * Purpose: get constant from a trigger expression corresponding a given * @@ -1072,14 +976,14 @@ static int DBget_item_value(zbx_uint64_t itemid, char **replace_to, int request) * otherwise FAIL * * * ******************************************************************************/ -static int DBget_trigger_value(const char *expression, char **replace_to, int N_functionid, int request) +static int DBget_trigger_value(const DB_TRIGGER *trigger, char **replace_to, int N_functionid, int request) { zbx_uint64_t itemid; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - if (SUCCEED == get_N_itemid(expression, N_functionid, &itemid)) + if (SUCCEED == zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid)) ret = DBget_item_value(itemid, replace_to, request); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -1480,7 +1384,7 @@ static int DBitem_get_value(zbx_uint64_t itemid, char **lastvalue, int raw, zbx_ * otherwise FAIL * * * ******************************************************************************/ -static int DBitem_value(const char *expression, char **value, int N_functionid, int clock, int ns, int raw) +static int DBitem_value(const DB_TRIGGER *trigger, char **value, int N_functionid, int clock, int ns, int raw) { zbx_uint64_t itemid; zbx_timespec_t ts = {clock, ns}; @@ -1488,7 +1392,7 @@ static int DBitem_value(const char *expression, char **value, int N_functionid, zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - if (SUCCEED == (ret = get_N_itemid(expression, N_functionid, &itemid))) + if (SUCCEED == (ret = zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid))) ret = DBitem_get_value(itemid, value, raw, &ts); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -1509,13 +1413,13 @@ static int DBitem_value(const char *expression, char **value, int N_functionid, * otherwise FAIL * * * ******************************************************************************/ -static int DBitem_lastvalue(const char *expression, char **lastvalue, int N_functionid, int raw) +static int DBitem_lastvalue(const DB_TRIGGER *trigger, char **lastvalue, int N_functionid, int raw) { int ret; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - ret = DBitem_value(expression, lastvalue, N_functionid, time(NULL), 999999999, raw); + ret = DBitem_value(trigger, lastvalue, N_functionid, time(NULL), 999999999, raw); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -2207,7 +2111,7 @@ static int get_action_value(const char *macro, zbx_uint64_t actionid, char **rep * otherwise FAIL * * * ******************************************************************************/ -static int get_host_inventory(const char *macro, const char *expression, char **replace_to, +static int get_host_inventory(const char *macro, const DB_TRIGGER *trigger, char **replace_to, int N_functionid) { int i; @@ -2218,7 +2122,7 @@ static int get_host_inventory(const char *macro, const char *expression, char ** { zbx_uint64_t itemid; - if (SUCCEED != get_N_itemid(expression, N_functionid, &itemid)) + if (SUCCEED != zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid)) return FAIL; return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx); @@ -2592,7 +2496,7 @@ static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_ * otherwise FAIL * * * ******************************************************************************/ -static int get_history_log_value(const char *m, const char *expression, char **replace_to, int N_functionid, +static int get_history_log_value(const char *m, const DB_TRIGGER *trigger, char **replace_to, int N_functionid, int clock, int ns, const char *tz) { zbx_uint64_t itemid; @@ -2627,7 +2531,7 @@ static int get_history_log_value(const char *m, const char *expression, char **r else /* MVAR_ITEM_LOG_TIME */ request = ZBX_REQUEST_ITEM_LOG_TIME; - if (SUCCEED == (ret = get_N_itemid(expression, N_functionid, &itemid))) + if (SUCCEED == (ret = zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid))) ret = DBget_history_log_value(itemid, replace_to, request, clock, ns, tz); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -2787,7 +2691,7 @@ static const char *func_macro_in_list(const char *str, zbx_token_func_macro_t *f * Comments: example: " {Zabbix server:{ITEM.KEY1}.last(0)} " to " 1.34 " * * * ******************************************************************************/ -static int get_trigger_function_value(const char *expression, char **replace_to, char *data, +static int get_trigger_function_value(const DB_TRIGGER *trigger, char **replace_to, char *data, const zbx_token_simple_macro_t *simple_macro, zbx_output_format_t format) { char *host = NULL, *key = NULL; @@ -2795,13 +2699,13 @@ static int get_trigger_function_value(const char *expression, char **replace_to, if (NULL != macro_in_list(data, simple_macro->host, simple_host_macros, &N_functionid)) { - if (SUCCEED != DBget_trigger_value(expression, &host, N_functionid, ZBX_REQUEST_HOST_HOST)) + if (SUCCEED != DBget_trigger_value(trigger, &host, N_functionid, ZBX_REQUEST_HOST_HOST)) goto out; } if (NULL != macro_in_list(data, simple_macro->key, simple_key_macros, &N_functionid)) { - if (SUCCEED != DBget_trigger_value(expression, &key, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG)) + if (SUCCEED != DBget_trigger_value(trigger, &key, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG)) goto out; } @@ -2827,33 +2731,6 @@ out: /****************************************************************************** * * - * Function: cache_trigger_hostids * - * * - * Purpose: cache host identifiers referenced by trigger expression * - * * - * Parameters: hostids - [OUT] the host identifier cache * - * expression - [IN] the trigger expression * - * recovery_expression - [IN] the trigger recovery expression * - * (can be empty) * - * * - ******************************************************************************/ -static void cache_trigger_hostids(zbx_vector_uint64_t *hostids, const char *expression, - const char *recovery_expression) -{ - if (0 == hostids->values_num) - { - zbx_vector_uint64_t functionids; - - zbx_vector_uint64_create(&functionids); - get_functionids(&functionids, expression); - get_functionids(&functionids, recovery_expression); - DCget_hostids_by_functionids(&functionids, hostids); - zbx_vector_uint64_destroy(&functionids); - } -} - -/****************************************************************************** - * * * Function: cache_item_hostid * * * * Purpose: cache host identifier referenced by an item or a lld-rule * @@ -2955,9 +2832,7 @@ static void resolve_opdata(const DB_EVENT *event, char **replace_to, const char if ('\0' == *event->trigger.opdata) { - int pos = 0; - zbx_token_t token; - zbx_uint64_t itemid; + int i; zbx_vector_uint64_t itemids; zbx_timespec_t ts; @@ -2965,38 +2840,22 @@ static void resolve_opdata(const DB_EVENT *event, char **replace_to, const char ts.ns = 999999999; zbx_vector_uint64_create(&itemids); + zbx_db_trigger_get_itemids(&event->trigger, &itemids); - for (; SUCCEED == zbx_token_find(event->trigger.expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++) + for (i = 0; i < itemids.values_num; i++) { - switch (token.type) - { - case ZBX_TOKEN_OBJECTID: - if (SUCCEED == get_N_itemid(event->trigger.expression + token.loc.l, 1, - &itemid) && - FAIL == zbx_vector_uint64_search(&itemids, itemid, - ZBX_DEFAULT_UINT64_COMPARE_FUNC)) - { - char *val = NULL; - - zbx_vector_uint64_append(&itemids, itemid); + char *val = NULL; - if (NULL != *replace_to) - *replace_to = zbx_strdcat(*replace_to, ", "); + if (NULL != *replace_to) + *replace_to = zbx_strdcat(*replace_to, ", "); - if (SUCCEED == DBitem_get_value(itemid, &val, 0, &ts)) - { - *replace_to = zbx_strdcat(*replace_to, val); - zbx_free(val); - } - else - *replace_to = zbx_strdcat(*replace_to, STR_UNKNOWN_VARIABLE); - } - ZBX_FALLTHROUGH; - case ZBX_TOKEN_USER_MACRO: - case ZBX_TOKEN_SIMPLE_MACRO: - case ZBX_TOKEN_MACRO: - pos = token.loc.r; + if (SUCCEED == DBitem_get_value(itemids.values[i], &val, 0, &ts)) + { + *replace_to = zbx_strdcat(*replace_to, val); + zbx_free(val); } + else + *replace_to = zbx_strdcat(*replace_to, STR_UNKNOWN_VARIABLE); } zbx_vector_uint64_destroy(&itemids); @@ -3024,16 +2883,17 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item, DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, const char *tz, char **data, int macro_type, char *error, int maxerrlen) { - char c, *replace_to = NULL, sql[64]; - const char *m; - int N_functionid, indexed_macro, require_address, ret, res = SUCCEED, - pos = 0, found, user_names_found = 0, raw_value; - size_t data_alloc, data_len; - DC_INTERFACE interface; - zbx_vector_uint64_t hostids; - zbx_token_t token, inner_token; - zbx_token_search_t token_search = ZBX_TOKEN_SEARCH_BASIC; - char *expression = NULL, *user_alias = NULL, *user_name = NULL, *user_surname = NULL; + char c, *replace_to = NULL, sql[64]; + const char *m; + int N_functionid, indexed_macro, require_address, ret, res = SUCCEED, + pos = 0, found, user_names_found = 0, raw_value; + size_t data_alloc, data_len; + DC_INTERFACE interface; + zbx_vector_uint64_t hostids; + const zbx_vector_uint64_t *phostids; + zbx_token_t token, inner_token; + zbx_token_search_t token_search = ZBX_TOKEN_SEARCH_BASIC; + char *expression = NULL, *user_alias = NULL, *user_name = NULL, *user_surname = NULL; if (NULL == data || NULL == *data || '\0' == **data) { @@ -3144,14 +3004,13 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT { if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, c_event->trigger.expression, - c_event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (ZBX_TOKEN_SIMPLE_MACRO == token.type) { - ret = get_trigger_function_value(c_event->trigger.expression, &replace_to, + ret = get_trigger_function_value(&c_event->trigger, &replace_to, *data, &token.data.simple_macro, ZBX_FORMAT_HUMAN); } else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION))) @@ -3221,113 +3080,112 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT } else if (0 == strcmp(m, MVAR_HOST_ID)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_ID); } else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_HOST); } else if (0 == strcmp(m, MVAR_HOST_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_NAME); } else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DESCRIPTION); } else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_IP); } else if (0 == strcmp(m, MVAR_HOST_DNS)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DNS); } else if (0 == strcmp(m, MVAR_HOST_CONN)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_CONN); } else if (0 == strcmp(m, MVAR_HOST_PORT)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_PORT); } else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) || 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE))) { - ret = get_host_inventory(m, c_event->trigger.expression, &replace_to, - N_functionid); + ret = get_host_inventory(m, &c_event->trigger, &replace_to, N_functionid); } else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION); } else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_ID)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_ID); } else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_KEY); } else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE)) { - ret = DBitem_lastvalue(c_event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_lastvalue(&c_event->trigger, &replace_to, N_functionid, raw_value); } else if (0 == strcmp(m, MVAR_ITEM_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_NAME); } else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_VALUE)) { - ret = DBitem_value(c_event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_value(&c_event->trigger, &replace_to, N_functionid, c_event->clock, c_event->ns, raw_value); } else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG))) { - ret = get_history_log_value(m, c_event->trigger.expression, &replace_to, + ret = get_history_log_value(m, &c_event->trigger, &replace_to, N_functionid, c_event->clock, c_event->ns, tz); } else if (0 == strcmp(m, MVAR_ITEM_VALUETYPE)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_VALUETYPE); } else if (0 == strcmp(m, MVAR_PROXY_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_PROXY_NAME); } else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION); } else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME)) @@ -3454,9 +3312,8 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT { if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, c_event->trigger.expression, - c_event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION))) @@ -3490,98 +3347,98 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT } else if (0 == strcmp(m, MVAR_HOST_ID)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_ID); } else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_HOST); } else if (0 == strcmp(m, MVAR_HOST_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_NAME); } else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DESCRIPTION); } else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_IP); } else if (0 == strcmp(m, MVAR_HOST_DNS)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DNS); } else if (0 == strcmp(m, MVAR_HOST_CONN)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_CONN); } else if (0 == strcmp(m, MVAR_HOST_PORT)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_PORT); } else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) || 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE))) { - ret = get_host_inventory(m, c_event->trigger.expression, &replace_to, + ret = get_host_inventory(m, &c_event->trigger, &replace_to, N_functionid); } else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION); } else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_ID)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_ID); } else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_KEY); } else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_NAME); } else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG); } else if (0 == strcmp(m, MVAR_ITEM_VALUETYPE)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_ITEM_VALUETYPE); } else if (0 == strcmp(m, MVAR_PROXY_NAME)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_PROXY_NAME); } else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION)) { - ret = DBget_trigger_value(c_event->trigger.expression, &replace_to, + ret = DBget_trigger_value(&c_event->trigger, &replace_to, N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION); } else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME)) @@ -4191,23 +4048,19 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT { if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, event->trigger.expression, - event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (ZBX_TOKEN_REFERENCE == token.type) { - /* try to expand trigger expression if it hasn't been done yet */ - if (NULL == expression && NULL == (expression = - get_expanded_expression(event->trigger.expression))) + if (SUCCEED != zbx_db_trigger_get_constant(&event->trigger, + token.data.reference.index, &replace_to)) { /* expansion failed, reference substitution is impossible */ token_search &= ~ZBX_TOKEN_SEARCH_REFERENCES; continue; } - - get_trigger_expression_constant(expression, &token.data.reference, &replace_to); } else if (ZBX_TOKEN_EXPRESSION_MACRO == inner_token.type) { @@ -4227,47 +4080,47 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT } else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_HOST); } else if (0 == strcmp(m, MVAR_HOST_NAME)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_NAME); } else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_IP); } else if (0 == strcmp(m, MVAR_HOST_DNS)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DNS); } else if (0 == strcmp(m, MVAR_HOST_CONN)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_CONN); } else if (0 == strcmp(m, MVAR_HOST_PORT)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_PORT); } else if (0 == strcmp(m, MVAR_ITEM_VALUE)) { - ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_value(&event->trigger, &replace_to, N_functionid, event->clock, event->ns, raw_value); } else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG))) { - ret = get_history_log_value(m, event->trigger.expression, &replace_to, + ret = get_history_log_value(m, &event->trigger, &replace_to, N_functionid, event->clock, event->ns, tz); } else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE)) { - ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid, raw_value); } else if (0 == strcmp(m, MVAR_TIME) && 0 != (macro_type & MACRO_TYPE_EVENT_NAME)) @@ -4305,44 +4158,43 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT { if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, event->trigger.expression, - event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (0 == strcmp(m, MVAR_HOST_ID)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_ID); } else if (0 == strcmp(m, MVAR_HOST_HOST)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_HOST); } else if (0 == strcmp(m, MVAR_HOST_NAME)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_NAME); } else if (0 == strcmp(m, MVAR_HOST_IP)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_IP); } else if (0 == strcmp(m, MVAR_HOST_DNS)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DNS); } else if (0 == strcmp(m, MVAR_HOST_CONN)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_CONN); } else if (0 == strcmp(m, MVAR_HOST_PORT)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_PORT); } else if (0 == strcmp(m, MVAR_TRIGGER_ID)) @@ -4351,17 +4203,17 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT } else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE)) { - ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid, raw_value); } else if (0 == strcmp(m, MVAR_ITEM_VALUE)) { - ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_value(&event->trigger, &replace_to, N_functionid, event->clock, event->ns, raw_value); } else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG))) { - ret = get_history_log_value(m, event->trigger.expression, &replace_to, + ret = get_history_log_value(m, &event->trigger, &replace_to, N_functionid, event->clock, event->ns, tz); } else if (0 == strcmp(m, MVAR_EVENT_ID)) @@ -4679,64 +4531,63 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT { if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, event->trigger.expression, - event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY))) { - ret = get_host_inventory(m, event->trigger.expression, &replace_to, + ret = get_host_inventory(m, &event->trigger, &replace_to, N_functionid); } else if (0 == strcmp(m, MVAR_HOST_ID)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_ID); } else if (0 == strcmp(m, MVAR_HOST_HOST)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_HOST); } else if (0 == strcmp(m, MVAR_HOST_NAME)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_NAME); } else if (0 == strcmp(m, MVAR_HOST_IP)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_IP); } else if (0 == strcmp(m, MVAR_HOST_DNS)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_DNS); } else if (0 == strcmp(m, MVAR_HOST_CONN)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_CONN); } else if (0 == strcmp(m, MVAR_HOST_PORT)) { - ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid, ZBX_REQUEST_HOST_PORT); } else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE)) { - ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid, raw_value); } else if (0 == strcmp(m, MVAR_ITEM_VALUE)) { - ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid, + ret = DBitem_value(&event->trigger, &replace_to, N_functionid, event->clock, event->ns, raw_value); } else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG))) { - ret = get_history_log_value(m, event->trigger.expression, &replace_to, + ret = get_history_log_value(m, &event->trigger, &replace_to, N_functionid, event->clock, event->ns, tz); } else if (0 == strcmp(m, MVAR_TRIGGER_ID)) @@ -4805,14 +4656,13 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT if (ZBX_TOKEN_USER_MACRO == token.type) { - cache_trigger_hostids(&hostids, c_event->trigger.expression, - c_event->trigger.recovery_expression); - DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to); + if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger, &phostids)) + DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); pos = token.loc.r; } else if (ZBX_TOKEN_SIMPLE_MACRO == token.type) { - ret = get_trigger_function_value(c_event->trigger.expression, &replace_to, + ret = get_trigger_function_value(&c_event->trigger, &replace_to, *data, &token.data.simple_macro, ZBX_FORMAT_RAW); } } @@ -4880,61 +4730,24 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT return res; } -static int extract_expression_functionids(zbx_vector_uint64_t *functionids, const char *expression) -{ - const char *bl, *br; - zbx_uint64_t functionid; - - for (bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{')) - { - if (NULL == (br = strchr(bl, '}'))) - break; - - if (SUCCEED != is_uint64_n(bl + 1, br - bl - 1, &functionid)) - break; - - zbx_vector_uint64_append(functionids, functionid); - - bl = br + 1; - } - - return (NULL == bl ? SUCCEED : FAIL); -} - static void zbx_extract_functionids(zbx_vector_uint64_t *functionids, zbx_vector_ptr_t *triggers) { DC_TRIGGER *tr; - int i, values_num_save; + int i; zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __func__, triggers->values_num); for (i = 0; i < triggers->values_num; i++) { - const char *error_expression = NULL; - tr = (DC_TRIGGER *)triggers->values[i]; if (NULL != tr->new_error) continue; - values_num_save = functionids->values_num; + zbx_eval_get_functionids(tr->eval_ctx, functionids); - if (SUCCEED != extract_expression_functionids(functionids, tr->expression)) - { - error_expression = tr->expression; - } - else if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode && - SUCCEED != extract_expression_functionids(functionids, tr->recovery_expression)) - { - error_expression = tr->recovery_expression; - } - - if (NULL != error_expression) - { - tr->new_error = zbx_dsprintf(tr->new_error, "Invalid expression [%s]", error_expression); - tr->new_value = TRIGGER_VALUE_UNKNOWN; - functionids->values_num = values_num_save; - } + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode) + zbx_eval_get_functionids(tr->eval_ctx_r, functionids); } zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); @@ -4963,18 +4776,23 @@ zbx_trigger_func_position_t; * Author: Andrea Biscuola * * * ******************************************************************************/ -static int expand_trigger_macros(DB_EVENT *event, DC_TRIGGER *trigger, char *error, size_t maxerrlen) +static int expand_trigger_macros(zbx_eval_context_t *ctx, const DB_EVENT *event, char *error, size_t maxerrlen) { - if (FAIL == substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &trigger->expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen)) - { - return FAIL; - } + int i; - if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode) + for (i = 0; i < ctx->stack.values_num; i++) { + zbx_eval_token_t *token = &ctx->stack.values[i]; + + if (ZBX_EVAL_TOKEN_VAR_MACRO != token->type && ZBX_EVAL_TOKEN_VAR_STR != token->type) + continue; + + /* all trigger macros macros are already extracted into strings */ + if (ZBX_VARIANT_STR != token->value.type) + continue; + if (FAIL == substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &trigger->recovery_expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen)) + &token->value.data.str, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen)) { return FAIL; } @@ -5001,7 +4819,6 @@ static void zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos { zbx_vector_uint64_t funcids; DC_TRIGGER *tr; - DB_EVENT ev; int i; zabbix_log(LOG_LEVEL_DEBUG, "In %s() trigger_order_num:%d", __func__, trigger_order->values_num); @@ -5009,8 +4826,6 @@ static void zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos zbx_vector_uint64_create(&funcids); zbx_vector_uint64_reserve(&funcids, functionids->values_num); - ev.object = EVENT_OBJECT_TRIGGER; - for (i = 0; i < trigger_order->values_num; i++) { zbx_trigger_func_position_t *tr_func_pos; @@ -5020,20 +4835,14 @@ static void zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos if (NULL != tr->new_error) continue; - ev.value = tr->value; - - expand_trigger_macros(&ev, tr, NULL, 0); - - if (SUCCEED == extract_expression_functionids(&funcids, tr->expression)) - { - tr_func_pos = (zbx_trigger_func_position_t *)zbx_malloc(NULL, sizeof(zbx_trigger_func_position_t)); - tr_func_pos->trigger = tr; - tr_func_pos->start_index = functionids->values_num; - tr_func_pos->count = funcids.values_num; + zbx_eval_get_functionids(tr->eval_ctx, &funcids); + tr_func_pos = (zbx_trigger_func_position_t *)zbx_malloc(NULL, sizeof(zbx_trigger_func_position_t)); + tr_func_pos->trigger = tr; + tr_func_pos->start_index = functionids->values_num; + tr_func_pos->count = funcids.values_num; - zbx_vector_uint64_append_array(functionids, funcids.values, funcids.values_num); - zbx_vector_ptr_append(triggers_func_pos, tr_func_pos); - } + zbx_vector_uint64_append_array(functionids, funcids.values, funcids.values_num); + zbx_vector_ptr_append(triggers_func_pos, tr_func_pos); zbx_vector_uint64_clear(&funcids); } @@ -5117,7 +4926,7 @@ typedef struct zbx_timespec_t timespec; /* output data */ - char *value; + zbx_variant_t value; char *error; } zbx_func_t; @@ -5169,8 +4978,9 @@ static void func_clean(void *ptr) zbx_free(func->function); zbx_free(func->parameter); - zbx_free(func->value); zbx_free(func->error); + + zbx_variant_clear(&func->value); } /****************************************************************************** @@ -5198,7 +5008,7 @@ static void zbx_populate_function_items(const zbx_vector_uint64_t *functionids, zabbix_log(LOG_LEVEL_DEBUG, "In %s() functionids_num:%d", __func__, functionids->values_num); - func_local.value = NULL; + zbx_variant_set_none(&func_local.value); func_local.error = NULL; functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids->values_num); @@ -5248,7 +5058,7 @@ static void zbx_populate_function_items(const zbx_vector_uint64_t *functionids, zabbix_log(LOG_LEVEL_DEBUG, "End of %s() ifuncs_num:%d", __func__, ifuncs->num_data); } -static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t *unknown_msgs) +static void zbx_evaluate_item_functions(zbx_hashset_t *funcs) { DC_ITEM *items = NULL; char *error = NULL; @@ -5278,8 +5088,7 @@ static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t * zbx_hashset_iter_reset(funcs, &iter); while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter))) { - int ret_unknown = 0; /* flag raised if current function evaluates to ZBX_UNKNOWN */ - char *unknown_msg; + char *value = NULL; i = zbx_vector_uint64_bsearch(&itemids, func->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC); @@ -5309,59 +5118,40 @@ static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t * continue; } - /* If the item is NOTSUPPORTED then evaluation is allowed for: */ - /* - time-based functions and nodata(). Their values can be */ - /* evaluated to regular numbers even for NOTSUPPORTED items. */ - /* - other functions. Result of evaluation is ZBX_UNKNOWN. */ - - if (ITEM_STATE_NOTSUPPORTED == items[i].state && FAIL == evaluatable_for_notsupported(func->function)) + if (ITEM_STATE_NOTSUPPORTED == items[i].state && + FAIL == zbx_evaluatable_for_notsupported(func->function)) { - /* compose and store 'unknown' message for future use */ - unknown_msg = zbx_dsprintf(NULL, + /* set 'unknown' error value */ + zbx_variant_set_error(&func->value, zbx_dsprintf(NULL, "Cannot evaluate function \"%s:%s.%s(%s)\": item is not supported.", - items[i].host.host, items[i].key_orig, func->function, func->parameter); - - zbx_free(func->error); - zbx_vector_ptr_append(unknown_msgs, unknown_msg); - ret_unknown = 1; + items[i].host.host, items[i].key_orig, func->function, func->parameter)); + continue; } - if (0 == ret_unknown && SUCCEED != evaluate_function(&func->value, &items[i], func->function, - func->parameter, &func->timespec, &error)) + if (SUCCEED != evaluate_function(&value, &items[i], func->function, func->parameter, &func->timespec, + &error)) { /* compose and store error message for future use */ if (NULL != error) { - unknown_msg = zbx_dsprintf(NULL, + zbx_variant_set_error(&func->value, zbx_dsprintf(NULL, "Cannot evaluate function \"%s:%s.%s(%s)\": %s.", items[i].host.host, items[i].key_orig, func->function, - func->parameter, error); - - zbx_free(func->error); + func->parameter, error)); zbx_free(error); } else { - unknown_msg = zbx_dsprintf(NULL, + zbx_variant_set_error(&func->value, zbx_dsprintf(NULL, "Cannot evaluate function \"%s:%s.%s(%s)\".", items[i].host.host, items[i].key_orig, - func->function, func->parameter); - - zbx_free(func->error); + func->function, func->parameter)); } - zbx_vector_ptr_append(unknown_msgs, unknown_msg); - ret_unknown = 1; + continue; } - if (0 != ret_unknown) - { - char buffer[MAX_ID_LEN + 1]; - /* write a special token of unknown value with 'unknown' message number, like */ - /* ZBX_UNKNOWN0, ZBX_UNKNOWN1 etc. not wrapped in () */ - zbx_snprintf(buffer, sizeof(buffer), ZBX_UNKNOWN_STR "%d", unknown_msgs->values_num - 1); - func->value = zbx_strdup(func->value, buffer); - } + zbx_variant_set_str(&func->value, value); } DCconfig_clean_items(items, errcodes, itemids.values_num); @@ -5373,34 +5163,30 @@ static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t * zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } -static int substitute_expression_functions_results(zbx_hashset_t *ifuncs, char *expression, char **out, - size_t *out_alloc, char **error) +static int substitute_expression_functions_results(zbx_hashset_t *ifuncs, zbx_eval_context_t *ctx, char **error) { - char *br, *bl; - size_t out_offset = 0; zbx_uint64_t functionid; zbx_func_t *func; zbx_ifunc_t *ifunc; + int i; - for (br = expression, bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{')) + for (i = 0; i < ctx->stack.values_num; i++) { - *bl = '\0'; - zbx_strcpy_alloc(out, out_alloc, &out_offset, br); - *bl = '{'; + zbx_eval_token_t *token = &ctx->stack.values[i]; - if (NULL == (br = strchr(bl, '}'))) + if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type) + continue; + + if (ZBX_VARIANT_UI64 != token->value.type) { - *error = zbx_strdup(*error, "Invalid trigger expression"); + /* functionids should be already extracted into uint64 vars */ + THIS_SHOULD_NEVER_HAPPEN; + *error = zbx_dsprintf(*error, "Cannot parse function at: \"%s\"", + ctx->expression + token->loc.l); return FAIL; } - *br = '\0'; - - ZBX_STR2UINT64(functionid, bl + 1); - - *br++ = '}'; - bl = br; - + functionid = token->value.data.ui64; if (NULL == (ifunc = (zbx_ifunc_t *)zbx_hashset_search(ifuncs, &functionid))) { *error = zbx_dsprintf(*error, "Cannot obtain function" @@ -5416,39 +5202,39 @@ static int substitute_expression_functions_results(zbx_hashset_t *ifuncs, char * return FAIL; } - if (NULL == func->value) + if (ZBX_VARIANT_NONE == func->value.type) { *error = zbx_strdup(*error, "Unexpected error while processing a trigger expression"); return FAIL; } - if (SUCCEED != is_double_suffix(func->value, ZBX_FLAG_DOUBLE_SUFFIX) || '-' == *func->value) - { - zbx_chrcpy_alloc(out, out_alloc, &out_offset, '('); - zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value); - zbx_chrcpy_alloc(out, out_alloc, &out_offset, ')'); - } - else - zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value); + zbx_variant_copy(&token->value, &func->value); } - zbx_strcpy_alloc(out, out_alloc, &out_offset, br); - return SUCCEED; } +static void log_expression(const char *prefix, int index, const zbx_eval_context_t *ctx) +{ + if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG)) + { + char *expression = NULL; + + zbx_eval_compose_expression(ctx, &expression); + zabbix_log(LOG_LEVEL_DEBUG, "%s() expression[%d]:'%s' => '%s'", prefix, index, ctx->expression, + expression); + zbx_free(expression); + } +} + static void zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_ptr_t *triggers) { DC_TRIGGER *tr; - char *out = NULL; - size_t out_alloc = TRIGGER_EXPRESSION_LEN_MAX; int i; zabbix_log(LOG_LEVEL_DEBUG, "In %s() ifuncs_num:%d tr_num:%d", __func__, ifuncs->num_data, triggers->values_num); - out = (char *)zbx_malloc(out, out_alloc); - for (i = 0; i < triggers->values_num; i++) { tr = (DC_TRIGGER *)triggers->values[i]; @@ -5456,35 +5242,26 @@ static void zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_p if (NULL != tr->new_error) continue; - if( SUCCEED != substitute_expression_functions_results(ifuncs, tr->expression, &out, &out_alloc, - &tr->new_error)) + if( SUCCEED != substitute_expression_functions_results(ifuncs, tr->eval_ctx, &tr->new_error)) { tr->new_value = TRIGGER_VALUE_UNKNOWN; continue; } - zabbix_log(LOG_LEVEL_DEBUG, "%s() expression[%d]:'%s' => '%s'", __func__, i, tr->expression, out); - - tr->expression = zbx_strdup(tr->expression, out); + log_expression(__func__, i, tr->eval_ctx); if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode) { - if (SUCCEED != substitute_expression_functions_results(ifuncs, - tr->recovery_expression, &out, &out_alloc, &tr->new_error)) + if (SUCCEED != substitute_expression_functions_results(ifuncs, tr->eval_ctx_r, &tr->new_error)) { tr->new_value = TRIGGER_VALUE_UNKNOWN; continue; } - zabbix_log(LOG_LEVEL_DEBUG, "%s() recovery_expression[%d]:'%s' => '%s'", __func__, i, - tr->recovery_expression, out); - - tr->recovery_expression = zbx_strdup(tr->recovery_expression, out); + log_expression(__func__, i, tr->eval_ctx_r); } } - zbx_free(out); - zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } @@ -5504,7 +5281,7 @@ static void zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_p * Comments: example: "({15}>10) or ({123}=1)" => "(26.416>10) or (0=1)" * * * ******************************************************************************/ -static void substitute_functions(zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *unknown_msgs) +static void substitute_functions(zbx_vector_ptr_t *triggers) { zbx_vector_uint64_t functionids; zbx_hashset_t ifuncs, funcs; @@ -5527,7 +5304,7 @@ static void substitute_functions(zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *u if (0 != ifuncs.num_data) { - zbx_evaluate_item_functions(&funcs, unknown_msgs); + zbx_evaluate_item_functions(&funcs); zbx_substitute_functions_results(&ifuncs, triggers); } @@ -5541,6 +5318,65 @@ empty: /****************************************************************************** * * + * Function: prepare_triggers * + * * + * Purpose: prepare triggers for evaluation * + * * + * Parameters: triggers - [IN] array of DC_TRIGGER pointers * + * triggres_num - [IN] the number of triggers to prepare * + * * + ******************************************************************************/ +void prepare_triggers(DC_TRIGGER **triggers, int triggers_num) +{ + int i; + + for (i = 0; i < triggers_num; i++) + { + DC_TRIGGER *tr = triggers[i]; + + tr->eval_ctx = zbx_eval_deserialize_dyn(tr->expression_bin, tr->expression, ZBX_EVAL_EXCTRACT_ALL); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode) + { + tr->eval_ctx_r = zbx_eval_deserialize_dyn(tr->recovery_expression_bin, tr->recovery_expression, + ZBX_EVAL_EXCTRACT_ALL); + } + } +} + +static int evaluate_expression(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, double *result, + char **error) +{ + zbx_variant_t value; + + if (SUCCEED != zbx_eval_execute(ctx, ts, &value, error)) + return FAIL; + + if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG)) + { + char *expression = NULL; + + zbx_eval_compose_expression(ctx, &expression); + zabbix_log(LOG_LEVEL_DEBUG, "%s(): %s => %s", __func__, expression, zbx_variant_value_desc(&value)); + zbx_free(expression); + } + + if (SUCCEED != zbx_variant_convert(&value, ZBX_VARIANT_DBL)) + { + *error = zbx_dsprintf(*error, "Cannot convert expression result of type \"%s\" to" + " floating point value", zbx_variant_type_desc(&value)); + zbx_variant_clear(&value); + + return FAIL; + } + + *result = value.data.dbl; + + return SUCCEED; +} + +/****************************************************************************** + * * * Function: evaluate_expressions * * * * Purpose: evaluate trigger expressions * @@ -5557,7 +5393,6 @@ void evaluate_expressions(zbx_vector_ptr_t *triggers) DC_TRIGGER *tr; int i; double expr_result; - zbx_vector_ptr_t unknown_msgs; /* pointers to messages about origins of 'unknown' values */ char err[MAX_STRING_LEN]; zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __func__, triggers->values_num); @@ -5570,18 +5405,21 @@ void evaluate_expressions(zbx_vector_ptr_t *triggers) event.value = tr->value; - if (SUCCEED != expand_trigger_macros(&event, tr, err, sizeof(err))) + if (SUCCEED != expand_trigger_macros(tr->eval_ctx, &event, err, sizeof(err))) { tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err); tr->new_value = TRIGGER_VALUE_UNKNOWN; } - } - /* Assumption: most often there will be no NOTSUPPORTED items and function errors. */ - /* Therefore initialize error messages vector but do not reserve any space. */ - zbx_vector_ptr_create(&unknown_msgs); + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode && + SUCCEED != expand_trigger_macros(tr->eval_ctx_r, &event, err, sizeof(err))) + { + tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err); + tr->new_value = TRIGGER_VALUE_UNKNOWN; + } + } - substitute_functions(triggers, &unknown_msgs); + substitute_functions(triggers); /* calculate new trigger values based on their recovery modes and expression evaluations */ for (i = 0; i < triggers->values_num; i++) @@ -5591,12 +5429,8 @@ void evaluate_expressions(zbx_vector_ptr_t *triggers) if (NULL != tr->new_error) continue; - if (SUCCEED != evaluate(&expr_result, tr->expression, err, sizeof(err), &unknown_msgs)) - { - tr->new_error = zbx_strdup(tr->new_error, err); - tr->new_value = TRIGGER_VALUE_UNKNOWN; + if (SUCCEED != evaluate_expression(tr->eval_ctx, &tr->timespec, &expr_result, &tr->new_error)) continue; - } /* trigger expression evaluates to true, set PROBLEM value */ if (SUCCEED != zbx_double_compare(expr_result, 0.0)) @@ -5624,9 +5458,8 @@ void evaluate_expressions(zbx_vector_ptr_t *triggers) } /* processing recovery expression mode */ - if (SUCCEED != evaluate(&expr_result, tr->recovery_expression, err, sizeof(err), &unknown_msgs)) + if (SUCCEED != evaluate_expression(tr->eval_ctx_r, &tr->timespec, &expr_result, &tr->new_error)) { - tr->new_error = zbx_strdup(tr->new_error, err); tr->new_value = TRIGGER_VALUE_UNKNOWN; continue; } @@ -5642,9 +5475,6 @@ void evaluate_expressions(zbx_vector_ptr_t *triggers) tr->new_value = TRIGGER_VALUE_NONE; } - zbx_vector_ptr_clear_ext(&unknown_msgs, zbx_ptr_free); - zbx_vector_ptr_destroy(&unknown_msgs); - if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG)) { for (i = 0; i < triggers->values_num; i++) diff --git a/src/libs/zbxsysinfo/sysinfo.c b/src/libs/zbxsysinfo/sysinfo.c index 9460f1f58d3..1cdec05eb76 100644 --- a/src/libs/zbxsysinfo/sysinfo.c +++ b/src/libs/zbxsysinfo/sysinfo.c @@ -187,8 +187,6 @@ int add_user_parameter(const char *itemkey, char *command, char *error, size_t m metric.function = &EXECUTE_USER_PARAMETER; metric.test_param = command; - printf("[WDN] itemkey=%s, command=%s, metric.key=%s\n", itemkey, command, metric.key); - ret = add_metric(&metric, error, max_error_len); } else diff --git a/src/libs/zbxtrends/trends.c b/src/libs/zbxtrends/trends.c index 674dcd2d670..3ed8d841898 100644 --- a/src/libs/zbxtrends/trends.c +++ b/src/libs/zbxtrends/trends.c @@ -90,17 +90,16 @@ static int trends_parse_base(const char *period_shift, zbx_time_unit_t *base, ch ******************************************************************************/ int zbx_trends_parse_base(const char *params, zbx_time_unit_t *base, char **error) { - char *period_shift; + const char *period_shift; int ret = FAIL; - if (NULL == (period_shift = zbx_function_get_param_dyn(params, 2))) + if (NULL == (period_shift = strchr(params, ':'))) { *error = zbx_strdup(*error, "missing period shift parameter"); return FAIL; } - ret = trends_parse_base(period_shift, base, error); - zbx_free(period_shift); + ret = trends_parse_base(period_shift + 1, base, error); return ret; } diff --git a/src/zabbix_server/escalator/escalator.c b/src/zabbix_server/escalator/escalator.c index bd22ccbc22f..52a12fa6d16 100644 --- a/src/zabbix_server/escalator/escalator.c +++ b/src/zabbix_server/escalator/escalator.c @@ -1823,7 +1823,12 @@ static int check_escalation_trigger(zbx_uint64_t triggerid, unsigned char source zbx_vector_uint64_create(&functionids); zbx_vector_uint64_create(&itemids); - get_functionids(&functionids, trigger.expression_orig); + zbx_get_serialized_expression_functionids(trigger.expression, trigger.expression_bin, &functionids); + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger.recovery_mode) + { + zbx_get_serialized_expression_functionids(trigger.recovery_expression, trigger.recovery_expression_bin, + &functionids); + } functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids.values_num); errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids.values_num); diff --git a/src/zabbix_server/events.c b/src/zabbix_server/events.c index c2e9b98818b..d4c8439b5da 100644 --- a/src/zabbix_server/events.c +++ b/src/zabbix_server/events.c @@ -155,12 +155,12 @@ static void process_item_tag(DB_EVENT* event, const zbx_item_tag_t *item_tag) validate_and_add_tag(event, t); } -static void get_item_tags_by_expression(const char *expression, zbx_vector_ptr_t *item_tags) +static void get_item_tags_by_expression(const DB_TRIGGER *trigger, zbx_vector_ptr_t *item_tags) { zbx_vector_uint64_t functionids; zbx_vector_uint64_create(&functionids); - get_functionids(&functionids, expression); + zbx_db_trigger_get_functionids(trigger, &functionids); zbx_dc_get_item_tags_by_functionids(functionids.values, functionids.values_num, item_tags); zbx_vector_uint64_destroy(&functionids); } @@ -240,6 +240,9 @@ DB_EVENT *zbx_add_event(unsigned char source, unsigned char object, zbx_uint64_t event->trigger.opdata = zbx_strdup(NULL, trigger_opdata); event->trigger.event_name = (NULL != event_name ? zbx_strdup(NULL, event_name) : NULL); event->name = zbx_strdup(NULL, (NULL != event_name ? event_name : trigger_description)); + event->trigger.cache = NULL; + event->trigger.url = NULL; + event->trigger.comments = NULL; substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &event->trigger.correlation_tag, MACRO_TYPE_TRIGGER_TAG, err, sizeof(err)); @@ -256,7 +259,7 @@ DB_EVENT *zbx_add_event(unsigned char source, unsigned char object, zbx_uint64_t } zbx_vector_ptr_create(&item_tags); - get_item_tags_by_expression(trigger_expression, &item_tags); + get_item_tags_by_expression(&event->trigger, &item_tags); for (i = 0; i < item_tags.values_num; i++) { @@ -1476,7 +1479,7 @@ static void flush_correlation_queue(zbx_vector_ptr_t *trigger_diff, zbx_vector_u close_trigger_event(recovery->eventid, recovery->objectid, &recovery->ts, 0, recovery->correlationid, recovery->c_eventid, trigger->description, - trigger->expression_orig, trigger->recovery_expression_orig, + trigger->expression, trigger->recovery_expression, trigger->priority, trigger->type, trigger->opdata, trigger->event_name); closed_num++; @@ -1696,12 +1699,9 @@ static void zbx_clean_event(DB_EVENT *event) if (EVENT_SOURCE_TRIGGERS == event->source) { - zbx_free(event->trigger.description); - zbx_free(event->trigger.expression); - zbx_free(event->trigger.recovery_expression); + zbx_db_trigger_clean(&event->trigger); + zbx_free(event->trigger.correlation_tag); - zbx_free(event->trigger.opdata); - zbx_free(event->trigger.event_name); zbx_vector_ptr_clear_ext(&event->tags, (zbx_clean_func_t)zbx_free_tag); zbx_vector_ptr_destroy(&event->tags); @@ -1726,18 +1726,17 @@ void zbx_clean_events(void) /****************************************************************************** * * - * Function: get_hosts_by_expression * + * Function: db_trigger_get_hosts * * * - * Purpose: get hosts that are used in expression * + * Purpose: get hosts that are used trigger expression/recovery expression * * * ******************************************************************************/ -static void get_hosts_by_expression(zbx_hashset_t *hosts, const char *expression, const char *recovery_expression) +static void db_trigger_get_hosts(zbx_hashset_t *hosts, DB_TRIGGER *trigger) { zbx_vector_uint64_t functionids; zbx_vector_uint64_create(&functionids); - get_functionids(&functionids, expression); - get_functionids(&functionids, recovery_expression); + zbx_db_trigger_get_all_functionids(trigger, &functionids); DCget_hosts_by_functionids(&functionids, hosts); zbx_vector_uint64_destroy(&functionids); } @@ -1793,8 +1792,7 @@ void zbx_export_events(void) zbx_json_adduint64(&json, ZBX_PROTO_TAG_EVENTID, event->eventid); zbx_json_addstring(&json, ZBX_PROTO_TAG_NAME, event->name, ZBX_JSON_TYPE_STRING); - get_hosts_by_expression(&hosts, event->trigger.expression, - event->trigger.recovery_expression); + db_trigger_get_hosts(&hosts, &event->trigger); zbx_json_addarray(&json, ZBX_PROTO_TAG_HOSTS); @@ -1901,8 +1899,7 @@ static void add_event_suppress_data(zbx_vector_ptr_t *event_refs, zbx_vector_uin query->eventid = event->eventid; zbx_vector_uint64_create(&query->functionids); - get_functionids(&query->functionids, event->trigger.expression); - get_functionids(&query->functionids, event->trigger.recovery_expression); + zbx_db_trigger_get_all_functionids(&event->trigger, &query->functionids); zbx_vector_ptr_create(&query->tags); if (0 != event->tags.values_num) @@ -2813,7 +2810,7 @@ int zbx_close_problem(zbx_uint64_t triggerid, zbx_uint64_t eventid, zbx_uint64_t DBbegin(); r_event = close_trigger_event(eventid, triggerid, &ts, userid, 0, 0, trigger.description, - trigger.expression_orig, trigger.recovery_expression_orig, trigger.priority, + trigger.expression, trigger.recovery_expression, trigger.priority, trigger.type, trigger.opdata, trigger.event_name); r_event->eventid = DBget_maxid_num("events", 1); diff --git a/src/zabbix_server/poller/checks_calculated.c b/src/zabbix_server/poller/checks_calculated.c index 26fe1b89f7b..e0216dec64b 100644 --- a/src/zabbix_server/poller/checks_calculated.c +++ b/src/zabbix_server/poller/checks_calculated.c @@ -240,7 +240,7 @@ static int calcitem_evaluate_expression(expression_t *exp, char *error, size_t m /* NOTSUPPORTED items. */ /* - other functions. Result of evaluation is ZBX_UNKNOWN. */ - if (ITEM_STATE_NOTSUPPORTED == items[i].state && FAIL == evaluatable_for_notsupported(f->func)) + if (ITEM_STATE_NOTSUPPORTED == items[i].state && FAIL == zbx_evaluatable_for_notsupported(f->func)) { /* compose and store 'unknown' message for future use */ unknown_msg = zbx_dsprintf(NULL, diff --git a/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.c b/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.c index d35438ff898..0eadec95d61 100644 --- a/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.c +++ b/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.c @@ -30,16 +30,21 @@ int zbx_dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, time_t from, zbx_uint64_t seed); -static int str_to_function_type(const char *str) +/* copiedf from zbxdbcache/dbconfig.c */ +#define ZBX_TRIGGER_TIMER_TRIGGER 0x0001 +#define ZBX_TRIGGER_TIMER_FUNCTION_TIME 0x0002 +#define ZBX_TRIGGER_TIMER_FUNCTION_TREND 0x0004 + +static int str_to_timer_type(const char *str) { - if (0 == strcmp(str, "ZBX_FUNCTION_TYPE_TIMER")) - return ZBX_FUNCTION_TYPE_TIMER; - if (0 == strcmp(str, "ZBX_FUNCTION_TYPE_TRENDS")) - return ZBX_FUNCTION_TYPE_TRENDS; - if (0 == strcmp(str, "ZBX_FUNCTION_TYPE_HISTORY")) - return ZBX_FUNCTION_TYPE_HISTORY; + if (0 == strcmp(str, "ZBX_TRIGGER_TIMER_TRIGGER")) + return ZBX_TRIGGER_TIMER_TRIGGER; + if (0 == strcmp(str, "ZBX_TRIGGER_TIMER_FUNCTION_TIME")) + return ZBX_TRIGGER_TIMER_FUNCTION_TIME; + if (0 == strcmp(str, "ZBX_TRIGGER_TIMER_FUNCTION_TREND")) + return ZBX_TRIGGER_TIMER_FUNCTION_TREND; - fail_msg("unknown function type \"%s\"", str); + fail_msg("unknown timer type \"%s\"", str); return ZBX_FUNCTION_TYPE_UNKNOWN; } @@ -60,10 +65,10 @@ void zbx_mock_test_entry(void **state) if (ZBX_MOCK_SUCCESS != zbx_strtime_to_timespec(zbx_mock_get_parameter_string("in.time"), &ts_from)) fail_msg("Invalid input time format"); - timer.type = str_to_function_type(zbx_mock_get_parameter_string("in.type")); + timer.type = str_to_timer_type(zbx_mock_get_parameter_string("in.type")); timer.parameter = zbx_mock_get_parameter_string("in.params"); - if (ZBX_FUNCTION_TYPE_TRENDS == timer.type) + if (ZBX_TRIGGER_TIMER_FUNCTION_TREND == timer.type) { if (SUCCEED != zbx_trends_parse_base(timer.parameter, &timer.trend_base, &error)) { diff --git a/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.yaml b/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.yaml index 4c3414e3b74..de7cff99cb5 100644 --- a/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.yaml +++ b/tests/libs/zbxdbcache/dc_function_calculate_nextcheck.yaml @@ -1,7 +1,7 @@ --- test case: Schedule time based trigger from 2020-09-01 00:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TIMER + type: ZBX_TRIGGER_TIMER_FUNCTION_TIME params: timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 @@ -10,7 +10,7 @@ out: --- test case: Schedule time based trigger from 2020-09-01 00:00:15.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TIMER + type: ZBX_TRIGGER_TIMER_FUNCTION_TIME params: timezone: :Europe/Riga time: 2020-09-01 00:00:15.000000000 +03:00 @@ -19,107 +19,107 @@ out: --- test case: Schedule time based trigger from 2020-09-01 00:00:30.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TIMER + type: ZBX_TRIGGER_TIMER_FUNCTION_TIME params: timezone: :Europe/Riga time: 2020-09-01 00:00:30.000000000 +03:00 out: nextcheck: 2020-09-01 00:01:00.000000000 +03:00 --- -test case: Schedule 1h,now/h 2020-09-01 10:30:30.000000000 +03:00 +test case: Schedule 1h:now/h 2020-09-01 10:30:30.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/h timezone: :Europe/Riga time: 2020-09-01 10:30:30.000000000 +03:00 out: nextcheck: 2020-09-01 11:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/h 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 1h:now/h 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/h timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-09-01 10:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/h 2020-09-01 10:59:00.000000000 +03:00 +test case: Schedule 1h:now/h 2020-09-01 10:59:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/h timezone: :Europe/Riga time: 2020-09-01 10:59:00.000000000 +03:00 out: nextcheck: 2020-09-01 11:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/d 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 1h:now/d 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/d + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-09-02 00:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/M+1h 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 1h:now/M+1h 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/M+1h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/M+1h timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-10-01 01:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/M+1d 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 1h:now/M+1d 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/M+1d + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/M+1d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-09-02 00:10:00.000000000 +03:00 --- -test case: Schedule 1h,now/M+1d 2020-09-02 10:00:00.000000000 +03:00 +test case: Schedule 1h:now/M+1d 2020-09-02 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/M+1d + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/M+1d timezone: :Europe/Riga time: 2020-09-02 10:00:00.000000000 +03:00 out: nextcheck: 2020-10-02 00:10:00.000000000 +03:00 --- -test case: Schedule 1d,now/M+6d/w+1d 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 1d:now/M+6d/w+1d 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/M+6d/w+1d + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/M+6d/w+1d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-09-08 00:10:00.000000000 +03:00 --- -test case: Schedule 1d,now/M+6d/w+1d 2020-09-09 10:00:00.000000000 +03:00 +test case: Schedule 1d:now/M+6d/w+1d 2020-09-09 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 1h,now/M+6d/w+1d + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 1h:now/M+6d/w+1d timezone: :Europe/Riga time: 2020-09-09 10:00:00.000000000 +03:00 out: nextcheck: 2020-10-06 00:10:00.000000000 +03:00 --- -test case: Schedule 8h,now/d+17h 2020-09-01 10:00:00.000000000 +03:00 +test case: Schedule 8h:now/d+17h 2020-09-01 10:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 8h,now/d+17h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 8h:now/d+17h timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: nextcheck: 2020-09-01 17:10:00.000000000 +03:00 --- -test case: Schedule 8h,now/d+17h 2020-09-01 18:00:00.000000000 +03:00 +test case: Schedule 8h:now/d+17h 2020-09-01 18:00:00.000000000 +03:00 in: - type: ZBX_FUNCTION_TYPE_TRENDS - params: 8h,now/d+17h + type: ZBX_TRIGGER_TIMER_FUNCTION_TREND + params: 8h:now/d+17h timezone: :Europe/Riga time: 2020-09-01 18:00:00.000000000 +03:00 out: diff --git a/tests/libs/zbxeval/zbx_eval_execute.yaml b/tests/libs/zbxeval/zbx_eval_execute.yaml index f87362f0fa9..dd99c430364 100644 --- a/tests/libs/zbxeval/zbx_eval_execute.yaml +++ b/tests/libs/zbxeval/zbx_eval_execute.yaml @@ -207,6 +207,14 @@ out: result: SUCCEED value: '1' --- +test case: Expression '3<2' +in: + rules: [] + expression: '3<2' +out: + result: SUCCEED + value: '0' +--- test case: Expression '1<1' in: rules: [] diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index 9cd8687be99..dc248420834 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -21,7 +21,7 @@ define('ZABBIX_VERSION', '5.4.0alpha1'); define('ZABBIX_API_VERSION', '5.4.0'); define('ZABBIX_EXPORT_VERSION', '5.4'); -define('ZABBIX_DB_VERSION', 5030025); +define('ZABBIX_DB_VERSION', 5030026); define('ZABBIX_COPYRIGHT_FROM', '2001'); define('ZABBIX_COPYRIGHT_TO', '2021'); |