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 "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25 
26 typedef struct
27 {
28 	zbx_uint64_t		graphid;
29 	char			*name;
30 	char			*name_orig;
31 	zbx_uint64_t		ymin_itemid;
32 	zbx_uint64_t		ymax_itemid;
33 	zbx_vector_ptr_t	gitems;
34 #define ZBX_FLAG_LLD_GRAPH_UNSET			__UINT64_C(0x00000000)
35 #define ZBX_FLAG_LLD_GRAPH_DISCOVERED			__UINT64_C(0x00000001)
36 #define ZBX_FLAG_LLD_GRAPH_UPDATE_NAME			__UINT64_C(0x00000002)
37 #define ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH			__UINT64_C(0x00000004)
38 #define ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT		__UINT64_C(0x00000008)
39 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN		__UINT64_C(0x00000010)
40 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX		__UINT64_C(0x00000020)
41 #define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD	__UINT64_C(0x00000040)
42 #define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS		__UINT64_C(0x00000080)
43 #define ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE		__UINT64_C(0x00000100)
44 #define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND		__UINT64_C(0x00000200)
45 #define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D		__UINT64_C(0x00000400)
46 #define ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT		__UINT64_C(0x00000800)
47 #define ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT		__UINT64_C(0x00001000)
48 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE		__UINT64_C(0x00002000)
49 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID		__UINT64_C(0x00004000)
50 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE		__UINT64_C(0x00008000)
51 #define ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID		__UINT64_C(0x00010000)
52 #define ZBX_FLAG_LLD_GRAPH_UPDATE									\
53 		(ZBX_FLAG_LLD_GRAPH_UPDATE_NAME | ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH |			\
54 		ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT | ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN |			\
55 		ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX | ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD |	\
56 		ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS | ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE |		\
57 		ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND | ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D |		\
58 		ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT | ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT |	\
59 		ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE | ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID |		\
60 		ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE | ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID)
61 	zbx_uint64_t		flags;
62 	int			lastcheck;
63 	int			ts_delete;
64 }
65 zbx_lld_graph_t;
66 
67 typedef struct
68 {
69 	zbx_uint64_t		gitemid;
70 	zbx_uint64_t		itemid;
71 	char			*color;
72 	int			sortorder;
73 	unsigned char		drawtype;
74 	unsigned char		yaxisside;
75 	unsigned char		calc_fnc;
76 	unsigned char		type;
77 #define ZBX_FLAG_LLD_GITEM_UNSET			__UINT64_C(0x0000)
78 #define ZBX_FLAG_LLD_GITEM_DISCOVERED			__UINT64_C(0x0001)
79 #define ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID		__UINT64_C(0x0002)
80 #define ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE		__UINT64_C(0x0004)
81 #define ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER		__UINT64_C(0x0008)
82 #define ZBX_FLAG_LLD_GITEM_UPDATE_COLOR			__UINT64_C(0x0010)
83 #define ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE		__UINT64_C(0x0020)
84 #define ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC		__UINT64_C(0x0040)
85 #define ZBX_FLAG_LLD_GITEM_UPDATE_TYPE			__UINT64_C(0x0080)
86 #define ZBX_FLAG_LLD_GITEM_UPDATE								\
87 		(ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID | ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE |	\
88 		ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER | ZBX_FLAG_LLD_GITEM_UPDATE_COLOR |		\
89 		ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE | ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC |	\
90 		ZBX_FLAG_LLD_GITEM_UPDATE_TYPE)
91 #define ZBX_FLAG_LLD_GITEM_DELETE			__UINT64_C(0x0100)
92 	zbx_uint64_t		flags;
93 }
94 zbx_lld_gitem_t;
95 
96 typedef struct
97 {
98 	zbx_uint64_t	itemid;
99 	unsigned char	flags;
100 }
101 zbx_lld_item_t;
102 
lld_item_free(zbx_lld_item_t * item)103 static void	lld_item_free(zbx_lld_item_t *item)
104 {
105 	zbx_free(item);
106 }
107 
lld_items_free(zbx_vector_ptr_t * items)108 static void	lld_items_free(zbx_vector_ptr_t *items)
109 {
110 	while (0 != items->values_num)
111 		lld_item_free((zbx_lld_item_t *)items->values[--items->values_num]);
112 }
113 
lld_gitem_free(zbx_lld_gitem_t * gitem)114 static void	lld_gitem_free(zbx_lld_gitem_t *gitem)
115 {
116 	zbx_free(gitem->color);
117 	zbx_free(gitem);
118 }
119 
lld_gitems_free(zbx_vector_ptr_t * gitems)120 static void	lld_gitems_free(zbx_vector_ptr_t *gitems)
121 {
122 	while (0 != gitems->values_num)
123 		lld_gitem_free((zbx_lld_gitem_t *)gitems->values[--gitems->values_num]);
124 }
125 
lld_graph_free(zbx_lld_graph_t * graph)126 static void	lld_graph_free(zbx_lld_graph_t *graph)
127 {
128 	lld_gitems_free(&graph->gitems);
129 	zbx_vector_ptr_destroy(&graph->gitems);
130 	zbx_free(graph->name_orig);
131 	zbx_free(graph->name);
132 	zbx_free(graph);
133 }
134 
lld_graphs_free(zbx_vector_ptr_t * graphs)135 static void	lld_graphs_free(zbx_vector_ptr_t *graphs)
136 {
137 	while (0 != graphs->values_num)
138 		lld_graph_free((zbx_lld_graph_t *)graphs->values[--graphs->values_num]);
139 }
140 
141 /******************************************************************************
142  *                                                                            *
143  * Function: lld_graphs_get                                                   *
144  *                                                                            *
145  * Purpose: retrieve graphs which were created by the specified graph         *
146  *          prototype                                                         *
147  *                                                                            *
148  * Parameters: parent_graphid - [IN] graph prototype identificator            *
149  *             graphs         - [OUT] sorted list of graphs                   *
150  *                                                                            *
151  ******************************************************************************/
lld_graphs_get(zbx_uint64_t parent_graphid,zbx_vector_ptr_t * graphs,int width,int height,double yaxismin,double yaxismax,unsigned char show_work_period,unsigned char show_triggers,unsigned char graphtype,unsigned char show_legend,unsigned char show_3d,double percent_left,double percent_right,unsigned char ymin_type,unsigned char ymax_type)152 static void	lld_graphs_get(zbx_uint64_t parent_graphid, zbx_vector_ptr_t *graphs, int width, int height,
153 		double yaxismin, double yaxismax, unsigned char show_work_period, unsigned char show_triggers,
154 		unsigned char graphtype, unsigned char show_legend, unsigned char show_3d, double percent_left,
155 		double percent_right, unsigned char ymin_type, unsigned char ymax_type)
156 {
157 	DB_RESULT	result;
158 	DB_ROW		row;
159 	zbx_lld_graph_t	*graph;
160 
161 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
162 
163 	result = DBselect(
164 			"select g.graphid,g.name,g.width,g.height,g.yaxismin,g.yaxismax,g.show_work_period,"
165 				"g.show_triggers,g.graphtype,g.show_legend,g.show_3d,g.percent_left,g.percent_right,"
166 				"g.ymin_type,g.ymin_itemid,g.ymax_type,g.ymax_itemid,gd.lastcheck,gd.ts_delete"
167 			" from graphs g,graph_discovery gd"
168 			" where g.graphid=gd.graphid"
169 				" and gd.parent_graphid=" ZBX_FS_UI64,
170 			parent_graphid);
171 
172 	while (NULL != (row = DBfetch(result)))
173 	{
174 		graph = (zbx_lld_graph_t *)zbx_malloc(NULL, sizeof(zbx_lld_graph_t));
175 
176 		ZBX_STR2UINT64(graph->graphid, row[0]);
177 		graph->name = zbx_strdup(NULL, row[1]);
178 		graph->name_orig = NULL;
179 
180 		graph->flags = ZBX_FLAG_LLD_GRAPH_UNSET;
181 
182 		if (atoi(row[2]) != width)
183 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH;
184 
185 		if (atoi(row[3]) != height)
186 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT;
187 
188 		if (atof(row[4]) != yaxismin)
189 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN;
190 
191 		if (atof(row[5]) != yaxismax)
192 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX;
193 
194 		if ((unsigned char)atoi(row[6]) != show_work_period)
195 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD;
196 
197 		if ((unsigned char)atoi(row[7]) != show_triggers)
198 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS;
199 
200 		if ((unsigned char)atoi(row[8]) != graphtype)
201 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE;
202 
203 		if ((unsigned char)atoi(row[9]) != show_legend)
204 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND;
205 
206 		if ((unsigned char)atoi(row[10]) != show_3d)
207 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D;
208 
209 		if (atof(row[11]) != percent_left)
210 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT;
211 
212 		if (atof(row[12]) != percent_right)
213 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT;
214 
215 		if ((unsigned char)atoi(row[13]) != ymin_type)
216 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE;
217 
218 		ZBX_DBROW2UINT64(graph->ymin_itemid, row[14]);
219 
220 		if ((unsigned char)atoi(row[15]) != ymax_type)
221 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE;
222 
223 		ZBX_DBROW2UINT64(graph->ymax_itemid, row[16]);
224 
225 		graph->lastcheck = atoi(row[17]);
226 		graph->ts_delete = atoi(row[18]);
227 
228 		zbx_vector_ptr_create(&graph->gitems);
229 
230 		zbx_vector_ptr_append(graphs, graph);
231 	}
232 	DBfree_result(result);
233 
234 	zbx_vector_ptr_sort(graphs, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
235 
236 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
237 }
238 
239 /******************************************************************************
240  *                                                                            *
241  * Function: lld_gitems_get                                                   *
242  *                                                                            *
243  * Purpose: retrieve graphs_items which are used by the graph prototype and   *
244  *          by selected graphs                                                *
245  *                                                                            *
246  ******************************************************************************/
lld_gitems_get(zbx_uint64_t parent_graphid,zbx_vector_ptr_t * gitems_proto,zbx_vector_ptr_t * graphs)247 static void	lld_gitems_get(zbx_uint64_t parent_graphid, zbx_vector_ptr_t *gitems_proto,
248 		zbx_vector_ptr_t *graphs)
249 {
250 	int			i, index;
251 	zbx_lld_graph_t		*graph;
252 	zbx_lld_gitem_t		*gitem;
253 	zbx_uint64_t		graphid;
254 	zbx_vector_uint64_t	graphids;
255 	DB_RESULT		result;
256 	DB_ROW			row;
257 	char			*sql = NULL;
258 	size_t			sql_alloc = 256, sql_offset = 0;
259 
260 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
261 
262 	zbx_vector_uint64_create(&graphids);
263 	zbx_vector_uint64_append(&graphids, parent_graphid);
264 
265 	for (i = 0; i < graphs->values_num; i++)
266 	{
267 		graph = (zbx_lld_graph_t *)graphs->values[i];
268 
269 		zbx_vector_uint64_append(&graphids, graph->graphid);
270 	}
271 
272 	zbx_vector_uint64_sort(&graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
273 
274 	sql = (char *)zbx_malloc(sql, sql_alloc);
275 
276 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
277 			"select gitemid,graphid,itemid,drawtype,sortorder,color,yaxisside,calc_fnc,type"
278 			" from graphs_items"
279 			" where");
280 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid",
281 			graphids.values, graphids.values_num);
282 
283 	result = DBselect("%s", sql);
284 
285 	zbx_free(sql);
286 
287 	while (NULL != (row = DBfetch(result)))
288 	{
289 		gitem = (zbx_lld_gitem_t *)zbx_malloc(NULL, sizeof(zbx_lld_gitem_t));
290 
291 		ZBX_STR2UINT64(gitem->gitemid, row[0]);
292 		ZBX_STR2UINT64(graphid, row[1]);
293 		ZBX_STR2UINT64(gitem->itemid, row[2]);
294 		ZBX_STR2UCHAR(gitem->drawtype, row[3]);
295 		gitem->sortorder = atoi(row[4]);
296 		gitem->color = zbx_strdup(NULL, row[5]);
297 		ZBX_STR2UCHAR(gitem->yaxisside, row[6]);
298 		ZBX_STR2UCHAR(gitem->calc_fnc, row[7]);
299 		ZBX_STR2UCHAR(gitem->type, row[8]);
300 
301 		gitem->flags = ZBX_FLAG_LLD_GITEM_UNSET;
302 
303 		if (graphid == parent_graphid)
304 		{
305 			zbx_vector_ptr_append(gitems_proto, gitem);
306 		}
307 		else if (FAIL != (index = zbx_vector_ptr_bsearch(graphs, &graphid,
308 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
309 		{
310 			graph = (zbx_lld_graph_t *)graphs->values[index];
311 
312 			zbx_vector_ptr_append(&graph->gitems, gitem);
313 		}
314 		else
315 		{
316 			THIS_SHOULD_NEVER_HAPPEN;
317 			lld_gitem_free(gitem);
318 		}
319 	}
320 	DBfree_result(result);
321 
322 	zbx_vector_ptr_sort(gitems_proto, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
323 
324 	for (i = 0; i < graphs->values_num; i++)
325 	{
326 		graph = (zbx_lld_graph_t *)graphs->values[i];
327 
328 		zbx_vector_ptr_sort(&graph->gitems, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
329 	}
330 
331 	zbx_vector_uint64_destroy(&graphids);
332 
333 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
334 }
335 
336 /******************************************************************************
337  *                                                                            *
338  * Function: lld_items_get                                                    *
339  *                                                                            *
340  * Purpose: returns the list of items which are related to the graph          *
341  *          prototype                                                         *
342  *                                                                            *
343  * Parameters: gitems_proto      - [IN] graph prototype's graphs_items        *
344  *             ymin_itemid_proto - [IN] graph prototype's ymin_itemid         *
345  *             ymax_itemid_proto - [IN] graph prototype's ymax_itemid         *
346  *             items             - [OUT] sorted list of items                 *
347  *                                                                            *
348  ******************************************************************************/
lld_items_get(const zbx_vector_ptr_t * gitems_proto,zbx_uint64_t ymin_itemid_proto,zbx_uint64_t ymax_itemid_proto,zbx_vector_ptr_t * items)349 static void	lld_items_get(const zbx_vector_ptr_t *gitems_proto, zbx_uint64_t ymin_itemid_proto,
350 		zbx_uint64_t ymax_itemid_proto, zbx_vector_ptr_t *items)
351 {
352 	DB_RESULT		result;
353 	DB_ROW			row;
354 	const zbx_lld_gitem_t	*gitem;
355 	zbx_lld_item_t		*item;
356 	zbx_vector_uint64_t	itemids;
357 	int			i;
358 
359 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
360 
361 	zbx_vector_uint64_create(&itemids);
362 
363 	for (i = 0; i < gitems_proto->values_num; i++)
364 	{
365 		gitem = (zbx_lld_gitem_t *)gitems_proto->values[i];
366 
367 		zbx_vector_uint64_append(&itemids, gitem->itemid);
368 	}
369 
370 	if (0 != ymin_itemid_proto)
371 		zbx_vector_uint64_append(&itemids, ymin_itemid_proto);
372 
373 	if (0 != ymax_itemid_proto)
374 		zbx_vector_uint64_append(&itemids, ymax_itemid_proto);
375 
376 	if (0 != itemids.values_num)
377 	{
378 		char	*sql = NULL;
379 		size_t	sql_alloc = 256, sql_offset = 0;
380 
381 		zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
382 
383 		sql = (char *)zbx_malloc(sql, sql_alloc);
384 
385 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
386 				"select itemid,flags"
387 				" from items"
388 				" where");
389 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids.values, itemids.values_num);
390 
391 		result = DBselect("%s", sql);
392 
393 		zbx_free(sql);
394 
395 		while (NULL != (row = DBfetch(result)))
396 		{
397 			item = (zbx_lld_item_t *)zbx_malloc(NULL, sizeof(zbx_lld_item_t));
398 
399 			ZBX_STR2UINT64(item->itemid, row[0]);
400 			ZBX_STR2UCHAR(item->flags, row[1]);
401 
402 			zbx_vector_ptr_append(items, item);
403 		}
404 		DBfree_result(result);
405 
406 		zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
407 	}
408 
409 	zbx_vector_uint64_destroy(&itemids);
410 
411 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
412 }
413 
414 /******************************************************************************
415  *                                                                            *
416  * Function: lld_graph_by_item                                                *
417  *                                                                            *
418  * Purpose: finds already existing graph, using an item                       *
419  *                                                                            *
420  * Return value: upon successful completion return pointer to the graph       *
421  *                                                                            *
422  ******************************************************************************/
lld_graph_by_item(zbx_vector_ptr_t * graphs,zbx_uint64_t itemid)423 static zbx_lld_graph_t	*lld_graph_by_item(zbx_vector_ptr_t *graphs, zbx_uint64_t itemid)
424 {
425 	int		i, j;
426 	zbx_lld_graph_t	*graph;
427 	zbx_lld_gitem_t	*gitem;
428 
429 	for (i = 0; i < graphs->values_num; i++)
430 	{
431 		graph = (zbx_lld_graph_t *)graphs->values[i];
432 
433 		if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
434 			continue;
435 
436 		for (j = 0; j < graph->gitems.values_num; j++)
437 		{
438 			gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
439 
440 			if (gitem->itemid == itemid)
441 				return graph;
442 		}
443 	}
444 
445 	return NULL;
446 }
447 
448 /******************************************************************************
449  *                                                                            *
450  * Function: lld_graph_get                                                    *
451  *                                                                            *
452  * Purpose: finds already existing graph, using an item prototype and items   *
453  *          already created by it                                             *
454  *                                                                            *
455  * Return value: upon successful completion return pointer to the graph       *
456  *                                                                            *
457  ******************************************************************************/
lld_graph_get(zbx_vector_ptr_t * graphs,const zbx_vector_ptr_t * item_links)458 static zbx_lld_graph_t	*lld_graph_get(zbx_vector_ptr_t *graphs, const zbx_vector_ptr_t *item_links)
459 {
460 	int		i;
461 	zbx_lld_graph_t	*graph;
462 
463 	for (i = 0; i < item_links->values_num; i++)
464 	{
465 		const zbx_lld_item_link_t	*item_link = (zbx_lld_item_link_t *)item_links->values[i];
466 
467 		if (NULL != (graph = lld_graph_by_item(graphs, item_link->itemid)))
468 			return graph;
469 	}
470 
471 	return NULL;
472 }
473 
474 /******************************************************************************
475  *                                                                            *
476  * Function: lld_item_get                                                     *
477  *                                                                            *
478  * Purpose: finds already created item when itemid_proto is an item prototype *
479  *          or return itemid_proto as itemid if it's a normal item            *
480  *                                                                            *
481  * Return value: SUCCEED if item successfully processed, FAIL - otherwise     *
482  *                                                                            *
483  ******************************************************************************/
lld_item_get(zbx_uint64_t itemid_proto,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * item_links,zbx_uint64_t * itemid)484 static int	lld_item_get(zbx_uint64_t itemid_proto, const zbx_vector_ptr_t *items,
485 		const zbx_vector_ptr_t *item_links, zbx_uint64_t *itemid)
486 {
487 	int			index;
488 	zbx_lld_item_t		*item_proto;
489 	zbx_lld_item_link_t	*item_link;
490 
491 	if (FAIL == (index = zbx_vector_ptr_bsearch(items, &itemid_proto, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
492 		return FAIL;
493 
494 	item_proto = (zbx_lld_item_t *)items->values[index];
495 
496 	if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
497 	{
498 		index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
499 
500 		if (FAIL == index)
501 			return FAIL;
502 
503 		item_link = (zbx_lld_item_link_t *)item_links->values[index];
504 
505 		*itemid = item_link->itemid;
506 	}
507 	else
508 		*itemid = item_proto->itemid;
509 
510 	return SUCCEED;
511 }
512 
lld_gitems_make(const zbx_vector_ptr_t * gitems_proto,zbx_vector_ptr_t * gitems,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * item_links)513 static int	lld_gitems_make(const zbx_vector_ptr_t *gitems_proto, zbx_vector_ptr_t *gitems,
514 		const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *item_links)
515 {
516 	int			i, ret = FAIL;
517 	const zbx_lld_gitem_t	*gitem_proto;
518 	zbx_lld_gitem_t		*gitem;
519 	zbx_uint64_t		itemid;
520 
521 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
522 
523 	for (i = 0; i < gitems_proto->values_num; i++)
524 	{
525 		gitem_proto = (zbx_lld_gitem_t *)gitems_proto->values[i];
526 
527 		if (SUCCEED != lld_item_get(gitem_proto->itemid, items, item_links, &itemid))
528 			goto out;
529 
530 		if (i == gitems->values_num)
531 		{
532 			gitem = (zbx_lld_gitem_t *)zbx_malloc(NULL, sizeof(zbx_lld_gitem_t));
533 
534 			gitem->gitemid = 0;
535 			gitem->itemid = itemid;
536 			gitem->drawtype = gitem_proto->drawtype;
537 			gitem->sortorder = gitem_proto->sortorder;
538 			gitem->color = zbx_strdup(NULL, gitem_proto->color);
539 			gitem->yaxisside = gitem_proto->yaxisside;
540 			gitem->calc_fnc = gitem_proto->calc_fnc;
541 			gitem->type = gitem_proto->type;
542 
543 			gitem->flags = ZBX_FLAG_LLD_GITEM_DISCOVERED;
544 
545 			zbx_vector_ptr_append(gitems, gitem);
546 		}
547 		else
548 		{
549 			gitem = (zbx_lld_gitem_t *)gitems->values[i];
550 
551 			if (gitem->itemid != itemid)
552 			{
553 				gitem->itemid = itemid;
554 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID;
555 			}
556 
557 			if (gitem->drawtype != gitem_proto->drawtype)
558 			{
559 				gitem->drawtype = gitem_proto->drawtype;
560 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE;
561 			}
562 
563 			if (gitem->sortorder != gitem_proto->sortorder)
564 			{
565 				gitem->sortorder = gitem_proto->sortorder;
566 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER;
567 			}
568 
569 			if (0 != strcmp(gitem->color, gitem_proto->color))
570 			{
571 				gitem->color = zbx_strdup(gitem->color, gitem_proto->color);
572 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_COLOR;
573 			}
574 
575 			if (gitem->yaxisside != gitem_proto->yaxisside)
576 			{
577 				gitem->yaxisside = gitem_proto->yaxisside;
578 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE;
579 			}
580 
581 			if (gitem->calc_fnc != gitem_proto->calc_fnc)
582 			{
583 				gitem->calc_fnc = gitem_proto->calc_fnc;
584 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC;
585 			}
586 
587 			if (gitem->type != gitem_proto->type)
588 			{
589 				gitem->type = gitem_proto->type;
590 				gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_TYPE;
591 			}
592 
593 			gitem->flags |= ZBX_FLAG_LLD_GITEM_DISCOVERED;
594 		}
595 	}
596 
597 	for (; i < gitems->values_num; i++)
598 	{
599 		gitem = (zbx_lld_gitem_t *)gitems->values[i];
600 
601 		gitem->flags |= ZBX_FLAG_LLD_GITEM_DELETE;
602 	}
603 
604 	ret = SUCCEED;
605 out:
606 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
607 
608 	return ret;
609 }
610 
611 /******************************************************************************
612  *                                                                            *
613  * Function: lld_graph_make                                                   *
614  *                                                                            *
615  * Purpose: create a graph based on lld rule and add it to the list           *
616  *                                                                            *
617  ******************************************************************************/
lld_graph_make(const zbx_vector_ptr_t * gitems_proto,zbx_vector_ptr_t * graphs,zbx_vector_ptr_t * items,const char * name_proto,zbx_uint64_t ymin_itemid_proto,zbx_uint64_t ymax_itemid_proto,unsigned char discover_proto,const zbx_lld_row_t * lld_row,const zbx_vector_ptr_t * lld_macro_paths)618 static void 	lld_graph_make(const zbx_vector_ptr_t *gitems_proto, zbx_vector_ptr_t *graphs, zbx_vector_ptr_t *items,
619 		const char *name_proto, zbx_uint64_t ymin_itemid_proto, zbx_uint64_t ymax_itemid_proto,
620 		unsigned char discover_proto, const zbx_lld_row_t *lld_row, const zbx_vector_ptr_t *lld_macro_paths)
621 {
622 	zbx_lld_graph_t			*graph = NULL;
623 	char				*buffer = NULL;
624 	const struct zbx_json_parse	*jp_row = &lld_row->jp_row;
625 	zbx_uint64_t			ymin_itemid, ymax_itemid;
626 
627 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
628 
629 	if (0 == ymin_itemid_proto)
630 		ymin_itemid = 0;
631 	else if (SUCCEED != lld_item_get(ymin_itemid_proto, items, &lld_row->item_links, &ymin_itemid))
632 		goto out;
633 
634 	if (0 == ymax_itemid_proto)
635 		ymax_itemid = 0;
636 	else if (SUCCEED != lld_item_get(ymax_itemid_proto, items, &lld_row->item_links, &ymax_itemid))
637 		goto out;
638 
639 	if (NULL != (graph = lld_graph_get(graphs, &lld_row->item_links)))
640 	{
641 		buffer = zbx_strdup(buffer, name_proto);
642 		substitute_lld_macros(&buffer, jp_row, lld_macro_paths, ZBX_MACRO_SIMPLE, NULL, 0);
643 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
644 		if (0 != strcmp(graph->name, buffer))
645 		{
646 			graph->name_orig = graph->name;
647 			graph->name = buffer;
648 			buffer = NULL;
649 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_NAME;
650 		}
651 
652 		lld_override_graph(&lld_row->overrides, graph->name, &discover_proto);
653 
654 		if (ZBX_PROTOTYPE_NO_DISCOVER == discover_proto)
655 			goto out;
656 
657 		if (graph->ymin_itemid != ymin_itemid)
658 		{
659 			graph->ymin_itemid = ymin_itemid;
660 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID;
661 		}
662 
663 		if (graph->ymax_itemid != ymax_itemid)
664 		{
665 			graph->ymax_itemid = ymax_itemid;
666 			graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID;
667 		}
668 	}
669 	else
670 	{
671 		graph = (zbx_lld_graph_t *)zbx_malloc(NULL, sizeof(zbx_lld_graph_t));
672 
673 		graph->graphid = 0;
674 		graph->lastcheck = 0;
675 		graph->ts_delete = 0;
676 
677 		graph->name = zbx_strdup(NULL, name_proto);
678 		graph->name_orig = NULL;
679 		substitute_lld_macros(&graph->name, jp_row, lld_macro_paths, ZBX_MACRO_SIMPLE, NULL, 0);
680 		zbx_lrtrim(graph->name, ZBX_WHITESPACE);
681 
682 		lld_override_graph(&lld_row->overrides, graph->name, &discover_proto);
683 
684 		if (ZBX_PROTOTYPE_NO_DISCOVER == discover_proto)
685 		{
686 			zbx_free(graph->name);
687 			zbx_free(graph);
688 			goto out;
689 		}
690 
691 		graph->ymin_itemid = ymin_itemid;
692 		graph->ymax_itemid = ymax_itemid;
693 
694 		zbx_vector_ptr_create(&graph->gitems);
695 
696 		graph->flags = ZBX_FLAG_LLD_GRAPH_UNSET;
697 
698 		zbx_vector_ptr_append(graphs, graph);
699 	}
700 
701 	if (SUCCEED != lld_gitems_make(gitems_proto, &graph->gitems, items, &lld_row->item_links))
702 		return;
703 
704 	graph->flags |= ZBX_FLAG_LLD_GRAPH_DISCOVERED;
705 out:
706 	zbx_free(buffer);
707 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
708 }
709 
lld_graphs_make(const zbx_vector_ptr_t * gitems_proto,zbx_vector_ptr_t * graphs,zbx_vector_ptr_t * items,const char * name_proto,zbx_uint64_t ymin_itemid_proto,zbx_uint64_t ymax_itemid_proto,unsigned char discover_proto,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths)710 static void	lld_graphs_make(const zbx_vector_ptr_t *gitems_proto, zbx_vector_ptr_t *graphs, zbx_vector_ptr_t *items,
711 		const char *name_proto, zbx_uint64_t ymin_itemid_proto, zbx_uint64_t ymax_itemid_proto,
712 		unsigned char discover_proto, const zbx_vector_ptr_t *lld_rows, const zbx_vector_ptr_t *lld_macro_paths)
713 {
714 	int	i;
715 
716 	for (i = 0; i < lld_rows->values_num; i++)
717 	{
718 		zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[i];
719 
720 		lld_graph_make(gitems_proto, graphs, items, name_proto, ymin_itemid_proto, ymax_itemid_proto,
721 				discover_proto, lld_row, lld_macro_paths);
722 	}
723 
724 	zbx_vector_ptr_sort(graphs, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
725 }
726 
727 /******************************************************************************
728  *                                                                            *
729  * Function: lld_validate_graph_field                                         *
730  *                                                                            *
731  ******************************************************************************/
lld_validate_graph_field(zbx_lld_graph_t * graph,char ** field,char ** field_orig,zbx_uint64_t flag,size_t field_len,char ** error)732 static void	lld_validate_graph_field(zbx_lld_graph_t *graph, char **field, char **field_orig, zbx_uint64_t flag,
733 		size_t field_len, char **error)
734 {
735 	if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
736 		return;
737 
738 	/* only new graphs or graphs with changed data will be validated */
739 	if (0 != graph->graphid && 0 == (graph->flags & flag))
740 		return;
741 
742 	if (SUCCEED != zbx_is_utf8(*field))
743 	{
744 		zbx_replace_invalid_utf8(*field);
745 		*error = zbx_strdcatf(*error, "Cannot %s graph: value \"%s\" has invalid UTF-8 sequence.\n",
746 				(0 != graph->graphid ? "update" : "create"), *field);
747 	}
748 	else if (zbx_strlen_utf8(*field) > field_len)
749 	{
750 		*error = zbx_strdcatf(*error, "Cannot %s graph: value \"%s\" is too long.\n",
751 				(0 != graph->graphid ? "update" : "create"), *field);
752 	}
753 	else if (ZBX_FLAG_LLD_GRAPH_UPDATE_NAME == flag && '\0' == **field)
754 	{
755 		*error = zbx_strdcatf(*error, "Cannot %s graph: name is empty.\n",
756 				(0 != graph->graphid ? "update" : "create"));
757 	}
758 	else
759 		return;
760 
761 	if (0 != graph->graphid)
762 		lld_field_str_rollback(field, field_orig, &graph->flags, flag);
763 	else
764 		graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
765 }
766 
767 /******************************************************************************
768  *                                                                            *
769  * Function: lld_graphs_validate                                              *
770  *                                                                            *
771  * Parameters: graphs - [IN] sorted list of graphs                            *
772  *                                                                            *
773  ******************************************************************************/
lld_graphs_validate(zbx_uint64_t hostid,zbx_vector_ptr_t * graphs,char ** error)774 static void	lld_graphs_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *graphs, char **error)
775 {
776 	int			i, j;
777 	zbx_lld_graph_t		*graph, *graph_b;
778 	zbx_vector_uint64_t	graphids;
779 	zbx_vector_str_t	names;
780 
781 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
782 
783 	zbx_vector_uint64_create(&graphids);
784 	zbx_vector_str_create(&names);		/* list of graph names */
785 
786 	/* checking a validity of the fields */
787 
788 	for (i = 0; i < graphs->values_num; i++)
789 	{
790 		graph = (zbx_lld_graph_t *)graphs->values[i];
791 
792 		lld_validate_graph_field(graph, &graph->name, &graph->name_orig,
793 				ZBX_FLAG_LLD_GRAPH_UPDATE_NAME, GRAPH_NAME_LEN, error);
794 	}
795 
796 	/* checking duplicated graph names */
797 	for (i = 0; i < graphs->values_num; i++)
798 	{
799 		graph = (zbx_lld_graph_t *)graphs->values[i];
800 
801 		if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
802 			continue;
803 
804 		/* only new graphs or graphs with changed name will be validated */
805 		if (0 != graph->graphid && 0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
806 			continue;
807 
808 		for (j = 0; j < graphs->values_num; j++)
809 		{
810 			graph_b = (zbx_lld_graph_t *)graphs->values[j];
811 
812 			if (0 == (graph_b->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED) || i == j)
813 				continue;
814 
815 			if (0 != strcmp(graph->name, graph_b->name))
816 				continue;
817 
818 			*error = zbx_strdcatf(*error, "Cannot %s graph:"
819 						" graph with the same name \"%s\" already exists.\n",
820 						(0 != graph->graphid ? "update" : "create"), graph->name);
821 
822 			if (0 != graph->graphid)
823 			{
824 				lld_field_str_rollback(&graph->name, &graph->name_orig, &graph->flags,
825 						ZBX_FLAG_LLD_GRAPH_UPDATE_NAME);
826 			}
827 			else
828 				graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
829 
830 			break;
831 		}
832 	}
833 
834 	/* checking duplicated graphs in DB */
835 
836 	for (i = 0; i < graphs->values_num; i++)
837 	{
838 		graph = (zbx_lld_graph_t *)graphs->values[i];
839 
840 		if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
841 			continue;
842 
843 		if (0 != graph->graphid)
844 		{
845 			zbx_vector_uint64_append(&graphids, graph->graphid);
846 
847 			if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
848 				continue;
849 		}
850 
851 		zbx_vector_str_append(&names, graph->name);
852 	}
853 
854 	if (0 != names.values_num)
855 	{
856 		DB_RESULT	result;
857 		DB_ROW		row;
858 		char		*sql = NULL;
859 		size_t		sql_alloc = 256, sql_offset = 0;
860 
861 		sql = (char *)zbx_malloc(sql, sql_alloc);
862 
863 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
864 				"select g.name"
865 				" from graphs g,graphs_items gi,items i"
866 				" where g.graphid=gi.graphid"
867 					" and gi.itemid=i.itemid"
868 					" and i.hostid=" ZBX_FS_UI64
869 					" and",
870 				hostid);
871 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.name",
872 				(const char **)names.values, names.values_num);
873 
874 		if (0 != graphids.values_num)
875 		{
876 			zbx_vector_uint64_sort(&graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
877 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
878 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.graphid",
879 					graphids.values, graphids.values_num);
880 		}
881 
882 		result = DBselect("%s", sql);
883 
884 		while (NULL != (row = DBfetch(result)))
885 		{
886 			for (i = 0; i < graphs->values_num; i++)
887 			{
888 				graph = (zbx_lld_graph_t *)graphs->values[i];
889 
890 				if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
891 					continue;
892 
893 				if (0 == strcmp(graph->name, row[0]))
894 				{
895 					*error = zbx_strdcatf(*error, "Cannot %s graph:"
896 							" graph with the same name \"%s\" already exists.\n",
897 							(0 != graph->graphid ? "update" : "create"), graph->name);
898 
899 					if (0 != graph->graphid)
900 					{
901 						lld_field_str_rollback(&graph->name, &graph->name_orig, &graph->flags,
902 								ZBX_FLAG_LLD_GRAPH_UPDATE_NAME);
903 					}
904 					else
905 						graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
906 
907 					continue;
908 				}
909 			}
910 		}
911 		DBfree_result(result);
912 
913 		zbx_free(sql);
914 	}
915 
916 	zbx_vector_str_destroy(&names);
917 	zbx_vector_uint64_destroy(&graphids);
918 
919 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
920 }
921 
922 /******************************************************************************
923  *                                                                            *
924  * Function: lld_graphs_save                                                  *
925  *                                                                            *
926  * Purpose: add or update graphs in database based on discovery rule          *
927  *                                                                            *
928  * Return value: SUCCEED - if graphs were successfully saved or saving        *
929  *                         was not necessary                                  *
930  *               FAIL    - graphs cannot be saved                             *
931  *                                                                            *
932  ******************************************************************************/
lld_graphs_save(zbx_uint64_t hostid,zbx_uint64_t parent_graphid,zbx_vector_ptr_t * graphs,int width,int height,double yaxismin,double yaxismax,unsigned char show_work_period,unsigned char show_triggers,unsigned char graphtype,unsigned char show_legend,unsigned char show_3d,double percent_left,double percent_right,unsigned char ymin_type,unsigned char ymax_type)933 static int	lld_graphs_save(zbx_uint64_t hostid, zbx_uint64_t parent_graphid, zbx_vector_ptr_t *graphs, int width,
934 		int height, double yaxismin, double yaxismax, unsigned char show_work_period,
935 		unsigned char show_triggers, unsigned char graphtype, unsigned char show_legend, unsigned char show_3d,
936 		double percent_left, double percent_right, unsigned char ymin_type, unsigned char ymax_type)
937 {
938 	int			ret = SUCCEED, i, j, new_graphs = 0, upd_graphs = 0, new_gitems = 0;
939 	zbx_lld_graph_t		*graph;
940 	zbx_lld_gitem_t		*gitem;
941 	zbx_vector_ptr_t	upd_gitems; 	/* the ordered list of graphs_items which will be updated */
942 	zbx_vector_uint64_t	del_gitemids;
943 
944 	zbx_uint64_t		graphid = 0, gitemid = 0;
945 	char			*sql = NULL, *name_esc, *color_esc;
946 	size_t			sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
947 	zbx_db_insert_t		db_insert, db_insert_gdiscovery, db_insert_gitems;
948 
949 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
950 
951 	zbx_vector_ptr_create(&upd_gitems);
952 	zbx_vector_uint64_create(&del_gitemids);
953 
954 	for (i = 0; i < graphs->values_num; i++)
955 	{
956 		graph = (zbx_lld_graph_t *)graphs->values[i];
957 
958 		if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
959 			continue;
960 
961 		if (0 == graph->graphid)
962 			new_graphs++;
963 		else if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE))
964 			upd_graphs++;
965 
966 		for (j = 0; j < graph->gitems.values_num; j++)
967 		{
968 			gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
969 
970 			if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_DELETE))
971 			{
972 				zbx_vector_uint64_append(&del_gitemids, gitem->gitemid);
973 				continue;
974 			}
975 
976 			if (0 == (gitem->flags & ZBX_FLAG_LLD_GITEM_DISCOVERED))
977 				continue;
978 
979 			if (0 == gitem->gitemid)
980 				new_gitems++;
981 			else if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE))
982 				zbx_vector_ptr_append(&upd_gitems, gitem);
983 		}
984 	}
985 
986 	if (0 == new_graphs && 0 == new_gitems && 0 == upd_graphs && 0 == upd_gitems.values_num &&
987 			0 == del_gitemids.values_num)
988 	{
989 		goto out;
990 	}
991 
992 	DBbegin();
993 
994 	if (SUCCEED != (ret = DBlock_hostid(hostid)) ||
995 			SUCCEED != (ret = DBlock_graphid(parent_graphid)))
996 	{
997 		/* the host or graph prototype was removed while processing lld rule */
998 		DBrollback();
999 		goto out;
1000 	}
1001 
1002 	if (0 != new_graphs)
1003 	{
1004 		graphid = DBget_maxid_num("graphs", new_graphs);
1005 
1006 		zbx_db_insert_prepare(&db_insert, "graphs", "graphid", "name", "width", "height", "yaxismin",
1007 				"yaxismax", "show_work_period", "show_triggers", "graphtype", "show_legend", "show_3d",
1008 				"percent_left", "percent_right", "ymin_type", "ymin_itemid", "ymax_type",
1009 				"ymax_itemid", "flags", NULL);
1010 
1011 		zbx_db_insert_prepare(&db_insert_gdiscovery, "graph_discovery", "graphid", "parent_graphid", NULL);
1012 	}
1013 
1014 	if (0 != new_gitems)
1015 	{
1016 		gitemid = DBget_maxid_num("graphs_items", new_gitems);
1017 
1018 		zbx_db_insert_prepare(&db_insert_gitems, "graphs_items", "gitemid", "graphid", "itemid", "drawtype",
1019 				"sortorder", "color", "yaxisside", "calc_fnc", "type", NULL);
1020 	}
1021 
1022 	if (0 != upd_graphs || 0 != upd_gitems.values_num || 0 != del_gitemids.values_num)
1023 	{
1024 		sql = (char *)zbx_malloc(sql, sql_alloc);
1025 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1026 	}
1027 
1028 	for (i = 0; i < graphs->values_num; i++)
1029 	{
1030 		graph = (zbx_lld_graph_t *)graphs->values[i];
1031 
1032 		if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
1033 			continue;
1034 
1035 		if (0 == graph->graphid)
1036 		{
1037 			zbx_db_insert_add_values(&db_insert, graphid, graph->name, width, height, yaxismin, yaxismax,
1038 					(int)show_work_period, (int)show_triggers, (int)graphtype, (int)show_legend,
1039 					(int)show_3d, percent_left, percent_right, (int)ymin_type, graph->ymin_itemid,
1040 					(int)ymax_type, graph->ymax_itemid, (int)ZBX_FLAG_DISCOVERY_CREATED);
1041 
1042 			zbx_db_insert_add_values(&db_insert_gdiscovery, graphid, parent_graphid);
1043 
1044 			graph->graphid = graphid++;
1045 		}
1046 		else if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE))
1047 		{
1048 			const char	*d = "";
1049 
1050 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update graphs set ");
1051 
1052 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
1053 			{
1054 				name_esc = DBdyn_escape_string(graph->name);
1055 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "name='%s'", name_esc);
1056 				zbx_free(name_esc);
1057 				d = ",";
1058 			}
1059 
1060 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH))
1061 			{
1062 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%swidth=%d", d, width);
1063 				d = ",";
1064 			}
1065 
1066 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT))
1067 			{
1068 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sheight=%d", d, height);
1069 				d = ",";
1070 			}
1071 
1072 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN))
1073 			{
1074 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxismin=" ZBX_FS_DBL64_SQL, d,
1075 						yaxismin);
1076 				d = ",";
1077 			}
1078 
1079 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX))
1080 			{
1081 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxismax=" ZBX_FS_DBL64_SQL, d,
1082 						yaxismax);
1083 				d = ",";
1084 			}
1085 
1086 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD))
1087 			{
1088 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_work_period=%d", d,
1089 						(int)show_work_period);
1090 				d = ",";
1091 			}
1092 
1093 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS))
1094 			{
1095 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_triggers=%d", d,
1096 						(int)show_triggers);
1097 				d = ",";
1098 			}
1099 
1100 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE))
1101 			{
1102 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sgraphtype=%d", d,
1103 						(int)graphtype);
1104 				d = ",";
1105 			}
1106 
1107 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND))
1108 			{
1109 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_legend=%d", d,
1110 						(int)show_legend);
1111 				d = ",";
1112 			}
1113 
1114 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D))
1115 			{
1116 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_3d=%d", d, (int)show_3d);
1117 				d = ",";
1118 			}
1119 
1120 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT))
1121 			{
1122 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spercent_left=" ZBX_FS_DBL64_SQL, d,
1123 						percent_left);
1124 				d = ",";
1125 			}
1126 
1127 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT))
1128 			{
1129 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1130 						"%spercent_right=" ZBX_FS_DBL64_SQL, d, percent_right);
1131 				d = ",";
1132 			}
1133 
1134 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE))
1135 			{
1136 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symin_type=%d", d,
1137 						(int)ymin_type);
1138 				d = ",";
1139 			}
1140 
1141 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID))
1142 			{
1143 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symin_itemid=%s", d,
1144 						DBsql_id_ins(graph->ymin_itemid));
1145 				d = ",";
1146 			}
1147 
1148 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE))
1149 			{
1150 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symax_type=%d", d,
1151 						(int)ymax_type);
1152 				d = ",";
1153 			}
1154 
1155 			if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID))
1156 			{
1157 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symax_itemid=%s", d,
1158 						DBsql_id_ins(graph->ymax_itemid));
1159 			}
1160 
1161 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where graphid=" ZBX_FS_UI64 ";\n",
1162 					graph->graphid);
1163 		}
1164 
1165 		for (j = 0; j < graph->gitems.values_num; j++)
1166 		{
1167 			gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
1168 
1169 			if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_DELETE))
1170 				continue;
1171 
1172 			if (0 == (gitem->flags & ZBX_FLAG_LLD_GITEM_DISCOVERED))
1173 				continue;
1174 
1175 			if (0 == gitem->gitemid)
1176 			{
1177 				zbx_db_insert_add_values(&db_insert_gitems, gitemid, graph->graphid, gitem->itemid,
1178 						(int)gitem->drawtype, gitem->sortorder, gitem->color,
1179 						(int)gitem->yaxisside, (int)gitem->calc_fnc, (int)gitem->type);
1180 
1181 				gitem->gitemid = gitemid++;
1182 			}
1183 		}
1184 	}
1185 
1186 	for (i = 0; i < upd_gitems.values_num; i++)
1187 	{
1188 		const char	*d = "";
1189 
1190 		gitem = (zbx_lld_gitem_t *)upd_gitems.values[i];
1191 
1192 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update graphs_items set ");
1193 
1194 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID))
1195 		{
1196 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64, gitem->itemid);
1197 			d = ",";
1198 		}
1199 
1200 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE))
1201 		{
1202 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sdrawtype=%d", d, (int)gitem->drawtype);
1203 			d = ",";
1204 		}
1205 
1206 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER))
1207 		{
1208 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%ssortorder=%d", d, gitem->sortorder);
1209 			d = ",";
1210 		}
1211 
1212 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_COLOR))
1213 		{
1214 			color_esc = DBdyn_escape_string(gitem->color);
1215 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scolor='%s'", d, color_esc);
1216 			zbx_free(color_esc);
1217 			d = ",";
1218 		}
1219 
1220 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE))
1221 		{
1222 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxisside=%d", d,
1223 					(int)gitem->yaxisside);
1224 			d = ",";
1225 		}
1226 
1227 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC))
1228 		{
1229 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scalc_fnc=%d", d, (int)gitem->calc_fnc);
1230 			d = ",";
1231 		}
1232 
1233 		if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_TYPE))
1234 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d, (int)gitem->type);
1235 
1236 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where gitemid=" ZBX_FS_UI64 ";\n",
1237 				gitem->gitemid);
1238 	}
1239 
1240 	if (0 != del_gitemids.values_num)
1241 	{
1242 		zbx_vector_uint64_sort(&del_gitemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1243 
1244 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from graphs_items where");
1245 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "gitemid",
1246 				del_gitemids.values, del_gitemids.values_num);
1247 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1248 	}
1249 
1250 	if (0 != upd_graphs || 0 != upd_gitems.values_num || 0 != del_gitemids.values_num)
1251 	{
1252 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1253 		DBexecute("%s", sql);
1254 		zbx_free(sql);
1255 	}
1256 
1257 	if (0 != new_graphs)
1258 	{
1259 		zbx_db_insert_execute(&db_insert);
1260 		zbx_db_insert_clean(&db_insert);
1261 
1262 		zbx_db_insert_execute(&db_insert_gdiscovery);
1263 		zbx_db_insert_clean(&db_insert_gdiscovery);
1264 	}
1265 
1266 	if (0 != new_gitems)
1267 	{
1268 		zbx_db_insert_execute(&db_insert_gitems);
1269 		zbx_db_insert_clean(&db_insert_gitems);
1270 	}
1271 
1272 	DBcommit();
1273 out:
1274 	zbx_vector_uint64_destroy(&del_gitemids);
1275 	zbx_vector_ptr_destroy(&upd_gitems);
1276 
1277 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1278 
1279 	return ret;
1280 }
1281 
get_graph_info(const void * object,zbx_uint64_t * id,int * discovery_flag,int * lastcheck,int * ts_delete)1282 static	void	get_graph_info(const void *object, zbx_uint64_t *id, int *discovery_flag, int *lastcheck,
1283 		int *ts_delete)
1284 {
1285 	zbx_lld_graph_t	*graph;
1286 
1287 	graph = (zbx_lld_graph_t *)object;
1288 
1289 	*id = graph->graphid;
1290 	*discovery_flag = graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED;
1291 	*lastcheck = graph->lastcheck;
1292 	*ts_delete = graph->ts_delete;
1293 }
1294 
1295 /******************************************************************************
1296  *                                                                            *
1297  * Function: lld_update_graphs                                                *
1298  *                                                                            *
1299  * Purpose: add or update graphs for discovery item                           *
1300  *                                                                            *
1301  * Parameters: hostid  - [IN] host identificator from database                *
1302  *             agent   - [IN] discovery item identificator from database      *
1303  *             jp_data - [IN] received data                                   *
1304  *                                                                            *
1305  * Return value: SUCCEED - if graphs were successfully added/updated or       *
1306  *                         adding/updating was not necessary                  *
1307  *               FAIL    - graphs cannot be added/updated                     *
1308  *                                                                            *
1309  * Author: Alexander Vladishev                                                *
1310  *                                                                            *
1311  ******************************************************************************/
lld_update_graphs(zbx_uint64_t hostid,zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths,char ** error,int lifetime,int lastcheck)1312 int	lld_update_graphs(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows,
1313 		const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck)
1314 {
1315 	int			ret = SUCCEED;
1316 	DB_RESULT		result;
1317 	DB_ROW			row;
1318 	zbx_vector_ptr_t	graphs;
1319 	zbx_vector_ptr_t	gitems_proto;
1320 	zbx_vector_ptr_t	items;
1321 
1322 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1323 
1324 	zbx_vector_ptr_create(&graphs);		/* list of graphs which were created or will be created or */
1325 						/* updated by the graph prototype */
1326 	zbx_vector_ptr_create(&gitems_proto);	/* list of graphs_items which are used by the graph prototype */
1327 	zbx_vector_ptr_create(&items);		/* list of items which are related to the graph prototype */
1328 
1329 	result = DBselect(
1330 			"select distinct g.graphid,g.name,g.width,g.height,g.yaxismin,g.yaxismax,g.show_work_period,"
1331 				"g.show_triggers,g.graphtype,g.show_legend,g.show_3d,g.percent_left,g.percent_right,"
1332 				"g.ymin_type,g.ymin_itemid,g.ymax_type,g.ymax_itemid,g.discover"
1333 			" from graphs g,graphs_items gi,items i,item_discovery id"
1334 			" where g.graphid=gi.graphid"
1335 				" and gi.itemid=i.itemid"
1336 				" and i.itemid=id.itemid"
1337 				" and id.parent_itemid=" ZBX_FS_UI64,
1338 			lld_ruleid);
1339 
1340 	while (SUCCEED == ret && NULL != (row = DBfetch(result)))
1341 	{
1342 		zbx_uint64_t	parent_graphid, ymin_itemid_proto, ymax_itemid_proto;
1343 		const char	*name_proto;
1344 		int		width, height;
1345 		double		yaxismin, yaxismax, percent_left, percent_right;
1346 		unsigned char	show_work_period, show_triggers, graphtype, show_legend, show_3d,
1347 				ymin_type, ymax_type, discover_proto;
1348 
1349 		ZBX_STR2UINT64(parent_graphid, row[0]);
1350 		name_proto = row[1];
1351 		width = atoi(row[2]);
1352 		height = atoi(row[3]);
1353 		yaxismin = atof(row[4]);
1354 		yaxismax = atof(row[5]);
1355 		ZBX_STR2UCHAR(show_work_period, row[6]);
1356 		ZBX_STR2UCHAR(show_triggers, row[7]);
1357 		ZBX_STR2UCHAR(graphtype, row[8]);
1358 		ZBX_STR2UCHAR(show_legend, row[9]);
1359 		ZBX_STR2UCHAR(show_3d, row[10]);
1360 		percent_left = atof(row[11]);
1361 		percent_right = atof(row[12]);
1362 		ZBX_STR2UCHAR(ymin_type, row[13]);
1363 		ZBX_DBROW2UINT64(ymin_itemid_proto, row[14]);
1364 		ZBX_STR2UCHAR(ymax_type, row[15]);
1365 		ZBX_DBROW2UINT64(ymax_itemid_proto, row[16]);
1366 		ZBX_STR2UCHAR(discover_proto, row[17]);
1367 
1368 		lld_graphs_get(parent_graphid, &graphs, width, height, yaxismin, yaxismax, show_work_period,
1369 				show_triggers, graphtype, show_legend, show_3d, percent_left, percent_right,
1370 				ymin_type, ymax_type);
1371 		lld_gitems_get(parent_graphid, &gitems_proto, &graphs);
1372 		lld_items_get(&gitems_proto, ymin_itemid_proto, ymax_itemid_proto, &items);
1373 
1374 		/* making graphs */
1375 
1376 		lld_graphs_make(&gitems_proto, &graphs, &items, name_proto, ymin_itemid_proto, ymax_itemid_proto,
1377 				discover_proto, lld_rows, lld_macro_paths);
1378 		lld_graphs_validate(hostid, &graphs, error);
1379 		ret = lld_graphs_save(hostid, parent_graphid, &graphs, width, height, yaxismin, yaxismax,
1380 				show_work_period, show_triggers, graphtype, show_legend, show_3d, percent_left,
1381 				percent_right, ymin_type, ymax_type);
1382 
1383 		lld_remove_lost_objects("graph_discovery", "graphid", &graphs, lifetime, lastcheck, DBdelete_graphs,
1384 				get_graph_info);
1385 
1386 		lld_items_free(&items);
1387 		lld_gitems_free(&gitems_proto);
1388 		lld_graphs_free(&graphs);
1389 	}
1390 	DBfree_result(result);
1391 
1392 	zbx_vector_ptr_destroy(&items);
1393 	zbx_vector_ptr_destroy(&gitems_proto);
1394 	zbx_vector_ptr_destroy(&graphs);
1395 
1396 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1397 
1398 	return ret;
1399 }
1400