1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "zbxserver.h"
21 #include "log.h"
22 #include "valuecache.h"
23 #include "evalfunc.h"
24 #include "zbxeval.h"
25 #include "expression.h"
26
27 #define ZBX_ITEM_QUERY_UNSET 0x0000
28
29 #define ZBX_ITEM_QUERY_HOST_SELF 0x0001
30 #define ZBX_ITEM_QUERY_HOST_ONE 0x0002
31 #define ZBX_ITEM_QUERY_HOST_ANY 0x0004
32
33 #define ZBX_ITEM_QUERY_KEY_ONE 0x0010
34 #define ZBX_ITEM_QUERY_KEY_SOME 0x0020
35 #define ZBX_ITEM_QUERY_KEY_ANY 0x0040
36 #define ZBX_ITEM_QUERY_FILTER 0x0100
37
38 #define ZBX_ITEM_QUERY_ERROR 0x8000
39
40 #define ZBX_ITEM_QUERY_MANY (ZBX_ITEM_QUERY_HOST_ANY |\
41 ZBX_ITEM_QUERY_KEY_SOME | ZBX_ITEM_QUERY_KEY_ANY |\
42 ZBX_ITEM_QUERY_FILTER)
43
44 #define ZBX_ITEM_QUERY_ITEM_ANY (ZBX_ITEM_QUERY_HOST_ANY | ZBX_ITEM_QUERY_KEY_ANY)
45
46 /* one item query data - index in hostkeys items */
47 typedef struct
48 {
49 int dcitem_hk_index;
50 }
51 zbx_expression_query_one_t;
52
53 /* many item query data - matching itemids */
54 typedef struct
55 {
56 zbx_vector_uint64_t itemids;
57 }
58 zbx_expression_query_many_t;
59
60 /* expression item query */
61 typedef struct
62 {
63 /* query flags, see see ZBX_ITEM_QUERY_* defines */
64 zbx_uint32_t flags;
65
66 /* the item query /host/key?[filter] */
67 zbx_item_query_t ref;
68
69 /* the query error */
70 char *error;
71
72 /* the expression item query data, zbx_expression_query_one_t or zbx_expression_query_many_t */
73 void *data;
74 }
75 zbx_expression_query_t;
76
77 /* group - hostids cache */
78 typedef struct
79 {
80 char *name;
81 zbx_vector_uint64_t hostids;
82 }
83 zbx_expression_group_t;
84
85 /* item - tags cache */
86 typedef struct
87 {
88 zbx_uint64_t itemid;
89 zbx_vector_ptr_t tags;
90 }
91 zbx_expression_item_t;
92
expression_query_free_one(zbx_expression_query_one_t * query)93 static void expression_query_free_one(zbx_expression_query_one_t *query)
94 {
95 zbx_free(query);
96 }
97
expression_query_free_many(zbx_expression_query_many_t * query)98 static void expression_query_free_many(zbx_expression_query_many_t *query)
99 {
100 zbx_vector_uint64_destroy(&query->itemids);
101 zbx_free(query);
102 }
103
expression_query_free(zbx_expression_query_t * query)104 static void expression_query_free(zbx_expression_query_t *query)
105 {
106 zbx_eval_clear_query(&query->ref);
107
108 if (ZBX_ITEM_QUERY_ERROR == query->flags)
109 zbx_free(query->error);
110 else if (0 != (query->flags & ZBX_ITEM_QUERY_MANY))
111 expression_query_free_many((zbx_expression_query_many_t*) query->data);
112 else
113 expression_query_free_one((zbx_expression_query_one_t*) query->data);
114
115 zbx_free(query);
116 }
117
118 /******************************************************************************
119 * *
120 * Function: test_key_param_wildcard_cb *
121 * *
122 * Purpose: check if key parameter is a wildcard '*' *
123 * *
124 ******************************************************************************/
test_key_param_wildcard_cb(const char * data,int key_type,int level,int num,int quoted,void * cb_data,char ** param)125 static int test_key_param_wildcard_cb(const char *data, int key_type, int level, int num, int quoted,
126 void *cb_data, char **param)
127 {
128 ZBX_UNUSED(key_type);
129 ZBX_UNUSED(num);
130 ZBX_UNUSED(quoted);
131 ZBX_UNUSED(param);
132
133 if (0 == level)
134 return SUCCEED;
135
136 if ('*' == data[0] && '\0' == data[1])
137 {
138 *(int *)cb_data = 1;
139 return FAIL;
140 }
141
142 return SUCCEED;
143 }
144
145 /******************************************************************************
146 * *
147 * Function: expression_create_query *
148 * *
149 * Purpose: create expression item query from item query /host/key?[filter] *
150 * *
151 * Parameters: itemquery - [IN] the item query *
152 * *
153 * Return value: The created expression item query. *
154 * *
155 ******************************************************************************/
expression_create_query(const char * itemquery)156 static zbx_expression_query_t* expression_create_query(const char *itemquery)
157 {
158 zbx_expression_query_t *query;
159
160 query = (zbx_expression_query_t *)zbx_malloc(NULL, sizeof(zbx_expression_query_t));
161 memset(query, 0, sizeof(zbx_expression_query_t));
162
163 query->flags = ZBX_ITEM_QUERY_UNSET;
164
165 if (0 != zbx_eval_parse_query(itemquery, strlen(itemquery), &query->ref))
166 {
167 if (NULL == query->ref.host)
168 query->flags |= ZBX_ITEM_QUERY_HOST_SELF;
169 else if ('*' == *query->ref.host)
170 query->flags |= ZBX_ITEM_QUERY_HOST_ANY;
171 else
172 query->flags |= ZBX_ITEM_QUERY_HOST_ONE;
173
174 if (NULL != query->ref.filter)
175 query->flags |= ZBX_ITEM_QUERY_FILTER;
176
177 if ('*' == *query->ref.key)
178 {
179 query->flags |= ZBX_ITEM_QUERY_KEY_ANY;
180 }
181 else if (NULL != strchr(query->ref.key, '*'))
182 {
183 int wildcard = 0;
184
185 replace_key_params_dyn(&query->ref.key, ZBX_KEY_TYPE_ITEM, test_key_param_wildcard_cb,
186 &wildcard, NULL, 0);
187
188 if (0 != wildcard)
189 query->flags |= ZBX_ITEM_QUERY_KEY_SOME;
190 else
191 query->flags |= ZBX_ITEM_QUERY_KEY_ONE;
192 }
193 else
194 query->flags |= ZBX_ITEM_QUERY_KEY_ONE;
195 }
196
197 return query;
198 }
199
200 /******************************************************************************
201 * *
202 * Function: expression_group_free *
203 * *
204 ******************************************************************************/
expression_group_free(zbx_expression_group_t * group)205 static void expression_group_free(zbx_expression_group_t *group)
206 {
207 zbx_free(group->name);
208 zbx_vector_uint64_destroy(&group->hostids);
209 zbx_free(group);
210 }
211
212 /******************************************************************************
213 * *
214 * Function: expression_get_group *
215 * *
216 * Purpose: get group from cache by name *
217 * *
218 * Parameters: eval - [IN] the evaluation data *
219 * name - [IN] the group name *
220 * *
221 * Return value: The cached group. *
222 * *
223 * Comments: Cache group if necessary. *
224 * *
225 ******************************************************************************/
expression_get_group(zbx_expression_eval_t * eval,const char * name)226 static zbx_expression_group_t *expression_get_group(zbx_expression_eval_t *eval, const char *name)
227 {
228 int i;
229 zbx_expression_group_t *group;
230
231 for (i = 0; i < eval->groups.values_num; i++)
232 {
233 group = (zbx_expression_group_t *)eval->groups.values[i];
234
235 if (0 == strcmp(group->name, name))
236 return group;
237 }
238
239 group = (zbx_expression_group_t *)zbx_malloc(NULL, sizeof(zbx_expression_group_t));
240 group->name = zbx_strdup(NULL, name);
241 zbx_vector_uint64_create(&group->hostids);
242 zbx_dc_get_hostids_by_group_name(name, &group->hostids);
243 zbx_vector_ptr_append(&eval->groups, group);
244
245 return group;
246 }
247
248 /******************************************************************************
249 * *
250 * Function: expression_get_item *
251 * *
252 * Purpose: get item from cache by itemid *
253 * *
254 * Parameters: eval - [IN] the evaluation data *
255 * itemid - [IN] the item identifier *
256 * *
257 * Return value: The cached item. *
258 * *
259 * Comments: Cache item if necessary. *
260 * *
261 ******************************************************************************/
expression_get_item(zbx_expression_eval_t * eval,zbx_uint64_t itemid)262 static zbx_expression_item_t *expression_get_item(zbx_expression_eval_t *eval, zbx_uint64_t itemid)
263 {
264 int i;
265 zbx_expression_item_t *item;
266
267 for (i = 0; i < eval->itemtags.values_num; i++)
268 {
269 item = (zbx_expression_item_t *)eval->itemtags.values[i];
270
271 if (item->itemid == itemid)
272 return item;
273 }
274
275 item = (zbx_expression_item_t *)zbx_malloc(NULL, sizeof(zbx_expression_group_t));
276 item->itemid = itemid;
277 zbx_vector_ptr_create(&item->tags);
278 zbx_dc_get_item_tags(itemid, &item->tags);
279 zbx_vector_ptr_append(&eval->itemtags, item);
280
281 return item;
282 }
283
284 /******************************************************************************
285 * *
286 * Function: expression_item_free *
287 * *
288 ******************************************************************************/
expression_item_free(zbx_expression_item_t * item)289 static void expression_item_free(zbx_expression_item_t *item)
290 {
291 zbx_vector_ptr_clear_ext(&item->tags, (zbx_clean_func_t) zbx_free_item_tag);
292 zbx_vector_ptr_destroy(&item->tags);
293 zbx_free(item);
294 }
295
296 /******************************************************************************
297 * *
298 * Function: expression_init_query_one *
299 * *
300 * Purpose: initialize one item query *
301 * *
302 * Parameters: eval - [IN] the evaluation data *
303 * query - [IN] the query to initialize *
304 * *
305 ******************************************************************************/
expression_init_query_one(zbx_expression_eval_t * eval,zbx_expression_query_t * query)306 static void expression_init_query_one(zbx_expression_eval_t *eval, zbx_expression_query_t *query)
307 {
308 zbx_expression_query_one_t *data;
309
310 data = (zbx_expression_query_one_t *)zbx_malloc(NULL, sizeof(zbx_expression_query_one_t));
311 data->dcitem_hk_index = eval->one_num++;
312 query->data = data;
313 }
314
315 /******************************************************************************
316 * *
317 * Function: replace_key_param_wildcard_cb *
318 * *
319 * Purpose: replace wildcards '*'in key parameters with % and escape existing *
320 * %, \ characters for SQL like operation *
321 * *
322 ******************************************************************************/
replace_key_param_wildcard_cb(const char * data,int key_type,int level,int num,int quoted,void * cb_data,char ** param)323 static int replace_key_param_wildcard_cb(const char *data, int key_type, int level, int num, int quoted, void *cb_data,
324 char **param)
325 {
326 char *tmp;
327
328 ZBX_UNUSED(key_type);
329 ZBX_UNUSED(num);
330 ZBX_UNUSED(cb_data);
331
332 if (0 == level)
333 return SUCCEED;
334
335 if ('*' == data[0] && '\0' == data[1])
336 {
337 *param = zbx_strdup(NULL, "%");
338 return SUCCEED;
339 }
340
341 if (NULL == strchr(data, '%') && NULL == strchr(data, '\\'))
342 return SUCCEED;
343
344 tmp = zbx_strdup(NULL, data);
345 unquote_key_param(tmp);
346 *param = zbx_dyn_escape_string(tmp, "\\%%");
347 zbx_free(tmp);
348
349 /* escaping cannot result in unquotable parameter */
350 if (FAIL == quote_key_param(param, quoted))
351 {
352 THIS_SHOULD_NEVER_HAPPEN;
353 zbx_free(*param);
354 }
355
356 return SUCCEED;
357 }
358
359 /******************************************************************************
360 * *
361 * Function: expression_match_item_key *
362 * *
363 * Purpose: check if item key matches the pattern *
364 * *
365 * Parameters: item_key - [IN] the item key to match *
366 * pattern - [IN] the pattern *
367 * *
368 ******************************************************************************/
expression_match_item_key(const char * item_key,const AGENT_REQUEST * pattern)369 static int expression_match_item_key(const char *item_key, const AGENT_REQUEST *pattern)
370 {
371 AGENT_REQUEST key;
372 int i, ret = FAIL;
373
374 init_request(&key);
375
376 if (SUCCEED != parse_item_key(item_key, &key))
377 goto out;
378
379 if (pattern->nparam != key.nparam)
380 goto out;
381
382 if (0 != strcmp(pattern->key, key.key))
383 goto out;
384
385 for (i = 0; i < key.nparam; i++)
386 {
387 if (0 == strcmp(pattern->params[i], "*"))
388 continue;
389
390 if (0 != strcmp(pattern->params[i], key.params[i]))
391 goto out;
392 }
393
394 ret = SUCCEED;
395 out:
396 free_request(&key);
397
398 return ret;
399 }
400
401 typedef struct
402 {
403 zbx_uint64_t itemid;
404 zbx_uint64_t hostid;
405 zbx_expression_eval_t *eval;
406 }
407 zbx_expression_eval_many_t;
408
409 /******************************************************************************
410 * *
411 * Function: expression_get_item_candidates *
412 * *
413 * Purpose: get itemids + hostids of items that might match query based on *
414 * host, key and filter groups *
415 * *
416 * Parameters: eval - [IN] the evaluation data *
417 * query - [IN] the expression item query *
418 * groups - [IN] the groups in filter template *
419 * filter_template - [IN] the group filter template with {index} *
420 * placeholders referring to a group in *
421 * groups vector *
422 * itemhosts - [out] itemid+hostid pairs matching query *
423 * *
424 ******************************************************************************/
expression_get_item_candidates(zbx_expression_eval_t * eval,const zbx_expression_query_t * query,const zbx_vector_str_t * groups,const char * filter_template,zbx_vector_uint64_pair_t * itemhosts)425 static void expression_get_item_candidates(zbx_expression_eval_t *eval, const zbx_expression_query_t *query,
426 const zbx_vector_str_t *groups, const char *filter_template, zbx_vector_uint64_pair_t *itemhosts)
427 {
428 DB_RESULT result;
429 DB_ROW row;
430 char *sql = NULL, *esc, *clause = "where";
431 size_t sql_alloc = 0, sql_offset = 0;
432 AGENT_REQUEST pattern;
433
434 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select i.itemid,i.hostid");
435
436 if (0 != (query->flags & ZBX_ITEM_QUERY_KEY_SOME))
437 {
438 init_request(&pattern);
439 if (SUCCEED != parse_item_key(query->ref.key, &pattern))
440 {
441 THIS_SHOULD_NEVER_HAPPEN;
442 zbx_free(sql);
443 return;
444 }
445
446 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ",i.key_");
447 }
448
449 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " from items i");
450
451 if (0 != (query->flags & ZBX_ITEM_QUERY_HOST_ONE))
452 {
453 esc = DBdyn_escape_string(query->ref.host);
454 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ",hosts h"
455 " where h.hostid=i.hostid"
456 " and h.host='%s'", esc);
457 zbx_free(esc);
458 clause = "and";
459 }
460 else if (0 != (query->flags & ZBX_ITEM_QUERY_HOST_SELF))
461 {
462 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where i.hostid=" ZBX_FS_UI64,
463 eval->hostid);
464 clause = "and";
465 }
466
467 if (0 != (query->flags & ZBX_ITEM_QUERY_KEY_SOME))
468 {
469 char *key;
470
471 key = zbx_strdup(NULL, query->ref.key);
472 replace_key_params_dyn(&key, ZBX_KEY_TYPE_ITEM, replace_key_param_wildcard_cb, NULL, NULL, 0);
473
474 esc = DBdyn_escape_string(key);
475 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " %s i.key_ like '%s'", clause, esc);
476 zbx_free(esc);
477 zbx_free(key);
478 clause = "and";
479 }
480 else if (0 != (query->flags & ZBX_ITEM_QUERY_KEY_ONE))
481 {
482 esc = DBdyn_escape_string(query->ref.key);
483 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " %s i.key_='%s'", clause, esc);
484 zbx_free(esc);
485 clause = "and";
486 }
487
488 if (0 != (query->flags & ZBX_ITEM_QUERY_FILTER) && NULL != filter_template && '\0' != *filter_template)
489 {
490 zbx_uint64_t index;
491 int pos = 0, last_pos = 0;
492 zbx_token_t token;
493 zbx_expression_group_t *group;
494
495 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " %s ", clause);
496
497 for (; SUCCEED == zbx_token_find(filter_template, pos, &token, ZBX_TOKEN_SEARCH_FUNCTIONID); pos++)
498 {
499 if (ZBX_TOKEN_OBJECTID != token.type)
500 continue;
501
502 if (SUCCEED != is_uint64_n(filter_template + token.loc.l + 1, token.loc.r - token.loc.l - 1,
503 &index) && (int)index < groups->values_num)
504 {
505 continue;
506 }
507
508 group = expression_get_group(eval, groups->values[index]);
509
510 zbx_strncpy_alloc(&sql, &sql_alloc, &sql_offset, filter_template + last_pos,
511 token.loc.l - last_pos);
512
513 if (' ' == sql[sql_offset - 1])
514 sql_offset--;
515
516 if (0 < group->hostids.values_num)
517 {
518 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", group->hostids.values,
519 group->hostids.values_num);
520 }
521 else
522 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " 1=0");
523
524 last_pos = token.loc.r + 1;
525 pos = token.loc.r;
526 }
527
528 if ('\0' != filter_template[last_pos])
529 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, filter_template + last_pos);
530 }
531
532 result = DBselect("%s", sql);
533
534 while (NULL != (row = DBfetch(result)))
535 {
536 zbx_uint64_pair_t pair;
537
538 if (0 == (query->flags & ZBX_ITEM_QUERY_KEY_SOME) ||
539 (NULL != pattern.key && SUCCEED == expression_match_item_key(row[2], &pattern)))
540 {
541 ZBX_STR2UINT64(pair.first, row[0]);
542 ZBX_STR2UINT64(pair.second, row[1]);
543 zbx_vector_uint64_pair_append(itemhosts, pair);
544 }
545 }
546 DBfree_result(result);
547
548 if (0 != (query->flags & ZBX_ITEM_QUERY_KEY_SOME))
549 free_request(&pattern);
550
551 zbx_free(sql);
552 }
553
554 /******************************************************************************
555 * *
556 * Function: expression_item_check_tag *
557 * *
558 * Purpose: check if the item matches the tag *
559 * *
560 * Parameters: item - [IN] the item with tags *
561 * tag - [IN] the tag to match in format <tag name>[:<tag value>]*
562 * *
563 * Return value: SUCCEED - the item matches the specified tag *
564 * FAIL - otherwise *
565 * *
566 ******************************************************************************/
expression_item_check_tag(zbx_expression_item_t * item,const char * tag)567 static int expression_item_check_tag(zbx_expression_item_t *item, const char *tag)
568 {
569 int i;
570 size_t taglen;
571 const char *value;
572
573 if (NULL != (value = strchr(tag, ':')))
574 {
575 taglen = (value - tag);
576 value++;
577 }
578 else
579 taglen = strlen(tag);
580
581 for (i = 0; i < item->tags.values_num; i++)
582 {
583 zbx_item_tag_t *itemtag = (zbx_item_tag_t *)item->tags.values[i];
584
585 if (taglen != strlen(itemtag->tag.tag) || 0 != memcmp(tag, itemtag->tag.tag, taglen))
586 continue;
587
588 if (NULL == value)
589 return SUCCEED;
590
591 if (0 == strcmp(itemtag->tag.value, value))
592 return SUCCEED;
593 }
594
595 return FAIL;
596 }
597
598 /******************************************************************************
599 * *
600 * Function: expression_eval_filter *
601 * *
602 * Purpose: evaluate filter function *
603 * *
604 * Parameters: name - [IN] the function name (not zero terminated) *
605 * len - [IN] the function name length *
606 * args_num - [IN] the number of function arguments *
607 * args - [IN] an array of the function arguments. *
608 * data - [IN] the caller data used for function evaluation *
609 * ts - [IN] the function execution time *
610 * value - [OUT] the function return value *
611 * error - [OUT] the error message if function failed *
612 * *
613 * Return value: SUCCEED - the function was evaluated successfully *
614 * FAIL - otherwise *
615 * *
616 * Comments: The group/tag comparisons in filter are converted to function *
617 * calls that are evaluated by this callback. *
618 * *
619 ******************************************************************************/
expression_eval_filter(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)620 static int expression_eval_filter(const char *name, size_t len, int args_num, const zbx_variant_t *args,
621 void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
622 {
623 zbx_expression_eval_many_t *many = (zbx_expression_eval_many_t *)data;
624
625 ZBX_UNUSED(ts);
626 ZBX_UNUSED(len);
627
628 if (1 != args_num)
629 {
630 *error = zbx_strdup(NULL, "invalid number of arguments");
631 return FAIL;
632 }
633
634 if (ZBX_VARIANT_STR != args[0].type)
635 {
636 *error = zbx_strdup(NULL, "invalid argument flags");
637 return FAIL;
638 }
639
640 if (0 == strncmp(name, "group", ZBX_CONST_STRLEN("group")))
641 {
642 zbx_expression_group_t *group;
643
644 group = expression_get_group(many->eval, args[0].data.str);
645
646 if (FAIL != zbx_vector_uint64_bsearch(&group->hostids, many->hostid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
647 zbx_variant_set_dbl(value, 1);
648 else
649 zbx_variant_set_dbl(value, 0);
650
651 return SUCCEED;
652 }
653 else if (0 == strncmp(name, "tag", ZBX_CONST_STRLEN("tag")))
654 {
655 zbx_expression_item_t *item;
656
657 item = expression_get_item(many->eval, many->itemid);
658
659 if (SUCCEED == expression_item_check_tag(item, args[0].data.str))
660 zbx_variant_set_dbl(value, 1);
661 else
662 zbx_variant_set_dbl(value, 0);
663
664 return SUCCEED;
665 }
666 else
667 {
668 *error = zbx_strdup(NULL, "unknown function");
669 return FAIL;
670 }
671 }
672
673 /******************************************************************************
674 * *
675 * Function: expression_init_query_many *
676 * *
677 * Purpose: initialize many item query *
678 * *
679 * Parameters: eval - [IN] the evaluation data *
680 * query - [IN] the query to initialize *
681 * *
682 ******************************************************************************/
expression_init_query_many(zbx_expression_eval_t * eval,zbx_expression_query_t * query)683 static void expression_init_query_many(zbx_expression_eval_t *eval, zbx_expression_query_t *query)
684 {
685 zbx_expression_query_many_t *data;
686 char *error = NULL, *errmsg = NULL, *filter_template = NULL;
687 int i, ret = FAIL;
688 zbx_eval_context_t ctx;
689 zbx_vector_uint64_pair_t itemhosts;
690 zbx_vector_str_t groups;
691 zbx_vector_uint64_t itemids;
692
693 zabbix_log(LOG_LEVEL_DEBUG, "In %s() /%s/%s?[%s]", __func__, ZBX_NULL2EMPTY_STR(query->ref.host),
694 ZBX_NULL2EMPTY_STR(query->ref.key), ZBX_NULL2EMPTY_STR(query->ref.filter));
695
696 zbx_eval_init(&ctx);
697
698 zbx_vector_uint64_create(&itemids);
699 zbx_vector_uint64_pair_create(&itemhosts);
700 zbx_vector_str_create(&groups);
701
702 if (ZBX_ITEM_QUERY_ITEM_ANY == (query->flags & ZBX_ITEM_QUERY_ITEM_ANY))
703 {
704 error = zbx_strdup(NULL, "item query must have at least a host or an item key defined");
705 goto out;
706 }
707
708 if (0 != (query->flags & ZBX_ITEM_QUERY_FILTER))
709 {
710 if (SUCCEED != zbx_eval_parse_expression(&ctx, query->ref.filter, ZBX_EVAL_PARSE_QUERY_EXPRESSION,
711 &errmsg))
712 {
713 error = zbx_dsprintf(NULL, "failed to parse item query filter: %s", errmsg);
714 zbx_free(errmsg);
715 goto out;
716 }
717
718 zbx_eval_prepare_filter(&ctx);
719
720 if (FAIL == zbx_eval_get_group_filter(&ctx, &groups, &filter_template, &errmsg))
721 {
722 error = zbx_dsprintf(NULL, "failed to extract groups from item filter: %s", errmsg);
723 zbx_free(errmsg);
724 goto out;
725 }
726 }
727
728 expression_get_item_candidates(eval, query, &groups, filter_template, &itemhosts);
729
730 if (0 != (query->flags & ZBX_ITEM_QUERY_FILTER))
731 {
732 zbx_expression_eval_many_t eval_data;
733 zbx_variant_t filter_value;
734
735 eval_data.eval = eval;
736
737 for (i = 0; i < itemhosts.values_num; i++)
738 {
739 eval_data.itemid = itemhosts.values[i].first;
740 eval_data.hostid = itemhosts.values[i].second;
741
742 if (SUCCEED != zbx_eval_execute_ext(&ctx, NULL, expression_eval_filter, NULL, (void *)&eval_data,
743 &filter_value, &errmsg))
744 {
745 zabbix_log(LOG_LEVEL_DEBUG, "failed to evaluate item query filter: %s", errmsg);
746 zbx_free(errmsg);
747 continue;
748 }
749
750 if (SUCCEED != zbx_variant_convert(&filter_value, ZBX_VARIANT_DBL))
751 {
752 zabbix_log(LOG_LEVEL_DEBUG, "unexpected item query filter evaluation result:"
753 " value:\"%s\" of type \"%s\"", zbx_variant_value_desc(&filter_value),
754 zbx_variant_type_desc(&filter_value));
755
756 zbx_variant_clear(&filter_value);
757 continue;
758 }
759
760 if (SUCCEED != zbx_double_compare(filter_value.data.dbl, 0))
761 zbx_vector_uint64_append(&itemids, eval_data.itemid);
762 }
763 }
764 else
765 {
766 for (i = 0; i < itemhosts.values_num; i++)
767 zbx_vector_uint64_append(&itemids, itemhosts.values[i].first);
768 }
769
770 if (0 == itemids.values_num)
771 {
772 error = zbx_strdup(NULL, "no items matching query");
773 goto out;
774 }
775
776 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
777 {
778 for (i = 0; i < itemids.values_num; i++)
779 zabbix_log(LOG_LEVEL_DEBUG, "%s() itemid:" ZBX_FS_UI64, __func__, itemids.values[i]);
780 }
781
782 data = (zbx_expression_query_many_t *)zbx_malloc(NULL, sizeof(zbx_expression_query_many_t));
783 data->itemids = itemids;
784 query->data = data;
785 eval->many_num++;
786
787 ret = SUCCEED;
788 out:
789 if (0 != (query->flags & ZBX_ITEM_QUERY_FILTER) && SUCCEED == zbx_eval_status(&ctx))
790 zbx_eval_clear(&ctx);
791
792 if (SUCCEED != ret)
793 {
794 query->error = error;
795 query->flags = ZBX_ITEM_QUERY_ERROR;
796 zbx_vector_uint64_destroy(&itemids);
797 }
798
799 zbx_free(filter_template);
800
801 zbx_vector_uint64_pair_destroy(&itemhosts);
802
803 zbx_vector_str_clear_ext(&groups, zbx_str_free);
804 zbx_vector_str_destroy(&groups);
805
806 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() items:%d", __func__, (SUCCEED == ret ? data->itemids.values_num : -1));
807 }
808
809 /******************************************************************************
810 * *
811 * Function: expression_cache_dcitems_hk *
812 * *
813 * Purpose: cache items used in one item queries *
814 * *
815 * Parameters: eval - [IN] the evaluation data *
816 * *
817 ******************************************************************************/
expression_cache_dcitems_hk(zbx_expression_eval_t * eval)818 static void expression_cache_dcitems_hk(zbx_expression_eval_t *eval)
819 {
820 int i;
821
822 eval->hostkeys = (zbx_host_key_t *)zbx_malloc(NULL, sizeof(zbx_host_key_t) * eval->one_num);
823 eval->dcitems_hk = (DC_ITEM *)zbx_malloc(NULL, sizeof(DC_ITEM) * eval->one_num);
824 eval->errcodes_hk = (int *)zbx_malloc(NULL, sizeof(int) * eval->one_num);
825
826 for (i = 0; i < eval->queries.values_num; i++)
827 {
828 zbx_expression_query_t *query = (zbx_expression_query_t *)eval->queries.values[i];
829 zbx_expression_query_one_t *data;
830
831 if (0 != (query->flags & ZBX_ITEM_QUERY_MANY) || ZBX_ITEM_QUERY_ERROR == query->flags)
832 continue;
833
834 data = (zbx_expression_query_one_t *)query->data;
835
836 eval->hostkeys[data->dcitem_hk_index].host = query->ref.host;
837 eval->hostkeys[data->dcitem_hk_index].key = query->ref.key;
838 }
839
840 DCconfig_get_items_by_keys(eval->dcitems_hk, eval->hostkeys, eval->errcodes_hk, eval->one_num);
841 }
842
843 /******************************************************************************
844 * *
845 * Purpose: dcitem reference vector lookup functions *
846 * *
847 ******************************************************************************/
compare_dcitems_by_itemid(const void * d1,const void * d2)848 static int compare_dcitems_by_itemid(const void *d1, const void *d2)
849 {
850 DC_ITEM *dci1 = *(DC_ITEM **)d1;
851 DC_ITEM *dci2 = *(DC_ITEM **)d2;
852
853 ZBX_RETURN_IF_NOT_EQUAL(dci1->itemid, dci2->itemid);
854
855 return 0;
856 }
857
expression_find_dcitem_by_itemid(const void * d1,const void * d2)858 static int expression_find_dcitem_by_itemid(const void *d1, const void *d2)
859 {
860 zbx_uint64_t itemid = **(zbx_uint64_t **)d1;
861 DC_ITEM *dci = *(DC_ITEM **)d2;
862
863 ZBX_RETURN_IF_NOT_EQUAL(itemid, dci->itemid);
864
865 return 0;
866 }
867
868 /******************************************************************************
869 * *
870 * Function: expression_cache_dcitems *
871 * *
872 * Purpose: cache items used in many item queries *
873 * *
874 * Parameters: eval - [IN] the evaluation data *
875 * *
876 ******************************************************************************/
expression_cache_dcitems(zbx_expression_eval_t * eval)877 static void expression_cache_dcitems(zbx_expression_eval_t *eval)
878 {
879 int i, j;
880 zbx_vector_uint64_t itemids;
881
882 zbx_vector_uint64_create(&itemids);
883
884 if (0 != eval->one_num)
885 {
886 for (i = 0; i < eval->one_num; i++)
887 {
888 if (SUCCEED != eval->errcodes_hk[i])
889 continue;
890
891 zbx_vector_ptr_append(&eval->dcitem_refs, &eval->dcitems_hk[i]);
892 }
893
894 zbx_vector_ptr_sort(&eval->dcitem_refs, compare_dcitems_by_itemid);
895 }
896
897 for (i = 0; i < eval->queries.values_num; i++)
898 {
899 zbx_expression_query_t *query = (zbx_expression_query_t *)eval->queries.values[i];
900 zbx_expression_query_many_t *data;
901
902 if (0 == (query->flags & ZBX_ITEM_QUERY_MANY))
903 continue;
904
905 data = (zbx_expression_query_many_t *)query->data;
906
907 for (j = 0; j < data->itemids.values_num; j++)
908 zbx_vector_uint64_append(&itemids, data->itemids.values[j]);
909 }
910
911 zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
912 zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
913
914 for (i = 0; i < itemids.values_num;)
915 {
916 if (FAIL != zbx_vector_ptr_bsearch(&eval->dcitem_refs, &itemids.values[i], expression_find_dcitem_by_itemid))
917 {
918 zbx_vector_uint64_remove(&itemids, i);
919 continue;
920 }
921 i++;
922 }
923
924 if (0 != (eval->dcitems_num = itemids.values_num))
925 {
926 zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
927
928 eval->dcitems = (DC_ITEM *)zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num);
929 eval->errcodes = (int *)zbx_malloc(NULL, sizeof(int) * itemids.values_num);
930
931 DCconfig_get_items_by_itemids(eval->dcitems, itemids.values, eval->errcodes, itemids.values_num);
932
933 for (i = 0; i < itemids.values_num; i++)
934 {
935 if (SUCCEED != eval->errcodes[i])
936 continue;
937
938 zbx_vector_ptr_append(&eval->dcitem_refs, &eval->dcitems[i]);
939 }
940
941 zbx_vector_ptr_sort(&eval->dcitem_refs, compare_dcitems_by_itemid);
942 }
943
944 zbx_vector_uint64_destroy(&itemids);
945 }
946
947 /******************************************************************************
948 * *
949 * Function: expression_eval_one *
950 * *
951 * Purpose: evaluate historical function for one item query *
952 * *
953 * Parameters: eval - [IN] the evaluation data *
954 * query - [IN] the item query *
955 * name - [IN] the function name (not zero terminated) *
956 * len - [IN] the function name length *
957 * args_num - [IN] the number of function arguments *
958 * args - [IN] an array of the function arguments. *
959 * data - [IN] the caller data used for function evaluation *
960 * ts - [IN] the function execution time *
961 * value - [OUT] the function return value *
962 * error - [OUT] the error message if function failed *
963 * *
964 * Return value: SUCCEED - the function was executed successfully *
965 * FAIL - otherwise *
966 * *
967 ******************************************************************************/
expression_eval_one(zbx_expression_eval_t * eval,zbx_expression_query_t * query,const char * name,size_t len,int args_num,const zbx_variant_t * args,const zbx_timespec_t * ts,zbx_variant_t * value,char ** error)968 static int expression_eval_one(zbx_expression_eval_t *eval, zbx_expression_query_t *query, const char *name,
969 size_t len, int args_num, const zbx_variant_t *args, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
970 {
971 char func_name[MAX_STRING_LEN], *params = NULL;
972 size_t params_alloc = 0, params_offset = 0;
973 DC_ITEM *item;
974 int i, ret = FAIL;
975 zbx_expression_query_one_t *data;
976
977 zabbix_log(LOG_LEVEL_DEBUG, "In %s() %.*s(/%s/%s?[%s],...)", __func__, (int )len, name,
978 ZBX_NULL2EMPTY_STR(query->ref.host), ZBX_NULL2EMPTY_STR(query->ref.key),
979 ZBX_NULL2EMPTY_STR(query->ref.filter));
980
981 data = (zbx_expression_query_one_t *)query->data;
982
983 if (SUCCEED != eval->errcodes_hk[data->dcitem_hk_index])
984 {
985 *error = zbx_dsprintf(NULL, "item \"/%s/%s\" does not exist",
986 eval->hostkeys[data->dcitem_hk_index].host, eval->hostkeys[data->dcitem_hk_index].key);
987 goto out;
988 }
989
990 item = &eval->dcitems_hk[data->dcitem_hk_index];
991
992 /* do not evaluate if the item is disabled or belongs to a disabled host */
993
994 if (ITEM_STATUS_ACTIVE != item->status)
995 {
996 *error = zbx_dsprintf(NULL, "item \"/%s/%s\" is disabled", eval->hostkeys[data->dcitem_hk_index].host,
997 eval->hostkeys[data->dcitem_hk_index].key);
998 goto out;
999 }
1000
1001 if (HOST_STATUS_MONITORED != item->host.status)
1002 {
1003 *error = zbx_dsprintf(NULL, "host \"%s\" is not monitored", eval->hostkeys[data->dcitem_hk_index].host);
1004 goto out;
1005 }
1006
1007 memcpy(func_name, name, len);
1008 func_name[len] = '\0';
1009
1010 /* If the item is NOTSUPPORTED then evaluation is allowed for: */
1011 /* - functions white-listed in evaluatable_for_notsupported(). */
1012 /* Their values can be evaluated to regular numbers even for */
1013 /* NOTSUPPORTED items. */
1014 /* - other functions. Result of evaluation is ZBX_UNKNOWN. */
1015
1016 if (ITEM_STATE_NOTSUPPORTED == item->state && FAIL == zbx_evaluatable_for_notsupported(func_name))
1017 {
1018 /* compose and store 'unknown' message for future use */
1019 *error = zbx_dsprintf(NULL, "item \"/%s/%s\" is not supported",
1020 eval->hostkeys[data->dcitem_hk_index].host, eval->hostkeys[data->dcitem_hk_index].key);
1021 goto out;
1022 }
1023
1024 if (0 == args_num)
1025 {
1026 ret = evaluate_function2(value, item, func_name, "", ts, error);
1027 goto out;
1028 }
1029
1030 for (i = 0; i < args_num; i++)
1031 {
1032 if (0 != i)
1033 zbx_chrcpy_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ',');
1034
1035 switch (args[i].type)
1036 {
1037 case ZBX_VARIANT_DBL:
1038 zbx_snprintf_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ZBX_FS_DBL64,
1039 args[i].data.dbl);
1040 break;
1041 case ZBX_VARIANT_STR:
1042 zbx_strquote_alloc(¶ms, ¶ms_alloc, ¶ms_offset, args[i].data.str);
1043 break;
1044 case ZBX_VARIANT_UI64:
1045 zbx_snprintf_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ZBX_FS_UI64,
1046 args[i].data.ui64);
1047 break;
1048 case ZBX_VARIANT_NONE:
1049 break;
1050 default:
1051 *error = zbx_dsprintf(NULL, " unsupported argument #%d type \"%s\"", i + 1,
1052 zbx_variant_type_desc(&args[i]));
1053 goto out;
1054 }
1055 }
1056
1057 ret = evaluate_function2(value, item, func_name, ZBX_NULL2EMPTY_STR(params), ts, error);
1058 out:
1059 zbx_free(params);
1060
1061 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:%s flags:%s", __func__, zbx_result_string(ret),
1062 zbx_variant_value_desc(value), zbx_variant_type_desc(value));
1063
1064 return ret;
1065 }
1066
1067 #define ZBX_VALUE_FUNC_UNKNOWN 0
1068 #define ZBX_VALUE_FUNC_MIN 1
1069 #define ZBX_VALUE_FUNC_AVG 2
1070 #define ZBX_VALUE_FUNC_MAX 3
1071 #define ZBX_VALUE_FUNC_SUM 4
1072 #define ZBX_VALUE_FUNC_COUNT 5
1073 #define ZBX_VALUE_FUNC_LAST 6
1074
1075
1076 #define MATCH_STRING(x, name, len) ZBX_CONST_STRLEN(x) == len && 0 == memcmp(name, x, len)
1077
get_function_by_name(const char * name,size_t len)1078 static int get_function_by_name(const char *name, size_t len)
1079 {
1080
1081 if (MATCH_STRING("avg_foreach", name, len))
1082 return ZBX_VALUE_FUNC_AVG;
1083
1084 if (MATCH_STRING("count_foreach", name, len))
1085 return ZBX_VALUE_FUNC_COUNT;
1086
1087 if (MATCH_STRING("last_foreach", name, len))
1088 return ZBX_VALUE_FUNC_LAST;
1089
1090 if (MATCH_STRING("max_foreach", name, len))
1091 return ZBX_VALUE_FUNC_MAX;
1092
1093 if (MATCH_STRING("min_foreach", name, len))
1094 return ZBX_VALUE_FUNC_MIN;
1095
1096 if (MATCH_STRING("sum_foreach", name, len))
1097 return ZBX_VALUE_FUNC_SUM;
1098
1099 return ZBX_VALUE_FUNC_UNKNOWN;
1100 }
1101
1102 /******************************************************************************
1103 * *
1104 * Function: evaluate_history_func_min *
1105 * *
1106 * Purpose: calculate minimum value from the history value vector *
1107 * *
1108 * Parameters: values - [IN] a vector containing history values *
1109 * value_type - [IN] the type of values. Only float/uint64 *
1110 * values are supported. *
1111 * result - [OUT] the resulting value *
1112 * *
1113 ******************************************************************************/
evaluate_history_func_min(zbx_vector_history_record_t * values,int value_type,double * result)1114 static void evaluate_history_func_min(zbx_vector_history_record_t *values, int value_type, double *result)
1115 {
1116 int i;
1117
1118 if (ITEM_VALUE_TYPE_UINT64 == value_type)
1119 {
1120 *result = (double)values->values[0].value.ui64;
1121
1122 for (i = 1; i < values->values_num; i++)
1123 if ((double)values->values[i].value.ui64 < *result)
1124 *result = (double)values->values[i].value.ui64;
1125 }
1126 else
1127 {
1128 *result = values->values[0].value.dbl;
1129
1130 for (i = 1; i < values->values_num; i++)
1131 if (values->values[i].value.dbl < *result)
1132 *result = values->values[i].value.dbl;
1133 }
1134 }
1135
1136 /******************************************************************************
1137 * *
1138 * Function: evaluate_history_func_max *
1139 * *
1140 * Purpose: calculate maximum value from the history value vector *
1141 * *
1142 * Parameters: values - [IN] a vector containing history values *
1143 * value_type - [IN] the type of values. Only float/uint64 *
1144 * values are supported. *
1145 * result - [OUT] the resulting value *
1146 * *
1147 ******************************************************************************/
evaluate_history_func_max(zbx_vector_history_record_t * values,int value_type,double * result)1148 static void evaluate_history_func_max(zbx_vector_history_record_t *values, int value_type, double *result)
1149 {
1150 int i;
1151
1152 if (ITEM_VALUE_TYPE_UINT64 == value_type)
1153 {
1154 *result = (double)values->values[0].value.ui64;
1155
1156 for (i = 1; i < values->values_num; i++)
1157 if ((double)values->values[i].value.ui64 > *result)
1158 *result = (double)values->values[i].value.ui64;
1159 }
1160 else
1161 {
1162 *result = values->values[0].value.dbl;
1163
1164 for (i = 1; i < values->values_num; i++)
1165 if (values->values[i].value.dbl > *result)
1166 *result = values->values[i].value.dbl;
1167 }
1168 }
1169
1170 /******************************************************************************
1171 * *
1172 * Function: evaluate_history_func_sum *
1173 * *
1174 * Purpose: calculate sum of values from the history value vector *
1175 * *
1176 * Parameters: values - [IN] a vector containing history values *
1177 * value_type - [IN] the type of values. Only float/uint64 *
1178 * values are supported. *
1179 * result - [OUT] the resulting value *
1180 * *
1181 ******************************************************************************/
evaluate_history_func_sum(zbx_vector_history_record_t * values,int value_type,double * result)1182 static void evaluate_history_func_sum(zbx_vector_history_record_t *values, int value_type, double *result)
1183 {
1184 int i;
1185
1186 *result = 0;
1187
1188 if (ITEM_VALUE_TYPE_UINT64 == value_type)
1189 {
1190 for (i = 0; i < values->values_num; i++)
1191 *result += (double)values->values[i].value.ui64;
1192 }
1193 else
1194 {
1195 for (i = 0; i < values->values_num; i++)
1196 *result += values->values[i].value.dbl;
1197 }
1198 }
1199
1200 /******************************************************************************
1201 * *
1202 * Function: evaluate_history_func_avg *
1203 * *
1204 * Purpose: calculate average value of values from the history value vector *
1205 * *
1206 * Parameters: values - [IN] a vector containing history values *
1207 * value_type - [IN] the type of values. Only float/uint64 *
1208 * values are supported. *
1209 * result - [OUT] the resulting value *
1210 * *
1211 ******************************************************************************/
evaluate_history_func_avg(zbx_vector_history_record_t * values,int value_type,double * result)1212 static void evaluate_history_func_avg(zbx_vector_history_record_t *values, int value_type, double *result)
1213 {
1214 evaluate_history_func_sum(values, value_type, result);
1215 *result /= values->values_num;
1216 }
1217
1218 /******************************************************************************
1219 * *
1220 * Function: evaluate_history_func_count *
1221 * *
1222 * Purpose: calculate number of values in value vector *
1223 * *
1224 * Parameters: values - [IN] a vector containing history values *
1225 * value_type - [IN] the type of values. Only float/uint64 *
1226 * values are supported. *
1227 * result - [OUT] the resulting value *
1228 * *
1229 ******************************************************************************/
evaluate_history_func_count(zbx_vector_history_record_t * values,double * result)1230 static void evaluate_history_func_count(zbx_vector_history_record_t *values, double *result)
1231 {
1232 *result = (double)values->values_num;
1233 }
1234
1235 /******************************************************************************
1236 * *
1237 * Function: evaluate_history_func_last *
1238 * *
1239 * Purpose: calculate the last (newest) value in value vector *
1240 * *
1241 * Parameters: values - [IN] a vector containing history values *
1242 * result - [OUT] the resulting value *
1243 * *
1244 ******************************************************************************/
evaluate_history_func_last(zbx_vector_history_record_t * values,int value_type,double * result)1245 static void evaluate_history_func_last(zbx_vector_history_record_t *values, int value_type, double *result)
1246 {
1247 if (ITEM_VALUE_TYPE_UINT64 == value_type)
1248 *result = (double)values->values[0].value.ui64;
1249 else
1250 *result = values->values[0].value.dbl;
1251 }
1252
1253 /******************************************************************************
1254 * *
1255 * Function: evaluate_history_func *
1256 * *
1257 * Purpose: calculate function with values from value vector *
1258 * *
1259 * Parameters: values - [IN] a vector containing history values *
1260 * value_type - [IN] the type of values. Only float/uint64 *
1261 * values are supported. *
1262 * func - [IN] the function to calculate. Only *
1263 * ZBX_VALUE_FUNC_MIN, ZBX_VALUE_FUNC_AVG, *
1264 * ZBX_VALUE_FUNC_MAX, ZBX_VALUE_FUNC_SUM, *
1265 * ZBX_VALUE_FUNC_COUNT, ZBX_VALUE_FUNC_LAST *
1266 * functions are supported. *
1267 * result - [OUT] the resulting value *
1268 * *
1269 ******************************************************************************/
evaluate_history_func(zbx_vector_history_record_t * values,int value_type,int func,double * result)1270 static void evaluate_history_func(zbx_vector_history_record_t *values, int value_type, int func,
1271 double *result)
1272 {
1273 switch (func)
1274 {
1275 case ZBX_VALUE_FUNC_MIN:
1276 evaluate_history_func_min(values, value_type, result);
1277 break;
1278 case ZBX_VALUE_FUNC_AVG:
1279 evaluate_history_func_avg(values, value_type, result);
1280 break;
1281 case ZBX_VALUE_FUNC_MAX:
1282 evaluate_history_func_max(values, value_type, result);
1283 break;
1284 case ZBX_VALUE_FUNC_SUM:
1285 evaluate_history_func_sum(values, value_type, result);
1286 break;
1287 case ZBX_VALUE_FUNC_COUNT:
1288 evaluate_history_func_count(values, result);
1289 break;
1290 case ZBX_VALUE_FUNC_LAST:
1291 evaluate_history_func_last(values, value_type, result);
1292 break;
1293 }
1294 }
1295
1296 /******************************************************************************
1297 * *
1298 * Function: get_dcitem *
1299 * *
1300 * Purpose: get item from cache by itemid *
1301 * *
1302 * Parameters: eval - [IN] the evaluation data *
1303 * itemid - [IN] the item identifier *
1304 * *
1305 * Return value: The cached item. *
1306 * *
1307 ******************************************************************************/
get_dcitem(zbx_vector_ptr_t * dcitem_refs,zbx_uint64_t itemid)1308 static DC_ITEM *get_dcitem(zbx_vector_ptr_t *dcitem_refs, zbx_uint64_t itemid)
1309 {
1310 int index;
1311
1312 if (FAIL == (index = zbx_vector_ptr_bsearch(dcitem_refs, &itemid, expression_find_dcitem_by_itemid)))
1313 return NULL;
1314
1315 return dcitem_refs->values[index];
1316 }
1317
1318 /******************************************************************************
1319 * *
1320 * Function: expression_eval_many *
1321 * *
1322 * Purpose: evaluate historical function for multiple items (aggregate checks)*
1323 * *
1324 * Parameters: eval - [IN] the evaluation data *
1325 * query - [IN] the calculated item query *
1326 * name - [IN] the function name (not zero terminated) *
1327 * len - [IN] the function name length *
1328 * args_num - [IN] the number of function arguments *
1329 * args - [IN] an array of the function arguments. *
1330 * data - [IN] the caller data used for function evaluation *
1331 * ts - [IN] the function execution time *
1332 * value - [OUT] the function return value *
1333 * error - [OUT] the error message if function failed *
1334 * *
1335 * Return value: SUCCEED - the function was executed successfully *
1336 * FAIL - otherwise *
1337 * *
1338 ******************************************************************************/
expression_eval_many(zbx_expression_eval_t * eval,zbx_expression_query_t * query,const char * name,size_t len,int args_num,const zbx_variant_t * args,const zbx_timespec_t * ts,zbx_variant_t * value,char ** error)1339 static int expression_eval_many(zbx_expression_eval_t *eval, zbx_expression_query_t *query, const char *name,
1340 size_t len, int args_num, const zbx_variant_t *args, const zbx_timespec_t *ts, zbx_variant_t *value,
1341 char **error)
1342 {
1343 zbx_expression_query_many_t *data;
1344 int ret = FAIL, item_func, count, seconds, i;
1345 zbx_vector_history_record_t values;
1346 zbx_vector_dbl_t *results;
1347 double result;
1348 zbx_variant_t arg;
1349
1350 zabbix_log(LOG_LEVEL_DEBUG, "In %s() %.*s(/%s/%s?[%s],...)", __func__, (int)len, name,
1351 ZBX_NULL2EMPTY_STR(query->ref.host), ZBX_NULL2EMPTY_STR(query->ref.key),
1352 ZBX_NULL2EMPTY_STR(query->ref.filter));
1353
1354 ZBX_UNUSED(args_num);
1355
1356 data = (zbx_expression_query_many_t *)query->data;
1357
1358 if (ZBX_VALUE_FUNC_UNKNOWN == (item_func = get_function_by_name(name, len)))
1359 {
1360 *error = zbx_strdup(NULL, "unsupported function");
1361 goto out;
1362 }
1363
1364 if (ZBX_VALUE_FUNC_LAST == item_func)
1365 {
1366 count = 1;
1367 seconds = 0;
1368 }
1369 else
1370 {
1371 if (1 != args_num)
1372 {
1373 *error = zbx_strdup(NULL, "invalid number of function parameters");
1374 goto out;
1375 }
1376
1377 if (ZBX_VARIANT_STR == args[0].type)
1378 {
1379 if (FAIL == is_time_suffix(args[0].data.str, &seconds, ZBX_LENGTH_UNLIMITED))
1380 {
1381 *error = zbx_strdup(NULL, "invalid second parameter");
1382 goto out;
1383 }
1384 }
1385 else
1386 {
1387 zbx_variant_copy(&arg, &args[0]);
1388
1389 if (SUCCEED != zbx_variant_convert(&arg, ZBX_VARIANT_DBL))
1390 {
1391 zbx_variant_clear(&arg);
1392 *error = zbx_strdup(NULL, "invalid second parameter");
1393 goto out;
1394 }
1395
1396 seconds = arg.data.dbl;
1397 zbx_variant_clear(&arg);
1398 }
1399 count = 0;
1400 }
1401
1402 results = (zbx_vector_dbl_t *)zbx_malloc(NULL, sizeof(zbx_vector_dbl_t));
1403 zbx_vector_dbl_create(results);
1404
1405 for (i = 0; i < data->itemids.values_num; i++)
1406 {
1407 DC_ITEM *dcitem;
1408
1409 if (NULL == (dcitem = get_dcitem(&eval->dcitem_refs, data->itemids.values[i])))
1410 continue;
1411
1412 if (ITEM_STATUS_ACTIVE != dcitem->status)
1413 continue;
1414
1415 if (HOST_STATUS_MONITORED != dcitem->host.status)
1416 continue;
1417
1418 if (ITEM_VALUE_TYPE_FLOAT != dcitem->value_type && ITEM_VALUE_TYPE_UINT64 != dcitem->value_type)
1419 continue;
1420
1421 zbx_history_record_vector_create(&values);
1422
1423 if (SUCCEED == zbx_vc_get_values(dcitem->itemid, dcitem->value_type, &values, seconds, count, ts) &&
1424 0 < values.values_num)
1425 {
1426 evaluate_history_func(&values, dcitem->value_type, item_func, &result);
1427 zbx_vector_dbl_append(results, result);
1428 }
1429
1430 zbx_history_record_vector_destroy(&values, dcitem->value_type);
1431 }
1432
1433 if (0 == results->values_num)
1434 {
1435 zbx_vector_dbl_destroy(results);
1436 zbx_free(results);
1437
1438 *error = zbx_strdup(NULL, "no data for query");
1439 goto out;
1440 }
1441
1442 zbx_variant_set_dbl_vector(value, results);
1443
1444 ret = SUCCEED;
1445 out:
1446 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:%s flags:%s", __func__, zbx_result_string(ret),
1447 zbx_variant_value_desc(value), zbx_variant_type_desc(value));
1448
1449 return ret;
1450 }
1451
1452 /******************************************************************************
1453 * *
1454 * Function: expression_eval_history *
1455 * *
1456 * Purpose: evaluate historical function *
1457 * *
1458 * Parameters: name - [IN] the function name (not zero terminated) *
1459 * len - [IN] the function name length *
1460 * args_num - [IN] the number of function arguments *
1461 * args - [IN] an array of the function arguments. *
1462 * data - [IN] the caller data used for function evaluation *
1463 * ts - [IN] the function execution time *
1464 * value - [OUT] the function return value *
1465 * error - [OUT] the error message if function failed *
1466 * *
1467 * Return value: SUCCEED - the function was executed successfully *
1468 * FAIL - otherwise *
1469 * *
1470 ******************************************************************************/
expression_eval_history(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)1471 static int expression_eval_history(const char *name, size_t len, int args_num, const zbx_variant_t *args,
1472 void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
1473 {
1474 int ret = FAIL;
1475 zbx_expression_eval_t *eval;
1476 zbx_expression_query_t *query;
1477 char *errmsg = NULL;
1478
1479 zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:%.*s", __func__, (int )len, name);
1480
1481 zbx_variant_set_none(value);
1482
1483 if (0 == args_num)
1484 {
1485 *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments");
1486 goto out;
1487 }
1488
1489 if (len >= MAX_STRING_LEN)
1490 {
1491 *error = zbx_strdup(NULL, "Cannot evaluate function: name too long");
1492 goto out;
1493 }
1494
1495 eval = (zbx_expression_eval_t *)data;
1496
1497 /* the historical function item query argument is replaced with corresponding itemrefs index */
1498 query = (zbx_expression_query_t *)eval->queries.values[(int) args[0].data.ui64];
1499
1500 if (ZBX_ITEM_QUERY_ERROR == query->flags)
1501 {
1502 *error = zbx_dsprintf(NULL, "Cannot evaluate function: %s", query->error);
1503 goto out;
1504 }
1505
1506 if (0 == (query->flags & ZBX_ITEM_QUERY_MANY))
1507 {
1508 ret = expression_eval_one(eval, query, name, len, args_num - 1, args + 1, ts, value, &errmsg);
1509 }
1510 else if (ZBX_EXPRESSION_AGGREGATE == eval->mode)
1511 {
1512 ret = expression_eval_many(eval, query, name, len, args_num - 1, args + 1, ts, value, &errmsg);
1513 }
1514 else
1515 {
1516 errmsg = zbx_strdup(NULL, "aggregate queries are not supported");
1517 ret = FAIL;
1518 }
1519
1520 if (SUCCEED != ret)
1521 {
1522 *error = zbx_dsprintf(NULL, "Cannot evaluate function: %s", errmsg);
1523 zbx_free(errmsg);
1524 }
1525 out:
1526 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s error:%s", __func__, zbx_result_string(ret),
1527 ZBX_NULL2EMPTY_STR(*error));
1528
1529 return ret;
1530 }
1531
1532 /******************************************************************************
1533 * *
1534 * Function: expression_eval_common *
1535 * *
1536 * Purpose: evaluate common function *
1537 * *
1538 * Parameters: name - [IN] the function name (not zero terminated) *
1539 * len - [IN] the function name length *
1540 * args_num - [IN] the number of function arguments *
1541 * args - [IN] an array of the function arguments. *
1542 * data - [IN] the caller data used for function evaluation *
1543 * ts - [IN] the function execution time *
1544 * value - [OUT] the function return value *
1545 * error - [OUT] the error message if function failed *
1546 * *
1547 * Return value: SUCCEED - the function was executed successfully *
1548 * FAIL - otherwise *
1549 * *
1550 * Comments: There are no custom common functions in expressions items, but *
1551 * it's used to check for /host/key query quoting errors instead. *
1552 * *
1553 ******************************************************************************/
expression_eval_common(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)1554 static int expression_eval_common(const char *name, size_t len, int args_num, const zbx_variant_t *args,
1555 void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
1556 {
1557 ZBX_UNUSED(data);
1558 ZBX_UNUSED(ts);
1559 ZBX_UNUSED(value);
1560
1561 if (SUCCEED != zbx_is_trigger_function(name, len))
1562 {
1563 *error = zbx_strdup(NULL, "Cannot evaluate formula: unsupported function");
1564 return FAIL;
1565 }
1566
1567 if (0 == args_num)
1568 {
1569 *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments");
1570 return FAIL;
1571 }
1572
1573 if (ZBX_VARIANT_STR == args[0].type)
1574 {
1575 zbx_item_query_t query;
1576
1577 if (0 != zbx_eval_parse_query(args[0].data.str, strlen(args[0].data.str), &query))
1578 {
1579 zbx_eval_clear_query(&query);
1580 *error = zbx_strdup(NULL, "Cannot evaluate function: quoted item query argument");
1581 return FAIL;
1582 }
1583 }
1584
1585 *error = zbx_strdup(NULL, "Cannot evaluate function: invalid first argument");
1586 return FAIL;
1587 }
1588
1589 /******************************************************************************
1590 * *
1591 * Function: expression_eval_init *
1592 * *
1593 * Purpose: initialize expression evaluation data *
1594 * *
1595 * Parameters: eval - [IN] the evaluation data *
1596 * mode - [IN] ZBX_EXPRESSION_NORMAL - support only single *
1597 * item queries *
1598 * ZBX_EXPRESSION_AGGREGATE - support aggregate *
1599 * item queries *
1600 * ctx - [IN] the parsed expression *
1601 * *
1602 ******************************************************************************/
zbx_expression_eval_init(zbx_expression_eval_t * eval,int mode,zbx_eval_context_t * ctx)1603 void zbx_expression_eval_init(zbx_expression_eval_t *eval, int mode, zbx_eval_context_t *ctx)
1604 {
1605 int i;
1606 zbx_expression_query_t *query;
1607 zbx_vector_str_t filters;
1608
1609 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1610
1611 zbx_vector_str_create(&filters);
1612 zbx_eval_extract_item_refs(ctx, &filters);
1613
1614 zbx_vector_ptr_create(&eval->queries);
1615 zbx_vector_ptr_create(&eval->groups);
1616 zbx_vector_ptr_create(&eval->itemtags);
1617 zbx_vector_ptr_create(&eval->dcitem_refs);
1618
1619 eval->ctx = ctx;
1620 eval->mode = mode;
1621 eval->one_num = 0;
1622 eval->many_num = 0;
1623 eval->dcitems_num = 0;
1624 eval->hostid = 0;
1625
1626 for (i = 0; i < filters.values_num; i++)
1627 {
1628 query = expression_create_query(filters.values[i]);
1629 zbx_vector_ptr_append(&eval->queries, query);
1630
1631 if (ZBX_ITEM_QUERY_UNSET == query->flags)
1632 {
1633 query->error = zbx_strdup(NULL, "invalid item query filter");
1634 query->flags = ZBX_ITEM_QUERY_ERROR;
1635 }
1636 }
1637
1638 zbx_vector_str_clear_ext(&filters, zbx_str_free);
1639 zbx_vector_str_destroy(&filters);
1640
1641 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1642 }
1643
1644 /******************************************************************************
1645 * *
1646 * Function: expression_eval_clear *
1647 * *
1648 * Purpose: free resources allocated by expression evaluation data *
1649 * *
1650 * Parameters: eval - [IN] the evaluation data *
1651 * *
1652 ******************************************************************************/
zbx_expression_eval_clear(zbx_expression_eval_t * eval)1653 void zbx_expression_eval_clear(zbx_expression_eval_t *eval)
1654 {
1655 if (0 != eval->one_num)
1656 {
1657 DCconfig_clean_items(eval->dcitems_hk, eval->errcodes_hk, eval->one_num);
1658 zbx_free(eval->dcitems_hk);
1659 zbx_free(eval->errcodes_hk);
1660 zbx_free(eval->hostkeys);
1661 }
1662
1663 if (0 != eval->dcitems_num)
1664 {
1665 DCconfig_clean_items(eval->dcitems, eval->errcodes, eval->dcitems_num);
1666 zbx_free(eval->dcitems);
1667 zbx_free(eval->errcodes);
1668 }
1669
1670 zbx_vector_ptr_destroy(&eval->dcitem_refs);
1671
1672 zbx_vector_ptr_clear_ext(&eval->itemtags, (zbx_clean_func_t) expression_item_free);
1673 zbx_vector_ptr_destroy(&eval->itemtags);
1674
1675 zbx_vector_ptr_clear_ext(&eval->groups, (zbx_clean_func_t) expression_group_free);
1676 zbx_vector_ptr_destroy(&eval->groups);
1677
1678 zbx_vector_ptr_clear_ext(&eval->queries, (zbx_clean_func_t) expression_query_free);
1679 zbx_vector_ptr_destroy(&eval->queries);
1680 }
1681
1682 /******************************************************************************
1683 * *
1684 * Function: zbx_expression_eval_resolve_item_hosts *
1685 * *
1686 * Purpose: resolve calculated item formula empty and macro host references *
1687 * (// , {HOST.HOST}) to host names *
1688 * *
1689 * Parameters: eval - [IN] the evaluation data *
1690 * item - [IN] the calculated item *
1691 * *
1692 ******************************************************************************/
zbx_expression_eval_resolve_item_hosts(zbx_expression_eval_t * eval,const DC_ITEM * item)1693 void zbx_expression_eval_resolve_item_hosts(zbx_expression_eval_t *eval, const DC_ITEM *item)
1694 {
1695 int i;
1696
1697 eval->hostid = item->host.hostid;
1698
1699 for (i = 0; i < eval->queries.values_num; i++)
1700 {
1701 zbx_expression_query_t *query = (zbx_expression_query_t *)eval->queries.values[i];
1702
1703 if (0 != (ZBX_ITEM_QUERY_HOST_SELF & query->flags) || 0 == strcmp(query->ref.host, "{HOST.HOST}"))
1704 query->ref.host = zbx_strdup(query->ref.host, item->host.host);
1705 }
1706 }
1707
1708 typedef struct
1709 {
1710 int num;
1711 char *host;
1712 }
1713 zbx_host_index_t;
1714
1715
host_index_compare(const void * d1,const void * d2)1716 static int host_index_compare(const void *d1, const void *d2)
1717 {
1718 const int *i1 = *(const int **)d1;
1719 const int *i2 = *(const int **)d2;
1720
1721 return *i1 - *i2;
1722 }
1723
host_index_free(zbx_host_index_t * index)1724 static void host_index_free(zbx_host_index_t *index)
1725 {
1726 zbx_free(index->host);
1727 zbx_free(index);
1728 }
1729
1730 /******************************************************************************
1731 * *
1732 * Function: zbx_expression_eval_resolve_trigger_hosts *
1733 * *
1734 * Purpose: resolve expression macro empty and macro host references *
1735 * (// , {HOST.HOST}, {HOST.HOST<N>}) to host names *
1736 * *
1737 * Parameters: eval - [IN] the evaluation data *
1738 * trigger - [IN] the calculated item *
1739 * *
1740 ******************************************************************************/
zbx_expression_eval_resolve_trigger_hosts(zbx_expression_eval_t * eval,const DB_TRIGGER * trigger)1741 void zbx_expression_eval_resolve_trigger_hosts(zbx_expression_eval_t *eval, const DB_TRIGGER *trigger)
1742 {
1743 int i, func_num, index;
1744 zbx_vector_ptr_t hosts;
1745 zbx_host_index_t *hi;
1746
1747 zbx_vector_ptr_create(&hosts);
1748
1749 for (i = 0; i < eval->queries.values_num; i++)
1750 {
1751 zbx_expression_query_t *query = (zbx_expression_query_t *)eval->queries.values[i];
1752
1753 if (0 != (ZBX_ITEM_QUERY_HOST_ONE & query->flags))
1754 func_num = zbx_host_macro_index(query->ref.host);
1755 else if (0 != (ZBX_ITEM_QUERY_HOST_SELF & query->flags))
1756 func_num = 1;
1757 else
1758 func_num = -1;
1759
1760 if (-1 == func_num)
1761 continue;
1762
1763 if (FAIL == (index = zbx_vector_ptr_search(&hosts, &func_num, host_index_compare)))
1764 {
1765 hi = (zbx_host_index_t *)zbx_malloc(NULL, sizeof(zbx_host_index_t));
1766 hi->num = func_num;
1767 hi->host = NULL;
1768 DBget_trigger_value(trigger, &hi->host, func_num, ZBX_REQUEST_HOST_HOST);
1769 zbx_vector_ptr_append(&hosts, hi);
1770 }
1771 else
1772 hi = (zbx_host_index_t *)hosts.values[index];
1773
1774 if (NULL != hi->host)
1775 {
1776 query->ref.host = zbx_strdup(query->ref.host, hi->host);
1777 }
1778 else
1779 {
1780 query->error = zbx_dsprintf(NULL, "invalid host \"%s\"", ZBX_NULL2EMPTY_STR(query->ref.host));
1781 query->flags = ZBX_ITEM_QUERY_ERROR;
1782 }
1783 }
1784
1785 zbx_vector_ptr_clear_ext(&hosts, (zbx_clean_func_t)host_index_free);
1786 zbx_vector_ptr_destroy(&hosts);
1787 }
1788
1789 /******************************************************************************
1790 * *
1791 * Function: zbx_expression_eval_execute *
1792 * *
1793 * Purpose: execute expression containing history functions *
1794 * *
1795 * Parameters: eval - [IN] the evaluation data *
1796 * ts - [IN] the calculated item *
1797 * value - [OUT] the expression evaluation result *
1798 * error - [OUT] the error message *
1799 * *
1800 * Return value: SUCCEED - the expression was evaluated successfully. *
1801 * FAIL - otherwise. *
1802 * *
1803 ******************************************************************************/
zbx_expression_eval_execute(zbx_expression_eval_t * eval,const zbx_timespec_t * ts,zbx_variant_t * value,char ** error)1804 int zbx_expression_eval_execute(zbx_expression_eval_t *eval, const zbx_timespec_t *ts, zbx_variant_t *value,
1805 char **error)
1806 {
1807 int i, ret;
1808
1809 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1810
1811 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
1812 {
1813 char *expression = NULL;
1814
1815 zbx_eval_compose_expression(eval->ctx, &expression);
1816 zabbix_log(LOG_LEVEL_DEBUG, "%s() expression:'%s'", __func__, expression);
1817 zbx_free(expression);
1818 }
1819
1820 for (i = 0; i < eval->queries.values_num; i++)
1821 {
1822 zbx_expression_query_t *query = (zbx_expression_query_t *)eval->queries.values[i];
1823
1824 if (ZBX_ITEM_QUERY_ERROR != query->flags)
1825 {
1826 if (0 != (query->flags & ZBX_ITEM_QUERY_MANY))
1827 expression_init_query_many(eval, query);
1828 else
1829 expression_init_query_one(eval, query);
1830 }
1831 }
1832
1833 /* cache items for functions using one item queries */
1834 if (0 != eval->one_num)
1835 expression_cache_dcitems_hk(eval);
1836
1837 /* cache items for functions using many item queries */
1838 if (0 != eval->many_num)
1839 expression_cache_dcitems(eval);
1840
1841 zbx_variant_set_none(value);
1842
1843 ret = zbx_eval_execute_ext(eval->ctx, ts, expression_eval_common, expression_eval_history, (void *)eval, value,
1844 error);
1845
1846 zbx_vc_flush_stats();
1847
1848 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:%s error:%s", __func__, zbx_result_string(ret),
1849 zbx_variant_value_desc(value), ZBX_NULL2EMPTY_STR(*error));
1850
1851 return ret;
1852 }
1853