diff options
Diffstat (limited to 'src/libs/zbxdbwrap/host.c')
-rw-r--r-- | src/libs/zbxdbwrap/host.c | 6513 |
1 files changed, 6513 insertions, 0 deletions
diff --git a/src/libs/zbxdbwrap/host.c b/src/libs/zbxdbwrap/host.c new file mode 100644 index 00000000000..f9236e5ae76 --- /dev/null +++ b/src/libs/zbxdbwrap/host.c @@ -0,0 +1,6513 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 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 "template.h" +#include "zbxdbwrap.h" + +#include "log.h" +#include "zbxcacheconfig.h" +#include "zbxserver.h" +#include "audit/zbxaudit_host.h" +#include "audit/zbxaudit_item.h" +#include "audit/zbxaudit_trigger.h" +#include "audit/zbxaudit_httptest.h" +#include "audit/zbxaudit_graph.h" +#include "audit/zbxaudit.h" +#include "trigger_linking.h" +#include "graph_linking.h" +#include "zbxnum.h" + +typedef struct +{ + zbx_uint64_t id; + char *name; +} +zbx_id_name_pair_t; + +static zbx_hash_t zbx_ids_names_hash_func(const void *data) +{ + const zbx_id_name_pair_t *id_name_pair_entry = (const zbx_id_name_pair_t *)data; + + return ZBX_DEFAULT_UINT64_HASH_ALGO(&(id_name_pair_entry->id), sizeof(id_name_pair_entry->id), + ZBX_DEFAULT_HASH_SEED); +} + +static int zbx_ids_names_compare_func(const void *d1, const void *d2) +{ + const zbx_id_name_pair_t *id_name_pair_entry_1 = (const zbx_id_name_pair_t *)d1; + const zbx_id_name_pair_t *id_name_pair_entry_2 = (const zbx_id_name_pair_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(id_name_pair_entry_1->id, id_name_pair_entry_2->id); + + return 0; +} + +/****************************************************************************** + * * + * Parameters: sql - [IN] sql statement * + * ids - [OUT] sorted list of selected uint64 values * + * names - [OUT] list of names of the requested resource, order * + * matches the order of ids list * + * * + * Return value: SUCCEED - query for selecting ids and names SUCCEEDED * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int DBselect_ids_names(const char *sql, zbx_vector_uint64_t *ids, zbx_vector_str_t *names) +{ + int i, ret = FAIL; + DB_RESULT result; + DB_ROW row; + zbx_uint64_t id; + zbx_hashset_t ids_names; + + if (NULL == (result = DBselect("%s", sql))) + goto out; + +#define IDS_NAMES_HASHSET_DEF_SIZE 100 + zbx_hashset_create(&ids_names, IDS_NAMES_HASHSET_DEF_SIZE, + zbx_ids_names_hash_func, + zbx_ids_names_compare_func); +#undef IDS_NAMES_HASHSET_DEF_SIZE + + while (NULL != (row = DBfetch(result))) + { + zbx_id_name_pair_t local_id_name_pair; + + ZBX_STR2UINT64(id, row[0]); + zbx_vector_uint64_append(ids, id); + local_id_name_pair.id = id; + local_id_name_pair.name = zbx_strdup(NULL, row[1]); + zbx_hashset_insert(&ids_names, &local_id_name_pair, sizeof(local_id_name_pair)); + } + DBfree_result(result); + + zbx_vector_uint64_sort(ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + for (i = 0; i < ids->values_num; i++) + { + zbx_id_name_pair_t *found, temp_t; + + temp_t.id = ids->values[i]; + if (NULL != (found = (zbx_id_name_pair_t *)zbx_hashset_search(&ids_names, &temp_t))) + { + zbx_vector_str_append(names, zbx_strdup(NULL, found->name)); + zbx_free(found->name); + } + else + { + THIS_SHOULD_NEVER_HAPPEN; + goto clean; + } + } + ret = SUCCEED; +clean: + zbx_hashset_destroy(&ids_names); +out: + return ret; +} + +typedef struct _zbx_template_graph_valid_t zbx_template_graph_valid_t; +ZBX_PTR_VECTOR_DECL(graph_valid_ptr, zbx_template_graph_valid_t *) + +struct _zbx_template_graph_valid_t +{ + zbx_uint64_t tgraphid; + zbx_uint64_t hgraphid; + char *name; + zbx_vector_str_t tkeys; + zbx_vector_str_t hkeys; +}; + +ZBX_PTR_VECTOR_IMPL(graph_valid_ptr, zbx_template_graph_valid_t *) + +static char *get_template_names(const zbx_vector_uint64_t *templateids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL, *template_names = NULL; + size_t sql_alloc = 256, sql_offset=0, tmp_alloc = 64, tmp_offset = 0; + + sql = (char *)zbx_malloc(sql, sql_alloc); + template_names = (char *)zbx_malloc(template_names, tmp_alloc); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select host" + " from hosts" + " where"); + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + templateids->values, templateids->values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + zbx_snprintf_alloc(&template_names, &tmp_alloc, &tmp_offset, "\"%s\", ", row[0]); + + template_names[tmp_offset - 2] = '\0'; + + DBfree_result(result); + zbx_free(sql); + + return template_names; +} + +/****************************************************************************** + * * + * Description: gets a vector of profile identifiers used with the specified * + * source, indexes and value identifiers * + * * + * Parameters: profileids - [OUT] the screen item identifiers * + * source - [IN] the source * + * idxs - [IN] an array of index values * + * idxs_num - [IN] the number of values in idxs array * + * value_ids - [IN] the resource identifiers * + * * + ******************************************************************************/ +static void DBget_profiles_by_source_idxs_values(zbx_vector_uint64_t *profileids, const char *source, + const char **idxs, int idxs_num, zbx_vector_uint64_t *value_ids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct profileid from profiles where"); + + if (NULL != source) + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " source='%s' and", source); + + if (0 != idxs_num) + { + DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "idx", idxs, idxs_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and"); + } + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "value_id", value_ids->values, value_ids->values_num); + + DBselect_uint64(sql, profileids); + + zbx_free(sql); + + zbx_vector_uint64_sort(profileids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Description: gets a vector of sysmap element identifiers used with the * + * specified element type and identifiers * + * * + * Parameters: selementids - [OUT] the sysmap element identifiers * + * elementtype - [IN] the element type * + * elementids - [IN] the element identifiers * + * * + ******************************************************************************/ +static void DBget_sysmapelements_by_element_type_ids(zbx_vector_uint64_t *selementids, int elementtype, + const zbx_vector_uint64_t *elementids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct selementid" + " from sysmaps_elements" + " where elementtype=%d" + " and", + elementtype); + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "elementid", elementids->values, elementids->values_num); + DBselect_uint64(sql, selementids); + + zbx_free(sql); + + zbx_vector_uint64_sort(selementids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Description: Check collisions between linked templates * + * * + * Parameters: templateids - [IN] array of template IDs * + * * + * Return value: SUCCEED if no collisions found * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static int validate_linked_templates(const zbx_vector_uint64_t *templateids, char *error, size_t max_error_len) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 256, sql_offset; + int ret = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == templateids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + /* items */ + if (SUCCEED == ret && 1 < templateids->values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select key_,count(*)" + " from items" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " group by key_" + " having count(*)>1"); + + result = DBselectN(sql, 1); + + if (NULL != (row = DBfetch(result))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, "conflicting item key \"%s\" found", row[0]); + } + DBfree_result(result); + } + + /* trigger expressions */ + if (SUCCEED == ret) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t1.description,h2.host" + " from items i1,functions f1,triggers t1,functions f2,items i2,hosts h2" + " where i1.itemid=f1.itemid" + " and f1.triggerid=t1.triggerid" + " and t1.triggerid=f2.triggerid" + " and f2.itemid=i2.itemid" + " and i2.hostid=h2.hostid" + " and h2.status=%d" + " and", + HOST_STATUS_TEMPLATE); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i1.hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i2.hostid", + templateids->values, templateids->values_num); + + result = DBselectN(sql, 1); + + if (NULL != (row = DBfetch(result))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "trigger \"%s\" has items from template \"%s\"", + row[0], row[1]); + } + DBfree_result(result); + } + + /* trigger dependencies */ + if (SUCCEED == ret) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + /* don't remove "description2 and host2" aliases, the ORACLE needs them */ + "select t1.description,h1.host,t2.description as description2,h2.host as host2" + " from trigger_depends td,triggers t1,functions f1,items i1,hosts h1," + "triggers t2,functions f2,items i2,hosts h2" + " where td.triggerid_down=t1.triggerid" + " and t1.triggerid=f1.triggerid" + " and f1.itemid=i1.itemid" + " and i1.hostid=h1.hostid" + " and td.triggerid_up=t2.triggerid" + " and t2.triggerid=f2.triggerid" + " and f2.itemid=i2.itemid" + " and i2.hostid=h2.hostid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i1.hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i2.hostid", + templateids->values, templateids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and h2.status=%d", HOST_STATUS_TEMPLATE); + + result = DBselectN(sql, 1); + + if (NULL != (row = DBfetch(result))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "trigger \"%s\" in template \"%s\"" + " has dependency from trigger \"%s\" in template \"%s\"", + row[0], row[1], row[2], row[3]); + } + DBfree_result(result); + } + + /* graphs */ + if (SUCCEED == ret && 1 < templateids->values_num) + { + zbx_vector_uint64_t graphids; + + zbx_vector_uint64_create(&graphids); + + /* select all linked graphs */ + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct gi.graphid" + " from graphs_items gi,items i" + " where gi.itemid=i.itemid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", + templateids->values, templateids->values_num); + + DBselect_uint64(sql, &graphids); + + /* check for names */ + if (0 != graphids.values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select name,count(*)" + " from graphs" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid", + graphids.values, graphids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " group by name" + " having count(*)>1"); + + result = DBselect("%s", sql); + + if (NULL != (row = DBfetch(result))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "template with graph \"%s\" already linked to the host", row[0]); + } + DBfree_result(result); + } + + zbx_vector_uint64_destroy(&graphids); + } + + /* httptests */ + if (SUCCEED == ret && 1 < templateids->values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select name,count(*)" + " from httptest" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " group by name" + " having count(*)>1"); + + result = DBselectN(sql, 1); + + if (NULL != (row = DBfetch(result))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "template with web scenario \"%s\" already linked to the host", row[0]); + } + DBfree_result(result); + } + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Description: Check collisions in item inventory links * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Return value: SUCCEED if no collisions found * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static int validate_inventory_links(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, + char *error, size_t max_error_len) +{ + DB_RESULT result; + char *sql = NULL; + size_t sql_alloc = 512, sql_offset; + int ret = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + sql = (char *)zbx_malloc(sql, sql_alloc); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select inventory_link,count(*)" + " from items" + " where inventory_link<>0" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " group by inventory_link" + " having count(*)>1"); + + result = DBselectN(sql, 1); + + if (NULL != DBfetch(result)) + { + ret = FAIL; + zbx_strlcpy(error, "two items cannot populate one host inventory field", max_error_len); + } + DBfree_result(result); + + if (FAIL == ret) + goto out; + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select ti.itemid" + " from items ti,items i" + " where ti.key_<>i.key_" + " and ti.inventory_link=i.inventory_link" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", + templateids->values, templateids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + " and i.hostid=" ZBX_FS_UI64 + " and ti.inventory_link<>0" + " and not exists (" + "select *" + " from items", + hostid); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "items.hostid", + templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " and items.key_=i.key_" + ")"); + + result = DBselectN(sql, 1); + + if (NULL != DBfetch(result)) + { + ret = FAIL; + zbx_strlcpy(error, "two items cannot populate one host inventory field", max_error_len); + } + DBfree_result(result); +out: + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Description: checking collisions on linking of web scenarios * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Return value: SUCCEED if no collisions found * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static int validate_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, + char *error, size_t max_error_len) +{ + DB_RESULT tresult; + DB_RESULT sresult; + DB_ROW trow; + char *sql = NULL; + size_t sql_alloc = 512, sql_offset = 0; + int ret = SUCCEED; + zbx_uint64_t t_httptestid, h_httptestid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + sql = (char *)zbx_malloc(sql, sql_alloc); + + /* selects web scenarios from templates and host with identical names */ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t.httptestid,t.name,h.httptestid" + " from httptest t" + " inner join httptest h" + " on h.name=t.name" + " and h.hostid=" ZBX_FS_UI64 + " where", hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num); + + tresult = DBselect("%s", sql); + + while (NULL != (trow = DBfetch(tresult))) + { + ZBX_STR2UINT64(t_httptestid, trow[0]); + ZBX_STR2UINT64(h_httptestid, trow[2]); + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + /* don't remove "h_httpstepid" alias, the ORACLE needs it */ + "select t.httpstepid,h.httpstepid as h_httpstepid" + " from httpstep t" + " left join httpstep h" + " on h.httptestid=" ZBX_FS_UI64 + " and h.no=t.no" + " and h.name=t.name" + " where t.httptestid=" ZBX_FS_UI64 + " and h.httpstepid is null" + " union " + "select t.httpstepid,h.httpstepid as h_httpstepid" + " from httpstep h" + " left outer join httpstep t" + " on t.httptestid=" ZBX_FS_UI64 + " and t.no=h.no" + " and t.name=h.name" + " where h.httptestid=" ZBX_FS_UI64 + " and t.httpstepid is null", + h_httptestid, t_httptestid, t_httptestid, h_httptestid); + + sresult = DBselectN(sql, 1); + + if (NULL != DBfetch(sresult)) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "web scenario \"%s\" already exists on the host (steps are not identical)", + trow[1]); + } + DBfree_result(sresult); + + if (SUCCEED != ret) + break; + } + DBfree_result(tresult); + + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static void zbx_graph_valid_free(zbx_template_graph_valid_t *graph) +{ + zbx_vector_str_clear_ext(&graph->tkeys, zbx_str_free); + zbx_vector_str_clear_ext(&graph->hkeys, zbx_str_free); + zbx_vector_str_destroy(&graph->tkeys); + zbx_vector_str_destroy(&graph->hkeys); + zbx_free(graph->name); + zbx_free(graph); +} + +/****************************************************************************** + * * + * Description: Check collisions between host and linked template * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Return value: SUCCEED if no collisions found * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static int validate_host(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids, char *error, size_t max_error_len) +{ + int ret = SUCCEED, i, j; + char *sql; + unsigned char t_flags, h_flags, type; + DB_RESULT tresult; + DB_ROW trow; + size_t sql_alloc = 256, sql_offset; + zbx_uint64_t graphid, interfaceids[INTERFACE_TYPE_COUNT]; + zbx_vector_graph_valid_ptr_t graphs; + zbx_vector_uint64_t graphids; + zbx_template_graph_valid_t *graph; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (SUCCEED != (ret = validate_inventory_links(hostid, templateids, error, max_error_len))) + goto out; + + if (SUCCEED != (ret = validate_httptests(hostid, templateids, error, max_error_len))) + goto out; + + zbx_vector_graph_valid_ptr_create(&graphs); + zbx_vector_uint64_create(&graphids); + + sql = (char *)zbx_malloc(NULL, sql_alloc); + + sql_offset = 0; + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct g.graphid,g.name,g.flags,g2.graphid,g2.flags" + " from graphs_items gi,items i,graphs g" + " join graphs g2 on g2.name=g.name and g2.templateid is null" + " join graphs_items gi2 on gi2.graphid=g2.graphid" + " join items i2 on i2.itemid=gi2.itemid and i2.hostid=" ZBX_FS_UI64 + " where g.graphid=gi.graphid and gi.itemid=i.itemid and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num); + + tresult = DBselect("%s", sql); + + while (NULL != (trow = DBfetch(tresult))) + { + t_flags = (unsigned char)atoi(trow[2]); + h_flags = (unsigned char)atoi(trow[4]); + + if (t_flags != h_flags) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "graph prototype and real graph \"%s\" have the same name", trow[1]); + break; + } + + graph = (zbx_template_graph_valid_t *)zbx_malloc(NULL, sizeof(zbx_template_graph_valid_t)); + + ZBX_STR2UINT64(graph->tgraphid, trow[0]); + ZBX_STR2UINT64(graph->hgraphid, trow[3]); + + zbx_vector_uint64_append(&graphids, graph->tgraphid); + zbx_vector_uint64_append(&graphids, graph->hgraphid); + + graph->name = zbx_strdup(NULL, trow[1]); + + zbx_vector_str_create(&graph->hkeys); + zbx_vector_str_create(&graph->tkeys); + + zbx_vector_graph_valid_ptr_append(&graphs, graph); + } + + DBfree_result(tresult); + + if (0 != graphids.values_num) + { + sql_offset = 0; + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select gi.graphid,i.key_" + " from items i,graphs_items gi" + " where gi.itemid=i.itemid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "gi.graphid", graphids.values, + graphids.values_num); + + tresult = DBselect("%s", sql); + + while (NULL != (trow = DBfetch(tresult))) + { + ZBX_STR2UINT64(graphid, trow[0]); + + for (i = 0; i < graphs.values_num; i++) + { + graph = (zbx_template_graph_valid_t *)graphs.values[i]; + + if (graphid == graph->tgraphid) + { + zbx_vector_str_append(&graph->tkeys, zbx_strdup(NULL, trow[1])); + break; + } + + if (graphid == graph->hgraphid) + { + zbx_vector_str_append(&graph->hkeys, zbx_strdup(NULL, trow[1])); + break; + } + } + } + DBfree_result(tresult); + } + + for (i = 0; i < graphs.values_num; i++) + { + graph = (zbx_template_graph_valid_t *)graphs.values[i]; + + if (graph->tkeys.values_num != graph->hkeys.values_num ) + { + ret = FAIL; + break; + } + + zbx_vector_str_sort(&graph->tkeys, ZBX_DEFAULT_STR_COMPARE_FUNC); + zbx_vector_str_sort(&graph->hkeys, ZBX_DEFAULT_STR_COMPARE_FUNC); + + for (j = 0; j < graph->tkeys.values_num; j++) + { + if (0 != strcmp(graph->tkeys.values[j], graph->hkeys.values[j])) + { + ret = FAIL; + break; + } + } + + if (FAIL == ret) + break; + } + + if (FAIL == ret && 0 < graphs.values_num) + { + graph = (zbx_template_graph_valid_t *)graphs.values[i]; + + zbx_snprintf(error, max_error_len, "graph \"%s\" already exists on the host (items are not identical)", + graph->name); + } + + if (SUCCEED == ret) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select i.key_" + " from items i,items t" + " where i.key_=t.key_" + " and i.flags<>t.flags" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", + templateids->values, templateids->values_num); + + tresult = DBselectN(sql, 1); + + if (NULL != (trow = DBfetch(tresult))) + { + ret = FAIL; + zbx_snprintf(error, max_error_len, + "item prototype and real item \"%s\" have the same key", trow[0]); + } + DBfree_result(tresult); + } + + /* interfaces */ + if (SUCCEED == ret) + { + memset(&interfaceids, 0, sizeof(interfaceids)); + + tresult = DBselect( + "select type,interfaceid" + " from interface" + " where hostid=" ZBX_FS_UI64 + " and type in (%d,%d,%d,%d)" + " and main=1", + hostid, INTERFACE_TYPE_AGENT, INTERFACE_TYPE_SNMP, + INTERFACE_TYPE_IPMI, INTERFACE_TYPE_JMX); + + while (NULL != (trow = DBfetch(tresult))) + { + type = (unsigned char)atoi(trow[0]); + ZBX_STR2UINT64(interfaceids[type - 1], trow[1]); + } + DBfree_result(tresult); + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct type" + " from items" + " where type not in (%d,%d,%d,%d,%d,%d,%d,%d)" + " and", + ITEM_TYPE_TRAPPER, ITEM_TYPE_INTERNAL, ITEM_TYPE_ZABBIX_ACTIVE, + ITEM_TYPE_HTTPTEST, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_CALCULATED, ITEM_TYPE_DEPENDENT, + ITEM_TYPE_HTTPAGENT); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + templateids->values, templateids->values_num); + + tresult = DBselect("%s", sql); + + while (SUCCEED == ret && NULL != (trow = DBfetch(tresult))) + { + type = (unsigned char)atoi(trow[0]); + type = get_interface_type_by_item_type(type); + + if (INTERFACE_TYPE_UNKNOWN == type) + continue; + + if (INTERFACE_TYPE_ANY == type) + { + for (i = 0; INTERFACE_TYPE_COUNT > i; i++) + { + if (0 != interfaceids[i]) + break; + } + + if (INTERFACE_TYPE_COUNT == i) + { + zbx_strlcpy(error, "cannot find any interfaces on host", max_error_len); + ret = FAIL; + } + } + else if (0 == interfaceids[type - 1]) + { + zbx_snprintf(error, max_error_len, "cannot find \"%s\" host interface", + zbx_interface_type_string((zbx_interface_type_t)type)); + ret = FAIL; + } + } + DBfree_result(tresult); + } + + zbx_free(sql); + + zbx_vector_graph_valid_ptr_clear_ext(&graphs, zbx_graph_valid_free); + zbx_vector_graph_valid_ptr_destroy(&graphs); + zbx_vector_uint64_destroy(&graphids); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Purpose: delete action conditions by condition type and id * + * * + ******************************************************************************/ +static void DBdelete_action_conditions(int conditiontype, zbx_uint64_t elementid) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t id; + zbx_vector_uint64_t actionids, conditionids; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + + zbx_vector_uint64_create(&actionids); + zbx_vector_uint64_create(&conditionids); + + /* disable actions */ + result = DBselect("select actionid,conditionid from conditions where conditiontype=%d and" + " value='" ZBX_FS_UI64 "'", conditiontype, elementid); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(id, row[0]); + zbx_vector_uint64_append(&actionids, id); + + ZBX_STR2UINT64(id, row[1]); + zbx_vector_uint64_append(&conditionids, id); + } + + DBfree_result(result); + + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (0 != actionids.values_num) + { + zbx_vector_uint64_sort(&actionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&actionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update actions set status=%d where", + ACTION_STATUS_DISABLED); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "actionid", actionids.values, + actionids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + if (0 != conditionids.values_num) + { + zbx_vector_uint64_sort(&conditionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from conditions where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "conditionid", conditionids.values, + conditionids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + /* in ORACLE always present begin..end; */ + if (16 < sql_offset) + DBexecute("%s", sql); + + zbx_free(sql); + + zbx_vector_uint64_destroy(&conditionids); + zbx_vector_uint64_destroy(&actionids); +} + +/****************************************************************************** + * * + * Purpose: adds table and field with specific id to housekeeper list * + * * + * Parameters: ids - [IN] identifiers for data removal * + * field - [IN] field name from table * + * tables_hk - [IN] table name to delete information from * + * count - [IN] number of tables in tables array * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBadd_to_housekeeper(const zbx_vector_uint64_t *ids, const char *field, const char * const *tables_hk, + int count) +{ + int i, j; + zbx_uint64_t housekeeperid; + zbx_db_insert_t db_insert; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, ids->values_num); + + if (0 == ids->values_num) + goto out; + + housekeeperid = DBget_maxid_num("housekeeper", count * ids->values_num); + + zbx_db_insert_prepare(&db_insert, "housekeeper", "housekeeperid", "tablename", "field", "value", NULL); + + for (i = 0; i < ids->values_num; i++) + { + for (j = 0; j < count; j++) + zbx_db_insert_add_values(&db_insert, housekeeperid++, tables_hk[j], field, ids->values[i]); + } + + zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete trigger from database * + * * + * Parameters: triggerids - [IN] trigger identifiers from database * + * * + ******************************************************************************/ +void DBdelete_triggers(zbx_vector_uint64_t *triggerids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset; + int i; + zbx_vector_uint64_t selementids; + const char *event_tables[] = {"events"}; + + if (0 == triggerids->values_num) + return; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&selementids); + + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_TRIGGER, triggerids); + if (0 != selementids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values, + selementids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + for (i = 0; i < triggerids->values_num; i++) + DBdelete_action_conditions(ZBX_CONDITION_TYPE_TRIGGER, triggerids->values[i]); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "delete from triggers" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + /* add housekeeper task to delete problems associated with trigger, this allows old events to be deleted */ + DBadd_to_housekeeper(triggerids, "triggerid", event_tables, ARRSIZE(event_tables)); + + zbx_vector_uint64_destroy(&selementids); + + zbx_free(sql); +} + +/****************************************************************************** + * * + * Purpose: delete parent triggers and auto-created children from database * + * * + * Parameters: triggerids - [IN] trigger identifiers from database * + * * + ******************************************************************************/ +static void DBdelete_trigger_hierarchy(zbx_vector_uint64_t *triggerids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + zbx_vector_uint64_t children_triggerids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == triggerids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&children_triggerids); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct td.triggerid,t.description,t.flags from " + "trigger_discovery td, triggers t where td.triggerid=t.triggerid and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_triggerid", triggerids->values, + triggerids->values_num); + + zbx_audit_DBselect_delete_for_trigger(sql, &children_triggerids); + zbx_vector_uint64_setdiff(triggerids, &children_triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + DBdelete_triggers(&children_triggerids); + DBdelete_triggers(triggerids); + + zbx_vector_uint64_destroy(&children_triggerids); + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete triggers by itemid * + * * + * Parameters: itemids - [IN] item identifiers from database * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBdelete_triggers_by_itemids(zbx_vector_uint64_t *itemids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t triggerids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, itemids->values_num); + + if (0 == itemids->values_num) + goto out; + + zbx_vector_uint64_create(&triggerids); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct f.triggerid,t.description,t.flags from " + "functions f join triggers t on t.triggerid=f.triggerid where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + + zbx_audit_DBselect_delete_for_trigger(sql, &triggerids); + + DBdelete_trigger_hierarchy(&triggerids); + zbx_vector_uint64_destroy(&triggerids); + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete graph from database * + * * + * Parameters: graphids - [IN] array of graph id's from database * + * * + ******************************************************************************/ +void DBdelete_graphs(zbx_vector_uint64_t *graphids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + zbx_vector_uint64_t profileids; + const char *profile_idx = "web.favorite.graphids"; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, graphids->values_num); + + if (0 == graphids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&profileids); + + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + /* delete from profiles */ + DBget_profiles_by_source_idxs_values(&profileids, "graphid", &profile_idx, 1, graphids); + if (0 != profileids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values, + profileids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + /* delete from graphs */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from graphs where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid", graphids->values, graphids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + zbx_vector_uint64_destroy(&profileids); + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete parent graphs and auto-created children from database * + * * + * Parameters: graphids - [IN] array of graph id's from database * + * * + ******************************************************************************/ +static void DBdelete_graph_hierarchy(zbx_vector_uint64_t *graphids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + zbx_vector_uint64_t children_graphids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == graphids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&children_graphids); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct gd.graphid,g.name,g.flags from" + " graph_discovery gd,graphs g where g.graphid=gd.graphid and "); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_graphid", graphids->values, + graphids->values_num); + + zbx_audit_DBselect_delete_for_graph(sql, &children_graphids); + zbx_vector_uint64_setdiff(graphids, &children_graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + DBdelete_graphs(&children_graphids); + DBdelete_graphs(graphids); + + zbx_vector_uint64_destroy(&children_graphids); + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Parameters: itemids - [IN] item identifiers from database * + * * + ******************************************************************************/ +static void DBdelete_graphs_by_itemids(const zbx_vector_uint64_t *itemids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset; + DB_RESULT result; + DB_ROW row; + zbx_uint64_t graphid; + zbx_vector_uint64_t graphids; + int index; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, itemids->values_num); + + if (0 == itemids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + zbx_vector_uint64_create(&graphids); + + /* select all graphs with items */ + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select distinct gi.graphid,g.name,g.flags from " + "graphs_items gi,graphs g where gi.graphid=g.graphid and "); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "gi.itemid", itemids->values, itemids->values_num); + + zbx_audit_DBselect_delete_for_graph(sql, &graphids); + + if (0 == graphids.values_num) + goto clean; + + /* select graphs with other items */ + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct graphid" + " from graphs_items" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid", graphids.values, graphids.values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and not"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(graphid, row[0]); + if (FAIL != (index = zbx_vector_uint64_bsearch(&graphids, graphid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + zbx_vector_uint64_remove(&graphids, index); + } + DBfree_result(result); + + DBdelete_graph_hierarchy(&graphids); +clean: + zbx_vector_uint64_destroy(&graphids); + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: get linked (discovered, dependent, etc) items * + * * + ******************************************************************************/ +static int db_get_linked_items(zbx_vector_uint64_t *itemids, const char *filter, const char *field) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0, sql_mark = 0; + zbx_vector_uint64_t itemids_tmp, *pitemids = itemids; + int ret; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&itemids_tmp); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct i.itemid,i.name,i.flags from "); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, filter); + + sql_mark = sql_offset; + + zbx_vector_uint64_sort(itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + for(;;) + { + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, field, pitemids->values, pitemids->values_num); + zbx_vector_uint64_clear(&itemids_tmp); + + if (FAIL == (ret = zbx_audit_DBselect_delete_for_item(sql, &itemids_tmp))) + break; + + if (0 == itemids_tmp.values_num) + break; + + sql_offset = sql_mark; + + zbx_vector_uint64_sort(&itemids_tmp, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&itemids_tmp, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_append_array(itemids, itemids_tmp.values, itemids_tmp.values_num); + pitemids = &itemids_tmp; + } + + zbx_vector_uint64_sort(itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_destroy(&itemids_tmp); + + zbx_free(sql); + + return ret; +} + +/****************************************************************************** + * * + * Purpose: delete items from database * + * * + * Parameters: itemids - [IN] array of item identifiers from database * + * * + ******************************************************************************/ +void DBdelete_items(zbx_vector_uint64_t *itemids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset; + zbx_vector_uint64_t profileids; + const char *event_tables[] = {"events"}; + const char *profile_idx = "web.favorite.graphids"; + unsigned char history_mode, trends_mode; + zbx_vector_str_t hk_history; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, itemids->values_num); + + if (0 == itemids->values_num) + goto out; + + if (SUCCEED != db_get_linked_items(itemids, "item_discovery id,items i where id.itemid=i.itemid and", + "id.parent_itemid")) + { + goto out; + } + + if (SUCCEED != db_get_linked_items(itemids, "items i where", "i.master_itemid")) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + zbx_vector_uint64_create(&profileids); + + DBdelete_graphs_by_itemids(itemids); + DBdelete_triggers_by_itemids(itemids); + + zbx_config_get_hk_mode(&history_mode, &trends_mode); + + zbx_vector_str_create(&hk_history); + + if (ZBX_HK_MODE_REGULAR == history_mode) + { + zbx_vector_str_append(&hk_history, "history"); + zbx_vector_str_append(&hk_history, "history_str"); + zbx_vector_str_append(&hk_history, "history_uint"); + zbx_vector_str_append(&hk_history, "history_log"); + zbx_vector_str_append(&hk_history, "history_text"); + } + + if (ZBX_HK_MODE_REGULAR == trends_mode) + { + zbx_vector_str_append(&hk_history, "trends"); + zbx_vector_str_append(&hk_history, "trends_uint"); + } + + if (0 != hk_history.values_num) + DBadd_to_housekeeper(itemids, "itemid", (const char * const *)hk_history.values, hk_history.values_num); + + zbx_vector_str_destroy(&hk_history); + + /* add housekeeper task to delete problems associated with item, this allows old events to be deleted */ + DBadd_to_housekeeper(itemids, "itemid", event_tables, ARRSIZE(event_tables)); + DBadd_to_housekeeper(itemids, "lldruleid", event_tables, ARRSIZE(event_tables)); + + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + /* delete from profiles */ + DBget_profiles_by_source_idxs_values(&profileids, "itemid", &profile_idx, 1, itemids); + if (0 != profileids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values, + profileids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + /* delete from item tags */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from item_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + /* delete from item preprocessing */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from item_preproc where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + /* delete from functions */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + /* delete from items */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update items set master_itemid=null where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and master_itemid is not null;\n"); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from items where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + zbx_vector_uint64_destroy(&profileids); + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete web tests from database * + * * + * Parameters: httptestids - [IN] array of httptest id's from database * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBdelete_httptests(const zbx_vector_uint64_t *httptestids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + zbx_vector_uint64_t itemids; + zbx_vector_uint64_t httpstepids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, httptestids->values_num); + + if (0 == httptestids->values_num) + goto out; + + sql = (char *)zbx_malloc(sql, sql_alloc); + zbx_vector_uint64_create(&itemids); + zbx_vector_uint64_create(&httpstepids); + + /* httpstepitem, httptestitem */ + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hsi.itemid,i.name,i.flags" + " from httpstepitem hsi,httpstep hs,items i" + " where hsi.httpstepid=hs.httpstepid and i.itemid=hsi.itemid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hs.httptestid", + httptestids->values, httptestids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " union all " + "select i.itemid,i.name,i.flags" + " from httptestitem ht,items i" + " where ht.itemid=i.itemid and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids->values, httptestids->values_num); + + if (FAIL == zbx_audit_DBselect_delete_for_item(sql, &itemids)) + goto clean; + + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select httpstepid from httpstep where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids->values, httptestids->values_num); + DBselect_uint64(sql, &httpstepids); + + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptest_field where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids->values, httptestids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptestitem where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids->values, httptestids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httpstep_field where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httpstepid", + httpstepids.values, httpstepids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httpstepitem where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httpstepid", + httpstepids.values, httpstepids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httpstep where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httpstepid", + httpstepids.values, httpstepids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + DBdelete_items(&itemids); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptest where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids->values, httptestids->values_num); + DBexecute("%s", sql); +clean: + zbx_vector_uint64_destroy(&httpstepids); + zbx_vector_uint64_destroy(&itemids); + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Parameters: del_group_prototypeids - [IN] list of group_prototypeids which * + * will be deleted * + * * + ******************************************************************************/ +static void DBgroup_prototypes_delete(const zbx_vector_uint64_t *del_group_prototypeids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset; + zbx_vector_uint64_t groupids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == del_group_prototypeids->values_num) + return; + + zbx_vector_uint64_create(&groupids); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select groupid from group_discovery where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_group_prototypeid", + del_group_prototypeids->values, del_group_prototypeids->values_num); + + DBselect_uint64(sql, &groupids); + + DBdelete_groups(&groupids); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from group_prototype where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "group_prototypeid", + del_group_prototypeids->values, del_group_prototypeids->values_num); + + DBexecute("%s", sql); + + zbx_vector_uint64_destroy(&groupids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: deletes host prototypes from database * + * * + * Parameters: host_prototype_ids - [IN] list of host prototype ids * + * host_prototype_names - [IN] list of host prototype names * + * * + ******************************************************************************/ +static void DBdelete_host_prototypes(const zbx_vector_uint64_t *host_prototype_ids, + const zbx_vector_str_t *host_prototype_names) +{ + int i; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset; + zbx_vector_uint64_t hostids, group_prototype_ids; + zbx_vector_str_t hostnames; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == host_prototype_ids->values_num) + goto out; + + /* delete discovered hosts */ + + zbx_vector_uint64_create(&hostids); + zbx_vector_str_create(&hostnames); + zbx_vector_uint64_create(&group_prototype_ids); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select hd.hostid,h.name from host_discovery hd,hosts h " + "where hd.hostid=h.hostid and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_hostid", + host_prototype_ids->values, host_prototype_ids->values_num); + + if (FAIL == DBselect_ids_names(sql, &hostids, &hostnames)) + goto clean; + + if (0 != hostids.values_num) + DBdelete_hosts(&hostids, &hostnames); + + /* delete group prototypes */ + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select group_prototypeid from group_prototype where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + host_prototype_ids->values, host_prototype_ids->values_num); + + DBselect_uint64(sql, &group_prototype_ids); + DBgroup_prototypes_delete(&group_prototype_ids); + + /* delete host prototypes */ + + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from host_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + host_prototype_ids->values, host_prototype_ids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from hosts where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", + host_prototype_ids->values, host_prototype_ids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + for (i = 0; i < host_prototype_ids->values_num; i++) + zbx_audit_host_prototype_del(host_prototype_ids->values[i], host_prototype_names->values[i]); +clean: + zbx_vector_uint64_destroy(&group_prototype_ids); + zbx_vector_uint64_destroy(&hostids); + zbx_vector_str_clear_ext(&hostnames, zbx_str_free); + zbx_vector_str_destroy(&hostnames); + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete template web scenarios from host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + ******************************************************************************/ +static void DBdelete_template_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t httptestids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&httptestids); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select h.httptestid,h.name" + " from httptest h" + " join httptest t" + " on"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + " and t.httptestid=h.templateid" + " where h.hostid=" ZBX_FS_UI64, hostid); + + if (FAIL == zbx_audit_DBselect_delete_for_httptest(sql, &httptestids)) + goto clean; + + DBdelete_httptests(&httptestids); +clean: + zbx_vector_uint64_destroy(&httptestids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete template graphs from host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBdelete_template_graphs(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t graphids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&graphids); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct gi.graphid,g.name,g.flags" + " from graphs_items gi,items i,items ti, graphs g" + " where gi.itemid=i.itemid" + " and i.templateid=ti.itemid" + " and g.graphid=gi.graphid" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num); + + zbx_audit_DBselect_delete_for_graph(sql, &graphids); + + DBdelete_graph_hierarchy(&graphids); + + zbx_vector_uint64_destroy(&graphids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete template triggers from host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBdelete_template_triggers(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t triggerids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&triggerids); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct f.triggerid,t.description,t.flags" + " from functions f,items i,items ti,triggers t" + " where f.itemid=i.itemid" + " and i.templateid=ti.itemid" + " and t.triggerid=f.triggerid" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num); + + zbx_audit_DBselect_delete_for_trigger(sql, &triggerids); + + DBdelete_trigger_hierarchy(&triggerids); + zbx_vector_uint64_destroy(&triggerids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete template host prototypes from host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + ******************************************************************************/ +static void DBdelete_template_host_prototypes(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t host_prototype_ids; + zbx_vector_str_t host_prototype_names; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&host_prototype_ids); + zbx_vector_str_create(&host_prototype_names); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select hp.hostid,hp.name" + " from items hi,host_discovery hhd,hosts hp,host_discovery thd,items ti" + " where hi.itemid=hhd.parent_itemid" + " and hhd.hostid=hp.hostid" + " and hp.templateid=thd.hostid" + " and thd.parent_itemid=ti.itemid" + " and hi.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num); + if (FAIL == DBselect_ids_names(sql, &host_prototype_ids, &host_prototype_names)) + goto clean; + DBdelete_host_prototypes(&host_prototype_ids, &host_prototype_names); +clean: + zbx_free(sql); + + zbx_vector_uint64_destroy(&host_prototype_ids); + zbx_vector_str_clear_ext(&host_prototype_names, zbx_str_free); + zbx_vector_str_destroy(&host_prototype_names); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete template items from host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +static void DBdelete_template_items(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t itemids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&itemids); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct i.itemid,i.name,i.flags" + " from items i,items ti" + " where i.templateid=ti.itemid" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num); + + if (FAIL == zbx_audit_DBselect_delete_for_item(sql, &itemids)) + goto clean; + + DBdelete_items(&itemids); +clean: + zbx_vector_uint64_destroy(&itemids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Description: Retrieve already linked templates for specified host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN/OUT] array of template IDs * + * * + ******************************************************************************/ +static void get_templates_by_hostid(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t templateid; + + result = DBselect( + "select templateid" + " from hosts_templates" + " where hostid=" ZBX_FS_UI64, + hostid); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(templateid, row[0]); + zbx_vector_uint64_append(templateids, templateid); + } + DBfree_result(result); + + zbx_vector_uint64_sort(templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); +} + +/****************************************************************************** + * * + * Parameters: hostid - [IN] host identifier from database * + * hostname - [IN] name of the host * + * del_templateids - [IN] array of template IDs * + * error - [OUT] error message * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ******************************************************************************/ +int DBdelete_template_elements(zbx_uint64_t hostid, const char *hostname, zbx_vector_uint64_t *del_templateids, + char **error) +{ + char *sql = NULL, err[MAX_STRING_LEN]; + size_t sql_alloc = 128, sql_offset = 0; + zbx_vector_uint64_t templateids; + int i, res = SUCCEED; + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&templateids); + + get_templates_by_hostid(hostid, &templateids); + + for (i = 0; i < del_templateids->values_num; i++) + { + int index; + + if (FAIL == (index = zbx_vector_uint64_bsearch(&templateids, del_templateids->values[i], + ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + /* template already unlinked */ + zbx_vector_uint64_remove(del_templateids, i--); + } + else + zbx_vector_uint64_remove(&templateids, index); + } + + /* all templates already unlinked */ + if (0 == del_templateids->values_num) + goto clean; + + if (SUCCEED != (res = validate_linked_templates(&templateids, err, sizeof(err)))) + { + *error = zbx_strdup(NULL, err); + goto clean; + } + + zbx_audit_host_create_entry(ZBX_AUDIT_ACTION_UPDATE, hostid, hostname); + + DBdelete_template_httptests(hostid, del_templateids); + DBdelete_template_graphs(hostid, del_templateids); + DBdelete_template_triggers(hostid, del_templateids); + DBdelete_template_host_prototypes(hostid, del_templateids); + + /* removing items will remove discovery rules related to them */ + DBdelete_template_items(hostid, del_templateids); + + /* need to find hosttemplateids for audit */ + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select hosttemplateid,templateid from hosts_templates" + " where hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "templateid", + del_templateids->values, del_templateids->values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_t hosttemplateid, templateid; + + ZBX_STR2UINT64(hosttemplateid, row[0]); + ZBX_STR2UINT64(templateid, row[1]); + zbx_audit_host_update_json_delete_parent_template(hostid, hosttemplateid); + } + + DBfree_result(result); + + sql_offset = 0; + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "delete from hosts_templates" + " where hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "templateid", + del_templateids->values, del_templateids->values_num); + DBexecute("%s", sql); + + zbx_free(sql); +clean: + zbx_vector_uint64_destroy(&templateids); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +typedef struct +{ + zbx_uint64_t group_prototypeid; + zbx_uint64_t groupid; + zbx_uint64_t templateid_host; /* for audit update */ + zbx_uint64_t templateid; /* reference to parent group_prototypeid */ + char *name; +} +zbx_group_prototype_t; + +static void DBgroup_prototype_clean(zbx_group_prototype_t *group_prototype) +{ + zbx_free(group_prototype->name); + zbx_free(group_prototype); +} + +static void DBgroup_prototypes_clean(zbx_vector_ptr_t *group_prototypes) +{ + int i; + + for (i = 0; i < group_prototypes->values_num; i++) + DBgroup_prototype_clean((zbx_group_prototype_t *)group_prototypes->values[i]); +} + +typedef struct +{ + zbx_uint64_t hostmacroid; + char *macro; + char *value_orig; + char *value; + char *description_orig; + char *description; + unsigned char type_orig; + unsigned char type; + unsigned char automatic; +#define ZBX_FLAG_HPMACRO_RESET_FLAG __UINT64_C(0x00000000) +#define ZBX_FLAG_HPMACRO_UPDATE_VALUE __UINT64_C(0x00000001) +#define ZBX_FLAG_HPMACRO_UPDATE_DESCRIPTION __UINT64_C(0x00000002) +#define ZBX_FLAG_HPMACRO_UPDATE_TYPE __UINT64_C(0x00000004) +#define ZBX_FLAG_HPMACRO_UPDATE \ + (ZBX_FLAG_HPMACRO_UPDATE_VALUE | ZBX_FLAG_HPMACRO_UPDATE_DESCRIPTION | ZBX_FLAG_HPMACRO_UPDATE_TYPE) + zbx_uint64_t flags; +} +zbx_macros_prototype_t; + +ZBX_PTR_VECTOR_DECL(macros, zbx_macros_prototype_t *) +ZBX_PTR_VECTOR_IMPL(macros, zbx_macros_prototype_t *) + +typedef struct +{ + char *community_orig; + char *community; + char *securityname_orig; + char *securityname; + char *authpassphrase_orig; + char *authpassphrase; + char *privpassphrase_orig; + char *privpassphrase; + char *contextname_orig; + char *contextname; + unsigned char securitylevel_orig; + unsigned char securitylevel; + unsigned char authprotocol_orig; + unsigned char authprotocol; + unsigned char privprotocol_orig; + unsigned char privprotocol; + unsigned char version_orig; + unsigned char version; + unsigned char bulk_orig; + unsigned char bulk; +#define ZBX_FLAG_HPINTERFACE_SNMP_RESET_FLAG __UINT64_C(0x00000000) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_TYPE __UINT64_C(0x00000001) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_BULK __UINT64_C(0x00000002) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_COMMUNITY __UINT64_C(0x00000004) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECNAME __UINT64_C(0x00000008) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECLEVEL __UINT64_C(0x00000010) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPASS __UINT64_C(0x00000020) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPASS __UINT64_C(0x00000040) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPROTOCOL __UINT64_C(0x00000080) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPROTOCOL __UINT64_C(0x00000100) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_CONTEXT __UINT64_C(0x00000200) +#define ZBX_FLAG_HPINTERFACE_SNMP_UPDATE \ + (ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_TYPE | ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_BULK | \ + ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_COMMUNITY | ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECNAME | \ + ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECLEVEL | ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPASS | \ + ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPASS | ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPROTOCOL | \ + ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPROTOCOL | ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_CONTEXT) +#define ZBX_FLAG_HPINTERFACE_SNMP_CREATE __UINT64_C(0x00000400) + zbx_uint64_t flags; +} +zbx_interface_prototype_snmp_t; + +typedef struct +{ + zbx_uint64_t interfaceid; + unsigned char main_orig; + unsigned char main; + unsigned char type_orig; + unsigned char type; + unsigned char useip_orig; + unsigned char useip; + char *ip_orig; + char *ip; + char *dns_orig; + char *dns; + char *port_orig; + char *port; +#define ZBX_FLAG_HPINTERFACE_RESET_FLAG __UINT64_C(0x00000000) +#define ZBX_FLAG_HPINTERFACE_UPDATE_MAIN __UINT64_C(0x00000001) +#define ZBX_FLAG_HPINTERFACE_UPDATE_TYPE __UINT64_C(0x00000002) +#define ZBX_FLAG_HPINTERFACE_UPDATE_USEIP __UINT64_C(0x00000004) +#define ZBX_FLAG_HPINTERFACE_UPDATE_IP __UINT64_C(0x00000008) +#define ZBX_FLAG_HPINTERFACE_UPDATE_DNS __UINT64_C(0x00000010) +#define ZBX_FLAG_HPINTERFACE_UPDATE_PORT __UINT64_C(0x00000020) +#define ZBX_FLAG_HPINTERFACE_UPDATE \ + (ZBX_FLAG_HPINTERFACE_UPDATE_MAIN | ZBX_FLAG_HPINTERFACE_UPDATE_TYPE | \ + ZBX_FLAG_HPINTERFACE_UPDATE_USEIP | ZBX_FLAG_HPINTERFACE_UPDATE_IP | \ + ZBX_FLAG_HPINTERFACE_UPDATE_DNS | ZBX_FLAG_HPINTERFACE_UPDATE_PORT) + zbx_uint64_t flags; + union _data + { + zbx_interface_prototype_snmp_t *snmp; + } + data; +} +zbx_interfaces_prototype_t; + +ZBX_PTR_VECTOR_DECL(interfaces, zbx_interfaces_prototype_t *) +ZBX_PTR_VECTOR_IMPL(interfaces, zbx_interfaces_prototype_t *) + +typedef struct +{ + zbx_uint64_t templateid; /* link to parent template */ + zbx_uint64_t hostid; + zbx_uint64_t itemid; /* discovery rule id */ + zbx_vector_uint64_t lnk_templateids; /* list of templates which should be linked */ + zbx_vector_ptr_t group_prototypes; /* list of group prototypes */ + zbx_vector_macros_t hostmacros; /* list of user macros */ + zbx_vector_db_tag_ptr_t tags; /* list of host prototype tags */ + zbx_vector_db_tag_ptr_t new_tags; /* list of host prototype template tags */ + zbx_vector_interfaces_t interfaces; /* list of interfaces */ + char *host; + char *name_orig; + char *name; + unsigned char status_orig; + unsigned char status; +#define ZBX_FLAG_HPLINK_RESET_FLAG 0x00 +#define ZBX_FLAG_HPLINK_UPDATE_NAME 0x01 +#define ZBX_FLAG_HPLINK_UPDATE_STATUS 0x02 +#define ZBX_FLAG_HPLINK_UPDATE_DISCOVER 0x04 +#define ZBX_FLAG_HPLINK_UPDATE_CUSTOM_INTERFACES 0x08 +#define ZBX_FLAG_HPLINK_UPDATE_INVENTORY_MODE 0x10 + unsigned char flags; + unsigned char discover_orig; + unsigned char discover; + unsigned char custom_interfaces_orig; + unsigned char custom_interfaces; + signed char inventory_mode_orig; + signed char inventory_mode; + zbx_uint64_t templateid_host; +} +zbx_host_prototype_t; + +static void DBhost_macro_free(zbx_macros_prototype_t *hostmacro) +{ + if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_VALUE)) + zbx_free(hostmacro->value_orig); + + if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_DESCRIPTION)) + zbx_free(hostmacro->description_orig); + + zbx_free(hostmacro->macro); + zbx_free(hostmacro->value); + zbx_free(hostmacro->description); + zbx_free(hostmacro); +} + +static void DBhost_interface_free(zbx_interfaces_prototype_t *interface) +{ + zbx_free(interface->ip); + zbx_free(interface->dns); + zbx_free(interface->port); + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_IP)) + zbx_free(interface->ip_orig); + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_DNS)) + zbx_free(interface->dns_orig); + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_PORT)) + zbx_free(interface->port_orig); + + if (INTERFACE_TYPE_SNMP == interface->type) + { + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_COMMUNITY)) + zbx_free(interface->data.snmp->community_orig); + + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECNAME)) + zbx_free(interface->data.snmp->securityname_orig); + + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPASS)) + zbx_free(interface->data.snmp->authpassphrase_orig); + + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPASS)) + zbx_free(interface->data.snmp->privpassphrase_orig); + + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_CONTEXT)) + zbx_free(interface->data.snmp->contextname_orig); + + zbx_free(interface->data.snmp->community); + zbx_free(interface->data.snmp->securityname); + zbx_free(interface->data.snmp->authpassphrase); + zbx_free(interface->data.snmp->privpassphrase); + zbx_free(interface->data.snmp->contextname); + zbx_free(interface->data.snmp); + } + + zbx_free(interface); +} + +static void DBhost_prototype_clean(zbx_host_prototype_t *host_prototype) +{ + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_NAME)) + zbx_free(host_prototype->name_orig); + + zbx_free(host_prototype->name); + zbx_free(host_prototype->host); + zbx_vector_macros_clear_ext(&host_prototype->hostmacros, DBhost_macro_free); + zbx_vector_macros_destroy(&host_prototype->hostmacros); + zbx_vector_db_tag_ptr_clear_ext(&host_prototype->tags, zbx_db_tag_free); + zbx_vector_db_tag_ptr_destroy(&host_prototype->tags); + zbx_vector_db_tag_ptr_clear_ext(&host_prototype->new_tags, zbx_db_tag_free); + zbx_vector_db_tag_ptr_destroy(&host_prototype->new_tags); + zbx_vector_interfaces_clear_ext(&host_prototype->interfaces, DBhost_interface_free); + zbx_vector_interfaces_destroy(&host_prototype->interfaces); + DBgroup_prototypes_clean(&host_prototype->group_prototypes); + zbx_vector_ptr_destroy(&host_prototype->group_prototypes); + zbx_vector_uint64_destroy(&host_prototype->lnk_templateids); + zbx_free(host_prototype); +} + +static void DBhost_prototypes_clean(zbx_vector_ptr_t *host_prototypes) +{ + int i; + + for (i = 0; i < host_prototypes->values_num; i++) + DBhost_prototype_clean((zbx_host_prototype_t *)host_prototypes->values[i]); +} + +/****************************************************************************** + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static int DBis_regular_host(zbx_uint64_t hostid) +{ + DB_RESULT result; + DB_ROW row; + int ret = FAIL; + + result = DBselect("select flags from hosts where hostid=" ZBX_FS_UI64, hostid); + + if (NULL != (row = DBfetch(result))) + { + if (0 == atoi(row[0])) + ret = SUCCEED; + } + DBfree_result(result); + + return ret; +} + +/****************************************************************************** + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_make(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids, + zbx_vector_ptr_t *host_prototypes) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t itemids; + zbx_host_prototype_t *host_prototype; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&itemids); + + /* selects host prototypes from templates */ + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select hi.itemid,th.hostid,th.host,th.name,th.status,th.discover,th.custom_interfaces," + "hinv.inventory_mode" + " from items hi,items ti,host_discovery thd,hosts th" + " left join host_inventory hinv on hinv.hostid=th.hostid" + " where hi.templateid=ti.itemid" + " and ti.itemid=thd.parent_itemid" + " and thd.hostid=th.hostid" + " and hi.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + host_prototype = (zbx_host_prototype_t *)zbx_malloc(NULL, sizeof(zbx_host_prototype_t)); + + host_prototype->hostid = 0; + ZBX_STR2UINT64(host_prototype->itemid, row[0]); + ZBX_STR2UINT64(host_prototype->templateid, row[1]); + zbx_vector_uint64_create(&host_prototype->lnk_templateids); + zbx_vector_ptr_create(&host_prototype->group_prototypes); + zbx_vector_macros_create(&host_prototype->hostmacros); + zbx_vector_db_tag_ptr_create(&host_prototype->tags); + zbx_vector_db_tag_ptr_create(&host_prototype->new_tags); + zbx_vector_interfaces_create(&host_prototype->interfaces); + host_prototype->host = zbx_strdup(NULL, row[2]); + host_prototype->name = zbx_strdup(NULL, row[3]); + ZBX_STR2UCHAR(host_prototype->status, row[4]); + host_prototype->flags = ZBX_FLAG_HPLINK_RESET_FLAG; + ZBX_STR2UCHAR(host_prototype->discover, row[5]); + ZBX_STR2UCHAR(host_prototype->custom_interfaces, row[6]); + host_prototype->name_orig = NULL; + host_prototype->status_orig = 0; + host_prototype->discover_orig = 0; + host_prototype->templateid_host = 0; + host_prototype->custom_interfaces_orig = 0; + + if (SUCCEED == DBis_null(row[7])) + host_prototype->inventory_mode = HOST_INVENTORY_DISABLED; + else + host_prototype->inventory_mode = (signed char)atoi(row[7]); + + host_prototype->inventory_mode_orig = HOST_INVENTORY_DISABLED; + + zbx_vector_ptr_append(host_prototypes, host_prototype); + zbx_vector_uint64_append(&itemids, host_prototype->itemid); + } + DBfree_result(result); + + if (0 != host_prototypes->values_num) + { + zbx_uint64_t itemid; + unsigned char status; + int i; + + zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + /* selects host prototypes from host */ + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select i.itemid,h.hostid,h.host,h.name,h.status,h.discover,h.custom_interfaces," + "h.templateid,hinv.inventory_mode" + " from items i,host_discovery hd,hosts h" + " left join host_inventory hinv on hinv.hostid=h.hostid" + " where i.itemid=hd.parent_itemid" + " and hd.hostid=h.hostid" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.itemid", itemids.values, itemids.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(itemid, row[0]); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->itemid == itemid && 0 == strcmp(host_prototype->host, row[2])) + { + signed char inventory_mode_null_processed; + + ZBX_STR2UINT64(host_prototype->hostid, row[1]); + + if (0 != strcmp(host_prototype->name, row[3])) + { + host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_NAME; + host_prototype->name_orig = zbx_strdup(NULL, row[3]); + } + + if (host_prototype->status != (status = (unsigned char)atoi(row[4]))) + { + host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_STATUS; + host_prototype->status_orig = status; + } + + if (host_prototype->discover != (unsigned char)atoi(row[5])) + { + host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_DISCOVER; + host_prototype->discover_orig = (unsigned char)atoi(row[5]); + } + + if (host_prototype->custom_interfaces != (unsigned char)atoi(row[6])) + { + host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_CUSTOM_INTERFACES; + host_prototype->custom_interfaces_orig = (unsigned char)atoi(row[6]); + } + + if (SUCCEED == DBis_null(row[8])) + inventory_mode_null_processed = HOST_INVENTORY_DISABLED; + else + inventory_mode_null_processed = (signed char)atoi(row[8]); + + if (host_prototype->inventory_mode != inventory_mode_null_processed) + { + host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_INVENTORY_MODE; + host_prototype->inventory_mode_orig = inventory_mode_null_processed; + } + + ZBX_DBROW2UINT64(host_prototype->templateid_host, row[7]); + + break; + } + } + } + DBfree_result(result); + } + + zbx_free(sql); + + zbx_vector_uint64_destroy(&itemids); + + /* sort by templateid */ + zbx_vector_ptr_sort(host_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Parameters: host_prototypes - [IN/OUT] list of host prototypes * + * should be sorted by templateid * + * del_hosttemplateids - [OUT] list of hosttemplateids which * + * should be deleted * + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_templates_make(zbx_vector_ptr_t *host_prototypes, + zbx_vector_uint64_t *del_hosttemplateids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t hostid, templateid, hosttemplateid; + zbx_host_prototype_t *host_prototype; + int i; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&hostids); + + /* select list of templates which should be linked to host prototypes */ + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + zbx_vector_uint64_append(&hostids, host_prototype->templateid); + } + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,templateid" + " from hosts_templates" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid,templateid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + ZBX_STR2UINT64(templateid, row[1]); + + if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + zbx_vector_uint64_append(&host_prototype->lnk_templateids, templateid); + } + DBfree_result(result); + + /* select list of templates which are already linked to host prototypes */ + + zbx_vector_uint64_clear(&hostids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + continue; + + zbx_vector_uint64_append(&hostids, host_prototype->hostid); + } + + if (0 != hostids.values_num) + { + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,templateid,hosttemplateid" + " from hosts_templates" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hosttemplateid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + ZBX_STR2UINT64(templateid, row[1]); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->hostid == hostid) + { + if (FAIL == (i = zbx_vector_uint64_bsearch(&host_prototype->lnk_templateids, + templateid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + ZBX_STR2UINT64(hosttemplateid, row[2]); + zbx_vector_uint64_append(del_hosttemplateids, hosttemplateid); + + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, + host_prototype->hostid, host_prototype->host); + + zbx_audit_host_prototype_update_json_delete_parent_template( + host_prototype->hostid, hosttemplateid); + } + else + zbx_vector_uint64_remove(&host_prototype->lnk_templateids, i); + + break; + } + } + + if (i == host_prototypes->values_num) + THIS_SHOULD_NEVER_HAPPEN; + } + DBfree_result(result); + } + + zbx_vector_uint64_destroy(&hostids); + + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Parameters: host_prototypes - [IN/OUT] list of host prototypes * + * should be sorted by templateid * + * del_group_prototypeids - [OUT] sorted list of * + * group_prototypeid which should be * + * deleted * + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_groups_make(zbx_vector_ptr_t *host_prototypes, + zbx_vector_uint64_t *del_group_prototypeids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t hostid, groupid, group_prototypeid; + zbx_host_prototype_t *host_prototype; + zbx_group_prototype_t *group_prototype; + int i; + + zbx_vector_uint64_create(&hostids); + + /* select list of groups which should be linked to host prototypes */ + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + zbx_vector_uint64_append(&hostids, host_prototype->templateid); + } + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,name,groupid,group_prototypeid" + " from group_prototype" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + + if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + group_prototype = (zbx_group_prototype_t *)zbx_malloc(NULL, sizeof(zbx_group_prototype_t)); + group_prototype->group_prototypeid = 0; + group_prototype->name = zbx_strdup(NULL, row[1]); + ZBX_DBROW2UINT64(group_prototype->groupid, row[2]); + ZBX_STR2UINT64(group_prototype->templateid, row[3]); + group_prototype->templateid_host = 0; + + zbx_vector_ptr_append(&host_prototype->group_prototypes, group_prototype); + } + DBfree_result(result); + + /* select list of group prototypes which already linked to host prototypes */ + + zbx_vector_uint64_clear(&hostids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + continue; + + zbx_vector_uint64_append(&hostids, host_prototype->hostid); + } + + if (0 != hostids.values_num) + { + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,group_prototypeid,groupid,name,templateid from group_prototype where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by group_prototypeid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->hostid == hostid) + { + int k; + + ZBX_STR2UINT64(group_prototypeid, row[1]); + ZBX_DBROW2UINT64(groupid, row[2]); + + for (k = 0; k < host_prototype->group_prototypes.values_num; k++) + { + group_prototype = (zbx_group_prototype_t *) + host_prototype->group_prototypes.values[k]; + + if (0 != group_prototype->group_prototypeid) + continue; + + if (group_prototype->groupid == groupid && + 0 == strcmp(group_prototype->name, row[3])) + { + zbx_uint64_t templateid_host; + + ZBX_DBROW2UINT64(templateid_host, row[4]); + group_prototype->templateid_host = templateid_host; + group_prototype->group_prototypeid = group_prototypeid; + break; + } + } + + if (k == host_prototype->group_prototypes.values_num) + zbx_vector_uint64_append(del_group_prototypeids, group_prototypeid); + + break; + } + } + + if (i == host_prototypes->values_num) + THIS_SHOULD_NEVER_HAPPEN; + } + DBfree_result(result); + } + + zbx_vector_uint64_sort(del_group_prototypeids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_vector_uint64_destroy(&hostids); + zbx_free(sql); +} + +/****************************************************************************** + * * + * Purpose: validate hostmacros value changes * + * * + * Parameters: hostmacros - [IN/OUT] list of hostmacros * + * hostmacroid - [IN] hostmacro id * + * macro - [IN] hostmacro key * + * value - [IN] hostmacro value * + * description - [IN] hostmacro description * + * type - [IN] hostmacro type * + * * + * Return value: SUCCEED - the host macro was found * + * FAIL - in the other case * + ******************************************************************************/ +static int DBhost_prototypes_macro_make(zbx_vector_macros_t *hostmacros, zbx_uint64_t hostmacroid, + const char *macro, const char *value, const char *description, unsigned char type) +{ + zbx_macros_prototype_t *hostmacro; + int i; + + for (i = 0; i < hostmacros->values_num; i++) + { + hostmacro = hostmacros->values[i]; + + /* check if host macro has already been added */ + if (0 == hostmacro->hostmacroid && 0 == strcmp(hostmacro->macro, macro)) + { + hostmacro->hostmacroid = hostmacroid; + + if (0 != strcmp(hostmacro->value, value)) + { + hostmacro->flags |= ZBX_FLAG_HPMACRO_UPDATE_VALUE; + hostmacro->value_orig = zbx_strdup(NULL, value); + } + + if (0 != strcmp(hostmacro->description, description)) + { + hostmacro->flags |= ZBX_FLAG_HPMACRO_UPDATE_DESCRIPTION; + hostmacro->description_orig = zbx_strdup(NULL, description); + } + + if (hostmacro->type != type) + { + hostmacro->flags |= ZBX_FLAG_HPMACRO_UPDATE_TYPE; + hostmacro->type_orig = type; + } + + return SUCCEED; + } + } + + return FAIL; +} + +/****************************************************************************** + * * + * Purpose: fill empty value in interfaces with input parameters * + * * + * Parameters: interfaces - [IN/OUT] list of host interfaces * + * interfaceid - [IN] interface id * + * del_snmp_ids - [IN/OUT] list of SNMP interfaces to delete * + * ifmain - [IN] interface main * + * type - [IN] interface type * + * useip - [IN] interface useip * + * ip - [IN] interface ip * + * dns - [IN] interface dns * + * port - [IN] interface port * + * snmp_type - [IN] interface_snmp version * + * bulk - [IN] interface_snmp bulk * + * community - [IN] interface_snmp community * + * securityname - [IN] interface_snmp securityname * + * securitylevel - [IN] interface_snmp securitylevel * + * authpassphrase - [IN] interface_snmp authpassphrase * + * privpassphrase - [IN] interface_snmp privpassphrase * + * authprotocol - [IN] interface_snmp authprotocol * + * privprotocol - [IN] interface_snmp privprotocol * + * contextname - [IN] interface_snmp contextname * + * * + * Return value: SUCCEED - the host interface was found * + * FAIL - in the other case * + ******************************************************************************/ +static int DBhost_prototypes_interface_make(zbx_vector_interfaces_t *interfaces, zbx_uint64_t interfaceid, + zbx_vector_uint64_t *del_snmp_ids, unsigned char ifmain, unsigned char type, unsigned char useip, + const char *ip, const char *dns, const char *port, unsigned char snmp_type, unsigned char bulk, + const char *community, const char *securityname, unsigned char securitylevel, + const char *authpassphrase, const char *privpassphrase, unsigned char authprotocol, + unsigned char privprotocol, const char *contextname) +{ + zbx_interfaces_prototype_t *interface; + int i; + + for (i = 0; i < interfaces->values_num; i++) + { + interface = interfaces->values[i]; + + if (0 == interface->interfaceid) + { + interface->interfaceid = interfaceid; + + if (interface->main != ifmain) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_MAIN; + interface->main_orig = ifmain; + } + + if (interface->type != type) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_TYPE; + interface->type_orig = type; + } + + if (interface->useip != useip) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_USEIP; + interface->useip_orig = useip; + } + + if (0 != strcmp(interface->ip, ip)) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_IP; + interface->ip_orig = zbx_strdup(NULL, ip); + } + + if (0 != strcmp(interface->dns, dns)) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_DNS; + interface->dns_orig = zbx_strdup(NULL, dns); + } + + if (0 != strcmp(interface->port, port)) + { + interface->flags |= ZBX_FLAG_HPINTERFACE_UPDATE_PORT; + interface->port_orig = zbx_strdup(NULL, port); + } + + if (INTERFACE_TYPE_SNMP == interface->type) + { + zbx_interface_prototype_snmp_t *snmp = interface->data.snmp; + + if (INTERFACE_TYPE_SNMP == type) + { + if (snmp->version != snmp_type) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_TYPE; + snmp->version_orig = snmp_type; + } + + if (snmp->bulk != bulk) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_BULK; + snmp->bulk_orig = bulk; + } + + if (0 != strcmp(snmp->community, community)) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_COMMUNITY; + snmp->community_orig = zbx_strdup(NULL, community); + } + + if (0 != strcmp(snmp->securityname, securityname)) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECNAME; + snmp->securityname_orig = zbx_strdup(NULL, securityname); + } + + if (snmp->securitylevel != securitylevel) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECLEVEL; + snmp->securitylevel_orig = securitylevel; + } + + if (0 != strcmp(snmp->authpassphrase, authpassphrase)) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPASS; + snmp->authpassphrase_orig = zbx_strdup(NULL, authpassphrase); + } + + if (0 != strcmp(snmp->privpassphrase, privpassphrase)) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPASS; + snmp->privpassphrase_orig = zbx_strdup(NULL, privpassphrase); + } + + if (snmp->authprotocol != authprotocol) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPROTOCOL; + snmp->authprotocol_orig = authprotocol; + } + + if (snmp->privprotocol != privprotocol) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPROTOCOL; + snmp->privprotocol_orig = privprotocol; + } + + if (0 != strcmp(snmp->contextname, contextname)) + { + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_CONTEXT; + snmp->contextname_orig = zbx_strdup(NULL, contextname); + } + } + else + snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_CREATE; + } + else if (INTERFACE_TYPE_SNMP == type) + { + zbx_vector_uint64_append(del_snmp_ids, interfaceid); + } + + return SUCCEED; + } + } + + return FAIL; +} + +/****************************************************************************** + * * + * Parameters: host_prototypes - [IN/OUT] list of host prototypes * + * should be sorted by templateid * + * del_macroids - [OUT] sorted list of host macroids which * + * should be deleted * + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_macros_make(zbx_vector_ptr_t *host_prototypes, zbx_vector_uint64_t *del_macroids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t hostid, hostmacroid; + zbx_host_prototype_t *host_prototype; + zbx_macros_prototype_t *hostmacro; + int i; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&hostids); + + /* select list of macros prototypes which should be linked to host prototypes */ + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + zbx_vector_uint64_append(&hostids, host_prototype->templateid); + } + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,macro,value,description,type,automatic" + " from hostmacro" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid"); + + result = DBselect("%s", sql); + host_prototype = NULL; + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + + if (NULL == host_prototype || host_prototype->templateid != hostid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + } + + hostmacro = (zbx_macros_prototype_t *)zbx_malloc(NULL, sizeof(zbx_macros_prototype_t)); + hostmacro->hostmacroid = 0; + hostmacro->macro = zbx_strdup(NULL, row[1]); + hostmacro->value = zbx_strdup(NULL, row[2]); + hostmacro->description = zbx_strdup(NULL, row[3]); + ZBX_STR2UCHAR(hostmacro->type, row[4]); + ZBX_STR2UCHAR(hostmacro->automatic, row[5]); + hostmacro->flags = ZBX_FLAG_HPMACRO_RESET_FLAG; + hostmacro->value_orig = NULL; + hostmacro->description_orig = NULL; + hostmacro->type_orig = 0; + + zbx_vector_macros_append(&host_prototype->hostmacros, hostmacro); + } + DBfree_result(result); + + /* select list of macros prototypes which already linked to host prototypes */ + + zbx_vector_uint64_clear(&hostids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + continue; + + zbx_vector_uint64_append(&hostids, host_prototype->hostid); + } + + if (0 != hostids.values_num) + { + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostmacroid,hostid,macro,value,description,type from hostmacro where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[1]); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->hostid == hostid) + { + unsigned char type; + + ZBX_STR2UINT64(hostmacroid, row[0]); + ZBX_STR2UCHAR(type, row[5]); + + if (FAIL == DBhost_prototypes_macro_make(&host_prototype->hostmacros, + hostmacroid, row[2], row[3], row[4], type)) + { + zbx_vector_uint64_append(del_macroids, hostmacroid); + + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, + host_prototype->hostid, host_prototype->host); + + zbx_audit_host_prototype_update_json_delete_hostmacro( + host_prototype->hostid, hostmacroid); + } + + break; + } + } + + if (i == host_prototypes->values_num) + THIS_SHOULD_NEVER_HAPPEN; + } + DBfree_result(result); + } + + zbx_vector_uint64_sort(del_macroids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_vector_uint64_destroy(&hostids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Parameters: host_prototypes - [IN/OUT] list of host prototypes * + * should be sorted by templateid * + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_tags_make(zbx_vector_ptr_t *host_prototypes) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t hostid; + zbx_host_prototype_t *host_prototype = NULL; + zbx_db_tag_t *tag; + int i; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&hostids); + + /* get template host prototype tags that must be added to host prototypes */ + + for (i = 0; i < host_prototypes->values_num; i++) + zbx_vector_uint64_append(&hostids, ((zbx_host_prototype_t *)host_prototypes->values[i])->templateid); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hostid,tag,value" + " from host_tag" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + + if (NULL == host_prototype || host_prototype->templateid != hostid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + } + + tag = zbx_db_tag_create(row[1], row[2]); + zbx_vector_db_tag_ptr_append(&host_prototype->new_tags, tag); + } + DBfree_result(result); + + /* get tags of existing host prototypes */ + + zbx_vector_uint64_clear(&hostids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + continue; + + zbx_vector_uint64_append(&hostids, host_prototype->hostid); + } + + if (0 != hostids.values_num) + { + host_prototype = NULL; + + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hosttagid,hostid,tag,value from host_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid"); + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_DBROW2UINT64(hostid, row[1]); + + if (NULL == host_prototype || host_prototype->hostid != hostid) + { + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->hostid == hostid) + break; + } + + if (NULL == host_prototype || host_prototype->hostid != hostid) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + } + + tag = zbx_db_tag_create(row[2], row[3]); + ZBX_DBROW2UINT64(tag->tagid, row[0]); + zbx_vector_db_tag_ptr_append(&host_prototype->tags, tag); + } + DBfree_result(result); + } + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + (void)zbx_merge_tags(&host_prototype->tags, &host_prototype->new_tags, NULL, NULL); + } + + zbx_vector_uint64_destroy(&hostids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: prepare interfaces to be added, updated or removed from DB * + * Parameters: host_prototypes - [IN/OUT] list of host prototypes * + * should be sorted by templateid * + * del_interfaceids - [OUT] sorted list of host interface * + * ids which should be deleted * + * del_snmp_interfaceids - [OUT] sorted list of host snmp * + * interface ids which should be * + * deleted * + * * + * Comments: auxiliary function for DBcopy_template_host_prototypes() * + * * + ******************************************************************************/ +static void DBhost_prototypes_interfaces_make(zbx_vector_ptr_t *host_prototypes, + zbx_vector_uint64_t *del_interfaceids, zbx_vector_uint64_t *del_snmp_interfaceids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t hostid; + zbx_host_prototype_t *host_prototype; + zbx_interfaces_prototype_t *interface; + int i; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&hostids); + + /* select list of interfaces which should be linked to host prototypes */ + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + zbx_vector_uint64_append(&hostids, host_prototype->templateid); + } + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hi.hostid,hi.main,hi.type,hi.useip,hi.ip,hi.dns,hi.port,s.version,s.bulk,s.community," + "s.securityname,s.securitylevel,s.authpassphrase,s.privpassphrase,s.authprotocol," + "s.privprotocol,s.contextname" + " from interface hi" + " left join interface_snmp s" + " on hi.interfaceid=s.interfaceid" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hi.hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hi.hostid"); + + result = DBselect("%s", sql); + host_prototype = NULL; + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[0]); + + if (NULL == host_prototype || host_prototype->templateid != hostid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + } + + interface = (zbx_interfaces_prototype_t *)zbx_malloc(NULL, sizeof(zbx_interfaces_prototype_t)); + interface->interfaceid = 0; + ZBX_STR2UCHAR(interface->main, row[1]); + ZBX_STR2UCHAR(interface->type, row[2]); + ZBX_STR2UCHAR(interface->useip, row[3]); + interface->ip = zbx_strdup(NULL, row[4]); + interface->dns = zbx_strdup(NULL, row[5]); + interface->port = zbx_strdup(NULL, row[6]); + interface->flags = ZBX_FLAG_HPINTERFACE_RESET_FLAG; + interface->main_orig = 0; + interface->type_orig = 0; + interface->useip_orig = 0; + interface->ip_orig = NULL; + interface->dns_orig = NULL; + interface->port_orig = NULL; + + if (INTERFACE_TYPE_SNMP == interface->type) + { + zbx_interface_prototype_snmp_t *snmp; + + snmp = (zbx_interface_prototype_snmp_t *)zbx_malloc(NULL, + sizeof(zbx_interface_prototype_snmp_t)); + ZBX_STR2UCHAR(snmp->version, row[7]); + ZBX_STR2UCHAR(snmp->bulk, row[8]); + snmp->community = zbx_strdup(NULL, row[9]); + snmp->securityname = zbx_strdup(NULL, row[10]); + ZBX_STR2UCHAR(snmp->securitylevel, row[11]); + snmp->authpassphrase = zbx_strdup(NULL, row[12]); + snmp->privpassphrase = zbx_strdup(NULL, row[13]); + ZBX_STR2UCHAR(snmp->authprotocol, row[14]); + ZBX_STR2UCHAR(snmp->privprotocol, row[15]); + snmp->contextname = zbx_strdup(NULL, row[16]); + snmp->flags = ZBX_FLAG_HPINTERFACE_SNMP_RESET_FLAG; + interface->data.snmp = snmp; + snmp->community_orig = NULL; + snmp->securityname_orig = NULL; + snmp->authpassphrase_orig = NULL; + snmp->privpassphrase_orig = NULL; + snmp->contextname_orig = NULL; + snmp->securitylevel_orig = 0; + snmp->authprotocol_orig = 0; + snmp->privprotocol_orig = 0; + snmp->version_orig = 0; + snmp->bulk_orig = 0; + } + else + interface->data.snmp = NULL; + + zbx_vector_interfaces_append(&host_prototype->interfaces, interface); + } + DBfree_result(result); + + /* select list of interfaces which are already linked to host prototypes */ + + zbx_vector_uint64_clear(&hostids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + /* host prototype is not saved yet */ + if (0 == host_prototype->hostid) + continue; + + zbx_vector_uint64_append(&hostids, host_prototype->hostid); + } + + if (0 != hostids.values_num) + { + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hi.interfaceid,hi.hostid,hi.main,hi.type,hi.useip,hi.ip,hi.dns,hi.port," + "s.version,s.bulk,s.community,s.securityname,s.securitylevel,s.authpassphrase," + "s.privpassphrase,s.authprotocol,s.privprotocol,s.contextname" + " from interface hi" + " left join interface_snmp s" + " on hi.interfaceid=s.interfaceid" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hi.hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hi.hostid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(hostid, row[1]); + + for (i = 0; i < host_prototypes->values_num; i++) + { + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (host_prototype->hostid == hostid) + { + unsigned char type; + uint64_t interfaceid; + + ZBX_STR2UINT64(interfaceid, row[0]); + ZBX_STR2UCHAR(type, row[3]); + + if (INTERFACE_TYPE_SNMP == type) + { + if (FAIL == DBhost_prototypes_interface_make( + &host_prototype->interfaces, interfaceid, + del_snmp_interfaceids, + (unsigned char)atoi(row[2]), /* main */ + type, + (unsigned char)atoi(row[4]), /* useip */ + row[5], /* ip */ + row[6], /* dns */ + row[7], /* port */ + (unsigned char)atoi(row[8]), /* version */ + (unsigned char)atoi(row[9]), /* bulk */ + row[10], /* community */ + row[11], /* securityname */ + (unsigned char)atoi(row[12]), /* securitylevel */ + row[13], /* authpassphrase */ + row[14], /* privpassphrase */ + (unsigned char)atoi(row[15]), /* authprotocol */ + (unsigned char)atoi(row[16]), /* privprotocol */ + row[17])) /* contextname */ + { + zbx_vector_uint64_append(del_interfaceids, interfaceid); + + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, + host_prototype->hostid, host_prototype->host); + + zbx_audit_host_prototype_update_json_delete_interface( + host_prototype->hostid, interfaceid); + } + } + else + { + if (FAIL == DBhost_prototypes_interface_make( + &host_prototype->interfaces, interfaceid, + del_snmp_interfaceids, + (unsigned char)atoi(row[2]), /* main */ + type, + (unsigned char)atoi(row[4]), /* useip */ + row[5], /* ip */ + row[6], /* dns */ + row[7], /* port */ + 0, 0, NULL, NULL, 0, NULL, NULL, 0, 0, NULL)) + { + zbx_vector_uint64_append(del_interfaceids, interfaceid); + + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, + host_prototype->hostid, host_prototype->host); + + zbx_audit_host_prototype_update_json_delete_interface( + host_prototype->hostid, interfaceid); + } + } + + break; + } + } + + /* no interfaces found for this host prototype, but there must be at least one */ + if (i == host_prototypes->values_num) + THIS_SHOULD_NEVER_HAPPEN; + } + DBfree_result(result); + } + + zbx_vector_uint64_sort(del_interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_sort(del_snmp_interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_vector_uint64_destroy(&hostids); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: prepare sql for update record of interface_snmp table * + * * + * Parameters: hostid - [IN] host identifier * + * interfaceid - [IN] snmp interface id; * + * snmp - [IN] snmp interface prototypes for update * + * sql - [IN/OUT] sql string * + * sql_alloc - [IN/OUT] size of sql string * + * sql_offset - [IN/OUT] offset in sql string * + * * + ******************************************************************************/ +static void DBhost_prototypes_interface_snmp_prepare_sql(zbx_uint64_t hostid, const zbx_uint64_t interfaceid, + const zbx_interface_prototype_snmp_t *snmp, char **sql, size_t *sql_alloc, size_t *sql_offset) +{ + const char *d = ""; + char *esc; + + zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update interface_snmp set "); + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_TYPE)) + { + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "version=%d", (int)snmp->version); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_version(hostid, interfaceid, + snmp->version_orig, snmp->version); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_BULK)) + { + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sbulk=%d", d, (int)snmp->bulk); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_bulk(hostid, interfaceid, snmp->bulk_orig, + snmp->bulk); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_COMMUNITY)) + { + esc = DBdyn_escape_string(snmp->community); + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%scommunity='%s'", d, esc); + zbx_free(esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_community(hostid, interfaceid, + snmp->community_orig, snmp->community); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECNAME)) + { + esc = DBdyn_escape_string(snmp->securityname); + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%ssecurityname='%s'", d, esc); + zbx_free(esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_securityname(hostid, interfaceid, + snmp->securityname_orig, snmp->securityname); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_SECLEVEL)) + { + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%ssecuritylevel=%d", d, (int)snmp->securitylevel); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_securitylevel(hostid, interfaceid, + snmp->securitylevel_orig, snmp->securitylevel); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPASS)) + { + esc = DBdyn_escape_string(snmp->authpassphrase); + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sauthpassphrase='%s'", d, esc); + zbx_free(esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_authpassphrase(hostid, interfaceid, + snmp->authpassphrase_orig, snmp->authpassphrase); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPASS)) + { + esc = DBdyn_escape_string(snmp->privpassphrase); + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sprivpassphrase='%s'", d, esc); + zbx_free(esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_privpassphrase(hostid, interfaceid, + snmp->privpassphrase_orig, snmp->privpassphrase); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_AUTHPROTOCOL)) + { + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sauthprotocol=%d", d, (int)snmp->authprotocol); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_authprotocol(hostid, interfaceid, + snmp->authprotocol_orig, snmp->authprotocol); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_PRIVPROTOCOL)) + { + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sprivprotocol=%d", d, (int)snmp->privprotocol); + d = ","; + + zbx_audit_host_prototype_update_json_update_interface_privprotocol(hostid, interfaceid, + snmp->privprotocol_orig, snmp->privprotocol); + } + + if (0 != (snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE_CONTEXT)) + { + esc = DBdyn_escape_string(snmp->contextname); + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%scontextname='%s'", d, esc); + zbx_free(esc); + + zbx_audit_host_prototype_update_json_update_interface_contextname(hostid, interfaceid, + snmp->contextname_orig, snmp->contextname); + } + + zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where interfaceid=" ZBX_FS_UI64 ";\n", interfaceid); + + DBexecute_overflowed_sql(sql, sql_alloc, sql_offset); +} + +/****************************************************************************** + * * + * Purpose: auxiliary function for DBcopy_template_host_prototypes() * + * * + * Parameters: host_prototypes - [IN] vector of host prototypes * + * del_hosttemplateids - [IN] host template ids for delete * + * del_hostmacroids - [IN] host macro ids for delete * + * del_interfaceids - [IN] interface ids for delete * + * del_snmpids - [IN] SNMP interface ids for delete * + * db_insert_htemplates - [IN/OUT] templates insert structure * + * * + ******************************************************************************/ +static void DBhost_prototypes_save(const zbx_vector_ptr_t *host_prototypes, + const zbx_vector_uint64_t *del_hosttemplateids, const zbx_vector_uint64_t *del_hostmacroids, + const zbx_vector_uint64_t *del_interfaceids, const zbx_vector_uint64_t *del_snmpids, + zbx_db_insert_t *db_insert_htemplates) +{ + char *sql1 = NULL, *sql2 = NULL, *name_esc, *value_esc; + size_t sql1_alloc = ZBX_KIBIBYTE, sql1_offset = 0, + sql2_alloc = ZBX_KIBIBYTE, sql2_offset = 0; + const zbx_group_prototype_t *group_prototype; + const zbx_macros_prototype_t *hostmacro; + zbx_interfaces_prototype_t *interface; + zbx_uint64_t hostid = 0, hosttemplateid = 0, group_prototypeid = 0, new_hostmacroid = 0, + hosttagid = 0, interfaceid = 0; + int i, j, new_hosts = 0, new_hosts_templates = 0, new_group_prototypes = 0, + upd_group_prototypes = 0, new_hostmacros = 0, upd_hostmacros = 0, + new_tags = 0, new_interfaces = 0, upd_interfaces = 0, new_snmp = 0, + upd_snmp = 0, new_inventory_modes = 0, upd_inventory_modes = 0, res = SUCCEED; + zbx_db_insert_t db_insert, db_insert_hdiscovery, db_insert_gproto, + db_insert_hmacro, db_insert_tag, db_insert_iface, db_insert_snmp, + db_insert_inventory_mode; + zbx_vector_db_tag_ptr_t upd_tags; + zbx_vector_uint64_t del_inventory_modes_hostids, del_tagids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_db_tag_ptr_create(&upd_tags); + zbx_vector_uint64_create(&del_inventory_modes_hostids); + zbx_vector_uint64_create(&del_tagids); + + for (i = 0; i < host_prototypes->values_num; i++) + { + const zbx_host_prototype_t *host_prototype; + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + { + new_hosts++; + + if (HOST_INVENTORY_DISABLED != host_prototype->inventory_mode) + new_inventory_modes++; + } + else + { + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, host_prototype->hostid, + host_prototype->host); + + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_INVENTORY_MODE)) + { + if (HOST_INVENTORY_DISABLED == host_prototype->inventory_mode) + zbx_vector_uint64_append(&del_inventory_modes_hostids, host_prototype->hostid); + else if (HOST_INVENTORY_DISABLED == host_prototype->inventory_mode_orig) + new_inventory_modes++; + else + upd_inventory_modes++; + } + } + + new_hosts_templates += host_prototype->lnk_templateids.values_num; + + for (j = 0; j < host_prototype->group_prototypes.values_num; j++) + { + group_prototype = (zbx_group_prototype_t *)host_prototype->group_prototypes.values[j]; + + if (0 == group_prototype->group_prototypeid) + new_group_prototypes++; + else + upd_group_prototypes++; + } + + for (j = 0; j < host_prototype->hostmacros.values_num; j++) + { + hostmacro = host_prototype->hostmacros.values[j]; + + if (0 == hostmacro->hostmacroid) + new_hostmacros++; + else if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE)) + upd_hostmacros++; + } + + for (j = 0; j < host_prototype->tags.values_num; j++) + { + zbx_db_tag_t *tag = host_prototype->tags.values[j]; + + if (0 == tag->tagid) + { + new_tags++; + } + else if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE)) + { + zbx_vector_db_tag_ptr_append(&upd_tags, tag); + + zbx_audit_host_prototype_update_json_update_tag_create_entry(host_prototype->hostid, + tag->tagid); + + if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_TAG)) + { + zbx_audit_host_prototype_update_json_update_tag_tag(host_prototype->hostid, + tag->tagid, tag->tag_orig, tag->tag); + } + + if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_VALUE)) + { + zbx_audit_host_prototype_update_json_update_tag_value(host_prototype->hostid, + tag->tagid, tag->value_orig, tag->value); + } + } + else if (ZBX_FLAG_DB_TAG_REMOVE == tag->flags) + { + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_UPDATE, host_prototype->hostid, + host_prototype->host); + zbx_audit_host_prototype_update_json_delete_tag(host_prototype->hostid, tag->tagid); + zbx_vector_uint64_append(&del_tagids, tag->tagid); + } + } + + for (j = 0; j < host_prototype->interfaces.values_num; j++) + { + interface = host_prototype->interfaces.values[j]; + + if (0 == interface->interfaceid) + new_interfaces++; + else if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE)) + upd_interfaces++; + + if (INTERFACE_TYPE_SNMP == interface->type) + { + if (0 == interface->interfaceid) + interface->data.snmp->flags |= ZBX_FLAG_HPINTERFACE_SNMP_CREATE; + + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_CREATE)) + new_snmp++; + else if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE)) + upd_snmp++; + } + } + } + + if (0 != new_hosts) + { + hostid = DBget_maxid_num("hosts", new_hosts); + + zbx_db_insert_prepare(&db_insert, "hosts", "hostid", "host", "name", "status", "flags", "templateid", + "discover", "custom_interfaces", NULL); + + zbx_db_insert_prepare(&db_insert_hdiscovery, "host_discovery", "hostid", "parent_itemid", NULL); + } + + if (new_hosts != host_prototypes->values_num || 0 != upd_group_prototypes || 0 != upd_hostmacros || + 0 != upd_tags.values_num) + { + sql1 = (char *)zbx_malloc(sql1, sql1_alloc); + zbx_DBbegin_multiple_update(&sql1, &sql1_alloc, &sql1_offset); + } + + if (0 != new_hosts_templates) + hosttemplateid = DBget_maxid_num("hosts_templates", new_hosts_templates); + + if (0 != del_hosttemplateids->values_num || 0 != del_hostmacroids->values_num || 0 != del_tagids.values_num || + 0 != del_snmpids->values_num || 0 != del_interfaceids->values_num || + 0 != del_inventory_modes_hostids.values_num) + { + sql2 = (char *)zbx_malloc(sql2, sql2_alloc); + zbx_DBbegin_multiple_update(&sql2, &sql2_alloc, &sql2_offset); + } + + if (0 != del_hosttemplateids->values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hosts_templates where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hosttemplateid", + del_hosttemplateids->values, del_hosttemplateids->values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != del_hostmacroids->values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hostmacro where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostmacroid", + del_hostmacroids->values, del_hostmacroids->values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != del_tagids.values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_tag where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hosttagid", del_tagids.values, + del_tagids.values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != del_snmpids->values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface_snmp where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid", + del_snmpids->values, del_snmpids->values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != del_interfaceids->values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid", + del_interfaceids->values, del_interfaceids->values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != del_inventory_modes_hostids.values_num) + { + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_inventory where"); + DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid", + del_inventory_modes_hostids.values, del_inventory_modes_hostids.values_num); + zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n"); + } + + if (0 != new_group_prototypes) + { + group_prototypeid = DBget_maxid_num("group_prototype", new_group_prototypes); + + zbx_db_insert_prepare(&db_insert_gproto, "group_prototype", "group_prototypeid", "hostid", "name", + "groupid", "templateid", NULL); + } + + if (0 != new_hostmacros) + { + new_hostmacroid = DBget_maxid_num("hostmacro", new_hostmacros); + + zbx_db_insert_prepare(&db_insert_hmacro, "hostmacro", "hostmacroid", "hostid", "macro", "value", + "description", "type", "automatic", NULL); + } + + if (0 != new_tags) + { + hosttagid = DBget_maxid_num("host_tag", new_tags); + + zbx_db_insert_prepare(&db_insert_tag, "host_tag", "hosttagid", "hostid", "tag", "value", "automatic", + NULL); + } + + if (0 != new_interfaces) + { + interfaceid = DBget_maxid_num("interface", new_interfaces); + + zbx_db_insert_prepare(&db_insert_iface, "interface", "interfaceid", "hostid", "main", "type", + "useip", "ip", "dns", "port", NULL); + } + + if (0 != new_snmp) + { + zbx_db_insert_prepare(&db_insert_snmp, "interface_snmp", "interfaceid", "version", "bulk", "community", + "securityname", "securitylevel", "authpassphrase", "privpassphrase", "authprotocol", + "privprotocol", "contextname", NULL); + } + + if (0 != new_inventory_modes) + zbx_db_insert_prepare(&db_insert_inventory_mode, "host_inventory", "hostid", "inventory_mode", NULL); + + for (i = 0; i < host_prototypes->values_num; i++) + { + zbx_host_prototype_t *host_prototype; + + host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i]; + + if (0 == host_prototype->hostid) + { + host_prototype->hostid = hostid++; + + zbx_db_insert_add_values(&db_insert, host_prototype->hostid, host_prototype->host, + host_prototype->name, (int)host_prototype->status, + (int)ZBX_FLAG_DISCOVERY_PROTOTYPE, host_prototype->templateid, + (int)host_prototype->discover, (int)host_prototype->custom_interfaces); + + zbx_audit_host_prototype_create_entry(ZBX_AUDIT_ACTION_ADD, host_prototype->hostid, + host_prototype->host); + + zbx_db_insert_add_values(&db_insert_hdiscovery, host_prototype->hostid, host_prototype->itemid); + + if (HOST_INVENTORY_DISABLED != host_prototype->inventory_mode) + { + zbx_db_insert_add_values(&db_insert_inventory_mode, host_prototype->hostid, + host_prototype->inventory_mode); + } + + zbx_audit_host_prototype_update_json_add_details(host_prototype->hostid, + host_prototype->templateid, host_prototype->name, (int)host_prototype->status, + (int)host_prototype->discover, (int)host_prototype->custom_interfaces, + host_prototype->inventory_mode); + } + else + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hosts set templateid=" ZBX_FS_UI64, + host_prototype->templateid); + + zbx_audit_host_prototype_update_json_update_templateid(host_prototype->hostid, + host_prototype->templateid_host, host_prototype->templateid); + + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_NAME)) + { + name_esc = DBdyn_escape_string(host_prototype->name); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",name='%s'", name_esc); + zbx_audit_host_prototype_update_json_update_name(host_prototype->hostid, + host_prototype->name_orig, name_esc); + zbx_free(name_esc); + } + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_STATUS)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",status=%d", + host_prototype->status); + zbx_audit_host_prototype_update_json_update_status(host_prototype->hostid, + host_prototype->status_orig, host_prototype->status); + } + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_DISCOVER)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",discover=%d", + host_prototype->discover); + zbx_audit_host_prototype_update_json_update_discover(host_prototype->hostid, + host_prototype->discover_orig, host_prototype->discover); + } + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_CUSTOM_INTERFACES)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",custom_interfaces=%d", + host_prototype->custom_interfaces); + zbx_audit_host_prototype_update_json_update_custom_interfaces(host_prototype->hostid, + host_prototype->custom_interfaces_orig, + host_prototype->custom_interfaces); + } + + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, " where hostid=" ZBX_FS_UI64 ";\n", + host_prototype->hostid); + + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, &sql1_offset))) + break; + + if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_INVENTORY_MODE)) + { + /* new host inventory value which is HOST_INVENTORY_DISABLED is handled later */ + if (HOST_INVENTORY_DISABLED != host_prototype->inventory_mode) + { + if (HOST_INVENTORY_DISABLED == host_prototype->inventory_mode_orig) + { + zbx_db_insert_add_values(&db_insert_inventory_mode, + host_prototype->hostid, host_prototype->inventory_mode); + } + else + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, + "update host_inventory set inventory_mode=%d" + " where hostid=" ZBX_FS_UI64 ";\n", + host_prototype->inventory_mode, host_prototype->hostid); + + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, + &sql1_offset))) + { + break; + } + } + } + + zbx_audit_host_prototype_update_json_update_inventory_mode(host_prototype->hostid, + (int)host_prototype->inventory_mode_orig, + (int)host_prototype->inventory_mode); + } + } + + for (j = 0; j < host_prototype->lnk_templateids.values_num; j++) + { + zbx_db_insert_add_values(db_insert_htemplates, hosttemplateid, host_prototype->hostid, + host_prototype->lnk_templateids.values[j]); + + zbx_audit_host_prototype_update_json_add_parent_template(host_prototype->hostid, hosttemplateid, + host_prototype->lnk_templateids.values[j], ZBX_TEMPLATE_LINK_MANUAL); + + hosttemplateid++; + } + + for (j = 0; j < host_prototype->group_prototypes.values_num; j++) + { + group_prototype = (zbx_group_prototype_t *)host_prototype->group_prototypes.values[j]; + + if (0 == group_prototype->group_prototypeid) + { + zbx_db_insert_add_values(&db_insert_gproto, group_prototypeid, host_prototype->hostid, + group_prototype->name, group_prototype->groupid, + group_prototype->templateid); + + zbx_audit_host_prototype_update_json_add_group_details(host_prototype->hostid, + group_prototypeid, group_prototype->name, group_prototype->groupid, + group_prototype->templateid); + + group_prototypeid++; + } + else + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, + "update group_prototype" + " set templateid=" ZBX_FS_UI64 + " where group_prototypeid=" ZBX_FS_UI64 ";\n", + group_prototype->templateid, group_prototype->group_prototypeid); + + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, &sql1_offset))) + break; + + zbx_audit_host_prototype_update_json_update_group_details(host_prototype->hostid, + group_prototype->group_prototypeid, group_prototype->name, + group_prototype->groupid, group_prototype->templateid_host, + group_prototype->templateid); + } + } + + for (j = 0; j < host_prototype->hostmacros.values_num; j++) + { + hostmacro = host_prototype->hostmacros.values[j]; + + if (0 == hostmacro->hostmacroid) + { + zbx_db_insert_add_values(&db_insert_hmacro, new_hostmacroid, host_prototype->hostid, + hostmacro->macro, hostmacro->value, hostmacro->description, + (int)hostmacro->type, (int)hostmacro->automatic); + + zbx_audit_host_prototype_update_json_add_hostmacro(host_prototype->hostid, + new_hostmacroid, hostmacro->macro, (ZBX_MACRO_VALUE_SECRET == + (int)hostmacro->type) ? ZBX_MACRO_SECRET_MASK : hostmacro->value, + hostmacro->description, (int)hostmacro->type, + (int)hostmacro->automatic); + new_hostmacroid++; + } + else if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE)) + { + const char *d = ""; + + zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hostmacro set "); + + zbx_audit_host_prototype_update_json_update_hostmacro_create_entry( + host_prototype->hostid, hostmacro->hostmacroid); + + if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_VALUE)) + { + value_esc = DBdyn_escape_string(hostmacro->value); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "value='%s'", value_esc); + zbx_free(value_esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_hostmacro_value( + host_prototype->hostid, hostmacro->hostmacroid, + ((0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_TYPE) && + ZBX_MACRO_VALUE_SECRET == (int)hostmacro->type_orig) || + (0 == (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_TYPE) && + ZBX_MACRO_VALUE_SECRET == (int)hostmacro->type)) ? + ZBX_MACRO_SECRET_MASK : hostmacro->value_orig, + (ZBX_MACRO_VALUE_SECRET == (int)hostmacro->type) ? + ZBX_MACRO_SECRET_MASK : hostmacro->value); + } + + if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_DESCRIPTION)) + { + value_esc = DBdyn_escape_string(hostmacro->description); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdescription='%s'", + d, value_esc); + zbx_free(value_esc); + d = ","; + + zbx_audit_host_prototype_update_json_update_hostmacro_description( + host_prototype->hostid, hostmacro->hostmacroid, + hostmacro->description_orig, hostmacro->description); + } + + if (0 != (hostmacro->flags & ZBX_FLAG_HPMACRO_UPDATE_TYPE)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%stype=%d", + d, hostmacro->type); + + zbx_audit_host_prototype_update_json_update_hostmacro_type( + host_prototype->hostid, hostmacro->hostmacroid, + hostmacro->type_orig, hostmacro->type); + } + + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, + " where hostmacroid=" ZBX_FS_UI64 ";\n", hostmacro->hostmacroid); + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, &sql1_offset))) + break; + } + } + + for (j = 0; j < host_prototype->tags.values_num; j++) + { + zbx_db_tag_t *tag = host_prototype->tags.values[j]; + + if (0 == tag->tagid) + { + zbx_db_insert_add_values(&db_insert_tag, hosttagid, host_prototype->hostid, + tag->tag, tag->value, ZBX_DB_TAG_NORMAL); + + zbx_audit_host_prototype_update_json_add_tag(host_prototype->hostid, hosttagid, + tag->tag, tag->value, ZBX_DB_TAG_NORMAL); + + hosttagid++; + } + } + + for (j = 0; j < host_prototype->interfaces.values_num; j++) + { + interface = host_prototype->interfaces.values[j]; + + if (0 == interface->interfaceid) + { + interface->interfaceid = interfaceid++; + zbx_db_insert_add_values(&db_insert_iface, interface->interfaceid, + host_prototype->hostid, (int)interface->main, (int)interface->type, + (int)interface->useip, interface->ip, interface->dns, interface->port); + + zbx_audit_host_prototype_update_json_add_interfaces(host_prototype->hostid, + interface->interfaceid, interface->main, interface->type, + interface->useip, interface->ip, interface->dns, atoi(interface->port)); + } + else if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE)) + { + const char *d = ""; + + zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update interface set "); + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_MAIN)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%smain=%d", d, + interface->main); + d = ","; + zbx_audit_host_prototype_update_json_update_interface_main( + host_prototype->hostid, interface->interfaceid, + interface->main_orig, interface->main); + } + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_TYPE)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%stype=%d", d, + interface->type); + d = ","; + zbx_audit_host_prototype_update_json_update_interface_type( + host_prototype->hostid, interface->interfaceid, + interface->type_orig, interface->type); + } + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_USEIP)) + { + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%suseip=%d", d, + interface->useip); + d = ","; + zbx_audit_host_prototype_update_json_update_interface_useip( + host_prototype->hostid, interface->interfaceid, + interface->useip_orig, interface->useip); + } + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_IP)) + { + value_esc = DBdyn_escape_string(interface->ip); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sip='%s'", d, value_esc); + zbx_free(value_esc); + d = ","; + zbx_audit_host_prototype_update_json_update_interface_ip( + host_prototype->hostid, interface->interfaceid, + interface->ip_orig, interface->ip); + } + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_DNS)) + { + value_esc = DBdyn_escape_string(interface->dns); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdns='%s'", d, + value_esc); + zbx_free(value_esc); + d = ","; + zbx_audit_host_prototype_update_json_update_interface_dns( + host_prototype->hostid, interface->interfaceid, + interface->dns_orig, interface->dns); + } + + if (0 != (interface->flags & ZBX_FLAG_HPINTERFACE_UPDATE_PORT)) + { + value_esc = DBdyn_escape_string(interface->port); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sport='%s'", d, + value_esc); + zbx_free(value_esc); + zbx_audit_host_prototype_update_json_update_interface_port( + host_prototype->hostid, interface->interfaceid, + atoi(interface->port_orig), atoi(interface->port)); + } + + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, + " where interfaceid=" ZBX_FS_UI64 ";\n", interface->interfaceid); + + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, &sql1_offset))) + break; + } + + if (INTERFACE_TYPE_SNMP == interface->type) + { + if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_CREATE)) + { + zbx_db_insert_add_values(&db_insert_snmp, interface->interfaceid, + (int)interface->data.snmp->version, + (int)interface->data.snmp->bulk, + interface->data.snmp->community, + interface->data.snmp->securityname, + (int)interface->data.snmp->securitylevel, + interface->data.snmp->authpassphrase, + interface->data.snmp->privpassphrase, + (int)interface->data.snmp->authprotocol, + (int)interface->data.snmp->privprotocol, + interface->data.snmp->contextname); + + zbx_audit_host_prototype_update_json_add_snmp_interface(host_prototype->hostid, + interface->data.snmp->version, interface->data.snmp->bulk, + interface->data.snmp->community, + interface->data.snmp->securityname, + interface->data.snmp->securitylevel, + interface->data.snmp->authpassphrase, + interface->data.snmp->privpassphrase, + interface->data.snmp->authprotocol, + interface->data.snmp->privprotocol, + interface->data.snmp->contextname, + interface->interfaceid); + } + else if (0 != (interface->data.snmp->flags & ZBX_FLAG_HPINTERFACE_SNMP_UPDATE)) + { + zbx_audit_host_prototype_update_json_update_interface_details_create_entry( + host_prototype->hostid, interface->interfaceid); + DBhost_prototypes_interface_snmp_prepare_sql(host_prototype->hostid, + interface->interfaceid, interface->data.snmp, &sql1, + &sql1_alloc, &sql1_offset); + } + } + } + } + + if (0 != upd_tags.values_num) + { + zbx_vector_db_tag_ptr_sort(&upd_tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + + for (i = 0; i < upd_tags.values_num; i++) + { + char delim = ' '; + zbx_db_tag_t *tag = upd_tags.values[i]; + + zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update host_tag set"); + + if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_TAG)) + { + value_esc = DBdyn_escape_string(tag->tag); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%ctag='%s'", delim, + value_esc); + zbx_free(value_esc); + delim = ','; + } + + if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_VALUE)) + { + value_esc = DBdyn_escape_string(tag->value); + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%cvalue='%s'", delim, + value_esc); + zbx_free(value_esc); + } + + zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, + " where hosttagid=" ZBX_FS_UI64 ";\n", tag->tagid); + + if (FAIL == (res = DBexecute_overflowed_sql(&sql1, &sql1_alloc, &sql1_offset))) + break; + } + } + + if (0 != new_hosts) + { + zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + + zbx_db_insert_execute(&db_insert_hdiscovery); + zbx_db_insert_clean(&db_insert_hdiscovery); + } + + if (0 != new_group_prototypes) + { + zbx_db_insert_execute(&db_insert_gproto); + zbx_db_insert_clean(&db_insert_gproto); + } + + if (0 != new_hostmacros) + { + zbx_db_insert_execute(&db_insert_hmacro); + zbx_db_insert_clean(&db_insert_hmacro); + } + + if (0 != new_tags) + { + zbx_db_insert_execute(&db_insert_tag); + zbx_db_insert_clean(&db_insert_tag); + } + + if (0 != new_interfaces) + { + zbx_db_insert_execute(&db_insert_iface); + zbx_db_insert_clean(&db_insert_iface); + } + + if (0 != new_snmp) + { + zbx_db_insert_execute(&db_insert_snmp); + zbx_db_insert_clean(&db_insert_snmp); + } + + if (0 != new_inventory_modes) + { + zbx_db_insert_execute(&db_insert_inventory_mode); + zbx_db_insert_clean(&db_insert_inventory_mode); + } + + if (SUCCEED == res && (NULL != sql1 || new_hosts != host_prototypes->values_num || 0 != upd_group_prototypes || + 0 != upd_hostmacros || 0 != upd_interfaces || 0 != upd_snmp || 0 != upd_inventory_modes)) + { + zbx_DBend_multiple_update(&sql1, &sql1_alloc, &sql1_offset); + + /* in ORACLE always present begin..end; */ + if (16 < sql1_offset) + DBexecute("%s", sql1); + } + + if (SUCCEED == res && (NULL != sql2 || 0 != del_hosttemplateids->values_num || + 0 != del_hostmacroids->values_num || 0 != del_tagids.values_num || + 0 != del_interfaceids->values_num || 0 != del_snmpids->values_num || + 0 != del_inventory_modes_hostids.values_num)) + { + zbx_DBend_multiple_update(&sql2, &sql2_alloc, &sql2_offset); + + /* in ORACLE always present begin..end; */ + if (16 < sql2_offset) + DBexecute("%s", sql2); + } + + zbx_free(sql1); + zbx_free(sql2); + + zbx_vector_db_tag_ptr_destroy(&upd_tags); + zbx_vector_uint64_destroy(&del_inventory_modes_hostids); + zbx_vector_uint64_destroy(&del_tagids); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: copy host prototypes from templates and create links between * + * them and discovery rules * + * * + * Parameters: hostid - [IN] host id * + * templateids - [IN] host template ids * + * db_insert_htemplates - [IN/OUT] templates insert structure * + * Comments: auxiliary function for DBcopy_template_elements() * + * * + ******************************************************************************/ +static void DBcopy_template_host_prototypes(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids, + zbx_db_insert_t *db_insert_htemplates) +{ + zbx_vector_ptr_t host_prototypes; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + /* only regular hosts can have host prototypes */ + if (SUCCEED != DBis_regular_host(hostid)) + return; + + zbx_vector_ptr_create(&host_prototypes); + + DBhost_prototypes_make(hostid, templateids, &host_prototypes); + + if (0 != host_prototypes.values_num) + { + zbx_vector_uint64_t del_hosttemplateids, del_group_prototypeids, del_macroids, del_interfaceids, + del_snmp_interfaceids; + + zbx_vector_uint64_create(&del_hosttemplateids); + zbx_vector_uint64_create(&del_group_prototypeids); + zbx_vector_uint64_create(&del_macroids); + zbx_vector_uint64_create(&del_interfaceids); + zbx_vector_uint64_create(&del_snmp_interfaceids); + + DBhost_prototypes_templates_make(&host_prototypes, &del_hosttemplateids); + DBhost_prototypes_groups_make(&host_prototypes, &del_group_prototypeids); + DBhost_prototypes_macros_make(&host_prototypes, &del_macroids); + DBhost_prototypes_tags_make(&host_prototypes); + DBhost_prototypes_interfaces_make(&host_prototypes, &del_interfaceids, &del_snmp_interfaceids); + DBhost_prototypes_save(&host_prototypes, &del_hosttemplateids, &del_macroids, + &del_interfaceids, &del_snmp_interfaceids, db_insert_htemplates); + DBgroup_prototypes_delete(&del_group_prototypeids); + + zbx_vector_uint64_destroy(&del_macroids); + zbx_vector_uint64_destroy(&del_group_prototypeids); + zbx_vector_uint64_destroy(&del_snmp_interfaceids); + zbx_vector_uint64_destroy(&del_interfaceids); + zbx_vector_uint64_destroy(&del_hosttemplateids); + } + + DBhost_prototypes_clean(&host_prototypes); + zbx_vector_ptr_destroy(&host_prototypes); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +typedef struct +{ + zbx_uint64_t t_itemid; + zbx_uint64_t h_itemid; + unsigned char type; +} +httpstepitem_t; + +typedef struct +{ + zbx_uint64_t httpstepid; + zbx_uint64_t hoststepid; + char *name; + char *url_orig; + char *url; + char *posts_orig; + char *posts; + char *required_orig; + char *required; + char *status_codes_orig; + char *status_codes; + zbx_vector_ptr_t httpstepitems; + zbx_vector_ptr_t fields; + char *timeout_orig; + char *timeout; + int no; + int follow_redirects_orig; + int follow_redirects; + int retrieve_mode_orig; + int retrieve_mode; + int post_type_orig; + int post_type; +#define ZBX_FLAG_HTTPSTEP_RESET_FLAG __UINT64_C(0x000000000000) +#define ZBX_FLAG_HTTPSTEP_UPDATE_URL __UINT64_C(0x000000000001) +#define ZBX_FLAG_HTTPSTEP_UPDATE_POSTS __UINT64_C(0x000000000002) +#define ZBX_FLAG_HTTPSTEP_UPDATE_REQUIRED __UINT64_C(0x000000000004) +#define ZBX_FLAG_HTTPSTEP_UPDATE_STATUS_CODES __UINT64_C(0x000000000008) +#define ZBX_FLAG_HTTPSTEP_UPDATE_TIMEOUT __UINT64_C(0x000000000010) +#define ZBX_FLAG_HTTPSTEP_UPDATE_FOLLOW_REDIRECTS __UINT64_C(0x000000000020) +#define ZBX_FLAG_HTTPSTEP_UPDATE_RETRIEVE_MODE __UINT64_C(0x000000000040) +#define ZBX_FLAG_HTTPSTEP_UPDATE_POST_TYPE __UINT64_C(0x000000000080) +#define ZBX_FLAG_HTTPSTEP_UPDATE \ + (ZBX_FLAG_HTTPSTEP_UPDATE_URL | ZBX_FLAG_HTTPSTEP_UPDATE_POSTS | \ + ZBX_FLAG_HTTPSTEP_UPDATE_REQUIRED | ZBX_FLAG_HTTPSTEP_UPDATE_STATUS_CODES | \ + ZBX_FLAG_HTTPSTEP_UPDATE_TIMEOUT | ZBX_FLAG_HTTPSTEP_UPDATE_FOLLOW_REDIRECTS | \ + ZBX_FLAG_HTTPSTEP_UPDATE_RETRIEVE_MODE | ZBX_FLAG_HTTPSTEP_UPDATE_POST_TYPE \ + ) + zbx_uint64_t upd_flags; +} +httpstep_t; + +typedef struct +{ + zbx_uint64_t httptesttagid; + char *tag; + char *value; +} +httptesttag_t; + +typedef struct +{ + zbx_uint64_t t_itemid; + zbx_uint64_t h_itemid; + unsigned char type; +} +httptestitem_t; + +typedef struct +{ + zbx_uint64_t templateid; + zbx_uint64_t templateid_host; + zbx_uint64_t httptestid; + char *name; + char *delay_orig; + char *delay; + zbx_vector_ptr_t fields; + char *agent_orig; + char *agent; + char *http_user_orig; + char *http_user; + char *http_password_orig; + char *http_password; + char *http_proxy_orig; + char *http_proxy; + zbx_vector_ptr_t httpsteps; + zbx_vector_ptr_t httptestitems; + zbx_vector_ptr_t httptesttags; + int retries_orig; + int retries; + unsigned char status_orig; + unsigned char status; + unsigned char authentication_orig; + unsigned char authentication; + char *ssl_cert_file_orig; + char *ssl_cert_file; + char *ssl_key_file_orig; + char *ssl_key_file; + char *ssl_key_password_orig; + char *ssl_key_password; + int verify_peer_orig; + int verify_peer; + int verify_host_orig; + int verify_host; +#define ZBX_FLAG_HTTPTEST_RESET_FLAG __UINT64_C(0x000000000000) +#define ZBX_FLAG_HTTPTEST_UPDATE_DELAY __UINT64_C(0x000000000001) +#define ZBX_FLAG_HTTPTEST_UPDATE_AGENT __UINT64_C(0x000000000002) +#define ZBX_FLAG_HTTPTEST_UPDATE_HTTP_USER __UINT64_C(0x000000000004) +#define ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PASSWORD __UINT64_C(0x000000000008) +#define ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PROXY __UINT64_C(0x000000000010) +#define ZBX_FLAG_HTTPTEST_UPDATE_RETRIES __UINT64_C(0x000000000020) +#define ZBX_FLAG_HTTPTEST_UPDATE_STATUS __UINT64_C(0x000000000040) +#define ZBX_FLAG_HTTPTEST_UPDATE_AUTHENTICATION __UINT64_C(0x000000000080) +#define ZBX_FLAG_HTTPTEST_UPDATE_SSL_CERT_FILE __UINT64_C(0x000000000100) +#define ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_FILE __UINT64_C(0x000000000200) +#define ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_PASSWORD __UINT64_C(0x000000000400) +#define ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_PEER __UINT64_C(0x000000000800) +#define ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_HOST __UINT64_C(0x000000001000) +#define ZBX_FLAG_HTTPTEST_UPDATE \ + (ZBX_FLAG_HTTPTEST_UPDATE_DELAY | ZBX_FLAG_HTTPTEST_UPDATE_AGENT | \ + ZBX_FLAG_HTTPTEST_UPDATE_HTTP_USER | ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PASSWORD | \ + ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PROXY | ZBX_FLAG_HTTPTEST_UPDATE_RETRIES | \ + ZBX_FLAG_HTTPTEST_UPDATE_STATUS | ZBX_FLAG_HTTPTEST_UPDATE_AUTHENTICATION | \ + ZBX_FLAG_HTTPTEST_UPDATE_SSL_CERT_FILE | ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_FILE | \ + ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_PASSWORD | ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_PEER | \ + ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_HOST \ + ) + zbx_uint64_t upd_flags; +} +httptest_t; + +typedef struct +{ + int type; + char *name; + char *value; +} +httpfield_t; + +static void DBget_httptests(const zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, + zbx_vector_ptr_t *httptests) +{ + int i, j, k, int_orig; + char *sql = NULL; + size_t sql_alloc = 512, sql_offset = 0; + DB_RESULT result; + DB_ROW row; + httptest_t *httptest; + httpstep_t *httpstep; + httpfield_t *httpfield; + httptestitem_t *httptestitem; + httpstepitem_t *httpstepitem; + zbx_vector_uint64_t httptestids; /* the list of web scenarios which should be added to a host */ + zbx_vector_uint64_t items; + zbx_uint64_t httptestid, httpstepid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&httptestids); + zbx_vector_uint64_create(&items); + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t.httptestid,t.name,t.delay,t.status,t.agent,t.authentication," + "t.http_user,t.http_password,t.http_proxy,t.retries,h.httptestid,h.templateid,h.delay," + "h.status,h.agent,h.authentication,h.http_user,h.http_password,h.http_proxy,h.retries," + "t.ssl_cert_file,t.ssl_key_file,t.ssl_key_password,t.verify_peer,t.verify_host," + "h.ssl_cert_file,h.ssl_key_file,h.ssl_key_password,h.verify_peer,h.verify_host" + " from httptest t" + " left join httptest h" + " on h.hostid=" ZBX_FS_UI64 + " and h.name=t.name" + " where", hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by t.httptestid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + httptest = (httptest_t *)zbx_calloc(NULL, 1, sizeof(httptest_t)); + + httptest->upd_flags = ZBX_FLAG_HTTPTEST_RESET_FLAG; + + ZBX_STR2UINT64(httptest->templateid, row[0]); + ZBX_DBROW2UINT64(httptest->templateid_host, row[11]); + ZBX_DBROW2UINT64(httptest->httptestid, row[10]); + zbx_vector_ptr_create(&httptest->httpsteps); + zbx_vector_ptr_create(&httptest->httptestitems); + zbx_vector_ptr_create(&httptest->fields); + zbx_vector_ptr_create(&httptest->httptesttags); + httptest->name = zbx_strdup(NULL, row[1]); + httptest->delay = zbx_strdup(NULL, row[2]); + httptest->delay_orig = NULL; + httptest->status = (unsigned char)atoi(row[3]); + httptest->status_orig = httptest->status; + httptest->agent = zbx_strdup(NULL, row[4]); + httptest->agent_orig = NULL; + httptest->authentication = (unsigned char)atoi(row[5]); + httptest->authentication_orig = httptest->authentication; + httptest->http_user = zbx_strdup(NULL, row[6]); + httptest->http_user_orig = NULL; + httptest->http_password = zbx_strdup(NULL, row[7]); + httptest->http_password_orig = NULL; + httptest->http_proxy = zbx_strdup(NULL, row[8]); + httptest->http_proxy_orig = NULL; + httptest->retries = atoi(row[9]); + httptest->retries_orig = httptest->retries; + + httptest->ssl_cert_file = zbx_strdup(NULL, row[20]); + httptest->ssl_cert_file_orig = NULL; + httptest->ssl_key_file = zbx_strdup(NULL, row[21]); + httptest->ssl_key_file_orig = NULL; + httptest->ssl_key_password = zbx_strdup(NULL, row[22]); + httptest->ssl_key_password_orig = NULL; + httptest->verify_peer = atoi(row[23]); + httptest->verify_peer_orig = httptest->verify_peer; + httptest->verify_host = atoi(row[24]); + httptest->verify_host_orig = httptest->verify_host; + + zbx_vector_ptr_append(httptests, httptest); + + if (0 != httptest->httptestid) + { + unsigned char uchar_orig; + +#define SET_FLAG_STR(r, i, f, s) \ +{ \ + if (0 != strcmp(r, (i))) \ + { \ + s->upd_flags |= f; \ + i##_orig = zbx_strdup(NULL, r); \ + } \ +} + +#define SET_FLAG_UCHAR(r, i, f, s) \ +{ \ + ZBX_STR2UCHAR(uchar_orig, (r)); \ + if (uchar_orig != (i)) \ + { \ + s->upd_flags |= f; \ + i##_orig = uchar_orig; \ + } \ +} + +#define SET_FLAG_INT(r, i, f, s) \ +{ \ + int_orig = atoi(r); \ + if (int_orig != (i)) \ + { \ + s->upd_flags |= f; \ + i##_orig = int_orig; \ + } \ +} + SET_FLAG_STR(row[12], httptest->delay, ZBX_FLAG_HTTPTEST_UPDATE_DELAY, httptest); + SET_FLAG_UCHAR(row[13], httptest->status, ZBX_FLAG_HTTPTEST_UPDATE_STATUS, httptest); + SET_FLAG_STR(row[14], httptest->agent, ZBX_FLAG_HTTPTEST_UPDATE_AGENT, httptest); + SET_FLAG_UCHAR(row[15], httptest->authentication, ZBX_FLAG_HTTPTEST_UPDATE_AUTHENTICATION, + httptest); + SET_FLAG_STR(row[16], httptest->http_user, ZBX_FLAG_HTTPTEST_UPDATE_HTTP_USER, httptest); + SET_FLAG_STR(row[17], httptest->http_password, ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PASSWORD, + httptest); + SET_FLAG_STR(row[18], httptest->http_proxy, ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PROXY, httptest); + SET_FLAG_INT(row[19], httptest->retries, ZBX_FLAG_HTTPTEST_UPDATE_RETRIES, httptest); + SET_FLAG_STR(row[25], httptest->ssl_cert_file, ZBX_FLAG_HTTPTEST_UPDATE_SSL_CERT_FILE, + httptest); + SET_FLAG_STR(row[26], httptest->ssl_key_file, ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_FILE, httptest); + SET_FLAG_STR(row[27], httptest->ssl_key_password, ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_PASSWORD, + httptest); + SET_FLAG_INT(row[28], httptest->verify_peer, ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_PEER, httptest); + SET_FLAG_INT(row[29], httptest->verify_host, ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_HOST, httptest); + } + + zbx_vector_uint64_append(&httptestids, httptest->templateid); + } + + DBfree_result(result); + + if (0 != httptestids.values_num) + { + httptest = NULL; + + /* web scenario fields */ + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptestid,type,name,value" + " from httptest_field" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids.values, httptestids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by httptestid,httptest_fieldid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(httptestid, row[0]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + } + + httpfield = (httpfield_t *)zbx_malloc(NULL, sizeof(httpfield_t)); + + httpfield->type = atoi(row[1]); + httpfield->name = zbx_strdup(NULL, row[2]); + httpfield->value = zbx_strdup(NULL, row[3]); + + zbx_vector_ptr_append(&httptest->fields, httpfield); + } + DBfree_result(result); + + /* web scenario steps */ + httptest = NULL; + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select ts.httpstepid,ts.httptestid,ts.name,ts.no,ts.url,ts.timeout,ts.posts," + "ts.required,ts.status_codes,ts.follow_redirects,ts.retrieve_mode,ts.post_type," + "hs.httpstepid,hs.url,hs.timeout,hs.posts,hs.required,hs.status_codes," + "hs.follow_redirects,hs.retrieve_mode,hs.post_type" + " from httpstep ts" + " left join httptest tt on tt.httptestid=ts.httptestid" + " left join httptest ht on ht.hostid=" ZBX_FS_UI64 " and ht.name=tt.name" + " left join httpstep hs on hs.httptestid=ht.httptestid and hs.no=ts.no" + " where", hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ts.httptestid", + httptestids.values, httptestids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by ts.httptestid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(httptestid, row[1]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + } + + httpstep = (httpstep_t *)zbx_malloc(NULL, sizeof(httpstep_t)); + + ZBX_STR2UINT64(httpstep->httpstepid, row[0]); + httpstep->name = zbx_strdup(NULL, row[2]); + httpstep->no = atoi(row[3]); + httpstep->url = zbx_strdup(NULL, row[4]); + httpstep->url_orig = NULL; + httpstep->timeout = zbx_strdup(NULL, row[5]); + httpstep->timeout_orig = NULL; + httpstep->posts = zbx_strdup(NULL, row[6]); + httpstep->posts_orig = NULL; + httpstep->required = zbx_strdup(NULL, row[7]); + httpstep->required_orig = NULL; + httpstep->status_codes = zbx_strdup(NULL, row[8]); + httpstep->status_codes_orig = NULL; + httpstep->follow_redirects = atoi(row[9]); + httpstep->follow_redirects_orig = httpstep->follow_redirects; + httpstep->retrieve_mode = atoi(row[10]); + httpstep->retrieve_mode_orig = httpstep->retrieve_mode; + httpstep->post_type = atoi(row[11]); + httpstep->post_type_orig = httpstep->post_type; + httpstep->upd_flags = ZBX_FLAG_HTTPSTEP_RESET_FLAG; + zbx_vector_ptr_create(&httpstep->httpstepitems); + zbx_vector_ptr_create(&httpstep->fields); + + ZBX_DBROW2UINT64(httpstep->hoststepid, row[12]); + + if (0 != httpstep->hoststepid) + { + SET_FLAG_STR(row[13], httpstep->url, ZBX_FLAG_HTTPSTEP_UPDATE_URL, httpstep); + SET_FLAG_STR(row[14], httpstep->timeout, ZBX_FLAG_HTTPSTEP_UPDATE_TIMEOUT, httpstep); + SET_FLAG_STR(row[15], httpstep->posts, ZBX_FLAG_HTTPSTEP_UPDATE_POSTS, httpstep); + SET_FLAG_STR(row[16], httpstep->required, ZBX_FLAG_HTTPSTEP_UPDATE_REQUIRED, httpstep); + SET_FLAG_STR(row[17], httpstep->status_codes, ZBX_FLAG_HTTPSTEP_UPDATE_STATUS_CODES, + httpstep); + SET_FLAG_INT(row[18], httpstep->follow_redirects, + ZBX_FLAG_HTTPSTEP_UPDATE_FOLLOW_REDIRECTS, httpstep); + SET_FLAG_INT(row[19], httpstep->retrieve_mode, ZBX_FLAG_HTTPSTEP_UPDATE_RETRIEVE_MODE, + httpstep); + SET_FLAG_INT(row[20], httpstep->post_type, ZBX_FLAG_HTTPSTEP_UPDATE_POST_TYPE, + httpstep); + } + + zbx_vector_ptr_append(&httptest->httpsteps, httpstep); + } + + DBfree_result(result); + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + zbx_vector_ptr_sort(&httptest->httpsteps, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + } + + /* web scenario step fields */ + httptest = NULL; + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select s.httptestid,f.httpstepid,f.type,f.name,f.value" + " from httpstep_field f" + " join httpstep s" + " on f.httpstepid=s.httpstepid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "s.httptestid", + httptestids.values, httptestids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " order by s.httptestid,f.httpstepid,f.httpstep_fieldid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(httptestid, row[0]); + ZBX_STR2UINT64(httpstepid, row[1]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + httpstep = NULL; + } + + if (NULL == httpstep || httpstep->httpstepid != httpstepid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(&httptest->httpsteps, &httpstepid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httpstep = (httpstep_t *)httptest->httpsteps.values[i]; + } + + httpfield = (httpfield_t *)zbx_malloc(NULL, sizeof(httpfield_t)); + + httpfield->type = atoi(row[2]); + httpfield->name = zbx_strdup(NULL, row[3]); + httpfield->value = zbx_strdup(NULL, row[4]); + + zbx_vector_ptr_append(&httpstep->fields, httpfield); + } + DBfree_result(result); + + /* web scenario tags */ + httptest = NULL; + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptesttagid,httptestid,tag,value" + " from httptest_tag" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids.values, httptestids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by httptestid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + httptesttag_t *httptesttag; + + ZBX_STR2UINT64(httptestid, row[1]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + } + + httptesttag = (httptesttag_t *)zbx_malloc(NULL, sizeof(httptesttag_t)); + + ZBX_STR2UINT64(httptesttag->httptesttagid, row[0]); + httptesttag->tag = zbx_strdup(NULL, row[2]); + httptesttag->value = zbx_strdup(NULL, row[3]); + + zbx_vector_ptr_append(&httptest->httptesttags, httptesttag); + } + DBfree_result(result); + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + zbx_vector_ptr_sort(&httptest->httptesttags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + } + } + + /* web scenario items */ + if (0 != httptestids.values_num) + { + httptest = NULL; + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptestid,itemid,type" + " from httptestitem" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", + httptestids.values, httptestids.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(httptestid, row[0]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + } + + httptestitem = (httptestitem_t *)zbx_calloc(NULL, 1, sizeof(httptestitem_t)); + + ZBX_STR2UINT64(httptestitem->t_itemid, row[1]); + httptestitem->type = (unsigned char)atoi(row[2]); + + zbx_vector_ptr_append(&httptest->httptestitems, httptestitem); + + zbx_vector_uint64_append(&items, httptestitem->t_itemid); + } + DBfree_result(result); + } + + /* web scenario step items */ + if (0 != httptestids.values_num) + { + httptest = NULL; + httpstep = NULL; + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hs.httptestid,hsi.httpstepid,hsi.itemid,hsi.type" + " from httpstepitem hsi" + " join httpstep hs" + " on"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hs.httptestid", + httptestids.values, httptestids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " and hs.httpstepid=hsi.httpstepid" + " order by hs.httptestid,hsi.httpstepid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(httptestid, row[0]); + ZBX_STR2UINT64(httpstepid, row[1]); + + if (NULL == httptest || httptest->templateid != httptestid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httptest = (httptest_t *)httptests->values[i]; + httpstep = NULL; + } + + if (NULL == httpstep || httpstep->httpstepid != httpstepid) + { + if (FAIL == (i = zbx_vector_ptr_bsearch(&httptest->httpsteps, &httpstepid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + httpstep = (httpstep_t *)httptest->httpsteps.values[i]; + } + + httpstepitem = (httpstepitem_t *)zbx_calloc(NULL, 1, sizeof(httpstepitem_t)); + + ZBX_STR2UINT64(httpstepitem->t_itemid, row[2]); + httpstepitem->type = (unsigned char)atoi(row[3]); + + zbx_vector_ptr_append(&httpstep->httpstepitems, httpstepitem); + + zbx_vector_uint64_append(&items, httpstepitem->t_itemid); + } + DBfree_result(result); + } + + /* items */ + if (0 != items.values_num) + { + zbx_vector_uint64_sort(&items, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t.itemid,h.itemid" + " from items t" + " join items h" + " on h.hostid=" ZBX_FS_UI64 + " and h.key_=t.key_" + " where", hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.itemid", + items.values, items.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_t itemid; + + ZBX_STR2UINT64(itemid, row[0]); + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + + for (j = 0; j < httptest->httptestitems.values_num; j++) + { + httptestitem = (httptestitem_t *)httptest->httptestitems.values[j]; + + if (httptestitem->t_itemid == itemid) + ZBX_STR2UINT64(httptestitem->h_itemid, row[1]); + } + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + for (k = 0; k < httpstep->httpstepitems.values_num; k++) + { + httpstepitem = (httpstepitem_t *)httpstep->httpstepitems.values[k]; + + if (httpstepitem->t_itemid == itemid) + ZBX_STR2UINT64(httpstepitem->h_itemid, row[1]); + } + } + } + } + DBfree_result(result); + } + + zbx_free(sql); + + zbx_vector_uint64_destroy(&items); + zbx_vector_uint64_destroy(&httptestids); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +static void DBsave_httptests(zbx_uint64_t hostid, const zbx_vector_ptr_t *httptests) +{ + char *sql; + size_t sql_alloc = 512, sql_offset = 0; + httptest_t *httptest; + httpfield_t *httpfield; + httpstep_t *httpstep; + zbx_uint64_t httptestid = 0, httpstepid = 0, httptestitemid = 0, httpstepitemid = 0, + httptestfieldid = 0, httpstepfieldid = 0, httptesttagid = 0; + int i, j, k, num_httpsteps = 0, num_httptestitems = 0, num_httpstepitems = 0, + num_httptestfields = 0, num_httpstepfields = 0, num_httptesttags = 0, num_httptests = 0; + zbx_db_insert_t db_insert_htest, db_insert_hstep, db_insert_htitem, db_insert_hsitem, db_insert_tfield, + db_insert_sfield, db_insert_httag; + zbx_vector_uint64_t httpupdtestids, httpupdstepids, deletefieldsids, deletestepfieldsids, deletetagids; + DB_RESULT result; + DB_ROW row; + + if (0 == httptests->values_num) + return; + + sql = (char *)zbx_malloc(NULL, sql_alloc); + + zbx_vector_uint64_create(&httpupdtestids); + zbx_vector_uint64_create(&httpupdstepids); + zbx_vector_uint64_create(&deletefieldsids); + zbx_vector_uint64_create(&deletestepfieldsids); + zbx_vector_uint64_create(&deletetagids); + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + + num_httptestfields += httptest->fields.values_num; + num_httptesttags += httptest->httptesttags.values_num; + + if (0 == httptest->httptestid) + { + num_httptests++; + num_httpsteps += httptest->httpsteps.values_num; + num_httptestitems += httptest->httptestitems.values_num; + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + num_httpstepfields += httpstep->fields.values_num; + num_httpstepitems += httpstep->httpstepitems.values_num; + } + } + else + { + zbx_vector_uint64_append(&httpupdtestids, httptest->httptestid); + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + num_httpstepfields += httpstep->fields.values_num; + zbx_vector_uint64_append(&httpupdstepids, httpstep->hoststepid); + } + + zbx_audit_httptest_create_entry(ZBX_AUDIT_ACTION_UPDATE, httptest->httptestid, httptest->name); + } + } + + if (0 != httpupdtestids.values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptest_fieldid,httptestid,type" + " from httptest_field where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", httpupdtestids.values, + httpupdtestids.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_t httpfieldid, testid; + int type; + + ZBX_STR2UINT64(httpfieldid, row[0]); + ZBX_STR2UINT64(testid, row[1]); + type = atoi(row[2]); + zbx_vector_uint64_append(&deletefieldsids, httpfieldid); + zbx_audit_httptest_update_json_delete_httptest_field(testid, httpfieldid, type); + } + + DBfree_result(result); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptesttagid,httptestid" + " from httptest_tag where" + ); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid", httpupdtestids.values, + httpupdtestids.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_t httptagid, testid; + + ZBX_STR2UINT64(httptagid, row[0]); + ZBX_STR2UINT64(testid, row[1]); + zbx_vector_uint64_append(&deletetagids, httptagid); + zbx_audit_httptest_update_json_delete_tags(testid, httptagid); + } + + DBfree_result(result); + } + + if (0 != httpupdstepids.values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select sf.httpstep_fieldid,sf.httpstepid,s.httptestid,sf.type" + " from httpstep_field sf" + " join httpstep s on s.httpstepid=sf.httpstepid" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sf.httpstepid", httpupdstepids.values, + httpupdstepids.values_num); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_t stepfieldid, stepid, testid; + int type; + + ZBX_STR2UINT64(stepfieldid, row[0]); + ZBX_STR2UINT64(stepid, row[1]); + ZBX_STR2UINT64(testid, row[2]); + type = atoi(row[3]); + zbx_vector_uint64_append(&deletestepfieldsids, stepfieldid); + zbx_audit_httptest_update_json_delete_httpstep_field(testid, stepid, stepfieldid, type); + } + + DBfree_result(result); + } + + if (0 != deletefieldsids.values_num) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptest_field where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptest_fieldid", deletefieldsids.values, + deletefieldsids.values_num); + DBexecute("%s", sql); + } + + if (0 != deletestepfieldsids.values_num) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from httpstep_field where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httpstep_fieldid", deletestepfieldsids.values, + deletestepfieldsids.values_num); + DBexecute("%s", sql); + } + + if (0 != deletetagids.values_num) + { + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptest_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptesttagid", deletetagids.values, + deletetagids.values_num); + DBexecute("%s", sql); + } + + sql_offset = 0; + + if (0 != num_httptests) + { + httptestid = DBget_maxid_num("httptest", num_httptests); + + zbx_db_insert_prepare(&db_insert_htest, "httptest", "httptestid", "name", "delay", "status", "agent", + "authentication", "http_user", "http_password", "http_proxy", "retries", "hostid", + "templateid", "ssl_cert_file", "ssl_key_file", "ssl_key_password", "verify_peer", + "verify_host", NULL); + } + + if (0 != num_httptestfields) + { + httptestfieldid = DBget_maxid_num("httptest_field", num_httptestfields); + + zbx_db_insert_prepare(&db_insert_tfield, "httptest_field", "httptest_fieldid", "httptestid", "type", + "name", "value", NULL); + } + + if (0 != num_httpsteps) + { + httpstepid = DBget_maxid_num("httpstep", num_httpsteps); + + zbx_db_insert_prepare(&db_insert_hstep, "httpstep", "httpstepid", "httptestid", "name", "no", "url", + "timeout", "posts", "required", "status_codes", "follow_redirects", "retrieve_mode", + "post_type", NULL); + } + + if (0 != num_httptestitems) + { + httptestitemid = DBget_maxid_num("httptestitem", num_httptestitems); + + zbx_db_insert_prepare(&db_insert_htitem, "httptestitem", "httptestitemid", "httptestid", "itemid", + "type", NULL); + } + + if (0 != num_httpstepitems) + { + httpstepitemid = DBget_maxid_num("httpstepitem", num_httpstepitems); + + zbx_db_insert_prepare(&db_insert_hsitem, "httpstepitem", "httpstepitemid", "httpstepid", "itemid", + "type", NULL); + } + + if (0 != num_httpstepfields) + { + httpstepfieldid = DBget_maxid_num("httpstep_field", num_httpstepfields); + + zbx_db_insert_prepare(&db_insert_sfield, "httpstep_field", "httpstep_fieldid", "httpstepid", "type", + "name", "value", NULL); + } + + if (0 != num_httptesttags) + { + httptesttagid = DBget_maxid_num("httptest_tag", num_httptesttags); + + zbx_db_insert_prepare(&db_insert_httag, "httptest_tag", "httptesttagid", "httptestid", "tag", "value", + NULL); + } + + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + + if (0 == httptest->httptestid) + { + httptest->httptestid = httptestid++; + + zbx_audit_httptest_create_entry(ZBX_AUDIT_ACTION_ADD, httptest->httptestid, httptest->name); + + zbx_db_insert_add_values(&db_insert_htest, httptest->httptestid, httptest->name, + httptest->delay, (int)httptest->status, httptest->agent, + (int)httptest->authentication, httptest->http_user, httptest->http_password, + httptest->http_proxy, httptest->retries, hostid, httptest->templateid, + httptest->ssl_cert_file, httptest->ssl_key_file, httptest->ssl_key_password, + httptest->verify_peer, httptest->verify_host); + + zbx_audit_httptest_update_json_add_data(httptest->httptestid, httptest->templateid, + httptest->name, httptest->delay, (int)httptest->status, httptest->agent, + (int)httptest->authentication, httptest->http_user, httptest->http_password, + httptest->http_proxy, httptest->retries, httptest->ssl_cert_file, + httptest->ssl_key_file, httptest->ssl_key_password, httptest->verify_peer, + httptest->verify_host, hostid); + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + zbx_db_insert_add_values(&db_insert_hstep, httpstepid, httptest->httptestid, + httpstep->name, httpstep->no, httpstep->url, httpstep->timeout, + httpstep->posts, httpstep->required, httpstep->status_codes, + httpstep->follow_redirects, httpstep->retrieve_mode, + httpstep->post_type); + + httpstep->hoststepid = httpstepid; + + zbx_audit_httptest_update_json_add_httptest_httpstep(httptest->httptestid, httpstepid, + httpstep->name, httpstep->no, httpstep->url, httpstep->timeout, + httpstep->posts, httpstep->required, httpstep->status_codes, + httpstep->follow_redirects, httpstep->retrieve_mode, + httpstep->post_type); + + for (k = 0; k < httpstep->httpstepitems.values_num; k++) + { + httpstepitem_t *httpstepitem; + + httpstepitem = (httpstepitem_t *)httpstep->httpstepitems.values[k]; + + zbx_db_insert_add_values(&db_insert_hsitem, httpstepitemid, httpstepid, + httpstepitem->h_itemid, (int)httpstepitem->type); + + httpstepitemid++; + } + + httpstepid++; + } + + for (j = 0; j < httptest->httptestitems.values_num; j++) + { + httptestitem_t *httptestitem; + + httptestitem = (httptestitem_t *)httptest->httptestitems.values[j]; + + zbx_db_insert_add_values(&db_insert_htitem, httptestitemid, httptest->httptestid, + httptestitem->h_itemid, (int)httptestitem->type); + + httptestitemid++; + } + } + else + { + const char *d = ","; + + zbx_audit_httptest_create_entry(ZBX_AUDIT_ACTION_UPDATE, httptest->httptestid, httptest->name); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update httptest" + " set templateid=" ZBX_FS_UI64, httptest->templateid); + + zbx_audit_httptest_update_json_update_templateid(httptest->httptestid, + httptest->templateid_host, httptest->templateid); + + if (0 != (httptest->upd_flags & ZBX_FLAG_HTTPTEST_UPDATE)) + { + +#define PREPARE_UPDATE_HTTPTEST_STR(FLAG, field) \ + if (0 != (httptest->upd_flags & FLAG)) \ + { \ + char *str_esc = DBdyn_escape_string(httptest->field); \ + \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"='%s'", d, str_esc); \ + d = ","; \ + zbx_free(str_esc); \ + \ + zbx_audit_httptest_update_json_update_##field(httptest->httptestid, \ + httptest->field##_orig, httptest->field); \ + } + +#define PREPARE_UPDATE_HTTPTEST_STR_SECRET(FLAG, field) \ + if (0 != (httptest->upd_flags & FLAG)) \ + { \ + char *str_esc = DBdyn_escape_string(httptest->field); \ + \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"='%s'", d, str_esc); \ + d = ","; \ + zbx_free(str_esc); \ + \ + zbx_audit_httptest_update_json_update_##field(httptest->httptestid, \ + (0 == strcmp("", httptest->field##_orig) ? "" :ZBX_MACRO_SECRET_MASK), \ + (0 == strcmp("", httptest->field) ? "" : ZBX_MACRO_SECRET_MASK)); \ + } + +#define PREPARE_UPDATE_HTTPTEST_INT(FLAG, field) \ + if (0 != (httptest->upd_flags & FLAG)) \ + { \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"=%d", d, httptest->field); \ + d = ","; \ + \ + zbx_audit_httptest_update_json_update_##field(httptest->httptestid, \ + httptest->field##_orig, httptest->field); \ + } + +#define PREPARE_UPDATE_HTTPTEST_UC(FLAG, field) \ + if (0 != (httptest->upd_flags & FLAG)) \ + { \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"=%d", d, \ + (int)httptest->field); \ + d = ","; \ + \ + zbx_audit_httptest_update_json_update_##field(httptest->httptestid, \ + httptest->field##_orig, httptest->field); \ + } + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_DELAY, delay) + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_AGENT, agent) + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_HTTP_USER, http_user) + PREPARE_UPDATE_HTTPTEST_STR_SECRET(ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PASSWORD, + http_password) + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_HTTP_PROXY, http_proxy) + PREPARE_UPDATE_HTTPTEST_INT(ZBX_FLAG_HTTPTEST_UPDATE_RETRIES, retries) + PREPARE_UPDATE_HTTPTEST_UC(ZBX_FLAG_HTTPTEST_UPDATE_STATUS, status) + PREPARE_UPDATE_HTTPTEST_UC(ZBX_FLAG_HTTPTEST_UPDATE_AUTHENTICATION, authentication) + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_SSL_CERT_FILE, ssl_cert_file) + PREPARE_UPDATE_HTTPTEST_STR(ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_FILE, ssl_key_file) + PREPARE_UPDATE_HTTPTEST_STR_SECRET(ZBX_FLAG_HTTPTEST_UPDATE_SSL_KEY_PASSWORD, + ssl_key_password) + PREPARE_UPDATE_HTTPTEST_INT(ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_PEER, verify_peer) + PREPARE_UPDATE_HTTPTEST_INT(ZBX_FLAG_HTTPTEST_UPDATE_VERIFY_HOST, verify_host) + } + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where httptestid=" ZBX_FS_UI64 ";\n", + httptest->httptestid); + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + if (0 != (httpstep->upd_flags & ZBX_FLAG_HTTPSTEP_UPDATE)) + { + +#define PREPARE_UPDATE_HTTPSTEP_STR(FLAG, field) \ + if (0 != (httpstep->upd_flags & FLAG)) \ + { \ + char *str_esc = DBdyn_escape_string(httpstep->field); \ + \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"='%s'", d, str_esc); \ + d = ","; \ + zbx_free(str_esc); \ + \ + zbx_audit_httptest_update_json_httpstep_update_##field(httptest->httptestid, \ + httpstep->httpstepid, httpstep->field##_orig, httpstep->field); \ + } + +#define PREPARE_UPDATE_HTTPSTEP_INT(FLAG, field) \ + if (0 != (httpstep->upd_flags & FLAG)) \ + { \ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s"#field"=%d", d, httpstep->field); \ + d = ","; \ + \ + zbx_audit_httptest_update_json_httpstep_update_##field(httptest->httptestid, \ + httpstep->httpstepid, httpstep->field##_orig, httpstep->field); \ + } + + d = ""; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update httpstep set "); + + PREPARE_UPDATE_HTTPSTEP_STR(ZBX_FLAG_HTTPSTEP_UPDATE_URL, url) + PREPARE_UPDATE_HTTPSTEP_STR(ZBX_FLAG_HTTPSTEP_UPDATE_POSTS, posts) + PREPARE_UPDATE_HTTPSTEP_STR(ZBX_FLAG_HTTPSTEP_UPDATE_REQUIRED, required) + PREPARE_UPDATE_HTTPSTEP_STR(ZBX_FLAG_HTTPSTEP_UPDATE_STATUS_CODES, + status_codes) + PREPARE_UPDATE_HTTPSTEP_STR(ZBX_FLAG_HTTPSTEP_UPDATE_TIMEOUT, timeout) + PREPARE_UPDATE_HTTPSTEP_INT(ZBX_FLAG_HTTPSTEP_UPDATE_FOLLOW_REDIRECTS, + follow_redirects) + PREPARE_UPDATE_HTTPSTEP_INT(ZBX_FLAG_HTTPSTEP_UPDATE_RETRIEVE_MODE, + retrieve_mode) + PREPARE_UPDATE_HTTPSTEP_INT(ZBX_FLAG_HTTPSTEP_UPDATE_POST_TYPE, post_type) + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + " where httpstepid=" ZBX_FS_UI64 ";\n", httpstep->hoststepid); + } + } + + zbx_audit_httptest_update_json_update_templateid(httptest->httptestid, + httptest->templateid_host, httptest->templateid); + } + + for (j = 0; j < httptest->fields.values_num; j++) + { + httpfield = (httpfield_t *)httptest->fields.values[j]; + + zbx_db_insert_add_values(&db_insert_tfield, httptestfieldid, httptest->httptestid, + httpfield->type, httpfield->name, httpfield->value); + + zbx_audit_httptest_update_json_add_httptest_field(httptest->httptestid, httptestfieldid, + httpfield->type, httpfield->name, httpfield->value); + + httptestfieldid++; + } + + for (j = 0; j < httptest->httptesttags.values_num; j++) + { + httptesttag_t *httptesttag; + + httptesttag = (httptesttag_t *)httptest->httptesttags.values[j]; + + zbx_db_insert_add_values(&db_insert_httag, httptesttagid, httptest->httptestid, + httptesttag->tag, httptesttag->value); + + zbx_audit_httptest_update_json_add_httptest_tag(httptest->httptestid, httptesttagid, + httptesttag->tag, httptesttag->value); + + httptesttagid++; + } + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + for (k = 0; k < httpstep->fields.values_num; k++) + { + httpfield = (httpfield_t *)httpstep->fields.values[k]; + + zbx_db_insert_add_values(&db_insert_sfield, httpstepfieldid, httpstep->hoststepid, + httpfield->type, httpfield->name, httpfield->value); + + zbx_audit_httptest_update_json_add_httpstep_field(httptest->httptestid, + httpstep->hoststepid, httpstepfieldid, httpfield->type, httpfield->name, + httpfield->value); + httpstepfieldid++; + } + } + } + + if (0 != num_httptests) + { + zbx_db_insert_execute(&db_insert_htest); + zbx_db_insert_clean(&db_insert_htest); + } + + if (0 != num_httpsteps) + { + zbx_db_insert_execute(&db_insert_hstep); + zbx_db_insert_clean(&db_insert_hstep); + } + + if (0 != num_httptestitems) + { + zbx_db_insert_execute(&db_insert_htitem); + zbx_db_insert_clean(&db_insert_htitem); + } + + if (0 != num_httpstepitems) + { + zbx_db_insert_execute(&db_insert_hsitem); + zbx_db_insert_clean(&db_insert_hsitem); + } + + if (0 != num_httptestfields) + { + zbx_db_insert_execute(&db_insert_tfield); + zbx_db_insert_clean(&db_insert_tfield); + } + + if (0 != num_httpstepfields) + { + zbx_db_insert_execute(&db_insert_sfield); + zbx_db_insert_clean(&db_insert_sfield); + } + + if (0 != num_httptesttags) + { + zbx_db_insert_execute(&db_insert_httag); + zbx_db_insert_clean(&db_insert_httag); + } + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (16 < sql_offset) + DBexecute("%s", sql); + + zbx_free(sql); + + zbx_vector_uint64_destroy(&httpupdtestids); + zbx_vector_uint64_destroy(&httpupdstepids); + zbx_vector_uint64_destroy(&deletefieldsids); + zbx_vector_uint64_destroy(&deletestepfieldsids); + zbx_vector_uint64_destroy(&deletetagids); +} + +static void clean_httptests(zbx_vector_ptr_t *httptests) +{ + httptest_t *httptest; + httpfield_t *httpfield; + httpstep_t *httpstep; + httptesttag_t *httptesttag; + int i, j, k; + + for (i = 0; i < httptests->values_num; i++) + { + httptest = (httptest_t *)httptests->values[i]; + + zbx_free(httptest->http_proxy); + zbx_free(httptest->http_proxy_orig); + zbx_free(httptest->http_password); + zbx_free(httptest->http_password_orig); + zbx_free(httptest->http_user); + zbx_free(httptest->http_user_orig); + zbx_free(httptest->agent); + zbx_free(httptest->agent_orig); + zbx_free(httptest->delay); + zbx_free(httptest->delay_orig); + zbx_free(httptest->name); + zbx_free(httptest->ssl_cert_file); + zbx_free(httptest->ssl_cert_file_orig); + zbx_free(httptest->ssl_key_file); + zbx_free(httptest->ssl_key_file_orig); + zbx_free(httptest->ssl_key_password); + zbx_free(httptest->ssl_key_password_orig); + + for (j = 0; j < httptest->fields.values_num; j++) + { + httpfield = (httpfield_t *)httptest->fields.values[j]; + + zbx_free(httpfield->name); + zbx_free(httpfield->value); + + zbx_free(httpfield); + } + + zbx_vector_ptr_destroy(&httptest->fields); + + for (j = 0; j < httptest->httptesttags.values_num; j++) + { + httptesttag = (httptesttag_t *)httptest->httptesttags.values[j]; + + zbx_free(httptesttag->tag); + zbx_free(httptesttag->value); + + zbx_free(httptesttag); + } + + zbx_vector_ptr_destroy(&httptest->httptesttags); + + for (j = 0; j < httptest->httpsteps.values_num; j++) + { + httpstep = (httpstep_t *)httptest->httpsteps.values[j]; + + zbx_free(httpstep->status_codes); + zbx_free(httpstep->status_codes_orig); + zbx_free(httpstep->required); + zbx_free(httpstep->required_orig); + zbx_free(httpstep->posts); + zbx_free(httpstep->posts_orig); + zbx_free(httpstep->timeout); + zbx_free(httpstep->timeout_orig); + zbx_free(httpstep->url); + zbx_free(httpstep->url_orig); + zbx_free(httpstep->name); + + for (k = 0; k < httpstep->fields.values_num; k++) + { + httpfield = (httpfield_t *)httpstep->fields.values[k]; + + zbx_free(httpfield->name); + zbx_free(httpfield->value); + + zbx_free(httpfield); + } + + zbx_vector_ptr_destroy(&httpstep->fields); + + for (k = 0; k < httpstep->httpstepitems.values_num; k++) + zbx_free(httpstep->httpstepitems.values[k]); + + zbx_vector_ptr_destroy(&httpstep->httpstepitems); + + zbx_free(httpstep); + } + + zbx_vector_ptr_destroy(&httptest->httpsteps); + + for (j = 0; j < httptest->httptestitems.values_num; j++) + zbx_free(httptest->httptestitems.values[j]); + + zbx_vector_ptr_destroy(&httptest->httptestitems); + + zbx_free(httptest); + } +} + +/****************************************************************************** + * * + * Purpose: copy web scenarios from template to host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * * + ******************************************************************************/ +static void DBcopy_template_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids) +{ + zbx_vector_ptr_t httptests; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(&httptests); + + DBget_httptests(hostid, templateids, &httptests); + DBsave_httptests(hostid, &httptests); + + clean_httptests(&httptests); + zbx_vector_ptr_destroy(&httptests); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: copy elements from specified template * + * * + * Parameters: hostid - [IN] host identifier from database * + * lnk_templateids - [IN] array of template IDs * + * link_type - [IN] link type 0 - manual, 1 - LLD automatic * + * error - [OUT] error message * + * * + * Return value: upon successful completion return SUCCEED * + * * + ******************************************************************************/ +int DBcopy_template_elements(zbx_uint64_t hostid, zbx_vector_uint64_t *lnk_templateids, + zbx_host_template_link_type link_type, char **error) +{ + zbx_vector_uint64_t templateids; + zbx_uint64_t hosttemplateid; + int i, res = SUCCEED; + char *template_names, err[MAX_STRING_LEN]; + zbx_db_insert_t *db_insert_htemplates; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&templateids); + + get_templates_by_hostid(hostid, &templateids); + + for (i = 0; i < lnk_templateids->values_num; i++) + { + if (FAIL != zbx_vector_uint64_search(&templateids, lnk_templateids->values[i], + ZBX_DEFAULT_UINT64_COMPARE_FUNC)) + { + /* template already linked */ + zbx_vector_uint64_remove(lnk_templateids, i--); + } + else + zbx_vector_uint64_append(&templateids, lnk_templateids->values[i]); + } + + /* all templates already linked */ + if (0 == lnk_templateids->values_num) + goto clean; + + zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + if (SUCCEED != (res = validate_linked_templates(&templateids, err, sizeof(err)))) + { + template_names = get_template_names(lnk_templateids); + + *error = zbx_dsprintf(NULL, "%s to host \"%s\": %s", template_names, zbx_host_string(hostid), err); + + zbx_free(template_names); + goto clean; + } + + if (SUCCEED != (res = validate_host(hostid, lnk_templateids, err, sizeof(err)))) + { + template_names = get_template_names(lnk_templateids); + + *error = zbx_dsprintf(NULL, "%s to host \"%s\": %s", template_names, zbx_host_string(hostid), err); + + zbx_free(template_names); + goto clean; + } + + hosttemplateid = DBget_maxid_num("hosts_templates", lnk_templateids->values_num); + + db_insert_htemplates = zbx_malloc(NULL, sizeof(zbx_db_insert_t)); + + zbx_db_insert_prepare(db_insert_htemplates, "hosts_templates", "hosttemplateid", "hostid", "templateid", + "link_type", NULL); + + for (i = 0; i < lnk_templateids->values_num; i++) + { + zbx_db_insert_add_values(db_insert_htemplates, hosttemplateid, hostid, lnk_templateids->values[i], + link_type); + zbx_audit_host_update_json_add_parent_template(hostid, hosttemplateid, lnk_templateids->values[i], + link_type); + + hosttemplateid++; + } + + DBcopy_template_items(hostid, lnk_templateids); + DBcopy_template_host_prototypes(hostid, lnk_templateids, db_insert_htemplates); + + zbx_db_insert_execute(db_insert_htemplates); + zbx_db_insert_clean(db_insert_htemplates); + zbx_free(db_insert_htemplates); + + if (SUCCEED == (res = DBcopy_template_triggers(hostid, lnk_templateids, error))) + { + res = DBcopy_template_graphs(hostid, lnk_templateids); + DBcopy_template_httptests(hostid, lnk_templateids); + } +clean: + zbx_vector_uint64_destroy(&templateids); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +/****************************************************************************** + * * + * Purpose: delete hosts from database with all elements * + * * + * Parameters: hostids - [IN] host identifiers from database * + * hostnames - [IN] names of hosts * + * * + ******************************************************************************/ +void DBdelete_hosts(const zbx_vector_uint64_t *hostids, const zbx_vector_str_t *hostnames) +{ + int i; + zbx_vector_uint64_t itemids, httptestids, selementids; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (SUCCEED != DBlock_hostids(hostids)) + goto out; + + zbx_vector_uint64_create(&httptestids); + zbx_vector_uint64_create(&selementids); + + /* delete web tests */ + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select httptestid" + " from httptest" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num); + + DBselect_uint64(sql, &httptestids); + + DBdelete_httptests(&httptestids); + + zbx_vector_uint64_destroy(&httptestids); + + zbx_vector_uint64_create(&itemids); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select itemid,name,flags" + " from items" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num); + + if (FAIL == zbx_audit_DBselect_delete_for_item(sql, &itemids)) + goto clean; + + DBdelete_items(&itemids); + + zbx_vector_uint64_destroy(&itemids); + + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + /* delete host from maps */ + DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_HOST, hostids); + if (0 != selementids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values, + selementids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + /* delete action conditions */ + for (i = 0; i < hostids->values_num; i++) + DBdelete_action_conditions(ZBX_CONDITION_TYPE_HOST, hostids->values[i]); + + /* delete host tags */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from host_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + + /* delete host */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from hosts where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + for (i = 0; i < hostids->values_num; i++) + zbx_audit_host_del(hostids->values[i], hostnames->values[i]); +clean: + zbx_free(sql); + + zbx_vector_uint64_destroy(&selementids); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: delete hosts from database, check if there are any hosts * + * prototypes and delete them first * + * * + * Parameters: hostids - [IN] host identifiers from database * + * hostnames - [IN] names of hosts * + * * + ******************************************************************************/ +void DBdelete_hosts_with_prototypes(const zbx_vector_uint64_t *hostids, const zbx_vector_str_t *hostnames) +{ + zbx_vector_uint64_t host_prototype_ids; + zbx_vector_str_t host_prototype_names; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&host_prototype_ids); + zbx_vector_str_create(&host_prototype_names); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hd.hostid,h.name" + " from items i,host_discovery hd, hosts h" + " where hd.hostid=h.hostid and i.itemid=hd.parent_itemid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", hostids->values, hostids->values_num); + + if (FAIL == DBselect_ids_names(sql, &host_prototype_ids, &host_prototype_names)) + goto clean; + + DBdelete_host_prototypes(&host_prototype_ids, &host_prototype_names); + + DBdelete_hosts(hostids, hostnames); +clean: + zbx_free(sql); + zbx_vector_uint64_destroy(&host_prototype_ids); + zbx_vector_str_destroy(&host_prototype_names); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: add new interface to specified host * + * * + * Parameters: hostid - [IN] host identifier from database * + * type - [IN] new interface type * + * useip - [IN] how to connect to the host 0/1 - DNS/IP * + * ip - [IN] IP address * + * dns - [IN] DNS address * + * port - [IN] port * + * flags - [IN] the used connection type * + * * + * Return value: upon successful completion return interface identifier * + * * + ******************************************************************************/ +zbx_uint64_t DBadd_interface(zbx_uint64_t hostid, unsigned char type, unsigned char useip, + const char *ip, const char *dns, unsigned short port, zbx_conn_flags_t flags) +{ + DB_RESULT result; + DB_ROW row; + char *ip_esc, *dns_esc, *tmp = NULL; + zbx_uint64_t interfaceid = 0; + unsigned char main_ = 1, db_main, db_useip; + unsigned short db_port; + const char *db_ip, *db_dns; + zbx_dc_um_handle_t *um_handle; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + um_handle = zbx_dc_open_user_macros(); + + result = DBselect( + "select interfaceid,useip,ip,dns,port,main" + " from interface" + " where hostid=" ZBX_FS_UI64 + " and type=%d", + hostid, (int)type); + + while (NULL != (row = DBfetch(result))) + { + db_useip = (unsigned char)atoi(row[1]); + db_ip = row[2]; + db_dns = row[3]; + db_main = (unsigned char)atoi(row[5]); + if (1 == db_main) + main_ = 0; + + if (ZBX_CONN_DEFAULT == flags) + { + if (db_useip != useip) + continue; + if (useip && 0 != strcmp(db_ip, ip)) + continue; + + if (!useip && 0 != strcmp(db_dns, dns)) + continue; + + zbx_free(tmp); + tmp = strdup(row[4]); + zbx_substitute_simple_macros(NULL, NULL, NULL, NULL, &hostid, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, &tmp, MACRO_TYPE_COMMON, NULL, 0); + if (FAIL == zbx_is_ushort(tmp, &db_port) || db_port != port) + continue; + + ZBX_STR2UINT64(interfaceid, row[0]); + break; + } + + /* update main interface if explicit connection flags were passed (flags != ZBX_CONN_DEFAULT) */ + if (1 == db_main) + { + char *update = NULL, delim = ' '; + size_t update_alloc = 0, update_offset = 0; + + ZBX_STR2UINT64(interfaceid, row[0]); + + if (db_useip != useip) + { + zbx_snprintf_alloc(&update, &update_alloc, &update_offset, "%cuseip=%d", delim, useip); + delim = ','; + zbx_audit_host_update_json_update_interface_useip(hostid, interfaceid, db_useip, useip); + } + + if (ZBX_CONN_IP == flags && 0 != strcmp(db_ip, ip)) + { + ip_esc = DBdyn_escape_field("interface", "ip", ip); + zbx_snprintf_alloc(&update, &update_alloc, &update_offset, "%cip='%s'", delim, ip_esc); + zbx_free(ip_esc); + delim = ','; + zbx_audit_host_update_json_update_interface_ip(hostid, interfaceid, db_ip, ip); + } + + if (ZBX_CONN_DNS == flags && 0 != strcmp(db_dns, dns)) + { + dns_esc = DBdyn_escape_field("interface", "dns", dns); + zbx_snprintf_alloc(&update, &update_alloc, &update_offset, "%cdns='%s'", delim, + dns_esc); + zbx_free(dns_esc); + delim = ','; + zbx_audit_host_update_json_update_interface_dns(hostid, interfaceid, db_dns, dns); + } + + if (FAIL == zbx_is_ushort(row[4], &db_port) || db_port != port) + { + zbx_snprintf_alloc(&update, &update_alloc, &update_offset, "%cport=%u", delim, port); + zbx_audit_host_update_json_update_interface_port(hostid, interfaceid, db_port, port); + } + + if (0 != update_alloc) + { + DBexecute("update interface set%s where interfaceid=" ZBX_FS_UI64, update, + interfaceid); + zbx_free(update); + } + break; + } + } + DBfree_result(result); + + zbx_free(tmp); + + if (0 != interfaceid) + goto out; + + ip_esc = DBdyn_escape_field("interface", "ip", ip); + dns_esc = DBdyn_escape_field("interface", "dns", dns); + + interfaceid = DBget_maxid_num("interface", 1); + + DBexecute("insert into interface" + " (interfaceid,hostid,main,type,useip,ip,dns,port)" + " values" + " (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d,%d,%d,'%s','%s',%d)", + interfaceid, hostid, (int)main_, (int)type, (int)useip, ip_esc, dns_esc, (int)port); + + zbx_audit_host_update_json_add_interfaces(hostid, interfaceid, main_, type, useip, ip_esc, dns_esc, (int)port); + zbx_free(dns_esc); + zbx_free(ip_esc); +out: + zbx_dc_close_user_macros(um_handle); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_UI64, __func__, interfaceid); + + return interfaceid; +} + +/****************************************************************************** + * * + * Purpose: add new or update interface options to specified interface * + * * + * Parameters: interfaceid - [IN] interface id from database * + * version - [IN] snmp version * + * bulk - [IN] snmp bulk options * + * community - [IN] snmp community name * + * securityname - [IN] snmp v3 security name * + * securitylevel - [IN] snmp v3 security level * + * authpassphrase - [IN] snmp v3 authentication passphrase * + * privpassphrase - [IN] snmp v3 private passphrase * + * authprotocol - [IN] snmp v3 authentication protocol * + * privprotocol - [IN] snmp v3 private protocol * + * contextname - [IN] snmp v3 context name * + * * + ******************************************************************************/ +void DBadd_interface_snmp(const zbx_uint64_t interfaceid, const unsigned char version, + const unsigned char bulk, const char *community, const char *securityname, + const unsigned char securitylevel, const char *authpassphrase, const char *privpassphrase, + const unsigned char authprotocol, const unsigned char privprotocol, const char *contextname, + const zbx_uint64_t hostid) +{ + char *community_esc, *securityname_esc, *authpassphrase_esc, *privpassphrase_esc, *contextname_esc; + unsigned char db_version, db_bulk, db_securitylevel, db_authprotocol, db_privprotocol; + DB_RESULT result; + DB_ROW row; + int break_loop = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() interfaceid:" ZBX_FS_UI64, __func__, interfaceid); + + result = DBselect( + "select version,bulk,community,securityname,securitylevel,authpassphrase,privpassphrase," + "authprotocol,privprotocol,contextname" + " from interface_snmp" + " where interfaceid=" ZBX_FS_UI64, + interfaceid); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UCHAR(db_version, row[0]); + + if (version != db_version) + break_loop = 1; + + ZBX_STR2UCHAR(db_bulk, row[1]); + + if (bulk != db_bulk) + break_loop = 1; + + if (0 != strcmp(community, row[2])) + break_loop = 1; + + if (0 != strcmp(securityname, row[3])) + break_loop = 1; + + ZBX_STR2UCHAR(db_securitylevel, row[4]); + + if (securitylevel != db_securitylevel) + break_loop = 1; + + if (0 != strcmp(authpassphrase, row[5])) + break_loop = 1; + + if (0 != strcmp(privpassphrase, row[6])) + break_loop = 1; + + ZBX_STR2UCHAR(db_authprotocol, row[7]); + + if (authprotocol != db_authprotocol) + break_loop = 1; + + ZBX_STR2UCHAR(db_privprotocol, row[8]); + + if (privprotocol != db_privprotocol) + break_loop = 1; + + if (0 != strcmp(contextname, row[9])) + break_loop = 1; + + if (1 == break_loop) + break; + + goto out; + } + + community_esc = DBdyn_escape_field("interface_snmp", "community", community); + securityname_esc = DBdyn_escape_field("interface_snmp", "securityname", securityname); + authpassphrase_esc = DBdyn_escape_field("interface_snmp", "authpassphrase", authpassphrase); + privpassphrase_esc = DBdyn_escape_field("interface_snmp", "privpassphrase", privpassphrase); + contextname_esc = DBdyn_escape_field("interface_snmp", "contextname", contextname); + + if (NULL == row) + { + DBexecute("insert into interface_snmp" + " (interfaceid,version,bulk,community,securityname,securitylevel,authpassphrase," + " privpassphrase,authprotocol,privprotocol,contextname)" + " values" + " (" ZBX_FS_UI64 ",%d,%d,'%s','%s',%d,'%s','%s',%d,%d,'%s')", + interfaceid, (int)version, (int)bulk, community_esc, securityname_esc, (int)securitylevel, + authpassphrase_esc, privpassphrase_esc, (int)authprotocol, (int)privprotocol, contextname_esc); + + zbx_audit_host_update_json_add_snmp_interface(hostid, version, bulk, community_esc, securityname_esc, + securitylevel, authpassphrase_esc, privpassphrase_esc, authprotocol, privprotocol, + contextname_esc, interfaceid); + } + else + { + DBexecute( + "update interface_snmp" + " set version=%d" + ",bulk=%d" + ",community='%s'" + ",securityname='%s'" + ",securitylevel=%d" + ",authpassphrase='%s'" + ",privpassphrase='%s'" + ",authprotocol=%d" + ",privprotocol=%d" + ",contextname='%s'" + " where interfaceid=" ZBX_FS_UI64, + (int)version, (int)bulk, community_esc, securityname_esc, (int)securitylevel, + authpassphrase_esc, privpassphrase_esc, (int)authprotocol, (int)privprotocol, contextname_esc, + interfaceid); + + zbx_audit_host_update_json_update_snmp_interface(hostid, db_version, version, db_bulk, bulk, row[2], + community_esc, row[3], securityname_esc, db_securitylevel, securitylevel, row[5], + authpassphrase_esc, row[6], privpassphrase_esc, db_authprotocol, authprotocol, + db_privprotocol, privprotocol, row[9], contextname_esc, interfaceid); + } + + zbx_free(community_esc); + zbx_free(securityname_esc); + zbx_free(authpassphrase_esc); + zbx_free(privpassphrase_esc); + zbx_free(contextname_esc); +out: + DBfree_result(result); + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: removes the groupids from the list which cannot be deleted * + * (host or template can remain without groups or it's an internal * + * group or it's used by a host prototype) * + * * + ******************************************************************************/ +static void DBdelete_groups_validate(zbx_vector_uint64_t *groupids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_t hostids; + zbx_uint64_t groupid; + int index; + + if (0 == groupids->values_num) + return; + + zbx_vector_uint64_create(&hostids); + + /* select of the list of hosts which remain without groups */ + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select hg.hostid" + " from hosts_groups hg" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.groupid", groupids->values, groupids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " and not exists (" + "select null" + " from hosts_groups hg2" + " where hg.hostid=hg2.hostid" + " and not"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg2.groupid", groupids->values, groupids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + ")"); + + DBselect_uint64(sql, &hostids); + + /* select of the list of groups which cannot be deleted */ + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select g.groupid,g.name,c.discovery_groupid" + " from hstgrp g,config c" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.groupid", groupids->values, groupids->values_num); + if (0 < hostids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " and (g.groupid=c.discovery_groupid" + " or exists (" + "select null" + " from hosts_groups hg" + " where g.groupid=hg.groupid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.hostid", hostids.values, hostids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "))"); + } + else + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and g.groupid=c.discovery_groupid"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(groupid, row[0]); + + if (FAIL != (index = zbx_vector_uint64_bsearch(groupids, groupid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + zbx_vector_uint64_remove(groupids, index); + + if (0 == hostids.values_num || 0 == strcmp(row[0], row[2])) + { + zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" is used for network discovery" + " and cannot be deleted", row[1]); + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" cannot be deleted," + " because some hosts or templates depend on it", row[1]); + } + } + DBfree_result(result); + + /* check if groups is used in the groups prototypes */ + + if (0 != groupids->values_num) + { + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select g.groupid,g.name" + " from hstgrp g" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.groupid", + groupids->values, groupids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + " and exists (" + "select null" + " from group_prototype gp" + " where g.groupid=gp.groupid" + ")"); + + result = DBselect("%s", sql); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(groupid, row[0]); + + if (FAIL != (index = zbx_vector_uint64_bsearch(groupids, groupid, + ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + zbx_vector_uint64_remove(groupids, index); + } + + zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" cannot be deleted," + " because it is used by a host prototype", row[1]); + } + DBfree_result(result); + } + + zbx_vector_uint64_destroy(&hostids); + zbx_free(sql); +} + +/****************************************************************************** + * * + * Purpose: delete host groups from database * + * * + * Parameters: groupids - [IN] array of group identifiers from database * + * * + ******************************************************************************/ +void DBdelete_groups(zbx_vector_uint64_t *groupids) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + int i; + zbx_vector_uint64_t selementids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __func__, groupids->values_num); + + DBdelete_groups_validate(groupids); + + if (0 == groupids->values_num) + goto out; + + for (i = 0; i < groupids->values_num; i++) + DBdelete_action_conditions(ZBX_CONDITION_TYPE_HOST_GROUP, groupids->values[i]); + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_vector_uint64_create(&selementids); + + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + /* delete sysmaps_elements */ + DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_HOST_GROUP, groupids); + if (0 != selementids.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values, + selementids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + } + + /* groups */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from hstgrp where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid", groupids->values, groupids->values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n"); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + DBexecute("%s", sql); + + zbx_vector_uint64_destroy(&selementids); + + zbx_free(sql); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: adds host inventory to the host * + * * + * Parameters: hostid - [IN] host identifier * + * inventory_mode - [IN] the host inventory mode * + * * + ******************************************************************************/ +void DBadd_host_inventory(zbx_uint64_t hostid, int inventory_mode) +{ + zbx_db_insert_t db_insert; + + zbx_db_insert_prepare(&db_insert, "host_inventory", "hostid", "inventory_mode", NULL); + zbx_db_insert_add_values(&db_insert, hostid, inventory_mode); + zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + zbx_audit_host_update_json_add_inventory_mode(hostid, inventory_mode); +} + +/****************************************************************************** + * * + * Purpose: sets host inventory mode for the specified host * + * * + * Parameters: hostid - [IN] host identifier * + * inventory_mode - [IN] the host inventory mode * + * * + * Comments: The host_inventory table record is created if absent. * + * * + * This function does not allow disabling host inventory - only * + * setting manual or automatic host inventory mode is supported. * + * * + ******************************************************************************/ +void DBset_host_inventory(zbx_uint64_t hostid, int inventory_mode) +{ + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + result = DBselect("select inventory_mode from host_inventory where hostid=" ZBX_FS_UI64, hostid); + + if (NULL == (row = DBfetch(result))) + { + DBadd_host_inventory(hostid, inventory_mode); + } + else if (inventory_mode != atoi(row[0])) + { + DBexecute("update host_inventory set inventory_mode=%d where hostid=" ZBX_FS_UI64, inventory_mode, + hostid); + zbx_audit_host_update_json_update_inventory_mode(hostid, atoi(row[0]), inventory_mode); + } + + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} |