1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxtrends.h"
24 #include "trends.h"
25 
26 static char	*trends_errors[ZBX_TREND_STATE_COUNT] = {
27 		"unknown error",
28 		NULL,
29 		"not enough data",
30 		"value is too large"
31 };
32 
33 /******************************************************************************
34  *                                                                            *
35  * Function: trends_parse_base                                                *
36  *                                                                            *
37  * Purpose: parse largest period base from function parameters                *
38  *                                                                            *
39  * Parameters: shift  - [IN] the period shift parameter                       *
40  *             base   - [OUT] the period shift base (now/?)                   *
41  *             error  - [OUT] the error message if parsing failed             *
42  *                                                                            *
43  * Return value: SUCCEED - period was parsed successfully                     *
44  *               FAIL    - invalid time period was specified                  *
45  *                                                                            *
46  ******************************************************************************/
trends_parse_base(const char * period_shift,zbx_time_unit_t * base,char ** error)47 static int	trends_parse_base(const char *period_shift, zbx_time_unit_t *base, char **error)
48 {
49 	zbx_time_unit_t	time_unit = ZBX_TIME_UNIT_UNKNOWN;
50 	const char	*ptr;
51 
52 	for (ptr = period_shift; NULL != (ptr = strchr(ptr, '/'));)
53 	{
54 		zbx_time_unit_t	tu;
55 
56 		if (ZBX_TIME_UNIT_UNKNOWN == (tu = zbx_tm_str_to_unit(++ptr)))
57 		{
58 			*error = zbx_strdup(*error, "invalid period shift cycle");
59 			return FAIL;
60 		}
61 
62 		if (tu > time_unit)
63 			time_unit = tu;
64 	}
65 
66 	if (ZBX_TIME_UNIT_UNKNOWN == time_unit)
67 	{
68 		*error = zbx_strdup(*error, "invalid period shift expression");
69 		return FAIL;
70 	}
71 
72 	*base = time_unit;
73 
74 	return SUCCEED;
75 }
76 
77 /******************************************************************************
78  *                                                                            *
79  * Function: zbx_trends_parse_base                                            *
80  *                                                                            *
81  * Purpose: parse largest period base from function parameters                *
82  *                                                                            *
83  * Parameters: params - [IN] the function parameters                          *
84  *             base   - [OUT] the period shift base (now/?)                   *
85  *             error  - [OUT] the error message if parsing failed             *
86  *                                                                            *
87  * Return value: SUCCEED - period was parsed successfully                     *
88  *               FAIL    - invalid time period was specified                  *
89  *                                                                            *
90  ******************************************************************************/
zbx_trends_parse_base(const char * params,zbx_time_unit_t * base,char ** error)91 int	zbx_trends_parse_base(const char *params, zbx_time_unit_t *base, char **error)
92 {
93 	const char	*period_shift;
94 	int		ret;
95 
96 	if (NULL == (period_shift = strchr(params, ':')))
97 	{
98 		*error = zbx_strdup(*error, "missing period shift parameter");
99 		return FAIL;
100 	}
101 
102 	ret = trends_parse_base(period_shift + 1, base, error);
103 
104 	return ret;
105 }
106 
107 /******************************************************************************
108  *                                                                            *
109  * Function: trends_parse_timeshift                                           *
110  *                                                                            *
111  * Purpose: parse timeshift                                                   *
112  *                                                                            *
113  * Parameters: from          - [IN] the start time                            *
114  *             timeshift     - [IN] the timeshift string                      *
115  *             min_time_unit - [IN] minimum time unit that can be used        *
116  *             tm            - [IN] the shifted time                          *
117  *             error         - [OUT] the error message if parsing failed      *
118  *                                                                            *
119  * Return value: SUCCEED - time shift was parsed successfully                 *
120  *               FAIL    - otherwise                                          *
121  *                                                                            *
122  ******************************************************************************/
trends_parse_timeshift(time_t from,const char * timeshift,zbx_time_unit_t min_time_unit,struct tm * tm,char ** error)123 static int	trends_parse_timeshift(time_t from, const char *timeshift, zbx_time_unit_t min_time_unit, struct tm *tm,
124 		char **error)
125 {
126 	size_t		len;
127 	const char	*p;
128 
129 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() shift:%s", __func__,  timeshift);
130 
131 	p = timeshift;
132 
133 	if (0 != strncmp(p, "now", ZBX_CONST_STRLEN("now")))
134 	{
135 		*error = zbx_strdup(*error, "time shift must begin with \"now\"");
136 		return FAIL;
137 	}
138 
139 	p += ZBX_CONST_STRLEN("now");
140 
141 	localtime_r(&from, tm);
142 
143 	while ('\0' != *p)
144 	{
145 		zbx_time_unit_t	unit;
146 
147 		if ('/' == *p)
148 		{
149 			if (ZBX_TIME_UNIT_UNKNOWN == (unit = zbx_tm_str_to_unit(++p)))
150 			{
151 				*error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p);
152 				return FAIL;
153 			}
154 
155 			if (unit < min_time_unit)
156 			{
157 				*error = zbx_dsprintf(*error, "time units in time shift must be greater or equal"
158 						" to period time unit");
159 				return FAIL;
160 			}
161 
162 			zbx_tm_round_down(tm, unit);
163 
164 			/* unit is single character */
165 			p++;
166 		}
167 		else if ('+' == *p || '-' == *p)
168 		{
169 			int	num;
170 			char	op = *(p++);
171 
172 			if (FAIL == zbx_tm_parse_period(p, &len, &num, &unit, error))
173 				return FAIL;
174 
175 			if (unit < min_time_unit)
176 			{
177 				*error = zbx_dsprintf(*error, "time units in period shift must be greater or equal"
178 						" to period time unit");
179 				return FAIL;
180 			}
181 
182 			if ('+' == op)
183 				zbx_tm_add(tm, num, unit);
184 			else
185 				zbx_tm_sub(tm, num, unit);
186 
187 			p += len;
188 		}
189 		else
190 		{
191 			*error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p);
192 			return FAIL;
193 		}
194 	}
195 
196 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() %04d.%02d.%02d %02d:%02d:%02d", __func__, tm->tm_year + 1900,
197 			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
198 
199 	return SUCCEED;
200 }
201 
202 /******************************************************************************
203  *                                                                            *
204  * Function: zbx_parse_timeshift                                              *
205  *                                                                            *
206  * Purpose: parse timeshift                                                   *
207  *                                                                            *
208  * Parameters: from          - [IN] the start time                            *
209  *             timeshift     - [IN] the timeshift string                      *
210  *             tm            - [IN] the shifted time                          *
211  *             error         - [OUT] the error message if parsing failed      *
212  *                                                                            *
213  * Return value: SUCCEED - time shift was parsed successfully                 *
214  *               FAIL    - otherwise                                          *
215  *                                                                            *
216  ******************************************************************************/
zbx_parse_timeshift(time_t from,const char * timeshift,struct tm * tm,char ** error)217 int	zbx_parse_timeshift(time_t from, const char *timeshift, struct tm *tm, char **error)
218 {
219 	return trends_parse_timeshift(from, timeshift, ZBX_TIME_UNIT_UNKNOWN, tm, error);
220 }
221 
222 /******************************************************************************
223  *                                                                            *
224  * Function: zbx_trends_parse_range                                           *
225  *                                                                            *
226  * Purpose: parse trend function period arguments into time range             *
227  *                                                                            *
228  * Parameters: from         - [IN] the time the period shift is calculated    *
229  *                                 from                                       *
230  *             param        - [IN] the history period parameter:              *
231  *                                     <period>:<period_shift>                *
232  *             start        - [OUT] the period start time in seconds since    *
233  *                                  Epoch                                     *
234  *             end          - [OUT] the period end time in seconds since      *
235  *                                  Epoch                                     *
236  *             error        - [OUT] the error message if parsing failed       *
237  *                                                                            *
238  * Return value: SUCCEED - period was parsed successfully                     *
239  *               FAIL    - invalid time period was specified                  *
240  *                                                                            *
241  * Comments: Daylight saving changes are applied when parsing ranges with     *
242  *           day+ used as period base (now/?).                                *
243  *                                                                            *
244  *           Example period_shift values:                                     *
245  *             now/d                                                          *
246  *             now/d-1h                                                       *
247  *             now/d+1h                                                       *
248  *             now/d+1h/w                                                     *
249  *             now/d/w/h+1h+2h                                                *
250  *             now-1d/h                                                       *
251  *                                                                            *
252  ******************************************************************************/
zbx_trends_parse_range(time_t from,const char * param,int * start,int * end,char ** error)253 int	zbx_trends_parse_range(time_t from, const char *param, int *start, int *end, char **error)
254 {
255 	int		period_num, period_hours[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, 1, 24, 24 * 7, 24 * 30, 24 * 365};
256 	zbx_time_unit_t	period_unit;
257 	size_t		len;
258 	struct tm	tm_end, tm_start;
259 
260 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() param:%s", __func__, param);
261 
262 	/* parse period */
263 
264 	if (SUCCEED != zbx_tm_parse_period(param, &len, &period_num, &period_unit, error))
265 		return FAIL;
266 
267 	if ('\0' != param[len] && ':' != param[len])
268 	{
269 		*error = zbx_dsprintf(*error, "unexpected character[s] in period \"%s\"", param + len);
270 		return FAIL;
271 	}
272 
273 	if (period_hours[period_unit] * period_num > 24 * 366)
274 	{
275 		*error = zbx_strdup(*error, "period is too large");
276 		return FAIL;
277 	}
278 
279 	/* parse period shift */
280 
281 	if (SUCCEED != trends_parse_timeshift(from, param + len + 1, period_unit, &tm_end, error))
282 		return FAIL;
283 
284 	tm_start = tm_end;
285 
286 	/* trends clock refers to the beginning of the hourly interval - subtract */
287 	/* one hour to get the trends clock for the last hourly interval          */
288 	zbx_tm_sub(&tm_end, 1, ZBX_TIME_UNIT_HOUR);
289 
290 	if (-1 == (*end = mktime(&tm_end)))
291 	{
292 		*error = zbx_dsprintf(*error, "cannot calculate the period end time: %s", zbx_strerror(errno));
293 		return FAIL;
294 	}
295 
296 	if (abs((int)from - *end) > SEC_PER_YEAR * 26)
297 	{
298 		*error = zbx_strdup(*error, "period shift is too large");
299 		return FAIL;
300 	}
301 
302 	zbx_tm_sub(&tm_start, period_num, period_unit);
303 	if (-1 == (*start = mktime(&tm_start)))
304 	{
305 		*error = zbx_dsprintf(*error, "cannot calculate the period start time: %s", zbx_strerror(errno));
306 		return FAIL;
307 	}
308 
309 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() start:%d end:%d", __func__, *start, *end);
310 
311 	return SUCCEED;
312 }
313 
314 /******************************************************************************
315  *                                                                            *
316  * Function: zbx_trends_parse_nextcheck                                       *
317  *                                                                            *
318  * Purpose: calculate possible nextcheck based on trend function parameters   *
319  *                                                                            *
320  * Parameters: from         - [IN] the time the period shift is calculated    *
321  *                                 from                                       *
322  *             p            - [IN] the history period shift                   *
323  *             nextcheck    - [OUT] the time starting from which the period   *
324  *                                  will end in future                        *
325  *             error        - [OUT] the error message if parsing failed       *
326  *                                                                            *
327  * Return value: SUCCEED - period was parsed successfully                     *
328  *               FAIL    - invalid time period was specified                  *
329  *                                                                            *
330  * Comments: Daylight saving changes are applied when parsing ranges with     *
331  *           day+ used as period base (now/?).                                *
332  *                                                                            *
333  ******************************************************************************/
zbx_trends_parse_nextcheck(time_t from,const char * period_shift,time_t * nextcheck,char ** error)334 int	zbx_trends_parse_nextcheck(time_t from, const char *period_shift, time_t *nextcheck, char **error)
335 {
336 	struct tm	tm;
337 	zbx_time_unit_t	base;
338 
339 	if (SUCCEED != trends_parse_base(period_shift, &base, error) || ZBX_TIME_UNIT_HOUR > base)
340 		return FAIL;
341 
342 	/* parse period shift */
343 
344 	if (0 != strncmp(period_shift, "now", ZBX_CONST_STRLEN("now")))
345 	{
346 		*error = zbx_strdup(*error, "period shift must begin with \"now\"");
347 		return FAIL;
348 	}
349 
350 	period_shift += ZBX_CONST_STRLEN("now");
351 
352 	localtime_r(&from, &tm);
353 
354 	while ('\0' != *period_shift)
355 	{
356 		zbx_time_unit_t	unit;
357 
358 		if ('/' == *period_shift)
359 		{
360 			if (ZBX_TIME_UNIT_UNKNOWN == (unit = zbx_tm_str_to_unit(++period_shift)))
361 			{
362 				*error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", period_shift);
363 				return FAIL;
364 			}
365 
366 			zbx_tm_round_down(&tm, unit);
367 
368 			/* unit is single character */
369 			period_shift++;
370 		}
371 		else if ('+' == *period_shift || '-' == *period_shift)
372 		{
373 			int	num;
374 			char	op = *(period_shift++);
375 			size_t	len;
376 
377 			if (FAIL == zbx_tm_parse_period(period_shift, &len, &num, &unit, error))
378 				return FAIL;
379 
380 			/* nextcheck calculation is based on the largest rounding unit, */
381 			/* so shifting larger or equal time units will not affect it    */
382 			if (unit < base)
383 			{
384 				if ('+' == op)
385 					zbx_tm_add(&tm, num, unit);
386 				else
387 					zbx_tm_sub(&tm, num, unit);
388 			}
389 
390 			period_shift += len;
391 		}
392 		else
393 		{
394 			*error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", period_shift);
395 			return FAIL;
396 		}
397 	}
398 
399 	/* trends clock refers to the beginning of the hourly interval - subtract */
400 	/* one hour to get the trends clock for the last hourly interval          */
401 	zbx_tm_sub(&tm, 1, ZBX_TIME_UNIT_HOUR);
402 
403 	if (-1 == (*nextcheck = mktime(&tm)))
404 	{
405 		*error = zbx_dsprintf(*error, "cannot calculate the period start time: %s", zbx_strerror(errno));
406 		return FAIL;
407 	}
408 
409 	return SUCCEED;
410 }
411 
412 /******************************************************************************
413  *                                                                            *
414  * Function: trends_eval                                                      *
415  *                                                                            *
416  * Purpose: evaluate expression with trends data                              *
417  *                                                                            *
418  * Parameters: table       - [IN] the trends table name                       *
419  *             itemid      - [IN] the itemid                                  *
420  *             start       - [OUT] the period start time in seconds since     *
421  *                                  Epoch                                     *
422  *             end         - [OUT] the period end time in seconds since       *
423  *                                  Epoch                                     *
424  *             eval_single - [IN] sql expression to evaluate for single       *
425  *                                 record                                     *
426  *             eval_multi  - [IN] sql expression to evaluate for multiple     *
427  *                                 records                                    *
428  *             value       - [OUT] the evaluation result                      *
429  *                                                                            *
430  * Return value: Trend value state of the specified period and function.      *
431  *                                                                            *
432  ******************************************************************************/
trends_eval(const char * table,zbx_uint64_t itemid,int start,int end,const char * eval_single,const char * eval_multi,double * value)433 static zbx_trend_state_t	trends_eval(const char *table, zbx_uint64_t itemid, int start, int end,
434 		const char *eval_single, const char *eval_multi, double *value)
435 {
436 	DB_RESULT		result;
437 	DB_ROW			row;
438 	char			*sql = NULL;
439 	size_t			sql_alloc = 0, sql_offset = 0;
440 	zbx_trend_state_t	state;
441 
442 	if (start != end)
443 	{
444 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
445 				"select %s from %s"
446 				" where itemid=" ZBX_FS_UI64
447 					" and clock>=%d"
448 					" and clock<=%d",
449 				eval_multi, table, itemid, start, end);
450 	}
451 	else
452 	{
453 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
454 				"select %s from %s"
455 				" where itemid=" ZBX_FS_UI64
456 					" and clock=%d",
457 				eval_single, table, itemid, start);
458 	}
459 
460 	result = DBselect("%s", sql);
461 	zbx_free(sql);
462 
463 	if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
464 	{
465 		*value = atof(row[0]);
466 		state = ZBX_TREND_STATE_NORMAL;
467 	}
468 	else
469 		state = ZBX_TREND_STATE_NODATA;
470 
471 	DBfree_result(result);
472 
473 	return state;
474 }
475 
476 /******************************************************************************
477  *                                                                            *
478  * Function: trends_eval_avg                                                  *
479  *                                                                            *
480  * Purpose: evaluate avg function with trends data                            *
481  *                                                                            *
482  * Parameters: table       - [IN] the trends table name                       *
483  *             itemid      - [IN] the itemid                                  *
484  *             start       - [OUT] the period start time in seconds since     *
485  *                                  Epoch                                     *
486  *             end         - [OUT] the period end time in seconds since       *
487  *                                  Epoch                                     *
488  *             value       - [OUT] the evaluation result                      *
489  *                                                                            *
490  * Return value: Trend value state of the specified period and function.      *
491  *                                                                            *
492  ******************************************************************************/
trends_eval_avg(const char * table,zbx_uint64_t itemid,int start,int end,double * value)493 static zbx_trend_state_t	trends_eval_avg(const char *table, zbx_uint64_t itemid, int start, int end,
494 		double *value)
495 {
496 	DB_RESULT		result;
497 	DB_ROW			row;
498 	char			*sql = NULL;
499 	size_t			sql_alloc = 0, sql_offset = 0;
500 	zbx_trend_state_t	state;
501 	double			avg, num, num2, avg2;
502 
503 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select value_avg,num from %s where itemid=" ZBX_FS_UI64,
504 			table, itemid);
505 	if (start != end)
506 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock>=%d and clock<=%d", start, end);
507 	else
508 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock=%d", start);
509 
510 	result = DBselect("%s", sql);
511 	zbx_free(sql);
512 
513 	if (NULL != (row = DBfetch(result)))
514 	{
515 		avg = atof(row[0]);
516 		num = atof(row[1]);
517 
518 		while (NULL != (row = DBfetch(result)))
519 		{
520 			avg2 = atof(row[0]);
521 			num2 = atof(row[1]);
522 			avg = avg / (num + num2) * num + avg2 / (num + num2) * num2;
523 			num += num2;
524 		}
525 
526 		*value = avg;
527 		state = ZBX_TREND_STATE_NORMAL;
528 	}
529 	else
530 		state = ZBX_TREND_STATE_NODATA;
531 
532 	DBfree_result(result);
533 
534 	return state;
535 }
536 
537 /******************************************************************************
538  *                                                                            *
539  * Function: trends_eval_sum                                                  *
540  *                                                                            *
541  * Purpose: evaluate sum function with trends data                            *
542  *                                                                            *
543  * Parameters: table       - [IN] the trends table name                       *
544  *             itemid      - [IN] the itemid                                  *
545  *             start       - [OUT] the period start time in seconds since     *
546  *                                  Epoch                                     *
547  *             end         - [OUT] the period end time in seconds since       *
548  *                                  Epoch                                     *
549  *             value       - [OUT] the evaluation result                      *
550  *                                                                            *
551  * Return value: Trend value state of the specified period and function.      *
552  *                                                                            *
553  ******************************************************************************/
trends_eval_sum(const char * table,zbx_uint64_t itemid,int start,int end,double * value)554 static zbx_trend_state_t	trends_eval_sum(const char *table, zbx_uint64_t itemid, int start, int end,
555 		double *value)
556 {
557 	DB_RESULT	result;
558 	DB_ROW		row;
559 	char		*sql = NULL;
560 	size_t		sql_alloc = 0, sql_offset = 0;
561 	double		sum = 0;
562 
563 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select value_avg,num from %s where itemid=" ZBX_FS_UI64,
564 			table, itemid);
565 	if (start != end)
566 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock>=%d and clock<=%d", start, end);
567 	else
568 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and clock=%d", start);
569 
570 	result = DBselect("%s", sql);
571 	zbx_free(sql);
572 
573 	while (NULL != (row = DBfetch(result)))
574 		sum += atof(row[0]) * atof(row[1]);
575 
576 	DBfree_result(result);
577 
578 	if (ZBX_INFINITY == sum)
579 		return ZBX_TREND_STATE_OVERFLOW;
580 
581 	*value = sum;
582 
583 	return ZBX_TREND_STATE_NORMAL;
584 }
585 
zbx_trends_eval_avg(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)586 int	zbx_trends_eval_avg(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
587 {
588 	zbx_trend_state_t	state;
589 
590 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_AVG, value, &state))
591 	{
592 		state = trends_eval_avg(table, itemid, start, end, value);
593 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_AVG, *value, state);
594 	}
595 
596 	if (ZBX_TREND_STATE_NORMAL == state)
597 		return SUCCEED;
598 
599 	if (NULL != error)
600 		*error = zbx_strdup(*error, trends_errors[state]);
601 
602 	return FAIL;
603 }
604 
zbx_trends_eval_count(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)605 int	zbx_trends_eval_count(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
606 {
607 	zbx_trend_state_t	state;
608 
609 	ZBX_UNUSED(error);
610 
611 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_COUNT, value, &state))
612 	{
613 		if (ZBX_TREND_STATE_NORMAL != (state = trends_eval(table, itemid, start, end, "num", "sum(num)", value)))
614 		{
615 			state = ZBX_TREND_STATE_NORMAL;
616 			*value = 0;
617 		}
618 
619 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_COUNT, *value, state);
620 	}
621 
622 	return SUCCEED;
623 }
624 
zbx_trends_eval_delta(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)625 int	zbx_trends_eval_delta(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
626 {
627 	zbx_trend_state_t	state;
628 
629 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_DELTA, value, &state))
630 	{
631 		state = trends_eval(table, itemid, start, end, "value_max-value_min", "max(value_max)-min(value_min)",
632 				value);
633 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_DELTA, *value, state);
634 	}
635 
636 	if (ZBX_TREND_STATE_NORMAL == state)
637 		return SUCCEED;
638 
639 	if (NULL != error)
640 		*error = zbx_strdup(*error, trends_errors[state]);
641 
642 	return FAIL;
643 }
644 
zbx_trends_eval_max(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)645 int	zbx_trends_eval_max(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
646 {
647 	zbx_trend_state_t	state;
648 
649 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_MAX, value, &state))
650 	{
651 		state = trends_eval(table, itemid, start, end, "value_max", "max(value_max)", value);
652 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_MAX, *value, state);
653 	}
654 
655 	if (ZBX_TREND_STATE_NORMAL == state)
656 		return SUCCEED;
657 
658 	if (NULL != error)
659 		*error = zbx_strdup(*error, trends_errors[state]);
660 
661 	return FAIL;
662 }
663 
zbx_trends_eval_min(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)664 int	zbx_trends_eval_min(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
665 {
666 	zbx_trend_state_t	state;
667 
668 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_MIN, value, &state))
669 	{
670 		state = trends_eval(table, itemid, start, end, "value_min", "min(value_min)", value);
671 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_MIN, *value, state);
672 	}
673 
674 	if (ZBX_TREND_STATE_NORMAL == state)
675 		return SUCCEED;
676 
677 	if (NULL != error)
678 		*error = zbx_strdup(*error, trends_errors[state]);
679 
680 	return FAIL;
681 }
682 
zbx_trends_eval_sum(const char * table,zbx_uint64_t itemid,int start,int end,double * value,char ** error)683 int	zbx_trends_eval_sum(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error)
684 {
685 	zbx_trend_state_t	state;
686 
687 	if (FAIL == zbx_tfc_get_value(itemid, start, end, ZBX_TREND_FUNCTION_SUM, value, &state))
688 	{
689 		state = trends_eval_sum(table, itemid, start, end, value);
690 		zbx_tfc_put_value(itemid, start, end, ZBX_TREND_FUNCTION_SUM, *value, state);
691 	}
692 
693 	if (ZBX_TREND_STATE_NORMAL == state)
694 		return SUCCEED;
695 
696 	if (NULL != error)
697 		*error = zbx_strdup(*error, trends_errors[state]);
698 
699 	return FAIL;
700 }
701