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 /*
21  * NOTE!!!!!
22  *
23  * This is the new expression syntax support for trigger functions and calculated/aggregated
24  * checks. The old syntax is still used in simple macros. When the new expression syntax
25  * support is added to simple macros the evalfunc.c:evaluate_function (and related code)
26  * must be removed, this code must be copied over the old implementation and unused code removed.
27  */
28 
29 #include "common.h"
30 #include "db.h"
31 #include "log.h"
32 #include "zbxserver.h"
33 #include "valuecache.h"
34 #include "evalfunc.h"
35 #include "zbxregexp.h"
36 #include "zbxtrends.h"
37 
38 typedef enum
39 {
40 	ZBX_PARAM_OPTIONAL,
41 	ZBX_PARAM_MANDATORY
42 }
43 zbx_param_type_t;
44 
45 typedef enum
46 {
47 	ZBX_VALUE_NONE,
48 	ZBX_VALUE_SECONDS,
49 	ZBX_VALUE_NVALUES
50 }
51 zbx_value_type_t;
52 
zbx_type_string(zbx_value_type_t type)53 static const char	*zbx_type_string(zbx_value_type_t type)
54 {
55 	switch (type)
56 	{
57 		case ZBX_VALUE_NONE:
58 			return "none";
59 		case ZBX_VALUE_SECONDS:
60 			return "sec";
61 		case ZBX_VALUE_NVALUES:
62 			return "num";
63 		default:
64 			THIS_SHOULD_NEVER_HAPPEN;
65 			return "unknown";
66 	}
67 }
68 
69 /******************************************************************************
70  *                                                                            *
71  * Function: get_function_parameter_int                                       *
72  *                                                                            *
73  * Purpose: get the value of sec|#num trigger function parameter              *
74  *                                                                            *
75  * Parameters: parameters     - [IN] trigger function parameters              *
76  *             Nparam         - [IN] specifies which parameter to extract     *
77  *             parameter_type - [IN] specifies whether parameter is mandatory *
78  *                              or optional                                   *
79  *             value          - [OUT] parameter value (preserved as is if the *
80  *                              parameter is optional and empty)              *
81  *             type           - [OUT] parameter value type (number of seconds *
82  *                              or number of values)                          *
83  *                                                                            *
84  * Return value: SUCCEED - parameter is valid                                 *
85  *               FAIL    - otherwise                                          *
86  *                                                                            *
87  ******************************************************************************/
get_function_parameter_int(const char * parameters,int Nparam,zbx_param_type_t parameter_type,int * value,zbx_value_type_t * type)88 static int	get_function_parameter_int(const char *parameters, int Nparam, zbx_param_type_t parameter_type,
89 		int *value, zbx_value_type_t *type)
90 {
91 	char	*parameter;
92 	int	ret = FAIL;
93 
94 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
95 
96 	if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
97 		goto out;
98 
99 	if ('\0' == *parameter)
100 	{
101 		switch (parameter_type)
102 		{
103 			case ZBX_PARAM_OPTIONAL:
104 				ret = SUCCEED;
105 				break;
106 			case ZBX_PARAM_MANDATORY:
107 				break;
108 			default:
109 				THIS_SHOULD_NEVER_HAPPEN;
110 		}
111 	}
112 	else if ('#' == *parameter)
113 	{
114 		*type = ZBX_VALUE_NVALUES;
115 		if (SUCCEED == is_uint31(parameter + 1, value) && 0 < *value)
116 			ret = SUCCEED;
117 	}
118 	else if ('-' == *parameter)
119 	{
120 		if (SUCCEED == is_time_suffix(parameter + 1, value, ZBX_LENGTH_UNLIMITED))
121 		{
122 			*value = -(*value);
123 			*type = ZBX_VALUE_SECONDS;
124 			ret = SUCCEED;
125 		}
126 	}
127 	else if (SUCCEED == is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED))
128 	{
129 		*type = ZBX_VALUE_SECONDS;
130 		ret = SUCCEED;
131 	}
132 
133 	if (SUCCEED == ret)
134 		zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d", __func__, zbx_type_string(*type), *value);
135 
136 	zbx_free(parameter);
137 out:
138 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
139 
140 	return ret;
141 }
142 
get_function_parameter_uint64(const char * parameters,int Nparam,zbx_uint64_t * value)143 static int	get_function_parameter_uint64(const char *parameters, int Nparam, zbx_uint64_t *value)
144 {
145 	char	*parameter;
146 	int	ret = FAIL;
147 
148 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
149 
150 	if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
151 		goto out;
152 
153 	if (SUCCEED == (ret = is_uint64(parameter, value)))
154 		zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_UI64, __func__, *value);
155 
156 	zbx_free(parameter);
157 out:
158 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
159 
160 	return ret;
161 }
162 
get_function_parameter_float(const char * parameters,int Nparam,unsigned char flags,double * value)163 static int	get_function_parameter_float(const char *parameters, int Nparam, unsigned char flags, double *value)
164 {
165 	char	*parameter;
166 	int	ret = FAIL;
167 
168 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
169 
170 	if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
171 		goto out;
172 
173 	if (SUCCEED == (ret = is_double_suffix(parameter, flags)))
174 	{
175 		*value = str2double(parameter);
176 		zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_DBL, __func__, *value);
177 	}
178 
179 	zbx_free(parameter);
180 out:
181 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
182 
183 	return ret;
184 }
185 
get_function_parameter_str(const char * parameters,int Nparam,char ** value)186 static int	get_function_parameter_str(const char *parameters, int Nparam, char **value)
187 {
188 	int	ret = FAIL;
189 
190 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
191 
192 	if (NULL == (*value = zbx_function_get_param_dyn(parameters, Nparam)))
193 		goto out;
194 
195 	zabbix_log(LOG_LEVEL_DEBUG, "%s() value:'%s'", __func__, *value);
196 	ret = SUCCEED;
197 out:
198 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
199 
200 	return ret;
201 }
202 
203 /******************************************************************************
204  *                                                                            *
205  * Function: get_function_parameter_hist_range                                *
206  *                                                                            *
207  * Purpose: get the value of sec|num + timeshift trigger function parameter   *
208  *                                                                            *
209  * Parameters: from           - [IN] the function calculation time            *
210  *             parameters     - [IN] trigger function parameters              *
211  *             Nparam         - [IN] specifies which parameter to extract     *
212  *             value          - [OUT] parameter value (preserved as is if the *
213  *                              parameter is optional and empty)              *
214  *             type           - [OUT] parameter value type (number of seconds *
215  *                              or number of values)                          *
216  *             timeshift      - [OUT] the timeshift value (0 if absent)       *
217  *                                                                            *
218  * Return value: SUCCEED - parameter is valid                                 *
219  *               FAIL    - otherwise                                          *
220  *                                                                            *
221  ******************************************************************************/
get_function_parameter_hist_range(int from,const char * parameters,int Nparam,int * value,zbx_value_type_t * type,int * timeshift)222 static int	get_function_parameter_hist_range(int from, const char *parameters, int Nparam, int *value,
223 		zbx_value_type_t *type, int *timeshift)
224 {
225 	char	*parameter = NULL, *shift;
226 	int	ret = FAIL;
227 
228 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
229 
230 	if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
231 		goto out;
232 
233 	if (NULL != (shift = strchr(parameter, ':')))
234 		*shift++ = '\0';
235 
236 	if ('\0' == *parameter)
237 	{
238 		*value = 0;
239 		*type = ZBX_VALUE_NONE;
240 	}
241 	else if ('#' != *parameter)
242 	{
243 		if (SUCCEED != is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED) || 0 > *value)
244 			goto out;
245 
246 		*type = ZBX_VALUE_SECONDS;
247 	}
248 	else
249 	{
250 		if (SUCCEED != is_uint31(parameter + 1, value) || 0 >= *value)
251 			goto out;
252 		*type = ZBX_VALUE_NVALUES;
253 	}
254 
255 	if (NULL != shift)
256 	{
257 		struct tm	tm;
258 		char		*error = NULL;
259 		int		end;
260 
261 		if (SUCCEED != zbx_parse_timeshift(from, shift, &tm, &error))
262 		{
263 			zabbix_log(LOG_LEVEL_DEBUG, "%s() timeshift error:%s", __func__, error);
264 			zbx_free(error);
265 			goto out;
266 		}
267 
268 		if (-1 == (end = mktime(&tm)))
269 		{
270 			zabbix_log(LOG_LEVEL_DEBUG, "%s() invalid timeshift value:%s", __func__, zbx_strerror(errno));
271 			goto out;
272 		}
273 
274 		*timeshift = from - end;
275 	}
276 	else
277 		*timeshift = 0;
278 
279 	ret = SUCCEED;
280 	zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d timeshift:%d", __func__, zbx_type_string(*type), *value,
281 			*timeshift);
282 out:
283 	zbx_free(parameter);
284 
285 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
286 
287 	return ret;
288 }
289 
290 /******************************************************************************
291  *                                                                            *
292  * Function: get_last_n_value                                                 *
293  *                                                                            *
294  * Purpose: get last Nth value defined by #num:now-timeshift first parameter  *
295  *                                                                            *
296  * Parameters: item       - [IN] item (performance metric)                    *
297  *             parameters - [IN] the parameter string with #sec|num/timeshift *
298  *                          in first parameter                                *
299  *             ts         - [IN] the starting timestamp                       *
300  *             value      - [OUT] the Nth value                               *
301  *             error      - [OUT] the error message                           *
302  *                                                                            *
303  * Return value: SUCCEED - value was found successfully copied                *
304  *               FAIL    - otherwise                                          *
305  *                                                                            *
306  ******************************************************************************/
get_last_n_value(const DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_history_record_t * value,char ** error)307 static int	get_last_n_value(const DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
308 		zbx_history_record_t *value, char **error)
309 {
310 	int				arg1 = 1, ret = FAIL, time_shift;
311 	zbx_value_type_t		arg1_type = ZBX_VALUE_NVALUES;
312 	zbx_vector_history_record_t	values;
313 	zbx_timespec_t			ts_end = *ts;
314 
315 	zbx_history_record_vector_create(&values);
316 
317 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
318 	{
319 		*error = zbx_strdup(*error, "invalid second parameter");
320 		goto out;
321 	}
322 
323 	if (ZBX_VALUE_NVALUES != arg1_type)
324 		arg1 = 1;	/* time or non parameter is defaulted to "last(0)" */
325 
326 	ts_end.sec -= time_shift;
327 
328 	if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, arg1, &ts_end))
329 	{
330 		*error = zbx_strdup(*error, "cannot get values from value cache");
331 		goto out;
332 	}
333 
334 	if (arg1 <= values.values_num)
335 	{
336 		*value = values.values[arg1 - 1];
337 		zbx_vector_history_record_remove(&values, arg1 - 1);
338 		ret = SUCCEED;
339 	}
340 	else
341 		*error = zbx_strdup(*error, "not enough data");
342 out:
343 	zbx_history_record_vector_destroy(&values, item->value_type);
344 
345 	return ret;
346 }
347 
348 /******************************************************************************
349  *                                                                            *
350  * Function: evaluate_LOGEVENTID                                              *
351  *                                                                            *
352  * Purpose: evaluate function 'logeventid' for the item                       *
353  *                                                                            *
354  * Parameters: item - item (performance metric)                               *
355  *             parameter - regex string for event id matching                 *
356  *                                                                            *
357  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
358  *               FAIL - failed to evaluate function                           *
359  *                                                                            *
360  ******************************************************************************/
evaluate_LOGEVENTID(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)361 static int	evaluate_LOGEVENTID(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
362 		const zbx_timespec_t *ts, char **error)
363 {
364 	char			*pattern = NULL;
365 	int			ret = FAIL, nparams;
366 	zbx_vector_ptr_t	regexps;
367 	zbx_history_record_t	vc_value;
368 
369 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
370 
371 	zbx_vector_ptr_create(&regexps);
372 
373 	if (ITEM_VALUE_TYPE_LOG != item->value_type)
374 	{
375 		*error = zbx_strdup(*error, "invalid value type");
376 		goto out;
377 	}
378 
379 	if (2 < (nparams = num_param(parameters)))
380 	{
381 		*error = zbx_strdup(*error, "invalid number of parameters");
382 		goto out;
383 	}
384 
385 	if (2 == nparams)
386 	{
387 		if (SUCCEED != get_function_parameter_str(parameters, 2, &pattern))
388 		{
389 			*error = zbx_strdup(*error, "invalid third parameter");
390 			goto out;
391 		}
392 
393 		if ('@' == *pattern)
394 		{
395 			DCget_expressions_by_name(&regexps, pattern + 1);
396 
397 			if (0 == regexps.values_num)
398 			{
399 				*error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist",
400 						pattern + 1);
401 				goto out;
402 			}
403 		}
404 	}
405 	else
406 		pattern = zbx_strdup(NULL, "");
407 
408 	if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
409 	{
410 		char	logeventid[16];
411 		int	regexp_ret;
412 
413 		zbx_snprintf(logeventid, sizeof(logeventid), "%d", vc_value.value.log->logeventid);
414 
415 		if (FAIL == (regexp_ret = regexp_match_ex(&regexps, logeventid, pattern, ZBX_CASE_SENSITIVE)))
416 		{
417 			*error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", pattern);
418 		}
419 		else
420 		{
421 			if (ZBX_REGEXP_MATCH == regexp_ret)
422 				zbx_variant_set_dbl(value, 1);
423 			else if (ZBX_REGEXP_NO_MATCH == regexp_ret)
424 				zbx_variant_set_dbl(value, 0);
425 
426 			ret = SUCCEED;
427 		}
428 
429 		zbx_history_record_clear(&vc_value, item->value_type);
430 	}
431 	else
432 		zabbix_log(LOG_LEVEL_DEBUG, "result for LOGEVENTID is empty");
433 out:
434 	zbx_free(pattern);
435 
436 	zbx_regexp_clean_expressions(&regexps);
437 	zbx_vector_ptr_destroy(&regexps);
438 
439 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
440 
441 	return ret;
442 }
443 
444 /******************************************************************************
445  *                                                                            *
446  * Function: evaluate_LOGSOURCE                                               *
447  *                                                                            *
448  * Purpose: evaluate function 'logsource' for the item                        *
449  *                                                                            *
450  * Parameters: item - item (performance metric)                               *
451  *             parameter - ignored                                            *
452  *                                                                            *
453  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
454  *               FAIL - failed to evaluate function                           *
455  *                                                                            *
456  ******************************************************************************/
evaluate_LOGSOURCE(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)457 static int	evaluate_LOGSOURCE(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
458 		char **error)
459 {
460 	char			*pattern = NULL;
461 	int			ret = FAIL, nparams;
462 	zbx_vector_ptr_t	regexps;
463 	zbx_history_record_t	vc_value;
464 
465 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
466 
467 	zbx_vector_ptr_create(&regexps);
468 
469 	if (ITEM_VALUE_TYPE_LOG != item->value_type)
470 	{
471 		*error = zbx_strdup(*error, "invalid value type");
472 		goto out;
473 	}
474 
475 	if (2 < (nparams = num_param(parameters)))
476 	{
477 		*error = zbx_strdup(*error, "invalid number of parameters");
478 		goto out;
479 	}
480 
481 	if (2 == nparams)
482 	{
483 		if (SUCCEED != get_function_parameter_str(parameters, 2, &pattern))
484 		{
485 			*error = zbx_strdup(*error, "invalid third parameter");
486 			goto out;
487 		}
488 
489 		if ('@' == *pattern)
490 		{
491 			DCget_expressions_by_name(&regexps, pattern + 1);
492 
493 			if (0 == regexps.values_num)
494 			{
495 				*error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist",
496 						pattern + 1);
497 				goto out;
498 			}
499 		}
500 	}
501 	else
502 		pattern = zbx_strdup(NULL, "");
503 
504 	if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
505 	{
506 		switch (regexp_match_ex(&regexps, vc_value.value.log->source, pattern, ZBX_CASE_SENSITIVE))
507 		{
508 			case ZBX_REGEXP_MATCH:
509 				zbx_variant_set_dbl(value, 1);
510 				ret = SUCCEED;
511 				break;
512 			case ZBX_REGEXP_NO_MATCH:
513 				zbx_variant_set_dbl(value, 0);
514 				ret = SUCCEED;
515 				break;
516 			case FAIL:
517 				*error = zbx_dsprintf(*error, "invalid regular expression");
518 		}
519 
520 		zbx_history_record_clear(&vc_value, item->value_type);
521 	}
522 	else
523 		zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSOURCE is empty");
524 out:
525 	zbx_free(pattern);
526 
527 	zbx_regexp_clean_expressions(&regexps);
528 	zbx_vector_ptr_destroy(&regexps);
529 
530 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
531 
532 	return ret;
533 }
534 
535 /******************************************************************************
536  *                                                                            *
537  * Function: evaluate_LOGSEVERITY                                             *
538  *                                                                            *
539  * Purpose: evaluate function 'logseverity' for the item                      *
540  *                                                                            *
541  * Parameters: item - item (performance metric)                               *
542  *                                                                            *
543  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
544  *               FAIL - failed to evaluate function                           *
545  *                                                                            *
546  ******************************************************************************/
evaluate_LOGSEVERITY(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)547 static int	evaluate_LOGSEVERITY(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
548 		const zbx_timespec_t *ts, char **error)
549 {
550 	int			ret = FAIL;
551 	zbx_history_record_t	vc_value;
552 
553 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
554 
555 	if (ITEM_VALUE_TYPE_LOG != item->value_type)
556 	{
557 		*error = zbx_strdup(*error, "invalid value type");
558 		goto out;
559 	}
560 
561 	if (1 < num_param(parameters))
562 	{
563 		*error = zbx_strdup(*error, "invalid number of parameters");
564 		goto out;
565 	}
566 
567 	if (SUCCEED == get_last_n_value(item, parameters, ts, &vc_value, error))
568 	{
569 		zbx_variant_set_dbl(value, vc_value.value.log->severity);
570 		zbx_history_record_clear(&vc_value, item->value_type);
571 
572 		ret = SUCCEED;
573 	}
574 	else
575 		zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSEVERITY is empty");
576 out:
577 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
578 
579 	return ret;
580 }
581 
history_record_float_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)582 static int	history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
583 {
584 	ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl);
585 
586 	return 0;
587 }
588 
history_record_uint64_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)589 static int	history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
590 {
591 	ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64);
592 
593 	return 0;
594 }
595 
history_record_str_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)596 static int	history_record_str_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
597 {
598 	return strcmp(d1->value.str, d2->value.str);
599 }
600 
history_record_log_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)601 static int	history_record_log_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
602 {
603 	int	value_match;
604 
605 	if (0 != (value_match = strcmp(d1->value.log->value, d2->value.log->value)))
606 		return value_match;
607 
608 	if (NULL != d1->value.log->source && NULL != d2->value.log->source)
609 		return strcmp(d1->value.log->source, d2->value.log->source);
610 
611 	if (NULL != d2->value.log->source)
612 		return -1;
613 
614 	if (NULL != d1->value.log->source)
615 		return 1;
616 
617 	return 0;
618 }
619 
620 /* specialized versions of zbx_vector_history_record_*_uniq() because */
621 /* standard versions do not release memory occupied by duplicate elements */
622 
zbx_vector_history_record_str_uniq(zbx_vector_history_record_t * vector,zbx_compare_func_t compare_func)623 static void	zbx_vector_history_record_str_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func)
624 {
625 	if (2 <= vector->values_num)
626 	{
627 		int	i = 0, j = 1;
628 
629 		while (j < vector->values_num)
630 		{
631 			if (0 != compare_func(&vector->values[i], &vector->values[j]))
632 			{
633 				i++;
634 				j++;
635 			}
636 			else
637 			{
638 				zbx_free(vector->values[j].value.str);
639 				zbx_vector_history_record_remove(vector, j);
640 			}
641 		}
642 	}
643 }
644 
zbx_vector_history_record_log_uniq(zbx_vector_history_record_t * vector,zbx_compare_func_t compare_func)645 static void	zbx_vector_history_record_log_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func)
646 {
647 	if (2 <= vector->values_num)
648 	{
649 		int	i = 0, j = 1;
650 
651 		while (j < vector->values_num)
652 		{
653 			if (0 != compare_func(&vector->values[i], &vector->values[j]))
654 			{
655 				i++;
656 				j++;
657 			}
658 			else
659 			{
660 				zbx_free(vector->values[j].value.log->source);
661 				zbx_free(vector->values[j].value.log->value);
662 				zbx_free(vector->values[j].value.log);
663 				zbx_vector_history_record_remove(vector, j);
664 			}
665 		}
666 	}
667 }
668 
669 #define OP_UNKNOWN	-1
670 #define OP_EQ		0
671 #define OP_NE		1
672 #define OP_GT		2
673 #define OP_GE		3
674 #define OP_LT		4
675 #define OP_LE		5
676 #define OP_LIKE		6
677 #define OP_REGEXP	7
678 #define OP_IREGEXP	8
679 #define OP_BITAND		9
680 
count_one_ui64(int * count,int op,zbx_uint64_t value,zbx_uint64_t pattern,zbx_uint64_t mask)681 static void	count_one_ui64(int *count, int op, zbx_uint64_t value, zbx_uint64_t pattern, zbx_uint64_t mask)
682 {
683 	switch (op)
684 	{
685 		case OP_EQ:
686 			if (value == pattern)
687 				(*count)++;
688 			break;
689 		case OP_NE:
690 			if (value != pattern)
691 				(*count)++;
692 			break;
693 		case OP_GT:
694 			if (value > pattern)
695 				(*count)++;
696 			break;
697 		case OP_GE:
698 			if (value >= pattern)
699 				(*count)++;
700 			break;
701 		case OP_LT:
702 			if (value < pattern)
703 				(*count)++;
704 			break;
705 		case OP_LE:
706 			if (value <= pattern)
707 				(*count)++;
708 			break;
709 		case OP_BITAND:
710 			if ((value & mask) == pattern)
711 				(*count)++;
712 	}
713 }
714 
count_one_dbl(int * count,int op,double value,double pattern)715 static void	count_one_dbl(int *count, int op, double value, double pattern)
716 {
717 	switch (op)
718 	{
719 		case OP_EQ:
720 			if (value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON)
721 				(*count)++;
722 			break;
723 		case OP_NE:
724 			if (!(value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON))
725 				(*count)++;
726 			break;
727 		case OP_GT:
728 			if (value >= pattern + ZBX_DOUBLE_EPSILON)
729 				(*count)++;
730 			break;
731 		case OP_GE:
732 			if (value > pattern - ZBX_DOUBLE_EPSILON)
733 				(*count)++;
734 			break;
735 		case OP_LT:
736 			if (value <= pattern - ZBX_DOUBLE_EPSILON)
737 				(*count)++;
738 			break;
739 		case OP_LE:
740 			if (value < pattern + ZBX_DOUBLE_EPSILON)
741 				(*count)++;
742 	}
743 }
744 
count_one_str(int * count,int op,const char * value,const char * pattern,zbx_vector_ptr_t * regexps)745 static void	count_one_str(int *count, int op, const char *value, const char *pattern, zbx_vector_ptr_t *regexps)
746 {
747 	int	res;
748 
749 	switch (op)
750 	{
751 		case OP_EQ:
752 			if (0 == strcmp(value, pattern))
753 				(*count)++;
754 			break;
755 		case OP_NE:
756 			if (0 != strcmp(value, pattern))
757 				(*count)++;
758 			break;
759 		case OP_LIKE:
760 			if (NULL != strstr(value, pattern))
761 				(*count)++;
762 			break;
763 		case OP_REGEXP:
764 			if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE)))
765 				(*count)++;
766 			else if (FAIL == res)
767 				*count = FAIL;
768 			break;
769 		case OP_IREGEXP:
770 			if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_IGNORE_CASE)))
771 				(*count)++;
772 			else if (FAIL == res)
773 				*count = FAIL;
774 	}
775 }
776 
777 /* flags for evaluate_COUNT() */
778 #define COUNT_ALL	0
779 #define COUNT_UNIQUE	1
780 
781 /******************************************************************************
782  *                                                                            *
783  * Function: evaluate_COUNT                                                   *
784  *                                                                            *
785  * Purpose: evaluate functions 'count' and 'find' for the item                *
786  *                                                                            *
787  * Parameters: item       - [IN] item (performance metric)                    *
788  *             parameters - [IN] up to three comma-separated fields:          *
789  *                            (1) number of seconds/values + timeshift        *
790  *                            (2) comparison operator (optional)              *
791  *                            (3) value to compare with (optional)            *
792  *                                Becomes mandatory for numeric items if 3rd  *
793  *                                parameter is specified and is not "regexp"  *
794  *                                or "iregexp". With "bitand" can take one of *
795  *                                2 forms:                                    *
796  *                                  - value_to_compare_with/mask              *
797  *                                  - mask                                    *
798  *             ts         - [IN] the function evaluation time                 *
799  *             limit      - [IN] the limit of counted values, will return     *
800  *                              when the limit is reached                     *
801  *             unique     - [IN] COUNT_ALL - count all values,                *
802  *                               COUNT_UNIQUE - count unique values           *
803  *             error      - [OUT] the error message                           *
804  *                                                                            *
805  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
806  *               FAIL - failed to evaluate function                           *
807  *                                                                            *
808  ******************************************************************************/
evaluate_COUNT(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,int limit,int unique,char ** error)809 static int	evaluate_COUNT(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
810 		int limit, int unique, char **error)
811 {
812 	int				arg1, op = OP_UNKNOWN, numeric_search, nparams, count = 0, i, ret = FAIL;
813 	int				seconds = 0, nvalues = 0, time_shift;
814 	char				*operator = NULL, *pattern2 = NULL, *pattern = NULL, buf[ZBX_MAX_UINT64_LEN];
815 	double				arg3_dbl;
816 	zbx_uint64_t			pattern_ui64, pattern2_ui64;
817 	zbx_value_type_t		arg1_type;
818 	zbx_vector_ptr_t		regexps;
819 	zbx_vector_history_record_t	values;
820 	zbx_timespec_t			ts_end = *ts;
821 
822 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
823 
824 	zbx_vector_ptr_create(&regexps);
825 	zbx_history_record_vector_create(&values);
826 
827 	numeric_search = (ITEM_VALUE_TYPE_UINT64 == item->value_type || ITEM_VALUE_TYPE_FLOAT == item->value_type);
828 
829 	if (3 < (nparams = num_param(parameters)))
830 	{
831 		*error = zbx_strdup(*error, "invalid number of parameters");
832 		goto out;
833 	}
834 
835 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
836 	{
837 		*error = zbx_strdup(*error, "invalid second parameter");
838 		goto out;
839 	}
840 
841 	if (2 <= nparams && SUCCEED != get_function_parameter_str(parameters, 2, &operator))
842 	{
843 		*error = zbx_strdup(*error, "invalid third parameter");
844 		goto out;
845 	}
846 
847 	if (3 <= nparams)
848 	{
849 		if (SUCCEED != get_function_parameter_str(parameters, 3, &pattern))
850 		{
851 			*error = zbx_strdup(*error, "invalid fourth parameter");
852 			goto out;
853 		}
854 	}
855 	else
856 		pattern = zbx_strdup(NULL, "");
857 
858 	ts_end.sec -= time_shift;
859 
860 	if (NULL == operator || '\0' == *operator)
861 		op = (0 != numeric_search ? OP_EQ : OP_LIKE);
862 	else if (0 == strcmp(operator, "eq"))
863 		op = OP_EQ;
864 	else if (0 == strcmp(operator, "ne"))
865 		op = OP_NE;
866 	else if (0 == strcmp(operator, "gt"))
867 		op = OP_GT;
868 	else if (0 == strcmp(operator, "ge"))
869 		op = OP_GE;
870 	else if (0 == strcmp(operator, "lt"))
871 		op = OP_LT;
872 	else if (0 == strcmp(operator, "le"))
873 		op = OP_LE;
874 	else if (0 == strcmp(operator, "like"))
875 		op = OP_LIKE;
876 	else if (0 == strcmp(operator, "regexp"))
877 		op = OP_REGEXP;
878 	else if (0 == strcmp(operator, "iregexp"))
879 		op = OP_IREGEXP;
880 	else if (0 == strcmp(operator, "bitand"))
881 		op = OP_BITAND;
882 
883 	if (OP_UNKNOWN == op)
884 	{
885 		*error = zbx_dsprintf(*error, "operator \"%s\" is not supported for function COUNT", operator);
886 		goto out;
887 	}
888 
889 	numeric_search = (0 != numeric_search && OP_REGEXP != op && OP_IREGEXP != op);
890 
891 	if (0 != numeric_search)
892 	{
893 		if (NULL != operator && '\0' != *operator && '\0' == *pattern)
894 		{
895 			*error = zbx_strdup(*error, "pattern must be provided along with operator for numeric values");
896 			goto out;
897 		}
898 
899 		if (OP_LIKE == op)
900 		{
901 			*error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting numeric values",
902 					operator);
903 			goto out;
904 		}
905 
906 		if (OP_BITAND == op && ITEM_VALUE_TYPE_FLOAT == item->value_type)
907 		{
908 			*error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting float values",
909 					operator);
910 			goto out;
911 		}
912 
913 		if (OP_BITAND == op && NULL != (pattern2 = strchr(pattern, '/')))
914 		{
915 			*pattern2 = '\0';	/* end of the 1st part of the 2nd parameter (number to compare with) */
916 			pattern2++;	/* start of the 2nd part of the 2nd parameter (mask) */
917 		}
918 
919 		if (NULL != pattern && '\0' != *pattern)
920 		{
921 			if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
922 			{
923 				if (OP_BITAND != op)
924 				{
925 					if (SUCCEED != str2uint64(pattern, ZBX_UNIT_SYMBOLS, &pattern_ui64))
926 					{
927 						*error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
928 								" value", pattern);
929 						goto out;
930 					}
931 					pattern2_ui64 = 0;
932 				}
933 				else
934 				{
935 					if (SUCCEED != is_uint64(pattern, &pattern_ui64))
936 					{
937 						*error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
938 								" value", pattern);
939 						goto out;
940 					}
941 
942 					if (NULL != pattern2)
943 					{
944 						if (SUCCEED != is_uint64(pattern2, &pattern2_ui64))
945 						{
946 							*error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric"
947 									" unsigned value", pattern2);
948 							goto out;
949 						}
950 					}
951 					else
952 						pattern2_ui64 = pattern_ui64;
953 				}
954 			}
955 			else
956 			{
957 				if (SUCCEED != is_double_suffix(pattern, ZBX_FLAG_DOUBLE_SUFFIX))
958 				{
959 					*error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric float value",
960 							pattern);
961 					goto out;
962 				}
963 
964 				arg3_dbl = str2double(pattern);
965 			}
966 		}
967 	}
968 	else if (OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op && OP_EQ != op && OP_NE != op)
969 	{
970 		*error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting textual values", operator);
971 		goto out;
972 	}
973 
974 	if ((OP_REGEXP == op || OP_IREGEXP == op) && NULL != pattern && '@' == *pattern)
975 	{
976 		DCget_expressions_by_name(&regexps, pattern + 1);
977 
978 		if (0 == regexps.values_num)
979 		{
980 			*error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", pattern + 1);
981 			goto out;
982 		}
983 	}
984 
985 	switch (arg1_type)
986 	{
987 		case ZBX_VALUE_SECONDS:
988 			seconds = arg1;
989 			break;
990 		case ZBX_VALUE_NVALUES:
991 			nvalues = arg1;
992 			break;
993 		case ZBX_VALUE_NONE:
994 			nvalues = 1;
995 			break;
996 		default:
997 			THIS_SHOULD_NEVER_HAPPEN;
998 	}
999 
1000 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1001 	{
1002 		*error = zbx_strdup(*error, "cannot get values from value cache");
1003 		goto out;
1004 	}
1005 
1006 	if (COUNT_UNIQUE == unique)
1007 	{
1008 		switch (item->value_type)
1009 		{
1010 			case ITEM_VALUE_TYPE_UINT64:
1011 				zbx_vector_history_record_sort(&values,
1012 						(zbx_compare_func_t)history_record_uint64_compare);
1013 				zbx_vector_history_record_uniq(&values,
1014 						(zbx_compare_func_t)history_record_uint64_compare);
1015 				break;
1016 			case ITEM_VALUE_TYPE_FLOAT:
1017 				zbx_vector_history_record_sort(&values,
1018 						(zbx_compare_func_t)history_record_float_compare);
1019 				zbx_vector_history_record_uniq(&values,
1020 						(zbx_compare_func_t)history_record_float_compare);
1021 				break;
1022 			case ITEM_VALUE_TYPE_LOG:
1023 				zbx_vector_history_record_sort(&values,
1024 						(zbx_compare_func_t)history_record_log_compare);
1025 				zbx_vector_history_record_log_uniq(&values,
1026 						(zbx_compare_func_t)history_record_log_compare);
1027 				break;
1028 			default:
1029 				zbx_vector_history_record_sort(&values,
1030 						(zbx_compare_func_t)history_record_str_compare);
1031 				zbx_vector_history_record_str_uniq(&values,
1032 						(zbx_compare_func_t)history_record_str_compare);
1033 		}
1034 	}
1035 
1036 	/* skip counting values one by one if both pattern and operator are empty or "" is searched in text values */
1037 	if ((NULL != pattern && '\0' != *pattern) || (NULL != operator && '\0' != *operator &&
1038 			OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op))
1039 	{
1040 		switch (item->value_type)
1041 		{
1042 			case ITEM_VALUE_TYPE_UINT64:
1043 				if (0 != numeric_search)
1044 				{
1045 					for (i = 0; i < values.values_num && count < limit; i++)
1046 					{
1047 						count_one_ui64(&count, op, values.values[i].value.ui64, pattern_ui64,
1048 								pattern2_ui64);
1049 					}
1050 				}
1051 				else
1052 				{
1053 					for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1054 					{
1055 						zbx_snprintf(buf, sizeof(buf), ZBX_FS_UI64,
1056 								values.values[i].value.ui64);
1057 						count_one_str(&count, op, buf, pattern, &regexps);
1058 					}
1059 				}
1060 				break;
1061 			case ITEM_VALUE_TYPE_FLOAT:
1062 				if (0 != numeric_search)
1063 				{
1064 					for (i = 0; i < values.values_num && count < limit; i++)
1065 						count_one_dbl(&count, op, values.values[i].value.dbl, arg3_dbl);
1066 				}
1067 				else
1068 				{
1069 					for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1070 					{
1071 						zbx_snprintf(buf, sizeof(buf), ZBX_FS_DBL_EXT(4),
1072 								values.values[i].value.dbl);
1073 						count_one_str(&count, op, buf, pattern, &regexps);
1074 					}
1075 				}
1076 				break;
1077 			case ITEM_VALUE_TYPE_LOG:
1078 				for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1079 					count_one_str(&count, op, values.values[i].value.log->value, pattern, &regexps);
1080 				break;
1081 			default:
1082 				for (i = 0; i < values.values_num && FAIL != count && count < limit; i++)
1083 					count_one_str(&count, op, values.values[i].value.str, pattern, &regexps);
1084 		}
1085 
1086 		if (FAIL == count)
1087 		{
1088 			*error = zbx_strdup(*error, "invalid regular expression");
1089 			goto out;
1090 		}
1091 	}
1092 	else
1093 	{
1094 		if ((count = values.values_num) > limit)
1095 			count = limit;
1096 	}
1097 
1098 	zbx_variant_set_dbl(value, count);
1099 
1100 	ret = SUCCEED;
1101 out:
1102 	zbx_free(operator);
1103 	zbx_free(pattern);
1104 
1105 	zbx_regexp_clean_expressions(&regexps);
1106 	zbx_vector_ptr_destroy(&regexps);
1107 
1108 	zbx_history_record_vector_destroy(&values, item->value_type);
1109 
1110 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1111 
1112 	return ret;
1113 }
1114 
1115 #undef OP_UNKNOWN
1116 #undef OP_EQ
1117 #undef OP_NE
1118 #undef OP_GT
1119 #undef OP_GE
1120 #undef OP_LT
1121 #undef OP_LE
1122 #undef OP_LIKE
1123 #undef OP_REGEXP
1124 #undef OP_IREGEXP
1125 #undef OP_BITAND
1126 
1127 /******************************************************************************
1128  *                                                                            *
1129  * Function: evaluate_SUM                                                     *
1130  *                                                                            *
1131  * Purpose: evaluate function 'sum' for the item                              *
1132  *                                                                            *
1133  * Parameters: item - item (performance metric)                               *
1134  *             parameters - number of seconds/values and time shift (optional)*
1135  *                                                                            *
1136  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1137  *               FAIL - failed to evaluate function                           *
1138  *                                                                            *
1139  ******************************************************************************/
evaluate_SUM(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1140 static int	evaluate_SUM(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1141 {
1142 	int				arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
1143 	zbx_value_type_t		arg1_type;
1144 	zbx_vector_history_record_t	values;
1145 	history_value_t			result;
1146 	zbx_timespec_t			ts_end = *ts;
1147 
1148 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1149 
1150 	zbx_history_record_vector_create(&values);
1151 
1152 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1153 	{
1154 		*error = zbx_strdup(*error, "invalid value type");
1155 		goto out;
1156 	}
1157 
1158 	if (1 != num_param(parameters))
1159 	{
1160 		*error = zbx_strdup(*error, "invalid number of parameters");
1161 		goto out;
1162 	}
1163 
1164 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1165 			ZBX_VALUE_NONE == arg1_type)
1166 	{
1167 		*error = zbx_strdup(*error, "invalid second parameter");
1168 		goto out;
1169 	}
1170 
1171 	ts_end.sec -= time_shift;
1172 
1173 	switch (arg1_type)
1174 	{
1175 		case ZBX_VALUE_SECONDS:
1176 			seconds = arg1;
1177 			break;
1178 		case ZBX_VALUE_NVALUES:
1179 			nvalues = arg1;
1180 			break;
1181 		default:
1182 			THIS_SHOULD_NEVER_HAPPEN;
1183 	}
1184 
1185 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1186 	{
1187 		*error = zbx_strdup(*error, "cannot get values from value cache");
1188 		goto out;
1189 	}
1190 
1191 	if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1192 	{
1193 		result.dbl = 0;
1194 
1195 		for (i = 0; i < values.values_num; i++)
1196 			result.dbl += values.values[i].value.dbl;
1197 	}
1198 	else
1199 	{
1200 		result.ui64 = 0;
1201 
1202 		for (i = 0; i < values.values_num; i++)
1203 			result.ui64 += values.values[i].value.ui64;
1204 	}
1205 
1206 	zbx_history_value2variant(&result, item->value_type, value);
1207 	ret = SUCCEED;
1208 out:
1209 	zbx_history_record_vector_destroy(&values, item->value_type);
1210 
1211 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1212 
1213 	return ret;
1214 }
1215 
1216 /******************************************************************************
1217  *                                                                            *
1218  * Function: evaluate_AVG                                                     *
1219  *                                                                            *
1220  * Purpose: evaluate function 'avg' for the item                              *
1221  *                                                                            *
1222  * Parameters: item - item (performance metric)                               *
1223  *             parameters - number of seconds/values and time shift (optional)*
1224  *                                                                            *
1225  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1226  *               FAIL - failed to evaluate function                           *
1227  *                                                                            *
1228  ******************************************************************************/
evaluate_AVG(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1229 static int	evaluate_AVG(zbx_variant_t  *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1230 {
1231 	int				arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift;
1232 	zbx_value_type_t		arg1_type;
1233 	zbx_vector_history_record_t	values;
1234 	zbx_timespec_t			ts_end = *ts;
1235 
1236 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1237 
1238 	zbx_history_record_vector_create(&values);
1239 
1240 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1241 	{
1242 		*error = zbx_strdup(*error, "invalid value type");
1243 		goto out;
1244 	}
1245 
1246 	if (1 != num_param(parameters))
1247 	{
1248 		*error = zbx_strdup(*error, "invalid number of parameters");
1249 		goto out;
1250 	}
1251 
1252 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1253 			ZBX_VALUE_NONE == arg1_type)
1254 	{
1255 		*error = zbx_strdup(*error, "invalid second parameter");
1256 		goto out;
1257 	}
1258 
1259 	ts_end.sec -= time_shift;
1260 
1261 	switch (arg1_type)
1262 	{
1263 		case ZBX_VALUE_SECONDS:
1264 			seconds = arg1;
1265 			break;
1266 		case ZBX_VALUE_NVALUES:
1267 			nvalues = arg1;
1268 			break;
1269 		default:
1270 			THIS_SHOULD_NEVER_HAPPEN;
1271 	}
1272 
1273 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1274 	{
1275 		*error = zbx_strdup(*error, "cannot get values from value cache");
1276 		goto out;
1277 	}
1278 
1279 	if (0 < values.values_num)
1280 	{
1281 		double	avg = 0;
1282 
1283 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1284 		{
1285 			for (i = 0; i < values.values_num; i++)
1286 				avg += values.values[i].value.dbl / (i + 1) - avg / (i + 1);
1287 		}
1288 		else
1289 		{
1290 			for (i = 0; i < values.values_num; i++)
1291 				avg += (double)values.values[i].value.ui64;
1292 
1293 			avg = avg / values.values_num;
1294 		}
1295 		zbx_variant_set_dbl(value, avg);
1296 
1297 		ret = SUCCEED;
1298 	}
1299 	else
1300 	{
1301 		zabbix_log(LOG_LEVEL_DEBUG, "result for AVG is empty");
1302 		*error = zbx_strdup(*error, "not enough data");
1303 	}
1304 out:
1305 	zbx_history_record_vector_destroy(&values, item->value_type);
1306 
1307 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1308 
1309 	return ret;
1310 }
1311 
1312 /******************************************************************************
1313  *                                                                            *
1314  * Function: evaluate_LAST                                                    *
1315  *                                                                            *
1316  * Purpose: evaluate function 'last' for the item                             *
1317  *                                                                            *
1318  * Parameters: value - dynamic buffer                                         *
1319  *             item - item (performance metric)                               *
1320  *             parameters - Nth last value and time shift (optional)          *
1321  *                                                                            *
1322  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1323  *               FAIL - failed to evaluate function                           *
1324  *                                                                            *
1325  ******************************************************************************/
evaluate_LAST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1326 static int	evaluate_LAST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1327 		char **error)
1328 {
1329 	int			ret;
1330 	zbx_history_record_t	vc_value;
1331 
1332 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1333 
1334 	if (SUCCEED == (ret = get_last_n_value(item, parameters, ts, &vc_value, error)))
1335 	{
1336 		zbx_history_value2variant(&vc_value.value, item->value_type, value);
1337 		zbx_history_record_clear(&vc_value, item->value_type);
1338 	}
1339 
1340 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1341 
1342 	return ret;
1343 }
1344 
1345 /******************************************************************************
1346  *                                                                            *
1347  * Function: evaluate_MIN                                                     *
1348  *                                                                            *
1349  * Purpose: evaluate function 'min' for the item                              *
1350  *                                                                            *
1351  * Parameters: item - item (performance metric)                               *
1352  *             parameters - number of seconds/values and time shift (optional)*
1353  *                                                                            *
1354  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1355  *               FAIL - failed to evaluate function                           *
1356  *                                                                            *
1357  ******************************************************************************/
evaluate_MIN(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1358 static int	evaluate_MIN(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1359 {
1360 	int				arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
1361 	zbx_value_type_t		arg1_type;
1362 	zbx_vector_history_record_t	values;
1363 	zbx_timespec_t			ts_end = *ts;
1364 
1365 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1366 
1367 	zbx_history_record_vector_create(&values);
1368 
1369 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1370 	{
1371 		*error = zbx_strdup(*error, "invalid value type");
1372 		goto out;
1373 	}
1374 
1375 	if (1 != num_param(parameters))
1376 	{
1377 		*error = zbx_strdup(*error, "invalid number of parameters");
1378 		goto out;
1379 	}
1380 
1381 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1382 			ZBX_VALUE_NONE == arg1_type)
1383 	{
1384 		*error = zbx_strdup(*error, "invalid second parameter");
1385 		goto out;
1386 	}
1387 
1388 	ts_end.sec -= time_shift;
1389 
1390 	switch (arg1_type)
1391 	{
1392 		case ZBX_VALUE_SECONDS:
1393 			seconds = arg1;
1394 			break;
1395 		case ZBX_VALUE_NVALUES:
1396 			nvalues = arg1;
1397 			break;
1398 		default:
1399 			THIS_SHOULD_NEVER_HAPPEN;
1400 	}
1401 
1402 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1403 	{
1404 		*error = zbx_strdup(*error, "cannot get values from value cache");
1405 		goto out;
1406 	}
1407 
1408 	if (0 < values.values_num)
1409 	{
1410 		int	index = 0;
1411 
1412 		if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1413 		{
1414 			for (i = 1; i < values.values_num; i++)
1415 			{
1416 				if (values.values[i].value.ui64 < values.values[index].value.ui64)
1417 					index = i;
1418 			}
1419 		}
1420 		else
1421 		{
1422 			for (i = 1; i < values.values_num; i++)
1423 			{
1424 				if (values.values[i].value.dbl < values.values[index].value.dbl)
1425 					index = i;
1426 			}
1427 		}
1428 
1429 		zbx_history_value2variant(&values.values[index].value, item->value_type, value);
1430 		ret = SUCCEED;
1431 	}
1432 	else
1433 	{
1434 		zabbix_log(LOG_LEVEL_DEBUG, "result for MIN is empty");
1435 		*error = zbx_strdup(*error, "not enough data");
1436 	}
1437 out:
1438 	zbx_history_record_vector_destroy(&values, item->value_type);
1439 
1440 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1441 
1442 	return ret;
1443 }
1444 
1445 /******************************************************************************
1446  *                                                                            *
1447  * Function: evaluate_MAX                                                     *
1448  *                                                                            *
1449  * Purpose: evaluate function 'max' for the item                              *
1450  *                                                                            *
1451  * Parameters: item - item (performance metric)                               *
1452  *             parameters - number of seconds/values and time shift (optional)*
1453  *                                                                            *
1454  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1455  *               FAIL - failed to evaluate function                           *
1456  *                                                                            *
1457  ******************************************************************************/
evaluate_MAX(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1458 static int	evaluate_MAX(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1459 {
1460 	int				arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift;
1461 	zbx_value_type_t		arg1_type;
1462 	zbx_vector_history_record_t	values;
1463 	zbx_timespec_t			ts_end = *ts;
1464 
1465 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1466 
1467 	zbx_history_record_vector_create(&values);
1468 
1469 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1470 	{
1471 		*error = zbx_strdup(*error, "invalid value type");
1472 		goto out;
1473 	}
1474 
1475 	if (1 != num_param(parameters))
1476 	{
1477 		*error = zbx_strdup(*error, "invalid number of parameters");
1478 		goto out;
1479 	}
1480 
1481 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1482 			ZBX_VALUE_NONE == arg1_type)
1483 	{
1484 		*error = zbx_strdup(*error, "invalid second parameter");
1485 		goto out;
1486 	}
1487 
1488 	ts_end.sec -= time_shift;
1489 
1490 	switch (arg1_type)
1491 	{
1492 		case ZBX_VALUE_SECONDS:
1493 			seconds = arg1;
1494 			break;
1495 		case ZBX_VALUE_NVALUES:
1496 			nvalues = arg1;
1497 			break;
1498 		default:
1499 			THIS_SHOULD_NEVER_HAPPEN;
1500 	}
1501 
1502 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1503 	{
1504 		*error = zbx_strdup(*error, "cannot get values from value cache");
1505 		goto out;
1506 	}
1507 
1508 	if (0 < values.values_num)
1509 	{
1510 		int	index = 0;
1511 
1512 		if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1513 		{
1514 			for (i = 1; i < values.values_num; i++)
1515 			{
1516 				if (values.values[i].value.ui64 > values.values[index].value.ui64)
1517 					index = i;
1518 			}
1519 		}
1520 		else
1521 		{
1522 			for (i = 1; i < values.values_num; i++)
1523 			{
1524 				if (values.values[i].value.dbl > values.values[index].value.dbl)
1525 					index = i;
1526 			}
1527 		}
1528 
1529 		zbx_history_value2variant(&values.values[index].value, item->value_type, value);
1530 
1531 		ret = SUCCEED;
1532 	}
1533 	else
1534 	{
1535 		zabbix_log(LOG_LEVEL_DEBUG, "result for MAX is empty");
1536 		*error = zbx_strdup(*error, "not enough data");
1537 	}
1538 out:
1539 	zbx_history_record_vector_destroy(&values, item->value_type);
1540 
1541 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1542 
1543 	return ret;
1544 }
1545 
1546 /******************************************************************************
1547  *                                                                            *
1548  * Function: evaluate_PERCENTILE                                              *
1549  *                                                                            *
1550  * Purpose: evaluate function 'percentile' for the item                       *
1551  *                                                                            *
1552  * Parameters: item       - [IN] item (performance metric)                    *
1553  *             parameters - [IN] seconds/values, time shift (optional),       *
1554  *                               percentage                                   *
1555  *                                                                            *
1556  * Return value: SUCCEED - evaluated successfully, result is stored in        *
1557  *                         'value'                                            *
1558  *               FAIL    - failed to evaluate function                        *
1559  *                                                                            *
1560  ******************************************************************************/
evaluate_PERCENTILE(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1561 static int	evaluate_PERCENTILE(zbx_variant_t  *value, DC_ITEM *item, const char *parameters,
1562 		const zbx_timespec_t *ts, char **error)
1563 {
1564 	int				arg1, time_shift, ret = FAIL, seconds = 0, nvalues = 0;
1565 	zbx_value_type_t		arg1_type;
1566 	double				percentage;
1567 	zbx_vector_history_record_t	values;
1568 	zbx_timespec_t			ts_end = *ts;
1569 
1570 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1571 
1572 	zbx_history_record_vector_create(&values);
1573 
1574 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1575 	{
1576 		*error = zbx_strdup(*error, "invalid value type");
1577 		goto out;
1578 	}
1579 
1580 	if (2 != num_param(parameters))
1581 	{
1582 		*error = zbx_strdup(*error, "invalid number of parameters");
1583 		goto out;
1584 	}
1585 
1586 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
1587 			ZBX_VALUE_NONE == arg1_type)
1588 	{
1589 		*error = zbx_strdup(*error, "invalid second parameter");
1590 		goto out;
1591 	}
1592 
1593 
1594 	switch (arg1_type)
1595 	{
1596 		case ZBX_VALUE_SECONDS:
1597 			seconds = arg1;
1598 			break;
1599 		case ZBX_VALUE_NVALUES:
1600 			nvalues = arg1;
1601 			break;
1602 		default:
1603 			THIS_SHOULD_NEVER_HAPPEN;
1604 	}
1605 
1606 	ts_end.sec -= time_shift;
1607 
1608 	if (SUCCEED != get_function_parameter_float(parameters, 2, ZBX_FLAG_DOUBLE_PLAIN, &percentage) ||
1609 			0.0 > percentage || 100.0 < percentage)
1610 	{
1611 		*error = zbx_strdup(*error, "invalid third parameter");
1612 		goto out;
1613 	}
1614 
1615 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1616 	{
1617 		*error = zbx_strdup(*error, "cannot get values from value cache");
1618 		goto out;
1619 	}
1620 
1621 	if (0 < values.values_num)
1622 	{
1623 		int	index;
1624 
1625 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1626 			zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_float_compare);
1627 		else
1628 			zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_uint64_compare);
1629 
1630 		if (0 == percentage)
1631 			index = 1;
1632 		else
1633 			index = (int)ceil(values.values_num * (percentage / 100));
1634 
1635 		zbx_history_value2variant(&values.values[index - 1].value, item->value_type, value);
1636 
1637 		ret = SUCCEED;
1638 	}
1639 	else
1640 	{
1641 		zabbix_log(LOG_LEVEL_DEBUG, "result for PERCENTILE is empty");
1642 		*error = zbx_strdup(*error, "not enough data");
1643 	}
1644 out:
1645 	zbx_history_record_vector_destroy(&values, item->value_type);
1646 
1647 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1648 
1649 	return ret;
1650 }
1651 
1652 /******************************************************************************
1653  *                                                                            *
1654  * Function: evaluate_NODATA                                                  *
1655  *                                                                            *
1656  * Purpose: evaluate function 'nodata' for the item                           *
1657  *                                                                            *
1658  * Parameters: item - item (performance metric)                               *
1659  *             parameter - number of seconds                                  *
1660  *                                                                            *
1661  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1662  *               FAIL - failed to evaluate function                           *
1663  *                                                                            *
1664  ******************************************************************************/
evaluate_NODATA(zbx_variant_t * value,DC_ITEM * item,const char * parameters,char ** error)1665 static int	evaluate_NODATA(zbx_variant_t *value, DC_ITEM *item, const char *parameters, char **error)
1666 {
1667 	int				arg1, num, period, lazy = 1, ret = FAIL;
1668 	zbx_value_type_t		arg1_type;
1669 	zbx_vector_history_record_t	values;
1670 	zbx_timespec_t			ts;
1671 	char				*arg2 = NULL;
1672 	zbx_proxy_suppress_t		nodata_win;
1673 
1674 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1675 
1676 	zbx_history_record_vector_create(&values);
1677 
1678 	if (2 < (num = num_param(parameters)))
1679 	{
1680 		*error = zbx_strdup(*error, "invalid number of parameters");
1681 		goto out;
1682 	}
1683 
1684 	if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) ||
1685 			ZBX_VALUE_SECONDS != arg1_type || 0 >= arg1)
1686 	{
1687 		*error = zbx_strdup(*error, "invalid second parameter");
1688 		goto out;
1689 	}
1690 
1691 	if (1 < num && (SUCCEED != get_function_parameter_str(parameters, 2, &arg2) ||
1692 			('\0' != *arg2 && 0 != (lazy = strcmp("strict", arg2)))))
1693 	{
1694 		*error = zbx_strdup(*error, "invalid third parameter");
1695 		goto out;
1696 	}
1697 
1698 	zbx_timespec(&ts);
1699 	nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
1700 
1701 	if (0 != item->host.proxy_hostid && 0 != lazy)
1702 	{
1703 		int			lastaccess;
1704 
1705 		if (SUCCEED != DCget_proxy_nodata_win(item->host.proxy_hostid, &nodata_win, &lastaccess))
1706 		{
1707 			*error = zbx_strdup(*error, "cannot retrieve proxy last access");
1708 			goto out;
1709 		}
1710 
1711 		period = arg1 + (ts.sec - lastaccess);
1712 	}
1713 	else
1714 		period = arg1;
1715 
1716 	if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, period, 1, &ts) &&
1717 			1 == values.values_num)
1718 	{
1719 		zbx_variant_set_dbl(value, 0);
1720 	}
1721 	else
1722 	{
1723 		int	seconds;
1724 
1725 		if (SUCCEED != DCget_data_expected_from(item->itemid, &seconds))
1726 		{
1727 			*error = zbx_strdup(*error, "item does not exist, is disabled or belongs to a disabled host");
1728 			goto out;
1729 		}
1730 
1731 		if (seconds + arg1 > ts.sec)
1732 		{
1733 			*error = zbx_strdup(*error,
1734 					"item does not have enough data after server start or item creation");
1735 			goto out;
1736 		}
1737 
1738 		if (0 != (nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE))
1739 		{
1740 			*error = zbx_strdup(*error, "historical data transfer from proxy is still in progress");
1741 			goto out;
1742 		}
1743 
1744 		zbx_variant_set_dbl(value, 1);
1745 
1746 		if (0 != item->host.proxy_hostid && 0 != lazy)
1747 		{
1748 			zabbix_log(LOG_LEVEL_TRACE, "Nodata in %s() flag:%d values_num:%d start_time:%d period:%d",
1749 					__func__, nodata_win.flags, nodata_win.values_num, ts.sec - period, period);
1750 		}
1751 	}
1752 
1753 	ret = SUCCEED;
1754 out:
1755 	zbx_history_record_vector_destroy(&values, item->value_type);
1756 	zbx_free(arg2);
1757 
1758 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1759 
1760 	return ret;
1761 }
1762 
1763 /******************************************************************************
1764  *                                                                            *
1765  * Function: evaluate_CHANGE                                                  *
1766  *                                                                            *
1767  * Purpose: evaluate function 'change' for the item                           *
1768  *                                                                            *
1769  * Parameters: item - item (performance metric)                               *
1770  *             parameter - number of seconds                                  *
1771  *                                                                            *
1772  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1773  *               FAIL - failed to evaluate function                           *
1774  *                                                                            *
1775  ******************************************************************************/
evaluate_CHANGE(zbx_variant_t * value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)1776 static int	evaluate_CHANGE(zbx_variant_t *value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
1777 {
1778 	int				ret = FAIL;
1779 	zbx_vector_history_record_t	values;
1780 	double				result;
1781 
1782 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1783 
1784 	zbx_history_record_vector_create(&values);
1785 
1786 	if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, 2, ts) ||
1787 			2 > values.values_num)
1788 	{
1789 		*error = zbx_strdup(*error, "cannot get values from value cache");
1790 		goto out;
1791 	}
1792 
1793 	switch (item->value_type)
1794 	{
1795 		case ITEM_VALUE_TYPE_FLOAT:
1796 			result = values.values[0].value.dbl - values.values[1].value.dbl;
1797 			break;
1798 		case ITEM_VALUE_TYPE_UINT64:
1799 			/* to avoid overflow */
1800 			if (values.values[0].value.ui64 >= values.values[1].value.ui64)
1801 				result = values.values[0].value.ui64 - values.values[1].value.ui64;
1802 			else
1803 				result = -(double)(values.values[1].value.ui64 - values.values[0].value.ui64);
1804 			break;
1805 		case ITEM_VALUE_TYPE_LOG:
1806 			if (0 == strcmp(values.values[0].value.log->value, values.values[1].value.log->value))
1807 				result = 0;
1808 			else
1809 				result = 1;
1810 			break;
1811 
1812 		case ITEM_VALUE_TYPE_STR:
1813 		case ITEM_VALUE_TYPE_TEXT:
1814 			if (0 == strcmp(values.values[0].value.str, values.values[1].value.str))
1815 				result = 0;
1816 			else
1817 				result = 1;
1818 			break;
1819 		default:
1820 			*error = zbx_strdup(*error, "invalid value type");
1821 			goto out;
1822 	}
1823 
1824 	zbx_variant_set_dbl(value, result);
1825 	ret = SUCCEED;
1826 out:
1827 	zbx_history_record_vector_destroy(&values, item->value_type);
1828 
1829 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1830 
1831 	return ret;
1832 }
1833 
1834 /******************************************************************************
1835  *                                                                            *
1836  * Function: evaluate_FUZZYTIME                                               *
1837  *                                                                            *
1838  * Purpose: evaluate function 'fuzzytime' for the item                        *
1839  *                                                                            *
1840  * Parameters: item - item (performance metric)                               *
1841  *             parameter - number of seconds                                  *
1842  *                                                                            *
1843  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1844  *               FAIL - failed to evaluate function                           *
1845  *                                                                            *
1846  ******************************************************************************/
evaluate_FUZZYTIME(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1847 static int	evaluate_FUZZYTIME(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1848 		char **error)
1849 {
1850 	int			arg1, ret = FAIL;
1851 	zbx_value_type_t	arg1_type;
1852 	zbx_history_record_t	vc_value;
1853 	zbx_uint64_t		fuzlow, fuzhig;
1854 
1855 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1856 
1857 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1858 	{
1859 		*error = zbx_strdup(*error, "invalid value type");
1860 		goto out;
1861 	}
1862 
1863 	if (1 < num_param(parameters))
1864 	{
1865 		*error = zbx_strdup(*error, "invalid number of parameters");
1866 		goto out;
1867 	}
1868 
1869 	if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1870 	{
1871 		*error = zbx_strdup(*error, "invalid second parameter");
1872 		goto out;
1873 	}
1874 
1875 	if (ZBX_VALUE_SECONDS != arg1_type || ts->sec <= arg1)
1876 	{
1877 		*error = zbx_strdup(*error, "invalid argument type or value");
1878 		goto out;
1879 	}
1880 
1881 	if (SUCCEED != zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
1882 	{
1883 		*error = zbx_strdup(*error, "cannot get value from value cache");
1884 		goto out;
1885 	}
1886 
1887 	fuzlow = (int)(ts->sec - arg1);
1888 	fuzhig = (int)(ts->sec + arg1);
1889 
1890 	if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1891 	{
1892 		if (vc_value.value.ui64 >= fuzlow && vc_value.value.ui64 <= fuzhig)
1893 			zbx_variant_set_dbl(value, 1);
1894 		else
1895 			zbx_variant_set_dbl(value, 0);
1896 	}
1897 	else
1898 	{
1899 		if (vc_value.value.dbl >= fuzlow && vc_value.value.dbl <= fuzhig)
1900 			zbx_variant_set_dbl(value, 1);
1901 		else
1902 			zbx_variant_set_dbl(value, 0);
1903 	}
1904 
1905 	zbx_history_record_clear(&vc_value, item->value_type);
1906 
1907 	ret = SUCCEED;
1908 out:
1909 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1910 
1911 	return ret;
1912 }
1913 
1914 /******************************************************************************
1915  *                                                                            *
1916  * Function: evaluate_BITAND                                                  *
1917  *                                                                            *
1918  * Purpose: evaluate logical bitwise function 'and' for the item              *
1919  *                                                                            *
1920  * Parameters: value - dynamic buffer                                         *
1921  *             item - item (performance metric)                               *
1922  *             parameters - to 2 comma-separated fields:                      *
1923  *                            (1) same as the 1st parameter for function      *
1924  *                                evaluate_LAST() (see documentation of       *
1925  *                                trigger function last()),                   *
1926  *                            (2) mask to bitwise AND with (mandatory),       *
1927  *                                                                            *
1928  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1929  *               FAIL - failed to evaluate function                           *
1930  *                                                                            *
1931  ******************************************************************************/
evaluate_BITAND(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1932 static int	evaluate_BITAND(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1933 		char **error)
1934 {
1935 	char		*last_parameters = NULL;
1936 	int		ret = FAIL;
1937 	zbx_uint64_t	mask;
1938 
1939 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1940 
1941 	if (ITEM_VALUE_TYPE_UINT64 != item->value_type)
1942 	{
1943 		*error = zbx_strdup(*error, "invalid value type");
1944 		goto clean;
1945 	}
1946 
1947 	if (2 < num_param(parameters))
1948 	{
1949 		*error = zbx_strdup(*error, "invalid number of parameters");
1950 		goto clean;
1951 	}
1952 
1953 	if (SUCCEED != get_function_parameter_uint64(parameters, 2, &mask))
1954 	{
1955 		*error = zbx_strdup(*error, "invalid third parameter");
1956 		goto clean;
1957 	}
1958 
1959 	/* prepare the 1st and the 3rd parameter for passing to evaluate_LAST() */
1960 	last_parameters = zbx_function_get_param_dyn(parameters, 1);
1961 
1962 	if (SUCCEED == evaluate_LAST(value, item, last_parameters, ts, error))
1963 	{
1964 		/* the evaluate_LAST() should return uint64 value, but just to be sure try to convert it */
1965 		if (SUCCEED != zbx_variant_convert(value, ZBX_VARIANT_UI64))
1966 		{
1967 			*error = zbx_strdup(*error, "invalid value type");
1968 			goto clean;
1969 		}
1970 		zbx_variant_set_dbl(value, value->data.ui64 & (zbx_uint64_t)mask);
1971 		ret = SUCCEED;
1972 	}
1973 
1974 	zbx_free(last_parameters);
1975 clean:
1976 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1977 
1978 	return ret;
1979 }
1980 
1981 /******************************************************************************
1982  *                                                                            *
1983  * Function: evaluate_FORECAST                                                *
1984  *                                                                            *
1985  * Purpose: evaluate function 'forecast' for the item                         *
1986  *                                                                            *
1987  * Parameters: item - item (performance metric)                               *
1988  *             parameters - number of seconds/values and time shift (optional)*
1989  *                                                                            *
1990  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1991  *               FAIL - failed to evaluate function                           *
1992  *                                                                            *
1993  ******************************************************************************/
evaluate_FORECAST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1994 static int	evaluate_FORECAST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1995 		char **error)
1996 {
1997 	char				*fit_str = NULL, *mode_str = NULL;
1998 	double				*t = NULL, *x = NULL;
1999 	int				nparams, time, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
2000 	zbx_value_type_t		time_type, arg1_type;
2001 	unsigned int			k = 0;
2002 	zbx_vector_history_record_t	values;
2003 	zbx_timespec_t			zero_time;
2004 	zbx_fit_t			fit;
2005 	zbx_mode_t			mode;
2006 	zbx_timespec_t			ts_end = *ts;
2007 
2008 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2009 
2010 	zbx_history_record_vector_create(&values);
2011 
2012 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2013 	{
2014 		*error = zbx_strdup(*error, "invalid value type");
2015 		goto out;
2016 	}
2017 
2018 	if (2 > (nparams = num_param(parameters)) || nparams > 4)
2019 	{
2020 		*error = zbx_strdup(*error, "invalid number of parameters");
2021 		goto out;
2022 	}
2023 
2024 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2025 			ZBX_VALUE_NONE == arg1_type)
2026 	{
2027 		*error = zbx_strdup(*error, "invalid second parameter");
2028 		goto out;
2029 	}
2030 
2031 	if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_MANDATORY, &time, &time_type) ||
2032 			ZBX_VALUE_SECONDS != time_type)
2033 	{
2034 		*error = zbx_strdup(*error, "invalid third parameter");
2035 		goto out;
2036 	}
2037 
2038 	if (3 <= nparams)
2039 	{
2040 		if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) ||
2041 				SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2042 		{
2043 			*error = zbx_strdup(*error, "invalid fourth parameter");
2044 			goto out;
2045 		}
2046 	}
2047 	else
2048 	{
2049 		fit = FIT_LINEAR;
2050 	}
2051 
2052 	if (4 == nparams)
2053 	{
2054 		if (SUCCEED != get_function_parameter_str(parameters, 4, &mode_str) ||
2055 				SUCCEED != zbx_mode_code(mode_str, &mode, error))
2056 		{
2057 			*error = zbx_strdup(*error, "invalid fifth parameter");
2058 			goto out;
2059 		}
2060 	}
2061 	else
2062 	{
2063 		mode = MODE_VALUE;
2064 	}
2065 
2066 	switch (arg1_type)
2067 	{
2068 		case ZBX_VALUE_SECONDS:
2069 			seconds = arg1;
2070 			break;
2071 		case ZBX_VALUE_NVALUES:
2072 			nvalues = arg1;
2073 			break;
2074 		default:
2075 			THIS_SHOULD_NEVER_HAPPEN;
2076 	}
2077 
2078 	ts_end.sec -= time_shift;
2079 
2080 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2081 	{
2082 		*error = zbx_strdup(*error, "cannot get values from value cache");
2083 		goto out;
2084 	}
2085 
2086 	if (0 < values.values_num)
2087 	{
2088 		t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2089 		x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2090 
2091 		zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2092 		zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2093 
2094 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2095 		{
2096 			for (i = 0; i < values.values_num; i++)
2097 			{
2098 				t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2099 						(values.values[i].timestamp.ns - zero_time.ns + 1);
2100 				x[i] = values.values[i].value.dbl;
2101 			}
2102 		}
2103 		else
2104 		{
2105 			for (i = 0; i < values.values_num; i++)
2106 			{
2107 				t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2108 						(values.values[i].timestamp.ns - zero_time.ns + 1);
2109 				x[i] = values.values[i].value.ui64;
2110 			}
2111 		}
2112 
2113 		zbx_variant_set_dbl(value, zbx_forecast(t, x, values.values_num,
2114 				ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), time, fit, k, mode));
2115 	}
2116 	else
2117 	{
2118 		zbx_variant_set_dbl(value, ZBX_MATH_ERROR);
2119 	}
2120 
2121 	ret = SUCCEED;
2122 out:
2123 	zbx_history_record_vector_destroy(&values, item->value_type);
2124 
2125 	zbx_free(fit_str);
2126 	zbx_free(mode_str);
2127 
2128 	zbx_free(t);
2129 	zbx_free(x);
2130 
2131 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2132 
2133 	return ret;
2134 }
2135 
2136 /******************************************************************************
2137  *                                                                            *
2138  * Function: evaluate_TIMELEFT                                                *
2139  *                                                                            *
2140  * Purpose: evaluate function 'timeleft' for the item                         *
2141  *                                                                            *
2142  * Parameters: item - item (performance metric)                               *
2143  *             parameters - number of seconds/values and time shift (optional)*
2144  *                                                                            *
2145  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2146  *               FAIL - failed to evaluate function                           *
2147  *                                                                            *
2148  ******************************************************************************/
evaluate_TIMELEFT(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2149 static int	evaluate_TIMELEFT(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2150 		char **error)
2151 {
2152 	char				*fit_str = NULL;
2153 	double				*t = NULL, *x = NULL, threshold;
2154 	int				nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift;
2155 	zbx_value_type_t		arg1_type;
2156 	unsigned			k = 0;
2157 	zbx_vector_history_record_t	values;
2158 	zbx_timespec_t			zero_time;
2159 	zbx_fit_t			fit;
2160 	zbx_timespec_t			ts_end = *ts;
2161 
2162 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2163 
2164 	zbx_history_record_vector_create(&values);
2165 
2166 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2167 	{
2168 		*error = zbx_strdup(*error, "invalid value type");
2169 		goto out;
2170 	}
2171 
2172 	if (2 > (nparams = num_param(parameters)) || nparams > 3)
2173 	{
2174 		*error = zbx_strdup(*error, "invalid number of parameters");
2175 		goto out;
2176 	}
2177 
2178 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2179 			ZBX_VALUE_NONE == arg1_type)
2180 	{
2181 		*error = zbx_strdup(*error, "invalid second parameter");
2182 		goto out;
2183 	}
2184 
2185 	if (SUCCEED != get_function_parameter_float(parameters, 2, ZBX_FLAG_DOUBLE_SUFFIX, &threshold))
2186 	{
2187 		*error = zbx_strdup(*error, "invalid third parameter");
2188 		goto out;
2189 	}
2190 
2191 	if (3 == nparams)
2192 	{
2193 		if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) ||
2194 				SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2195 		{
2196 			*error = zbx_strdup(*error, "invalid fourth parameter");
2197 			goto out;
2198 		}
2199 	}
2200 	else
2201 	{
2202 		fit = FIT_LINEAR;
2203 	}
2204 
2205 	if ((FIT_EXPONENTIAL == fit || FIT_POWER == fit) && 0.0 >= threshold)
2206 	{
2207 		*error = zbx_strdup(*error, "exponential and power functions are always positive");
2208 		goto out;
2209 	}
2210 
2211 	switch (arg1_type)
2212 	{
2213 		case ZBX_VALUE_SECONDS:
2214 			seconds = arg1;
2215 			break;
2216 		case ZBX_VALUE_NVALUES:
2217 			nvalues = arg1;
2218 			break;
2219 		default:
2220 			THIS_SHOULD_NEVER_HAPPEN;
2221 	}
2222 
2223 	ts_end.sec -= time_shift;
2224 
2225 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2226 	{
2227 		*error = zbx_strdup(*error, "cannot get values from value cache");
2228 		goto out;
2229 	}
2230 
2231 	if (0 < values.values_num)
2232 	{
2233 		t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2234 		x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2235 
2236 		zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2237 		zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2238 
2239 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2240 		{
2241 			for (i = 0; i < values.values_num; i++)
2242 			{
2243 				t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2244 						(values.values[i].timestamp.ns - zero_time.ns + 1);
2245 				x[i] = values.values[i].value.dbl;
2246 			}
2247 		}
2248 		else
2249 		{
2250 			for (i = 0; i < values.values_num; i++)
2251 			{
2252 				t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2253 						(values.values[i].timestamp.ns - zero_time.ns + 1);
2254 				x[i] = values.values[i].value.ui64;
2255 			}
2256 		}
2257 
2258 		zbx_variant_set_dbl(value, zbx_timeleft(t, x, values.values_num,
2259 				ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), threshold, fit, k));
2260 	}
2261 	else
2262 	{
2263 		zbx_variant_set_dbl(value, ZBX_MATH_ERROR);
2264 	}
2265 
2266 	ret = SUCCEED;
2267 out:
2268 	zbx_history_record_vector_destroy(&values, item->value_type);
2269 
2270 	zbx_free(fit_str);
2271 
2272 	zbx_free(t);
2273 	zbx_free(x);
2274 
2275 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2276 
2277 	return ret;
2278 }
2279 
2280 /******************************************************************************
2281  *                                                                            *
2282  * Function: evaluate_TREND                                                   *
2283  *                                                                            *
2284  * Purpose: evaluate trend* functions for the item                            *
2285  *                                                                            *
2286  * Parameters: value      - [OUT] the function result                         *
2287  *             item       - [IN] item (performance metric)                    *
2288  *             func       - [IN] the trend function to evaluate               *
2289  *                               (avg, sum, count, delta, max, min)           *
2290  *             parameters - [IN] function parameters                          *
2291  *             ts         - [IN] the historical time when function must be    *
2292  *                               evaluated                                    *
2293  *                                                                            *
2294  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2295  *               FAIL - failed to evaluate function                           *
2296  *                                                                            *
2297  ******************************************************************************/
evaluate_TREND(zbx_variant_t * value,DC_ITEM * item,const char * func,const char * parameters,const zbx_timespec_t * ts,char ** error)2298 static int	evaluate_TREND(zbx_variant_t *value, DC_ITEM *item, const char *func, const char *parameters,
2299 		const zbx_timespec_t *ts, char **error)
2300 {
2301 	int		ret = FAIL, start, end;
2302 	char		*period = NULL;
2303 	const char	*table;
2304 	double		value_dbl;
2305 
2306 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2307 
2308 	if (1 != num_param(parameters))
2309 	{
2310 		*error = zbx_strdup(*error, "invalid number of parameters");
2311 		goto out;
2312 	}
2313 
2314 	if (SUCCEED != get_function_parameter_str(parameters, 1, &period))
2315 	{
2316 		*error = zbx_strdup(*error, "invalid second parameter");
2317 		goto out;
2318 	}
2319 
2320 	if (SUCCEED != zbx_trends_parse_range(ts->sec, period, &start, &end, error))
2321 		goto out;
2322 
2323 	switch (item->value_type)
2324 	{
2325 		case ITEM_VALUE_TYPE_FLOAT:
2326 			table = "trends";
2327 			break;
2328 		case ITEM_VALUE_TYPE_UINT64:
2329 			table = "trends_uint";
2330 			break;
2331 		default:
2332 			*error = zbx_strdup(*error, "unsupported value type");
2333 			goto out;
2334 	}
2335 
2336 	if (0 == strcmp(func, "avg"))
2337 	{
2338 		ret = zbx_trends_eval_avg(table, item->itemid, start, end, &value_dbl, error);
2339 	}
2340 	else if (0 == strcmp(func, "count"))
2341 	{
2342 		ret = zbx_trends_eval_count(table, item->itemid, start, end, &value_dbl, error);
2343 	}
2344 	else if (0 == strcmp(func, "max"))
2345 	{
2346 		ret = zbx_trends_eval_max(table, item->itemid, start, end, &value_dbl, error);
2347 	}
2348 	else if (0 == strcmp(func, "min"))
2349 	{
2350 		ret = zbx_trends_eval_min(table, item->itemid, start, end, &value_dbl, error);
2351 	}
2352 	else if (0 == strcmp(func, "sum"))
2353 	{
2354 		ret = zbx_trends_eval_sum(table, item->itemid, start, end, &value_dbl, error);
2355 	}
2356 	else
2357 	{
2358 		*error = zbx_strdup(*error, "unknown trend function");
2359 		goto out;
2360 	}
2361 
2362 	if (SUCCEED == ret)
2363 		zbx_variant_set_dbl(value, value_dbl);
2364 out:
2365 	zbx_free(period);
2366 
2367 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2368 
2369 	return ret;
2370 }
2371 
validate_params_and_get_data(DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_vector_history_record_t * values,char ** error)2372 static int	validate_params_and_get_data(DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2373 		zbx_vector_history_record_t *values, char **error)
2374 {
2375 	int			arg1, seconds = 0, nvalues = 0, time_shift;
2376 	zbx_value_type_t	arg1_type;
2377 	zbx_timespec_t		ts_end = *ts;
2378 
2379 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2380 	{
2381 		*error = zbx_strdup(*error, "invalid value type");
2382 		return FAIL;
2383 	}
2384 
2385 	if (1 != num_param(parameters))
2386 	{
2387 		*error = zbx_strdup(*error, "invalid number of parameters");
2388 		return FAIL;
2389 	}
2390 
2391 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) ||
2392 			ZBX_VALUE_NONE == arg1_type)
2393 	{
2394 		*error = zbx_strdup(*error, "invalid parameter");
2395 		return FAIL;
2396 	}
2397 
2398 	ts_end.sec -= time_shift;
2399 
2400 	switch (arg1_type)
2401 	{
2402 		case ZBX_VALUE_SECONDS:
2403 			seconds = arg1;
2404 			break;
2405 		case ZBX_VALUE_NVALUES:
2406 			nvalues = arg1;
2407 			break;
2408 		default:
2409 			*error = zbx_strdup(*error, "invalid type of first argument");
2410 			THIS_SHOULD_NEVER_HAPPEN;
2411 			return FAIL;
2412 	}
2413 
2414 	if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, values, seconds, nvalues, &ts_end))
2415 	{
2416 		*error = zbx_strdup(*error, "cannot get values from value cache");
2417 		return FAIL;
2418 	}
2419 
2420 	return SUCCEED;
2421 }
2422 
2423 /******************************************************************************
2424  *                                                                            *
2425  * Function: evaluate_FIRST                                                   *
2426  *                                                                            *
2427  * Purpose: evaluate function 'first' for the item                            *
2428  *                                                                            *
2429  * Parameters: value - dynamic buffer                                         *
2430  *             item - item (performance metric)                               *
2431  *             parameters - Nth first value and time shift (optional)         *
2432  *                                                                            *
2433  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2434  *               FAIL - failed to evaluate function                           *
2435  *                                                                            *
2436  ******************************************************************************/
evaluate_FIRST(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2437 static int	evaluate_FIRST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2438 		char **error)
2439 {
2440 	int				arg1 = 1, ret = FAIL, seconds = 0, time_shift;
2441 	zbx_value_type_t		arg1_type = ZBX_VALUE_NVALUES;
2442 	zbx_vector_history_record_t	values;
2443 	zbx_timespec_t			ts_end = *ts;
2444 
2445 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2446 
2447 	zbx_history_record_vector_create(&values);
2448 
2449 	if (1 != num_param(parameters))
2450 	{
2451 		*error = zbx_strdup(*error, "invalid number of parameters");
2452 		goto out;
2453 	}
2454 
2455 	if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift))
2456 	{
2457 		*error = zbx_strdup(*error, "invalid parameter");
2458 		goto out;
2459 	}
2460 
2461 	switch (arg1_type)
2462 	{
2463 		case ZBX_VALUE_SECONDS:
2464 			seconds = arg1;
2465 			break;
2466 		case ZBX_VALUE_NONE:
2467 			*error = zbx_strdup(*error, "the first argument is not specified");
2468 			goto out;
2469 		case ZBX_VALUE_NVALUES:
2470 			*error = zbx_strdup(*error, "the first argument cannot be number of value");
2471 			goto out;
2472 		default:
2473 			*error = zbx_strdup(*error, "invalid type of first argument");
2474 			THIS_SHOULD_NEVER_HAPPEN;
2475 			goto out;
2476 	}
2477 
2478 	if (0 >= arg1)
2479 	{
2480 		*error = zbx_strdup(*error, "the first argument must be greater than 0");
2481 		goto out;
2482 	}
2483 
2484 	ts_end.sec -= time_shift;
2485 
2486 	if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, 0, &ts_end))
2487 	{
2488 		if (0 < values.values_num)
2489 		{
2490 			zbx_history_value2variant(&values.values[values.values_num - 1].value, item->value_type, value);
2491 			ret = SUCCEED;
2492 		}
2493 		else
2494 		{
2495 			*error = zbx_strdup(*error, "not enough data");
2496 			goto out;
2497 		}
2498 	}
2499 	else
2500 		*error = zbx_strdup(*error, "cannot get values from value cache");
2501 out:
2502 	zbx_history_record_vector_destroy(&values, item->value_type);
2503 
2504 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2505 
2506 	return ret;
2507 }
2508 
history_to_dbl_vector(const zbx_history_record_t * v,int n,unsigned char value_type,zbx_vector_dbl_t * values)2509 static void	history_to_dbl_vector(const zbx_history_record_t *v, int n, unsigned char value_type,
2510 		zbx_vector_dbl_t *values)
2511 {
2512 	int	i;
2513 
2514 	zbx_vector_dbl_reserve(values, (size_t)n);
2515 
2516 	if (ITEM_VALUE_TYPE_FLOAT == value_type)
2517 	{
2518 		for (i = 0; i < n; i++)
2519 			zbx_vector_dbl_append(values, v[i].value.dbl);
2520 	}
2521 	else
2522 	{
2523 		for (i = 0; i < n; i++)
2524 			zbx_vector_dbl_append(values, (double)v[i].value.ui64);
2525 	}
2526 }
2527 
2528 /******************************************************************************
2529  *                                                                            *
2530  * Function: evaluate_statistical_func                                        *
2531  *                                                                            *
2532  * Purpose: common operations for aggregate function calculation              *
2533  *                                                                            *
2534  * Parameters: value      - [OUT] result                                      *
2535  *             item       - [IN] item (performance metric)                    *
2536  *             parameters - [IN] number of seconds/values and time shift      *
2537  *                               (optional)                                   *
2538  *             ts         - [IN] time shift                                   *
2539  *             stat_func  - [IN] pointer to aggregate function to be called   *
2540  *             min_values - [IN] minimum data values required                 *
2541  *             error      - [OUT] the error message in the case of failure    *
2542  *                                                                            *
2543  * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2544  *               FAIL - failed to evaluate function                           *
2545  *                                                                            *
2546  ******************************************************************************/
evaluate_statistical_func(zbx_variant_t * value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,zbx_statistical_func_t stat_func,int min_values,char ** error)2547 static int	evaluate_statistical_func(zbx_variant_t *value, DC_ITEM *item, const char *parameters,
2548 		const zbx_timespec_t *ts, zbx_statistical_func_t stat_func, int min_values, char **error)
2549 {
2550 	int				ret = FAIL;
2551 	zbx_vector_history_record_t	values;
2552 
2553 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2554 
2555 	zbx_history_record_vector_create(&values);
2556 
2557 	if (SUCCEED != validate_params_and_get_data(item, parameters, ts, &values, error))
2558 		goto out;
2559 
2560 	if (min_values <= values.values_num)
2561 	{
2562 		zbx_vector_dbl_t	values_dbl;
2563 		double			result;
2564 
2565 		zbx_vector_dbl_create(&values_dbl);
2566 
2567 		history_to_dbl_vector(values.values, values.values_num, item->value_type, &values_dbl);
2568 
2569 		if (SUCCEED == (ret = stat_func(&values_dbl, &result, error)))
2570 			zbx_variant_set_dbl(value, result);
2571 
2572 		zbx_vector_dbl_destroy(&values_dbl);
2573 	}
2574 	else
2575 		*error = zbx_strdup(*error, "not enough data");
2576 out:
2577 	zbx_history_record_vector_destroy(&values, item->value_type);
2578 
2579 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2580 
2581 	return ret;
2582 }
2583 
2584 /******************************************************************************
2585  *                                                                            *
2586  * Function: evaluate_function                                                *
2587  *                                                                            *
2588  * Purpose: evaluate function                                                 *
2589  *                                                                            *
2590  * Parameters: item      - item to calculate function for                     *
2591  *             function  - function (for example, 'max')                      *
2592  *             parameter - parameter of the function                          *
2593  *                                                                            *
2594  * Return value: SUCCEED - evaluated successfully, value contains its value   *
2595  *               FAIL - evaluation failed                                     *
2596  *                                                                            *
2597  ******************************************************************************/
evaluate_function2(zbx_variant_t * value,DC_ITEM * item,const char * function,const char * parameter,const zbx_timespec_t * ts,char ** error)2598 int	evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function, const char *parameter,
2599 		const zbx_timespec_t *ts, char **error)
2600 {
2601 	int	ret;
2602 
2603 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:'%s(/%s/%s,%s)' ts:'%s\'", __func__,
2604 			function, item->host.host, item->key_orig, parameter, zbx_timespec_str(ts));
2605 
2606 	if (0 == strcmp(function, "last"))
2607 	{
2608 		ret = evaluate_LAST(value, item, parameter, ts, error);
2609 	}
2610 	else if (0 == strcmp(function, "min"))
2611 	{
2612 		ret = evaluate_MIN(value, item, parameter, ts, error);
2613 	}
2614 	else if (0 == strcmp(function, "max"))
2615 	{
2616 		ret = evaluate_MAX(value, item, parameter, ts, error);
2617 	}
2618 	else if (0 == strcmp(function, "avg"))
2619 	{
2620 		ret = evaluate_AVG(value, item, parameter, ts, error);
2621 	}
2622 	else if (0 == strcmp(function, "sum"))
2623 	{
2624 		ret = evaluate_SUM(value, item, parameter, ts, error);
2625 	}
2626 	else if (0 == strcmp(function, "percentile"))
2627 	{
2628 		ret = evaluate_PERCENTILE(value, item, parameter, ts, error);
2629 	}
2630 	else if (0 == strcmp(function, "count"))
2631 	{
2632 		ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_ALL, error);
2633 	}
2634 	else if (0 == strcmp(function, "countunique"))
2635 	{
2636 		ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_UNIQUE, error);
2637 	}
2638 	else if (0 == strcmp(function, "nodata"))
2639 	{
2640 		ret = evaluate_NODATA(value, item, parameter, error);
2641 	}
2642 	else if (0 == strcmp(function, "change"))
2643 	{
2644 		ret = evaluate_CHANGE(value, item, ts, error);
2645 	}
2646 	else if (0 == strcmp(function, "find"))
2647 	{
2648 		ret = evaluate_COUNT(value, item, parameter, ts, 1, COUNT_ALL, error);
2649 	}
2650 	else if (0 == strcmp(function, "fuzzytime"))
2651 	{
2652 		ret = evaluate_FUZZYTIME(value, item, parameter, ts, error);
2653 	}
2654 	else if (0 == strcmp(function, "logeventid"))
2655 	{
2656 		ret = evaluate_LOGEVENTID(value, item, parameter, ts, error);
2657 	}
2658 	else if (0 == strcmp(function, "logseverity"))
2659 	{
2660 		ret = evaluate_LOGSEVERITY(value, item, parameter, ts, error);
2661 	}
2662 	else if (0 == strcmp(function, "logsource"))
2663 	{
2664 		ret = evaluate_LOGSOURCE(value, item, parameter, ts, error);
2665 	}
2666 	else if (0 == strcmp(function, "bitand"))
2667 	{
2668 		ret = evaluate_BITAND(value, item, parameter, ts, error);
2669 	}
2670 	else if (0 == strcmp(function, "forecast"))
2671 	{
2672 		ret = evaluate_FORECAST(value, item, parameter, ts, error);
2673 	}
2674 	else if (0 == strcmp(function, "timeleft"))
2675 	{
2676 		ret = evaluate_TIMELEFT(value, item, parameter, ts, error);
2677 	}
2678 	else if (0 == strncmp(function, "trend", 5))
2679 	{
2680 		ret = evaluate_TREND(value, item, function + 5, parameter, ts, error);
2681 	}
2682 	else if (0 == strcmp(function, "first"))
2683 	{
2684 		ret = evaluate_FIRST(value, item, parameter, ts, error);
2685 	}
2686 	else if (0 == strcmp(function, "kurtosis"))
2687 	{
2688 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_kurtosis, 1, error);
2689 	}
2690 	else if (0 == strcmp(function, "mad"))
2691 	{
2692 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_mad, 1, error);
2693 	}
2694 	else if (0 == strcmp(function, "skewness"))
2695 	{
2696 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_skewness, 1, error);
2697 	}
2698 	else if (0 == strcmp(function, "stddevpop"))
2699 	{
2700 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevpop, 1, error);
2701 	}
2702 	else if (0 == strcmp(function, "stddevsamp"))
2703 	{
2704 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevsamp, 2, error);
2705 	}
2706 	else if (0 == strcmp(function, "sumofsquares"))
2707 	{
2708 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_sumofsquares, 1, error);
2709 	}
2710 	else if (0 == strcmp(function, "varpop"))
2711 	{
2712 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varpop, 1, error);
2713 	}
2714 	else if (0 == strcmp(function, "varsamp"))
2715 	{
2716 		ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varsamp, 2, error);
2717 	}
2718 	else
2719 	{
2720 		*error = zbx_strdup(*error, "function is not supported");
2721 		ret = FAIL;
2722 	}
2723 
2724 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:'%s' of type:'%s'", __func__, zbx_result_string(ret),
2725 			zbx_variant_value_desc(value), zbx_variant_type_desc(value));
2726 
2727 	return ret;
2728 }
2729 
2730 /******************************************************************************
2731  *                                                                            *
2732  * Function: zbx_is_trigger_function                                          *
2733  *                                                                            *
2734  * Purpose: check if the specified function is a trigger function             *
2735  *                                                                            *
2736  * Parameters: name - [IN] the function name to check                         *
2737  *             len  - [IN] the length of function name                        *
2738  *                                                                            *
2739  * Return value: SUCCEED - the function is a trigger function                 *
2740  *               FAIL - otherwise                                             *
2741  *                                                                            *
2742  ******************************************************************************/
zbx_is_trigger_function(const char * name,size_t len)2743 int	zbx_is_trigger_function(const char *name, size_t len)
2744 {
2745 	char	*functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "countunique", "nodata",
2746 			"change", "find", "fuzzytime", "logeventid", "logseverity", "logsource", "bitand", "forecast",
2747 			"timeleft", "trendavg", "trendcount", "trendmax", "trendmin", "trendsum", "abs", "cbrt",
2748 			"ceil", "exp", "floor", "log", "log10", "power", "round", "rand", "signum", "sqrt", "truncate",
2749 			"acos", "asin", "atan", "cos", "cosh", "cot", "sin", "sinh", "tan", "degrees", "radians", "mod",
2750 			"pi", "e", "expm1", "atan2", "first", "kurtosis", "mad", "skewness", "stddevpop", "stddevsamp",
2751 			"sumofsquares", "varpop", "varsamp", "ascii", "bitlength", "char", "concat", "insert", "lcase",
2752 			"left", "ltrim", "bytelength", "repeat", "replace", "right", "rtrim", "mid", "trim", "between",
2753 			"in", "bitor", "bitxor", "bitnot", "bitlshift", "bitrshift", NULL};
2754 	char	**ptr;
2755 
2756 	for (ptr = functions; NULL != *ptr; ptr++)
2757 	{
2758 		size_t	compare_len;
2759 
2760 		compare_len = strlen(*ptr);
2761 		if (compare_len == len && 0 == memcmp(*ptr, name, len))
2762 			return SUCCEED;
2763 	}
2764 
2765 	return FAIL;
2766 }
2767