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:
-rw-r--r--include/common.h1
-rw-r--r--include/dbcache.h3
-rw-r--r--include/zbxeval.h75
-rw-r--r--include/zbxserver.h8
-rw-r--r--src/libs/zbxcommon/str.c53
-rw-r--r--src/libs/zbxdbcache/dbconfig.c36
-rw-r--r--src/libs/zbxdbupgrade/dbupgrade_5030.c4
-rw-r--r--src/libs/zbxeval/Makefile.am4
-rw-r--r--src/libs/zbxeval/execute.c118
-rw-r--r--src/libs/zbxeval/misc.c82
-rw-r--r--src/libs/zbxeval/parse.c72
-rw-r--r--src/libs/zbxserver/evalfunc2.c33
-rw-r--r--src/libs/zbxserver/expression.c359
-rw-r--r--tests/libs/zbxcommon/zbx_token_find.yaml2
-rw-r--r--tests/libs/zbxeval/zbx_eval_execute_ext.c8
-rw-r--r--tests/libs/zbxeval/zbx_eval_execute_ext.yaml8
-rw-r--r--tests/libs/zbxeval/zbx_eval_parse_expression.c2
-rw-r--r--tests/libs/zbxeval/zbx_eval_parse_expression.yaml66
18 files changed, 684 insertions, 250 deletions
diff --git a/include/common.h b/include/common.h
index b7f3bde2b46..fc2a669d77d 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1183,6 +1183,7 @@ void zbx_strncpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char
void zbx_strcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src);
void zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c);
void zbx_str_memcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src, size_t n);
+void zbx_strquote_alloc(char **str, size_t *str_alloc, size_t *str_offset, const char *value_str);
void zbx_strsplit(const char *src, char delimiter, char **left, char **right);
diff --git a/include/dbcache.h b/include/dbcache.h
index 41bba8facc9..3aacdd44a13 100644
--- a/include/dbcache.h
+++ b/include/dbcache.h
@@ -975,6 +975,9 @@ const char *zbx_dc_get_instanceid(void);
char *zbx_dc_expand_user_macros(const char *text, zbx_uint64_t hostid);
char *zbx_dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid);
+int zbx_dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num,
+ char **value, char **error);
+
/* diagnostic data */
void zbx_hc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num);
diff --git a/include/zbxeval.h b/include/zbxeval.h
index 85d7f6fee2d..73bf9b87530 100644
--- a/include/zbxeval.h
+++ b/include/zbxeval.h
@@ -58,21 +58,20 @@
#define ZBX_EVAL_TOKEN_OP_NOT (14 | ZBX_EVAL_CLASS_OPERATOR1 | ZBX_EVAL_OP_SET_PRECEDENCE(2))
#define ZBX_EVAL_TOKEN_VAR_NUM (15 | ZBX_EVAL_CLASS_OPERAND)
#define ZBX_EVAL_TOKEN_VAR_STR (16 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_VAR_TIME (17 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_VAR_MACRO (18 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_VAR_USERMACRO (19 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_VAR_LLDMACRO (20 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_FUNCTIONID (21 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_FUNCTION (22 | ZBX_EVAL_CLASS_FUNCTION)
-#define ZBX_EVAL_TOKEN_HIST_FUNCTION (23 | ZBX_EVAL_CLASS_FUNCTION)
-#define ZBX_EVAL_TOKEN_GROUP_OPEN (24 | ZBX_EVAL_CLASS_SEPARATOR)
-#define ZBX_EVAL_TOKEN_GROUP_CLOSE (25 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_COMMA (26 | ZBX_EVAL_CLASS_SEPARATOR)
-#define ZBX_EVAL_TOKEN_ARG_QUERY (27 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_ARG_PERIOD (28 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_ARG_NULL (29 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_ARG_RAW (30 | ZBX_EVAL_CLASS_OPERAND)
-#define ZBX_EVAL_TOKEN_EXCEPTION (31 | ZBX_EVAL_CLASS_FUNCTION)
+#define ZBX_EVAL_TOKEN_VAR_MACRO (17 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_VAR_USERMACRO (18 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_VAR_LLDMACRO (19 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_FUNCTIONID (20 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_FUNCTION (21 | ZBX_EVAL_CLASS_FUNCTION)
+#define ZBX_EVAL_TOKEN_HIST_FUNCTION (22 | ZBX_EVAL_CLASS_FUNCTION)
+#define ZBX_EVAL_TOKEN_GROUP_OPEN (23 | ZBX_EVAL_CLASS_SEPARATOR)
+#define ZBX_EVAL_TOKEN_GROUP_CLOSE (24 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_COMMA (25 | ZBX_EVAL_CLASS_SEPARATOR)
+#define ZBX_EVAL_TOKEN_ARG_QUERY (26 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_ARG_PERIOD (27 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_ARG_NULL (28 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_ARG_RAW (29 | ZBX_EVAL_CLASS_OPERAND)
+#define ZBX_EVAL_TOKEN_EXCEPTION (30 | ZBX_EVAL_CLASS_FUNCTION)
/* expression parsing rules */
@@ -89,7 +88,11 @@
ZBX_EVAL_PARSE_FUNCTIONID | ZBX_EVAL_PARSE_FUNCTION)
#define ZBX_EVAL_PARSE_CALC_EXPRESSSION (ZBX_EVAL_PARSE_MACRO | ZBX_EVAL_PARSE_USERMACRO | \
- ZBX_EVAL_PARSE_ITEM_QUERY | ZBX_EVAL_PARSE_FUNCTION)
+ ZBX_EVAL_PARSE_ITEM_QUERY | ZBX_EVAL_PARSE_FUNCTION | \
+ ZBX_EVAL_PARSE_COMPOUND_CONST)
+
+#define ZBX_EVAL_PARSE_EXPRESSION_MACRO (ZBX_EVAL_PARSE_USERMACRO | ZBX_EVAL_PARSE_ITEM_QUERY | \
+ ZBX_EVAL_PARSE_FUNCTION | ZBX_EVAL_PARSE_COMPOUND_CONST)
/* expression composition rules */
@@ -111,6 +114,11 @@
ZBX_EVAL_COMPOSE_LLD | \
ZBX_EVAL_COMPOSE_FUNCTIONID)
+#define ZBX_EVAL_CALC_EXPRESSION_LLD (ZBX_EVAL_PARSE_CALC_EXPRESSSION | \
+ ZBX_EVAL_PARSE_LLDMACRO | \
+ ZBX_EVAL_COMPOSE_LLD)
+
+
typedef zbx_uint32_t zbx_token_type_t;
/******************************************************************************
@@ -123,6 +131,8 @@ typedef zbx_uint32_t zbx_token_type_t;
* len - [IN] the function name length *
* args_num - [IN] the number of function arguments *
* args - [IN] an array of the function arguments. *
+ * data - [IN] the caller data used for function evaluation *
+ * ts - [IN] the function execution time *
* value - [OUT] the function return value *
* error - [OUT] the error message if function failed *
* *
@@ -131,7 +141,7 @@ typedef zbx_uint32_t zbx_token_type_t;
* *
******************************************************************************/
typedef int (*zbx_eval_function_cb_t)(const char *name, size_t len, int args_num, const zbx_variant_t *args,
- zbx_variant_t *value, char **error);
+ void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error);
typedef struct
{
@@ -154,7 +164,9 @@ typedef struct
zbx_timespec_t ts;
zbx_vector_eval_token_t stack;
zbx_vector_eval_token_t ops;
- zbx_eval_function_cb_t function_cb;
+ zbx_eval_function_cb_t common_func_cb;
+ zbx_eval_function_cb_t history_func_cb;
+ void *data_cb;
}
zbx_eval_context_t;
@@ -162,7 +174,6 @@ typedef int (*zbx_macro_resolve_func_t)(const char *str, size_t length, zbx_uint
int hostids_num, char **value, char **error);
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_init(zbx_eval_context_t *ctx);
void zbx_eval_clear(zbx_eval_context_t *ctx);
int zbx_eval_status(const zbx_eval_context_t *ctx);
@@ -171,8 +182,8 @@ void zbx_eval_deserialize(zbx_eval_context_t *ctx, const char *expression, zbx_u
const unsigned char *data);
void zbx_eval_compose_expression(const zbx_eval_context_t *ctx, char **expression);
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);
+int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t common_func_cb,
+ zbx_eval_function_cb_t history_func_cb, void *data, zbx_variant_t *value, char **error);
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);
int zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *hostids, int hostids_num,
@@ -198,4 +209,26 @@ void zbx_eval_copy(zbx_eval_context_t *dst, const zbx_eval_context_t *src, const
char *zbx_eval_format_function_error(const char *function, const char *host, const char *key,
const char *parameter, const char *error);
+void zbx_eval_extract_item_refs(zbx_eval_context_t *ctx, zbx_vector_str_t *refs);
+
+typedef enum
+{
+ ZBX_ITEM_QUERY_UNKNOWN,
+ ZBX_ITEM_QUERY_SINGLE,
+ ZBX_ITEM_QUERY_MULTI
+}
+zbx_item_query_type_t;
+
+typedef struct
+{
+ char *host;
+ char *key;
+ zbx_item_query_type_t type;
+ int index;
+}
+zbx_item_query_t;
+
+void zbx_eval_parse_query(const char *str, size_t len, zbx_item_query_t *query);
+void zbx_eval_clear_query(zbx_item_query_t *query);
+
#endif
diff --git a/include/zbxserver.h b/include/zbxserver.h
index 4f540cea9dc..1c6509b02cd 100644
--- a/include/zbxserver.h
+++ b/include/zbxserver.h
@@ -50,10 +50,9 @@
#define MACRO_TYPE_ALLOWED_HOSTS 0x00800000
#define MACRO_TYPE_ITEM_TAG 0x01000000
#define MACRO_TYPE_EVENT_NAME 0x02000000 /* event name in trigger configuration */
-#define MACRO_TYPE_EXPRESSION 0x04000000 /* macros in expression macro */
-#define MACRO_TYPE_SCRIPT_PARAMS_FIELD 0x08000000
-#define MACRO_TYPE_SCRIPT_NORMAL 0x10000000
-#define MACRO_TYPE_SCRIPT_RECOVERY 0x20000000
+#define MACRO_TYPE_SCRIPT_PARAMS_FIELD 0x04000000
+#define MACRO_TYPE_SCRIPT_NORMAL 0x08000000
+#define MACRO_TYPE_SCRIPT_RECOVERY 0x10000000
#define MACRO_EXPAND_NO 0
#define MACRO_EXPAND_YES 1
@@ -65,6 +64,7 @@ int evaluate_function(char **value, DC_ITEM *item, const char *function, const c
int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function, const char *parameter,
const zbx_timespec_t *ts, char **error);
+int zbx_is_trigger_function(const char *name, size_t len);
int substitute_simple_macros(const zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event,
const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item,
diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c
index 87bb5d57834..eae0c246893 100644
--- a/src/libs/zbxcommon/str.c
+++ b/src/libs/zbxcommon/str.c
@@ -358,6 +358,58 @@ void zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c)
zbx_strncpy_alloc(str, alloc_len, offset, &c, 1);
}
+void zbx_strquote_alloc(char **str, size_t *str_alloc, size_t *str_offset, const char *value_str)
+{
+ size_t size;
+ const char *src;
+ char *dst;
+
+ 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;
+}
+
/* Has to be rewritten to avoid malloc */
char *string_replace(const char *str, const char *sub_str1, const char *sub_str2)
{
@@ -3687,6 +3739,7 @@ static int token_parse_expression_macro(const char *expression, const char *macr
{
switch (tmp.type)
{
+ case ZBX_TOKEN_MACRO:
case ZBX_TOKEN_LLD_MACRO:
case ZBX_TOKEN_LLD_FUNC_MACRO:
case ZBX_TOKEN_USER_MACRO:
diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c
index 15499201d0b..8e36a10f769 100644
--- a/src/libs/zbxdbcache/dbconfig.c
+++ b/src/libs/zbxdbcache/dbconfig.c
@@ -10902,6 +10902,42 @@ int dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *h
/******************************************************************************
* *
+ * Function: zbx_dc_expand_user_macros_len *
+ * *
+ * Purpose: expand user macros in the specified text *
+ * *
+ * Parameters: text - [IN] the text value to expand *
+ * len - [IN] the text length *
+ * hostids - [IN] an array of related hostids *
+ * hostids_num - [IN] the number of hostids *
+ * value - [IN] the expanded macro with expanded user *
+ * macros. Unknown or invalid macros will be *
+ * left unresolved. *
+ * error - [IN] the error message, optional. If specified *
+ * the function will return failure on first *
+ * unknown user macro *
+ * *
+ * Return value: SUCCEED - the macros were expanded successfully *
+ * FAIL - error parameter was given and at least one of *
+ * macros was not expanded *
+ * *
+ * Comments: The returned value must be freed by the caller. *
+ * *
+ ******************************************************************************/
+int zbx_dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num,
+ char **value, char **error)
+{
+ int ret;
+
+ RDLOCK_CACHE;
+ ret = dc_expand_user_macros_len(text, text_len, hostids, hostids_num, value, error);
+ UNLOCK_CACHE;
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
* Function: dc_expand_user_macros *
* *
* Purpose: expand user macros in the specified text value *
diff --git a/src/libs/zbxdbupgrade/dbupgrade_5030.c b/src/libs/zbxdbupgrade/dbupgrade_5030.c
index 5d08bc83d05..0377916cf15 100644
--- a/src/libs/zbxdbupgrade/dbupgrade_5030.c
+++ b/src/libs/zbxdbupgrade/dbupgrade_5030.c
@@ -2750,10 +2750,12 @@ static void dbpatch_convert_simple_macro(const char *expression, const zbx_token
host = zbx_substr(expression, data->host.l, data->host.r);
key = zbx_substr(expression, data->key.l, data->key.r);
+ /* TODO: clarify if {HOST.HOST} should be replaced with //
if (0 == strcmp(host, "{HOST.HOST}"))
func->arg0 = zbx_dsprintf(NULL, "//%s", key);
else
- func->arg0 = zbx_dsprintf(NULL, "/%s/%s", host, key);
+ */
+ func->arg0 = zbx_dsprintf(NULL, "/%s/%s", host, key);
zbx_vector_ptr_append(&functions, func);
diff --git a/src/libs/zbxeval/Makefile.am b/src/libs/zbxeval/Makefile.am
index a788c852c12..c6d4dc4c93a 100644
--- a/src/libs/zbxeval/Makefile.am
+++ b/src/libs/zbxeval/Makefile.am
@@ -5,5 +5,5 @@ noinst_LIBRARIES = libzbxeval.a
libzbxeval_a_SOURCES = \
parse.c \
execute.c \
- misc.c
-
+ misc.c \
+ query.c
diff --git a/src/libs/zbxeval/execute.c b/src/libs/zbxeval/execute.c
index 2a9007007b4..761d0866a6e 100644
--- a/src/libs/zbxeval/execute.c
+++ b/src/libs/zbxeval/execute.c
@@ -428,11 +428,6 @@ static int eval_execute_push_value(const zbx_eval_context_t *ctx, const zbx_eval
suffix2factor(ctx->expression[token->loc.r]));
}
}
- else if (ZBX_EVAL_TOKEN_VAR_TIME == token->type)
- {
- zbx_variant_set_dbl(&value, atof(ctx->expression + token->loc.l) *
- suffix2factor(ctx->expression[token->loc.r]));
- }
else
{
dst = zbx_malloc(NULL, token->loc.r - token->loc.l + 2);
@@ -1248,50 +1243,47 @@ static int eval_execute_function_bitand(const zbx_eval_context_t *ctx, const zbx
* *
* Purpose: evaluate function by calling custom callback (if configured) *
* *
- * Parameters: ctx - [IN] the evaluation context *
- * token - [IN] the function token *
- * output - [IN/OUT] the output value stack *
- * error - [OUT] the error message in the case of failure *
+ * Parameters: ctx - [IN] the evaluation context *
+ * token - [IN] the function token *
+ * functio_cb - [IN] the callback function *
+ * output - [IN/OUT] the output value stack *
+ * error - [OUT] the error message in the case of failure *
* *
* Return value: SUCCEED - the function was executed successfully *
* FAIL - otherwise *
* *
******************************************************************************/
static int eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
- zbx_vector_var_t *output, char **error)
+ zbx_eval_function_cb_t function_cb, zbx_vector_var_t *output, char **error)
{
zbx_variant_t value, *args;
-
- if (NULL == ctx->function_cb)
- {
- *error = zbx_dsprintf(*error, "unknown function at \"%s\"", ctx->expression + token->loc.l);
- return FAIL;
- }
+ char *errmsg = NULL;
args = (0 == token->opt ? NULL : &output->values[output->values_num - token->opt]);
- if (SUCCEED != ctx->function_cb(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1,
- token->opt, args, &value, error))
+ if (SUCCEED != function_cb(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1,
+ token->opt, args, ctx->data_cb, &ctx->ts, &value, &errmsg))
{
- return FAIL;
- }
+ *error = zbx_dsprintf(*error, "%s at \"%s\".", errmsg, ctx->expression + token->loc.l);
+ zbx_free(errmsg);
- if (ZBX_VARIANT_ERR == value.type && 0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR))
- {
- *error = zbx_dsprintf(*error, "%s at \"%s\"", value.data.err, ctx->expression + token->loc.l);
- zbx_variant_clear(&value);
- return FAIL;
+ if (0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR))
+ return FAIL;
+
+ zbx_variant_set_error(&value, *error);
+ *error = NULL;
}
eval_function_return(token->opt, &value, output);
+
return SUCCEED;
}
/******************************************************************************
* *
- * Function: eval_execute_function *
+ * Function: eval_execute_common_function *
* *
- * Purpose: evaluate normal (non history) function *
+ * Purpose: evaluate common function *
* *
* Parameters: ctx - [IN] the evaluation context *
* token - [IN] the function token *
@@ -1302,11 +1294,9 @@ static int eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eva
* FAIL - otherwise *
* *
******************************************************************************/
-static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
+static int eval_execute_common_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
zbx_vector_var_t *output, char **error)
{
- char *errmsg = NULL;
-
if ((zbx_uint32_t)output->values_num < token->opt)
{
*error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"",
@@ -1339,19 +1329,16 @@ static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_t
if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitand", ZBX_CONST_STRLEN("bitand")))
return eval_execute_function_bitand(ctx, token, output, error);
- if (FAIL == eval_execute_cb_function(ctx, token, output, &errmsg))
- {
- *error = zbx_dsprintf(*error, "%s at \"%s\"", errmsg, ctx->expression + token->loc.l);
- zbx_free(errmsg);
- return FAIL;
- }
+ if (NULL != ctx->common_func_cb)
+ return eval_execute_cb_function(ctx, token, ctx->common_func_cb, output, error);
- return SUCCEED;
+ *error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l);
+ return FAIL;
}
/******************************************************************************
* *
- * Function: eval_execute_hist_function *
+ * Function: eval_execute_history_function *
* *
* Purpose: evaluate history function *
* *
@@ -1364,19 +1351,21 @@ static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_t
* FAIL - otherwise *
* *
******************************************************************************/
-static int eval_execute_hist_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
+static int eval_execute_history_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
zbx_vector_var_t *output, char **error)
{
- char *errmsg = NULL;
-
- if (FAIL == eval_execute_cb_function(ctx, token, output, &errmsg))
+ if ((zbx_uint32_t)output->values_num < token->opt)
{
- *error = zbx_dsprintf(*error, "%s at \"%s\"", errmsg, ctx->expression + token->loc.l);
- zbx_free(errmsg);
+ *error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"",
+ ctx->expression + token->loc.l);
return FAIL;
}
- return SUCCEED;
+ if (NULL != ctx->history_func_cb)
+ return eval_execute_cb_function(ctx, token, ctx->history_func_cb, output, error);
+
+ *error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l);
+ return FAIL;
}
/******************************************************************************
@@ -1445,7 +1434,6 @@ static int eval_execute(const zbx_eval_context_t *ctx, zbx_variant_t *value, cha
switch (token->type)
{
case ZBX_EVAL_TOKEN_VAR_NUM:
- case ZBX_EVAL_TOKEN_VAR_TIME:
case ZBX_EVAL_TOKEN_VAR_STR:
case ZBX_EVAL_TOKEN_VAR_MACRO:
case ZBX_EVAL_TOKEN_VAR_USERMACRO:
@@ -1461,11 +1449,11 @@ static int eval_execute(const zbx_eval_context_t *ctx, zbx_variant_t *value, cha
eval_execute_push_null(&output);
break;
case ZBX_EVAL_TOKEN_FUNCTION:
- if (SUCCEED != eval_execute_function(ctx, token, &output, error))
+ if (SUCCEED != eval_execute_common_function(ctx, token, &output, error))
goto out;
break;
case ZBX_EVAL_TOKEN_HIST_FUNCTION:
- if (SUCCEED != eval_execute_hist_function(ctx, token, &output, error))
+ if (SUCCEED != eval_execute_history_function(ctx, token, &output, error))
goto out;
break;
case ZBX_EVAL_TOKEN_FUNCTIONID:
@@ -1520,15 +1508,20 @@ out:
* *
* Purpose: initialize execution context *
* *
- * Parameters: ctx - [IN] the evaluation context *
- * ts - [IN] the timestamp of the execution time *
- * function_cb - [IN] the callback for function processing *
+ * Parameters: ctx - [IN] the evaluation context *
+ * ts - [IN] the timestamp of the execution time *
+ * common_func_cb - [IN] the common function callback (optional) *
+ * history_func_cb - [IN] the history function callback (optional)*
+ * data_cb - [IN] the caller data to be passed to callback*
+ * functions *
* *
******************************************************************************/
static void eval_init_execute_context(zbx_eval_context_t *ctx, const zbx_timespec_t *ts,
- zbx_eval_function_cb_t function_cb)
+ zbx_eval_function_cb_t common_func_cb, zbx_eval_function_cb_t history_func_cb, void *data_cb)
{
- ctx->function_cb = function_cb;
+ ctx->common_func_cb = common_func_cb;
+ ctx->history_func_cb = history_func_cb;
+ ctx->data_cb = data_cb;
if (NULL == ts)
ctx->ts.sec = ctx->ts.ns = 0;
@@ -1553,7 +1546,7 @@ static void eval_init_execute_context(zbx_eval_context_t *ctx, const zbx_timespe
******************************************************************************/
int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
{
- eval_init_execute_context(ctx, ts, NULL);
+ eval_init_execute_context(ctx, ts, NULL, NULL, NULL);
return eval_execute(ctx, value, error);
}
@@ -1565,11 +1558,12 @@ int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_vari
* Purpose: evaluate parsed expression with callback for custom function *
* processing *
* *
- * Parameters: ctx - [IN] the evaluation context *
- * ts - [IN] the timestamp of the execution time *
- * function_cb - [IN] the callback for function processing *
- * value - [OUT] the resulting value *
- * error - [OUT] the error message in the case of failure *
+ * Parameters: ctx - [IN] the evaluation context *
+ * ts - [IN] the timestamp of the execution time *
+ * common_func_cb - [IN] the common function callback (optional) *
+ * history_func_cb - [IN] the history function callback (optional)*
+ * value - [OUT] the resulting value *
+ * error - [OUT] the error message *
* *
* Return value: SUCCEED - the expression was evaluated successfully *
* FAIL - otherwise *
@@ -1578,10 +1572,10 @@ int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_vari
* functions. *
* *
******************************************************************************/
-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)
+int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t common_func_cb,
+ zbx_eval_function_cb_t history_func_cb, void *data, zbx_variant_t *value, char **error)
{
- eval_init_execute_context(ctx, ts, function_cb);
+ eval_init_execute_context(ctx, ts, common_func_cb, history_func_cb, data);
return eval_execute(ctx, value, error);
}
diff --git a/src/libs/zbxeval/misc.c b/src/libs/zbxeval/misc.c
index 7d2275792fb..ec877071b5f 100644
--- a/src/libs/zbxeval/misc.c
+++ b/src/libs/zbxeval/misc.c
@@ -277,9 +277,7 @@ static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, si
const zbx_eval_token_t *token)
{
int quoted = 0, check_value = 0;
- const char *src, *value_str;
- char *dst;
- size_t size;
+ const char *value_str;
if (ZBX_VARIANT_NONE == token->value.type)
return;
@@ -338,55 +336,9 @@ static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, si
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;
+ else
+ zbx_strquote_alloc(str, str_alloc, str_offset, value_str);
}
/******************************************************************************
@@ -473,6 +425,8 @@ int zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *hos
hostids, hostids_num, &value, error);
break;
case ZBX_EVAL_TOKEN_VAR_STR:
+ case ZBX_EVAL_TOKEN_VAR_NUM:
+ case ZBX_EVAL_TOKEN_ARG_PERIOD:
if (NULL == (ptr = strstr(ctx->expression + token->loc.l, "{$")) ||
ptr >= ctx->expression + token->loc.r)
{
@@ -970,3 +924,29 @@ char *zbx_eval_format_function_error(const char *function, const char *host, con
return msg;
}
+
+/******************************************************************************
+ * *
+ * Function: zbx_eval_extract_history_queries *
+ * *
+ * Purpose: copy history query into vector and replace it with vector index *
+ * *
+ * Parameters: ctx - [IN] the evaluation context *
+ * refs - [OUT] the item references *
+ * *
+ ******************************************************************************/
+void zbx_eval_extract_item_refs(zbx_eval_context_t *ctx, zbx_vector_str_t *refs)
+{
+ int i;
+
+ for (i = 0; i < ctx->stack.values_num; i++)
+ {
+ zbx_eval_token_t *token = &ctx->stack.values[i];
+
+ if (ZBX_EVAL_TOKEN_ARG_QUERY != token->type)
+ continue;
+
+ zbx_variant_set_ui64(&token->value, refs->values_num);
+ zbx_vector_str_append(refs, zbx_substr(ctx->expression, token->loc.l, token->loc.r));
+ }
+}
diff --git a/src/libs/zbxeval/parse.c b/src/libs/zbxeval/parse.c
index 2602a03f6e0..f76f95c887e 100644
--- a/src/libs/zbxeval/parse.c
+++ b/src/libs/zbxeval/parse.c
@@ -468,19 +468,7 @@ static int eval_parse_number_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval
len += offset;
- switch (ctx->expression[pos + len - 1])
- {
- case 's':
- case 'm':
- case 'h':
- case 'd':
- case 'w':
- token->type = ZBX_EVAL_TOKEN_VAR_TIME;
- break;
- default:
- token->type = ZBX_EVAL_TOKEN_VAR_NUM;
- break;
- }
+ token->type = ZBX_EVAL_TOKEN_VAR_NUM;
tmp = strtod(ctx->expression + pos, &end) * suffix2factor(ctx->expression[pos + len - 1]);
if (HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno)
@@ -594,7 +582,7 @@ static int eval_parse_function_token(zbx_eval_context_t *ctx, size_t pos, zbx_ev
******************************************************************************/
static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_token_t *token, char **error)
{
-#define MVAR_HOST_HOST "{HOST.HOST}"
+#define MVAR_HOST_HOST "{HOST.HOST"
const char *ptr = ctx->expression + pos + 1, *key;
@@ -605,8 +593,25 @@ static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_
break;
case '{':
if (0 == strncmp(ptr, MVAR_HOST_HOST, ZBX_CONST_STRLEN(MVAR_HOST_HOST)))
- ptr += ZBX_CONST_STRLEN(MVAR_HOST_HOST);
- break;
+ {
+ int offset = 0;
+
+ if ('}' == ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST)])
+ {
+ offset = 1;
+ }
+ else if (0 != isdigit((unsigned char)ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST)]) &&
+ '}' == ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST) + 1])
+ {
+ offset = 2;
+ }
+
+ if (0 != offset)
+ {
+ ptr += ZBX_CONST_STRLEN(MVAR_HOST_HOST) + offset;
+ break;
+ }
+ }
default:
while (SUCCEED == is_hostname_char(*ptr))
ptr++;
@@ -614,7 +619,13 @@ static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_
if ('/' != *ptr)
{
- *error = zbx_dsprintf(*error, "invalid host name in query starting at \"%s\"", ctx->expression + pos);
+ if (ptr == ctx->expression + pos + 1)
+ {
+ *error = zbx_dsprintf(*error, "invalid host name in query starting at \"%s\"", ctx->expression + pos);
+ return FAIL;
+ }
+
+ *error = zbx_dsprintf(*error, "missing item key in query starting at \"%s\"", ctx->expression + pos);
return FAIL;
}
@@ -953,7 +964,8 @@ static int eval_parse_expression(zbx_eval_context_t *ctx, const char *expression
goto out;
}
- if (ZBX_EVAL_TOKEN_ARG_QUERY == ctx->last_token_type && ZBX_EVAL_TOKEN_COMMA != token.type)
+ if (ZBX_EVAL_TOKEN_ARG_QUERY == ctx->last_token_type && ZBX_EVAL_TOKEN_COMMA != token.type &&
+ ZBX_EVAL_TOKEN_GROUP_CLOSE != token.type)
{
*error = zbx_dsprintf(*error, "invalid expression following query token at \"%s\"",
ctx->expression + pos);
@@ -1173,30 +1185,6 @@ int zbx_eval_parse_expression(zbx_eval_context_t *ctx, const char *expression, z
/******************************************************************************
* *
- * Function: zbx_eval_parse_expression *
- * *
- * Purpose: parse expression into tokens in postfix notation order *
- * *
- * Parameters: expression - [IN] the expression to parse *
- * rules - [IN] the parsing rules *
- * error - [OUT] the error message in the case of failure *
- * *
- * Return value: The evaluation context or NULL in the case of error. *
- * *
- ******************************************************************************/
-zbx_eval_context_t *zbx_eval_parse_expression_dyn(const char *expression, zbx_uint64_t rules, char **error)
-{
- zbx_eval_context_t *ctx;
-
- 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);
-
- return ctx;
-}
-
-/******************************************************************************
- * *
* Function: zbx_eval_init *
* *
* Purpose: initialize context so it can be cleared without parsing *
diff --git a/src/libs/zbxserver/evalfunc2.c b/src/libs/zbxserver/evalfunc2.c
index 4897f358d89..afc577adc47 100644
--- a/src/libs/zbxserver/evalfunc2.c
+++ b/src/libs/zbxserver/evalfunc2.c
@@ -2340,3 +2340,36 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function
return ret;
}
+
+/******************************************************************************
+ * *
+ * Function: zbx_is_trigger_function *
+ * *
+ * Purpose: check if the specified function is a trigger function *
+ * *
+ * Parameters: name - [IN] the function name to check *
+ * len - [IN] the length of function name *
+ * *
+ * Return value: SUCCEED - the function is a trigger function *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_is_trigger_function(const char *name, size_t len)
+{
+ char *functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "nodata", "change", "find",
+ "fuzzytime", "logeventid", "logseverity", "logsource", "band", "forecast", "timeleft",
+ "trendavg", "trendcount", "trendmax", "trendmin", "trendsum",
+ NULL};
+ char **ptr;
+
+ for (ptr = functions; NULL != *ptr; ptr++)
+ {
+ size_t compare_len;
+
+ compare_len = strlen(*ptr);
+ if (compare_len == len && 0 == memcmp(*ptr, name, len))
+ return SUCCEED;
+ }
+
+ return FAIL;
+}
diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c
index 0706454d648..582409470a3 100644
--- a/src/libs/zbxserver/expression.c
+++ b/src/libs/zbxserver/expression.c
@@ -22,6 +22,7 @@
#include "log.h"
#include "zbxregexp.h"
#include "zbxvariant.h"
+#include "zbxeval.h"
#include "valuecache.h"
#include "macrofunc.h"
@@ -2368,40 +2369,6 @@ static void get_event_value(const char *macro, const DB_EVENT *event, char **rep
/******************************************************************************
* *
- * Function: get_expression_macro_result *
- * *
- * Purpose: calculate result of expression macro *
- * *
- * Return value: upon successful completion return SUCCEED *
- * otherwise FAIL *
- * *
- ******************************************************************************/
-static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_event, char **expression,
- char **replace_to, char *error, int maxerrlen)
-{
- int ret;
- double expression_result;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, *expression);
-
- substitute_simple_macros_impl(NULL, event, r_event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, expression,
- MACRO_TYPE_EXPRESSION, error, maxerrlen);
-
- if (SUCCEED == (ret = evaluate(&expression_result, *expression, error, maxerrlen, NULL)))
- {
- char buffer[ZBX_MAX_DOUBLE_LEN + 1];
-
- zbx_print_double(buffer, sizeof(buffer), expression_result);
- *replace_to = zbx_strdup(*replace_to, buffer);
- }
-
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
-
- return ret;
-}
-
-/******************************************************************************
- * *
* Function: get_history_log_value *
* *
* Purpose: retrieve a particular attribute of a log value *
@@ -2643,6 +2610,294 @@ out:
return ret;
}
+
+typedef struct
+{
+ const DB_EVENT *event;
+}
+zbx_expression_macro_data_t;
+
+/******************************************************************************
+ * *
+ * Function: expression_macro_common_func_cb *
+ * *
+ * Purpose: evaluate common function *
+ * *
+ * Parameters: name - [IN] the function name (not zero terminated) *
+ * len - [IN] the function name length *
+ * args_num - [IN] the number of function arguments *
+ * args - [IN] an array of the function arguments. *
+ * data - [IN] the caller data used for function evaluation *
+ * ts - [IN] the function execution time *
+ * value - [OUT] the function return value *
+ * error - [OUT] the error message if function failed *
+ * *
+ * Return value: SUCCEED - the function was executed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: There are no custom common functions for expression macros, but *
+ * it's used to check for /host/key query quoting errors instead. *
+ * *
+ ******************************************************************************/
+static int expression_macro_common_func_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args,
+ void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
+{
+ ZBX_UNUSED(data);
+ ZBX_UNUSED(ts);
+ ZBX_UNUSED(value);
+
+ if (SUCCEED != zbx_is_trigger_function(name, len))
+ {
+ *error = zbx_strdup(NULL, "Cannot evaluate formula: unsupported function");
+ return FAIL;
+ }
+
+ if (0 == args_num)
+ {
+ *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments");
+ return FAIL;
+ }
+
+ if (ZBX_VARIANT_STR == args[0].type)
+ {
+ zbx_item_query_t query;
+
+ zbx_eval_parse_query(args[0].data.str, strlen(args[0].data.str), &query);
+
+ if (ZBX_ITEM_QUERY_UNKNOWN != query.type)
+ {
+ zbx_eval_clear_query(&query);
+ *error = zbx_strdup(NULL, "Cannot evaluate function: quoted item query argument");
+ return FAIL;
+ }
+ }
+
+ *error = zbx_strdup(NULL, "Cannot evaluate function: invalid first argument");
+ return FAIL;
+}
+
+static int expression_macro_history_func_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args,
+ void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
+{
+ zbx_expression_macro_data_t *md = (zbx_expression_macro_data_t *)data;
+ zbx_item_query_t query;
+ zbx_host_key_t hkey;
+ DC_ITEM item;
+ int i, errcode, ret = FAIL;
+ char func_name[MAX_STRING_LEN], *params = NULL, *errmsg = NULL, *host = NULL;
+ size_t params_alloc = 0, params_offset = 0;
+ int N_functionid = 0;
+
+ if (SUCCEED != zbx_is_trigger_function(name, len))
+ {
+ *error = zbx_strdup(NULL, "Cannot evaluate formula: unsupported function");
+ return FAIL;
+ }
+
+ if (0 == args_num)
+ {
+ *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments");
+ return FAIL;
+ }
+
+ if (ZBX_VARIANT_STR != args[0].type)
+ {
+ *error = zbx_strdup(NULL, "Cannot evaluate function: invalid first argument");
+ return FAIL;
+ }
+
+ zbx_eval_parse_query(args[0].data.str, strlen(args[0].data.str), &query);
+
+ if (ZBX_ITEM_QUERY_SINGLE != query.type)
+ {
+ zbx_eval_clear_query(&query);
+ *error = zbx_strdup(NULL, "Cannot evaluate function: invalid item query");
+ return FAIL;
+ }
+
+ if (query.host != NULL)
+ {
+ zbx_strloc_t loc;
+
+ loc.l = 0;
+ loc.r = strlen(query.host) - 1;
+ macro_in_list(query.host, loc, simple_host_macros, &N_functionid);
+ }
+ else
+ N_functionid = 1;
+
+ if (0 != N_functionid)
+ {
+ if (SUCCEED != DBget_trigger_value(&md->event->trigger, &host, N_functionid,
+ ZBX_REQUEST_HOST_HOST))
+ {
+ *error = zbx_dsprintf(NULL, "cannot get host from trigger expression by index");
+ goto out;
+ }
+ hkey.host = host;
+ }
+ else
+ hkey.host = query.host;
+
+ hkey.key = query.key;
+
+ DCconfig_get_items_by_keys(&item, &hkey, &errcode, 1);
+
+ if (SUCCEED != errcode)
+ {
+ *error = zbx_dsprintf(NULL, "Cannot evaluate function because item \"/%s/%s\" does not exist",
+ hkey.host, hkey.key);
+ goto out;
+ }
+
+ /* do not evaluate if the item is disabled or belongs to a disabled host */
+
+ if (ITEM_STATUS_ACTIVE != item.status)
+ {
+ *error = zbx_dsprintf(NULL, "Cannot evaluate function with disabled item \"/%s/%s\"",
+ hkey.host, hkey.key);
+ goto out;
+ }
+
+ if (HOST_STATUS_MONITORED != item.host.status)
+ {
+ *error = zbx_dsprintf(NULL, "Cannot evaluate function with item \"/%s/%s\" belonging to a disabled host",
+ hkey.host, hkey.key);
+ goto out;
+ }
+
+ memcpy(func_name, name, len);
+ func_name[len] = '\0';
+
+ /* If the item is NOTSUPPORTED then evaluation is allowed for: */
+ /* - functions white-listed in evaluatable_for_notsupported(). */
+ /* Their values can be evaluated to regular numbers even for */
+ /* NOTSUPPORTED items. */
+ /* - other functions. Result of evaluation is ZBX_UNKNOWN. */
+
+ if (ITEM_STATE_NOTSUPPORTED == item.state && FAIL == zbx_evaluatable_for_notsupported(func_name))
+ {
+ *error = zbx_dsprintf(NULL,"Cannot evaluate function with not supported item \"/%s/%s\"",
+ hkey.host, hkey.key);
+ goto out;
+ }
+
+ if (1 == args_num)
+ {
+ if (SUCCEED != (ret = evaluate_function2(value, &item, func_name, "", ts, &errmsg)))
+ {
+ *error = zbx_dsprintf(NULL, "Cannot evaluate calculated item formula: %s", errmsg);
+ zbx_free(errmsg);
+ }
+ goto out;
+ }
+
+ for (i = 1; i < args_num; i++)
+ {
+ if (0 != i)
+ zbx_chrcpy_alloc(&params, &params_alloc, &params_offset, ',');
+
+ switch (args[i].type)
+ {
+ case ZBX_VARIANT_DBL:
+ zbx_snprintf_alloc(&params, &params_alloc, &params_offset, ZBX_FS_DBL64,
+ args[i].data.dbl);
+ break;
+ case ZBX_VARIANT_STR:
+ zbx_strquote_alloc(&params, &params_alloc, &params_offset, args[i].data.str);
+ break;
+ case ZBX_VARIANT_UI64:
+ zbx_snprintf_alloc(&params, &params_alloc, &params_offset, ZBX_FS_UI64,
+ args[i].data.ui64);
+ break;
+ case ZBX_VARIANT_NONE:
+ break;
+ default:
+ *error = zbx_dsprintf(NULL,"Cannot evaluate function \"%s\":"
+ " unsupported argument #%d type: %s",
+ func_name, i + 1, zbx_variant_type_desc(&args[i]));
+ goto out;
+ }
+ }
+
+ if (SUCCEED != (ret = evaluate_function2(value, &item, func_name, params, ts, &errmsg)))
+ {
+ *error = zbx_dsprintf(NULL, "Cannot evaluate calculated item formula: %s", errmsg);
+ zbx_free(errmsg);
+ }
+
+out:
+ zbx_free(params);
+ zbx_free(host);
+ zbx_eval_clear_query(&query);
+ DCconfig_clean_items(&item, &errcode, 1);
+
+ return ret;
+}
+
+
+/******************************************************************************
+ * *
+ * Function: get_expression_macro_result *
+ * *
+ * Purpose: calculate result of expression macro *
+ * *
+ * Return value: upon successful completion return SUCCEED *
+ * otherwise FAIL *
+ * *
+ ******************************************************************************/
+static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_event, const char *expression,
+ char **replace_to, char **error)
+{
+ int ret = FAIL;
+ zbx_eval_context_t ctx;
+ const zbx_vector_uint64_t *hostids;
+ zbx_timespec_t ts;
+ zbx_variant_t value;
+ zbx_expression_macro_data_t data;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression);
+
+ ZBX_UNUSED(r_event);
+
+ if (SUCCEED != zbx_eval_parse_expression(&ctx, expression, ZBX_EVAL_PARSE_EXPRESSION_MACRO, error))
+ goto out;
+
+ if (SUCCEED != zbx_db_trigger_get_all_hostids(&event->trigger, &hostids))
+ {
+ *error = zbx_strdup(NULL, "cannot obtain host identifiers for the expression macro");
+ goto out;
+ }
+
+ if (SUCCEED != zbx_eval_expand_user_macros(&ctx, hostids->values, hostids->values_num,
+ zbx_dc_expand_user_macros_len, error))
+ {
+ goto out;
+ }
+
+ ts.sec = event->clock;
+ ts.ns = event->ns;
+
+ data.event = event;
+
+ if (SUCCEED != zbx_eval_execute_ext(&ctx, &ts, expression_macro_common_func_cb,
+ expression_macro_history_func_cb, (void *)&data, &value, error))
+ {
+ goto out;
+ }
+
+ *replace_to = zbx_strdup(NULL, zbx_variant_value_desc(&value));
+ zbx_variant_clear(&value);
+
+ ret = SUCCEED;
+out:
+ zbx_eval_clear(&ctx);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
+
+ return ret;
+}
+
/******************************************************************************
* *
* Function: cache_item_hostid *
@@ -2961,8 +3216,8 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_
break;
case ZBX_TOKEN_SIMPLE_MACRO:
if (0 == (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
- MACRO_TYPE_MESSAGE_ACK | MACRO_TYPE_EXPRESSION |
- MACRO_TYPE_SCRIPT_NORMAL | MACRO_TYPE_SCRIPT_RECOVERY)) ||
+ MACRO_TYPE_MESSAGE_ACK | MACRO_TYPE_SCRIPT_NORMAL |
+ MACRO_TYPE_SCRIPT_RECOVERY)) ||
EVENT_SOURCE_TRIGGERS != ((NULL != r_event) ? r_event : event)->source)
{
pos++;
@@ -4108,16 +4363,24 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_
{
if (0 != (macro_type & MACRO_TYPE_EVENT_NAME))
{
- char *exp = NULL;
+ char *exp = NULL, *errmsg = NULL;
size_t exp_alloc = 0, exp_offset = 0;
zbx_strloc_t *loc = &inner_token.data.expression_macro.expression;
zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, *data + loc->l,
loc->r - loc->l + 1);
- ret = get_expression_macro_result(event, r_event, &exp, &replace_to,
- error, maxerrlen);
+ ret = get_expression_macro_result(event, r_event, exp, &replace_to,
+ &errmsg);
zbx_free(exp);
+
+ if (SUCCEED != ret)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot evaluate"
+ " expression macro: %s", __func__, errmsg);
+ zbx_strlcpy(error, errmsg, maxerrlen);
+ zbx_free(errmsg);
+ }
}
}
else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
@@ -4666,24 +4929,6 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_
}
}
}
- else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_EXPRESSION))
- {
- const DB_EVENT *c_event;
-
- c_event = ((NULL != r_event) ? r_event : event);
-
- if (ZBX_TOKEN_USER_MACRO == token.type)
- {
- 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, &replace_to,
- *data, &token.data.simple_macro, ZBX_FORMAT_RAW);
- }
- }
if (0 != (macro_type & MACRO_TYPE_HTTP_JSON) && NULL != replace_to)
zbx_json_escape(&replace_to);
diff --git a/tests/libs/zbxcommon/zbx_token_find.yaml b/tests/libs/zbxcommon/zbx_token_find.yaml
index 798680d3e45..c09ddf73479 100644
--- a/tests/libs/zbxcommon/zbx_token_find.yaml
+++ b/tests/libs/zbxcommon/zbx_token_find.yaml
@@ -543,7 +543,7 @@ in:
out:
token: '{?{HOST.HOST}'
token_type: ZBX_TOKEN_EXPRESSION_MACRO
- expression: '{HOST.HOST'
+ expression: '{HOST.HOST}'
return: SUCCEED
---
test case: 'Success: {?{$MACRO}}'
diff --git a/tests/libs/zbxeval/zbx_eval_execute_ext.c b/tests/libs/zbxeval/zbx_eval_execute_ext.c
index 185c3ad5f84..0a03776c7bd 100644
--- a/tests/libs/zbxeval/zbx_eval_execute_ext.c
+++ b/tests/libs/zbxeval/zbx_eval_execute_ext.c
@@ -112,12 +112,14 @@ static void mock_read_callbacks(const char *path)
}
}
-static int callback_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args,
- zbx_variant_t *value, char **error)
+static int callback_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args, void *data,
+ const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
{
int i;
ZBX_UNUSED(args);
+ ZBX_UNUSED(data);
+ ZBX_UNUSED(ts);
for (i = 0; i < callbacks.values_num; i++)
{
@@ -167,7 +169,7 @@ void zbx_mock_test_entry(void **state)
mock_eval_read_values(&ctx, "in.replace");
mock_read_callbacks("in.callbacks");
- returned_ret = zbx_eval_execute_ext(&ctx, NULL, callback_cb, &value, &error);
+ returned_ret = zbx_eval_execute_ext(&ctx, NULL, callback_cb, callback_cb, NULL, &value, &error);
if (SUCCEED != returned_ret)
printf("ERROR: %s\n", error);
diff --git a/tests/libs/zbxeval/zbx_eval_execute_ext.yaml b/tests/libs/zbxeval/zbx_eval_execute_ext.yaml
index c01faf467ff..4c9aea8aaca 100644
--- a/tests/libs/zbxeval/zbx_eval_execute_ext.yaml
+++ b/tests/libs/zbxeval/zbx_eval_execute_ext.yaml
@@ -52,7 +52,7 @@ in:
callbacks:
- name: err
args_num: 0
- reterr: 'forced return error'
+ error: 'forced return error'
out:
result: SUCCEED
value: 1
@@ -64,7 +64,7 @@ in:
callbacks:
- name: err
args_num: 0
- reterr: 'forced return error'
+ error: 'forced return error'
out:
result: FAIL
---
@@ -75,7 +75,7 @@ in:
callbacks:
- name: err
args_num: 0
- reterr: 'forced return error'
+ error: 'forced return error'
out:
result: SUCCEED
value: 0
@@ -87,7 +87,7 @@ in:
callbacks:
- name: err
args_num: 0
- reterr: 'forced return error'
+ error: 'forced return error'
out:
result: FAIL
---
diff --git a/tests/libs/zbxeval/zbx_eval_parse_expression.c b/tests/libs/zbxeval/zbx_eval_parse_expression.c
index d1fcb36549a..4669d5e81d3 100644
--- a/tests/libs/zbxeval/zbx_eval_parse_expression.c
+++ b/tests/libs/zbxeval/zbx_eval_parse_expression.c
@@ -48,7 +48,6 @@ static const char *mock_token_type2str(zbx_uint32_t type)
ZBX_MOCK_TOKEN_CASE(OP_NOT)
ZBX_MOCK_TOKEN_CASE(VAR_NUM)
ZBX_MOCK_TOKEN_CASE(VAR_STR)
- ZBX_MOCK_TOKEN_CASE(VAR_TIME)
ZBX_MOCK_TOKEN_CASE(VAR_MACRO)
ZBX_MOCK_TOKEN_CASE(VAR_USERMACRO)
ZBX_MOCK_TOKEN_CASE(VAR_LLDMACRO)
@@ -90,7 +89,6 @@ static zbx_uint32_t mock_token_str2type(const char *str)
ZBX_MOCK_TOKEN_IF(OP_NOT)
ZBX_MOCK_TOKEN_IF(VAR_NUM)
ZBX_MOCK_TOKEN_IF(VAR_STR)
- ZBX_MOCK_TOKEN_IF(VAR_TIME)
ZBX_MOCK_TOKEN_IF(VAR_MACRO)
ZBX_MOCK_TOKEN_IF(VAR_USERMACRO)
ZBX_MOCK_TOKEN_IF(VAR_LLDMACRO)
diff --git a/tests/libs/zbxeval/zbx_eval_parse_expression.yaml b/tests/libs/zbxeval/zbx_eval_parse_expression.yaml
index 4d5e1251d80..0be187fded3 100644
--- a/tests/libs/zbxeval/zbx_eval_parse_expression.yaml
+++ b/tests/libs/zbxeval/zbx_eval_parse_expression.yaml
@@ -1508,6 +1508,59 @@ in:
out:
result: FAIL
---
+test case: Succeed 'last(/host/key)'
+in:
+ rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION]
+ expression: 'last(/host/key)'
+out:
+ stack:
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 1}
+ result: SUCCEED
+---
+test case: Succeed 'last(/host/key,#1)'
+in:
+ rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION]
+ expression: 'last(/host/key,#1)'
+out:
+ stack:
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#1', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 2}
+ result: SUCCEED
+---
+test case: Succeed 'count(//trap[1],#5,,0)'
+in:
+ rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION]
+ expression: 'count(//trap[1],#5,,0)'
+out:
+ stack:
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '//trap[1]', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#5', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_NULL, token: '', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '0', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4}
+ result: SUCCEED
+---
+test case: Succeed 'count(//trap[1],#5,,0) + count(/Trapper/trap[1] ,5m ,"1h ","1 ")'
+in:
+ rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION]
+ expression: 'count(//trap[1],#5,,0) + count(/Trapper/trap[1] ,5m ,"1h","1")'
+out:
+ stack:
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '//trap[1]', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#5', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_NULL, token: '', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '0', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4}
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/Trapper/trap[1]', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '5m', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_VAR_STR, token: '"1h"', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_VAR_STR, token: '"1"', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4}
+ - {type: ZBX_EVAL_TOKEN_OP_ADD, token: '+', opt: 0}
+ result: SUCCEED
+---
test case: Succeed 'min(1 + 2, 0.5 + 1.5)'
in:
rules: [ZBX_EVAL_PARSE_FUNCTION]
@@ -1557,4 +1610,17 @@ out:
- {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '-1', opt: 0}
- {type: ZBX_EVAL_TOKEN_OP_EQ, token: '=', opt: 0}
result: SUCCEED
+---
+test case: Succeed 'last(/host/key,#1:now-1h)'
+in:
+ rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION]
+ expression: 'last(/host/key,#1:now-1h)'
+out:
+ stack:
+ - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#1:now-1h', opt: 0}
+ - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 2}
+ result: SUCCEED
...
+
+