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