Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/zbxdbwrap/trigger.c')
-rw-r--r--src/libs/zbxdbwrap/trigger.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/src/libs/zbxdbwrap/trigger.c b/src/libs/zbxdbwrap/trigger.c
new file mode 100644
index 00000000000..f0f4b81431c
--- /dev/null
+++ b/src/libs/zbxdbwrap/trigger.c
@@ -0,0 +1,754 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "zbxdbhigh.h"
+
+#include "log.h"
+#include "zbxdbwrap.h"
+#include "events.h"
+#include "zbxserver.h"
+#include "zbxnum.h"
+
+/* temporary cache of trigger related data */
+typedef struct
+{
+ zbx_uint32_t init;
+ zbx_uint32_t done;
+ 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_EVAL_CTX_R_MACROS,
+ ZBX_TRIGGER_CACHE_HOSTIDS,
+}
+zbx_trigger_cache_state_t;
+
+static int db_trigger_expand_macros(const ZBX_DB_TRIGGER *trigger, zbx_eval_context_t *ctx);
+
+/******************************************************************************
+ * *
+ * 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 ZBX_DB_TRIGGER *trigger, zbx_trigger_cache_state_t state)
+{
+ zbx_trigger_cache_t *cache;
+ char *error = NULL;
+ zbx_uint32_t flag = 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->init = cache->done = 0;
+ ((ZBX_DB_TRIGGER *)trigger)->cache = cache;
+ }
+ else
+ cache = (zbx_trigger_cache_t *)trigger->cache;
+
+ if (0 != (cache->init & flag))
+ return 0 != (cache->done & flag) ? cache : NULL;
+
+ cache->init |= 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_TRIGGER_CACHE_EVAL_CTX_MACROS:
+ if (FAIL == db_trigger_expand_macros(trigger, &cache->eval_ctx))
+ return NULL;
+
+ break;
+ case ZBX_TRIGGER_CACHE_EVAL_CTX_R_MACROS:
+ if (FAIL == db_trigger_expand_macros(trigger, &cache->eval_ctx_r))
+ return NULL;
+
+ 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->done |= flag;
+
+ return cache;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: expand macros in trigger expression/recovery expression *
+ * *
+ ******************************************************************************/
+static int db_trigger_expand_macros(const ZBX_DB_TRIGGER *trigger, zbx_eval_context_t *ctx)
+{
+ int i;
+ ZBX_DB_EVENT db_event;
+ zbx_dc_um_handle_t *um_handle;
+ zbx_trigger_cache_t *cache;
+
+ if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_HOSTIDS)))
+ return FAIL;
+
+ db_event.value = trigger->value;
+ db_event.object = EVENT_OBJECT_TRIGGER;
+
+ um_handle = zbx_dc_open_user_macros();
+
+ (void)zbx_eval_expand_user_macros(ctx, cache->hostids.values, cache->hostids.values_num,
+ (zbx_macro_expand_func_t)zbx_dc_expand_user_macros, um_handle, NULL);
+
+ zbx_dc_close_user_macros(um_handle);
+
+ for (i = 0; i < ctx->stack.values_num; i++)
+ {
+ char *value;
+ zbx_eval_token_t *token = &ctx->stack.values[i];
+
+ switch (token->type)
+ {
+ case ZBX_EVAL_TOKEN_VAR_STR:
+ if (ZBX_VARIANT_NONE != token->value.type)
+ {
+ zbx_variant_convert(&token->value, ZBX_VARIANT_STR);
+ value = token->value.data.str;
+ zbx_variant_set_none(&token->value);
+ break;
+ }
+ value = zbx_substr_unquote(ctx->expression, token->loc.l, token->loc.r);
+ break;
+ case ZBX_EVAL_TOKEN_VAR_MACRO:
+ value = zbx_substr_unquote(ctx->expression, token->loc.l, token->loc.r);
+ break;
+ default:
+ continue;
+ }
+
+ if (SUCCEED == zbx_substitute_simple_macros(NULL, &db_event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &value, MACRO_TYPE_TRIGGER_EXPRESSION, NULL, 0))
+ {
+ zbx_variant_clear(&token->value);
+ zbx_variant_set_str(&token->value, value);
+ }
+ else
+ zbx_free(value);
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free trigger cache *
+ * *
+ * Parameters: cache - [IN] the trigger cache *
+ * *
+ ******************************************************************************/
+static void trigger_cache_free(zbx_trigger_cache_t *cache)
+{
+ if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_EVAL_CTX)))
+ zbx_eval_clear(&cache->eval_ctx);
+
+ if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_EVAL_CTX_R)))
+ zbx_eval_clear(&cache->eval_ctx_r);
+
+ if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_HOSTIDS)))
+ zbx_vector_uint64_destroy(&cache->hostids);
+
+ zbx_free(cache);
+}
+
+/******************************************************************************
+ * *
+ * 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 ZBX_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);
+}
+
+/******************************************************************************
+ * *
+ * 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 ZBX_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);
+}
+/******************************************************************************
+ * *
+ * 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 ZBX_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;
+}
+
+/******************************************************************************
+ * *
+ * 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 ZBX_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 != zbx_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;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: get unique itemids of trigger functions in the order they are *
+ * written in expression *
+ * *
+ * Parameters: trigger - [IN] the trigger *
+ * itemids - [IN] the function itemids *
+ * *
+ ******************************************************************************/
+void zbx_db_trigger_get_itemids(const ZBX_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 *functions;
+ int i, *errcodes, index;
+
+ 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 (-1 == (index = zbx_vector_uint64_bsearch(&functionids, functionids_ordered.values[i],
+ ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ continue;
+ }
+
+ if (SUCCEED != errcodes[index])
+ continue;
+
+ if (FAIL == zbx_vector_uint64_search(itemids, functions[index].itemid,
+ ZBX_DEFAULT_UINT64_COMPARE_FUNC))
+ {
+ zbx_vector_uint64_append(itemids, functions[index].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);
+}
+
+/******************************************************************************
+ * *
+ * 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 ZBX_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;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: frees resources allocated to store trigger data *
+ * *
+ * Parameters: trigger - *
+ * *
+ ******************************************************************************/
+void zbx_db_trigger_clean(ZBX_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->url_name);
+ zbx_free(trigger->opdata);
+ zbx_free(trigger->event_name);
+
+ if (NULL != trigger->cache)
+ trigger_cache_free((zbx_trigger_cache_t *)trigger->cache);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: get original trigger expression/recovery expression with expanded *
+ * functions *
+ * *
+ * Parameters: ctx - [IN] the parsed expression *
+ * expression - [OUT] the trigger expression *
+ * *
+ ******************************************************************************/
+static void db_trigger_get_expression(const zbx_eval_context_t *ctx, char **expression)
+{
+ int i;
+ zbx_eval_context_t local_ctx;
+
+ zbx_eval_copy(&local_ctx, ctx, ctx->expression);
+ local_ctx.rules |= ZBX_EVAL_COMPOSE_MASK_ERROR;
+
+ for (i = 0; i < local_ctx.stack.values_num; i++)
+ {
+ zbx_eval_token_t *token = &local_ctx.stack.values[i];
+ zbx_uint64_t functionid;
+ DC_FUNCTION function;
+ DC_ITEM item;
+ int err_func, err_item;
+
+ if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type)
+ {
+ /* reset cached token values to get the original expression */
+ zbx_variant_clear(&token->value);
+ continue;
+ }
+
+ switch (token->value.type)
+ {
+ case ZBX_VARIANT_UI64:
+ functionid = token->value.data.ui64;
+ break;
+ case ZBX_VARIANT_NONE:
+ if (SUCCEED != zbx_is_uint64_n(local_ctx.expression + token->loc.l + 1,
+ token->loc.r - token->loc.l - 1, &functionid))
+ {
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ DCconfig_get_functions_by_functionids(&function, &functionid, &err_func, 1);
+
+ if (SUCCEED == err_func)
+ {
+ DCconfig_get_items_by_itemids(&item, &function.itemid, &err_item, 1);
+
+ if (SUCCEED == err_item)
+ {
+ char *func = NULL;
+ size_t func_alloc = 0, func_offset = 0;
+
+ zbx_snprintf_alloc(&func, &func_alloc, &func_offset, "%s(/%s/%s",
+ function.function, item.host.host, item.key_orig);
+
+ if ('\0' != *function.parameter)
+ zbx_snprintf_alloc(&func, &func_alloc, &func_offset, ",%s", function.parameter);
+
+ zbx_chrcpy_alloc(&func, &func_alloc, &func_offset,')');
+
+ zbx_variant_clear(&token->value);
+ zbx_variant_set_str(&token->value, func);
+ DCconfig_clean_items(&item, &err_item, 1);
+ }
+ else
+ {
+ zbx_variant_clear(&token->value);
+ zbx_variant_set_error(&token->value, zbx_dsprintf(NULL, "item id:" ZBX_FS_UI64
+ " deleted", function.itemid));
+ }
+
+ DCconfig_clean_functions(&function, &err_func, 1);
+ }
+ else
+ {
+ zbx_variant_clear(&token->value);
+ zbx_variant_set_error(&token->value, zbx_dsprintf(NULL, "function id:" ZBX_FS_UI64 " deleted",
+ functionid));
+ }
+ }
+
+ zbx_eval_compose_expression(&local_ctx, expression);
+
+ zbx_eval_clear(&local_ctx);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: get original trigger expression with expanded functions *
+ * *
+ * Parameters: trigger - [IN] the trigger *
+ * expression - [OUT] the trigger expression *
+ * *
+ ******************************************************************************/
+void zbx_db_trigger_get_expression(const ZBX_DB_TRIGGER *trigger, char **expression)
+{
+ zbx_trigger_cache_t *cache;
+
+ if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX)))
+ *expression = zbx_strdup(NULL, trigger->expression);
+ else
+ db_trigger_get_expression(&cache->eval_ctx, expression);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: get original trigger recovery expression with expanded functions *
+ * *
+ * Parameters: trigger - [IN] the trigger *
+ * expression - [OUT] the trigger expression *
+ * *
+ ******************************************************************************/
+void zbx_db_trigger_get_recovery_expression(const ZBX_DB_TRIGGER *trigger, char **expression)
+{
+ zbx_trigger_cache_t *cache;
+
+ if (NULL == (cache = db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX_R)))
+ *expression = zbx_strdup(NULL, trigger->recovery_expression);
+ else
+ db_trigger_get_expression(&cache->eval_ctx_r, expression);
+}
+
+static void evaluate_function_by_id(zbx_uint64_t functionid, char **value, zbx_trigger_func_t eval_func_cb)
+{
+ DC_ITEM item;
+ DC_FUNCTION function;
+ int err_func, err_item;
+
+ DCconfig_get_functions_by_functionids(&function, &functionid, &err_func, 1);
+
+ if (SUCCEED == err_func)
+ {
+ DCconfig_get_items_by_itemids(&item, &function.itemid, &err_item, 1);
+
+ if (SUCCEED == err_item)
+ {
+ char *error = NULL, *parameter = NULL;
+ zbx_variant_t var;
+ zbx_timespec_t ts;
+
+ parameter = zbx_dc_expand_user_macros_in_func_params(function.parameter, item.host.hostid);
+ zbx_timespec(&ts);
+
+ if (SUCCEED == eval_func_cb(&var, &item, function.function, parameter, &ts, &error) &&
+ ZBX_VARIANT_NONE != var.type)
+ {
+ *value = zbx_strdup(NULL, zbx_variant_value_desc(&var));
+ zbx_variant_clear(&var);
+ }
+ else
+ zbx_free(error);
+
+ zbx_free(parameter);
+ DCconfig_clean_items(&item, &err_item, 1);
+ }
+
+ DCconfig_clean_functions(&function, &err_func, 1);
+ }
+
+ if (NULL == *value)
+ *value = zbx_strdup(NULL, "*UNKNOWN*");
+}
+
+static void db_trigger_explain_expression(const zbx_eval_context_t *ctx, char **expression,
+ zbx_trigger_func_t eval_func_cb)
+{
+ int i;
+ zbx_eval_context_t local_ctx;
+
+ zbx_eval_copy(&local_ctx, ctx, ctx->expression);
+ local_ctx.rules |= ZBX_EVAL_COMPOSE_MASK_ERROR;
+
+ for (i = 0; i < local_ctx.stack.values_num; i++)
+ {
+ zbx_eval_token_t *token = &local_ctx.stack.values[i];
+ char *value = NULL;
+ zbx_uint64_t functionid;
+
+ if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type)
+ continue;
+
+ switch (token->value.type)
+ {
+ case ZBX_VARIANT_UI64:
+ functionid = token->value.data.ui64;
+ break;
+ case ZBX_VARIANT_NONE:
+ if (SUCCEED != zbx_is_uint64_n(local_ctx.expression + token->loc.l + 1,
+ token->loc.r - token->loc.l - 1, &functionid))
+ {
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ zbx_variant_clear(&token->value);
+ evaluate_function_by_id(functionid, &value, eval_func_cb);
+ zbx_variant_set_str(&token->value, value);
+ }
+
+ zbx_eval_compose_expression(&local_ctx, expression);
+
+ zbx_eval_clear(&local_ctx);
+}
+
+static void db_trigger_get_function_value(const zbx_eval_context_t *ctx, int index, char **value_ret,
+ zbx_trigger_func_t eval_func_cb)
+{
+ int i;
+ zbx_eval_context_t local_ctx;
+
+ zbx_eval_copy(&local_ctx, ctx, ctx->expression);
+
+ for (i = 0; i < local_ctx.stack.values_num; i++)
+ {
+ zbx_eval_token_t *token = &local_ctx.stack.values[i];
+ zbx_uint64_t functionid;
+
+ 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 != zbx_is_uint64_n(local_ctx.expression + token->loc.l + 1,
+ token->loc.r - token->loc.l - 1, &functionid))
+ {
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ evaluate_function_by_id(functionid, value_ret, eval_func_cb);
+ break;
+ }
+
+ zbx_eval_clear(&local_ctx);
+
+ if (NULL == *value_ret)
+ *value_ret = zbx_strdup(NULL, "*UNKNOWN*");
+}
+
+void zbx_db_trigger_explain_expression(const ZBX_DB_TRIGGER *trigger, char **expression,
+ zbx_trigger_func_t eval_func_cb, int recovery)
+{
+ zbx_trigger_cache_t *cache;
+ zbx_trigger_cache_state_t state;
+ const zbx_eval_context_t *ctx;
+
+ state = (1 == recovery) ? ZBX_TRIGGER_CACHE_EVAL_CTX_R_MACROS : ZBX_TRIGGER_CACHE_EVAL_CTX_MACROS;
+
+ if (NULL == (cache = db_trigger_get_cache(trigger, state)))
+ {
+ *expression = zbx_strdup(NULL, "*UNKNOWN*");
+ return;
+ }
+
+ ctx = (1 == recovery) ? &cache->eval_ctx_r : &cache->eval_ctx;
+
+ db_trigger_explain_expression(ctx, expression, eval_func_cb);
+}
+
+void zbx_db_trigger_get_function_value(const ZBX_DB_TRIGGER *trigger, int index, char **value,
+ zbx_trigger_func_t eval_func_cb, int recovery)
+{
+ zbx_trigger_cache_t *cache;
+ zbx_trigger_cache_state_t state;
+ const zbx_eval_context_t *ctx;
+
+ state = (1 == recovery) ? ZBX_TRIGGER_CACHE_EVAL_CTX_R : ZBX_TRIGGER_CACHE_EVAL_CTX;
+
+ if (NULL == (cache = db_trigger_get_cache(trigger, state)))
+ {
+ *value = zbx_strdup(NULL, "*UNKNOWN*");
+ return;
+ }
+
+ ctx = (1 == recovery) ? &cache->eval_ctx_r : &cache->eval_ctx;
+
+ db_trigger_get_function_value(ctx, index, value, eval_func_cb);
+}