Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/zabbix_server/lld/lld_graph.c')
-rw-r--r--src/zabbix_server/lld/lld_graph.c1377
1 files changed, 1377 insertions, 0 deletions
diff --git a/src/zabbix_server/lld/lld_graph.c b/src/zabbix_server/lld/lld_graph.c
new file mode 100644
index 00000000000..a6a6aaea608
--- /dev/null
+++ b/src/zabbix_server/lld/lld_graph.c
@@ -0,0 +1,1377 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "lld.h"
+#include "db.h"
+#include "log.h"
+#include "zbxalgo.h"
+#include "zbxserver.h"
+
+typedef struct
+{
+ zbx_uint64_t graphid;
+ char *name;
+ char *name_orig;
+ zbx_uint64_t ymin_itemid;
+ zbx_uint64_t ymax_itemid;
+ zbx_vector_ptr_t gitems;
+#define ZBX_FLAG_LLD_GRAPH_UNSET __UINT64_C(0x00000000)
+#define ZBX_FLAG_LLD_GRAPH_DISCOVERED __UINT64_C(0x00000001)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_NAME __UINT64_C(0x00000002)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH __UINT64_C(0x00000004)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT __UINT64_C(0x00000008)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN __UINT64_C(0x00000010)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX __UINT64_C(0x00000020)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD __UINT64_C(0x00000040)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS __UINT64_C(0x00000080)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE __UINT64_C(0x00000100)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND __UINT64_C(0x00000200)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D __UINT64_C(0x00000400)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT __UINT64_C(0x00000800)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT __UINT64_C(0x00001000)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE __UINT64_C(0x00002000)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID __UINT64_C(0x00004000)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE __UINT64_C(0x00008000)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID __UINT64_C(0x00010000)
+#define ZBX_FLAG_LLD_GRAPH_UPDATE \
+ (ZBX_FLAG_LLD_GRAPH_UPDATE_NAME | ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT | ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX | ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS | ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND | ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT | ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE | ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID | \
+ ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE | ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID)
+ zbx_uint64_t flags;
+}
+zbx_lld_graph_t;
+
+typedef struct
+{
+ zbx_uint64_t gitemid;
+ zbx_uint64_t itemid;
+ char *color;
+ int sortorder;
+ unsigned char drawtype;
+ unsigned char yaxisside;
+ unsigned char calc_fnc;
+ unsigned char type;
+#define ZBX_FLAG_LLD_GITEM_UNSET __UINT64_C(0x0000)
+#define ZBX_FLAG_LLD_GITEM_DISCOVERED __UINT64_C(0x0001)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID __UINT64_C(0x0002)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE __UINT64_C(0x0004)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER __UINT64_C(0x0008)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_COLOR __UINT64_C(0x0010)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE __UINT64_C(0x0020)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC __UINT64_C(0x0040)
+#define ZBX_FLAG_LLD_GITEM_UPDATE_TYPE __UINT64_C(0x0080)
+#define ZBX_FLAG_LLD_GITEM_UPDATE \
+ (ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID | ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE | \
+ ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER | ZBX_FLAG_LLD_GITEM_UPDATE_COLOR | \
+ ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE | ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC | \
+ ZBX_FLAG_LLD_GITEM_UPDATE_TYPE)
+#define ZBX_FLAG_LLD_GITEM_DELETE __UINT64_C(0x0100)
+ zbx_uint64_t flags;
+}
+zbx_lld_gitem_t;
+
+typedef struct
+{
+ zbx_uint64_t itemid;
+ unsigned char flags;
+}
+zbx_lld_item_t;
+
+static void lld_item_free(zbx_lld_item_t *item)
+{
+ zbx_free(item);
+}
+
+static void lld_items_free(zbx_vector_ptr_t *items)
+{
+ while (0 != items->values_num)
+ lld_item_free((zbx_lld_item_t *)items->values[--items->values_num]);
+}
+
+static void lld_gitem_free(zbx_lld_gitem_t *gitem)
+{
+ zbx_free(gitem->color);
+ zbx_free(gitem);
+}
+
+static void lld_gitems_free(zbx_vector_ptr_t *gitems)
+{
+ while (0 != gitems->values_num)
+ lld_gitem_free((zbx_lld_gitem_t *)gitems->values[--gitems->values_num]);
+}
+
+static void lld_graph_free(zbx_lld_graph_t *graph)
+{
+ lld_gitems_free(&graph->gitems);
+ zbx_vector_ptr_destroy(&graph->gitems);
+ zbx_free(graph->name_orig);
+ zbx_free(graph->name);
+ zbx_free(graph);
+}
+
+static void lld_graphs_free(zbx_vector_ptr_t *graphs)
+{
+ while (0 != graphs->values_num)
+ lld_graph_free((zbx_lld_graph_t *)graphs->values[--graphs->values_num]);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graphs_get *
+ * *
+ * Purpose: retrieve graphs which were created by the specified graph *
+ * prototype *
+ * *
+ * Parameters: parent_graphid - [IN] graph prototype identificator *
+ * graphs - [OUT] sorted list of graphs *
+ * *
+ ******************************************************************************/
+static void 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)
+{
+ const char *__function_name = "lld_graphs_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_graph_t *graph;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select g.graphid,g.name,g.width,g.height,g.yaxismin,g.yaxismax,g.show_work_period,"
+ "g.show_triggers,g.graphtype,g.show_legend,g.show_3d,g.percent_left,g.percent_right,"
+ "g.ymin_type,g.ymin_itemid,g.ymax_type,g.ymax_itemid"
+ " from graphs g,graph_discovery gd"
+ " where g.graphid=gd.graphid"
+ " and gd.parent_graphid=" ZBX_FS_UI64,
+ parent_graphid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ graph = (zbx_lld_graph_t *)zbx_malloc(NULL, sizeof(zbx_lld_graph_t));
+
+ ZBX_STR2UINT64(graph->graphid, row[0]);
+ graph->name = zbx_strdup(NULL, row[1]);
+ graph->name_orig = NULL;
+
+ graph->flags = ZBX_FLAG_LLD_GRAPH_UNSET;
+
+ if (atoi(row[2]) != width)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH;
+
+ if (atoi(row[3]) != height)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT;
+
+ if (atof(row[4]) != yaxismin)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN;
+
+ if (atof(row[5]) != yaxismax)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX;
+
+ if ((unsigned char)atoi(row[6]) != show_work_period)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD;
+
+ if ((unsigned char)atoi(row[7]) != show_triggers)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS;
+
+ if ((unsigned char)atoi(row[8]) != graphtype)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE;
+
+ if ((unsigned char)atoi(row[9]) != show_legend)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND;
+
+ if ((unsigned char)atoi(row[10]) != show_3d)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D;
+
+ if (atof(row[11]) != percent_left)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT;
+
+ if (atof(row[12]) != percent_right)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT;
+
+ if ((unsigned char)atoi(row[13]) != ymin_type)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE;
+
+ ZBX_DBROW2UINT64(graph->ymin_itemid, row[14]);
+
+ if ((unsigned char)atoi(row[15]) != ymax_type)
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE;
+
+ ZBX_DBROW2UINT64(graph->ymax_itemid, row[16]);
+
+ zbx_vector_ptr_create(&graph->gitems);
+
+ zbx_vector_ptr_append(graphs, graph);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(graphs, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_gitems_get *
+ * *
+ * Purpose: retrieve graphs_items which are used by the graph prototype and *
+ * by selected graphs *
+ * *
+ ******************************************************************************/
+static void lld_gitems_get(zbx_uint64_t parent_graphid, zbx_vector_ptr_t *gitems_proto,
+ zbx_vector_ptr_t *graphs)
+{
+ const char *__function_name = "lld_gitems_get";
+
+ int i, index;
+ zbx_lld_graph_t *graph;
+ zbx_lld_gitem_t *gitem;
+ zbx_uint64_t graphid;
+ zbx_vector_uint64_t graphids;
+ DB_RESULT result;
+ DB_ROW row;
+ char *sql = NULL;
+ size_t sql_alloc = 256, sql_offset = 0;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&graphids);
+ zbx_vector_uint64_append(&graphids, parent_graphid);
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ zbx_vector_uint64_append(&graphids, graph->graphid);
+ }
+
+ zbx_vector_uint64_sort(&graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ sql = (char *)zbx_malloc(sql, sql_alloc);
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select gitemid,graphid,itemid,drawtype,sortorder,color,yaxisside,calc_fnc,type"
+ " from graphs_items"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid",
+ graphids.values, graphids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ gitem = (zbx_lld_gitem_t *)zbx_malloc(NULL, sizeof(zbx_lld_gitem_t));
+
+ ZBX_STR2UINT64(gitem->gitemid, row[0]);
+ ZBX_STR2UINT64(graphid, row[1]);
+ ZBX_STR2UINT64(gitem->itemid, row[2]);
+ ZBX_STR2UCHAR(gitem->drawtype, row[3]);
+ gitem->sortorder = atoi(row[4]);
+ gitem->color = zbx_strdup(NULL, row[5]);
+ ZBX_STR2UCHAR(gitem->yaxisside, row[6]);
+ ZBX_STR2UCHAR(gitem->calc_fnc, row[7]);
+ ZBX_STR2UCHAR(gitem->type, row[8]);
+
+ gitem->flags = ZBX_FLAG_LLD_GITEM_UNSET;
+
+ if (graphid == parent_graphid)
+ {
+ zbx_vector_ptr_append(gitems_proto, gitem);
+ }
+ else if (FAIL != (index = zbx_vector_ptr_bsearch(graphs, &graphid,
+ ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[index];
+
+ zbx_vector_ptr_append(&graph->gitems, gitem);
+ }
+ else
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ lld_gitem_free(gitem);
+ }
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(gitems_proto, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ zbx_vector_ptr_sort(&graph->gitems, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+ }
+
+ zbx_vector_uint64_destroy(&graphids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_items_get *
+ * *
+ * Purpose: returns the list of items which are related to the graph *
+ * prototype *
+ * *
+ * Parameters: gitems_proto - [IN] graph prototype's graphs_items *
+ * ymin_itemid_proto - [IN] graph prototype's ymin_itemid *
+ * ymax_itemid_proto - [IN] graph prototype's ymax_itemid *
+ * items - [OUT] sorted list of items *
+ * *
+ ******************************************************************************/
+static void 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)
+{
+ const char *__function_name = "lld_items_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ const zbx_lld_gitem_t *gitem;
+ zbx_lld_item_t *item;
+ zbx_vector_uint64_t itemids;
+ int i;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&itemids);
+
+ for (i = 0; i < gitems_proto->values_num; i++)
+ {
+ gitem = (zbx_lld_gitem_t *)gitems_proto->values[i];
+
+ zbx_vector_uint64_append(&itemids, gitem->itemid);
+ }
+
+ if (0 != ymin_itemid_proto)
+ zbx_vector_uint64_append(&itemids, ymin_itemid_proto);
+
+ if (0 != ymax_itemid_proto)
+ zbx_vector_uint64_append(&itemids, ymax_itemid_proto);
+
+ if (0 != itemids.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 256, sql_offset = 0;
+
+ zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ sql = (char *)zbx_malloc(sql, sql_alloc);
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select itemid,flags"
+ " from items"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids.values, itemids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ item = (zbx_lld_item_t *)zbx_malloc(NULL, sizeof(zbx_lld_item_t));
+
+ ZBX_STR2UINT64(item->itemid, row[0]);
+ ZBX_STR2UCHAR(item->flags, row[1]);
+
+ zbx_vector_ptr_append(items, item);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+ }
+
+ zbx_vector_uint64_destroy(&itemids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graph_by_item *
+ * *
+ * Purpose: finds already existing graph, using an item *
+ * *
+ * Return value: upon successful completion return pointer to the graph *
+ * *
+ ******************************************************************************/
+static zbx_lld_graph_t *lld_graph_by_item(zbx_vector_ptr_t *graphs, zbx_uint64_t itemid)
+{
+ int i, j;
+ zbx_lld_graph_t *graph;
+ zbx_lld_gitem_t *gitem;
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ for (j = 0; j < graph->gitems.values_num; j++)
+ {
+ gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
+
+ if (gitem->itemid == itemid)
+ return graph;
+ }
+ }
+
+ return NULL;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graph_get *
+ * *
+ * Purpose: finds already existing graph, using an item prototype and items *
+ * already created by it *
+ * *
+ * Return value: upon successful completion return pointer to the graph *
+ * *
+ ******************************************************************************/
+static zbx_lld_graph_t *lld_graph_get(zbx_vector_ptr_t *graphs, const zbx_vector_ptr_t *item_links)
+{
+ int i;
+ zbx_lld_graph_t *graph;
+
+ for (i = 0; i < item_links->values_num; i++)
+ {
+ const zbx_lld_item_link_t *item_link = (zbx_lld_item_link_t *)item_links->values[i];
+
+ if (NULL != (graph = lld_graph_by_item(graphs, item_link->itemid)))
+ return graph;
+ }
+
+ return NULL;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_item_get *
+ * *
+ * Purpose: finds already created item when itemid_proto is an item prototype *
+ * or return itemid_proto as itemid if it's a normal item *
+ * *
+ * Return value: SUCCEED if item successfully processed, FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int 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)
+{
+ int index;
+ zbx_lld_item_t *item_proto;
+ zbx_lld_item_link_t *item_link;
+
+ if (FAIL == (index = zbx_vector_ptr_bsearch(items, &itemid_proto, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ return FAIL;
+
+ item_proto = (zbx_lld_item_t *)items->values[index];
+
+ if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
+ {
+ index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ if (FAIL == index)
+ return FAIL;
+
+ item_link = (zbx_lld_item_link_t *)item_links->values[index];
+
+ *itemid = item_link->itemid;
+ }
+ else
+ *itemid = item_proto->itemid;
+
+ return SUCCEED;
+}
+
+static int 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)
+{
+ const char *__function_name = "lld_gitems_make";
+
+ int i, ret = FAIL;
+ const zbx_lld_gitem_t *gitem_proto;
+ zbx_lld_gitem_t *gitem;
+ zbx_uint64_t itemid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < gitems_proto->values_num; i++)
+ {
+ gitem_proto = (zbx_lld_gitem_t *)gitems_proto->values[i];
+
+ if (SUCCEED != lld_item_get(gitem_proto->itemid, items, item_links, &itemid))
+ goto out;
+
+ if (i == gitems->values_num)
+ {
+ gitem = (zbx_lld_gitem_t *)zbx_malloc(NULL, sizeof(zbx_lld_gitem_t));
+
+ gitem->gitemid = 0;
+ gitem->itemid = itemid;
+ gitem->drawtype = gitem_proto->drawtype;
+ gitem->sortorder = gitem_proto->sortorder;
+ gitem->color = zbx_strdup(NULL, gitem_proto->color);
+ gitem->yaxisside = gitem_proto->yaxisside;
+ gitem->calc_fnc = gitem_proto->calc_fnc;
+ gitem->type = gitem_proto->type;
+
+ gitem->flags = ZBX_FLAG_LLD_GITEM_DISCOVERED;
+
+ zbx_vector_ptr_append(gitems, gitem);
+ }
+ else
+ {
+ gitem = (zbx_lld_gitem_t *)gitems->values[i];
+
+ if (gitem->itemid != itemid)
+ {
+ gitem->itemid = itemid;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID;
+ }
+
+ if (gitem->drawtype != gitem_proto->drawtype)
+ {
+ gitem->drawtype = gitem_proto->drawtype;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE;
+ }
+
+ if (gitem->sortorder != gitem_proto->sortorder)
+ {
+ gitem->sortorder = gitem_proto->sortorder;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER;
+ }
+
+ if (0 != strcmp(gitem->color, gitem_proto->color))
+ {
+ gitem->color = zbx_strdup(gitem->color, gitem_proto->color);
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_COLOR;
+ }
+
+ if (gitem->yaxisside != gitem_proto->yaxisside)
+ {
+ gitem->yaxisside = gitem_proto->yaxisside;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE;
+ }
+
+ if (gitem->calc_fnc != gitem_proto->calc_fnc)
+ {
+ gitem->calc_fnc = gitem_proto->calc_fnc;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC;
+ }
+
+ if (gitem->type != gitem_proto->type)
+ {
+ gitem->type = gitem_proto->type;
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_UPDATE_TYPE;
+ }
+
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_DISCOVERED;
+ }
+ }
+
+ for (; i < gitems->values_num; i++)
+ {
+ gitem = (zbx_lld_gitem_t *)gitems->values[i];
+
+ gitem->flags |= ZBX_FLAG_LLD_GITEM_DELETE;
+ }
+
+ ret = SUCCEED;
+out:
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graph_make *
+ * *
+ * Purpose: create a graph based on lld rule and add it to the list *
+ * *
+ ******************************************************************************/
+static void 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, const zbx_vector_ptr_t *lld_macro_paths)
+{
+ const char *__function_name = "lld_graph_make";
+
+ zbx_lld_graph_t *graph = NULL;
+ char *buffer = NULL;
+ const struct zbx_json_parse *jp_row = &lld_row->jp_row;
+ zbx_uint64_t ymin_itemid, ymax_itemid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ if (0 == ymin_itemid_proto)
+ ymin_itemid = 0;
+ else if (SUCCEED != lld_item_get(ymin_itemid_proto, items, &lld_row->item_links, &ymin_itemid))
+ goto out;
+
+ if (0 == ymax_itemid_proto)
+ ymax_itemid = 0;
+ else if (SUCCEED != lld_item_get(ymax_itemid_proto, items, &lld_row->item_links, &ymax_itemid))
+ goto out;
+
+ if (NULL != (graph = lld_graph_get(graphs, &lld_row->item_links)))
+ {
+ buffer = zbx_strdup(buffer, name_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macro_paths, ZBX_MACRO_SIMPLE, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+ if (0 != strcmp(graph->name, buffer))
+ {
+ graph->name_orig = graph->name;
+ graph->name = buffer;
+ buffer = NULL;
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_NAME;
+ }
+
+ if (graph->ymin_itemid != ymin_itemid)
+ {
+ graph->ymin_itemid = ymin_itemid;
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID;
+ }
+
+ if (graph->ymax_itemid != ymax_itemid)
+ {
+ graph->ymax_itemid = ymax_itemid;
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID;
+ }
+ }
+ else
+ {
+ graph = (zbx_lld_graph_t *)zbx_malloc(NULL, sizeof(zbx_lld_graph_t));
+
+ graph->graphid = 0;
+
+ graph->name = zbx_strdup(NULL, name_proto);
+ graph->name_orig = NULL;
+ substitute_lld_macros(&graph->name, jp_row, lld_macro_paths, ZBX_MACRO_SIMPLE, NULL, 0);
+ zbx_lrtrim(graph->name, ZBX_WHITESPACE);
+
+ graph->ymin_itemid = ymin_itemid;
+ graph->ymax_itemid = ymax_itemid;
+
+ zbx_vector_ptr_create(&graph->gitems);
+
+ graph->flags = ZBX_FLAG_LLD_GRAPH_UNSET;
+
+ zbx_vector_ptr_append(graphs, graph);
+ }
+
+ zbx_free(buffer);
+
+ if (SUCCEED != lld_gitems_make(gitems_proto, &graph->gitems, items, &lld_row->item_links))
+ return;
+
+ graph->flags |= ZBX_FLAG_LLD_GRAPH_DISCOVERED;
+out:
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+static void 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, const zbx_vector_ptr_t *lld_macro_paths)
+{
+ int i;
+
+ for (i = 0; i < lld_rows->values_num; i++)
+ {
+ zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[i];
+
+ lld_graph_make(gitems_proto, graphs, items, name_proto, ymin_itemid_proto, ymax_itemid_proto, lld_row,
+ lld_macro_paths);
+ }
+
+ zbx_vector_ptr_sort(graphs, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_validate_graph_field *
+ * *
+ ******************************************************************************/
+static void lld_validate_graph_field(zbx_lld_graph_t *graph, char **field, char **field_orig, zbx_uint64_t flag,
+ size_t field_len, char **error)
+{
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ return;
+
+ /* only new graphs or graphs with changed data will be validated */
+ if (0 != graph->graphid && 0 == (graph->flags & flag))
+ return;
+
+ if (SUCCEED != zbx_is_utf8(*field))
+ {
+ zbx_replace_invalid_utf8(*field);
+ *error = zbx_strdcatf(*error, "Cannot %s graph: value \"%s\" has invalid UTF-8 sequence.\n",
+ (0 != graph->graphid ? "update" : "create"), *field);
+ }
+ else if (zbx_strlen_utf8(*field) > field_len)
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s graph: value \"%s\" is too long.\n",
+ (0 != graph->graphid ? "update" : "create"), *field);
+ }
+ else if (ZBX_FLAG_LLD_GRAPH_UPDATE_NAME == flag && '\0' == **field)
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s graph: name is empty.\n",
+ (0 != graph->graphid ? "update" : "create"));
+ }
+ else
+ return;
+
+ if (0 != graph->graphid)
+ lld_field_str_rollback(field, field_orig, &graph->flags, flag);
+ else
+ graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graphs_validate *
+ * *
+ * Parameters: graphs - [IN] sorted list of graphs *
+ * *
+ ******************************************************************************/
+static void lld_graphs_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *graphs, char **error)
+{
+ const char *__function_name = "lld_graphs_validate";
+
+ int i, j;
+ zbx_lld_graph_t *graph, *graph_b;
+ zbx_vector_uint64_t graphids;
+ zbx_vector_str_t names;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&graphids);
+ zbx_vector_str_create(&names); /* list of graph names */
+
+ /* checking a validity of the fields */
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ lld_validate_graph_field(graph, &graph->name, &graph->name_orig,
+ ZBX_FLAG_LLD_GRAPH_UPDATE_NAME, GRAPH_NAME_LEN, error);
+ }
+
+ /* checking duplicated graph names */
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ /* only new graphs or graphs with changed name will be validated */
+ if (0 != graph->graphid && 0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
+ continue;
+
+ for (j = 0; j < graphs->values_num; j++)
+ {
+ graph_b = (zbx_lld_graph_t *)graphs->values[j];
+
+ if (0 == (graph_b->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED) || i == j)
+ continue;
+
+ if (0 != strcmp(graph->name, graph_b->name))
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot %s graph:"
+ " graph with the same name \"%s\" already exists.\n",
+ (0 != graph->graphid ? "update" : "create"), graph->name);
+
+ if (0 != graph->graphid)
+ {
+ lld_field_str_rollback(&graph->name, &graph->name_orig, &graph->flags,
+ ZBX_FLAG_LLD_GRAPH_UPDATE_NAME);
+ }
+ else
+ graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
+
+ break;
+ }
+ }
+
+ /* checking duplicated graphs in DB */
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ if (0 != graph->graphid)
+ {
+ zbx_vector_uint64_append(&graphids, graph->graphid);
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
+ continue;
+ }
+
+ zbx_vector_str_append(&names, graph->name);
+ }
+
+ if (0 != names.values_num)
+ {
+ DB_RESULT result;
+ DB_ROW row;
+ char *sql = NULL;
+ size_t sql_alloc = 256, sql_offset = 0;
+
+ sql = (char *)zbx_malloc(sql, sql_alloc);
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ "select g.name"
+ " from graphs g,graphs_items gi,items i"
+ " where g.graphid=gi.graphid"
+ " and gi.itemid=i.itemid"
+ " and i.hostid=" ZBX_FS_UI64
+ " and",
+ hostid);
+ DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.name",
+ (const char **)names.values, names.values_num);
+
+ if (0 != graphids.values_num)
+ {
+ zbx_vector_uint64_sort(&graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.graphid",
+ graphids.values, graphids.values_num);
+ }
+
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ if (0 == strcmp(graph->name, row[0]))
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s graph:"
+ " graph with the same name \"%s\" already exists.\n",
+ (0 != graph->graphid ? "update" : "create"), graph->name);
+
+ if (0 != graph->graphid)
+ {
+ lld_field_str_rollback(&graph->name, &graph->name_orig, &graph->flags,
+ ZBX_FLAG_LLD_GRAPH_UPDATE_NAME);
+ }
+ else
+ graph->flags &= ~ZBX_FLAG_LLD_GRAPH_DISCOVERED;
+
+ continue;
+ }
+ }
+ }
+ DBfree_result(result);
+
+ zbx_free(sql);
+ }
+
+ zbx_vector_str_destroy(&names);
+ zbx_vector_uint64_destroy(&graphids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_graphs_save *
+ * *
+ * Purpose: add or update graphs in database based on discovery rule *
+ * *
+ * Return value: SUCCEED - if graphs were successfully saved or saving *
+ * was not necessary *
+ * FAIL - graphs cannot be saved *
+ * *
+ ******************************************************************************/
+static int 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)
+{
+ const char *__function_name = "lld_graphs_save";
+
+ int ret = SUCCEED, i, j, new_graphs = 0, upd_graphs = 0, new_gitems = 0;
+ zbx_lld_graph_t *graph;
+ zbx_lld_gitem_t *gitem;
+ zbx_vector_ptr_t upd_gitems; /* the ordered list of graphs_items which will be updated */
+ zbx_vector_uint64_t del_gitemids;
+
+ zbx_uint64_t graphid = 0, gitemid = 0;
+ char *sql = NULL, *name_esc, *color_esc;
+ size_t sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
+ zbx_db_insert_t db_insert, db_insert_gdiscovery, db_insert_gitems;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_ptr_create(&upd_gitems);
+ zbx_vector_uint64_create(&del_gitemids);
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ if (0 == graph->graphid)
+ new_graphs++;
+ else if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE))
+ upd_graphs++;
+
+ for (j = 0; j < graph->gitems.values_num; j++)
+ {
+ gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_DELETE))
+ {
+ zbx_vector_uint64_append(&del_gitemids, gitem->gitemid);
+ continue;
+ }
+
+ if (0 == (gitem->flags & ZBX_FLAG_LLD_GITEM_DISCOVERED))
+ continue;
+
+ if (0 == gitem->gitemid)
+ new_gitems++;
+ else if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE))
+ zbx_vector_ptr_append(&upd_gitems, gitem);
+ }
+ }
+
+ if (0 == new_graphs && 0 == new_gitems && 0 == upd_graphs && 0 == upd_gitems.values_num &&
+ 0 == del_gitemids.values_num)
+ {
+ goto out;
+ }
+
+ DBbegin();
+
+ if (SUCCEED != (ret = DBlock_hostid(hostid)))
+ {
+ /* the host was removed while processing lld rule */
+ DBrollback();
+ goto out;
+ }
+
+ if (0 != new_graphs)
+ {
+ graphid = DBget_maxid_num("graphs", new_graphs);
+
+ zbx_db_insert_prepare(&db_insert, "graphs", "graphid", "name", "width", "height", "yaxismin",
+ "yaxismax", "show_work_period", "show_triggers", "graphtype", "show_legend", "show_3d",
+ "percent_left", "percent_right", "ymin_type", "ymin_itemid", "ymax_type",
+ "ymax_itemid", "flags", NULL);
+
+ zbx_db_insert_prepare(&db_insert_gdiscovery, "graph_discovery", "graphid", "parent_graphid", NULL);
+ }
+
+ if (0 != new_gitems)
+ {
+ gitemid = DBget_maxid_num("graphs_items", new_gitems);
+
+ zbx_db_insert_prepare(&db_insert_gitems, "graphs_items", "gitemid", "graphid", "itemid", "drawtype",
+ "sortorder", "color", "yaxisside", "calc_fnc", "type", NULL);
+ }
+
+ if (0 != upd_graphs || 0 != upd_gitems.values_num || 0 != del_gitemids.values_num)
+ {
+ sql = (char *)zbx_malloc(sql, sql_alloc);
+ DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+ }
+
+ for (i = 0; i < graphs->values_num; i++)
+ {
+ graph = (zbx_lld_graph_t *)graphs->values[i];
+
+ if (0 == (graph->flags & ZBX_FLAG_LLD_GRAPH_DISCOVERED))
+ continue;
+
+ if (0 == graph->graphid)
+ {
+ zbx_db_insert_add_values(&db_insert, graphid, graph->name, width, height, yaxismin, yaxismax,
+ (int)show_work_period, (int)show_triggers, (int)graphtype, (int)show_legend,
+ (int)show_3d, percent_left, percent_right, (int)ymin_type, graph->ymin_itemid,
+ (int)ymax_type, graph->ymax_itemid, (int)ZBX_FLAG_DISCOVERY_CREATED);
+
+ zbx_db_insert_add_values(&db_insert_gdiscovery, graphid, parent_graphid);
+
+ graph->graphid = graphid++;
+ }
+ else if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE))
+ {
+ const char *d = "";
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update graphs set ");
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_NAME))
+ {
+ name_esc = DBdyn_escape_string(graph->name);
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "name='%s'", name_esc);
+ zbx_free(name_esc);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_WIDTH))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%swidth=%d", d, width);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_HEIGHT))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sheight=%d", d, height);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMIN))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxismin=" ZBX_FS_DBL, d,
+ yaxismin);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YAXISMAX))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxismax=" ZBX_FS_DBL, d,
+ yaxismax);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_WORK_PERIOD))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_work_period=%d", d,
+ (int)show_work_period);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_TRIGGERS))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_triggers=%d", d,
+ (int)show_triggers);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_GRAPHTYPE))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sgraphtype=%d", d,
+ (int)graphtype);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_LEGEND))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_legend=%d", d,
+ (int)show_legend);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_SHOW_3D))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sshow_3d=%d", d, (int)show_3d);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_LEFT))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spercent_left=" ZBX_FS_DBL, d,
+ percent_left);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_PERCENT_RIGHT))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spercent_right=" ZBX_FS_DBL, d,
+ percent_right);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_TYPE))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symin_type=%d", d,
+ (int)ymin_type);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMIN_ITEMID))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symin_itemid=%s", d,
+ DBsql_id_ins(graph->ymin_itemid));
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_TYPE))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symax_type=%d", d,
+ (int)ymax_type);
+ d = ",";
+ }
+
+ if (0 != (graph->flags & ZBX_FLAG_LLD_GRAPH_UPDATE_YMAX_ITEMID))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%symax_itemid=%s", d,
+ DBsql_id_ins(graph->ymax_itemid));
+ }
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where graphid=" ZBX_FS_UI64 ";\n",
+ graph->graphid);
+ }
+
+ for (j = 0; j < graph->gitems.values_num; j++)
+ {
+ gitem = (zbx_lld_gitem_t *)graph->gitems.values[j];
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_DELETE))
+ continue;
+
+ if (0 == (gitem->flags & ZBX_FLAG_LLD_GITEM_DISCOVERED))
+ continue;
+
+ if (0 == gitem->gitemid)
+ {
+ zbx_db_insert_add_values(&db_insert_gitems, gitemid, graph->graphid, gitem->itemid,
+ (int)gitem->drawtype, gitem->sortorder, gitem->color,
+ (int)gitem->yaxisside, (int)gitem->calc_fnc, (int)gitem->type);
+
+ gitem->gitemid = gitemid++;
+ }
+ }
+ }
+
+ for (i = 0; i < upd_gitems.values_num; i++)
+ {
+ const char *d = "";
+
+ gitem = (zbx_lld_gitem_t *)upd_gitems.values[i];
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update graphs_items set ");
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_ITEMID))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64, gitem->itemid);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_DRAWTYPE))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sdrawtype=%d", d, (int)gitem->drawtype);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_SORTORDER))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%ssortorder=%d", d, gitem->sortorder);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_COLOR))
+ {
+ color_esc = DBdyn_escape_string(gitem->color);
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scolor='%s'", d, color_esc);
+ zbx_free(color_esc);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_YAXISSIDE))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%syaxisside=%d", d,
+ (int)gitem->yaxisside);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_CALC_FNC))
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scalc_fnc=%d", d, (int)gitem->calc_fnc);
+ d = ",";
+ }
+
+ if (0 != (gitem->flags & ZBX_FLAG_LLD_GITEM_UPDATE_TYPE))
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d, (int)gitem->type);
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where gitemid=" ZBX_FS_UI64 ";\n",
+ gitem->gitemid);
+ }
+
+ if (0 != del_gitemids.values_num)
+ {
+ zbx_vector_uint64_sort(&del_gitemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from graphs_items where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "gitemid",
+ del_gitemids.values, del_gitemids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+ }
+
+ if (0 != upd_graphs || 0 != upd_gitems.values_num || 0 != del_gitemids.values_num)
+ {
+ DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+ DBexecute("%s", sql);
+ zbx_free(sql);
+ }
+
+ if (0 != new_graphs)
+ {
+ zbx_db_insert_execute(&db_insert);
+ zbx_db_insert_clean(&db_insert);
+
+ zbx_db_insert_execute(&db_insert_gdiscovery);
+ zbx_db_insert_clean(&db_insert_gdiscovery);
+ }
+
+ if (0 != new_gitems)
+ {
+ zbx_db_insert_execute(&db_insert_gitems);
+ zbx_db_insert_clean(&db_insert_gitems);
+ }
+
+ DBcommit();
+out:
+ zbx_vector_uint64_destroy(&del_gitemids);
+ zbx_vector_ptr_destroy(&upd_gitems);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_update_graphs *
+ * *
+ * Purpose: add or update graphs for discovery item *
+ * *
+ * Parameters: hostid - [IN] host identificator from database *
+ * agent - [IN] discovery item identificator from database *
+ * jp_data - [IN] received data *
+ * *
+ * Return value: SUCCEED - if graphs were successfully added/updated or *
+ * adding/updating was not necessary *
+ * FAIL - graphs cannot be added/updated *
+ * *
+ * Author: Alexander Vladishev *
+ * *
+ ******************************************************************************/
+int 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)
+{
+ const char *__function_name = "lld_update_graphs";
+
+ int ret = SUCCEED;
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_vector_ptr_t graphs;
+ zbx_vector_ptr_t gitems_proto;
+ zbx_vector_ptr_t items;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_ptr_create(&graphs); /* list of graphs which were created or will be created or */
+ /* updated by the graph prototype */
+ zbx_vector_ptr_create(&gitems_proto); /* list of graphs_items which are used by the graph prototype */
+ zbx_vector_ptr_create(&items); /* list of items which are related to the graph prototype */
+
+ result = DBselect(
+ "select distinct g.graphid,g.name,g.width,g.height,g.yaxismin,g.yaxismax,g.show_work_period,"
+ "g.show_triggers,g.graphtype,g.show_legend,g.show_3d,g.percent_left,g.percent_right,"
+ "g.ymin_type,g.ymin_itemid,g.ymax_type,g.ymax_itemid"
+ " from graphs g,graphs_items gi,items i,item_discovery id"
+ " where g.graphid=gi.graphid"
+ " and gi.itemid=i.itemid"
+ " and i.itemid=id.itemid"
+ " and id.parent_itemid=" ZBX_FS_UI64,
+ lld_ruleid);
+
+ while (SUCCEED == ret && NULL != (row = DBfetch(result)))
+ {
+ zbx_uint64_t parent_graphid, ymin_itemid_proto, ymax_itemid_proto;
+ const char *name_proto;
+ int width, height;
+ double yaxismin, yaxismax, percent_left, percent_right;
+ unsigned char show_work_period, show_triggers, graphtype, show_legend, show_3d,
+ ymin_type, ymax_type;
+
+ ZBX_STR2UINT64(parent_graphid, row[0]);
+ name_proto = row[1];
+ width = atoi(row[2]);
+ height = atoi(row[3]);
+ yaxismin = atof(row[4]);
+ yaxismax = atof(row[5]);
+ ZBX_STR2UCHAR(show_work_period, row[6]);
+ ZBX_STR2UCHAR(show_triggers, row[7]);
+ ZBX_STR2UCHAR(graphtype, row[8]);
+ ZBX_STR2UCHAR(show_legend, row[9]);
+ ZBX_STR2UCHAR(show_3d, row[10]);
+ percent_left = atof(row[11]);
+ percent_right = atof(row[12]);
+ ZBX_STR2UCHAR(ymin_type, row[13]);
+ ZBX_DBROW2UINT64(ymin_itemid_proto, row[14]);
+ ZBX_STR2UCHAR(ymax_type, row[15]);
+ ZBX_DBROW2UINT64(ymax_itemid_proto, row[16]);
+
+ lld_graphs_get(parent_graphid, &graphs, width, height, yaxismin, yaxismax, show_work_period,
+ show_triggers, graphtype, show_legend, show_3d, percent_left, percent_right,
+ ymin_type, ymax_type);
+ lld_gitems_get(parent_graphid, &gitems_proto, &graphs);
+ lld_items_get(&gitems_proto, ymin_itemid_proto, ymax_itemid_proto, &items);
+
+ /* making graphs */
+
+ lld_graphs_make(&gitems_proto, &graphs, &items, name_proto, ymin_itemid_proto, ymax_itemid_proto,
+ lld_rows, lld_macro_paths);
+ lld_graphs_validate(hostid, &graphs, error);
+ ret = lld_graphs_save(hostid, parent_graphid, &graphs, width, height, yaxismin, yaxismax,
+ show_work_period, show_triggers, graphtype, show_legend, show_3d, percent_left,
+ percent_right, ymin_type, ymax_type);
+
+ lld_items_free(&items);
+ lld_gitems_free(&gitems_proto);
+ lld_graphs_free(&graphs);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_destroy(&items);
+ zbx_vector_ptr_destroy(&gitems_proto);
+ zbx_vector_ptr_destroy(&graphs);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+
+ return ret;
+}